Squashed 'third_party/allwpilib/' changes from e4b91005cf..83f1860047
83f1860047 [wpilib] Add/update documentation to PneumaticBase and subclasses (NFC) (#4881)
9872e676d8 [commands] Make Subsystem destructor virtual (#4892)
25db20e49d [hal] Fix segfault in various HAL functions (#4891)
b0c6724eed [glass] Add hamburger menu icon to titlebars (#4874)
f0fa8205ac Add missing compiler flags and fix warnings (#4889)
42fc4cb6bc [wpiutil] SafeThread: Provide start/stop hooks (#4880)
cc166c98d2 [templates] Add Command-based skeleton template (#4861)
3f51f10ad3 [build] Update to 2023v3 image (#4886)
1562eae74a [ntcore] Refactor meta-topic decoding from glass (#4809)
b632b288a3 Fix usages of std::min and std::max to be windows safe (#4887)
c11bd2720f [wpilibc] Add internal function to reset Shuffleboard instance (#4884)
f1151d375f [ntcore] Add method to get server time offset (#4847)
fe1b62647f [hal,wpilib] Update documentation for getComments (NFC) (#4879)
c49a45abbd [build] Fix examples linking in incorrect jni library (#4873)
bc3d01a721 [build] Add platform check to doxygen plugin (#4862)
bc473240ae Add Jetbrains Fleet folder to .gitignore (#4872)
2121bd5fb8 [wpimath] Remove RKF45 (#4870)
835f8470d6 [build] Fix roborio cross-compiler on arm hosts (#4864)
6cfe5de00d [ntcore] Don't deadlock server on early destroy (#4863)
2ac41f3edc [hal, wpilib] Add RobotController.getComments() (#4463)
26bdbf3d41 Java optimization and formatting fixes (#4857)
92149efa11 Spelling and grammar cleanups (#4849)
176fddeb4c [commands] Add functions to HID classes to allow use of axes as BooleanEvents/Triggers (#4762)
87a34af367 [templates] Add bindings to command-based template (#4838)
4534e75787 [examples] Remove redundant MotorControl example (#4837)
1cbebaa2f7 [commands] Remove final semicolon from test macro definition (#4859)
6efb9ee405 [commands] Add constructor for SwerveControllerCommand that takes a HolonomicDriveController (#4785)
1e7fcd5637 [cscore] Change run loop functions to not be mac specific (#4854)
1f940e2b60 [apriltag] Add C++ wrappers, rewrite Java/JNI to match (#4842)
a6d127aedf [build] Add missing task dependency in wpilibjExamples (#4852)
b893b3d6d3 [cscore] Add support for USB cameras on macOS (#4846)
1696a490fa [glass] Add support for alternate NT ports (#4848)
40a22d69bc [glass] Add support for alternate NT ports (#4848)
e84dbfede0 [wpilib] GenericHID: Add rumble both option (#4843)
8aa9dbfa90 [examples] Link apriltag package in examples build.gradle (#4845)
eda2fa8a17 [build] Update Spotless (#4840)
d20594db0d Fix typos (#4839)
dd8ecfdd54 [commands] Fix typo in waitUntil docs (NFC) (#4841)
17ceebfff4 [apriltag] Clean up apriltag JNI (#4823)
8b74ab389d [examples] RapidReactCommandBot: Fix array indices (#4833)
1aad3489c2 [sim] Implement PD total current and power (#4830)
2744991771 [wpimath] Fix docs in SwerveModulePosition (#4825)
ffbf6a1fa2 [commands] Disable regularly failing unit test (#4824)
fbabd0ef15 [commands] Enhance Command Sendable implementations (#4822)
7713f68772 [hal] Use atomic rather then mutex for DS Data updates (#4787)
701995d6cc [examples] Update Command-based starter project (#4778)
bf7068ac27 [wpilibc] Add missing PPS implementation for C++ (#4821)
aae0f52ca6 [ntcore] NetworkTable: fix visibility of get/set value (#4820)
ee02fb7ba7 [hal] Add support for Pulse-Per-Second signal (#4819)
518916ba02 [wpilib] Fix DS mode thread event being manual reset accidentally (#4818)
3997c6635b [hal] Update to new image, use new TCP notify callback and new duty cycle API (#4774)
cc8675a4e5 [examples] Add comment on how to view elevator sim (NFC) (#4482)
fb2c170b6e [ntcore] Simplify local startup (#4803)
7ba8a9ee1f [wpimath] ProfiledPIDController: Add to SendableRegistry (#4656)
c569d8e523 [wpilib] Joystick.getMagnitude(): use hypot() function (#4816)
2a5e89fa97 [apriltag] Improve description of pose coordinates (NFC) (#4810)
cc003c6c38 [apriltag] Fix AprilTagFieldLayout JSON name (#4814)
5522916123 [commands] CommandXBoxController bumper documentation fix (NFC) (#4815)
967b30de3a [glass] Fix NT view UpdateClients() bug (#4808)
3270d4fc86 [wpimath] Rewrite pose estimator docs (#4807)
be39678447 [apriltag] Add test to ensure apriltagjni loads (#4805)
61c75deb2a [commands] Test no-op behavior of scheduling a scheduled command (#4806)
a865f48e96 [ntcore] Pass pub/sub options as a unified PubSubOptions struct (#4794)
f66a667321 [commands] Fix incorrect Trigger docs (NFC) (#4792)
f8d4e9866e [ntcore] Clean up ntcore_test.h (#4804)
7e84ea891f [wpimath] Fix ComputerVisionUtil transform example in parameter docs (NFC) (#4800)
da3ec1be10 [wpimath] Change terminology for ArmFeedforward gravity gain (NFC) (#4791)
944dd7265d [wpilibc] Add C++ Notifier error handling, update java notifier error message (#4795)
6948cea67a [wpiutil] Fix MemoryBuffer initialization (#4797)
a31459bce6 [wpiutil] Fix UnescapeCString overflow when inputSize < 2 (#4796)
4a0ad6b48c [wpimath] Rotation2d: Add reference to angleModulus in docs (NFC) (#4786)
e6552d272e [ntcore] Remove table multi-subscriber (#4789)
bde383f763 [hal] Replace const char* with std::string_view in Driver Station sim functions (#4532)
5a52b51443 [hal] Add RobotController.getSerialNumber() (#4783)
69a66ec5ec [wpilib] Fix multiple motor safety issues (#4784)
989c9fb29a [wpimath] Revert Rotation2D change that limits angles (#4781)
0f5b08ec69 [wpigui] Update imgui to 1.89.1+ (#4780)
fba191099c [examples] AddressableLED: Add unit test (#4779)
b390cad095 [wpilibj] Consistently use ErrorMessages.requireNonNullParam (#4776)
b9772214d9 [wpilib] Sendable: Don't call setter for getter changes
342c375a71 [ntcore] Add subscriber option to exclude single publisher
b0e4053087 [ntcore] Use int for options instead of double
f3e666b7bb [cscore] Convert YUYV and UYVY directly to grayscale (#4777)
b300518bd1 [hal] Add CAN Stream API to Java through JNI bindings (#4193)
be27171236 [wpilibj] Shuffleboard: Check for null sendable (#4772)
4bbdbdfb48 [commands] Move GroupedCommands to CommandScheduler (#4728)
f18fd41ac3 [wpimath] Remove broken and obsoleted ComputerVisionUtil functions (#4775)
2d0faecf4f [glass] DataSource: Add spinlock to protect value (#4771)
348bd107fc [hal] Add CANManufacturer for The Thrifty Bot (#4773)
3149dc64b8 [examples] HatchbotInlined: Use Subsystem factories (#4765)
8618dd4160 [glass, wpilib] Replace remaining references to Speed Controller with Motor Controller (#4769)
72e21a1ed1 [apriltag] Use wpilibsuite fork of apriltag (#4764)
eab0d929e6 [commands] CommandGenericHID POV methods: Fix docs (NFC) (#4760)
6789869663 [wpilib] Call set(0) rather than disable for stopMotor (#4763)
c9dea2968d [cscore] Emit warning that USB Camera isn't supported on OSX (#4766)
8f402645f5 [commands] Fix PIDSubsystem setSetpoint behavior (#4759)
f24ad1d715 [build] Upgrade to googletest 1.12.1 (#4752)
ff88756864 [wpimath] Add new DCMotor functions for alternative calculations and reduction calculation (#4749)
f58873db8e [wpimath] Remove extra terms in matrix for pose estimator docs (#4756)
37e969b41a [wpimath] Add constructors to pose estimators with default standard deviations (#4754)
13cdc29382 [ci] Rename comment command from "/wpiformat" to "/format" (#4755)
6e23985ae6 [examples] Add main include directory to test builds (#4751)
66bb0ffb2c [examples] Add unit testing infrastructure (#4646)
74cc86c4c5 [wpimath] Make transform tests use pose/transform equality operators (#4675)
e22d8cc343 [wpimath] Use Odometry for internal state in Pose Estimation (#4668)
68dba92630 [ci] Update mac and windows builds to Java 17 (#4750)
23bfc2d9ab [sim] Remove unmaintained Gazebo support (#4736)
1f1461e254 [wpilib] Add method to enable/disable LiveWindow in test mode (#4678)
eae68fc165 [wpimath] Add tolerance for Rotation3d rotation matrix special orthogonality (#4744)
4c4545fb4b [apriltag] Suppress warning (#4743)
16ffaa754d [docs] Generate docs for apriltag subproject (#4745)
5e74ff26d8 [apriltag, build] Update native utils, add apriltag impl and JNI (#4733)
53875419a1 [hal] Allow overriding stderr printing by HAL_SendError (#4742)
aa6499e920 [ntcore] Fix special topic multi-subscriber handling (#4740)
df70351107 [build] Fix cmake install of thirdparty includes (#4741)
e9bd50ff9b [glass] NT view: clear meta-topic info on disconnect (#4732)
9b319fd56b [ntcore] Add sub option for local vs remote changes (#4731)
18d28ec5e3 [ntcore] Remove duplicate value checking from ClientImpl
bdfb625211 [ntcore] Send duplicate values to network if necessary
21003e34eb [commands] Update Subsystem factories and example to return CommandBase (#4729)
70080457d5 [commands] Refactor ProxyScheduleCommand, SelectCommand into ProxyCommand (#4534)
e82cd5147b [wpilib] Tweak Color HSV formula and use in AddressableLED (#4724)
ec124bb662 [commands] Allow unsetting a subsystem's default command (#4621)
2b2aa8eef7 [examples] Update all examples to use NWU coordinate conventions (#4725)
cb38bacfe8 [commands] Revert to original Trigger implementation (#4673)
15561338d5 [commands] Remove one more default command isFinished check (#4727)
ca35a2e097 Add simgui files to .gitignore (#4726)
20dbae0cee [examples] Renovate command-based examples (#4409)
1a59737f40 [commands] Add convenience factories (#4460)
42b6d4e3f7 Use defaulted comparison operators in C++ (#4723)
135c13958f [wpigui] Add FontAwesome (#4713)
ffbfc61532 [ntcore] Add NetworkTable table-specific listeners (#4640)
8958b2a4da [commands] Add property tests for command compositions (#4715)
e4ac09077c [wpilib] Add link to MotorSafety article (#4720)
f40de0c120 [commands] Add C++ factory templates (#4686)
51fa3e851f [build] cmake: Use FetchContent instead of ExternalProject (#4714)
1da84b2255 [wpigui] Reload fonts to scale rather than preloading (#4712)
e43e2fbc84 [wpiutil] StringExtras: Add UnescapeCString (#4707)
5804d8fa84 [ntcore] Server: Properly handle multiple subscribers (#4717)
169ef5fabf [glass] Update NT view for topicsOnly and sendAll changes (#4718)
148759ef54 [examples] CANPDP: Expand properties shown (#4687)
58ed112b51 [commands] RepeatCommand: restart on following iteration (#4706)
dd1da77d20 [readme] Fix broken CI badge (#4710)
7cda85df20 [build] Check Gradle plugin repo last to fix CI (#4711)
7ed9b13277 [build] Bump version plugin to fix null tag (#4705)
6b4f26225d [apriltag] Fix pluralization of apriltag artifacts (#4671)
b2d2924b72 [cscore] Add Y16 image support (#4702)
34ec89c041 [wpilibc] Shuffleboard SimpleWidget: Return pointer instead of reference (#4703)
e15200068d [ci] Disable HW testbench runs (#4704)
d5200db6cd [wpimath] Rename HolonomicDriveController.calculate params (#4683)
2ee3d86de4 [wpimath] Clarify Rotation3d roll-pitch-yaw direction (#4699)
9f0a8b930f [cscore] Use MFVideoFormat_L8 for Gray on Windows (#4701)
2bca43779e [cscore] Add UYVY image support (#4700)
4307d0ee8b [glass] Plot: allow for more than 11 plots (#4685)
3fe8d355a1 [examples] StateSpaceDifferentialDriveSimulation: Use encoder reversed constants (#4682)
b44034dadc [ntcore] Allow duplicate client IDs on server (#4676)
52d2c53888 [commands] Rename Java factory wait() to waitSeconds() (#4684)
76e918f71e [build] Fix JNI artifacts linking to incorrect libraries (#4680)
0bee875aff [commands] Change C++ CommandPtr to use CommandBase (#4677)
98e922313b [glass] Don't check IsConnected for NT widgets (#4674)
9a36373b8f [apriltag] Switch 2022 apriltag layout length and width values (#4670)
cf8faa9e67 [wpilib] Update values on controllable sendables (#4667)
5ec067c1f8 [ntcore] Implement keep duplicates pub/sub flag (#4666)
e962fd2916 [ntcore] Allow numeric-compatible value sets (#4620)
88bd67e7de [ci] Update clang repositories to jammy (#4665)
902e8686d3 [wpimath] Rework odometry APIs to improve feature parity (#4645)
e2d49181da Update to native utils 2023.8.0 (#4664)
149bac55b1 [cscore] Add Arducam OV9281 exposure quirk (#4663)
88f7a3ccb9 [wpimath] Fix Pose relativeTo documentation (#4661)
8acce443f0 [examples] Fix swerve examples to use getDistance for turning encoder (#4652)
295a1f8f3b [ntcore] Fix WaitForListenerQueue (#4662)
388e7a4265 [ntcore] Provide mechanism to reset internals of NT instance (#4653)
13aceea8dc [apriltag] Fix FieldDimensions argument order (#4659)
c203f3f0a9 [apriltag] Fix documentation for AprilTagFieldLayout (#4657)
f54d495c90 Fix non initialized hal functionality during motor safety init (#4658)
e6392a1570 [cmd] Change factories return type to CommandBase (#4655)
53904e7cf4 [apriltag] Split AprilTag functionality to a separate library (#4578)
2e88a496c2 [wpimath] Add support for swerve joystick normalization (#4516)
ce4c45df13 [wpimath] Rework function signatures for Pose Estimation / Odometry (#4642)
0401597d3b [readme] Add wpinet to MavenArtifacts.md (#4651)
2e5f9e45bb [wpimath] Remove encoder reset comments on Swerve, Mecanum Odometry and Pose Estimation (#4643)
e4b5795fc7 [docs] Disable Doxygen for memory to fix search (#4636)
03d0ea188c [build] cmake: Add missing wpinet to installed config file (#4637)
3082bd236b [build] Move version file to its own source set (#4638)
b7ca860417 [build] Use build cache for sign step (#4635)
64838e6367 [commands] Remove unsafe default command isFinished check (#4411)
1269d2b901 [myRobot] Disable spotbugs (#4565)
14d8506b72 [wpimath] Fix units docs for LinearSystemId::IdentifyDrivetrainSystem() (#4600)
d1d458db2b [wpimath] Constrain Rotation2d range to -pi to pi (#4611)
f656e99245 [readme] Add links to development build documentation (#4481)
6dd937cef7 [commands] Fix Trigger API docs (NFC) (#4599)
49047c85b9 [commands] Report error on C++ CommandPtr use-after-move (#4575)
d07267fed1 [ci] Upgrade containers to Ubuntu 22.04 and remove libclang installation (#4633)
b53ce1d3f0 [build, wpiutil] Switch macos to universal binaries (#4628)
5a320c326b [upstream_util, wpiutil] Refactor python scripts (#4614)
c4e526d315 [glass] Fix NT Mechanism2D (#4626)
d122e4254f [ci] Run spotlessApply after wpiformat in comment command (#4623)
5a1e7ea036 [wpilibj] FieldObject2d: Add null check to close() (#4619)
179f569113 [ntcore] Notify locally on SetDefault (#4617)
b0f6dc199d [wpilibc] ShuffleboardComponent.WithProperties: Update type (#4615)
7836f661cd [wpimath] Add missing open curly brace to units/base.h (#4613)
dbcc1de37f [wpimath] Add DifferentialDriveFeedforward classes which wrap LinearPlantInversionFeedforward (#4598)
93890c528b [wpimath] Add additional angular acceleration units (#4610)
3d8d5936f9 [wpimath] Add macro for disabling units fmt support (#4609)
2b04159dec [wpimath] Update units/base.h license header (#4608)
2764004fad [wpinet] Fix incorrect jni definitions (#4605)
85f1bb8f2b [wpiutil] Reenable jni check task (#4606)
231ae2c353 [glass] Plot: Fix Y-axis not being saved (#4594)
e92b6dd5f9 [wpilib] Fix AprilTagFieldLayout JSON property name typos (#4597)
2a8e0e1cc8 Update all dependencies that use grgit (#4596)
7d06e517e9 [commands] Move SelectCommand factory impl to header (#4581)
323524fed6 [wpimath] Remove deprecated units/units.h header (#4572)
d426873ed1 [commands] Add missing PS4 triangle methods (#4576)
5be5869b2f [apriltags] Use map as internal data model (#4577)
b1b4c1e9e7 [wpimath] Fix Pose3d transformBy rotation type (#4545)
a4054d702f [commands] Allow composing two triggers directly (#4580)
0190301e09 [wpilibc] Explicitly mark EventLoop as non-copyable/non-movable (#4579)
9d1ce6a6d9 [ntcore] Catch file open error when saving preferences (#4571)
5005e2ca04 [ntcore] Change Java event mask to EnumSet (#4564)
fa44a07938 [upstream-utils][mpack] Add upstream util for mpack (#4500)
4ba16db645 [ntcore] Various fixes and cleanups (#4544)
837415abfd [hal] Fix joysticks either crashing or returning 0 (#4570)
2c20fd0d09 [wpilib] SingleJointedArmSim: Check angle equals limit on wouldHit (#4567)
64a7136e08 [wpimath] SwerveDrivePoseEstimator: Restore comment about encoder reset (#4569)
b2b473b24a [wpilib] Add AprilTag and AprilTagFieldLayout (#4421)
7aab8fa93a [build] Update to Native Utils 2023.6.0 (#4563)
12c2851856 [commands] WrapperCommand: inherit from CommandBase (#4561)
0da169dd84 [wpimath] Remove template argument from ElevatorFeedforward (#4554)
2416827c25 [wpimath] Fix docs for pose estimator local measurement models (#4558)
1177a3522e [wpilib] Fix Xbox/PS4 POV sim for port number constructors (#4548)
102344e27a [commands] HID classes: Add missing methods, tweak return types (#4557)
1831ef3e19 [wpilib] Fix Shuffleboard SuppliedValueWidget (#4559)
a9606ce870 [wpilib] Fix Xbox/PS4 POV sim (#4546)
6c80d5eab3 [wpimath] Remove unused SymbolExports.h include from units/base.h (#4541)
b114006543 [ntcore] Unify listeners (#4536)
32fbfb7da6 [build] cmake: Install ntcore generated include files (#4540)
02465920fb [build] Update native utils to 2023.4.0 (#4539)
3a5a376465 [wpimath] Increase constexpr support in geometry data types (#4231)
1c3c86e9f1 [ntcore] Cache GetEntry(name) values (#4531)
dcda09f90a [command] Rename trigger methods (#4210)
66157397c1 [wpilib] Make drive classes follow NWU axes convention (#4079)
9e22ffbebf [ntcore] Fix null deref in NT3 client (#4530)
648ab6115c [wpigui,dlt,glass,ov] Support arm in GUI tools (#4527)
8bc3b04f5b [wpimath] Make ComputerVisionUtil use 3D geometry classes (#4528)
cfb84a6083 [wpilibc] Don't hang waiting for NT server to start (#4524)
02c47726e1 [wpimath] Remove unused odometry instance from DifferentialDrivePoseEstimator test (#4522)
b2a0093294 [ci] Revert upgrade of github-pages-deploy-action (#4521)
2a98d6b5d7 [wpimath] PIDController: Add getters for position & velocity tolerances (#4458)
9f36301dc8 [ci] Write wpiformat patch to job summary (#4519)
901fc555f4 [wpimath] Position Delta Odometry for Mecanum (#4514)
4170ec6107 [wpimath] Position Delta Odometry for Swerve (#4493)
fe400f68c5 [docs] Add wpinet to docs build (#4517)
794669b346 [ntcore] Revamp listeners (#4511)
dcfa85a5d5 [ci] Build sanitizers with clang-14 (#4518)
15ad855f1d [ntcore] Add UnitTopic<T> (C++ only) (#4497)
11244a49d9 [wpilib] Add IsConnected function to all gyros (#4465)
1d2e8eb153 [build] Update myRobot deployment (#4515)
ad53fb19b4 [hal] Use new HMB api for addressable LED (#4479)
ba850bac3b [hal] Add more shutdown checks and motor safety shutdown (#4510)
023a5989f8 [ntcore] Fix typo in NetworkServer client connect message (#4512)
c970011ccc [docs] Add Doxygen aliases used by Foonathan memory (#4509)
07a43c3d9a [readme] Document clang-format version and /wpiformat (#4503)
a05b212b04 [ci] Revert changes to wpiformat task from #4501 (#4508)
09faf31b67 [commands] Replace Command HID inheritance with delegation (#4470)
9e1f9c1133 [commands] Add command factories (#4476)
f19d2b9b84 [ci] Add NUMBER environment variable to comment command commit script (#4507)
a28f93863c [ci] Push comment command commit directly to PR (#4506)
c9f61669b8 [ci] Fix comment command commit push (#4505)
dcce5ad3b3 [ci] Update github-script API usage (#4504)
6836e5923d [wpilibc] Restore get duty cycle scale factor (#4502)
335188c652 [dlt] Add deselect/select all buttons to download view (#4499)
60a29dcb99 [glass] Field2D: Add "hidden" option for objects (#4498)
b55d5b3034 [ci] Update deprecated github actions (#4501)
10ed4b3969 [ntcore] Various NT4 fixes (#4474)
4a401b89d7 [hal, wpilib] New DS thread model and implementation (#3787)
c195b4fc46 [wpimath] Clean up PoseEstimator nominal dt docs (#4496)
8f2e34c6a3 [build] Remove wpilib prefix from CMake flat install (#4492)
150d692df7 [wpimath] Remove unused private PoseEstimator function (#4495)
3e5bfff1b5 [wpimath] FromFieldRelativeSpeeds: Add ChassisSpeeds overload (#4494)
9c7e66a27d [commands] C++: Add CommandPtr overload for SetDefaultCommand (#4488)
0ca274866b [build] Fix CMake system library opt-ins (#4487)
dc037f8d41 [commands] Remove EndlessCommand (#4483)
16cdc741cf [wpimath] Add Pose3d(Pose2d) constructor (#4485)
9d5055176d [build] cmake: Allow disabling ntcore build (#4486)
d1e66e1296 [build] Compile all java code with inline string concatenation (#4490)
1fc098e696 Enable log macros to work with no args (#4475)
878cc8defb [wpilib] LiveWindow: Add enableAllTelemetry() (#4480)
8153911160 [build] Fix MSVC runtime archiver to grab default runtime (#4478)
fbdc810887 Upgrade to C++20 (#4239)
396143004c [ntcore] Add ntcoreffi binary (#4471)
1f45732700 [build] Update to 2023.2.4 native-utils and new dependencies (#4473)
574cb41c18 [ntcore] Various fixes (#4469)
d9d6c425e7 [build] Force Java 11 source compatibility (#4472)
58b6484dbe Switch away from NI interrupt manager to custom implementation (#3705)
ca43fe2798 [wpimath] Use Units conversions in ComputerVisionUtil docs (NFC) (#4464)
87a64ccedc [hal] Convert DutyCycle Raw output to be a high time measurement (#4466)
89a3d00297 [commands] Add FinallyDo and HandleInterrupt decorators (#4412)
1497665f96 [commands] Add C++ versions of Java-only decorators (#4457)
27b173374e [wpimath] Add minLinearAccel parameter to DifferentialDriveAccelerationLimiter (#4422)
2a13dba8ac [wpilib] TrajectoryUtil: Fix ambiguous documentation (NFC) (#4461)
77301b126c [ntcore] NetworkTables 4 (#3217)
90cfa00115 [build] cmake: Fix libssh include directory order (#4459)
5cf961edb9 [commands] Refactor lambda-based commands to inherit FunctionalCommand (#4451)
b2276e47de [wpimath] Enable continuous angle input for HolonomicDriveController (#4453)
893b46139a [fieldImages] Add utilities to simplify loading of fields (#4456)
60e29627c0 [commands] C++ unique_ptr migration (#4319)
3b81cf6c35 [wpilib] Improve Color.toString (#4450)
5c067d30a0 [wpinet] WebSocket: Add SendFrames() (#4445)
ceaf493811 [wpiutil] MakeJByteArray: Use span<uint8> instead of string_view (#4446)
10e04e2b13 [examples] FrisbeeBot: Fix reference capture (#4449)
726f67c64b [build] Add exeSplitSetup (#4444)
c7b7624c1c [wpiutil] Add MessagePack utility functions (#4448)
d600529ec0 [wpinet] uv::Async: Add UnsafeSend() (#4447)
b53b3526a2 [wpimath] Add CoordinateSystem conversion for Transform3d (#4443)
38bb23eb18 [wpimath] Add scalar multiply and divide operators to all geometry classes (#4438)
3937ff8221 [wpilib] Remove deprecated Controller class (#4440)
abbfe244b5 [wpilib] Improve Color FromHSV (#4439)
4ddb8aa0dd [sim] Provide function that resets all simulation data (#4016)
a791470de7 Clean up Java warning suppressions (#4433)
17f504f548 [hal,wpilib] Fix SPI Mode Setting (#4434)
773198537c [wpiutil] Add wpi::scope_exit (#4432)
5ac658c8f0 [wpiutil] Logger: Conditionalize around WPI_LOG (#4431)
8767e4a941 [wpiutil] DataLog: Fix SetMetadata output (#4430)
8c4af073f4 [wpiutil] Synchronization: shutdown race protection (#4429)
c79f38584a [build] Fix Java integration tests (#4428)
36c08dd97c [build] Fix cmake install of fmtlib (#4426)
69b7b3dd7d [ci] Remove the Windows cmake job (#4425)
738c75fed8 [readme] Fix formatting/linting link (#4423)
4eb1d03fb3 [wpimath] Document C++ LinearFilter exception (#4417)
ba4ec6c967 [build] Fix clang-tidy false positive on Linux (#4406)
97836f0e55 [commands] Fix ProfiledPIDSubsystem setGoal behavior (#4414)
fdfb85f695 [wpimath] Remove Java LQR constructor that takes a controller gain matrix (#4419)
ab1baf4832 [wpimath] Add rotation matrix constructor to Rotation3d (#4413)
9730032866 [wpimath] Document LQR and KalmanFilter exceptions (#4418)
5b656eecf6 [wpimath] Fix HTML5 entity (#4420)
9ae38eaa7c [commands] Add owning overload to ProxyScheduleCommand (#4405)
cb33bd71df [commands] deprecate withInterrupt decorator (#4407)
d9b4e7b8bf [commands] Revert "Change grouping decorator impl to flatten nested group structures (#3335)" (#4402)
0389bf5214 [hal] REVPH: Improve handling of disconnected CAN Bus (#4169)
4267fa08d1 [wpilibc] ADIS IMUs: Fix memory leak (#4170)
65c8fbd452 [wpilib] MotorControllerGroup: Override setVoltage (#4403)
f36162fddc [wpimath] Improve Discretization internal docs (#4400)
5149f7d894 [wpimath] Add two-vector Rotation3d constructor (#4398)
20b5bed1cb [wpimath] Clean up Java Quaternion class (#4399)
f18dd1905d [build] Include all thirdparty sources in distribution (#4397)
aa9d7f1cdc [wpiutil] Import foonathan memory (#4306)
2742662254 [ci] Remove a couple of obsolete clang-tidy checks (#4396)
a5df391166 [hal, wpilib] Fix up DIO pulse API (#4387)
59e6706b75 [glass] Turn on docking by default
8461bb1e03 [glass] Add support for saving docking info
b873e208b4 [wpigui] Add support for imgui config flags
873e72df8c [build] Update imgui to 1.88 docking branch
c8bd6fc5b4 [ci] Fix comment-command (take 2) (#4395)
fed68b83b4 [ci] Fix comment-command action not running runners (#4393)
0ef8a4e1df [wpimath] Support formatting more Eigen types (#4391)
c393b3b367 [build] Update to native utils 2023.1.0 and Gradle 7.5.1 (#4392)
b5a17f762c [wpimath] Add direction to slew rate limiter (#4377)
fafc81ed1a [wpiutil] Upgrade to fmt 9.1.0 (#4389)
cc56bdc787 [wpiutil] SafeThread: Add Synchronization object variant (#4382)
4254438d8d [commands] Mark command group lifecycle methods as final (#4385)
97c15af238 [wpimath] LinearSystemId: Fix docs, move C++ impls out of header (#4388)
d22ff8a158 [wpiutil] Add JNI access to C++ stderr (#4381)
fdb5a2791f [wpiutil] jni_util: Add Mac-friendly MakeJLongArray/JArrayRef (#4383)
c3a93fb995 [commands] Revamp Interruptible (#4192)
f2a8d38d2a [commands] Rename Command.repeat to repeatedly (#4379)
9e24c6eac0 [wpiutil] Logger: paren-protect instance usage in macro (#4384)
fe4d12ce22 [wpimath] Add LTV controller derivations and make enums private (#4380)
eb08486039 [build] Fix MacOS binary rpath generation (#4376)
ccf83c634a [build] Use native-utils platform names instead of raw strings (#4375)
3fd69749e7 [docs] Upgrade to doxygen 1.9.4 (#4370)
594df5fc08 [wpinet] uv/util.h: Pull in ws2_32.lib on Windows for ntohs (#4371)
539070820d [ci] Enable asan for wpinet and wpiutil (#4369)
564a56d99b [wpinet] Fix memory leak in WorkerThreadTest (#4368)
5adf50d93c [upstream_utils] Refactor upstream_utils scripts (#4367)
d80e8039d7 [wpiutil] Suppress fmtlib clang-tidy warning in C++20 consteval contexts (#4364)
0e6d67b23b [upstream_utils] Remove yapf format disable comment (#4366)
be5270697a [build] Suppress enum-enum deprecation warning in OpenCV (#4365)
8d28851263 Add Rosetta install command to build requirements (#4363)
3d2115c93e [wpinet] include-what-you-use in MulticastTest (#4360)
91002ae3cc [wpimath] Upgrade to Drake 1.6.0 (#4361)
148c18e658 [wpinet] Upgrade to libuv 1.44.2 (#4362)
a2a5c926b6 Fix clang-tidy warnings (#4359)
ea6b1d8449 [wpiutil] Remove unused ManagedStatic class (#4358)
ac9be78e27 Use stricter C++ type conversions (#4357)
151dabb2af [wpiutil] Upgrade to fmt 9.0.0 (#4337)
340465c929 [ci] Upgrade to clang-format and clang-tidy 14 (NFC) (#4347)
d45bcddd15 [examples] Add comments to StateSpaceDifferentialDrive (#4341)
0e0786331a Update LLVM libraries to 14.0.6 (#4350)
c5db23f296 [wpimath] Add Eigen sparse matrix and iterative solver support (#4349)
44abc8dfa6 [upstream_utils] Remove git version from upstream patches (#4351)
3fdb2f767d [wpimath] Add comments with Ramsete equations (#4348)
0485f05da9 [wpilibjExamples] Upgrade jacoco to match allwpilib (#4346)
0a5eb65231 [wpinet] Handle empty txt block for mdns announcer (#4072)
19ffebaf3e [wpilib] Add reference to I2C Lockup to API Docs (NFC) (#4340)
ce1a90d639 [hal] Replace SerialHelper "goto done" with continue (#4342)
d25af48797 [ci] Make upstream_utils CI fail on untracked files (#4339)
ebb836dacb [examples] Fix negations in event loop examples (#4334)
d83e202f00 [upstream_utils] Update paths in update_fmt.py (#4338)
3ccf806064 [wpimath] Remove redundant LinearFilter.finiteDifference() argument (#4335)
6f1e01f8bd [wpimath] Document example of online filtering for LinearFilter.finiteDifference() (#4336)
1023c34b1c [readme] Update location of ni-libraries (#4333)
faa29d596c [wpilib] Improve Notifier docs (NFC) (#4326)
add00a96ed [wpimath] Improve DifferentialDriveAccelerationLimiter docs (NFC) (#4323)
82fac41244 [wpimath] Better document trackwidth parameters (NFC) (#4324)
5eb44e22a9 Format Python scripts with black (NFC) (#4325)
2e09fa7325 [build] Fix mpack cmake (#4322)
fe3c24b1ee [command] Add ignoringDisable decorator (#4305)
aa221597bc [build] Add M1 builds, change arm name, update to 2023 deps (#4315)
579a8ee229 [ci] Use one worker for Windows release Gradle build (#4318)
5105c5eab6 [wpilibj] Change "final" to "exit" in the IterativeRobotBase JavaDoc (NFC) (#4317)
787fe6e7a5 [wpiutil] Separate third party libraries (#4190)
6671f8d099 [wpigui] Update portable file dialogs (#4316)
9ac9b69aa2 [command] Reorder Scheduler operations (#4261)
e61028cb18 [build] halsim_gui: Add wpinet dependency (#4313)
661d23eaf5 [glass] Add precision setting for NetworkTable view (#4311)
666040e3e5 [hal] Throw exceptions for invalid sizes in I2C and SPI JNI (#4312)
aebc272449 [build] Upgrade to spotbugs Gradle plugin 5.0.8 (#4310)
fd884581e4 [wpilib] Add BooleanEvent/Trigger factories on HID classes (#4247)
9b1bf5c7f1 [wpimath] Move Drake and Eigen to thirdparty folders (#4307)
c9e620a920 [wpilibc] Change EventLoop data structure to vector (#4304)
41d40dd62f [wpinet] Fix libuv unused variable warning on Mac (#4299)
30f5b68264 [wpinet] Fix JNI loading error (#4295)
f7b3f4b90e [examples] Getting Started: Change Joystick to XboxController (#4194)
a99c11c14c [wpimath] Replace UKF implementation with square root form (#4168)
45b7fc445b [wpilib] Add EventLoop (#4104)
16a4888c52 [wpilib] Default off LiveWindow telemetry (#4301)
17752f1337 [ci] Split debug and release Windows builds (#4277)
abb45a68db [commands] Remove custom test wrappers (#4296)
1280a54ef3 [upstream_utils]: Make work with Python 3.8 (#4298)
f2d243fa68 [build] Change defaults for Java lints (#4300)
a4787130f4 Update using development build to work with 2023 gradlerio (#4294)
af7985e46c [wpiutil] Use invoke_result_t instead of result_of in future.h (#4293)
e9d1b5c2d0 [hal] Remove deprecated SimDevice functions (#4209)
45b598d236 [wpilibj] Add toString() methods to Color and Color8Bit (#4286)
fc37265da5 [wpimath] Add angle measurement convention to ArmFeedforward docs (NFC) (#4285)
a4ec13eb0e [wpilibjexamples] Remove unnecessary voltage desaturation
2fa52007af [wpilibc] Use GetBatteryVoltage() in MotorController::SetVoltage
d9f9cd1140 [wpimath] Reset prev_time on pose estimator reset (#4283)
8b6df88783 [wpilibj] Tachometer.getFrequency(): Fix bug (#4281)
345cff08c0 [wpiutil] Make wpi::array constexpr (#4278)
57428112ac [wpimath] Upgrade to Drake v1.3.0 (#4279)
a18d4ff154 [build] Fix tools not being copied when built with -Ponly* (#4276)
d1cd07b9f3 [wpigui] Add OpenURL (#4273)
e67f8e917a [glass] Use glfwSetKeyCallback for Enter key remap (#4275)
be2fedfe50 [wpimath] Add stdexcept include for std::invalid_argument (IWYU) (#4274)
7ad2be172e [build] Update native-utils to 2023.0.1 (#4272)
abc605c9c9 [ci] Update workflows to 20.04 base image (#4271)
3e94805220 [wpiutil] Reduce llvm collections patches (#4268)
db2e1d170e [upstream_utils] Document how to update thirdparty libraries (#4253)
96ebdcaf16 [wpimath] Remove unused Eigen AutoDiff module (#4267)
553b2a3b12 [upstream_utils] Fix stackwalker (#4265)
3e13ef42eb [wpilibc] Add missing std::array #include (include-what-you-use) (#4266)
d651a1fcec Fix internal deprecation warnings (#4257)
b193b318c1 [commands] Add unless() decorator (#4244)
ef3714223b [commands] Remove docs reference to obsolete interrupted() method (NFC) (#4262)
3d8dbbbac3 [readme] Add quickstart (#4225)
013efdde25 [wpinet] Wrap a number of newer libuv features (#4260)
816aa4e465 [wpilib] Add Pneumatics sim classes (#4033)
046c2c8972 [wpilibc] Rename SpeedControllerGroupTest.cpp (#4258)
d80e9cdf64 [upstream_utils] Use shallow clones for thirdparty repos (#4255)
7576136b4a [upstream_utils] Make update_llvm.py executable (#4254)
c3b223ce60 [wpiutil] Vendor llvm and update to 13.0.0 (#4224)
5aa67f56e6 [wpimath] Clean up math comments (#4252)
fff4d1f44e [wpimath] Extend Eigen warning suppression to GCC 12 (#4251)
0d9956273c [wpimath] Add CoordinateSystem.convert() translation and rotation overloads (#4227)
3fada4e0b4 [wpinet] Update to libuv 1.44.1 (#4232)
65b23ac45e [wpilibc] Fix return value of DriverStation::GetJoystickAxisType() (#4230)
4ac34c0141 [upstream_utils] Cleanup update_libuv.py (#4249)
8bd614bb1e [upstream_utils] Use "git am" instead of "git apply" for patches (#4248)
4253d6d5f0 [upstream_utils] Apply "git am" patches individually (#4250)
6a4752dcdc Fix GCC 12.1 warning false positives (#4246)
5876b40f08 [wpimath] Memoize CoordinateSystem and CoordinateAxis statics (#4241)
5983434a70 [cameraserver] Replace IterativeRobot in comment sample code with TimedRobot (#4238)
a3d44a1e69 [wpimath] Add Translation2d.getAngle() (#4217)
d364bbd5a7 [upstream_utils] Give vendor update scripts execute permissions (#4226)
f341e1b2be [wpimath] Document standard coordinate systems better (NFC) (#4228)
9af389b200 [wpinet] AddrToName: Initialize name (#4229)
2ae4adf2d7 [ci] Add wpiformat command to PRs (#4223)
178b2a1e88 Contributing.md: Correct version of clang-format used (#4222)
18db343cdc [wpiutil, wpinet] Vendor libuv, stack walker (#4219)
f0c821282a [build] Use artifactory mirror (#4220)
d673ead481 [wpinet] Move network portions of wpiutil into new wpinet library (#4077)
b33715db15 [wpimath] Add CoordinateSystem class (#4214)
99424ad562 [sim] Allow creating a PWMSim object from a PWMMotorController (#4039)
dc6f641fd2 [wpimath] PIDController: Reset position and velocity error when reset() is called. (#4064)
f20a20f3f1 [wpimath] Add 3D geometry classes (#4175)
708a4bc3bc [wpimath] Conserve previously calculated swerve module angles when updating states for stationary ChassisSpeeds (#4208)
ef7ed21a9d [wpimath] Improve accuracy of ComputerVisionUtil.calculateDistanceToTarget() (#4215)
b1abf455c1 [wpimath] LTVUnicycleController: Use LUT, provide default hyperparameters (#4213)
d5456cf278 [wpimath] LTVDifferentialDriveController: Remove unused variable (#4212)
99343d40ba [command] Remove old command-based framework (#4211)
ee03a7ad3b Remove most 2022 deprecations (#4205)
ce1a7d698a [wpimath] Refactor WheelVoltages inner class to a separate file (#4203)
87bf70fa8e [wpimath] Add LTV controllers (#4094)
ebd2a303bf [wpimath] Remove deprecated MakeMatrix() function (#4202)
e28776d361 [wpimath] LinearSystemLoop: Add extern templates for common cases
dac1429aa9 [wpimath] LQR: Use extern template instead of Impl class
e767605e94 [wpimath] Add typedefs for common types
97c493241f [wpimath] UnscentedKalmanFilter: Move implementation out-of-line
8ea90d8bc9 [wpimath] ExtendedKalmanFilter: Move implementation out-of-line
ae7b1851ec [wpimath] KalmanFilter: Use extern template instead of Impl class
e3d62c22d3 [wpimath] Add extern templates for common cases
7200c4951d [wpiutil] SymbolExports: Add WPILIB_IMPORTS for dllimport
84056c9347 [wpiutil] SymbolExports: Add EXPORT_TEMPLATE_DECLARE/DEFINE
09cf6eeecb [wpimath] ApplyDeadband: add a scale param (#3865)
03230fc842 [build,ci] Enable artifactory build cache (#4200)
63cf3aaa3f [examples] Don't square ArcadeDrive inputs in auto (#4201)
18ff694f02 [wpimath] Add Rotation2d.fromRadians factory (#4178)
4f79ceedd9 [wpilibc] Add missing #include (#4198)
f7ca72fb41 [command] Rename PerpetualCommand to EndlessCommand (#4177)
a06b3f0307 [hal] Correct documentation on updateNotifierAlarm (#4156)
d926dd1610 [wpimath] Fix pose estimator performance (#4111)
51bc893bc5 [wpiutil] CircularBuffer: Change Java package-private methods to public (#4181)
fbe761f7f6 [build] Increase Gradle JVM heap size (#4172)
5ebe911933 [wpimath] Add DifferentialDriveAccelerationLimiter (#4091)
3919250da2 [wpilibj] Remove finalizers (#4158)
b3aee28388 [commands] Allow BooleanSupplier for Trigger operations (#4103)
9d20ab3024 [wpilib] Allow disabling ElevatorSim gravity (#4145)
aaa69f6717 [ci] Remove 32-bit Windows builds (#4078)
355a11a414 Update Java linters and fix new PMD errors (#4157)
ffc69d406c [examples] Reduce suggested acceleration in Ramsete example (#4171)
922d50079a [wpimath] Units: fix comment in degreesToRotations (NFC) (#4159)
dd163b62ae [wpimath] Rotation2d: Add factory method that uses rotations (#4166)
bd80e220b9 [ci] Upgrade CMake actions (#4161)
aef4b16d4c [wpimath] Remove unnecessary NOLINT in LinearPlantInversionFeedforward (NFC) (#4155)
975171609e [wpilib] Compressor: Rename enabled to isEnabled (#4147)
5bf46a9093 [wpimath] Add ComputerVisionUtil (#4124)
f27a1f9bfb [commands] Fix JoystickButton.getAsBoolean (#4131)
1b26e2d5da [commands] Add RepeatCommand (#4009)
88222daa3d [hal] Fix misspelling in AnalogInput/Output docs (NFC) (#4153)
81c5b41ce1 [wpilibj] Document MechanismLigament2d angle unit (NFC) (#4142)
9650e6733e [wpiutil] DataLog: Document finish and thread safety (NFC) (#4140)
c8905ec29a [wpimath] Remove ImplicitModelFollower dt argument (#4119)
b4620f01f9 [wpimath] Fix Rotation2d interpolation in Java (#4125)
2e462a19d3 [wpimath] Constexprify units unary operators (#4138)
069f932e59 [build] Fix gl3w cmake build (#4139)
126e3de91a [wpilibc] Remove unused SetPriority() call from Ultrasonic (#4123)
ba0dccaae4 [wpimath] Fix reference to Rotation2d.fromRadians() (#4118)
e1b6e5f212 [wpilib] Improve MotorSafety documentation (NFC) (#4120)
8d79dc8738 [wpimath] Add ImplicitModelFollower (#4056)
78108c2aba [wpimath] Fix PIDController having incorrect error after calling SetSetpoint() (#4070)
cdafc723fb [examples] Remove unused LinearPlantInversionFeedforward includes (#4069)
0d70884dce [wpimath] Add InterpolatedTreeMap (#4073)
765efa325e [wpimath] Remove redundant column index from vectors (#4116)
89ffcbbe41 [wpimath] Update TrapezoidProfile class name in comment (NFC) (#4107)
95ae23b0e7 [wpimath] Improve EKF numerical stability (#4093)
d5cb6fed67 [wpimath] Support zero cost entries in MakeCostMatrix() (#4100)
d0fef18378 [wpimath] Remove redundant `this.` from ExtendedKalmanFilter.java (#4115)
d640c0f41f [wpimath] Fix pose estimator local measurement standard deviation docs (NFC) (#4113)
a2fa5e3ff7 [wpilibc] BatterySim: Provide non-initializer list versions of Calculate (#4076)
a3eea9958e [hal] Add link to FRC CAN Spec (NFC) (#4086)
db27331d7b [wpilib] Update DifferentialDrive docs (NFC) (#4085)
fdfb31f164 [dlt] Export boolean[] values (#4082)
f93c3331b3 [wpigui] disable changing directory when initializing on MacOS (#4092)
ab7ac4fbb9 [build] Fix various warnings in cmake builds (#4081)
bc39a1a293 [wpilibc] Fix moved pneumatics objects not destructing properly (#4068)
2668130e70 [wpimath] Remove SwerveDrivePoseEstimator encoder reset warning (#4066)
d27ed3722b [ci] Set actions workflow concurrency (#4060)
dae18308c9 [wpimath] Minor fixes to Rotation2d docs (NFC) (#4055)
d66555e42f [datalogtool] Add datalogtool
9f52d8a3b1 [wpilib] DriverStation: Add DataLog support for modes and joystick data
757ea91932 [wpilib] Add DataLogManager
02a804f1c5 [ntcore] Add DataLog support
9b500df0d9 [wpiutil] Add high speed data logging
5a89575b3a [wpiutil] Import customized LLVM MemoryBuffer
b8c4d7527b [wpiutil] Add MappedFileRegion
ac5d46cfa7 [wpilibc] Fix ProfiledPID SetTolerance default velocity value (#4054)
bc9e96e86f [wpilib] Absolute Encoder API and behavior fixes (#4052)
f88c435dd0 [hal] Add mechanism to cancel all periodic callbacks (#4049)
Change-Id: I49aa5b08abbefc7a045e99e19d48ce2cd8fc4d1b
git-subtree-dir: third_party/allwpilib
git-subtree-split: 83f1860047c86aa3330fcb41caf3b2047e074804
Signed-off-by: James Kuszmaul <jabukuszmaul+collab@gmail.com>
diff --git a/wpiutil/src/main/native/cpp/Base64.cpp b/wpiutil/src/main/native/cpp/Base64.cpp
index 8f1f810..bc1d3ba 100644
--- a/wpiutil/src/main/native/cpp/Base64.cpp
+++ b/wpiutil/src/main/native/cpp/Base64.cpp
@@ -138,8 +138,8 @@
return Base64Decode(os, encoded);
}
-span<uint8_t> Base64Decode(std::string_view encoded, size_t* num_read,
- SmallVectorImpl<uint8_t>& buf) {
+std::span<uint8_t> Base64Decode(std::string_view encoded, size_t* num_read,
+ SmallVectorImpl<uint8_t>& buf) {
buf.clear();
raw_usvector_ostream os(buf);
*num_read = Base64Decode(os, encoded);
@@ -193,19 +193,19 @@
return os.str();
}
-void Base64Encode(raw_ostream& os, span<const uint8_t> plain) {
+void Base64Encode(raw_ostream& os, std::span<const uint8_t> plain) {
Base64Encode(os, std::string_view{reinterpret_cast<const char*>(plain.data()),
plain.size()});
}
-void Base64Encode(span<const uint8_t> plain, std::string* encoded) {
+void Base64Encode(std::span<const uint8_t> plain, std::string* encoded) {
encoded->resize(0);
raw_string_ostream os(*encoded);
Base64Encode(os, plain);
os.flush();
}
-std::string_view Base64Encode(span<const uint8_t> plain,
+std::string_view Base64Encode(std::span<const uint8_t> plain,
SmallVectorImpl<char>& buf) {
buf.clear();
raw_svector_ostream os(buf);
diff --git a/wpiutil/src/main/native/cpp/DataLog.cpp b/wpiutil/src/main/native/cpp/DataLog.cpp
new file mode 100644
index 0000000..7009628
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/DataLog.cpp
@@ -0,0 +1,821 @@
+// 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/DataLog.h"
+
+#include "wpi/Synchronization.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h> // NOLINT(build/include_order)
+
+#endif
+
+#include <atomic>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <random>
+#include <vector>
+
+#include "fmt/format.h"
+#include "wpi/Endian.h"
+#include "wpi/Logger.h"
+#include "wpi/MathExtras.h"
+#include "wpi/fs.h"
+#include "wpi/timestamp.h"
+
+using namespace wpi::log;
+
+static constexpr size_t kBlockSize = 16 * 1024;
+static constexpr size_t kRecordMaxHeaderSize = 17;
+
+template <typename T>
+static unsigned int WriteVarInt(uint8_t* buf, T val) {
+ unsigned int len = 0;
+ do {
+ *buf++ = static_cast<unsigned int>(val) & 0xff;
+ ++len;
+ val >>= 8;
+ } while (val != 0);
+ return len;
+}
+
+// min size: 4, max size: 17
+static unsigned int WriteRecordHeader(uint8_t* buf, uint32_t entry,
+ uint64_t timestamp,
+ uint32_t payloadSize) {
+ uint8_t* origbuf = buf++;
+
+ unsigned int entryLen = WriteVarInt(buf, entry);
+ buf += entryLen;
+ unsigned int payloadLen = WriteVarInt(buf, payloadSize);
+ buf += payloadLen;
+ unsigned int timestampLen =
+ WriteVarInt(buf, timestamp == 0 ? wpi::Now() : timestamp);
+ buf += timestampLen;
+ *origbuf =
+ ((timestampLen - 1) << 4) | ((payloadLen - 1) << 2) | (entryLen - 1);
+ return buf - origbuf;
+}
+
+class DataLog::Buffer {
+ public:
+ explicit Buffer(size_t alloc = kBlockSize)
+ : m_buf{new uint8_t[alloc]}, m_maxLen{alloc} {}
+ ~Buffer() { delete[] m_buf; }
+
+ Buffer(const Buffer&) = delete;
+ Buffer& operator=(const Buffer&) = delete;
+
+ Buffer(Buffer&& oth)
+ : m_buf{oth.m_buf}, m_len{oth.m_len}, m_maxLen{oth.m_maxLen} {
+ oth.m_buf = nullptr;
+ oth.m_len = 0;
+ oth.m_maxLen = 0;
+ }
+
+ Buffer& operator=(Buffer&& oth) {
+ if (m_buf) {
+ delete[] m_buf;
+ }
+ m_buf = oth.m_buf;
+ m_len = oth.m_len;
+ m_maxLen = oth.m_maxLen;
+ oth.m_buf = nullptr;
+ oth.m_len = 0;
+ oth.m_maxLen = 0;
+ return *this;
+ }
+
+ uint8_t* Reserve(size_t size) {
+ assert(size <= GetRemaining());
+ uint8_t* rv = m_buf + m_len;
+ m_len += size;
+ return rv;
+ }
+
+ void Unreserve(size_t size) { m_len -= size; }
+
+ void Clear() { m_len = 0; }
+
+ size_t GetRemaining() const { return m_maxLen - m_len; }
+
+ std::span<uint8_t> GetData() { return {m_buf, m_len}; }
+ std::span<const uint8_t> GetData() const { return {m_buf, m_len}; }
+
+ private:
+ uint8_t* m_buf;
+ size_t m_len = 0;
+ size_t m_maxLen;
+};
+
+static void DefaultLog(unsigned int level, const char* file, unsigned int line,
+ const char* msg) {
+ if (level > wpi::WPI_LOG_INFO) {
+ fmt::print(stderr, "DataLog: {}\n", msg);
+ } else if (level == wpi::WPI_LOG_INFO) {
+ fmt::print("DataLog: {}\n", msg);
+ }
+}
+
+static wpi::Logger defaultMessageLog{DefaultLog};
+
+DataLog::DataLog(std::string_view dir, std::string_view filename, double period,
+ std::string_view extraHeader)
+ : DataLog{defaultMessageLog, dir, filename, period, extraHeader} {}
+
+DataLog::DataLog(wpi::Logger& msglog, std::string_view dir,
+ std::string_view filename, double period,
+ std::string_view extraHeader)
+ : m_msglog{msglog},
+ m_period{period},
+ m_extraHeader{extraHeader},
+ m_newFilename{filename},
+ m_thread{[this, dir = std::string{dir}] { WriterThreadMain(dir); }} {}
+
+DataLog::DataLog(std::function<void(std::span<const uint8_t> data)> write,
+ double period, std::string_view extraHeader)
+ : DataLog{defaultMessageLog, std::move(write), period, extraHeader} {}
+
+DataLog::DataLog(wpi::Logger& msglog,
+ std::function<void(std::span<const uint8_t> data)> write,
+ double period, std::string_view extraHeader)
+ : m_msglog{msglog},
+ m_period{period},
+ m_extraHeader{extraHeader},
+ m_thread{[this, write = std::move(write)] {
+ WriterThreadMain(std::move(write));
+ }} {}
+
+DataLog::~DataLog() {
+ {
+ std::scoped_lock lock{m_mutex};
+ m_active = false;
+ m_doFlush = true;
+ }
+ m_cond.notify_all();
+ m_thread.join();
+}
+
+void DataLog::SetFilename(std::string_view filename) {
+ {
+ std::scoped_lock lock{m_mutex};
+ m_newFilename = filename;
+ }
+ m_cond.notify_all();
+}
+
+void DataLog::Flush() {
+ {
+ std::scoped_lock lock{m_mutex};
+ m_doFlush = true;
+ }
+ m_cond.notify_all();
+}
+
+void DataLog::Pause() {
+ std::scoped_lock lock{m_mutex};
+ m_paused = true;
+}
+
+void DataLog::Resume() {
+ std::scoped_lock lock{m_mutex};
+ m_paused = false;
+}
+
+static void WriteToFile(fs::file_t f, std::span<const uint8_t> data,
+ std::string_view filename, wpi::Logger& msglog) {
+ do {
+#ifdef _WIN32
+ DWORD ret;
+ if (!WriteFile(f, data.data(), data.size(), &ret, nullptr)) {
+ WPI_ERROR(msglog, "Error writing to log file '{}': {}", filename,
+ GetLastError());
+ break;
+ }
+#else
+ ssize_t ret = ::write(f, data.data(), data.size());
+ if (ret < 0) {
+ // If it's a recoverable error, swallow it and retry the write
+ if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK) {
+ continue;
+ }
+
+ // Otherwise it's a non-recoverable error; quit trying
+ WPI_ERROR(msglog, "Error writing to log file '{}': {}", filename,
+ std::strerror(errno));
+ break;
+ }
+#endif
+
+ // The write may have written some or all of the data
+ data = data.subspan(ret);
+ } while (data.size() > 0);
+}
+
+static std::string MakeRandomFilename() {
+ // build random filename
+ static std::random_device dev;
+ static std::mt19937 rng(dev());
+ std::uniform_int_distribution<int> dist(0, 15);
+ const char* v = "0123456789abcdef";
+ std::string filename = "wpilog_";
+ for (int i = 0; i < 16; i++) {
+ filename += v[dist(rng)];
+ }
+ filename += ".wpilog";
+ return filename;
+}
+
+void DataLog::WriterThreadMain(std::string_view dir) {
+ std::chrono::duration<double> periodTime{m_period};
+
+ 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;
+ }
+ }
+
+ if (f == fs::kInvalidFile) {
+ WPI_ERROR(m_msglog, "Could not open log file, no log being saved");
+ } else {
+ WPI_INFO(m_msglog, "Logging to '{}'", (dirPath / filename).string());
+ }
+
+ // write header (version 1.0)
+ if (f != fs::kInvalidFile) {
+ const uint8_t header[] = {'W', 'P', 'I', 'L', 'O', 'G', 0, 1};
+ WriteToFile(f, header, filename, m_msglog);
+ uint8_t extraLen[4];
+ support::endian::write32le(extraLen, m_extraHeader.size());
+ WriteToFile(f, extraLen, filename, m_msglog);
+ if (m_extraHeader.size() > 0) {
+ WriteToFile(f,
+ {reinterpret_cast<const uint8_t*>(m_extraHeader.data()),
+ m_extraHeader.size()},
+ filename, m_msglog);
+ }
+ }
+
+ std::vector<Buffer> toWrite;
+
+ std::unique_lock lock{m_mutex};
+ while (m_active) {
+ 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()) {
+ auto newFilename = std::move(m_newFilename);
+ m_newFilename.clear();
+ lock.unlock();
+ // rename
+ if (filename != newFilename) {
+ fs::rename(dirPath / filename, dirPath / newFilename, ec);
+ }
+ if (ec) {
+ WPI_ERROR(m_msglog, "Could not rename log file from '{}' to '{}': {}",
+ filename, newFilename, ec.message());
+ } else {
+ WPI_INFO(m_msglog, "Renamed log file from '{}' to '{}'", filename,
+ newFilename);
+ }
+ filename = std::move(newFilename);
+ lock.lock();
+ }
+
+ if (doFlush || m_doFlush) {
+ // flush to file
+ m_doFlush = false;
+ if (m_outgoing.empty()) {
+ continue;
+ }
+ // swap outgoing with empty vector
+ toWrite.swap(m_outgoing);
+
+ if (f != fs::kInvalidFile) {
+ lock.unlock();
+ // write buffers to file
+ for (auto&& buf : toWrite) {
+ WriteToFile(f, buf.GetData(), filename, m_msglog);
+ }
+
+ // sync to storage
+#if defined(__linux__)
+ ::fdatasync(f);
+#elif defined(__APPLE__)
+ ::fsync(f);
+#endif
+ lock.lock();
+ }
+
+ // release buffers back to free list
+ for (auto&& buf : toWrite) {
+ buf.Clear();
+ m_free.emplace_back(std::move(buf));
+ }
+ toWrite.resize(0);
+ }
+ }
+
+ if (f != fs::kInvalidFile) {
+ fs::CloseFile(f);
+ }
+}
+
+void DataLog::WriterThreadMain(
+ std::function<void(std::span<const uint8_t> data)> write) {
+ std::chrono::duration<double> periodTime{m_period};
+
+ // write header (version 1.0)
+ {
+ const uint8_t header[] = {'W', 'P', 'I', 'L', 'O', 'G', 0, 1};
+ write(header);
+ uint8_t extraLen[4];
+ support::endian::write32le(extraLen, m_extraHeader.size());
+ write(extraLen);
+ if (m_extraHeader.size() > 0) {
+ write({reinterpret_cast<const uint8_t*>(m_extraHeader.data()),
+ m_extraHeader.size()});
+ }
+ }
+
+ std::vector<Buffer> toWrite;
+
+ std::unique_lock lock{m_mutex};
+ while (m_active) {
+ 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 (doFlush || m_doFlush) {
+ // flush to file
+ m_doFlush = false;
+ if (m_outgoing.empty()) {
+ continue;
+ }
+ // swap outgoing with empty vector
+ toWrite.swap(m_outgoing);
+
+ lock.unlock();
+ // write buffers
+ for (auto&& buf : toWrite) {
+ if (!buf.GetData().empty()) {
+ write(buf.GetData());
+ }
+ }
+ lock.lock();
+
+ // release buffers back to free list
+ for (auto&& buf : toWrite) {
+ buf.Clear();
+ m_free.emplace_back(std::move(buf));
+ }
+ toWrite.resize(0);
+ }
+ }
+
+ write({}); // indicate EOF
+}
+
+// Control records use the following format:
+// 1-byte type
+// 4-byte entry
+// rest of data (depending on type)
+
+int DataLog::Start(std::string_view name, std::string_view type,
+ std::string_view metadata, int64_t timestamp) {
+ std::scoped_lock lock{m_mutex};
+ auto& entryInfo = m_entries[name];
+ if (entryInfo.id == 0) {
+ entryInfo.id = ++m_lastId;
+ }
+ auto& savedCount = m_entryCounts[entryInfo.id];
+ ++savedCount;
+ if (savedCount > 1) {
+ if (entryInfo.type != type) {
+ WPI_ERROR(m_msglog,
+ "type mismatch for '{}': was '{}', requested '{}'; ignoring",
+ name, entryInfo.type, type);
+ return 0;
+ }
+ return entryInfo.id;
+ }
+ entryInfo.type = type;
+ 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);
+ AppendStringImpl(name);
+ AppendStringImpl(type);
+ AppendStringImpl(metadata);
+
+ return entryInfo.id;
+}
+
+void DataLog::Finish(int entry, int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ auto& savedCount = m_entryCounts[entry];
+ if (savedCount == 0) {
+ return;
+ }
+ --savedCount;
+ if (savedCount != 0) {
+ return;
+ }
+ m_entryCounts.erase(entry);
+ uint8_t* buf = StartRecord(0, timestamp, 5, 5);
+ *buf++ = impl::kControlFinish;
+ wpi::support::endian::write32le(buf, entry);
+}
+
+void DataLog::SetMetadata(int entry, std::string_view metadata,
+ int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ uint8_t* buf = StartRecord(0, timestamp, 5 + 4 + metadata.size(), 5);
+ *buf++ = impl::kControlSetMetadata;
+ wpi::support::endian::write32le(buf, entry);
+ AppendStringImpl(metadata);
+}
+
+uint8_t* DataLog::Reserve(size_t size) {
+ assert(size <= kBlockSize);
+ if (m_outgoing.empty() || size > m_outgoing.back().GetRemaining()) {
+ if (m_free.empty()) {
+ m_outgoing.emplace_back();
+ } else {
+ m_outgoing.emplace_back(std::move(m_free.back()));
+ m_free.pop_back();
+ }
+ }
+ return m_outgoing.back().Reserve(size);
+}
+
+uint8_t* DataLog::StartRecord(uint32_t entry, uint64_t timestamp,
+ uint32_t payloadSize, size_t reserveSize) {
+ uint8_t* buf = Reserve(kRecordMaxHeaderSize + reserveSize);
+ auto headerLen = WriteRecordHeader(buf, entry, timestamp, payloadSize);
+ m_outgoing.back().Unreserve(kRecordMaxHeaderSize - headerLen);
+ buf += headerLen;
+ return buf;
+}
+
+void DataLog::AppendImpl(std::span<const uint8_t> data) {
+ while (data.size() > kBlockSize) {
+ uint8_t* buf = Reserve(kBlockSize);
+ std::memcpy(buf, data.data(), kBlockSize);
+ data = data.subspan(kBlockSize);
+ }
+ uint8_t* buf = Reserve(data.size());
+ std::memcpy(buf, data.data(), data.size());
+}
+
+void DataLog::AppendStringImpl(std::string_view str) {
+ uint8_t* buf = Reserve(4);
+ wpi::support::endian::write32le(buf, str.size());
+ AppendImpl({reinterpret_cast<const uint8_t*>(str.data()), str.size()});
+}
+
+void DataLog::AppendRaw(int entry, std::span<const uint8_t> data,
+ int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ StartRecord(entry, timestamp, data.size(), 0);
+ AppendImpl(data);
+}
+
+void DataLog::AppendRaw2(int entry,
+ std::span<const std::span<const uint8_t>> data,
+ int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ size_t size = 0;
+ for (auto&& chunk : data) {
+ size += chunk.size();
+ }
+ StartRecord(entry, timestamp, size, 0);
+ for (auto chunk : data) {
+ AppendImpl(chunk);
+ }
+}
+
+void DataLog::AppendBoolean(int entry, bool value, int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ uint8_t* buf = StartRecord(entry, timestamp, 1, 1);
+ buf[0] = value ? 1 : 0;
+}
+
+void DataLog::AppendInteger(int entry, int64_t value, int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ uint8_t* buf = StartRecord(entry, timestamp, 8, 8);
+ wpi::support::endian::write64le(buf, value);
+}
+
+void DataLog::AppendFloat(int entry, float value, int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ 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));
+ }
+}
+
+void DataLog::AppendDouble(int entry, double value, int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ 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));
+ }
+}
+
+void DataLog::AppendString(int entry, std::string_view value,
+ int64_t timestamp) {
+ AppendRaw(entry,
+ {reinterpret_cast<const uint8_t*>(value.data()), value.size()},
+ timestamp);
+}
+
+void DataLog::AppendBooleanArray(int entry, std::span<const bool> arr,
+ int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ StartRecord(entry, timestamp, arr.size(), 0);
+ uint8_t* buf;
+ while (arr.size() > kBlockSize) {
+ buf = Reserve(kBlockSize);
+ for (auto val : arr.subspan(0, kBlockSize)) {
+ *buf++ = val ? 1 : 0;
+ }
+ arr = arr.subspan(kBlockSize);
+ }
+ buf = Reserve(arr.size());
+ for (auto val : arr) {
+ *buf++ = val ? 1 : 0;
+ }
+}
+
+void DataLog::AppendBooleanArray(int entry, std::span<const int> arr,
+ int64_t timestamp) {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ StartRecord(entry, timestamp, arr.size(), 0);
+ uint8_t* buf;
+ while (arr.size() > kBlockSize) {
+ buf = Reserve(kBlockSize);
+ for (auto val : arr.subspan(0, kBlockSize)) {
+ *buf++ = val & 1;
+ }
+ arr = arr.subspan(kBlockSize);
+ }
+ buf = Reserve(arr.size());
+ for (auto val : arr) {
+ *buf++ = val & 1;
+ }
+}
+
+void DataLog::AppendBooleanArray(int entry, std::span<const uint8_t> arr,
+ int64_t timestamp) {
+ AppendRaw(entry, arr, timestamp);
+}
+
+void DataLog::AppendIntegerArray(int entry, std::span<const int64_t> arr,
+ int64_t timestamp) {
+ if constexpr (wpi::support::endian::system_endianness() ==
+ wpi::support::little) {
+ AppendRaw(entry,
+ {reinterpret_cast<const uint8_t*>(arr.data()), arr.size() * 8},
+ timestamp);
+ } else {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ 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, val);
+ buf += 8;
+ }
+ arr = arr.subspan(kBlockSize / 8);
+ }
+ buf = Reserve(arr.size() * 8);
+ for (auto val : arr) {
+ wpi::support::endian::write64le(buf, val);
+ buf += 8;
+ }
+ }
+}
+
+void DataLog::AppendFloatArray(int entry, std::span<const float> arr,
+ int64_t timestamp) {
+ if constexpr (wpi::support::endian::system_endianness() ==
+ wpi::support::little) {
+ AppendRaw(entry,
+ {reinterpret_cast<const uint8_t*>(arr.data()), arr.size() * 4},
+ timestamp);
+ } else {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ 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));
+ buf += 4;
+ }
+ arr = arr.subspan(kBlockSize / 4);
+ }
+ buf = Reserve(arr.size() * 4);
+ for (auto val : arr) {
+ wpi::support::endian::write32le(buf, wpi::FloatToBits(val));
+ buf += 4;
+ }
+ }
+}
+
+void DataLog::AppendDoubleArray(int entry, std::span<const double> arr,
+ int64_t timestamp) {
+ if constexpr (wpi::support::endian::system_endianness() ==
+ wpi::support::little) {
+ AppendRaw(entry,
+ {reinterpret_cast<const uint8_t*>(arr.data()), arr.size() * 8},
+ timestamp);
+ } else {
+ if (entry <= 0) {
+ return;
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ 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));
+ buf += 8;
+ }
+ arr = arr.subspan(kBlockSize / 8);
+ }
+ buf = Reserve(arr.size() * 8);
+ for (auto val : arr) {
+ wpi::support::endian::write64le(buf, wpi::DoubleToBits(val));
+ buf += 8;
+ }
+ }
+}
+
+void DataLog::AppendStringArray(int entry, std::span<const std::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.size();
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ uint8_t* buf = StartRecord(entry, timestamp, size, 4);
+ wpi::support::endian::write32le(buf, arr.size());
+ for (auto&& str : arr) {
+ AppendStringImpl(str);
+ }
+}
+
+void DataLog::AppendStringArray(int entry,
+ std::span<const std::string_view> 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.size();
+ }
+ std::scoped_lock lock{m_mutex};
+ if (m_paused) {
+ return;
+ }
+ uint8_t* buf = StartRecord(entry, timestamp, size, 4);
+ wpi::support::endian::write32le(buf, arr.size());
+ for (auto sv : arr) {
+ AppendStringImpl(sv);
+ }
+}
diff --git a/wpiutil/src/main/native/cpp/DataLogReader.cpp b/wpiutil/src/main/native/cpp/DataLogReader.cpp
new file mode 100644
index 0000000..96f6689
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/DataLogReader.cpp
@@ -0,0 +1,307 @@
+// 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/DataLogReader.h"
+
+#include "wpi/DataLog.h"
+#include "wpi/Endian.h"
+#include "wpi/MathExtras.h"
+
+using namespace wpi::log;
+
+static bool ReadString(std::span<const uint8_t>* buf, std::string_view* str) {
+ if (buf->size() < 4) {
+ *str = {};
+ return false;
+ }
+ uint32_t len = wpi::support::endian::read32le(buf->data());
+ if (len > (buf->size() - 4)) {
+ *str = {};
+ return false;
+ }
+ *str = {reinterpret_cast<const char*>(buf->data() + 4), len};
+ *buf = buf->subspan(len + 4);
+ return true;
+}
+
+bool DataLogRecord::IsStart() const {
+ return m_entry == 0 && m_data.size() >= 17 &&
+ m_data[0] == impl::kControlStart;
+}
+
+bool DataLogRecord::IsFinish() const {
+ return m_entry == 0 && m_data.size() == 5 &&
+ m_data[0] == impl::kControlFinish;
+}
+
+bool DataLogRecord::IsSetMetadata() const {
+ return m_entry == 0 && m_data.size() >= 9 &&
+ m_data[0] == impl::kControlSetMetadata;
+}
+
+bool DataLogRecord::GetStartData(StartRecordData* out) const {
+ if (!IsStart()) {
+ return false;
+ }
+ out->entry = wpi::support::endian::read32le(&m_data[1]);
+ auto buf = m_data.subspan(5);
+ if (!ReadString(&buf, &out->name)) {
+ return false;
+ }
+ if (!ReadString(&buf, &out->type)) {
+ return false;
+ }
+ if (!ReadString(&buf, &out->metadata)) {
+ return false;
+ }
+ return true;
+}
+
+bool DataLogRecord::GetFinishEntry(int* out) const {
+ if (!IsFinish()) {
+ return false;
+ }
+ *out = wpi::support::endian::read32le(&m_data[1]);
+ return true;
+}
+
+bool DataLogRecord::GetSetMetadataData(MetadataRecordData* out) const {
+ if (!IsSetMetadata()) {
+ return false;
+ }
+ out->entry = wpi::support::endian::read32le(&m_data[1]);
+ auto buf = m_data.subspan(5);
+ return ReadString(&buf, &out->metadata);
+}
+
+bool DataLogRecord::GetBoolean(bool* value) const {
+ if (m_data.size() != 1) {
+ return false;
+ }
+ *value = m_data[0] != 0;
+ return true;
+}
+
+bool DataLogRecord::GetInteger(int64_t* value) const {
+ if (m_data.size() != 8) {
+ return false;
+ }
+ *value = wpi::support::endian::read64le(m_data.data());
+ return true;
+}
+
+bool DataLogRecord::GetFloat(float* value) const {
+ if (m_data.size() != 4) {
+ return false;
+ }
+ *value = wpi::BitsToFloat(wpi::support::endian::read32le(m_data.data()));
+ return true;
+}
+
+bool DataLogRecord::GetDouble(double* value) const {
+ if (m_data.size() != 8) {
+ return false;
+ }
+ *value = wpi::BitsToDouble(wpi::support::endian::read64le(m_data.data()));
+ return true;
+}
+
+bool DataLogRecord::GetString(std::string_view* value) const {
+ *value = {reinterpret_cast<const char*>(m_data.data()), m_data.size()};
+ return true;
+}
+
+bool DataLogRecord::GetBooleanArray(std::vector<int>* arr) const {
+ arr->clear();
+ arr->reserve(m_data.size());
+ for (auto v : m_data) {
+ arr->push_back(v);
+ }
+ return true;
+}
+
+bool DataLogRecord::GetIntegerArray(std::vector<int64_t>* arr) const {
+ arr->clear();
+ if ((m_data.size() % 8) != 0) {
+ return false;
+ }
+ arr->reserve(m_data.size() / 8);
+ for (size_t pos = 0; pos < m_data.size(); pos += 8) {
+ arr->push_back(wpi::support::endian::read64le(&m_data[pos]));
+ }
+ return true;
+}
+
+bool DataLogRecord::GetFloatArray(std::vector<float>* arr) const {
+ arr->clear();
+ if ((m_data.size() % 4) != 0) {
+ return false;
+ }
+ 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])));
+ }
+ return true;
+}
+
+bool DataLogRecord::GetDoubleArray(std::vector<double>* arr) const {
+ arr->clear();
+ if ((m_data.size() % 8) != 0) {
+ return false;
+ }
+ 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])));
+ }
+ return true;
+}
+
+bool DataLogRecord::GetStringArray(std::vector<std::string_view>* arr) const {
+ arr->clear();
+ if (m_data.size() < 4) {
+ return false;
+ }
+ uint32_t size = wpi::support::endian::read32le(m_data.data());
+ // sanity check size
+ if (size > ((m_data.size() - 4) / 4)) {
+ return false;
+ }
+ auto buf = m_data.subspan(4);
+ arr->reserve(size);
+ for (uint32_t i = 0; i < size; ++i) {
+ std::string_view str;
+ if (!ReadString(&buf, &str)) {
+ arr->clear();
+ return false;
+ }
+ arr->push_back(str);
+ }
+ // any left over? treat as corrupt
+ if (!buf.empty()) {
+ arr->clear();
+ return false;
+ }
+ return true;
+}
+
+DataLogReader::DataLogReader(std::unique_ptr<MemoryBuffer> buffer)
+ : m_buf{std::move(buffer)} {}
+
+bool DataLogReader::IsValid() const {
+ if (!m_buf) {
+ return false;
+ }
+ auto buf = m_buf->GetBuffer();
+ return buf.size() >= 12 &&
+ std::string_view{reinterpret_cast<const char*>(buf.data()), 6} ==
+ "WPILOG" &&
+ wpi::support::endian::read16le(&buf[6]) >= 0x0100;
+}
+
+uint16_t DataLogReader::GetVersion() const {
+ if (!m_buf) {
+ return 0;
+ }
+ auto buf = m_buf->GetBuffer();
+ if (buf.size() < 12) {
+ return 0;
+ }
+ return wpi::support::endian::read16le(&buf[6]);
+}
+
+std::string_view DataLogReader::GetExtraHeader() const {
+ if (!m_buf) {
+ return {};
+ }
+ auto buf = m_buf->GetBuffer();
+ if (buf.size() < 8) {
+ return {};
+ }
+ std::string_view rv;
+ buf = buf.subspan(8);
+ ReadString(&buf, &rv);
+ return rv;
+}
+
+DataLogReader::iterator DataLogReader::begin() const {
+ if (!m_buf) {
+ return end();
+ }
+ auto buf = m_buf->GetBuffer();
+ if (buf.size() < 12) {
+ return end();
+ }
+ uint32_t size = wpi::support::endian::read32le(&buf[8]);
+ if (buf.size() < (12 + size)) {
+ return end();
+ }
+ return DataLogIterator{this, 12 + size};
+}
+
+static uint64_t ReadVarInt(std::span<const uint8_t> buf) {
+ uint64_t val = 0;
+ int shift = 0;
+ for (auto v : buf) {
+ val |= static_cast<uint64_t>(v) << shift;
+ shift += 8;
+ }
+ return val;
+}
+
+bool DataLogReader::GetRecord(size_t* pos, DataLogRecord* out) const {
+ if (!m_buf) {
+ return false;
+ }
+ auto buf = m_buf->GetBuffer();
+ if (*pos >= buf.size()) {
+ return false;
+ }
+ buf = buf.subspan(*pos);
+ if (buf.size() < 4) { // minimum header length
+ return false;
+ }
+ unsigned int entryLen = (buf[0] & 0x3) + 1;
+ unsigned int sizeLen = ((buf[0] >> 2) & 0x3) + 1;
+ unsigned int timestampLen = ((buf[0] >> 4) & 0x7) + 1;
+ unsigned int headerLen = 1 + entryLen + sizeLen + timestampLen;
+ if (buf.size() < headerLen) {
+ return false;
+ }
+ int entry = ReadVarInt(buf.subspan(1, entryLen));
+ uint32_t size = ReadVarInt(buf.subspan(1 + entryLen, sizeLen));
+ if (size > (buf.size() - headerLen)) {
+ return false;
+ }
+ int64_t timestamp =
+ ReadVarInt(buf.subspan(1 + entryLen + sizeLen, timestampLen));
+ *out = DataLogRecord{entry, timestamp, buf.subspan(headerLen, size)};
+ *pos += headerLen + size;
+ return true;
+}
+
+bool DataLogReader::GetNextRecord(size_t* pos) const {
+ if (!m_buf) {
+ return false;
+ }
+ auto buf = m_buf->GetBuffer();
+ if (buf.size() < (*pos + 4)) { // minimum header length
+ return false;
+ }
+ unsigned int entryLen = (buf[*pos] & 0x3) + 1;
+ unsigned int sizeLen = ((buf[*pos] >> 2) & 0x3) + 1;
+ unsigned int timestampLen = ((buf[*pos] >> 4) & 0x7) + 1;
+ unsigned int headerLen = 1 + entryLen + sizeLen + timestampLen;
+ if (buf.size() < (*pos + headerLen)) {
+ return false;
+ }
+ uint32_t size = ReadVarInt(buf.subspan(*pos + 1 + entryLen, sizeLen));
+ // check this way to avoid overflow
+ if (size >= (buf.size() - *pos - headerLen)) {
+ return false;
+ }
+ *pos += headerLen + size;
+ return true;
+}
diff --git a/wpiutil/src/main/native/cpp/DsClient.cpp b/wpiutil/src/main/native/cpp/DsClient.cpp
deleted file mode 100644
index 455f10c..0000000
--- a/wpiutil/src/main/native/cpp/DsClient.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
-// 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/DsClient.h"
-
-#include <fmt/format.h>
-#include <wpi/StringExtras.h>
-#include <wpi/json.h>
-#include <wpi/uv/Tcp.h>
-#include <wpi/uv/Timer.h>
-
-#include "wpi/Logger.h"
-
-using namespace wpi;
-
-static constexpr uv::Timer::Time kReconnectTime{500};
-
-DsClient::DsClient(wpi::uv::Loop& loop, wpi::Logger& logger,
- const private_init&)
- : m_logger{logger},
- m_tcp{uv::Tcp::Create(loop)},
- m_timer{uv::Timer::Create(loop)} {
- m_tcp->end.connect([this] {
- WPI_DEBUG4(m_logger, "{}", "DS connection closed");
- clearIp();
- // try to connect again
- m_tcp->Reuse([this] { m_timer->Start(kReconnectTime); });
- });
- m_tcp->data.connect([this](wpi::uv::Buffer buf, size_t len) {
- HandleIncoming({buf.base, len});
- });
- m_timer->timeout.connect([this] { Connect(); });
- Connect();
-}
-
-DsClient::~DsClient() = default;
-
-void DsClient::Close() {
- m_tcp->Close();
- m_timer->Close();
- clearIp();
-}
-
-void DsClient::Connect() {
- auto connreq = std::make_shared<uv::TcpConnectReq>();
- connreq->connected.connect([this] {
- m_json.clear();
- m_tcp->StopRead();
- m_tcp->StartRead();
- });
-
- connreq->error = [this](uv::Error err) {
- WPI_DEBUG4(m_logger, "DS connect failure: {}", err.str());
- // try to connect again
- m_tcp->Reuse([this] { m_timer->Start(kReconnectTime); });
- };
-
- WPI_DEBUG4(m_logger, "{}", "Starting DS connection attempt");
- m_tcp->Connect("127.0.0.1", 1742, connreq);
-}
-
-void DsClient::HandleIncoming(std::string_view in) {
- // this is very bare-bones, as there are never nested {} in these messages
- while (!in.empty()) {
- // if json is empty, look for the first { (and discard)
- if (m_json.empty()) {
- auto start = in.find('{');
- in = wpi::slice(in, start, std::string_view::npos);
- }
-
- // look for the terminating } (and save)
- auto end = in.find('}');
- if (end == std::string_view::npos) {
- m_json.append(in);
- return; // nothing left to read
- }
-
- // have complete json message
- ++end;
- m_json.append(wpi::slice(in, 0, end));
- in = wpi::slice(in, end, std::string_view::npos);
- ParseJson();
- m_json.clear();
- }
-}
-
-void DsClient::ParseJson() {
- WPI_DEBUG4(m_logger, "DsClient JSON: {}", m_json);
- unsigned int ip = 0;
- try {
- ip = wpi::json::parse(m_json).at("robotIP").get<unsigned int>();
- } catch (wpi::json::exception& e) {
- WPI_INFO(m_logger, "DsClient JSON error: {}", e.what());
- return;
- }
-
- if (ip == 0) {
- clearIp();
- } else {
- // Convert number into dotted quad
- auto newip = fmt::format("{}.{}.{}.{}", (ip >> 24) & 0xff,
- (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
- WPI_INFO(m_logger, "DS received server IP: {}", newip);
- setIp(newip);
- }
-}
diff --git a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp b/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
deleted file mode 100644
index c86176e..0000000
--- a/wpiutil/src/main/native/cpp/EventLoopRunner.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-// 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/EventLoopRunner.h"
-
-#include "wpi/SmallVector.h"
-#include "wpi/condition_variable.h"
-#include "wpi/mutex.h"
-#include "wpi/uv/AsyncFunction.h"
-#include "wpi/uv/Loop.h"
-
-using namespace wpi;
-
-class EventLoopRunner::Thread : public SafeThread {
- public:
- using UvExecFunc = uv::AsyncFunction<void(LoopFunc)>;
-
- Thread() : m_loop(uv::Loop::Create()) {
- // set up async handles
- if (!m_loop) {
- return;
- }
-
- // run function
- m_doExec = UvExecFunc::Create(
- m_loop, [loop = m_loop.get()](auto out, LoopFunc func) {
- func(*loop);
- out.set_value();
- });
- }
-
- void Main() override {
- if (m_loop) {
- m_loop->Run();
- }
- }
-
- // the loop
- std::shared_ptr<uv::Loop> m_loop;
-
- // run function
- std::weak_ptr<UvExecFunc> m_doExec;
-};
-
-EventLoopRunner::EventLoopRunner() {
- m_owner.Start();
-}
-
-EventLoopRunner::~EventLoopRunner() {
- Stop();
-}
-
-void EventLoopRunner::Stop() {
- ExecAsync([](uv::Loop& loop) {
- // close all handles; this will (eventually) stop the loop
- loop.Walk([](uv::Handle& h) {
- h.SetLoopClosing(true);
- h.Close();
- });
- });
- m_owner.Join();
-}
-
-void EventLoopRunner::ExecAsync(LoopFunc func) {
- if (auto thr = m_owner.GetThread()) {
- if (auto doExec = thr->m_doExec.lock()) {
- doExec->Call(std::move(func));
- }
- }
-}
-
-void EventLoopRunner::ExecSync(LoopFunc func) {
- wpi::future<void> f;
- if (auto thr = m_owner.GetThread()) {
- if (auto doExec = thr->m_doExec.lock()) {
- f = doExec->Call(std::move(func));
- }
- }
- if (f.valid()) {
- f.wait();
- }
-}
-
-std::shared_ptr<uv::Loop> EventLoopRunner::GetLoop() {
- if (auto thr = m_owner.GetThread()) {
- return thr->m_loop;
- }
- return nullptr;
-}
diff --git a/wpiutil/src/main/native/cpp/HttpParser.cpp b/wpiutil/src/main/native/cpp/HttpParser.cpp
deleted file mode 100644
index 3c18e0f..0000000
--- a/wpiutil/src/main/native/cpp/HttpParser.cpp
+++ /dev/null
@@ -1,193 +0,0 @@
-// 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/HttpParser.h"
-
-using namespace wpi;
-
-uint32_t HttpParser::GetParserVersion() {
- return static_cast<uint32_t>(http_parser_version());
-}
-
-HttpParser::HttpParser(Type type) {
- http_parser_init(&m_parser,
- static_cast<http_parser_type>(static_cast<int>(type)));
- m_parser.data = this;
-
- http_parser_settings_init(&m_settings);
-
- // Unlike the underlying http_parser library, we don't perform callbacks
- // (other than body) with partial data; instead we buffer and call the user
- // callback only when the data is complete.
-
- // on_message_begin: initialize our state, call user callback
- m_settings.on_message_begin = [](http_parser* p) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- self.m_urlBuf.clear();
- self.m_state = kStart;
- self.messageBegin();
- return self.m_aborted;
- };
-
- // on_url: collect into buffer
- m_settings.on_url = [](http_parser* p, const char* at, size_t length) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- // append to buffer
- if ((self.m_urlBuf.size() + length) > self.m_maxLength) {
- return 1;
- }
- self.m_urlBuf += std::string_view{at, length};
- self.m_state = kUrl;
- return 0;
- };
-
- // on_status: collect into buffer, call user URL callback
- m_settings.on_status = [](http_parser* p, const char* at,
- size_t length) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- // use valueBuf for the status
- if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
- return 1;
- }
- self.m_valueBuf += std::string_view{at, length};
- self.m_state = kStatus;
- return 0;
- };
-
- // on_header_field: collect into buffer, call user header/status callback
- m_settings.on_header_field = [](http_parser* p, const char* at,
- size_t length) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
-
- // once we're in header, we know the URL is complete
- if (self.m_state == kUrl) {
- self.url(self.m_urlBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- // once we're in header, we know the status is complete
- if (self.m_state == kStatus) {
- self.status(self.m_valueBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- // if we previously were in value state, that means we finished a header
- if (self.m_state == kValue) {
- self.header(self.m_fieldBuf, self.m_valueBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- // clear field and value when we enter this state
- if (self.m_state != kField) {
- self.m_state = kField;
- self.m_fieldBuf.clear();
- self.m_valueBuf.clear();
- }
-
- // append data to field buffer
- if ((self.m_fieldBuf.size() + length) > self.m_maxLength) {
- return 1;
- }
- self.m_fieldBuf += std::string_view{at, length};
- return 0;
- };
-
- // on_header_field: collect into buffer
- m_settings.on_header_value = [](http_parser* p, const char* at,
- size_t length) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
-
- // if we weren't previously in value state, clear the buffer
- if (self.m_state != kValue) {
- self.m_state = kValue;
- self.m_valueBuf.clear();
- }
-
- // append data to value buffer
- if ((self.m_valueBuf.size() + length) > self.m_maxLength) {
- return 1;
- }
- self.m_valueBuf += std::string_view{at, length};
- return 0;
- };
-
- // on_headers_complete: call user status/header/complete callback
- m_settings.on_headers_complete = [](http_parser* p) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
-
- // if we previously were in url state, that means we finished the url
- if (self.m_state == kUrl) {
- self.url(self.m_urlBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- // if we previously were in status state, that means we finished the status
- if (self.m_state == kStatus) {
- self.status(self.m_valueBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- // if we previously were in value state, that means we finished a header
- if (self.m_state == kValue) {
- self.header(self.m_fieldBuf, self.m_valueBuf);
- if (self.m_aborted) {
- return 1;
- }
- }
-
- self.headersComplete(self.ShouldKeepAlive());
- return self.m_aborted;
- };
-
- // on_body: call user callback
- m_settings.on_body = [](http_parser* p, const char* at,
- size_t length) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- self.body(std::string_view{at, length}, self.IsBodyFinal());
- return self.m_aborted;
- };
-
- // on_message_complete: call user callback
- m_settings.on_message_complete = [](http_parser* p) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- self.messageComplete(self.ShouldKeepAlive());
- return self.m_aborted;
- };
-
- // on_chunk_header: call user callback
- m_settings.on_chunk_header = [](http_parser* p) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- self.chunkHeader(p->content_length);
- return self.m_aborted;
- };
-
- // on_chunk_complete: call user callback
- m_settings.on_chunk_complete = [](http_parser* p) -> int {
- auto& self = *static_cast<HttpParser*>(p->data);
- self.chunkComplete();
- return self.m_aborted;
- };
-}
-
-void HttpParser::Reset(Type type) {
- http_parser_init(&m_parser,
- static_cast<http_parser_type>(static_cast<int>(type)));
- m_parser.data = this;
- m_maxLength = 1024;
- m_state = kStart;
- m_urlBuf.clear();
- m_fieldBuf.clear();
- m_valueBuf.clear();
- m_aborted = false;
-}
diff --git a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp b/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
deleted file mode 100644
index 716d2af..0000000
--- a/wpiutil/src/main/native/cpp/HttpServerConnection.cpp
+++ /dev/null
@@ -1,178 +0,0 @@
-// 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/HttpServerConnection.h"
-
-#include "fmt/format.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/SpanExtras.h"
-#include "wpi/StringExtras.h"
-#include "wpi/fmt/raw_ostream.h"
-#include "wpi/raw_uv_ostream.h"
-
-using namespace wpi;
-
-HttpServerConnection::HttpServerConnection(std::shared_ptr<uv::Stream> stream)
- : m_stream(*stream) {
- // process HTTP messages
- m_messageCompleteConn =
- m_request.messageComplete.connect_connection([this](bool keepAlive) {
- m_keepAlive = keepAlive;
- ProcessRequest();
- });
-
- // look for Accept-Encoding headers to determine if gzip is acceptable
- m_request.messageBegin.connect([this] { m_acceptGzip = false; });
- m_request.header.connect(
- [this](std::string_view name, std::string_view value) {
- if (wpi::equals_lower(name, "accept-encoding") &&
- wpi::contains(value, "gzip")) {
- m_acceptGzip = true;
- }
- });
-
- // pass incoming data to HTTP parser
- m_dataConn =
- stream->data.connect_connection([this](uv::Buffer& buf, size_t size) {
- m_request.Execute({buf.base, size});
- if (m_request.HasError()) {
- // could not parse; just close the connection
- m_stream.Close();
- }
- });
-
- // close when remote side closes
- m_endConn =
- stream->end.connect_connection([h = stream.get()] { h->Close(); });
-
- // start reading
- stream->StartRead();
-}
-
-void HttpServerConnection::BuildCommonHeaders(raw_ostream& os) {
- os << "Server: WebServer/1.0\r\n"
- "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, "
- "post-check=0, max-age=0\r\n"
- "Pragma: no-cache\r\n"
- "Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n";
-}
-
-void HttpServerConnection::BuildHeader(raw_ostream& os, int code,
- std::string_view codeText,
- std::string_view contentType,
- uint64_t contentLength,
- std::string_view extra) {
- fmt::print(os, "HTTP/{}.{} {} {}\r\n", m_request.GetMajor(),
- m_request.GetMinor(), code, codeText);
- if (contentLength == 0) {
- m_keepAlive = false;
- }
- if (!m_keepAlive) {
- os << "Connection: close\r\n";
- }
- BuildCommonHeaders(os);
- os << "Content-Type: " << contentType << "\r\n";
- if (contentLength != 0) {
- fmt::print(os, "Content-Length: {}\r\n", contentLength);
- }
- os << "Access-Control-Allow-Origin: *\r\nAccess-Control-Allow-Methods: *\r\n";
- if (!extra.empty()) {
- os << extra;
- }
- os << "\r\n"; // header ends with a blank line
-}
-
-void HttpServerConnection::SendData(span<const uv::Buffer> bufs,
- bool closeAfter) {
- m_stream.Write(bufs, [closeAfter, stream = &m_stream](auto bufs, uv::Error) {
- for (auto&& buf : bufs) {
- buf.Deallocate();
- }
- if (closeAfter) {
- stream->Close();
- }
- });
-}
-
-void HttpServerConnection::SendResponse(int code, std::string_view codeText,
- std::string_view contentType,
- std::string_view content,
- std::string_view extraHeader) {
- SmallVector<uv::Buffer, 4> toSend;
- raw_uv_ostream os{toSend, 4096};
- BuildHeader(os, code, codeText, contentType, content.size(), extraHeader);
- os << content;
- // close after write completes if we aren't keeping alive
- SendData(os.bufs(), !m_keepAlive);
-}
-
-void HttpServerConnection::SendStaticResponse(
- int code, std::string_view codeText, std::string_view contentType,
- std::string_view content, bool gzipped, std::string_view extraHeader) {
- // TODO: handle remote side not accepting gzip (very rare)
-
- std::string_view contentEncodingHeader;
- if (gzipped /* && m_acceptGzip*/) {
- contentEncodingHeader = "Content-Encoding: gzip\r\n";
- }
-
- SmallVector<uv::Buffer, 4> bufs;
- raw_uv_ostream os{bufs, 4096};
- BuildHeader(os, code, codeText, contentType, content.size(),
- fmt::format("{}{}", extraHeader, contentEncodingHeader));
- // can send content without copying
- bufs.emplace_back(content);
-
- m_stream.Write(bufs, [closeAfter = !m_keepAlive, stream = &m_stream](
- auto bufs, uv::Error) {
- // don't deallocate the static content
- for (auto&& buf : wpi::drop_back(bufs)) {
- buf.Deallocate();
- }
- if (closeAfter) {
- stream->Close();
- }
- });
-}
-
-void HttpServerConnection::SendError(int code, std::string_view message) {
- std::string_view codeText, extra, baseMessage;
- switch (code) {
- case 401:
- codeText = "Unauthorized";
- extra = "WWW-Authenticate: Basic realm=\"CameraServer\"";
- baseMessage = "401: Not Authenticated!";
- break;
- case 404:
- codeText = "Not Found";
- baseMessage = "404: Not Found!";
- break;
- case 500:
- codeText = "Internal Server Error";
- baseMessage = "500: Internal Server Error!";
- break;
- case 400:
- codeText = "Bad Request";
- baseMessage = "400: Not Found!";
- break;
- case 403:
- codeText = "Forbidden";
- baseMessage = "403: Forbidden!";
- break;
- case 503:
- codeText = "Service Unavailable";
- baseMessage = "503: Service Unavailable";
- break;
- default:
- code = 501;
- codeText = "Not Implemented";
- baseMessage = "501: Not Implemented!";
- break;
- }
- SmallString<256> content{baseMessage};
- content += "\r\n";
- content += message;
- SendResponse(code, codeText, "text/plain", content.str(), extra);
-}
diff --git a/wpiutil/src/main/native/cpp/HttpUtil.cpp b/wpiutil/src/main/native/cpp/HttpUtil.cpp
deleted file mode 100644
index b8b7cc8..0000000
--- a/wpiutil/src/main/native/cpp/HttpUtil.cpp
+++ /dev/null
@@ -1,493 +0,0 @@
-// 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/HttpUtil.h"
-
-#include <cctype>
-
-#include "fmt/format.h"
-#include "wpi/Base64.h"
-#include "wpi/StringExtras.h"
-#include "wpi/TCPConnector.h"
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-std::string_view UnescapeURI(std::string_view str, SmallVectorImpl<char>& buf,
- bool* error) {
- buf.clear();
- for (auto i = str.begin(), end = str.end(); i != end; ++i) {
- // pass non-escaped characters to output
- if (*i != '%') {
- // decode + to space
- if (*i == '+') {
- buf.push_back(' ');
- } else {
- buf.push_back(*i);
- }
- continue;
- }
-
- // are there enough characters left?
- if (i + 2 >= end) {
- *error = true;
- return {};
- }
-
- // replace %xx with the corresponding character
- unsigned val1 = hexDigitValue(*++i);
- if (val1 == -1U) {
- *error = true;
- return {};
- }
- unsigned val2 = hexDigitValue(*++i);
- if (val2 == -1U) {
- *error = true;
- return {};
- }
- buf.push_back((val1 << 4) | val2);
- }
-
- *error = false;
- return {buf.data(), buf.size()};
-}
-
-std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
- bool spacePlus) {
- static const char* const hexLut = "0123456789ABCDEF";
-
- buf.clear();
- for (auto i = str.begin(), end = str.end(); i != end; ++i) {
- // pass unreserved characters to output
- if (std::isalnum(*i) || *i == '-' || *i == '_' || *i == '.' || *i == '~') {
- buf.push_back(*i);
- continue;
- }
-
- // encode space to +
- if (spacePlus && *i == ' ') {
- buf.push_back('+');
- continue;
- }
-
- // convert others to %xx
- buf.push_back('%');
- buf.push_back(hexLut[((*i) >> 4) & 0x0f]);
- buf.push_back(hexLut[(*i) & 0x0f]);
- }
-
- return {buf.data(), buf.size()};
-}
-
-HttpQueryMap::HttpQueryMap(std::string_view query) {
- SmallVector<std::string_view, 16> queryElems;
- split(query, queryElems, '&', 100, false);
- for (auto elem : queryElems) {
- auto [nameEsc, valueEsc] = split(elem, '=');
- SmallString<64> nameBuf;
- bool err = false;
- auto name = wpi::UnescapeURI(nameEsc, nameBuf, &err);
- // note: ignores duplicates
- if (!err) {
- m_elems.try_emplace(name, valueEsc);
- }
- }
-}
-
-std::optional<std::string_view> HttpQueryMap::Get(
- std::string_view name, wpi::SmallVectorImpl<char>& buf) const {
- auto it = m_elems.find(name);
- if (it == m_elems.end()) {
- return {};
- }
- bool err = false;
- auto val = wpi::UnescapeURI(it->second, buf, &err);
- if (err) {
- return {};
- }
- return val;
-}
-
-HttpPath::HttpPath(std::string_view path) {
- // special-case root path to be a single empty element
- if (path == "/") {
- m_pathEnds.emplace_back(0);
- return;
- }
- wpi::SmallVector<std::string_view, 16> pathElems;
- split(path, pathElems, '/', 100, false);
- for (auto elem : pathElems) {
- SmallString<64> buf;
- bool err = false;
- auto val = wpi::UnescapeURI(elem, buf, &err);
- if (err) {
- m_pathEnds.clear();
- return;
- }
- m_pathBuf += val;
- m_pathEnds.emplace_back(m_pathBuf.size());
- }
-}
-
-bool HttpPath::startswith(size_t start,
- span<const std::string_view> match) const {
- if (m_pathEnds.size() < (start + match.size())) {
- return false;
- }
- bool first = start == 0;
- auto p = m_pathEnds.begin() + start;
- for (auto m : match) {
- auto val = slice(m_pathBuf, first ? 0 : *(p - 1), *p);
- if (val != m) {
- return false;
- }
- first = false;
- ++p;
- }
- return true;
-}
-
-std::string_view HttpPath::operator[](size_t n) const {
- return slice(m_pathBuf, n == 0 ? 0 : m_pathEnds[n - 1], m_pathEnds[n]);
-}
-
-bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
- SmallVectorImpl<char>* contentLength) {
- if (contentType) {
- contentType->clear();
- }
- if (contentLength) {
- contentLength->clear();
- }
-
- bool inContentType = false;
- bool inContentLength = false;
- SmallString<64> lineBuf;
- for (;;) {
- std::string_view line = rtrim(is.getline(lineBuf, 1024));
- if (is.has_error()) {
- return false;
- }
- if (line.empty()) {
- return true; // empty line signals end of headers
- }
-
- // header fields start at the beginning of the line
- if (!std::isspace(line[0])) {
- inContentType = false;
- inContentLength = false;
- std::string_view field;
- std::tie(field, line) = split(line, ':');
- field = rtrim(field);
- if (equals_lower(field, "content-type")) {
- inContentType = true;
- } else if (equals_lower(field, "content-length")) {
- inContentLength = true;
- } else {
- continue; // ignore other fields
- }
- }
-
- // collapse whitespace
- line = ltrim(line);
-
- // save field data
- if (inContentType && contentType) {
- contentType->append(line.begin(), line.end());
- } else if (inContentLength && contentLength) {
- contentLength->append(line.begin(), line.end());
- }
- }
-}
-
-bool FindMultipartBoundary(raw_istream& is, std::string_view boundary,
- std::string* saveBuf) {
- SmallString<64> searchBuf;
- searchBuf.resize(boundary.size() + 2);
- size_t searchPos = 0;
-
- // Per the spec, the --boundary should be preceded by \r\n, so do a first
- // pass of 1-byte reads to throw those away (common case) and keep the
- // last non-\r\n character in searchBuf.
- if (!saveBuf) {
- do {
- is.read(searchBuf.data(), 1);
- if (is.has_error()) {
- return false;
- }
- } while (searchBuf[0] == '\r' || searchBuf[0] == '\n');
- searchPos = 1;
- }
-
- // Look for --boundary. Read boundarysize+2 bytes at a time
- // during the search to speed up the reads, then fast-scan for -,
- // and only then match the entire boundary. This will be slow if
- // there's a bunch of continuous -'s in the output, but that's unlikely.
- for (;;) {
- is.read(searchBuf.data() + searchPos, searchBuf.size() - searchPos);
- if (is.has_error()) {
- return false;
- }
-
- // Did we find the boundary?
- if (searchBuf[0] == '-' && searchBuf[1] == '-' &&
- wpi::substr(searchBuf, 2) == boundary) {
- return true;
- }
-
- // Fast-scan for '-'
- size_t pos = searchBuf.find('-', searchBuf[0] == '-' ? 1 : 0);
- if (pos == std::string_view::npos) {
- if (saveBuf) {
- saveBuf->append(searchBuf.data(), searchBuf.size());
- }
- } else {
- if (saveBuf) {
- saveBuf->append(searchBuf.data(), pos);
- }
-
- // move '-' and following to start of buffer (next read will fill)
- std::memmove(searchBuf.data(), searchBuf.data() + pos,
- searchBuf.size() - pos);
- searchPos = searchBuf.size() - pos;
- }
- }
-}
-
-HttpLocation::HttpLocation(std::string_view url_, bool* error,
- std::string* errorMsg)
- : url{url_} {
- // Split apart into components
- std::string_view query{url};
-
- // scheme:
- std::string_view scheme;
- std::tie(scheme, query) = split(query, ':');
- if (!equals_lower(scheme, "http")) {
- *errorMsg = "only supports http URLs";
- *error = true;
- return;
- }
-
- // "//"
- if (!starts_with(query, "//")) {
- *errorMsg = "expected http://...";
- *error = true;
- return;
- }
- query.remove_prefix(2);
-
- // user:password@host:port/
- std::string_view authority;
- std::tie(authority, query) = split(query, '/');
-
- auto [userpass, hostport] = split(authority, '@');
- // split leaves the RHS empty if the split char isn't present...
- if (hostport.empty()) {
- hostport = userpass;
- userpass = {};
- }
-
- if (!userpass.empty()) {
- auto [rawUser, rawPassword] = split(userpass, ':');
- SmallString<64> userBuf, passBuf;
- user = UnescapeURI(rawUser, userBuf, error);
- if (*error) {
- *errorMsg = fmt::format("could not unescape user \"{}\"", rawUser);
- return;
- }
- password = UnescapeURI(rawPassword, passBuf, error);
- if (*error) {
- *errorMsg =
- fmt::format("could not unescape password \"{}\"", rawPassword);
- return;
- }
- }
-
- std::string_view portStr;
- std::tie(host, portStr) = rsplit(hostport, ':');
- if (host.empty()) {
- *errorMsg = "host is empty";
- *error = true;
- return;
- }
- if (portStr.empty()) {
- port = 80;
- } else if (auto p = parse_integer<int>(portStr, 10)) {
- port = p.value();
- } else {
- *errorMsg = fmt::format("port \"{}\" is not an integer", portStr);
- *error = true;
- return;
- }
-
- // path?query#fragment
- std::tie(query, fragment) = split(query, '#');
- std::tie(path, query) = split(query, '?');
-
- // Split query string into parameters
- while (!query.empty()) {
- // split out next param and value
- std::string_view rawParam, rawValue;
- std::tie(rawParam, query) = split(query, '&');
- if (rawParam.empty()) {
- continue; // ignore "&&"
- }
- std::tie(rawParam, rawValue) = split(rawParam, '=');
-
- // unescape param
- *error = false;
- SmallString<64> paramBuf;
- std::string_view param = UnescapeURI(rawParam, paramBuf, error);
- if (*error) {
- *errorMsg = fmt::format("could not unescape parameter \"{}\"", rawParam);
- return;
- }
-
- // unescape value
- SmallString<64> valueBuf;
- std::string_view value = UnescapeURI(rawValue, valueBuf, error);
- if (*error) {
- *errorMsg = fmt::format("could not unescape value \"{}\"", rawValue);
- return;
- }
-
- params.emplace_back(std::make_pair(param, value));
- }
-
- *error = false;
-}
-
-void HttpRequest::SetAuth(const HttpLocation& loc) {
- if (!loc.user.empty()) {
- SmallString<64> userpass;
- userpass += loc.user;
- userpass += ':';
- userpass += loc.password;
- Base64Encode(userpass.str(), &auth);
- }
-}
-
-bool HttpConnection::Handshake(const HttpRequest& request,
- std::string* warnMsg) {
- // send GET request
- os << "GET /" << request.path << " HTTP/1.1\r\n";
- os << "Host: " << request.host << "\r\n";
- if (!request.auth.empty()) {
- os << "Authorization: Basic " << request.auth << "\r\n";
- }
- os << "\r\n";
- os.flush();
-
- // read first line of response
- SmallString<64> lineBuf;
- std::string_view line = rtrim(is.getline(lineBuf, 1024));
- if (is.has_error()) {
- *warnMsg = "disconnected before response";
- return false;
- }
-
- // see if we got a HTTP 200 response
- std::string_view httpver, code, codeText;
- std::tie(httpver, line) = split(line, ' ');
- std::tie(code, codeText) = split(line, ' ');
- if (!starts_with(httpver, "HTTP")) {
- *warnMsg = "did not receive HTTP response";
- return false;
- }
- if (code != "200") {
- *warnMsg = fmt::format("received {} {} response", code, codeText);
- return false;
- }
-
- // Parse headers
- if (!ParseHttpHeaders(is, &contentType, &contentLength)) {
- *warnMsg = "disconnected during headers";
- return false;
- }
-
- return true;
-}
-
-void HttpMultipartScanner::SetBoundary(std::string_view boundary) {
- m_boundaryWith = "\n--";
- m_boundaryWith += boundary;
- m_boundaryWithout = "\n";
- m_boundaryWithout += boundary;
- m_dashes = kUnknown;
-}
-
-void HttpMultipartScanner::Reset(bool saveSkipped) {
- m_saveSkipped = saveSkipped;
- m_state = kBoundary;
- m_posWith = 0;
- m_posWithout = 0;
- m_buf.resize(0);
-}
-
-std::string_view HttpMultipartScanner::Execute(std::string_view in) {
- if (m_state == kDone) {
- Reset(m_saveSkipped);
- }
- if (m_saveSkipped) {
- m_buf += in;
- }
-
- size_t pos = 0;
- if (m_state == kBoundary) {
- for (char ch : in) {
- ++pos;
- if (m_dashes != kWithout) {
- if (ch == m_boundaryWith[m_posWith]) {
- ++m_posWith;
- if (m_posWith == m_boundaryWith.size()) {
- // Found the boundary; transition to padding
- m_state = kPadding;
- m_dashes = kWith; // no longer accept plain 'boundary'
- break;
- }
- } else if (ch == m_boundaryWith[0]) {
- m_posWith = 1;
- } else {
- m_posWith = 0;
- }
- }
-
- if (m_dashes != kWith) {
- if (ch == m_boundaryWithout[m_posWithout]) {
- ++m_posWithout;
- if (m_posWithout == m_boundaryWithout.size()) {
- // Found the boundary; transition to padding
- m_state = kPadding;
- m_dashes = kWithout; // no longer accept '--boundary'
- break;
- }
- } else if (ch == m_boundaryWithout[0]) {
- m_posWithout = 1;
- } else {
- m_posWithout = 0;
- }
- }
- }
- }
-
- if (m_state == kPadding) {
- for (char ch : drop_front(in, pos)) {
- ++pos;
- if (ch == '\n') {
- // Found the LF; return remaining input buffer (following it)
- m_state = kDone;
- if (m_saveSkipped) {
- m_buf.resize(m_buf.size() - in.size() + pos);
- }
- return drop_front(in, pos);
- }
- }
- }
-
- // We consumed the entire input
- return {};
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/MappedFileRegion.cpp b/wpiutil/src/main/native/cpp/MappedFileRegion.cpp
new file mode 100644
index 0000000..006e395
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/MappedFileRegion.cpp
@@ -0,0 +1,133 @@
+// 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/MappedFileRegion.h"
+
+#include <sys/types.h>
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h> // NOLINT(build/include_order)
+
+#include <memoryapi.h>
+#include <sysinfoapi.h>
+
+#else // _WIN32
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+#endif // _WIN32
+
+#ifdef _MSC_VER
+#include <io.h>
+#endif
+
+#ifdef _WIN32
+#include "wpi/WindowsError.h"
+#endif
+
+using namespace wpi;
+
+MappedFileRegion::MappedFileRegion(fs::file_t f, uint64_t length,
+ uint64_t offset, MapMode mapMode,
+ std::error_code& ec)
+ : m_size(length) {
+#ifdef _WIN32
+ if (f == INVALID_HANDLE_VALUE) {
+ ec = std::make_error_code(std::errc::bad_file_descriptor);
+ return;
+ }
+
+ HANDLE fileMappingHandle = ::CreateFileMappingW(
+ f, 0, mapMode == kReadOnly ? PAGE_READONLY : PAGE_READWRITE, length >> 32,
+ length & 0xffffffff, 0);
+ if (fileMappingHandle == nullptr) {
+ ec = wpi::mapWindowsError(GetLastError());
+ return;
+ }
+
+ DWORD dwDesiredAccess = 0;
+ switch (mapMode) {
+ case kReadOnly:
+ dwDesiredAccess = FILE_MAP_READ;
+ break;
+ case kReadWrite:
+ dwDesiredAccess = FILE_MAP_WRITE;
+ break;
+ case kPriv:
+ dwDesiredAccess = FILE_MAP_WRITE | FILE_MAP_COPY;
+ break;
+ }
+ m_mapping = ::MapViewOfFile(fileMappingHandle, dwDesiredAccess, offset >> 32,
+ offset & 0xffffffff, length);
+ if (m_mapping == nullptr) {
+ ec = wpi::mapWindowsError(GetLastError());
+ ::CloseHandle(fileMappingHandle);
+ return;
+ }
+
+ // Close the file mapping handle, as it's kept alive by the file mapping. But
+ // neither the file mapping nor the file mapping handle keep the file handle
+ // alive, so we need to keep a reference to the file in case all other handles
+ // are closed and the file is deleted, which may cause invalid data to be read
+ // from the file.
+ ::CloseHandle(fileMappingHandle);
+ if (!::DuplicateHandle(::GetCurrentProcess(), f, ::GetCurrentProcess(),
+ &m_fileHandle, 0, 0, DUPLICATE_SAME_ACCESS)) {
+ ec = wpi::mapWindowsError(GetLastError());
+ ::UnmapViewOfFile(m_mapping);
+ m_mapping = nullptr;
+ return;
+ }
+#else
+ m_mapping =
+ ::mmap(nullptr, length,
+ mapMode == kReadOnly ? PROT_READ : (PROT_READ | PROT_WRITE),
+ mapMode == kPriv ? MAP_PRIVATE : MAP_SHARED, f, offset);
+ if (m_mapping == MAP_FAILED) {
+ ec = std::error_code(errno, std::generic_category());
+ m_mapping = nullptr;
+ }
+#endif
+}
+
+void MappedFileRegion::Flush() {
+#ifdef _WIN32
+ ::FlushViewOfFile(m_mapping, 0);
+ ::FlushFileBuffers(m_fileHandle);
+#else
+ ::msync(m_mapping, m_size, MS_ASYNC);
+#endif
+}
+
+void MappedFileRegion::Unmap() {
+ if (!m_mapping) {
+ return;
+ }
+#ifdef _WIN32
+ ::UnmapViewOfFile(m_mapping);
+ ::CloseHandle(m_fileHandle);
+#else
+ ::munmap(m_mapping, m_size);
+#endif
+ m_mapping = nullptr;
+}
+
+size_t MappedFileRegion::GetAlignment() {
+#ifdef _WIN32
+ SYSTEM_INFO SysInfo;
+ ::GetSystemInfo(&SysInfo);
+ return SysInfo.dwAllocationGranularity;
+#else
+ static long pageSize = ::getpagesize(); // NOLINT
+ if (pageSize < 0) {
+ pageSize = 4096;
+ }
+ return pageSize;
+#endif
+}
diff --git a/wpiutil/src/main/native/cpp/MessagePack.cpp b/wpiutil/src/main/native/cpp/MessagePack.cpp
new file mode 100644
index 0000000..60a2f01
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/MessagePack.cpp
@@ -0,0 +1,45 @@
+// 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/MessagePack.h"
+
+using namespace mpack;
+
+mpack_error_t mpack::mpack_expect_str(mpack_reader_t* reader, std::string* out,
+ uint32_t maxLen) {
+ uint32_t count = mpack_expect_str_max(reader, maxLen);
+ mpack_error_t err = mpack_reader_error(reader);
+ if (err != mpack_ok) {
+ return err;
+ }
+ const char* bytes = mpack_read_bytes_inplace(reader, count);
+ if (bytes) {
+ out->assign(bytes, count);
+ } else {
+ return mpack_reader_error(reader);
+ }
+ mpack_done_str(reader);
+ return mpack_ok;
+}
+
+mpack_error_t mpack::mpack_read_str(mpack_reader_t* reader, mpack_tag_t* tag,
+ std::string* out, uint32_t maxLen) {
+ uint32_t count = mpack_tag_str_length(tag);
+ mpack_error_t err = mpack_reader_error(reader);
+ if (err != mpack_ok) {
+ return err;
+ }
+ if (count > maxLen) {
+ mpack_reader_flag_error(reader, mpack_error_too_big);
+ return mpack_error_too_big;
+ }
+ const char* bytes = mpack_read_bytes_inplace(reader, count);
+ if (bytes) {
+ out->assign(bytes, count);
+ } else {
+ return mpack_reader_error(reader);
+ }
+ mpack_done_str(reader);
+ return mpack_ok;
+}
diff --git a/wpiutil/src/main/native/cpp/MimeTypes.cpp b/wpiutil/src/main/native/cpp/MimeTypes.cpp
deleted file mode 100644
index 5f5bf59..0000000
--- a/wpiutil/src/main/native/cpp/MimeTypes.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-// 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/MimeTypes.h"
-
-#include "wpi/StringExtras.h"
-#include "wpi/StringMap.h"
-
-namespace wpi {
-
-// derived partially from
-// https://github.com/DEGoodmanWilson/libmime/blob/stable/0.1.2/mime/mime.cpp
-std::string_view MimeTypeFromPath(std::string_view path) {
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types
- static StringMap<const char*> mimeTypes{
- // text
- {"css", "text/css"},
- {"csv", "text/csv"},
- {"htm", "text/html"},
- {"html", "text/html"},
- {"js", "text/javascript"},
- {"json", "application/json"},
- {"map", "application/json"},
- {"md", "text/markdown"},
- {"txt", "text/plain"},
- {"xml", "text/xml"},
-
- // images
- {"apng", "image/apng"},
- {"bmp", "image/bmp"},
- {"gif", "image/gif"},
- {"cur", "image/x-icon"},
- {"ico", "image/x-icon"},
- {"jpg", "image/jpeg"},
- {"jpeg", "image/jpeg"},
- {"png", "image/png"},
- {"svg", "image/svg+xml"},
- {"tif", "image/tiff"},
- {"tiff", "image/tiff"},
- {"webp", "image/webp"},
-
- // fonts
- {"otf", "font/otf"},
- {"ttf", "font/ttf"},
- {"woff", "font/woff"},
-
- // misc
- {"pdf", "application/pdf"},
- {"zip", "application/zip"},
- };
-
- static const char* defaultType = "application/octet-stream";
-
- auto pos = path.find_last_of("/");
- if (pos != std::string_view::npos) {
- path = wpi::substr(path, pos + 1);
- }
- auto dot_pos = path.find_last_of(".");
- if (dot_pos > 0 && dot_pos != std::string_view::npos) {
- auto type = mimeTypes.find(wpi::substr(path, dot_pos + 1));
- if (type != mimeTypes.end()) {
- return type->getValue();
- }
- }
- return defaultType;
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/MulticastHandleManager.cpp b/wpiutil/src/main/native/cpp/MulticastHandleManager.cpp
deleted file mode 100644
index d249a1c..0000000
--- a/wpiutil/src/main/native/cpp/MulticastHandleManager.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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 "MulticastHandleManager.h"
-
-using namespace wpi;
-
-MulticastHandleManager& wpi::GetMulticastManager() {
- static MulticastHandleManager manager;
- return manager;
-}
diff --git a/wpiutil/src/main/native/cpp/MulticastHandleManager.h b/wpiutil/src/main/native/cpp/MulticastHandleManager.h
deleted file mode 100644
index be8d061..0000000
--- a/wpiutil/src/main/native/cpp/MulticastHandleManager.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 "wpi/DenseMap.h"
-#include "wpi/MulticastServiceAnnouncer.h"
-#include "wpi/MulticastServiceResolver.h"
-#include "wpi/UidVector.h"
-
-namespace wpi {
-struct MulticastHandleManager {
- wpi::mutex mutex;
- wpi::UidVector<int, 8> handleIds;
- wpi::DenseMap<size_t, std::unique_ptr<wpi::MulticastServiceResolver>>
- resolvers;
- wpi::DenseMap<size_t, std::unique_ptr<wpi::MulticastServiceAnnouncer>>
- announcers;
-};
-
-MulticastHandleManager& GetMulticastManager();
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/MulticastServiceAnnouncer.cpp b/wpiutil/src/main/native/cpp/MulticastServiceAnnouncer.cpp
deleted file mode 100644
index 736a03d..0000000
--- a/wpiutil/src/main/native/cpp/MulticastServiceAnnouncer.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-// 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/MulticastServiceAnnouncer.h"
-
-#include <wpi/SmallVector.h>
-
-#include "MulticastHandleManager.h"
-
-extern "C" {
-WPI_MulticastServiceAnnouncerHandle WPI_CreateMulticastServiceAnnouncer(
- const char* serviceName, const char* serviceType, int32_t port,
- int32_t txtCount, const char** keys, const char** values)
-
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
-
- wpi::SmallVector<std::pair<std::string_view, std::string_view>, 8> txts;
-
- for (int32_t i = 0; i < txtCount; i++) {
- txts.emplace_back(
- std::pair<std::string_view, std::string_view>{keys[i], values[i]});
- }
-
- auto announcer = std::make_unique<wpi::MulticastServiceAnnouncer>(
- serviceName, serviceType, port, txts);
-
- size_t index = manager.handleIds.emplace_back(3);
- manager.announcers[index] = std::move(announcer);
-
- return index;
-}
-
-void WPI_FreeMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- manager.announcers[handle] = nullptr;
- manager.handleIds.erase(handle);
-}
-
-void WPI_StartMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- announcer->Start();
-}
-
-void WPI_StopMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- announcer->Stop();
-}
-
-int32_t WPI_GetMulticastServiceAnnouncerHasImplementation(
- WPI_MulticastServiceAnnouncerHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- return announcer->HasImplementation();
-}
-} // extern "C"
diff --git a/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp b/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp
deleted file mode 100644
index b834f17..0000000
--- a/wpiutil/src/main/native/cpp/MulticastServiceResolver.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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/MulticastServiceResolver.h"
-
-#include "MulticastHandleManager.h"
-#include "wpi/MemAlloc.h"
-
-extern "C" {
-WPI_MulticastServiceResolverHandle WPI_CreateMulticastServiceResolver(
- const char* serviceType)
-
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
-
- auto resolver = std::make_unique<wpi::MulticastServiceResolver>(serviceType);
-
- size_t index = manager.handleIds.emplace_back(2);
- manager.resolvers[index] = std::move(resolver);
-
- return index;
-}
-
-void WPI_FreeMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- manager.resolvers[handle] = nullptr;
- manager.handleIds.erase(handle);
-}
-
-void WPI_StartMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- resolver->Start();
-}
-
-void WPI_StopMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- resolver->Stop();
-}
-
-int32_t WPI_GetMulticastServiceResolverHasImplementation(
- WPI_MulticastServiceResolverHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- return resolver->HasImplementation();
-}
-
-WPI_EventHandle WPI_GetMulticastServiceResolverEventHandle(
- WPI_MulticastServiceResolverHandle handle) {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- return resolver->GetEventHandle();
-}
-
-WPI_ServiceData* WPI_GetMulticastServiceResolverData(
- WPI_MulticastServiceResolverHandle handle, int32_t* dataCount) {
- std::vector<wpi::MulticastServiceResolver::ServiceData> allData;
- {
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- allData = resolver->GetData();
- }
- if (allData.empty()) {
- *dataCount = 0;
- return nullptr;
- }
- size_t allocSize = sizeof(WPI_ServiceData) * allData.size();
-
- for (auto&& data : allData) {
- // Include space for hostName and serviceType (+ terminators)
- allocSize += data.hostName.size() + data.serviceName.size() + 2;
-
- size_t keysTotalLength = 0;
- size_t valuesTotalLength = 0;
- // Include space for all keys and values, and pointer array
- for (auto&& t : data.txt) {
- allocSize += sizeof(const char*);
- keysTotalLength += (t.first.size() + 1);
- allocSize += sizeof(const char*);
- valuesTotalLength += (t.second.size() + 1);
- }
- allocSize += keysTotalLength;
- allocSize += valuesTotalLength;
- }
-
- uint8_t* cDataRaw = reinterpret_cast<uint8_t*>(wpi::safe_malloc(allocSize));
- if (!cDataRaw) {
- return nullptr;
- }
- WPI_ServiceData* rootArray = reinterpret_cast<WPI_ServiceData*>(cDataRaw);
- cDataRaw += (sizeof(WPI_ServiceData) + allData.size());
- WPI_ServiceData* currentData = rootArray;
-
- for (auto&& data : allData) {
- currentData->ipv4Address = data.ipv4Address;
- currentData->port = data.port;
- currentData->txtCount = data.txt.size();
-
- std::memcpy(cDataRaw, data.hostName.c_str(), data.hostName.size() + 1);
- currentData->hostName = reinterpret_cast<const char*>(cDataRaw);
- cDataRaw += data.hostName.size() + 1;
-
- std::memcpy(cDataRaw, data.serviceName.c_str(),
- data.serviceName.size() + 1);
- currentData->serviceName = reinterpret_cast<const char*>(cDataRaw);
- cDataRaw += data.serviceName.size() + 1;
-
- char** valuesPtrArr = reinterpret_cast<char**>(cDataRaw);
- cDataRaw += (sizeof(char**) * data.txt.size());
- char** keysPtrArr = reinterpret_cast<char**>(cDataRaw);
- cDataRaw += (sizeof(char**) * data.txt.size());
-
- currentData->txtKeys = const_cast<const char**>(keysPtrArr);
- currentData->txtValues = const_cast<const char**>(valuesPtrArr);
-
- for (size_t i = 0; i < data.txt.size(); i++) {
- keysPtrArr[i] = reinterpret_cast<char*>(cDataRaw);
- std::memcpy(keysPtrArr[i], data.txt[i].first.c_str(),
- data.txt[i].first.size() + 1);
- cDataRaw += (data.txt[i].first.size() + 1);
-
- valuesPtrArr[i] = reinterpret_cast<char*>(cDataRaw);
- std::memcpy(valuesPtrArr[i], data.txt[i].second.c_str(),
- data.txt[i].second.size() + 1);
- cDataRaw += (data.txt[i].second.size() + 1);
- }
- currentData++;
- }
-
- return rootArray;
-}
-
-void WPI_FreeServiceData(WPI_ServiceData* serviceData, int32_t length) {
- std::free(serviceData);
-}
-} // extern "C"
diff --git a/wpiutil/src/main/native/cpp/ParallelTcpConnector.cpp b/wpiutil/src/main/native/cpp/ParallelTcpConnector.cpp
deleted file mode 100644
index 5a8394a..0000000
--- a/wpiutil/src/main/native/cpp/ParallelTcpConnector.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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/ParallelTcpConnector.h"
-
-#include <fmt/format.h>
-
-#include "wpi/Logger.h"
-#include "wpi/uv/GetAddrInfo.h"
-#include "wpi/uv/Loop.h"
-#include "wpi/uv/Tcp.h"
-#include "wpi/uv/Timer.h"
-#include "wpi/uv/util.h"
-
-using namespace wpi;
-
-ParallelTcpConnector::ParallelTcpConnector(
- wpi::uv::Loop& loop, wpi::uv::Timer::Time reconnectRate,
- wpi::Logger& logger, std::function<void(wpi::uv::Tcp& tcp)> connected,
- const private_init&)
- : m_loop{loop},
- m_logger{logger},
- m_reconnectRate{reconnectRate},
- m_connected{std::move(connected)},
- m_reconnectTimer{uv::Timer::Create(loop)} {
- m_reconnectTimer->timeout.connect([this] {
- if (!IsConnected()) {
- WPI_DEBUG1(m_logger, "{}", "timed out, reconnecting");
- Connect();
- }
- });
-}
-
-ParallelTcpConnector::~ParallelTcpConnector() = default;
-
-void ParallelTcpConnector::Close() {
- CancelAll();
- m_reconnectTimer->Close();
-}
-
-void ParallelTcpConnector::SetServers(
- wpi::span<const std::pair<std::string, unsigned int>> servers) {
- m_servers.assign(servers.begin(), servers.end());
- if (!IsConnected()) {
- Connect();
- }
-}
-
-void ParallelTcpConnector::Disconnected() {
- if (m_isConnected) {
- m_isConnected = false;
- Connect();
- }
-}
-
-void ParallelTcpConnector::Succeeded(uv::Tcp& tcp) {
- if (!m_isConnected) {
- m_isConnected = true;
- m_reconnectTimer->Stop();
- CancelAll(&tcp);
- }
-}
-
-void ParallelTcpConnector::Connect() {
- if (IsConnected()) {
- return;
- }
-
- CancelAll();
- m_reconnectTimer->Start(m_reconnectRate);
-
- WPI_DEBUG3(m_logger, "{}", "starting new connection attempts");
-
- // kick off parallel lookups
- for (auto&& server : m_servers) {
- auto req = std::make_shared<uv::GetAddrInfoReq>();
- m_resolvers.emplace_back(req);
-
- req->resolved.connect(
- [this, req = req.get()](const addrinfo& addrinfo) {
- if (IsConnected()) {
- return;
- }
-
- // kick off parallel connection attempts
- for (auto ai = &addrinfo; ai; ai = ai->ai_next) {
- auto tcp = uv::Tcp::Create(m_loop);
- m_attempts.emplace_back(tcp);
-
- auto connreq = std::make_shared<uv::TcpConnectReq>();
- connreq->connected.connect(
- [this, tcp = tcp.get()] {
- if (m_logger.min_level() <= wpi::WPI_LOG_DEBUG4) {
- std::string ip;
- unsigned int port = 0;
- uv::AddrToName(tcp->GetPeer(), &ip, &port);
- WPI_DEBUG4(m_logger,
- "successful connection ({}) to {} port {}",
- static_cast<void*>(tcp), ip, port);
- }
- if (IsConnected()) {
- tcp->Shutdown([tcp] { tcp->Close(); });
- return;
- }
- if (m_connected) {
- m_connected(*tcp);
- }
- },
- shared_from_this());
-
- connreq->error = [selfWeak = weak_from_this(),
- tcp = tcp.get()](uv::Error err) {
- if (auto self = selfWeak.lock()) {
- WPI_DEBUG1(self->m_logger, "connect failure ({}): {}",
- static_cast<void*>(tcp), err.str());
- }
- };
-
- if (m_logger.min_level() <= wpi::WPI_LOG_DEBUG4) {
- std::string ip;
- unsigned int port = 0;
- uv::AddrToName(*reinterpret_cast<sockaddr_storage*>(ai->ai_addr),
- &ip, &port);
- WPI_DEBUG4(
- m_logger,
- "Info({}) starting connection attempt ({}) to {} port {}",
- static_cast<void*>(req), static_cast<void*>(tcp.get()), ip,
- port);
- }
- tcp->Connect(*ai->ai_addr, connreq);
- }
- },
- shared_from_this());
-
- req->error = [req = req.get(), selfWeak = weak_from_this()](uv::Error err) {
- if (auto self = selfWeak.lock()) {
- WPI_DEBUG1(self->m_logger, "GetAddrInfo({}) failure: {}",
- static_cast<void*>(req), err.str());
- }
- };
-
- WPI_DEBUG4(m_logger, "starting GetAddrInfo({}) for {} port {}",
- static_cast<void*>(req.get()), server.first, server.second);
- addrinfo hints;
- std::memset(&hints, 0, sizeof(hints));
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
- hints.ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG;
- uv::GetAddrInfo(m_loop, req, server.first, fmt::format("{}", server.second),
- &hints);
- }
-}
-
-void ParallelTcpConnector::CancelAll(wpi::uv::Tcp* except) {
- WPI_DEBUG4(m_logger, "{}", "canceling previous attempts");
- for (auto&& resolverWeak : m_resolvers) {
- if (auto resolver = resolverWeak.lock()) {
- WPI_DEBUG4(m_logger, "canceling GetAddrInfo({})",
- static_cast<void*>(resolver.get()));
- resolver->Cancel();
- }
- }
- m_resolvers.clear();
-
- for (auto&& tcpWeak : m_attempts) {
- if (auto tcp = tcpWeak.lock()) {
- if (tcp.get() != except) {
- WPI_DEBUG4(m_logger, "canceling connection attempt ({})",
- static_cast<void*>(tcp.get()));
- tcp->Close();
- }
- }
- }
- m_attempts.clear();
-}
diff --git a/wpiutil/src/main/native/cpp/PortForwarder.cpp b/wpiutil/src/main/native/cpp/PortForwarder.cpp
deleted file mode 100644
index a423d48..0000000
--- a/wpiutil/src/main/native/cpp/PortForwarder.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-// 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/PortForwarder.h"
-
-#include "fmt/format.h"
-#include "wpi/DenseMap.h"
-#include "wpi/EventLoopRunner.h"
-#include "wpi/uv/GetAddrInfo.h"
-#include "wpi/uv/Tcp.h"
-#include "wpi/uv/Timer.h"
-
-using namespace wpi;
-
-struct PortForwarder::Impl {
- public:
- EventLoopRunner runner;
- DenseMap<unsigned int, std::weak_ptr<uv::Tcp>> servers;
-};
-
-PortForwarder::PortForwarder() : m_impl{new Impl} {}
-
-PortForwarder& PortForwarder::GetInstance() {
- static PortForwarder instance;
- return instance;
-}
-
-static void CopyStream(uv::Stream& in, std::weak_ptr<uv::Stream> outWeak) {
- in.data.connect([&in, outWeak](uv::Buffer& buf, size_t len) {
- uv::Buffer buf2 = buf.Dup();
- buf2.len = len;
- auto out = outWeak.lock();
- if (!out) {
- buf2.Deallocate();
- in.Close();
- return;
- }
- out->Write({buf2}, [](auto bufs, uv::Error) {
- for (auto buf : bufs) {
- buf.Deallocate();
- }
- });
- });
-}
-
-void PortForwarder::Add(unsigned int port, std::string_view remoteHost,
- unsigned int remotePort) {
- m_impl->runner.ExecSync([&](uv::Loop& loop) {
- auto server = uv::Tcp::Create(loop);
-
- // bind to local port
- server->Bind("", port);
-
- // when we get a connection, accept it
- server->connection.connect([serverPtr = server.get(),
- host = std::string{remoteHost}, remotePort] {
- auto& loop = serverPtr->GetLoopRef();
- auto client = serverPtr->Accept();
- if (!client) {
- return;
- }
-
- // close on error
- client->error.connect(
- [clientPtr = client.get()](uv::Error err) { clientPtr->Close(); });
-
- // connected flag
- auto connected = std::make_shared<bool>(false);
- client->SetData(connected);
-
- auto remote = uv::Tcp::Create(loop);
- remote->error.connect(
- [remotePtr = remote.get(),
- clientWeak = std::weak_ptr<uv::Tcp>(client)](uv::Error err) {
- remotePtr->Close();
- if (auto client = clientWeak.lock()) {
- client->Close();
- }
- });
-
- // resolve address
- uv::GetAddrInfo(
- loop,
- [clientWeak = std::weak_ptr<uv::Tcp>(client),
- remoteWeak = std::weak_ptr<uv::Tcp>(remote)](const addrinfo& addr) {
- auto remote = remoteWeak.lock();
- if (!remote) {
- return;
- }
-
- // connect to remote address/port
- remote->Connect(*addr.ai_addr, [remotePtr = remote.get(),
- remoteWeak, clientWeak] {
- auto client = clientWeak.lock();
- if (!client) {
- remotePtr->Close();
- return;
- }
- *(client->GetData<bool>()) = true;
-
- // close both when either side closes
- client->end.connect([clientPtr = client.get(), remoteWeak] {
- clientPtr->Close();
- if (auto remote = remoteWeak.lock()) {
- remote->Close();
- }
- });
- remotePtr->end.connect([remotePtr, clientWeak] {
- remotePtr->Close();
- if (auto client = clientWeak.lock()) {
- client->Close();
- }
- });
-
- // copy bidirectionally
- client->StartRead();
- remotePtr->StartRead();
- CopyStream(*client, remoteWeak);
- CopyStream(*remotePtr, clientWeak);
- });
- },
- host, fmt::to_string(remotePort));
-
- // time out for connection
- uv::Timer::SingleShot(loop, uv::Timer::Time{500},
- [connectedWeak = std::weak_ptr<bool>(connected),
- clientWeak = std::weak_ptr<uv::Tcp>(client),
- remoteWeak = std::weak_ptr<uv::Tcp>(remote)] {
- if (auto connected = connectedWeak.lock()) {
- if (!*connected) {
- if (auto client = clientWeak.lock()) {
- client->Close();
- }
- if (auto remote = remoteWeak.lock()) {
- remote->Close();
- }
- }
- }
- });
- });
-
- // start listening for incoming connections
- server->Listen();
-
- m_impl->servers[port] = server;
- });
-}
-
-void PortForwarder::Remove(unsigned int port) {
- m_impl->runner.ExecSync([&](uv::Loop& loop) {
- if (auto server = m_impl->servers.lookup(port).lock()) {
- server->Close();
- m_impl->servers.erase(port);
- }
- });
-}
diff --git a/wpiutil/src/main/native/cpp/SafeThread.cpp b/wpiutil/src/main/native/cpp/SafeThread.cpp
index bbecc5c..ba1eba3 100644
--- a/wpiutil/src/main/native/cpp/SafeThread.cpp
+++ b/wpiutil/src/main/native/cpp/SafeThread.cpp
@@ -4,10 +4,50 @@
#include "wpi/SafeThread.h"
+#include <atomic>
+
using namespace wpi;
+// thread start/stop notifications for bindings that need to set up
+// per-thread state
+
+static void* DefaultOnThreadStart() {
+ return nullptr;
+}
+static void DefaultOnThreadEnd(void*) {}
+
+using OnThreadStartFn = void* (*)();
+using OnThreadEndFn = void (*)(void*);
+static std::atomic<int> gSafeThreadRefcount;
+static std::atomic<OnThreadStartFn> gOnSafeThreadStart{DefaultOnThreadStart};
+static std::atomic<OnThreadEndFn> gOnSafeThreadEnd{DefaultOnThreadEnd};
+
+namespace wpi::impl {
+void SetSafeThreadNotifiers(OnThreadStartFn OnStart, OnThreadEndFn OnEnd) {
+ if (gSafeThreadRefcount != 0) {
+ throw std::runtime_error(
+ "cannot set notifier while safe threads are running");
+ }
+ // Note: there's a race here, but if you're not calling this function on
+ // the main thread before you start anything else, you're using this function
+ // incorrectly
+ gOnSafeThreadStart = OnStart ? OnStart : DefaultOnThreadStart;
+ gOnSafeThreadEnd = OnEnd ? OnEnd : DefaultOnThreadEnd;
+}
+} // namespace wpi::impl
+
+void SafeThread::Stop() {
+ m_active = false;
+ m_cond.notify_all();
+}
+
+void SafeThreadEvent::Stop() {
+ m_active = false;
+ m_stopEvent.Set();
+}
+
detail::SafeThreadProxyBase::SafeThreadProxyBase(
- std::shared_ptr<SafeThread> thr)
+ std::shared_ptr<SafeThreadBase> thr)
: m_thread(std::move(thr)) {
if (!m_thread) {
return;
@@ -28,12 +68,18 @@
}
}
-void detail::SafeThreadOwnerBase::Start(std::shared_ptr<SafeThread> thr) {
+void detail::SafeThreadOwnerBase::Start(std::shared_ptr<SafeThreadBase> thr) {
std::scoped_lock lock(m_mutex);
if (auto thr = m_thread.lock()) {
return;
}
- m_stdThread = std::thread([=] { thr->Main(); });
+ m_stdThread = std::thread([=] {
+ gSafeThreadRefcount++;
+ void* opaque = (gOnSafeThreadStart.load())();
+ thr->Main();
+ (gOnSafeThreadEnd.load())(opaque);
+ gSafeThreadRefcount--;
+ });
thr->m_threadId = m_stdThread.get_id();
m_thread = thr;
}
@@ -41,8 +87,7 @@
void detail::SafeThreadOwnerBase::Stop() {
std::scoped_lock lock(m_mutex);
if (auto thr = m_thread.lock()) {
- thr->m_active = false;
- thr->m_cond.notify_all();
+ thr->Stop();
m_thread.reset();
}
if (m_stdThread.joinable()) {
@@ -56,8 +101,7 @@
auto stdThread = std::move(m_stdThread);
m_thread.reset();
lock.unlock();
- thr->m_active = false;
- thr->m_cond.notify_all();
+ thr->Stop();
stdThread.join();
} else if (m_stdThread.joinable()) {
m_stdThread.detach();
@@ -85,8 +129,8 @@
return m_stdThread.native_handle();
}
-std::shared_ptr<SafeThread> detail::SafeThreadOwnerBase::GetThreadSharedPtr()
- const {
+std::shared_ptr<SafeThreadBase>
+detail::SafeThreadOwnerBase::GetThreadSharedPtr() const {
std::scoped_lock lock(m_mutex);
return m_thread.lock();
}
diff --git a/wpiutil/src/main/native/cpp/SocketError.cpp b/wpiutil/src/main/native/cpp/SocketError.cpp
deleted file mode 100644
index 3f08d1e..0000000
--- a/wpiutil/src/main/native/cpp/SocketError.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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/SocketError.h"
-
-#ifdef _WIN32
-#include <winsock2.h>
-#else
-#include <cerrno>
-#include <cstring>
-#endif
-
-namespace wpi {
-
-int SocketErrno() {
-#ifdef _WIN32
- return WSAGetLastError();
-#else
- return errno;
-#endif
-}
-
-std::string SocketStrerror(int code) {
-#ifdef _WIN32
- LPSTR errstr = nullptr;
- FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 0,
- code, 0, (LPSTR)&errstr, 0, 0);
- std::string rv(errstr);
- LocalFree(errstr);
- return rv;
-#else
- return std::strerror(code);
-#endif
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/Synchronization.cpp b/wpiutil/src/main/native/cpp/Synchronization.cpp
index da97897..f9ac75b 100644
--- a/wpiutil/src/main/native/cpp/Synchronization.cpp
+++ b/wpiutil/src/main/native/cpp/Synchronization.cpp
@@ -5,6 +5,7 @@
#include "wpi/Synchronization.h"
#include <algorithm>
+#include <atomic>
#include <cstring>
#include <mutex>
@@ -16,6 +17,8 @@
using namespace wpi;
+static std::atomic_bool gShutdown{false};
+
namespace {
struct State {
@@ -25,6 +28,8 @@
};
struct HandleManager {
+ ~HandleManager() { gShutdown = true; }
+
wpi::mutex mutex;
wpi::UidVector<int, 8> eventIds;
wpi::UidVector<int, 8> semaphoreIds;
@@ -40,6 +45,9 @@
WPI_EventHandle wpi::CreateEvent(bool manualReset, bool initialState) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return {};
+ }
std::scoped_lock lock{manager.mutex};
auto index = manager.eventIds.emplace_back(0);
@@ -61,6 +69,9 @@
DestroySignalObject(handle);
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
manager.eventIds.erase(handle & 0xffffff);
}
@@ -83,6 +94,9 @@
WPI_SemaphoreHandle wpi::CreateSemaphore(int initialCount, int maximumCount) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return {};
+ }
std::scoped_lock lock{manager.mutex};
auto index = manager.semaphoreIds.emplace_back(maximumCount);
@@ -104,6 +118,9 @@
DestroySignalObject(handle);
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
manager.eventIds.erase(handle & 0xffffff);
}
@@ -119,6 +136,9 @@
int index = handle & 0xffffff;
auto& manager = GetManager();
+ if (gShutdown) {
+ return true;
+ }
std::scoped_lock lock{manager.mutex};
auto it = manager.states.find(handle);
if (it == manager.states.end()) {
@@ -146,22 +166,26 @@
bool wpi::WaitForObject(WPI_Handle handle, double timeout, bool* timedOut) {
WPI_Handle signaledValue;
auto signaled = WaitForObjects(
- wpi::span(&handle, 1), wpi::span(&signaledValue, 1), timeout, timedOut);
+ std::span(&handle, 1), std::span(&signaledValue, 1), timeout, timedOut);
if (signaled.empty()) {
return false;
}
return (signaled[0] & 0x80000000ul) == 0;
}
-wpi::span<WPI_Handle> wpi::WaitForObjects(wpi::span<const WPI_Handle> handles,
- wpi::span<WPI_Handle> signaled) {
+std::span<WPI_Handle> wpi::WaitForObjects(std::span<const WPI_Handle> handles,
+ std::span<WPI_Handle> signaled) {
return WaitForObjects(handles, signaled, -1, nullptr);
}
-wpi::span<WPI_Handle> wpi::WaitForObjects(wpi::span<const WPI_Handle> handles,
- wpi::span<WPI_Handle> signaled,
+std::span<WPI_Handle> wpi::WaitForObjects(std::span<const WPI_Handle> handles,
+ std::span<WPI_Handle> signaled,
double timeout, bool* timedOut) {
auto& manager = GetManager();
+ if (gShutdown) {
+ *timedOut = false;
+ return {};
+ }
std::unique_lock lock{manager.mutex};
wpi::condition_variable cv;
bool addedWaiters = false;
@@ -240,6 +264,9 @@
void wpi::CreateSignalObject(WPI_Handle handle, bool manualReset,
bool initialState) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
auto& state = manager.states[handle];
state.signaled = initialState ? 1 : 0;
@@ -248,6 +275,9 @@
void wpi::SetSignalObject(WPI_Handle handle) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
auto it = manager.states.find(handle);
if (it == manager.states.end()) {
@@ -266,6 +296,9 @@
void wpi::ResetSignalObject(WPI_Handle handle) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
auto it = manager.states.find(handle);
if (it != manager.states.end()) {
@@ -275,6 +308,9 @@
void wpi::DestroySignalObject(WPI_Handle handle) {
auto& manager = GetManager();
+ if (gShutdown) {
+ return;
+ }
std::scoped_lock lock{manager.mutex};
auto it = manager.states.find(handle);
@@ -332,8 +368,8 @@
int WPI_WaitForObjects(const WPI_Handle* handles, int handles_count,
WPI_Handle* signaled) {
- return wpi::WaitForObjects(wpi::span(handles, handles_count),
- wpi::span(signaled, handles_count))
+ return wpi::WaitForObjects(std::span(handles, handles_count),
+ std::span(signaled, handles_count))
.size();
}
@@ -341,8 +377,8 @@
WPI_Handle* signaled, double timeout,
int* timed_out) {
bool timedOutBool;
- auto signaledResult = wpi::WaitForObjects(wpi::span(handles, handles_count),
- wpi::span(signaled, handles_count),
+ auto signaledResult = wpi::WaitForObjects(std::span(handles, handles_count),
+ std::span(signaled, handles_count),
timeout, &timedOutBool);
*timed_out = timedOutBool ? 1 : 0;
return signaledResult.size();
diff --git a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp b/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
deleted file mode 100644
index 8d12ac3..0000000
--- a/wpiutil/src/main/native/cpp/TCPAcceptor.cpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- TCPAcceptor.cpp
-
- TCPAcceptor class definition. TCPAcceptor provides methods to passively
- establish TCP/IP connections with clients.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "wpi/TCPAcceptor.h"
-
-#include <cstdio>
-#include <cstring>
-
-#ifdef _WIN32
-#define _WINSOCK_DEPRECATED_NO_WARNINGS
-#include <WinSock2.h>
-#include <Ws2tcpip.h>
-#pragma comment(lib, "Ws2_32.lib")
-#else
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#endif
-
-#include "wpi/Logger.h"
-#include "wpi/SmallString.h"
-#include "wpi/SocketError.h"
-
-using namespace wpi;
-
-TCPAcceptor::TCPAcceptor(int port, std::string_view address, Logger& logger)
- : m_lsd(0),
- m_port(port),
- m_address(address),
- m_listening(false),
- m_logger(logger) {
- m_shutdown = false;
-#ifdef _WIN32
- WSAData wsaData;
- WORD wVersionRequested = MAKEWORD(2, 2);
- (void)WSAStartup(wVersionRequested, &wsaData);
-#endif
-}
-
-TCPAcceptor::~TCPAcceptor() {
- if (m_lsd > 0) {
- shutdown();
-#ifdef _WIN32
- closesocket(m_lsd);
-#else
- close(m_lsd);
-#endif
- }
-#ifdef _WIN32
- WSACleanup();
-#endif
-}
-
-int TCPAcceptor::start() {
- if (m_listening) {
- return 0;
- }
-
- m_lsd = socket(PF_INET, SOCK_STREAM, 0);
- if (m_lsd < 0) {
- WPI_ERROR(m_logger, "{}", "could not create socket");
- return -1;
- }
- struct sockaddr_in address;
-
- std::memset(&address, 0, sizeof(address));
- address.sin_family = PF_INET;
- if (m_address.size() > 0) {
-#ifdef _WIN32
- SmallString<128> addr_copy(m_address);
- addr_copy.push_back('\0');
- int res = InetPton(PF_INET, addr_copy.data(), &(address.sin_addr));
-#else
- int res = inet_pton(PF_INET, m_address.c_str(), &(address.sin_addr));
-#endif
- if (res != 1) {
- WPI_ERROR(m_logger, "could not resolve {} address", m_address);
- return -1;
- }
- } else {
- address.sin_addr.s_addr = INADDR_ANY;
- }
- address.sin_port = htons(m_port);
-
-#ifdef _WIN32
- int optval = 1;
- setsockopt(m_lsd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
- reinterpret_cast<char*>(&optval), sizeof optval);
-#else
- int optval = 1;
- setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&optval),
- sizeof optval);
-#endif
-
- int result = bind(m_lsd, reinterpret_cast<struct sockaddr*>(&address),
- sizeof(address));
- if (result != 0) {
- WPI_ERROR(m_logger, "bind() to port {} failed: {}", m_port,
- SocketStrerror());
- return result;
- }
-
- result = listen(m_lsd, 5);
- if (result != 0) {
- WPI_ERROR(m_logger, "listen() on port {} failed: {}", m_port,
- SocketStrerror());
- return result;
- }
- m_listening = true;
- return result;
-}
-
-void TCPAcceptor::shutdown() {
- m_shutdown = true;
-#ifdef _WIN32
- ::shutdown(m_lsd, SD_BOTH);
-
- // this is ugly, but the easiest way to do this
- // force wakeup of accept() with a non-blocking connect to ourselves
- struct sockaddr_in address;
-
- std::memset(&address, 0, sizeof(address));
- address.sin_family = PF_INET;
- SmallString<128> addr_copy;
- if (m_address.size() > 0)
- addr_copy = m_address;
- else
- addr_copy = "127.0.0.1";
- addr_copy.push_back('\0');
- int size = sizeof(address);
- if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr,
- (struct sockaddr*)&address, &size) != 0)
- return;
- address.sin_port = htons(m_port);
-
- int result = -1, sd = socket(AF_INET, SOCK_STREAM, 0);
- if (sd < 0)
- return;
-
- // Set socket to non-blocking
- u_long mode = 1;
- ioctlsocket(sd, FIONBIO, &mode);
-
- // Try to connect
- ::connect(sd, (struct sockaddr*)&address, sizeof(address));
-
- // Close
- ::closesocket(sd);
-
-#else
- ::shutdown(m_lsd, SHUT_RDWR);
- int nullfd = ::open("/dev/null", O_RDONLY);
- if (nullfd >= 0) {
- ::dup2(nullfd, m_lsd);
- ::close(nullfd);
- }
-#endif
-}
-
-std::unique_ptr<NetworkStream> TCPAcceptor::accept() {
- if (!m_listening || m_shutdown) {
- return nullptr;
- }
-
- struct sockaddr_in address;
-#ifdef _WIN32
- int len = sizeof(address);
-#else
- socklen_t len = sizeof(address);
-#endif
- std::memset(&address, 0, sizeof(address));
- int sd = ::accept(m_lsd, reinterpret_cast<struct sockaddr*>(&address), &len);
- if (sd < 0) {
- if (!m_shutdown) {
- WPI_ERROR(m_logger, "accept() on port {} failed: {}", m_port,
- SocketStrerror());
- }
- return nullptr;
- }
- if (m_shutdown) {
-#ifdef _WIN32
- closesocket(sd);
-#else
- close(sd);
-#endif
- return nullptr;
- }
- return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
-}
diff --git a/wpiutil/src/main/native/cpp/TCPConnector.cpp b/wpiutil/src/main/native/cpp/TCPConnector.cpp
deleted file mode 100644
index ed97962..0000000
--- a/wpiutil/src/main/native/cpp/TCPConnector.cpp
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- TCPConnector.h
-
- TCPConnector class definition. TCPConnector provides methods to actively
- establish TCP/IP connections with a server.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
-*/
-
-#include "wpi/TCPConnector.h"
-
-#include <fcntl.h>
-
-#include <cerrno>
-#include <cstdio>
-#include <cstring>
-
-#ifdef _WIN32
-#include <WS2tcpip.h>
-#include <WinSock2.h>
-#else
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/select.h>
-#include <unistd.h>
-#endif
-
-#include "wpi/Logger.h"
-#include "wpi/SmallString.h"
-#include "wpi/SocketError.h"
-#include "wpi/TCPStream.h"
-
-using namespace wpi;
-
-static int ResolveHostName(const char* hostname, struct in_addr* addr) {
- struct addrinfo hints;
- struct addrinfo* res;
-
- hints.ai_flags = 0;
- hints.ai_family = AF_INET;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = 0;
- hints.ai_addrlen = 0;
- hints.ai_addr = nullptr;
- hints.ai_canonname = nullptr;
- hints.ai_next = nullptr;
- int result = getaddrinfo(hostname, nullptr, &hints, &res);
- if (result == 0) {
- std::memcpy(
- addr, &(reinterpret_cast<struct sockaddr_in*>(res->ai_addr)->sin_addr),
- sizeof(struct in_addr));
- freeaddrinfo(res);
- }
- return result;
-}
-
-std::unique_ptr<NetworkStream> TCPConnector::connect(const char* server,
- int port, Logger& logger,
- int timeout) {
-#ifdef _WIN32
- struct WSAHelper {
- WSAHelper() {
- WSAData wsaData;
- WORD wVersionRequested = MAKEWORD(2, 2);
- WSAStartup(wVersionRequested, &wsaData);
- }
- ~WSAHelper() { WSACleanup(); }
- };
- static WSAHelper helper;
-#endif
- struct sockaddr_in address;
-
- std::memset(&address, 0, sizeof(address));
- address.sin_family = AF_INET;
- if (ResolveHostName(server, &(address.sin_addr)) != 0) {
-#ifdef _WIN32
- SmallString<128> addr_copy(server);
- addr_copy.push_back('\0');
- int res = InetPton(PF_INET, addr_copy.data(), &(address.sin_addr));
-#else
- int res = inet_pton(PF_INET, server, &(address.sin_addr));
-#endif
- if (res != 1) {
- WPI_ERROR(logger, "could not resolve {} address", server);
- return nullptr;
- }
- }
- address.sin_port = htons(port);
-
- if (timeout == 0) {
- int sd = socket(AF_INET, SOCK_STREAM, 0);
- if (sd < 0) {
- WPI_ERROR(logger, "{}", "could not create socket");
- return nullptr;
- }
- if (::connect(sd, reinterpret_cast<struct sockaddr*>(&address),
- sizeof(address)) != 0) {
- WPI_ERROR(logger, "connect() to {} port {} failed: {}", server, port,
- SocketStrerror());
-#ifdef _WIN32
- closesocket(sd);
-#else
- ::close(sd);
-#endif
- return nullptr;
- }
- return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
- }
-
- fd_set sdset;
- struct timeval tv;
- socklen_t len;
- int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0);
- if (sd < 0) {
- WPI_ERROR(logger, "{}", "could not create socket");
- return nullptr;
- }
-
-// Set socket to non-blocking
-#ifdef _WIN32
- u_long mode = 1;
- if (ioctlsocket(sd, FIONBIO, &mode) == SOCKET_ERROR)
- WPI_WARNING(logger, "could not set socket to non-blocking: {}",
- SocketStrerror());
-#else
- int arg;
- arg = fcntl(sd, F_GETFL, nullptr);
- if (arg < 0) {
- WPI_WARNING(logger, "could not set socket to non-blocking: {}",
- SocketStrerror());
- } else {
- arg |= O_NONBLOCK;
- if (fcntl(sd, F_SETFL, arg) < 0) {
- WPI_WARNING(logger, "could not set socket to non-blocking: {}",
- SocketStrerror());
- }
- }
-#endif
-
- // Connect with time limit
- if ((result = ::connect(sd, reinterpret_cast<struct sockaddr*>(&address),
- sizeof(address))) < 0) {
- int my_errno = SocketErrno();
-#ifdef _WIN32
- if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) {
-#else
- if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) {
-#endif
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- FD_ZERO(&sdset);
- FD_SET(sd, &sdset);
- if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) {
- len = sizeof(int);
- getsockopt(sd, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&valopt),
- &len);
- if (valopt) {
- WPI_ERROR(logger, "select() to {} port {} error {} - {}", server,
- port, valopt, SocketStrerror(valopt));
- } else {
- // connection established
- result = 0;
- }
- } else {
- WPI_INFO(logger, "connect() to {} port {} timed out", server, port);
- }
- } else {
- WPI_ERROR(logger, "connect() to {} port {} error {} - {}", server, port,
- SocketErrno(), SocketStrerror());
- }
- }
-
-// Return socket to blocking mode
-#ifdef _WIN32
- mode = 0;
- if (ioctlsocket(sd, FIONBIO, &mode) == SOCKET_ERROR)
- WPI_WARNING(logger, "could not set socket to blocking: {}",
- SocketStrerror());
-#else
- arg = fcntl(sd, F_GETFL, nullptr);
- if (arg < 0) {
- WPI_WARNING(logger, "could not set socket to blocking: {}",
- SocketStrerror());
- } else {
- arg &= (~O_NONBLOCK);
- if (fcntl(sd, F_SETFL, arg) < 0) {
- WPI_WARNING(logger, "could not set socket to blocking: {}",
- SocketStrerror());
- }
- }
-#endif
-
- // Create stream object if connected, close if not.
- if (result == -1) {
-#ifdef _WIN32
- closesocket(sd);
-#else
- ::close(sd);
-#endif
- return nullptr;
- }
- return std::unique_ptr<NetworkStream>(new TCPStream(sd, &address));
-}
diff --git a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp b/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
deleted file mode 100644
index 26258cf..0000000
--- a/wpiutil/src/main/native/cpp/TCPConnector_parallel.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-// 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/TCPConnector.h" // NOLINT(build/include_order)
-
-#include <atomic>
-#include <chrono>
-#include <thread>
-#include <tuple>
-
-#include "wpi/SmallSet.h"
-#include "wpi/condition_variable.h"
-#include "wpi/mutex.h"
-
-using namespace wpi;
-
-// MSVC < 1900 doesn't have support for thread_local
-#if !defined(_MSC_VER) || _MSC_VER >= 1900
-// clang check for availability of thread_local
-#if !defined(__has_feature) || __has_feature(cxx_thread_local)
-#define HAVE_THREAD_LOCAL
-#endif
-#endif
-
-std::unique_ptr<NetworkStream> TCPConnector::connect_parallel(
- span<const std::pair<const char*, int>> servers, Logger& logger,
- int timeout) {
- if (servers.empty()) {
- return nullptr;
- }
-
- // structure to make sure we don't start duplicate workers
- struct GlobalState {
- wpi::mutex mtx;
-#ifdef HAVE_THREAD_LOCAL
- SmallSet<std::pair<std::string, int>, 16> active;
-#else
- SmallSet<std::tuple<std::thread::id, std::string, int>, 16> active;
-#endif
- };
-#ifdef HAVE_THREAD_LOCAL
- thread_local auto global = std::make_shared<GlobalState>();
-#else
- static auto global = std::make_shared<GlobalState>();
- auto this_id = std::this_thread::get_id();
-#endif
- auto local = global; // copy to an automatic variable for lambda capture
-
- // structure shared between threads and this function
- struct Result {
- wpi::mutex mtx;
- wpi::condition_variable cv;
- std::unique_ptr<NetworkStream> stream;
- std::atomic<unsigned int> count{0};
- std::atomic<bool> done{false};
- };
- auto result = std::make_shared<Result>();
-
- // start worker threads; this is I/O bound so we don't limit to # of procs
- Logger* plogger = &logger;
- unsigned int num_workers = 0;
- for (const auto& server : servers) {
- std::pair<std::string, int> server_copy{std::string{server.first},
- server.second};
-#ifdef HAVE_THREAD_LOCAL
- const auto& active_tracker = server_copy;
-#else
- std::tuple<std::thread::id, std::string, int> active_tracker{
- this_id, server_copy.first, server_copy.second};
-#endif
-
- // don't start a new worker if we had a previously still-active connection
- // attempt to the same server
- {
- std::scoped_lock lock(local->mtx);
- if (local->active.count(active_tracker) > 0) {
- continue; // already in set
- }
- }
-
- ++num_workers;
-
- // start the worker
- std::thread([=] {
- if (!result->done) {
- // add to global state
- {
- std::scoped_lock lock(local->mtx);
- local->active.insert(active_tracker);
- }
-
- // try to connect
- auto stream = connect(server_copy.first.c_str(), server_copy.second,
- *plogger, timeout);
-
- // remove from global state
- {
- std::scoped_lock lock(local->mtx);
- local->active.erase(active_tracker);
- }
-
- // successful connection
- if (stream) {
- std::scoped_lock lock(result->mtx);
- if (!result->done.exchange(true)) {
- result->stream = std::move(stream);
- }
- }
- }
- ++result->count;
- result->cv.notify_all();
- }).detach();
- }
-
- // wait for a result, timeout, or all finished
- std::unique_lock lock(result->mtx);
- if (timeout == 0) {
- result->cv.wait(
- lock, [&] { return result->stream || result->count >= num_workers; });
- } else {
- auto timeout_time =
- std::chrono::steady_clock::now() + std::chrono::seconds(timeout);
- result->cv.wait_until(lock, timeout_time, [&] {
- return result->stream || result->count >= num_workers;
- });
- }
-
- // no need to wait for remaining worker threads; shared_ptr will clean up
- return std::move(result->stream);
-}
diff --git a/wpiutil/src/main/native/cpp/TCPStream.cpp b/wpiutil/src/main/native/cpp/TCPStream.cpp
deleted file mode 100644
index 4567161..0000000
--- a/wpiutil/src/main/native/cpp/TCPStream.cpp
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- TCPStream.h
-
- TCPStream class definition. TCPStream provides methods to transfer
- data between peers over a TCP/IP connection.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#include "wpi/TCPStream.h"
-
-#include <fcntl.h>
-
-#ifdef _WIN32
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#else
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
-#include <unistd.h>
-#endif
-
-#include <cerrno>
-
-using namespace wpi;
-
-TCPStream::TCPStream(int sd, sockaddr_in* address)
- : m_sd(sd), m_blocking(true) {
- char ip[50];
-#ifdef _WIN32
- InetNtop(PF_INET, &(address->sin_addr.s_addr), ip, sizeof(ip) - 1);
-#else
- inet_ntop(PF_INET, reinterpret_cast<in_addr*>(&(address->sin_addr.s_addr)),
- ip, sizeof(ip) - 1);
-#ifdef SO_NOSIGPIPE
- // disable SIGPIPE on Mac OS X
- int set = 1;
- setsockopt(m_sd, SOL_SOCKET, SO_NOSIGPIPE, reinterpret_cast<char*>(&set),
- sizeof set);
-#endif
-#endif
- m_peerIP = ip;
- m_peerPort = ntohs(address->sin_port);
-}
-
-TCPStream::~TCPStream() {
- close();
-}
-
-size_t TCPStream::send(const char* buffer, size_t len, Error* err) {
- if (m_sd < 0) {
- *err = kConnectionClosed;
- return 0;
- }
-#ifdef _WIN32
- WSABUF wsaBuf;
- wsaBuf.buf = const_cast<char*>(buffer);
- wsaBuf.len = (ULONG)len;
- DWORD rv;
- bool result = true;
- while (WSASend(m_sd, &wsaBuf, 1, &rv, 0, nullptr, nullptr) == SOCKET_ERROR) {
- if (WSAGetLastError() != WSAEWOULDBLOCK) {
- result = false;
- break;
- }
- if (!m_blocking) {
- *err = kWouldBlock;
- return 0;
- }
- Sleep(1);
- }
- if (!result) {
- char Buffer[128];
-#ifdef _MSC_VER
- sprintf_s(Buffer, "Send() failed: WSA error=%d\n", WSAGetLastError());
-#else
- std::snprintf(Buffer, sizeof(Buffer), "Send() failed: WSA error=%d\n",
- WSAGetLastError());
-#endif
- OutputDebugStringA(Buffer);
- *err = kConnectionReset;
- return 0;
- }
-#else
-#ifdef MSG_NOSIGNAL
- // disable SIGPIPE on Linux
- ssize_t rv = ::send(m_sd, buffer, len, MSG_NOSIGNAL);
-#else
- ssize_t rv = ::send(m_sd, buffer, len, 0);
-#endif
- if (rv < 0) {
- if (!m_blocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- *err = kWouldBlock;
- } else {
- *err = kConnectionReset;
- }
- return 0;
- }
-#endif
- return static_cast<size_t>(rv);
-}
-
-size_t TCPStream::receive(char* buffer, size_t len, Error* err, int timeout) {
- if (m_sd < 0) {
- *err = kConnectionClosed;
- return 0;
- }
-#ifdef _WIN32
- int rv;
-#else
- ssize_t rv;
-#endif
- if (timeout <= 0) {
-#ifdef _WIN32
- rv = recv(m_sd, buffer, len, 0);
-#else
- rv = read(m_sd, buffer, len);
-#endif
- } else if (WaitForReadEvent(timeout)) {
-#ifdef _WIN32
- rv = recv(m_sd, buffer, len, 0);
-#else
- rv = read(m_sd, buffer, len);
-#endif
- } else {
- *err = kConnectionTimedOut;
- return 0;
- }
- if (rv < 0) {
-#ifdef _WIN32
- if (!m_blocking && WSAGetLastError() == WSAEWOULDBLOCK) {
-#else
- if (!m_blocking && (errno == EAGAIN || errno == EWOULDBLOCK)) {
-#endif
- *err = kWouldBlock;
- } else {
- *err = kConnectionReset;
- }
- return 0;
- }
- return static_cast<size_t>(rv);
-}
-
-void TCPStream::close() {
- if (m_sd >= 0) {
-#ifdef _WIN32
- ::shutdown(m_sd, SD_BOTH);
- closesocket(m_sd);
-#else
- ::shutdown(m_sd, SHUT_RDWR);
- ::close(m_sd);
-#endif
- }
- m_sd = -1;
-}
-
-std::string_view TCPStream::getPeerIP() const {
- return m_peerIP;
-}
-
-int TCPStream::getPeerPort() const {
- return m_peerPort;
-}
-
-void TCPStream::setNoDelay() {
- if (m_sd < 0) {
- return;
- }
- int optval = 1;
- setsockopt(m_sd, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<char*>(&optval),
- sizeof optval);
-}
-
-bool TCPStream::setBlocking(bool enabled) {
- if (m_sd < 0) {
- return true; // silently accept
- }
-#ifdef _WIN32
- u_long mode = enabled ? 0 : 1;
- if (ioctlsocket(m_sd, FIONBIO, &mode) == SOCKET_ERROR) {
- return false;
- }
-#else
- int flags = fcntl(m_sd, F_GETFL, nullptr);
- if (flags < 0) {
- return false;
- }
- if (enabled) {
- flags &= ~O_NONBLOCK;
- } else {
- flags |= O_NONBLOCK;
- }
- if (fcntl(m_sd, F_SETFL, flags) < 0) {
- return false;
- }
-#endif
- return true;
-}
-
-int TCPStream::getNativeHandle() const {
- return m_sd;
-}
-
-bool TCPStream::WaitForReadEvent(int timeout) {
- fd_set sdset;
- struct timeval tv;
-
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
- FD_ZERO(&sdset);
- FD_SET(m_sd, &sdset);
- if (select(m_sd + 1, &sdset, nullptr, nullptr, &tv) > 0) {
- return true;
- }
- return false;
-}
diff --git a/wpiutil/src/main/native/cpp/UDPClient.cpp b/wpiutil/src/main/native/cpp/UDPClient.cpp
deleted file mode 100644
index 108ef54..0000000
--- a/wpiutil/src/main/native/cpp/UDPClient.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-// 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/UDPClient.h"
-
-#ifdef _WIN32
-#include <WinSock2.h>
-#include <Ws2tcpip.h>
-#pragma comment(lib, "Ws2_32.lib")
-#else
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#include <unistd.h>
-#endif
-
-#include "wpi/Logger.h"
-#include "wpi/SmallString.h"
-#include "wpi/SocketError.h"
-
-using namespace wpi;
-
-UDPClient::UDPClient(Logger& logger) : UDPClient("", logger) {}
-
-UDPClient::UDPClient(std::string_view address, Logger& logger)
- : m_lsd(0), m_port(0), m_address(address), m_logger(logger) {}
-
-UDPClient::UDPClient(UDPClient&& other)
- : m_lsd(other.m_lsd),
- m_port(other.m_port),
- m_address(std::move(other.m_address)),
- m_logger(other.m_logger) {
- other.m_lsd = 0;
- other.m_port = 0;
-}
-
-UDPClient::~UDPClient() {
- if (m_lsd > 0) {
- shutdown();
- }
-}
-
-UDPClient& UDPClient::operator=(UDPClient&& other) {
- if (this == &other) {
- return *this;
- }
- shutdown();
- m_logger = other.m_logger;
- m_lsd = other.m_lsd;
- m_address = std::move(other.m_address);
- m_port = other.m_port;
- other.m_lsd = 0;
- other.m_port = 0;
- return *this;
-}
-
-int UDPClient::start() {
- return start(0);
-}
-
-int UDPClient::start(int port) {
- if (m_lsd > 0) {
- return 0;
- }
-
-#ifdef _WIN32
- WSAData wsaData;
- WORD wVersionRequested = MAKEWORD(2, 2);
- WSAStartup(wVersionRequested, &wsaData);
-#endif
-
- m_lsd = socket(AF_INET, SOCK_DGRAM, 0);
-
- if (m_lsd < 0) {
- WPI_ERROR(m_logger, "{}", "could not create socket");
- return -1;
- }
-
- struct sockaddr_in addr;
- std::memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- if (m_address.size() > 0) {
-#ifdef _WIN32
- SmallString<128> addr_copy(m_address);
- addr_copy.push_back('\0');
- int res = InetPton(PF_INET, addr_copy.data(), &(addr.sin_addr));
-#else
- int res = inet_pton(PF_INET, m_address.c_str(), &(addr.sin_addr));
-#endif
- if (res != 1) {
- WPI_ERROR(m_logger, "could not resolve {} address", m_address);
- return -1;
- }
- } else {
- addr.sin_addr.s_addr = INADDR_ANY;
- }
- addr.sin_port = htons(port);
-
- if (port != 0) {
-#ifdef _WIN32
- int optval = 1;
- setsockopt(m_lsd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
- reinterpret_cast<char*>(&optval), sizeof optval);
-#else
- int optval = 1;
- setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR,
- reinterpret_cast<char*>(&optval), sizeof optval);
-#endif
- }
-
- int result = bind(m_lsd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
- if (result != 0) {
- WPI_ERROR(m_logger, "bind() failed: {}", SocketStrerror());
- return result;
- }
- m_port = port;
- return 0;
-}
-
-void UDPClient::shutdown() {
- if (m_lsd > 0) {
-#ifdef _WIN32
- ::shutdown(m_lsd, SD_BOTH);
- closesocket(m_lsd);
- WSACleanup();
-#else
- ::shutdown(m_lsd, SHUT_RDWR);
- close(m_lsd);
-#endif
- m_lsd = 0;
- m_port = 0;
- }
-}
-
-int UDPClient::send(span<const uint8_t> data, std::string_view server,
- int port) {
- // server must be a resolvable IP address
- struct sockaddr_in addr;
- std::memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- SmallString<128> remoteAddr{server};
- if (remoteAddr.empty()) {
- WPI_ERROR(m_logger, "{}", "server must be passed");
- return -1;
- }
-
-#ifdef _WIN32
- int res = InetPton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
-#else
- int res = inet_pton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
-#endif
- if (res != 1) {
- WPI_ERROR(m_logger, "could not resolve {} address", server);
- return -1;
- }
- addr.sin_port = htons(port);
-
- // sendto should not block
- int result =
- sendto(m_lsd, reinterpret_cast<const char*>(data.data()), data.size(), 0,
- reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
- return result;
-}
-
-int UDPClient::send(std::string_view data, std::string_view server, int port) {
- // server must be a resolvable IP address
- struct sockaddr_in addr;
- std::memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- SmallString<128> remoteAddr{server};
- if (remoteAddr.empty()) {
- WPI_ERROR(m_logger, "{}", "server must be passed");
- return -1;
- }
-
-#ifdef _WIN32
- int res = InetPton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
-#else
- int res = inet_pton(AF_INET, remoteAddr.c_str(), &(addr.sin_addr));
-#endif
- if (res != 1) {
- WPI_ERROR(m_logger, "could not resolve {} address", server);
- return -1;
- }
- addr.sin_port = htons(port);
-
- // sendto should not block
- int result = sendto(m_lsd, data.data(), data.size(), 0,
- reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
- return result;
-}
-
-int UDPClient::receive(uint8_t* data_received, int receive_len) {
- if (m_port == 0) {
- return -1; // return if not receiving
- }
- return recv(m_lsd, reinterpret_cast<char*>(data_received), receive_len, 0);
-}
-
-int UDPClient::receive(uint8_t* data_received, int receive_len,
- SmallVectorImpl<char>* addr_received,
- int* port_received) {
- if (m_port == 0) {
- return -1; // return if not receiving
- }
-
- struct sockaddr_in remote;
- socklen_t remote_len = sizeof(remote);
- std::memset(&remote, 0, sizeof(remote));
-
- int result =
- recvfrom(m_lsd, reinterpret_cast<char*>(data_received), receive_len, 0,
- reinterpret_cast<sockaddr*>(&remote), &remote_len);
-
- char ip[50];
-#ifdef _WIN32
- InetNtop(PF_INET, &(remote.sin_addr.s_addr), ip, sizeof(ip) - 1);
-#else
- inet_ntop(PF_INET, reinterpret_cast<in_addr*>(&(remote.sin_addr.s_addr)), ip,
- sizeof(ip) - 1);
-#endif
-
- ip[49] = '\0';
- int addr_len = std::strlen(ip);
- addr_received->clear();
- addr_received->append(&ip[0], &ip[addr_len]);
-
- *port_received = ntohs(remote.sin_port);
-
- return result;
-}
-
-int UDPClient::set_timeout(double timeout) {
- if (timeout < 0) {
- return -1;
- }
- struct timeval tv;
- tv.tv_sec = timeout; // truncating will give seconds
- timeout -= tv.tv_sec; // remove seconds portion
- tv.tv_usec = timeout * 1000000; // fractions of a second to us
- int ret = setsockopt(m_lsd, SOL_SOCKET, SO_RCVTIMEO,
- reinterpret_cast<char*>(&tv), sizeof(tv));
- if (ret < 0) {
- WPI_ERROR(m_logger, "{}", "set timeout failed");
- }
- return ret;
-}
diff --git a/wpiutil/src/main/native/cpp/WebSocket.cpp b/wpiutil/src/main/native/cpp/WebSocket.cpp
deleted file mode 100644
index 4bb49d3..0000000
--- a/wpiutil/src/main/native/cpp/WebSocket.cpp
+++ /dev/null
@@ -1,656 +0,0 @@
-// 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/WebSocket.h"
-
-#include <random>
-
-#include "fmt/format.h"
-#include "wpi/Base64.h"
-#include "wpi/HttpParser.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/StringExtras.h"
-#include "wpi/raw_uv_ostream.h"
-#include "wpi/sha1.h"
-#include "wpi/uv/Stream.h"
-
-using namespace wpi;
-
-namespace {
-class WebSocketWriteReq : public uv::WriteReq {
- public:
- explicit WebSocketWriteReq(
- std::function<void(span<uv::Buffer>, uv::Error)> callback)
- : m_callback{std::move(callback)} {
- finish.connect([this](uv::Error err) {
- span<uv::Buffer> bufs{m_bufs};
- for (auto&& buf : bufs.subspan(0, m_startUser)) {
- buf.Deallocate();
- }
- m_callback(bufs.subspan(m_startUser), err);
- });
- }
-
- std::function<void(span<uv::Buffer>, uv::Error)> m_callback;
- SmallVector<uv::Buffer, 4> m_bufs;
- size_t m_startUser;
-};
-} // namespace
-
-class WebSocket::ClientHandshakeData {
- public:
- ClientHandshakeData() {
- // key is a random nonce
- static std::random_device rd;
- static std::default_random_engine gen{rd()};
- std::uniform_int_distribution<unsigned int> dist(0, 255);
- char nonce[16]; // the nonce sent to the server
- for (char& v : nonce) {
- v = static_cast<char>(dist(gen));
- }
- raw_svector_ostream os(key);
- Base64Encode(os, {nonce, 16});
- }
- ~ClientHandshakeData() {
- if (auto t = timer.lock()) {
- t->Stop();
- t->Close();
- }
- }
-
- SmallString<64> key; // the key sent to the server
- SmallVector<std::string, 2> protocols; // valid protocols
- HttpParser parser{HttpParser::kResponse}; // server response parser
- bool hasUpgrade = false;
- bool hasConnection = false;
- bool hasAccept = false;
- bool hasProtocol = false;
-
- std::weak_ptr<uv::Timer> timer;
-};
-
-static std::string_view AcceptHash(std::string_view key,
- SmallVectorImpl<char>& buf) {
- SHA1 hash;
- hash.Update(key);
- hash.Update("258EAFA5-E914-47DA-95CA-C5AB0DC85B11");
- SmallString<64> hashBuf;
- return Base64Encode(hash.RawFinal(hashBuf), buf);
-}
-
-WebSocket::WebSocket(uv::Stream& stream, bool server, const private_init&)
- : m_stream{stream}, m_server{server} {
- // Connect closed and error signals to ourselves
- m_stream.closed.connect([this]() { SetClosed(1006, "handle closed"); });
- m_stream.error.connect([this](uv::Error err) {
- Terminate(1006, fmt::format("stream error: {}", err.name()));
- });
-
- // Start reading
- m_stream.StopRead(); // we may have been reading
- m_stream.StartRead();
- m_stream.data.connect(
- [this](uv::Buffer& buf, size_t size) { HandleIncoming(buf, size); });
- m_stream.end.connect(
- [this]() { Terminate(1006, "remote end closed connection"); });
-}
-
-WebSocket::~WebSocket() = default;
-
-std::shared_ptr<WebSocket> WebSocket::CreateClient(
- uv::Stream& stream, std::string_view uri, std::string_view host,
- span<const std::string_view> protocols, const ClientOptions& options) {
- auto ws = std::make_shared<WebSocket>(stream, false, private_init{});
- stream.SetData(ws);
- ws->StartClient(uri, host, protocols, options);
- return ws;
-}
-
-std::shared_ptr<WebSocket> WebSocket::CreateServer(uv::Stream& stream,
- std::string_view key,
- std::string_view version,
- std::string_view protocol) {
- auto ws = std::make_shared<WebSocket>(stream, true, private_init{});
- stream.SetData(ws);
- ws->StartServer(key, version, protocol);
- return ws;
-}
-
-void WebSocket::Close(uint16_t code, std::string_view reason) {
- SendClose(code, reason);
- if (m_state != FAILED && m_state != CLOSED) {
- m_state = CLOSING;
- }
-}
-
-void WebSocket::Fail(uint16_t code, std::string_view reason) {
- if (m_state == FAILED || m_state == CLOSED) {
- return;
- }
- SendClose(code, reason);
- SetClosed(code, reason, true);
- Shutdown();
-}
-
-void WebSocket::Terminate(uint16_t code, std::string_view reason) {
- if (m_state == FAILED || m_state == CLOSED) {
- return;
- }
- SetClosed(code, reason);
- Shutdown();
-}
-
-void WebSocket::StartClient(std::string_view uri, std::string_view host,
- span<const std::string_view> protocols,
- const ClientOptions& options) {
- // Create client handshake data
- m_clientHandshake = std::make_unique<ClientHandshakeData>();
-
- // Build client request
- SmallVector<uv::Buffer, 4> bufs;
- raw_uv_ostream os{bufs, 4096};
-
- os << "GET " << uri << " HTTP/1.1\r\n";
- os << "Host: " << host << "\r\n";
- os << "Upgrade: websocket\r\n";
- os << "Connection: Upgrade\r\n";
- os << "Sec-WebSocket-Key: " << m_clientHandshake->key << "\r\n";
- os << "Sec-WebSocket-Version: 13\r\n";
-
- // protocols (if provided)
- if (!protocols.empty()) {
- os << "Sec-WebSocket-Protocol: ";
- bool first = true;
- for (auto protocol : protocols) {
- if (!first) {
- os << ", ";
- } else {
- first = false;
- }
- os << protocol;
- // also save for later checking against server response
- m_clientHandshake->protocols.emplace_back(protocol);
- }
- os << "\r\n";
- }
-
- // other headers
- for (auto&& header : options.extraHeaders) {
- os << header.first << ": " << header.second << "\r\n";
- }
-
- // finish headers
- os << "\r\n";
-
- // Send client request
- m_stream.Write(bufs, [](auto bufs, uv::Error) {
- for (auto& buf : bufs) {
- buf.Deallocate();
- }
- });
-
- // Set up client response handling
- m_clientHandshake->parser.status.connect([this](std::string_view status) {
- unsigned int code = m_clientHandshake->parser.GetStatusCode();
- if (code != 101) {
- Terminate(code, status);
- }
- });
- m_clientHandshake->parser.header.connect(
- [this](std::string_view name, std::string_view value) {
- value = trim(value);
- if (equals_lower(name, "upgrade")) {
- if (!equals_lower(value, "websocket")) {
- return Terminate(1002, "invalid upgrade response value");
- }
- m_clientHandshake->hasUpgrade = true;
- } else if (equals_lower(name, "connection")) {
- if (!equals_lower(value, "upgrade")) {
- return Terminate(1002, "invalid connection response value");
- }
- m_clientHandshake->hasConnection = true;
- } else if (equals_lower(name, "sec-websocket-accept")) {
- // Check against expected response
- SmallString<64> acceptBuf;
- if (!equals(value, AcceptHash(m_clientHandshake->key, acceptBuf))) {
- return Terminate(1002, "invalid accept key");
- }
- m_clientHandshake->hasAccept = true;
- } else if (equals_lower(name, "sec-websocket-extensions")) {
- // No extensions are supported
- if (!value.empty()) {
- return Terminate(1010, "unsupported extension");
- }
- } else if (equals_lower(name, "sec-websocket-protocol")) {
- // Make sure it was one of the provided protocols
- bool match = false;
- for (auto&& protocol : m_clientHandshake->protocols) {
- if (equals_lower(value, protocol)) {
- match = true;
- break;
- }
- }
- if (!match) {
- return Terminate(1003, "unsupported protocol");
- }
- m_clientHandshake->hasProtocol = true;
- m_protocol = value;
- }
- });
- m_clientHandshake->parser.headersComplete.connect([this](bool) {
- if (!m_clientHandshake->hasUpgrade || !m_clientHandshake->hasConnection ||
- !m_clientHandshake->hasAccept ||
- (!m_clientHandshake->hasProtocol &&
- !m_clientHandshake->protocols.empty())) {
- return Terminate(1002, "invalid response");
- }
- if (m_state == CONNECTING) {
- m_state = OPEN;
- open(m_protocol);
- }
- });
-
- // Start handshake timer if a timeout was specified
- if (options.handshakeTimeout != (uv::Timer::Time::max)()) {
- auto timer = uv::Timer::Create(m_stream.GetLoopRef());
- timer->timeout.connect(
- [this]() { Terminate(1006, "connection timed out"); });
- timer->Start(options.handshakeTimeout);
- m_clientHandshake->timer = timer;
- }
-}
-
-void WebSocket::StartServer(std::string_view key, std::string_view version,
- std::string_view protocol) {
- m_protocol = protocol;
-
- // Build server response
- SmallVector<uv::Buffer, 4> bufs;
- raw_uv_ostream os{bufs, 4096};
-
- // Handle unsupported version
- if (version != "13") {
- os << "HTTP/1.1 426 Upgrade Required\r\n";
- os << "Upgrade: WebSocket\r\n";
- os << "Sec-WebSocket-Version: 13\r\n\r\n";
- m_stream.Write(bufs, [this](auto bufs, uv::Error) {
- for (auto& buf : bufs) {
- buf.Deallocate();
- }
- // XXX: Should we support sending a new handshake on the same connection?
- // XXX: "this->" is required by GCC 5.5 (bug)
- this->Terminate(1003, "unsupported protocol version");
- });
- return;
- }
-
- os << "HTTP/1.1 101 Switching Protocols\r\n";
- os << "Upgrade: websocket\r\n";
- os << "Connection: Upgrade\r\n";
-
- // accept hash
- SmallString<64> acceptBuf;
- os << "Sec-WebSocket-Accept: " << AcceptHash(key, acceptBuf) << "\r\n";
-
- if (!protocol.empty()) {
- os << "Sec-WebSocket-Protocol: " << protocol << "\r\n";
- }
-
- // end headers
- os << "\r\n";
-
- // Send server response
- m_stream.Write(bufs, [this](auto bufs, uv::Error) {
- for (auto& buf : bufs) {
- buf.Deallocate();
- }
- if (m_state == CONNECTING) {
- m_state = OPEN;
- open(m_protocol);
- }
- });
-}
-
-void WebSocket::SendClose(uint16_t code, std::string_view reason) {
- SmallVector<uv::Buffer, 4> bufs;
- if (code != 1005) {
- raw_uv_ostream os{bufs, 4096};
- const uint8_t codeMsb[] = {static_cast<uint8_t>((code >> 8) & 0xff),
- static_cast<uint8_t>(code & 0xff)};
- os << span{codeMsb};
- os << reason;
- }
- Send(kFlagFin | kOpClose, bufs, [](auto bufs, uv::Error) {
- for (auto&& buf : bufs) {
- buf.Deallocate();
- }
- });
-}
-
-void WebSocket::SetClosed(uint16_t code, std::string_view reason, bool failed) {
- if (m_state == FAILED || m_state == CLOSED) {
- return;
- }
- m_state = failed ? FAILED : CLOSED;
- closed(code, reason);
-}
-
-void WebSocket::Shutdown() {
- m_stream.Shutdown([this] { m_stream.Close(); });
-}
-
-void WebSocket::HandleIncoming(uv::Buffer& buf, size_t size) {
- // ignore incoming data if we're failed or closed
- if (m_state == FAILED || m_state == CLOSED) {
- return;
- }
-
- std::string_view data{buf.base, size};
-
- // Handle connecting state (mainly on client)
- if (m_state == CONNECTING) {
- if (m_clientHandshake) {
- data = m_clientHandshake->parser.Execute(data);
- // check for parser failure
- if (m_clientHandshake->parser.HasError()) {
- return Terminate(1003, "invalid response");
- }
- if (m_state != OPEN) {
- return; // not done with handshake yet
- }
-
- // we're done with the handshake, so release its memory
- m_clientHandshake.reset();
-
- // fall through to process additional data after handshake
- } else {
- return Terminate(1003, "got data on server before response");
- }
- }
-
- // Message processing
- while (!data.empty()) {
- if (m_frameSize == UINT64_MAX) {
- // Need at least two bytes to determine header length
- if (m_header.size() < 2u) {
- size_t toCopy = (std::min)(2u - m_header.size(), data.size());
- m_header.append(data.data(), data.data() + toCopy);
- data.remove_prefix(toCopy);
- if (m_header.size() < 2u) {
- return; // need more data
- }
-
- // Validate RSV bits are zero
- if ((m_header[0] & 0x70) != 0) {
- return Fail(1002, "nonzero RSV");
- }
- }
-
- // Once we have first two bytes, we can calculate the header size
- if (m_headerSize == 0) {
- m_headerSize = 2;
- uint8_t len = m_header[1] & kLenMask;
- if (len == 126) {
- m_headerSize += 2;
- } else if (len == 127) {
- m_headerSize += 8;
- }
- bool masking = (m_header[1] & kFlagMasking) != 0;
- if (masking) {
- m_headerSize += 4; // masking key
- }
- // On server side, incoming messages MUST be masked
- // On client side, incoming messages MUST NOT be masked
- if (m_server && !masking) {
- return Fail(1002, "client data not masked");
- }
- if (!m_server && masking) {
- return Fail(1002, "server data masked");
- }
- }
-
- // Need to complete header to calculate message size
- if (m_header.size() < m_headerSize) {
- size_t toCopy = (std::min)(m_headerSize - m_header.size(), data.size());
- m_header.append(data.data(), data.data() + toCopy);
- data.remove_prefix(toCopy);
- if (m_header.size() < m_headerSize) {
- return; // need more data
- }
- }
-
- if (m_header.size() >= m_headerSize) {
- // get payload length
- uint8_t len = m_header[1] & kLenMask;
- if (len == 126) {
- m_frameSize = (static_cast<uint16_t>(m_header[2]) << 8) |
- static_cast<uint16_t>(m_header[3]);
- } else if (len == 127) {
- m_frameSize = (static_cast<uint64_t>(m_header[2]) << 56) |
- (static_cast<uint64_t>(m_header[3]) << 48) |
- (static_cast<uint64_t>(m_header[4]) << 40) |
- (static_cast<uint64_t>(m_header[5]) << 32) |
- (static_cast<uint64_t>(m_header[6]) << 24) |
- (static_cast<uint64_t>(m_header[7]) << 16) |
- (static_cast<uint64_t>(m_header[8]) << 8) |
- static_cast<uint64_t>(m_header[9]);
- } else {
- m_frameSize = len;
- }
-
- // limit maximum size
- if ((m_payload.size() + m_frameSize) > m_maxMessageSize) {
- return Fail(1009, "message too large");
- }
- }
- }
-
- if (m_frameSize != UINT64_MAX) {
- size_t need = m_frameStart + m_frameSize - m_payload.size();
- size_t toCopy = (std::min)(need, data.size());
- m_payload.append(data.data(), data.data() + toCopy);
- data.remove_prefix(toCopy);
- need -= toCopy;
- if (need == 0) {
- // We have a complete frame
- // If the message had masking, unmask it
- if ((m_header[1] & kFlagMasking) != 0) {
- uint8_t key[4] = {
- m_header[m_headerSize - 4], m_header[m_headerSize - 3],
- m_header[m_headerSize - 2], m_header[m_headerSize - 1]};
- int n = 0;
- for (uint8_t& ch : span{m_payload}.subspan(m_frameStart)) {
- ch ^= key[n++];
- if (n >= 4) {
- n = 0;
- }
- }
- }
-
- // Handle message
- bool fin = (m_header[0] & kFlagFin) != 0;
- uint8_t opcode = m_header[0] & kOpMask;
- switch (opcode) {
- case kOpCont:
- switch (m_fragmentOpcode) {
- case kOpText:
- if (!m_combineFragments || fin) {
- text(std::string_view{reinterpret_cast<char*>(
- m_payload.data()),
- m_payload.size()},
- fin);
- }
- break;
- case kOpBinary:
- if (!m_combineFragments || fin) {
- binary(m_payload, fin);
- }
- break;
- default:
- // no preceding message?
- return Fail(1002, "invalid continuation message");
- }
- if (fin) {
- m_fragmentOpcode = 0;
- }
- break;
- case kOpText:
- if (m_fragmentOpcode != 0) {
- return Fail(1002, "incomplete fragment");
- }
- if (!m_combineFragments || fin) {
- text(std::string_view{reinterpret_cast<char*>(m_payload.data()),
- m_payload.size()},
- fin);
- }
- if (!fin) {
- m_fragmentOpcode = opcode;
- }
- break;
- case kOpBinary:
- if (m_fragmentOpcode != 0) {
- return Fail(1002, "incomplete fragment");
- }
- if (!m_combineFragments || fin) {
- binary(m_payload, fin);
- }
- if (!fin) {
- m_fragmentOpcode = opcode;
- }
- break;
- case kOpClose: {
- uint16_t code;
- std::string_view reason;
- if (!fin) {
- code = 1002;
- reason = "cannot fragment control frames";
- } else if (m_payload.size() < 2) {
- code = 1005;
- } else {
- code = (static_cast<uint16_t>(m_payload[0]) << 8) |
- static_cast<uint16_t>(m_payload[1]);
- reason = drop_front(
- {reinterpret_cast<char*>(m_payload.data()), m_payload.size()},
- 2);
- }
- // Echo the close if we didn't previously send it
- if (m_state != CLOSING) {
- SendClose(code, reason);
- }
- SetClosed(code, reason);
- // If we're the server, shutdown the connection.
- if (m_server) {
- Shutdown();
- }
- break;
- }
- case kOpPing:
- if (!fin) {
- return Fail(1002, "cannot fragment control frames");
- }
- ping(m_payload);
- break;
- case kOpPong:
- if (!fin) {
- return Fail(1002, "cannot fragment control frames");
- }
- pong(m_payload);
- break;
- default:
- return Fail(1002, "invalid message opcode");
- }
-
- // Prepare for next message
- m_header.clear();
- m_headerSize = 0;
- if (!m_combineFragments || fin) {
- m_payload.clear();
- }
- m_frameStart = m_payload.size();
- m_frameSize = UINT64_MAX;
- }
- }
- }
-}
-
-void WebSocket::Send(
- uint8_t opcode, span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- // If we're not open, emit an error and don't send the data
- if (m_state != OPEN) {
- int err;
- if (m_state == CONNECTING) {
- err = UV_EAGAIN;
- } else {
- err = UV_ESHUTDOWN;
- }
- SmallVector<uv::Buffer, 4> bufs{data.begin(), data.end()};
- callback(bufs, uv::Error{err});
- return;
- }
-
- auto req = std::make_shared<WebSocketWriteReq>(std::move(callback));
- raw_uv_ostream os{req->m_bufs, 4096};
-
- // opcode (includes FIN bit)
- os << static_cast<unsigned char>(opcode);
-
- // payload length
- uint64_t size = 0;
- for (auto&& buf : data) {
- size += buf.len;
- }
- if (size < 126) {
- os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | size);
- } else if (size <= 0xffff) {
- os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 126);
- const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 8) & 0xff),
- static_cast<uint8_t>(size & 0xff)};
- os << span{sizeMsb};
- } else {
- os << static_cast<unsigned char>((m_server ? 0x00 : kFlagMasking) | 127);
- const uint8_t sizeMsb[] = {static_cast<uint8_t>((size >> 56) & 0xff),
- static_cast<uint8_t>((size >> 48) & 0xff),
- static_cast<uint8_t>((size >> 40) & 0xff),
- static_cast<uint8_t>((size >> 32) & 0xff),
- static_cast<uint8_t>((size >> 24) & 0xff),
- static_cast<uint8_t>((size >> 16) & 0xff),
- static_cast<uint8_t>((size >> 8) & 0xff),
- static_cast<uint8_t>(size & 0xff)};
- os << span{sizeMsb};
- }
-
- // clients need to mask the input data
- if (!m_server) {
- // generate masking key
- static std::random_device rd;
- static std::default_random_engine gen{rd()};
- std::uniform_int_distribution<unsigned int> dist(0, 255);
- uint8_t key[4];
- for (uint8_t& v : key) {
- v = dist(gen);
- }
- os << span<const uint8_t>{key, 4};
- // copy and mask data
- int n = 0;
- for (auto&& buf : data) {
- for (auto&& ch : buf.data()) {
- os << static_cast<unsigned char>(static_cast<uint8_t>(ch) ^ key[n++]);
- if (n >= 4) {
- n = 0;
- }
- }
- }
- req->m_startUser = req->m_bufs.size();
- req->m_bufs.append(data.begin(), data.end());
- // don't send the user bufs as we copied their data
- m_stream.Write(span{req->m_bufs}.subspan(0, req->m_startUser), req);
- } else {
- // servers can just send the buffers directly without masking
- req->m_startUser = req->m_bufs.size();
- req->m_bufs.append(data.begin(), data.end());
- m_stream.Write(req->m_bufs, req);
- }
-}
diff --git a/wpiutil/src/main/native/cpp/WebSocketServer.cpp b/wpiutil/src/main/native/cpp/WebSocketServer.cpp
deleted file mode 100644
index 1562f3b..0000000
--- a/wpiutil/src/main/native/cpp/WebSocketServer.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-// 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/WebSocketServer.h"
-
-#include <utility>
-
-#include "wpi/StringExtras.h"
-#include "wpi/fmt/raw_ostream.h"
-#include "wpi/raw_uv_ostream.h"
-#include "wpi/uv/Buffer.h"
-#include "wpi/uv/Stream.h"
-
-using namespace wpi;
-
-WebSocketServerHelper::WebSocketServerHelper(HttpParser& req) {
- req.header.connect([this](std::string_view name, std::string_view value) {
- if (equals_lower(name, "host")) {
- m_gotHost = true;
- } else if (equals_lower(name, "upgrade")) {
- if (equals_lower(value, "websocket")) {
- m_websocket = true;
- }
- } else if (equals_lower(name, "sec-websocket-key")) {
- m_key = value;
- } else if (equals_lower(name, "sec-websocket-version")) {
- m_version = value;
- } else if (equals_lower(name, "sec-websocket-protocol")) {
- // Protocols are comma delimited, repeated headers add to list
- SmallVector<std::string_view, 2> protocols;
- split(value, protocols, ",", -1, false);
- for (auto protocol : protocols) {
- protocol = trim(protocol);
- if (!protocol.empty()) {
- m_protocols.emplace_back(protocol);
- }
- }
- }
- });
- req.headersComplete.connect([&req, this](bool) {
- if (req.IsUpgrade() && IsUpgrade()) {
- upgrade();
- }
- });
-}
-
-std::pair<bool, std::string_view> WebSocketServerHelper::MatchProtocol(
- span<const std::string_view> protocols) {
- if (protocols.empty() && m_protocols.empty()) {
- return {true, {}};
- }
- for (auto protocol : protocols) {
- for (auto&& clientProto : m_protocols) {
- if (protocol == clientProto) {
- return {true, protocol};
- }
- }
- }
- return {false, {}};
-}
-
-WebSocketServer::WebSocketServer(uv::Stream& stream,
- span<const std::string_view> protocols,
- ServerOptions options, const private_init&)
- : m_stream{stream},
- m_helper{m_req},
- m_protocols{protocols.begin(), protocols.end()},
- m_options{std::move(options)} {
- // Header handling
- m_req.header.connect([this](std::string_view name, std::string_view value) {
- if (equals_lower(name, "host")) {
- if (m_options.checkHost) {
- if (!m_options.checkHost(value)) {
- Abort(401, "Unrecognized Host");
- }
- }
- }
- });
- m_req.url.connect([this](std::string_view name) {
- if (m_options.checkUrl) {
- if (!m_options.checkUrl(name)) {
- Abort(404, "Not Found");
- }
- }
- });
- m_req.headersComplete.connect([this](bool) {
- // We only accept websocket connections
- if (!m_helper.IsUpgrade() || !m_req.IsUpgrade()) {
- Abort(426, "Upgrade Required");
- }
- });
-
- // Handle upgrade event
- m_helper.upgrade.connect([this] {
- if (m_aborted) {
- return;
- }
-
- // Negotiate sub-protocol
- SmallVector<std::string_view, 2> protocols{m_protocols.begin(),
- m_protocols.end()};
- std::string_view protocol = m_helper.MatchProtocol(protocols).second;
-
- // Disconnect our header reader
- m_dataConn.disconnect();
-
- // Accepting the stream may destroy this (as it replaces the stream user
- // data), so grab a shared pointer first.
- auto self = shared_from_this();
-
- // Accept the upgrade
- auto ws = m_helper.Accept(m_stream, protocol);
-
- // Connect the websocket open event to our connected event.
- ws->open.connect_extended(
- [self, s = ws.get()](auto conn, std::string_view) {
- self->connected(self->m_req.GetUrl(), *s);
- conn.disconnect(); // one-shot
- });
- });
-
- // Set up stream
- stream.StartRead();
- m_dataConn =
- stream.data.connect_connection([this](uv::Buffer& buf, size_t size) {
- if (m_aborted) {
- return;
- }
- m_req.Execute(std::string_view{buf.base, size});
- if (m_req.HasError()) {
- Abort(400, "Bad Request");
- }
- });
- m_errorConn =
- stream.error.connect_connection([this](uv::Error) { m_stream.Close(); });
- m_endConn = stream.end.connect_connection([this] { m_stream.Close(); });
-}
-
-std::shared_ptr<WebSocketServer> WebSocketServer::Create(
- uv::Stream& stream, span<const std::string_view> protocols,
- const ServerOptions& options) {
- auto server = std::make_shared<WebSocketServer>(stream, protocols, options,
- private_init{});
- stream.SetData(server);
- return server;
-}
-
-void WebSocketServer::Abort(uint16_t code, std::string_view reason) {
- if (m_aborted) {
- return;
- }
- m_aborted = true;
-
- // Build response
- SmallVector<uv::Buffer, 4> bufs;
- raw_uv_ostream os{bufs, 1024};
-
- // Handle unsupported version
- fmt::print(os, "HTTP/1.1 {} {}\r\n", code, reason);
- if (code == 426) {
- os << "Upgrade: WebSocket\r\n";
- }
- os << "\r\n";
- m_stream.Write(bufs, [this](auto bufs, uv::Error) {
- for (auto& buf : bufs) {
- buf.Deallocate();
- }
- m_stream.Shutdown([this] { m_stream.Close(); });
- });
-}
diff --git a/wpiutil/src/main/native/cpp/fs.cpp b/wpiutil/src/main/native/cpp/fs.cpp
index 34d6cca..fad6a66 100644
--- a/wpiutil/src/main/native/cpp/fs.cpp
+++ b/wpiutil/src/main/native/cpp/fs.cpp
@@ -82,17 +82,6 @@
const file_t kInvalidFile = INVALID_HANDLE_VALUE;
static DWORD nativeDisposition(CreationDisposition Disp, OpenFlags Flags) {
- // This is a compatibility hack. Really we should respect the creation
- // disposition, but a lot of old code relied on the implicit assumption that
- // OF_Append implied it would open an existing file. Since the disposition is
- // now explicit and defaults to CD_CreateAlways, this assumption would cause
- // any usage of OF_Append to append to a new file, even if the file already
- // existed. A better solution might have two new creation dispositions:
- // CD_AppendAlways and CD_AppendNew. This would also address the problem of
- // OF_Append being used on a read-only descriptor, which doesn't make sense.
- if (Flags & OF_Append)
- return OPEN_ALWAYS;
-
switch (Disp) {
case CD_CreateAlways:
return CREATE_ALWAYS;
@@ -251,12 +240,6 @@
Result |= O_RDWR;
}
- // This is for compatibility with old code that assumed F_Append implied
- // would open an existing file. See Windows/Path.inc for a longer comment.
- if (Flags & F_Append) {
- Disp = CD_OpenAlways;
- }
-
if (Disp == CD_CreateNew) {
Result |= O_CREAT; // Create if it doesn't exist.
Result |= O_EXCL; // Fail if it does.
diff --git a/wpiutil/src/main/native/cpp/hostname.cpp b/wpiutil/src/main/native/cpp/hostname.cpp
deleted file mode 100644
index d907023..0000000
--- a/wpiutil/src/main/native/cpp/hostname.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-// 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/hostname.h"
-
-#include <cstdlib>
-#include <string>
-#include <string_view>
-
-#include "uv.h"
-#include "wpi/SmallVector.h"
-
-namespace wpi {
-
-std::string GetHostname() {
- std::string rv;
- char name[256];
- size_t size = sizeof(name);
-
- int err = uv_os_gethostname(name, &size);
- if (err == 0) {
- rv.assign(name, size);
- } else if (err == UV_ENOBUFS) {
- char* name2 = static_cast<char*>(std::malloc(size));
- err = uv_os_gethostname(name2, &size);
- if (err == 0) {
- rv.assign(name2, size);
- }
- std::free(name2);
- }
-
- return rv;
-}
-
-std::string_view GetHostname(SmallVectorImpl<char>& name) {
- // Use a tmp array to not require the SmallVector to be too large.
- char tmpName[256];
- size_t size = sizeof(tmpName);
-
- name.clear();
-
- int err = uv_os_gethostname(tmpName, &size);
- if (err == 0) {
- name.append(tmpName, tmpName + size);
- } else if (err == UV_ENOBUFS) {
- name.resize(size);
- err = uv_os_gethostname(name.data(), &size);
- if (err != 0) {
- size = 0;
- }
- }
-
- return {name.data(), size};
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/http_parser.cpp b/wpiutil/src/main/native/cpp/http_parser.cpp
deleted file mode 100644
index bc442b2..0000000
--- a/wpiutil/src/main/native/cpp/http_parser.cpp
+++ /dev/null
@@ -1,2475 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors.
- *
- * 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/http_parser.h"
-#include <assert.h>
-#include <stddef.h>
-#include <ctype.h>
-#include <string.h>
-#include <limits.h>
-
-#ifdef _WIN32
-#pragma warning(disable : 4018 26451)
-#endif
-
-#ifndef ULLONG_MAX
-# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */
-#endif
-
-#ifndef MIN
-# define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#ifndef ARRAY_SIZE
-# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-#ifndef BIT_AT
-# define BIT_AT(a, i) \
- (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \
- (1 << ((unsigned int) (i) & 7))))
-#endif
-
-#ifndef ELEM_AT
-# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v))
-#endif
-
-#define SET_ERRNO(e) \
-do { \
- parser->nread = nread; \
- parser->http_errno = (e); \
-} while(0)
-
-#define CURRENT_STATE() p_state
-#define UPDATE_STATE(V) p_state = (enum state) (V);
-#define RETURN(V) \
-do { \
- parser->nread = nread; \
- parser->state = CURRENT_STATE(); \
- return (V); \
-} while (0);
-#define REEXECUTE() \
- goto reexecute; \
-
-
-#ifdef __GNUC__
-# define LIKELY(X) __builtin_expect(!!(X), 1)
-# define UNLIKELY(X) __builtin_expect(!!(X), 0)
-#else
-# define LIKELY(X) (X)
-# define UNLIKELY(X) (X)
-#endif
-
-
-/* Run the notify callback FOR, returning ER if it fails */
-#define CALLBACK_NOTIFY_(FOR, ER) \
-do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
- \
- if (LIKELY(settings->on_##FOR)) { \
- parser->state = CURRENT_STATE(); \
- if (UNLIKELY(0 != settings->on_##FOR(parser))) { \
- SET_ERRNO(HPE_CB_##FOR); \
- } \
- UPDATE_STATE(parser->state); \
- \
- /* We either errored above or got paused; get out */ \
- if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
- return (ER); \
- } \
- } \
-} while (0)
-
-/* Run the notify callback FOR and consume the current byte */
-#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1)
-
-/* Run the notify callback FOR and don't consume the current byte */
-#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data)
-
-/* Run data callback FOR with LEN bytes, returning ER if it fails */
-#define CALLBACK_DATA_(FOR, LEN, ER) \
-do { \
- assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \
- \
- if (FOR##_mark) { \
- if (LIKELY(settings->on_##FOR)) { \
- parser->state = CURRENT_STATE(); \
- if (UNLIKELY(0 != \
- settings->on_##FOR(parser, FOR##_mark, (LEN)))) { \
- SET_ERRNO(HPE_CB_##FOR); \
- } \
- UPDATE_STATE(parser->state); \
- \
- /* We either errored above or got paused; get out */ \
- if (UNLIKELY(HTTP_PARSER_ERRNO(parser) != HPE_OK)) { \
- return (ER); \
- } \
- } \
- FOR##_mark = NULL; \
- } \
-} while (0)
-
-/* Run the data callback FOR and consume the current byte */
-#define CALLBACK_DATA(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
-
-/* Run the data callback FOR and don't consume the current byte */
-#define CALLBACK_DATA_NOADVANCE(FOR) \
- CALLBACK_DATA_(FOR, p - FOR##_mark, p - data)
-
-/* Set the mark FOR; non-destructive if mark is already set */
-#define MARK(FOR) \
-do { \
- if (!FOR##_mark) { \
- FOR##_mark = p; \
- } \
-} while (0)
-
-/* Don't allow the total size of the HTTP headers (including the status
- * line) to exceed HTTP_MAX_HEADER_SIZE. This check is here to protect
- * embedders against denial-of-service attacks where the attacker feeds
- * us a never-ending header that the embedder keeps buffering.
- *
- * This check is arguably the responsibility of embedders but we're doing
- * it on the embedder's behalf because most won't bother and this way we
- * make the web a little safer. HTTP_MAX_HEADER_SIZE is still far bigger
- * than any reasonable request or response so this should never affect
- * day-to-day operation.
- */
-#define COUNT_HEADER_SIZE(V) \
-do { \
- nread += (V); \
- if (UNLIKELY(nread > (HTTP_MAX_HEADER_SIZE))) { \
- SET_ERRNO(HPE_HEADER_OVERFLOW); \
- goto error; \
- } \
-} while (0)
-
-
-#define PROXY_CONNECTION "proxy-connection"
-#define CONNECTION "connection"
-#define CONTENT_LENGTH "content-length"
-#define TRANSFER_ENCODING "transfer-encoding"
-#define UPGRADE "upgrade"
-#define CHUNKED "chunked"
-#define KEEP_ALIVE "keep-alive"
-#define CLOSE "close"
-
-namespace wpi {
-
-
-static const char *method_strings[] =
- {
-#define XX(num, name, string) #string,
- HTTP_METHOD_MAP(XX)
-#undef XX
- };
-
-
-/* Tokens as defined by rfc 2616. Also lowercases them.
- * token = 1*<any CHAR except CTLs or separators>
- * separators = "(" | ")" | "<" | ">" | "@"
- * | "," | ";" | ":" | "\" | <">
- * | "/" | "[" | "]" | "?" | "="
- * | "{" | "}" | SP | HT
- */
-static const char tokens[256] = {
-/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
- 0, 0, 0, 0, 0, 0, 0, 0,
-/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
- 0, 0, 0, 0, 0, 0, 0, 0,
-/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
- 0, 0, 0, 0, 0, 0, 0, 0,
-/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
- 0, 0, 0, 0, 0, 0, 0, 0,
-/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
- ' ', '!', 0, '#', '$', '%', '&', '\'',
-/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
- 0, 0, '*', '+', 0, '-', '.', 0,
-/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
- '0', '1', '2', '3', '4', '5', '6', '7',
-/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
- '8', '9', 0, 0, 0, 0, 0, 0,
-/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
- 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
- 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
-/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
- 'x', 'y', 'z', 0, 0, 0, '^', '_',
-/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
- '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
-/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
- 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
-/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
- 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
-/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
- 'x', 'y', 'z', 0, '|', 0, '~', 0 };
-
-
-static const int8_t unhex[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
- , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1
- ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1
- ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
- };
-
-
-#if HTTP_PARSER_STRICT
-# define T(v) 0
-#else
-# define T(v) v
-#endif
-
-
-static const uint8_t normal_url_char[32] = {
-/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */
- 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
-/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */
- 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0,
-/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */
- 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
-/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */
- 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0,
-/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */
- 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128,
-/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0,
-/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128,
-/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */
- 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, };
-
-#undef T
-
-enum state
- { s_dead = 1 /* important that this is > 0 */
-
- , s_start_req_or_res
- , s_res_or_resp_H
- , s_start_res
- , s_res_H
- , s_res_HT
- , s_res_HTT
- , s_res_HTTP
- , s_res_http_major
- , s_res_http_dot
- , s_res_http_minor
- , s_res_http_end
- , s_res_first_status_code
- , s_res_status_code
- , s_res_status_start
- , s_res_status
- , s_res_line_almost_done
-
- , s_start_req
-
- , s_req_method
- , s_req_spaces_before_url
- , s_req_schema
- , s_req_schema_slash
- , s_req_schema_slash_slash
- , s_req_server_start
- , s_req_server
- , s_req_server_with_at
- , s_req_path
- , s_req_query_string_start
- , s_req_query_string
- , s_req_fragment_start
- , s_req_fragment
- , s_req_http_start
- , s_req_http_H
- , s_req_http_HT
- , s_req_http_HTT
- , s_req_http_HTTP
- , s_req_http_major
- , s_req_http_dot
- , s_req_http_minor
- , s_req_http_end
- , s_req_line_almost_done
-
- , s_header_field_start
- , s_header_field
- , s_header_value_discard_ws
- , s_header_value_discard_ws_almost_done
- , s_header_value_discard_lws
- , s_header_value_start
- , s_header_value
- , s_header_value_lws
-
- , s_header_almost_done
-
- , s_chunk_size_start
- , s_chunk_size
- , s_chunk_parameters
- , s_chunk_size_almost_done
-
- , s_headers_almost_done
- , s_headers_done
-
- /* Important: 's_headers_done' must be the last 'header' state. All
- * states beyond this must be 'body' states. It is used for overflow
- * checking. See the PARSING_HEADER() macro.
- */
-
- , s_chunk_data
- , s_chunk_data_almost_done
- , s_chunk_data_done
-
- , s_body_identity
- , s_body_identity_eof
-
- , s_message_done
- };
-
-
-#define PARSING_HEADER(state) (state <= s_headers_done)
-
-
-enum header_states
- { h_general = 0
- , h_C
- , h_CO
- , h_CON
-
- , h_matching_connection
- , h_matching_proxy_connection
- , h_matching_content_length
- , h_matching_transfer_encoding
- , h_matching_upgrade
-
- , h_connection
- , h_content_length
- , h_content_length_num
- , h_content_length_ws
- , h_transfer_encoding
- , h_upgrade
-
- , h_matching_transfer_encoding_chunked
- , h_matching_connection_token_start
- , h_matching_connection_keep_alive
- , h_matching_connection_close
- , h_matching_connection_upgrade
- , h_matching_connection_token
-
- , h_transfer_encoding_chunked
- , h_connection_keep_alive
- , h_connection_close
- , h_connection_upgrade
- };
-
-enum http_host_state
- {
- s_http_host_dead = 1
- , s_http_userinfo_start
- , s_http_userinfo
- , s_http_host_start
- , s_http_host_v6_start
- , s_http_host
- , s_http_host_v6
- , s_http_host_v6_end
- , s_http_host_v6_zone_start
- , s_http_host_v6_zone
- , s_http_host_port_start
- , s_http_host_port
-};
-
-/* Macros for character classes; depends on strict-mode */
-#define CR '\r'
-#define LF '\n'
-#define LOWER(c) (unsigned char)(c | 0x20)
-#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z')
-#define IS_NUM(c) ((c) >= '0' && (c) <= '9')
-#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c))
-#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f'))
-#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \
- (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \
- (c) == ')')
-#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \
- (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \
- (c) == '$' || (c) == ',')
-
-#define STRICT_TOKEN(c) ((c == ' ') ? 0 : tokens[(unsigned char)c])
-
-#if HTTP_PARSER_STRICT
-#define TOKEN(c) STRICT_TOKEN(c)
-#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c))
-#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-')
-#else
-#define TOKEN(c) tokens[(unsigned char)c]
-#define IS_URL_CHAR(c) \
- (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80))
-#define IS_HOST_CHAR(c) \
- (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_')
-#endif
-
-/**
- * Verify that a char is a valid visible (printable) US-ASCII
- * character or %x80-FF
- **/
-#define IS_HEADER_CHAR(ch) \
- (ch == CR || ch == LF || ch == 9 || ((unsigned char)ch > 31 && ch != 127))
-
-#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res)
-
-
-#if HTTP_PARSER_STRICT
-# define STRICT_CHECK(cond) \
-do { \
- if (cond) { \
- SET_ERRNO(HPE_STRICT); \
- goto error; \
- } \
-} while (0)
-# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead)
-#else
-# define STRICT_CHECK(cond)
-# define NEW_MESSAGE() start_state
-#endif
-
-
-/* Map errno values to strings for human-readable output */
-#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s },
-static struct {
- const char *name;
- const char *description;
-} http_strerror_tab[] = {
- HTTP_ERRNO_MAP(HTTP_STRERROR_GEN)
-};
-#undef HTTP_STRERROR_GEN
-
-int http_message_needs_eof(const http_parser *parser);
-
-/* Our URL parser.
- *
- * This is designed to be shared by http_parser_execute() for URL validation,
- * hence it has a state transition + byte-for-byte interface. In addition, it
- * is meant to be embedded in http_parser_parse_url(), which does the dirty
- * work of turning state transitions URL components for its API.
- *
- * This function should only be invoked with non-space characters. It is
- * assumed that the caller cares about (and can detect) the transition between
- * URL and non-URL states by looking for these.
- */
-static enum state
-parse_url_char(enum state s, const char ch)
-{
- if (ch == ' ' || ch == '\r' || ch == '\n') {
- return s_dead;
- }
-
-#if HTTP_PARSER_STRICT
- if (ch == '\t' || ch == '\f') {
- return s_dead;
- }
-#endif
-
- switch (s) {
- case s_req_spaces_before_url:
- /* Proxied requests are followed by scheme of an absolute URI (alpha).
- * All methods except CONNECT are followed by '/' or '*'.
- */
-
- if (ch == '/' || ch == '*') {
- return s_req_path;
- }
-
- if (IS_ALPHA(ch)) {
- return s_req_schema;
- }
-
- break;
-
- case s_req_schema:
- if (IS_ALPHA(ch)) {
- return s;
- }
-
- if (ch == ':') {
- return s_req_schema_slash;
- }
-
- break;
-
- case s_req_schema_slash:
- if (ch == '/') {
- return s_req_schema_slash_slash;
- }
-
- break;
-
- case s_req_schema_slash_slash:
- if (ch == '/') {
- return s_req_server_start;
- }
-
- break;
-
- case s_req_server_with_at:
- if (ch == '@') {
- return s_dead;
- }
-
- /* fall through */
- case s_req_server_start:
- case s_req_server:
- if (ch == '/') {
- return s_req_path;
- }
-
- if (ch == '?') {
- return s_req_query_string_start;
- }
-
- if (ch == '@') {
- return s_req_server_with_at;
- }
-
- if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') {
- return s_req_server;
- }
-
- break;
-
- case s_req_path:
- if (IS_URL_CHAR(ch)) {
- return s;
- }
-
- switch (ch) {
- case '?':
- return s_req_query_string_start;
-
- case '#':
- return s_req_fragment_start;
- }
-
- break;
-
- case s_req_query_string_start:
- case s_req_query_string:
- if (IS_URL_CHAR(ch)) {
- return s_req_query_string;
- }
-
- switch (ch) {
- case '?':
- /* allow extra '?' in query string */
- return s_req_query_string;
-
- case '#':
- return s_req_fragment_start;
- }
-
- break;
-
- case s_req_fragment_start:
- if (IS_URL_CHAR(ch)) {
- return s_req_fragment;
- }
-
- switch (ch) {
- case '?':
- return s_req_fragment;
-
- case '#':
- return s;
- }
-
- break;
-
- case s_req_fragment:
- if (IS_URL_CHAR(ch)) {
- return s;
- }
-
- switch (ch) {
- case '?':
- case '#':
- return s;
- }
-
- break;
-
- default:
- break;
- }
-
- /* We should never fall out of the switch above unless there's an error */
- return s_dead;
-}
-
-size_t http_parser_execute (http_parser *parser,
- const http_parser_settings *settings,
- const char *data,
- size_t len)
-{
- char c, ch;
- int8_t unhex_val;
- const char *p = data;
- const char *header_field_mark = 0;
- const char *header_value_mark = 0;
- const char *url_mark = 0;
- const char *body_mark = 0;
- const char *status_mark = 0;
- enum state p_state = (enum state) parser->state;
- const unsigned int lenient = parser->lenient_http_headers;
- uint32_t nread = parser->nread;
-
- /* We're in an error state. Don't bother doing anything. */
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
- return 0;
- }
-
- if (len == 0) {
- switch (CURRENT_STATE()) {
- case s_body_identity_eof:
- /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if
- * we got paused.
- */
- CALLBACK_NOTIFY_NOADVANCE(message_complete);
- return 0;
-
- case s_dead:
- case s_start_req_or_res:
- case s_start_res:
- case s_start_req:
- return 0;
-
- default:
- SET_ERRNO(HPE_INVALID_EOF_STATE);
- return 1;
- }
- }
-
-
- if (CURRENT_STATE() == s_header_field)
- header_field_mark = data;
- if (CURRENT_STATE() == s_header_value)
- header_value_mark = data;
- switch (CURRENT_STATE()) {
- case s_req_path:
- case s_req_schema:
- case s_req_schema_slash:
- case s_req_schema_slash_slash:
- case s_req_server_start:
- case s_req_server:
- case s_req_server_with_at:
- case s_req_query_string_start:
- case s_req_query_string:
- case s_req_fragment_start:
- case s_req_fragment:
- url_mark = data;
- break;
- case s_res_status:
- status_mark = data;
- break;
- default:
- break;
- }
-
- for (p=data; p != data + len; p++) {
- ch = *p;
-
- if (PARSING_HEADER(CURRENT_STATE()))
- COUNT_HEADER_SIZE(1);
-
-reexecute:
- switch (CURRENT_STATE()) {
-
- case s_dead:
- /* this state is used after a 'Connection: close' message
- * the parser will error out if it reads another message
- */
- if (LIKELY(ch == CR || ch == LF))
- break;
-
- SET_ERRNO(HPE_CLOSED_CONNECTION);
- goto error;
-
- case s_start_req_or_res:
- {
- if (ch == CR || ch == LF)
- break;
- parser->flags = 0;
- parser->content_length = ULLONG_MAX;
-
- if (ch == 'H') {
- UPDATE_STATE(s_res_or_resp_H);
-
- CALLBACK_NOTIFY(message_begin);
- } else {
- parser->type = HTTP_REQUEST;
- UPDATE_STATE(s_start_req);
- REEXECUTE();
- }
-
- break;
- }
-
- case s_res_or_resp_H:
- if (ch == 'T') {
- parser->type = HTTP_RESPONSE;
- UPDATE_STATE(s_res_HT);
- } else {
- if (UNLIKELY(ch != 'E')) {
- SET_ERRNO(HPE_INVALID_CONSTANT);
- goto error;
- }
-
- parser->type = HTTP_REQUEST;
- parser->method = HTTP_HEAD;
- parser->index = 2;
- UPDATE_STATE(s_req_method);
- }
- break;
-
- case s_start_res:
- {
- parser->flags = 0;
- parser->content_length = ULLONG_MAX;
-
- switch (ch) {
- case 'H':
- UPDATE_STATE(s_res_H);
- break;
-
- case CR:
- case LF:
- break;
-
- default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
- goto error;
- }
-
- CALLBACK_NOTIFY(message_begin);
- break;
- }
-
- case s_res_H:
- STRICT_CHECK(ch != 'T');
- UPDATE_STATE(s_res_HT);
- break;
-
- case s_res_HT:
- STRICT_CHECK(ch != 'T');
- UPDATE_STATE(s_res_HTT);
- break;
-
- case s_res_HTT:
- STRICT_CHECK(ch != 'P');
- UPDATE_STATE(s_res_HTTP);
- break;
-
- case s_res_HTTP:
- STRICT_CHECK(ch != '/');
- UPDATE_STATE(s_res_http_major);
- break;
-
- case s_res_http_major:
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_major = ch - '0';
- UPDATE_STATE(s_res_http_dot);
- break;
-
- case s_res_http_dot:
- {
- if (UNLIKELY(ch != '.')) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- UPDATE_STATE(s_res_http_minor);
- break;
- }
-
- case s_res_http_minor:
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_minor = ch - '0';
- UPDATE_STATE(s_res_http_end);
- break;
-
- case s_res_http_end:
- {
- if (UNLIKELY(ch != ' ')) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- UPDATE_STATE(s_res_first_status_code);
- break;
- }
-
- case s_res_first_status_code:
- {
- if (!IS_NUM(ch)) {
- if (ch == ' ') {
- break;
- }
-
- SET_ERRNO(HPE_INVALID_STATUS);
- goto error;
- }
- parser->status_code = ch - '0';
- UPDATE_STATE(s_res_status_code);
- break;
- }
-
- case s_res_status_code:
- {
- if (!IS_NUM(ch)) {
- switch (ch) {
- case ' ':
- UPDATE_STATE(s_res_status_start);
- break;
- case CR:
- case LF:
- UPDATE_STATE(s_res_status_start);
- REEXECUTE();
- break;
- default:
- SET_ERRNO(HPE_INVALID_STATUS);
- goto error;
- }
- break;
- }
-
- parser->status_code *= 10;
- parser->status_code += ch - '0';
-
- if (UNLIKELY(parser->status_code > 999)) {
- SET_ERRNO(HPE_INVALID_STATUS);
- goto error;
- }
-
- break;
- }
-
- case s_res_status_start:
- {
- MARK(status);
- UPDATE_STATE(s_res_status);
- parser->index = 0;
-
- if (ch == CR || ch == LF)
- REEXECUTE();
-
- break;
- }
-
- case s_res_status:
- if (ch == CR) {
- UPDATE_STATE(s_res_line_almost_done);
- CALLBACK_DATA(status);
- break;
- }
-
- if (ch == LF) {
- UPDATE_STATE(s_header_field_start);
- CALLBACK_DATA(status);
- break;
- }
-
- break;
-
- case s_res_line_almost_done:
- STRICT_CHECK(ch != LF);
- UPDATE_STATE(s_header_field_start);
- break;
-
- case s_start_req:
- {
- if (ch == CR || ch == LF)
- break;
- parser->flags = 0;
- parser->content_length = ULLONG_MAX;
-
- if (UNLIKELY(!IS_ALPHA(ch))) {
- SET_ERRNO(HPE_INVALID_METHOD);
- goto error;
- }
-
- parser->method = (enum http_method) 0;
- parser->index = 1;
- switch (ch) {
- case 'A': parser->method = HTTP_ACL; break;
- case 'B': parser->method = HTTP_BIND; break;
- case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break;
- case 'D': parser->method = HTTP_DELETE; break;
- case 'G': parser->method = HTTP_GET; break;
- case 'H': parser->method = HTTP_HEAD; break;
- case 'L': parser->method = HTTP_LOCK; /* or LINK */ break;
- case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break;
- case 'N': parser->method = HTTP_NOTIFY; break;
- case 'O': parser->method = HTTP_OPTIONS; break;
- case 'P': parser->method = HTTP_POST;
- /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */
- break;
- case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break;
- case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH, SOURCE */ break;
- case 'T': parser->method = HTTP_TRACE; break;
- case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break;
- default:
- SET_ERRNO(HPE_INVALID_METHOD);
- goto error;
- }
- UPDATE_STATE(s_req_method);
-
- CALLBACK_NOTIFY(message_begin);
-
- break;
- }
-
- case s_req_method:
- {
- const char *matcher;
- if (UNLIKELY(ch == '\0')) {
- SET_ERRNO(HPE_INVALID_METHOD);
- goto error;
- }
-
- matcher = method_strings[parser->method];
- if (ch == ' ' && matcher[parser->index] == '\0') {
- UPDATE_STATE(s_req_spaces_before_url);
- } else if (ch == matcher[parser->index]) {
- ; /* nada */
- } else if ((ch >= 'A' && ch <= 'Z') || ch == '-') {
-
- switch (parser->method << 16 | parser->index << 8 | ch) {
-#define XX(meth, pos, ch, new_meth) \
- case (HTTP_##meth << 16 | pos << 8 | ch): \
- parser->method = HTTP_##new_meth; break;
-
- XX(POST, 1, 'U', PUT)
- XX(POST, 1, 'A', PATCH)
- XX(POST, 1, 'R', PROPFIND)
- XX(PUT, 2, 'R', PURGE)
- XX(CONNECT, 1, 'H', CHECKOUT)
- XX(CONNECT, 2, 'P', COPY)
- XX(MKCOL, 1, 'O', MOVE)
- XX(MKCOL, 1, 'E', MERGE)
- XX(MKCOL, 1, '-', MSEARCH)
- XX(MKCOL, 2, 'A', MKACTIVITY)
- XX(MKCOL, 3, 'A', MKCALENDAR)
- XX(SUBSCRIBE, 1, 'E', SEARCH)
- XX(SUBSCRIBE, 1, 'O', SOURCE)
- XX(REPORT, 2, 'B', REBIND)
- XX(PROPFIND, 4, 'P', PROPPATCH)
- XX(LOCK, 1, 'I', LINK)
- XX(UNLOCK, 2, 'S', UNSUBSCRIBE)
- XX(UNLOCK, 2, 'B', UNBIND)
- XX(UNLOCK, 3, 'I', UNLINK)
-#undef XX
- default:
- SET_ERRNO(HPE_INVALID_METHOD);
- goto error;
- }
- } else {
- SET_ERRNO(HPE_INVALID_METHOD);
- goto error;
- }
-
- ++parser->index;
- break;
- }
-
- case s_req_spaces_before_url:
- {
- if (ch == ' ') break;
-
- MARK(url);
- if (parser->method == HTTP_CONNECT) {
- UPDATE_STATE(s_req_server_start);
- }
-
- UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
- if (UNLIKELY(CURRENT_STATE() == s_dead)) {
- SET_ERRNO(HPE_INVALID_URL);
- goto error;
- }
-
- break;
- }
-
- case s_req_schema:
- case s_req_schema_slash:
- case s_req_schema_slash_slash:
- case s_req_server_start:
- {
- switch (ch) {
- /* No whitespace allowed here */
- case ' ':
- case CR:
- case LF:
- SET_ERRNO(HPE_INVALID_URL);
- goto error;
- default:
- UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
- if (UNLIKELY(CURRENT_STATE() == s_dead)) {
- SET_ERRNO(HPE_INVALID_URL);
- goto error;
- }
- }
-
- break;
- }
-
- case s_req_server:
- case s_req_server_with_at:
- case s_req_path:
- case s_req_query_string_start:
- case s_req_query_string:
- case s_req_fragment_start:
- case s_req_fragment:
- {
- switch (ch) {
- case ' ':
- UPDATE_STATE(s_req_http_start);
- CALLBACK_DATA(url);
- break;
- case CR:
- case LF:
- parser->http_major = 0;
- parser->http_minor = 9;
- UPDATE_STATE((ch == CR) ?
- s_req_line_almost_done :
- s_header_field_start);
- CALLBACK_DATA(url);
- break;
- default:
- UPDATE_STATE(parse_url_char(CURRENT_STATE(), ch));
- if (UNLIKELY(CURRENT_STATE() == s_dead)) {
- SET_ERRNO(HPE_INVALID_URL);
- goto error;
- }
- }
- break;
- }
-
- case s_req_http_start:
- switch (ch) {
- case 'H':
- UPDATE_STATE(s_req_http_H);
- break;
- case ' ':
- break;
- default:
- SET_ERRNO(HPE_INVALID_CONSTANT);
- goto error;
- }
- break;
-
- case s_req_http_H:
- STRICT_CHECK(ch != 'T');
- UPDATE_STATE(s_req_http_HT);
- break;
-
- case s_req_http_HT:
- STRICT_CHECK(ch != 'T');
- UPDATE_STATE(s_req_http_HTT);
- break;
-
- case s_req_http_HTT:
- STRICT_CHECK(ch != 'P');
- UPDATE_STATE(s_req_http_HTTP);
- break;
-
- case s_req_http_HTTP:
- STRICT_CHECK(ch != '/');
- UPDATE_STATE(s_req_http_major);
- break;
-
- case s_req_http_major:
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_major = ch - '0';
- UPDATE_STATE(s_req_http_dot);
- break;
-
- case s_req_http_dot:
- {
- if (UNLIKELY(ch != '.')) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- UPDATE_STATE(s_req_http_minor);
- break;
- }
-
- case s_req_http_minor:
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- }
-
- parser->http_minor = ch - '0';
- UPDATE_STATE(s_req_http_end);
- break;
-
- case s_req_http_end:
- {
- if (ch == CR) {
- UPDATE_STATE(s_req_line_almost_done);
- break;
- }
-
- if (ch == LF) {
- UPDATE_STATE(s_header_field_start);
- break;
- }
-
- SET_ERRNO(HPE_INVALID_VERSION);
- goto error;
- break;
- }
-
- /* end of request line */
- case s_req_line_almost_done:
- {
- if (UNLIKELY(ch != LF)) {
- SET_ERRNO(HPE_LF_EXPECTED);
- goto error;
- }
-
- UPDATE_STATE(s_header_field_start);
- break;
- }
-
- case s_header_field_start:
- {
- if (ch == CR) {
- UPDATE_STATE(s_headers_almost_done);
- break;
- }
-
- if (ch == LF) {
- /* they might be just sending \n instead of \r\n so this would be
- * the second \n to denote the end of headers*/
- UPDATE_STATE(s_headers_almost_done);
- REEXECUTE();
- }
-
- c = TOKEN(ch);
-
- if (UNLIKELY(!c)) {
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
- goto error;
- }
-
- MARK(header_field);
-
- parser->index = 0;
- UPDATE_STATE(s_header_field);
-
- switch (c) {
- case 'c':
- parser->header_state = h_C;
- break;
-
- case 'p':
- parser->header_state = h_matching_proxy_connection;
- break;
-
- case 't':
- parser->header_state = h_matching_transfer_encoding;
- break;
-
- case 'u':
- parser->header_state = h_matching_upgrade;
- break;
-
- default:
- parser->header_state = h_general;
- break;
- }
- break;
- }
-
- case s_header_field:
- {
- const char* start = p;
- for (; p != data + len; p++) {
- ch = *p;
- c = TOKEN(ch);
-
- if (!c)
- break;
-
- switch (parser->header_state) {
- case h_general: {
- size_t limit = data + len - p;
- limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
- while (p+1 < data + limit && TOKEN(p[1])) {
- p++;
- }
- break;
- }
-
- case h_C:
- parser->index++;
- parser->header_state = (c == 'o' ? h_CO : h_general);
- break;
-
- case h_CO:
- parser->index++;
- parser->header_state = (c == 'n' ? h_CON : h_general);
- break;
-
- case h_CON:
- parser->index++;
- switch (c) {
- case 'n':
- parser->header_state = h_matching_connection;
- break;
- case 't':
- parser->header_state = h_matching_content_length;
- break;
- default:
- parser->header_state = h_general;
- break;
- }
- break;
-
- /* connection */
-
- case h_matching_connection:
- parser->index++;
- if (parser->index > sizeof(CONNECTION)-1
- || c != CONNECTION[parser->index]) {
- parser->header_state = h_general;
- } else if (parser->index == sizeof(CONNECTION)-2) {
- parser->header_state = h_connection;
- }
- break;
-
- /* proxy-connection */
-
- case h_matching_proxy_connection:
- parser->index++;
- if (parser->index > sizeof(PROXY_CONNECTION)-1
- || c != PROXY_CONNECTION[parser->index]) {
- parser->header_state = h_general;
- } else if (parser->index == sizeof(PROXY_CONNECTION)-2) {
- parser->header_state = h_connection;
- }
- break;
-
- /* content-length */
-
- case h_matching_content_length:
- parser->index++;
- if (parser->index > sizeof(CONTENT_LENGTH)-1
- || c != CONTENT_LENGTH[parser->index]) {
- parser->header_state = h_general;
- } else if (parser->index == sizeof(CONTENT_LENGTH)-2) {
- parser->header_state = h_content_length;
- }
- break;
-
- /* transfer-encoding */
-
- case h_matching_transfer_encoding:
- parser->index++;
- if (parser->index > sizeof(TRANSFER_ENCODING)-1
- || c != TRANSFER_ENCODING[parser->index]) {
- parser->header_state = h_general;
- } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) {
- parser->header_state = h_transfer_encoding;
- }
- break;
-
- /* upgrade */
-
- case h_matching_upgrade:
- parser->index++;
- if (parser->index > sizeof(UPGRADE)-1
- || c != UPGRADE[parser->index]) {
- parser->header_state = h_general;
- } else if (parser->index == sizeof(UPGRADE)-2) {
- parser->header_state = h_upgrade;
- }
- break;
-
- case h_connection:
- case h_content_length:
- case h_transfer_encoding:
- case h_upgrade:
- if (ch != ' ') parser->header_state = h_general;
- break;
-
- default:
- assert(0 && "Unknown header_state");
- break;
- }
- }
-
- if (p == data + len) {
- --p;
- COUNT_HEADER_SIZE(p - start);
- break;
- }
-
- COUNT_HEADER_SIZE(p - start);
-
- if (ch == ':') {
- UPDATE_STATE(s_header_value_discard_ws);
- CALLBACK_DATA(header_field);
- break;
- }
-
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
- goto error;
- }
-
- case s_header_value_discard_ws:
- if (ch == ' ' || ch == '\t') break;
-
- if (ch == CR) {
- UPDATE_STATE(s_header_value_discard_ws_almost_done);
- break;
- }
-
- if (ch == LF) {
- UPDATE_STATE(s_header_value_discard_lws);
- break;
- }
-
- /* fall through */
-
- case s_header_value_start:
- {
- MARK(header_value);
-
- UPDATE_STATE(s_header_value);
- parser->index = 0;
-
- c = LOWER(ch);
-
- switch (parser->header_state) {
- case h_upgrade:
- parser->flags |= F_UPGRADE;
- parser->header_state = h_general;
- break;
-
- case h_transfer_encoding:
- /* looking for 'Transfer-Encoding: chunked' */
- if ('c' == c) {
- parser->header_state = h_matching_transfer_encoding_chunked;
- } else {
- parser->header_state = h_general;
- }
- break;
-
- case h_content_length:
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
- goto error;
- }
-
- if (parser->flags & F_CONTENTLENGTH) {
- SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
- goto error;
- }
-
- parser->flags |= F_CONTENTLENGTH;
- parser->content_length = ch - '0';
- parser->header_state = h_content_length_num;
- break;
-
- case h_connection:
- /* looking for 'Connection: keep-alive' */
- if (c == 'k') {
- parser->header_state = h_matching_connection_keep_alive;
- /* looking for 'Connection: close' */
- } else if (c == 'c') {
- parser->header_state = h_matching_connection_close;
- } else if (c == 'u') {
- parser->header_state = h_matching_connection_upgrade;
- } else {
- parser->header_state = h_matching_connection_token;
- }
- break;
-
- /* Multi-value `Connection` header */
- case h_matching_connection_token_start:
- break;
-
- default:
- parser->header_state = h_general;
- break;
- }
- break;
- }
-
- case s_header_value:
- {
- const char* start = p;
- enum header_states h_state = (enum header_states) parser->header_state;
- for (; p != data + len; p++) {
- ch = *p;
- if (ch == CR) {
- UPDATE_STATE(s_header_almost_done);
- parser->header_state = h_state;
- CALLBACK_DATA(header_value);
- break;
- }
-
- if (ch == LF) {
- UPDATE_STATE(s_header_almost_done);
- COUNT_HEADER_SIZE(p - start);
- parser->header_state = h_state;
- CALLBACK_DATA_NOADVANCE(header_value);
- REEXECUTE();
- }
-
- if (!lenient && !IS_HEADER_CHAR(ch)) {
- SET_ERRNO(HPE_INVALID_HEADER_TOKEN);
- goto error;
- }
-
- c = LOWER(ch);
-
- switch (h_state) {
- case h_general:
- {
- const char* p_cr;
- const char* p_lf;
- size_t limit = data + len - p;
-
- limit = MIN(limit, HTTP_MAX_HEADER_SIZE);
-
- p_cr = (const char*) memchr(p, CR, limit);
- p_lf = (const char*) memchr(p, LF, limit);
- if (p_cr != NULL) {
- if (p_lf != NULL && p_cr >= p_lf)
- p = p_lf;
- else
- p = p_cr;
- } else if (UNLIKELY(p_lf != NULL)) {
- p = p_lf;
- } else {
- p = data + len;
- }
- --p;
- break;
- }
-
- case h_connection:
- case h_transfer_encoding:
- assert(0 && "Shouldn't get here.");
- break;
-
- case h_content_length:
- if (ch == ' ') break;
- h_state = h_content_length_num;
- /* fall through */
-
- case h_content_length_num:
- {
- uint64_t t;
-
- if (ch == ' ') {
- h_state = h_content_length_ws;
- break;
- }
-
- if (UNLIKELY(!IS_NUM(ch))) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
- parser->header_state = h_state;
- goto error;
- }
-
- t = parser->content_length;
- t *= 10;
- t += ch - '0';
-
- /* Overflow? Test against a conservative limit for simplicity. */
- if (UNLIKELY((ULLONG_MAX - 10) / 10 < parser->content_length)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
- parser->header_state = h_state;
- goto error;
- }
-
- parser->content_length = t;
- break;
- }
-
- case h_content_length_ws:
- if (ch == ' ') break;
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
- parser->header_state = h_state;
- goto error;
-
- /* Transfer-Encoding: chunked */
- case h_matching_transfer_encoding_chunked:
- parser->index++;
- if (parser->index > sizeof(CHUNKED)-1
- || c != CHUNKED[parser->index]) {
- h_state = h_general;
- } else if (parser->index == sizeof(CHUNKED)-2) {
- h_state = h_transfer_encoding_chunked;
- }
- break;
-
- case h_matching_connection_token_start:
- /* looking for 'Connection: keep-alive' */
- if (c == 'k') {
- h_state = h_matching_connection_keep_alive;
- /* looking for 'Connection: close' */
- } else if (c == 'c') {
- h_state = h_matching_connection_close;
- } else if (c == 'u') {
- h_state = h_matching_connection_upgrade;
- } else if (STRICT_TOKEN(c)) {
- h_state = h_matching_connection_token;
- } else if (c == ' ' || c == '\t') {
- /* Skip lws */
- } else {
- h_state = h_general;
- }
- break;
-
- /* looking for 'Connection: keep-alive' */
- case h_matching_connection_keep_alive:
- parser->index++;
- if (parser->index > sizeof(KEEP_ALIVE)-1
- || c != KEEP_ALIVE[parser->index]) {
- h_state = h_matching_connection_token;
- } else if (parser->index == sizeof(KEEP_ALIVE)-2) {
- h_state = h_connection_keep_alive;
- }
- break;
-
- /* looking for 'Connection: close' */
- case h_matching_connection_close:
- parser->index++;
- if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) {
- h_state = h_matching_connection_token;
- } else if (parser->index == sizeof(CLOSE)-2) {
- h_state = h_connection_close;
- }
- break;
-
- /* looking for 'Connection: upgrade' */
- case h_matching_connection_upgrade:
- parser->index++;
- if (parser->index > sizeof(UPGRADE) - 1 ||
- c != UPGRADE[parser->index]) {
- h_state = h_matching_connection_token;
- } else if (parser->index == sizeof(UPGRADE)-2) {
- h_state = h_connection_upgrade;
- }
- break;
-
- case h_matching_connection_token:
- if (ch == ',') {
- h_state = h_matching_connection_token_start;
- parser->index = 0;
- }
- break;
-
- case h_transfer_encoding_chunked:
- if (ch != ' ') h_state = h_general;
- break;
-
- case h_connection_keep_alive:
- case h_connection_close:
- case h_connection_upgrade:
- if (ch == ',') {
- if (h_state == h_connection_keep_alive) {
- parser->flags |= F_CONNECTION_KEEP_ALIVE;
- } else if (h_state == h_connection_close) {
- parser->flags |= F_CONNECTION_CLOSE;
- } else if (h_state == h_connection_upgrade) {
- parser->flags |= F_CONNECTION_UPGRADE;
- }
- h_state = h_matching_connection_token_start;
- parser->index = 0;
- } else if (ch != ' ') {
- h_state = h_matching_connection_token;
- }
- break;
-
- default:
- UPDATE_STATE(s_header_value);
- h_state = h_general;
- break;
- }
- }
- parser->header_state = h_state;
-
- if (p == data + len)
- --p;
-
- COUNT_HEADER_SIZE(p - start);
- break;
- }
-
- case s_header_almost_done:
- {
- if (UNLIKELY(ch != LF)) {
- SET_ERRNO(HPE_LF_EXPECTED);
- goto error;
- }
-
- UPDATE_STATE(s_header_value_lws);
- break;
- }
-
- case s_header_value_lws:
- {
- if (ch == ' ' || ch == '\t') {
- UPDATE_STATE(s_header_value_start);
- REEXECUTE();
- }
-
- /* finished the header */
- switch (parser->header_state) {
- case h_connection_keep_alive:
- parser->flags |= F_CONNECTION_KEEP_ALIVE;
- break;
- case h_connection_close:
- parser->flags |= F_CONNECTION_CLOSE;
- break;
- case h_transfer_encoding_chunked:
- parser->flags |= F_CHUNKED;
- break;
- case h_connection_upgrade:
- parser->flags |= F_CONNECTION_UPGRADE;
- break;
- default:
- break;
- }
-
- UPDATE_STATE(s_header_field_start);
- REEXECUTE();
- }
-
- case s_header_value_discard_ws_almost_done:
- {
- STRICT_CHECK(ch != LF);
- UPDATE_STATE(s_header_value_discard_lws);
- break;
- }
-
- case s_header_value_discard_lws:
- {
- if (ch == ' ' || ch == '\t') {
- UPDATE_STATE(s_header_value_discard_ws);
- break;
- } else {
- switch (parser->header_state) {
- case h_connection_keep_alive:
- parser->flags |= F_CONNECTION_KEEP_ALIVE;
- break;
- case h_connection_close:
- parser->flags |= F_CONNECTION_CLOSE;
- break;
- case h_connection_upgrade:
- parser->flags |= F_CONNECTION_UPGRADE;
- break;
- case h_transfer_encoding_chunked:
- parser->flags |= F_CHUNKED;
- break;
- default:
- break;
- }
-
- /* header value was empty */
- MARK(header_value);
- UPDATE_STATE(s_header_field_start);
- CALLBACK_DATA_NOADVANCE(header_value);
- REEXECUTE();
- }
- }
-
- case s_headers_almost_done:
- {
- STRICT_CHECK(ch != LF);
-
- if (parser->flags & F_TRAILING) {
- /* End of a chunked request */
- UPDATE_STATE(s_message_done);
- CALLBACK_NOTIFY_NOADVANCE(chunk_complete);
- REEXECUTE();
- }
-
- /* Cannot use chunked encoding and a content-length header together
- per the HTTP specification. */
- if ((parser->flags & F_CHUNKED) &&
- (parser->flags & F_CONTENTLENGTH)) {
- SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH);
- goto error;
- }
-
- UPDATE_STATE(s_headers_done);
-
- /* Set this here so that on_headers_complete() callbacks can see it */
- if ((parser->flags & F_UPGRADE) &&
- (parser->flags & F_CONNECTION_UPGRADE)) {
- /* For responses, "Upgrade: foo" and "Connection: upgrade" are
- * mandatory only when it is a 101 Switching Protocols response,
- * otherwise it is purely informational, to announce support.
- */
- parser->upgrade =
- (parser->type == HTTP_REQUEST || parser->status_code == 101);
- } else {
- parser->upgrade = (parser->method == HTTP_CONNECT);
- }
-
- /* Here we call the headers_complete callback. This is somewhat
- * different than other callbacks because if the user returns 1, we
- * will interpret that as saying that this message has no body. This
- * is needed for the annoying case of receiving a response to a HEAD
- * request.
- *
- * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so
- * we have to simulate it by handling a change in errno below.
- */
- if (settings->on_headers_complete) {
- switch (settings->on_headers_complete(parser)) {
- case 0:
- break;
-
- case 2:
- parser->upgrade = 1;
-
- /* fall through */
- case 1:
- parser->flags |= F_SKIPBODY;
- break;
-
- default:
- SET_ERRNO(HPE_CB_headers_complete);
- RETURN(p - data); /* Error */
- }
- }
-
- if (HTTP_PARSER_ERRNO(parser) != HPE_OK) {
- RETURN(p - data);
- }
-
- REEXECUTE();
- }
-
- case s_headers_done:
- {
- int hasBody;
- STRICT_CHECK(ch != LF);
-
- parser->nread = 0;
- nread = 0;
-
- hasBody = parser->flags & F_CHUNKED ||
- (parser->content_length > 0 && parser->content_length != ULLONG_MAX);
- if (parser->upgrade && (parser->method == HTTP_CONNECT ||
- (parser->flags & F_SKIPBODY) || !hasBody)) {
- /* Exit, the rest of the message is in a different protocol. */
- UPDATE_STATE(NEW_MESSAGE());
- CALLBACK_NOTIFY(message_complete);
- RETURN((p - data) + 1);
- }
-
- if (parser->flags & F_SKIPBODY) {
- UPDATE_STATE(NEW_MESSAGE());
- CALLBACK_NOTIFY(message_complete);
- } else if (parser->flags & F_CHUNKED) {
- /* chunked encoding - ignore Content-Length header */
- UPDATE_STATE(s_chunk_size_start);
- } else {
- if (parser->content_length == 0) {
- /* Content-Length header given but zero: Content-Length: 0\r\n */
- UPDATE_STATE(NEW_MESSAGE());
- CALLBACK_NOTIFY(message_complete);
- } else if (parser->content_length != ULLONG_MAX) {
- /* Content-Length header given and non-zero */
- UPDATE_STATE(s_body_identity);
- } else {
- if (!http_message_needs_eof(parser)) {
- /* Assume content-length 0 - read the next */
- UPDATE_STATE(NEW_MESSAGE());
- CALLBACK_NOTIFY(message_complete);
- } else {
- /* Read body until EOF */
- UPDATE_STATE(s_body_identity_eof);
- }
- }
- }
-
- break;
- }
-
- case s_body_identity:
- {
- uint64_t to_read = MIN(parser->content_length,
- (uint64_t) ((data + len) - p));
-
- assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
-
- /* The difference between advancing content_length and p is because
- * the latter will automaticaly advance on the next loop iteration.
- * Further, if content_length ends up at 0, we want to see the last
- * byte again for our message complete callback.
- */
- MARK(body);
- parser->content_length -= to_read;
- p += to_read - 1;
-
- if (parser->content_length == 0) {
- UPDATE_STATE(s_message_done);
-
- /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte.
- *
- * The alternative to doing this is to wait for the next byte to
- * trigger the data callback, just as in every other case. The
- * problem with this is that this makes it difficult for the test
- * harness to distinguish between complete-on-EOF and
- * complete-on-length. It's not clear that this distinction is
- * important for applications, but let's keep it for now.
- */
- CALLBACK_DATA_(body, p - body_mark + 1, p - data);
- REEXECUTE();
- }
-
- break;
- }
-
- /* read until EOF */
- case s_body_identity_eof:
- MARK(body);
- p = data + len - 1;
-
- break;
-
- case s_message_done:
- UPDATE_STATE(NEW_MESSAGE());
- CALLBACK_NOTIFY(message_complete);
- if (parser->upgrade) {
- /* Exit, the rest of the message is in a different protocol. */
- RETURN((p - data) + 1);
- }
- break;
-
- case s_chunk_size_start:
- {
- assert(nread == 1);
- assert(parser->flags & F_CHUNKED);
-
- unhex_val = unhex[(unsigned char)ch];
- if (UNLIKELY(unhex_val == -1)) {
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
- goto error;
- }
-
- parser->content_length = unhex_val;
- UPDATE_STATE(s_chunk_size);
- break;
- }
-
- case s_chunk_size:
- {
- uint64_t t;
-
- assert(parser->flags & F_CHUNKED);
-
- if (ch == CR) {
- UPDATE_STATE(s_chunk_size_almost_done);
- break;
- }
-
- unhex_val = unhex[(unsigned char)ch];
-
- if (unhex_val == -1) {
- if (ch == ';' || ch == ' ') {
- UPDATE_STATE(s_chunk_parameters);
- break;
- }
-
- SET_ERRNO(HPE_INVALID_CHUNK_SIZE);
- goto error;
- }
-
- t = parser->content_length;
- t *= 16;
- t += unhex_val;
-
- /* Overflow? Test against a conservative limit for simplicity. */
- if (UNLIKELY((ULLONG_MAX - 16) / 16 < parser->content_length)) {
- SET_ERRNO(HPE_INVALID_CONTENT_LENGTH);
- goto error;
- }
-
- parser->content_length = t;
- break;
- }
-
- case s_chunk_parameters:
- {
- assert(parser->flags & F_CHUNKED);
- /* just ignore this shit. TODO check for overflow */
- if (ch == CR) {
- UPDATE_STATE(s_chunk_size_almost_done);
- break;
- }
- break;
- }
-
- case s_chunk_size_almost_done:
- {
- assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
-
- parser->nread = 0;
- nread = 0;
-
- if (parser->content_length == 0) {
- parser->flags |= F_TRAILING;
- UPDATE_STATE(s_header_field_start);
- } else {
- UPDATE_STATE(s_chunk_data);
- }
- CALLBACK_NOTIFY(chunk_header);
- break;
- }
-
- case s_chunk_data:
- {
- uint64_t to_read = MIN(parser->content_length,
- (uint64_t) ((data + len) - p));
-
- assert(parser->flags & F_CHUNKED);
- assert(parser->content_length != 0
- && parser->content_length != ULLONG_MAX);
-
- /* See the explanation in s_body_identity for why the content
- * length and data pointers are managed this way.
- */
- MARK(body);
- parser->content_length -= to_read;
- p += to_read - 1;
-
- if (parser->content_length == 0) {
- UPDATE_STATE(s_chunk_data_almost_done);
- }
-
- break;
- }
-
- case s_chunk_data_almost_done:
- assert(parser->flags & F_CHUNKED);
- assert(parser->content_length == 0);
- STRICT_CHECK(ch != CR);
- UPDATE_STATE(s_chunk_data_done);
- CALLBACK_DATA(body);
- break;
-
- case s_chunk_data_done:
- assert(parser->flags & F_CHUNKED);
- STRICT_CHECK(ch != LF);
- parser->nread = 0;
- nread = 0;
- UPDATE_STATE(s_chunk_size_start);
- CALLBACK_NOTIFY(chunk_complete);
- break;
-
- default:
- assert(0 && "unhandled state");
- SET_ERRNO(HPE_INVALID_INTERNAL_STATE);
- goto error;
- }
- }
-
- /* Run callbacks for any marks that we have leftover after we ran our of
- * bytes. There should be at most one of these set, so it's OK to invoke
- * them in series (unset marks will not result in callbacks).
- *
- * We use the NOADVANCE() variety of callbacks here because 'p' has already
- * overflowed 'data' and this allows us to correct for the off-by-one that
- * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p'
- * value that's in-bounds).
- */
-
- assert(((header_field_mark ? 1 : 0) +
- (header_value_mark ? 1 : 0) +
- (url_mark ? 1 : 0) +
- (body_mark ? 1 : 0) +
- (status_mark ? 1 : 0)) <= 1);
-
- CALLBACK_DATA_NOADVANCE(header_field);
- CALLBACK_DATA_NOADVANCE(header_value);
- CALLBACK_DATA_NOADVANCE(url);
- CALLBACK_DATA_NOADVANCE(body);
- CALLBACK_DATA_NOADVANCE(status);
-
- RETURN(len);
-
-error:
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK) {
- SET_ERRNO(HPE_UNKNOWN);
- }
-
- RETURN(p - data);
-}
-
-
-/* Does the parser need to see an EOF to find the end of the message? */
-int
-http_message_needs_eof (const http_parser *parser)
-{
- if (parser->type == HTTP_REQUEST) {
- return 0;
- }
-
- /* See RFC 2616 section 4.4 */
- if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */
- parser->status_code == 204 || /* No Content */
- parser->status_code == 304 || /* Not Modified */
- parser->flags & F_SKIPBODY) { /* response to a HEAD request */
- return 0;
- }
-
- if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) {
- return 0;
- }
-
- return 1;
-}
-
-
-int
-http_should_keep_alive (const http_parser *parser)
-{
- if (parser->http_major > 0 && parser->http_minor > 0) {
- /* HTTP/1.1 */
- if (parser->flags & F_CONNECTION_CLOSE) {
- return 0;
- }
- } else {
- /* HTTP/1.0 or earlier */
- if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) {
- return 0;
- }
- }
-
- return !http_message_needs_eof(parser);
-}
-
-
-const char *
-http_method_str (enum http_method m)
-{
- return ELEM_AT(method_strings, m, "<unknown>");
-}
-
-const char *
-http_status_str (enum http_status s)
-{
- switch (s) {
-#define XX(num, name, string) case HTTP_STATUS_##name: return #string;
- HTTP_STATUS_MAP(XX)
-#undef XX
- default: return "<unknown>";
- }
-}
-
-void
-http_parser_init (http_parser *parser, enum http_parser_type t)
-{
- void *data = parser->data; /* preserve application data */
- memset(parser, 0, sizeof(*parser));
- parser->data = data;
- parser->type = t;
- parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res));
- parser->http_errno = HPE_OK;
-}
-
-void
-http_parser_settings_init(http_parser_settings *settings)
-{
- memset(settings, 0, sizeof(*settings));
-}
-
-const char *
-http_errno_name(enum http_errno err) {
- assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
- return http_strerror_tab[err].name;
-}
-
-const char *
-http_errno_description(enum http_errno err) {
- assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab));
- return http_strerror_tab[err].description;
-}
-
-static enum http_host_state
-http_parse_host_char(enum http_host_state s, const char ch) {
- switch(s) {
- case s_http_userinfo:
- case s_http_userinfo_start:
- if (ch == '@') {
- return s_http_host_start;
- }
-
- if (IS_USERINFO_CHAR(ch)) {
- return s_http_userinfo;
- }
- break;
-
- case s_http_host_start:
- if (ch == '[') {
- return s_http_host_v6_start;
- }
-
- if (IS_HOST_CHAR(ch)) {
- return s_http_host;
- }
-
- break;
-
- case s_http_host:
- if (IS_HOST_CHAR(ch)) {
- return s_http_host;
- }
-
- /* fall through */
- case s_http_host_v6_end:
- if (ch == ':') {
- return s_http_host_port_start;
- }
-
- break;
-
- case s_http_host_v6:
- if (ch == ']') {
- return s_http_host_v6_end;
- }
-
- /* fall through */
- case s_http_host_v6_start:
- if (IS_HEX(ch) || ch == ':' || ch == '.') {
- return s_http_host_v6;
- }
-
- if (s == s_http_host_v6 && ch == '%') {
- return s_http_host_v6_zone_start;
- }
- break;
-
- case s_http_host_v6_zone:
- if (ch == ']') {
- return s_http_host_v6_end;
- }
-
- /* fall through */
- case s_http_host_v6_zone_start:
- /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */
- if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' ||
- ch == '~') {
- return s_http_host_v6_zone;
- }
- break;
-
- case s_http_host_port:
- case s_http_host_port_start:
- if (IS_NUM(ch)) {
- return s_http_host_port;
- }
-
- break;
-
- default:
- break;
- }
- return s_http_host_dead;
-}
-
-static int
-http_parse_host(const char * buf, struct http_parser_url *u, int found_at) {
- enum http_host_state s;
-
- const char *p;
- size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len;
-
- assert(u->field_set & (1 << UF_HOST));
-
- u->field_data[UF_HOST].len = 0;
-
- s = found_at ? s_http_userinfo_start : s_http_host_start;
-
- for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) {
- enum http_host_state new_s = http_parse_host_char(s, *p);
-
- if (new_s == s_http_host_dead) {
- return 1;
- }
-
- switch(new_s) {
- case s_http_host:
- if (s != s_http_host) {
- u->field_data[UF_HOST].off = p - buf;
- }
- u->field_data[UF_HOST].len++;
- break;
-
- case s_http_host_v6:
- if (s != s_http_host_v6) {
- u->field_data[UF_HOST].off = p - buf;
- }
- u->field_data[UF_HOST].len++;
- break;
-
- case s_http_host_v6_zone_start:
- case s_http_host_v6_zone:
- u->field_data[UF_HOST].len++;
- break;
-
- case s_http_host_port:
- if (s != s_http_host_port) {
- u->field_data[UF_PORT].off = p - buf;
- u->field_data[UF_PORT].len = 0;
- u->field_set |= (1 << UF_PORT);
- }
- u->field_data[UF_PORT].len++;
- break;
-
- case s_http_userinfo:
- if (s != s_http_userinfo) {
- u->field_data[UF_USERINFO].off = p - buf ;
- u->field_data[UF_USERINFO].len = 0;
- u->field_set |= (1 << UF_USERINFO);
- }
- u->field_data[UF_USERINFO].len++;
- break;
-
- default:
- break;
- }
- s = new_s;
- }
-
- /* Make sure we don't end somewhere unexpected */
- switch (s) {
- case s_http_host_start:
- case s_http_host_v6_start:
- case s_http_host_v6:
- case s_http_host_v6_zone_start:
- case s_http_host_v6_zone:
- case s_http_host_port_start:
- case s_http_userinfo:
- case s_http_userinfo_start:
- return 1;
- default:
- break;
- }
-
- return 0;
-}
-
-void
-http_parser_url_init(struct http_parser_url *u) {
- memset(u, 0, sizeof(*u));
-}
-
-int
-http_parser_parse_url(const char *buf, size_t buflen, int is_connect,
- struct http_parser_url *u)
-{
- enum state s;
- const char *p;
- enum http_parser_url_fields uf, old_uf;
- int found_at = 0;
-
- if (buflen == 0) {
- return 1;
- }
-
- u->port = u->field_set = 0;
- s = is_connect ? s_req_server_start : s_req_spaces_before_url;
- old_uf = UF_MAX;
-
- for (p = buf; p < buf + buflen; p++) {
- s = parse_url_char(s, *p);
-
- /* Figure out the next field that we're operating on */
- switch (s) {
- case s_dead:
- return 1;
-
- /* Skip delimeters */
- case s_req_schema_slash:
- case s_req_schema_slash_slash:
- case s_req_server_start:
- case s_req_query_string_start:
- case s_req_fragment_start:
- continue;
-
- case s_req_schema:
- uf = UF_SCHEMA;
- break;
-
- case s_req_server_with_at:
- found_at = 1;
-
- /* fall through */
- case s_req_server:
- uf = UF_HOST;
- break;
-
- case s_req_path:
- uf = UF_PATH;
- break;
-
- case s_req_query_string:
- uf = UF_QUERY;
- break;
-
- case s_req_fragment:
- uf = UF_FRAGMENT;
- break;
-
- default:
- assert(!"Unexpected state");
- return 1;
- }
-
- /* Nothing's changed; soldier on */
- if (uf == old_uf) {
- u->field_data[uf].len++;
- continue;
- }
-
- u->field_data[uf].off = p - buf;
- u->field_data[uf].len = 1;
-
- u->field_set |= (1 << uf);
- old_uf = uf;
- }
-
- /* host must be present if there is a schema */
- /* parsing http:///toto will fail */
- if ((u->field_set & (1 << UF_SCHEMA)) &&
- (u->field_set & (1 << UF_HOST)) == 0) {
- return 1;
- }
-
- if (u->field_set & (1 << UF_HOST)) {
- if (http_parse_host(buf, u, found_at) != 0) {
- return 1;
- }
- }
-
- /* CONNECT requests can only contain "hostname:port" */
- if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) {
- return 1;
- }
-
- if (u->field_set & (1 << UF_PORT)) {
- uint16_t off;
- uint16_t len;
- const char* p;
- const char* end;
- unsigned long v;
-
- off = u->field_data[UF_PORT].off;
- len = u->field_data[UF_PORT].len;
- end = buf + off + len;
-
- /* NOTE: The characters are already validated and are in the [0-9] range */
- assert(off + len <= buflen && "Port number overflow");
- v = 0;
- for (p = buf + off; p < end; p++) {
- v *= 10;
- v += *p - '0';
-
- /* Ports have a max value of 2^16 */
- if (v > 0xffff) {
- return 1;
- }
- }
-
- u->port = (uint16_t) v;
- }
-
- return 0;
-}
-
-void
-http_parser_pause(http_parser *parser, int paused) {
- /* Users should only be pausing/unpausing a parser that is not in an error
- * state. In non-debug builds, there's not much that we can do about this
- * other than ignore it.
- */
- if (HTTP_PARSER_ERRNO(parser) == HPE_OK ||
- HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) {
- uint32_t nread = parser->nread; /* used by the SET_ERRNO macro */
- SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK);
- } else {
- assert(0 && "Attempting to pause parser in error state");
- }
-}
-
-int
-http_body_is_final(const struct http_parser *parser) {
- return parser->state == s_message_done;
-}
-
-unsigned long
-http_parser_version(void) {
- return HTTP_PARSER_VERSION_MAJOR * 0x10000 |
- HTTP_PARSER_VERSION_MINOR * 0x00100 |
- HTTP_PARSER_VERSION_PATCH * 0x00001;
-}
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp
new file mode 100644
index 0000000..997b90b
--- /dev/null
+++ b/wpiutil/src/main/native/cpp/jni/DataLogJNI.cpp
@@ -0,0 +1,357 @@
+// 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 <jni.h>
+
+#include "edu_wpi_first_util_datalog_DataLogJNI.h"
+#include "wpi/DataLog.h"
+#include "wpi/jni_util.h"
+
+using namespace wpi::java;
+using namespace wpi::log;
+
+extern "C" {
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: create
+ * Signature: (Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;)J
+ */
+JNIEXPORT jlong JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_create
+ (JNIEnv* env, jclass, jstring dir, jstring filename, jdouble period,
+ jstring extraHeader)
+{
+ return reinterpret_cast<jlong>(new DataLog{JStringRef{env, dir},
+ JStringRef{env, filename}, period,
+ JStringRef{env, extraHeader}});
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: setFilename
+ * Signature: (JLjava/lang/String;)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_setFilename
+ (JNIEnv* env, jclass, jlong impl, jstring filename)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->SetFilename(JStringRef{env, filename});
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: flush
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_flush
+ (JNIEnv*, jclass, jlong impl)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->Flush();
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: pause
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_pause
+ (JNIEnv*, jclass, jlong impl)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->Pause();
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: resume
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_resume
+ (JNIEnv*, jclass, jlong impl)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->Resume();
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: start
+ * Signature: (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;J)I
+ */
+JNIEXPORT jint JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_start
+ (JNIEnv* env, jclass, jlong impl, jstring name, jstring type,
+ jstring metadata, jlong timestamp)
+{
+ if (impl == 0) {
+ return 0;
+ }
+ return reinterpret_cast<DataLog*>(impl)->Start(
+ JStringRef{env, name}, JStringRef{env, type}, JStringRef{env, metadata},
+ timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: finish
+ * Signature: (JIJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_finish
+ (JNIEnv*, jclass, jlong impl, jint entry, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->Finish(entry, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: setMetadata
+ * Signature: (JILjava/lang/String;J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_setMetadata
+ (JNIEnv* env, jclass, jlong impl, jint entry, jstring metadata,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->SetMetadata(
+ entry, JStringRef{env, metadata}, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: close
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_close
+ (JNIEnv*, jclass, jlong impl)
+{
+ delete reinterpret_cast<DataLog*>(impl);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendRaw
+ * Signature: (JI[BJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendRaw
+ (JNIEnv* env, jclass, jlong impl, jint entry, jbyteArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ JByteArrayRef cvalue{env, value};
+ reinterpret_cast<DataLog*>(impl)->AppendRaw(
+ entry,
+ {reinterpret_cast<const uint8_t*>(cvalue.array().data()), cvalue.size()},
+ timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendBoolean
+ * Signature: (JIZJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendBoolean
+ (JNIEnv*, jclass, jlong impl, jint entry, jboolean value, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendBoolean(entry, value, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendInteger
+ * Signature: (JIJJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendInteger
+ (JNIEnv*, jclass, jlong impl, jint entry, jlong value, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendInteger(entry, value, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendFloat
+ * Signature: (JIFJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendFloat
+ (JNIEnv*, jclass, jlong impl, jint entry, jfloat value, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendFloat(entry, value, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendDouble
+ * Signature: (JIDJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendDouble
+ (JNIEnv*, jclass, jlong impl, jint entry, jdouble value, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendDouble(entry, value, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendString
+ * Signature: (JILjava/lang/String;J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendString
+ (JNIEnv* env, jclass, jlong impl, jint entry, jstring value, jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendString(entry, JStringRef{env, value},
+ timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendBooleanArray
+ * Signature: (JI[ZJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendBooleanArray
+ (JNIEnv* env, jclass, jlong impl, jint entry, jbooleanArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendBooleanArray(
+ entry, JBooleanArrayRef{env, value}, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendIntegerArray
+ * Signature: (JI[JJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendIntegerArray
+ (JNIEnv* env, jclass, jlong impl, jint entry, jlongArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ JLongArrayRef 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()},
+ timestamp);
+ } else {
+ wpi::SmallVector<int64_t, 16> arr;
+ arr.reserve(jarr.size());
+ for (auto v : jarr.array()) {
+ arr.push_back(v);
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendIntegerArray(entry, arr, timestamp);
+ }
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendFloatArray
+ * Signature: (JI[FJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendFloatArray
+ (JNIEnv* env, jclass, jlong impl, jint entry, jfloatArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendFloatArray(
+ entry, JFloatArrayRef{env, value}, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendDoubleArray
+ * Signature: (JI[DJ)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendDoubleArray
+ (JNIEnv* env, jclass, jlong impl, jint entry, jdoubleArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendDoubleArray(
+ entry, JDoubleArrayRef{env, value}, timestamp);
+}
+
+/*
+ * Class: edu_wpi_first_util_datalog_DataLogJNI
+ * Method: appendStringArray
+ * Signature: (JI[Ljava/lang/Object;J)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_datalog_DataLogJNI_appendStringArray
+ (JNIEnv* env, jclass, jlong impl, jint entry, jobjectArray value,
+ jlong timestamp)
+{
+ if (impl == 0) {
+ return;
+ }
+ size_t len = env->GetArrayLength(value);
+ std::vector<std::string> arr;
+ arr.reserve(len);
+ for (size_t i = 0; i < len; ++i) {
+ JLocal<jstring> elem{
+ env, static_cast<jstring>(env->GetObjectArrayElement(value, i))};
+ if (!elem) {
+ return;
+ }
+ arr.emplace_back(JStringRef{env, elem}.str());
+ }
+ reinterpret_cast<DataLog*>(impl)->AppendStringArray(entry, arr, timestamp);
+}
+
+} // extern "C"
diff --git a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
index e876d9c..5fa4ddf 100644
--- a/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
+++ b/wpiutil/src/main/native/cpp/jni/WPIUtilJNI.cpp
@@ -4,14 +4,9 @@
#include <jni.h>
-#include "../MulticastHandleManager.h"
#include "edu_wpi_first_util_WPIUtilJNI.h"
-#include "wpi/DenseMap.h"
-#include "wpi/MulticastServiceAnnouncer.h"
-#include "wpi/MulticastServiceResolver.h"
-#include "wpi/PortForwarder.h"
+#include "fmt/format.h"
#include "wpi/Synchronization.h"
-#include "wpi/UidVector.h"
#include "wpi/jni_util.h"
#include "wpi/timestamp.h"
@@ -21,8 +16,6 @@
static uint64_t mockNow = 0;
static JException interruptedEx;
-static JClass serviceDataCls;
-static JGlobal<jobjectArray> serviceDataEmptyArray;
extern "C" {
@@ -37,17 +30,6 @@
return JNI_ERR;
}
- serviceDataCls = JClass{env, "edu/wpi/first/util/ServiceData"};
- if (!serviceDataCls) {
- return JNI_ERR;
- }
-
- serviceDataEmptyArray = JGlobal<jobjectArray>{
- env, env->NewObjectArray(0, serviceDataCls, nullptr)};
- if (serviceDataEmptyArray == nullptr) {
- return JNI_ERR;
- }
-
return JNI_VERSION_1_6;
}
@@ -57,13 +39,23 @@
return;
}
- serviceDataEmptyArray.free(env);
- serviceDataCls.free(env);
interruptedEx.free(env);
}
/*
* Class: edu_wpi_first_util_WPIUtilJNI
+ * Method: writeStderr
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL
+Java_edu_wpi_first_util_WPIUtilJNI_writeStderr
+ (JNIEnv* env, jclass, jstring str)
+{
+ fmt::print(stderr, "{}", JStringRef{env, str});
+}
+
+/*
+ * Class: edu_wpi_first_util_WPIUtilJNI
* Method: enableMockTime
* Signature: ()V
*/
@@ -130,32 +122,6 @@
/*
* Class: edu_wpi_first_util_WPIUtilJNI
- * Method: addPortForwarder
- * Signature: (ILjava/lang/String;I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_addPortForwarder
- (JNIEnv* env, jclass, jint port, jstring remoteHost, jint remotePort)
-{
- wpi::PortForwarder::GetInstance().Add(static_cast<unsigned int>(port),
- JStringRef{env, remoteHost}.str(),
- static_cast<unsigned int>(remotePort));
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: removePortForwarder
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_removePortForwarder
- (JNIEnv* env, jclass, jint port)
-{
- wpi::PortForwarder::GetInstance().Remove(port);
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
* Method: createEvent
* Signature: (ZZ)I
*/
@@ -281,7 +247,7 @@
JIntArrayRef handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
- wpi::span<const WPI_Handle> handlesArr2{
+ std::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
handlesArr.size()};
@@ -305,7 +271,7 @@
JIntArrayRef handlesArr{env, handles};
wpi::SmallVector<WPI_Handle, 8> signaledBuf;
signaledBuf.resize(handlesArr.size());
- wpi::span<const WPI_Handle> handlesArr2{
+ std::span<const WPI_Handle> handlesArr2{
reinterpret_cast<const WPI_Handle*>(handlesArr.array().data()),
handlesArr.size()};
@@ -319,257 +285,4 @@
return MakeJIntArray(env, signaled);
}
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: createMulticastServiceAnnouncer
- * Signature: (Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/Object;[Ljava/lang/Object;)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_createMulticastServiceAnnouncer
- (JNIEnv* env, jclass, jstring serviceName, jstring serviceType, jint port,
- jobjectArray keys, jobjectArray values)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
-
- JStringRef serviceNameRef{env, serviceName};
- JStringRef serviceTypeRef{env, serviceType};
-
- size_t keysLen = env->GetArrayLength(keys);
- wpi::SmallVector<std::pair<std::string, std::string>, 8> txtVec;
- txtVec.reserve(keysLen);
- for (size_t i = 0; i < keysLen; i++) {
- JLocal<jstring> key{
- env, static_cast<jstring>(env->GetObjectArrayElement(keys, i))};
- JLocal<jstring> value{
- env, static_cast<jstring>(env->GetObjectArrayElement(values, i))};
-
- txtVec.emplace_back(std::pair<std::string, std::string>{
- JStringRef{env, key}.str(), JStringRef{env, value}.str()});
- }
-
- auto announcer = std::make_unique<wpi::MulticastServiceAnnouncer>(
- serviceNameRef.str(), serviceTypeRef.str(), port, txtVec);
-
- size_t index = manager.handleIds.emplace_back(1);
-
- manager.announcers[index] = std::move(announcer);
-
- return static_cast<jint>(index);
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: freeMulticastServiceAnnouncer
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_freeMulticastServiceAnnouncer
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- manager.announcers[handle] = nullptr;
- manager.handleIds.erase(handle);
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: startMulticastServiceAnnouncer
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_startMulticastServiceAnnouncer
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- announcer->Start();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: stopMulticastServiceAnnouncer
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_stopMulticastServiceAnnouncer
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- announcer->Stop();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: getMulticastServiceAnnouncerHasImplementation
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceAnnouncerHasImplementation
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& announcer = manager.announcers[handle];
- return announcer->HasImplementation();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: createMulticastServiceResolver
- * Signature: (Ljava/lang/String;)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_createMulticastServiceResolver
- (JNIEnv* env, jclass, jstring serviceType)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- JStringRef serviceTypeRef{env, serviceType};
-
- auto resolver =
- std::make_unique<wpi::MulticastServiceResolver>(serviceTypeRef.str());
-
- size_t index = manager.handleIds.emplace_back(2);
-
- manager.resolvers[index] = std::move(resolver);
-
- return static_cast<jint>(index);
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: freeMulticastServiceResolver
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_freeMulticastServiceResolver
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- manager.resolvers[handle] = nullptr;
- manager.handleIds.erase(handle);
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: startMulticastServiceResolver
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_startMulticastServiceResolver
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- resolver->Start();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: stopMulticastServiceResolver
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_stopMulticastServiceResolver
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- resolver->Stop();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: getMulticastServiceResolverHasImplementation
- * Signature: (I)Z
- */
-JNIEXPORT jboolean JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverHasImplementation
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- return resolver->HasImplementation();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: getMulticastServiceResolverEventHandle
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverEventHandle
- (JNIEnv* env, jclass, jint handle)
-{
- auto& manager = wpi::GetMulticastManager();
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- return resolver->GetEventHandle();
-}
-
-/*
- * Class: edu_wpi_first_util_WPIUtilJNI
- * Method: getMulticastServiceResolverData
- * Signature: (I)[Ljava/lang/Object;
- */
-JNIEXPORT jobjectArray JNICALL
-Java_edu_wpi_first_util_WPIUtilJNI_getMulticastServiceResolverData
- (JNIEnv* env, jclass, jint handle)
-{
- static jmethodID constructor =
- env->GetMethodID(serviceDataCls, "<init>",
- "(JILjava/lang/String;Ljava/lang/String;[Ljava/lang/"
- "String;[Ljava/lang/String;)V");
- auto& manager = wpi::GetMulticastManager();
- std::vector<wpi::MulticastServiceResolver::ServiceData> allData;
- {
- std::scoped_lock lock{manager.mutex};
- auto& resolver = manager.resolvers[handle];
- allData = resolver->GetData();
- }
- if (allData.empty()) {
- return serviceDataEmptyArray;
- }
-
- JLocal<jobjectArray> returnData{
- env, env->NewObjectArray(allData.size(), serviceDataCls, nullptr)};
-
- for (auto&& data : allData) {
- JLocal<jstring> serviceName{env, MakeJString(env, data.serviceName)};
- JLocal<jstring> hostName{env, MakeJString(env, data.hostName)};
-
- wpi::SmallVector<std::string_view, 8> keysRef;
- wpi::SmallVector<std::string_view, 8> valuesRef;
-
- size_t index = 0;
- for (auto&& txt : data.txt) {
- keysRef.emplace_back(txt.first);
- valuesRef.emplace_back(txt.second);
- }
-
- JLocal<jobjectArray> keys{env, MakeJStringArray(env, keysRef)};
- JLocal<jobjectArray> values{env, MakeJStringArray(env, valuesRef)};
-
- JLocal<jobject> dataItem{
- env, env->NewObject(serviceDataCls, constructor,
- static_cast<jlong>(data.ipv4Address),
- static_cast<jint>(data.port), serviceName.obj(),
- hostName.obj(), keys.obj(), values.obj())};
-
- env->SetObjectArrayElement(returnData, index, dataItem);
- index++;
- }
-
- return returnData;
-}
-
} // extern "C"
diff --git a/wpiutil/src/main/native/cpp/leb128.cpp b/wpiutil/src/main/native/cpp/leb128.cpp
index 9657883..17fbeb9 100644
--- a/wpiutil/src/main/native/cpp/leb128.cpp
+++ b/wpiutil/src/main/native/cpp/leb128.cpp
@@ -7,7 +7,6 @@
#include "wpi/SpanExtras.h"
#include "wpi/raw_istream.h"
#include "wpi/raw_ostream.h"
-#include "wpi/span.h"
namespace wpi {
@@ -98,7 +97,7 @@
return true;
}
-std::optional<uint64_t> Uleb128Reader::ReadOne(span<const uint8_t>* in) {
+std::optional<uint64_t> Uleb128Reader::ReadOne(std::span<const uint8_t>* in) {
while (!in->empty()) {
uint8_t byte = in->front();
*in = wpi::drop_front(*in);
diff --git a/wpiutil/src/main/native/cpp/llvm/ConvertUTFWrapper.cpp b/wpiutil/src/main/native/cpp/llvm/ConvertUTFWrapper.cpp
deleted file mode 100644
index db190d0..0000000
--- a/wpiutil/src/main/native/cpp/llvm/ConvertUTFWrapper.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "wpi/ConvertUTF.h"
-#include "wpi/SmallVector.h"
-#include <string>
-#include <vector>
-
-namespace wpi {
-
-bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
- const UTF32 *SourceStart = &Source;
- const UTF32 *SourceEnd = SourceStart + 1;
- UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
- UTF8 *TargetEnd = TargetStart + 4;
- ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
- &TargetStart, TargetEnd,
- strictConversion);
- if (CR != conversionOK)
- return false;
-
- ResultPtr = reinterpret_cast<char*>(TargetStart);
- return true;
-}
-
-bool hasUTF16ByteOrderMark(span<const char> S) {
- return (S.size() >= 2 &&
- ((S[0] == '\xff' && S[1] == '\xfe') ||
- (S[0] == '\xfe' && S[1] == '\xff')));
-}
-
-bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
- SmallVectorImpl<char> &DstUTF8) {
- assert(DstUTF8.empty());
-
- // Avoid OOB by returning early on empty input.
- if (SrcUTF16.empty())
- return true;
-
- const UTF16 *Src = SrcUTF16.begin();
- const UTF16 *SrcEnd = SrcUTF16.end();
-
- // Byteswap if necessary.
- std::vector<UTF16> ByteSwapped;
- if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
- ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
- for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I)
- ByteSwapped[I] = (ByteSwapped[I] << 8) | (ByteSwapped[I] >> 8);
- Src = &ByteSwapped[0];
- SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
- }
-
- // Skip the BOM for conversion.
- if (Src[0] == UNI_UTF16_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.
- DstUTF8.resize(SrcUTF16.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1);
- UTF8 *Dst = reinterpret_cast<UTF8*>(&DstUTF8[0]);
- UTF8 *DstEnd = Dst + DstUTF8.size();
-
- ConversionResult CR =
- ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
- assert(CR != targetExhausted);
-
- if (CR != conversionOK) {
- DstUTF8.clear();
- return false;
- }
-
- DstUTF8.resize(reinterpret_cast<char*>(Dst) - &DstUTF8[0]);
- DstUTF8.push_back(0);
- DstUTF8.pop_back();
- return true;
-}
-
-bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
- SmallVectorImpl<UTF16> &DstUTF16) {
- assert(DstUTF16.empty());
-
- // Avoid OOB by returning early on empty input.
- if (SrcUTF8.empty()) {
- DstUTF16.push_back(0);
- DstUTF16.pop_back();
- return true;
- }
-
- const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
- const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
-
- // Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
- // as UTF-16 should always require the same amount or less code units than the
- // UTF-8 encoding. Allocate one extra byte for the null terminator though,
- // so that someone calling DstUTF16.data() gets a null terminated string.
- // We resize down later so we don't have to worry that this over allocates.
- DstUTF16.resize(SrcUTF8.size()+1);
- UTF16 *Dst = &DstUTF16[0];
- UTF16 *DstEnd = Dst + DstUTF16.size();
-
- ConversionResult CR =
- ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
- assert(CR != targetExhausted);
-
- if (CR != conversionOK) {
- DstUTF16.clear();
- return false;
- }
-
- DstUTF16.resize(Dst - &DstUTF16[0]);
- DstUTF16.push_back(0);
- DstUTF16.pop_back();
- return true;
-}
-
-} // end namespace wpi
-
diff --git a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp b/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
deleted file mode 100644
index a8c82bf..0000000
--- a/wpiutil/src/main/native/cpp/llvm/ManagedStatic.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-//===-- ManagedStatic.cpp - Static Global wrapper -------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the ManagedStatic class and wpi_shutdown().
-//
-//===----------------------------------------------------------------------===//
-
-#include "wpi/ManagedStatic.h"
-#include "wpi/mutex.h"
-#include <cassert>
-#include <mutex>
-using namespace wpi;
-
-static const ManagedStaticBase *StaticList = nullptr;
-static wpi::mutex *ManagedStaticMutex = nullptr;
-static std::once_flag mutex_init_flag;
-
-static void initializeMutex() {
- ManagedStaticMutex = new wpi::mutex();
-}
-
-static wpi::mutex* getManagedStaticMutex() {
- std::call_once(mutex_init_flag, initializeMutex);
- return ManagedStaticMutex;
-}
-
-void ManagedStaticBase::RegisterManagedStatic(void* created,
- void (*Deleter)(void*)) const {
- std::scoped_lock Lock(*getManagedStaticMutex());
-
- if (!Ptr.load(std::memory_order_relaxed)) {
- void *Tmp = created;
-
- Ptr.store(Tmp, std::memory_order_release);
- DeleterFn = Deleter;
-
- // Add to list of managed statics.
- Next = StaticList;
- StaticList = this;
- }
-}
-
-void ManagedStaticBase::RegisterManagedStatic(void *(*Creator)(),
- void (*Deleter)(void*)) const {
- assert(Creator);
- std::scoped_lock Lock(*getManagedStaticMutex());
-
- if (!Ptr.load(std::memory_order_relaxed)) {
- void *Tmp = Creator();
-
- Ptr.store(Tmp, std::memory_order_release);
- DeleterFn = Deleter;
-
- // Add to list of managed statics.
- Next = StaticList;
- StaticList = this;
- }
-}
-
-void ManagedStaticBase::destroy() const {
- assert(DeleterFn && "ManagedStatic not initialized correctly!");
- assert(StaticList == this &&
- "Not destroyed in reverse order of construction?");
- // Unlink from list.
- StaticList = Next;
- Next = nullptr;
-
- // Destroy memory.
- DeleterFn(Ptr);
-
- // Cleanup.
- Ptr = nullptr;
- DeleterFn = nullptr;
-}
-
-/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
-void wpi::wpi_shutdown() {
- std::scoped_lock Lock(*getManagedStaticMutex());
-
- while (StaticList)
- StaticList->destroy();
-}
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp b/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
deleted file mode 100644
index 974fec9..0000000
--- a/wpiutil/src/main/native/cpp/llvm/SmallVector.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the SmallVector class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "wpi/SmallVector.h"
-#include "wpi/MemAlloc.h"
-using namespace wpi;
-
-/// grow_pod - This is an implementation of the grow() method which only works
-/// on POD-like datatypes and is out of line to reduce code duplication.
-void SmallVectorBase::grow_pod(void *FirstEl, size_t MinCapacity,
- size_t TSize) {
- // Ensure we can fit the new capacity in 32 bits.
- if (MinCapacity > UINT32_MAX)
- report_bad_alloc_error("SmallVector capacity overflow during allocation");
-
- size_t NewCapacity = 2 * capacity() + 1; // Always grow.
- NewCapacity =
- std::min(std::max(NewCapacity, MinCapacity), size_t(UINT32_MAX));
-
- void *NewElts;
- if (BeginX == FirstEl) {
- NewElts = safe_malloc(NewCapacity * TSize);
-
- // 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);
- }
-
- this->BeginX = NewElts;
- this->Capacity = NewCapacity;
-}
diff --git a/wpiutil/src/main/native/cpp/raw_socket_istream.cpp b/wpiutil/src/main/native/cpp/raw_socket_istream.cpp
deleted file mode 100644
index c6b759e..0000000
--- a/wpiutil/src/main/native/cpp/raw_socket_istream.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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/raw_socket_istream.h"
-
-#include "wpi/NetworkStream.h"
-
-using namespace wpi;
-
-void raw_socket_istream::read_impl(void* data, size_t len) {
- char* cdata = static_cast<char*>(data);
- size_t pos = 0;
-
- while (pos < len) {
- NetworkStream::Error err;
- size_t count = m_stream.receive(&cdata[pos], len - pos, &err, m_timeout);
- if (count == 0) {
- error_detected();
- break;
- }
- pos += count;
- }
- set_read_count(pos);
-}
-
-void raw_socket_istream::close() {
- m_stream.close();
-}
-
-size_t raw_socket_istream::in_avail() const {
- return 0;
-}
diff --git a/wpiutil/src/main/native/cpp/raw_socket_ostream.cpp b/wpiutil/src/main/native/cpp/raw_socket_ostream.cpp
deleted file mode 100644
index af01c84..0000000
--- a/wpiutil/src/main/native/cpp/raw_socket_ostream.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-// 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/raw_socket_ostream.h"
-
-#include "wpi/NetworkStream.h"
-
-using namespace wpi;
-
-raw_socket_ostream::~raw_socket_ostream() {
- flush();
- if (m_shouldClose) {
- close();
- }
-}
-
-void raw_socket_ostream::write_impl(const char* data, size_t len) {
- size_t pos = 0;
-
- while (pos < len) {
- NetworkStream::Error err;
- size_t count = m_stream.send(&data[pos], len - pos, &err);
- if (count == 0) {
- error_detected();
- return;
- }
- pos += count;
- }
-}
-
-uint64_t raw_socket_ostream::current_pos() const {
- return 0;
-}
-
-void raw_socket_ostream::close() {
- if (!m_shouldClose) {
- return;
- }
- flush();
- m_stream.close();
-}
diff --git a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp b/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
deleted file mode 100644
index f055a2a..0000000
--- a/wpiutil/src/main/native/cpp/raw_uv_ostream.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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/raw_uv_ostream.h"
-
-#include <cstring>
-
-using namespace wpi;
-
-void raw_uv_ostream::write_impl(const char* data, size_t len) {
- while (len > 0) {
- // allocate additional buffers as required
- if (m_left == 0) {
- m_bufs.emplace_back(m_alloc());
- // we want bufs() to always be valid, so set len=0 and keep track of the
- // amount of space remaining separately
- m_left = m_bufs.back().len;
- m_bufs.back().len = 0;
- assert(m_left != 0);
- }
-
- size_t amt = (std::min)(m_left, len);
- auto& buf = m_bufs.back();
- std::memcpy(buf.base + buf.len, data, amt);
- data += amt;
- len -= amt;
- buf.len += amt;
- m_left -= amt;
- }
-}
-
-uint64_t raw_uv_ostream::current_pos() const {
- uint64_t size = 0;
- for (auto&& buf : m_bufs) {
- size += buf.len;
- }
- return size;
-}
diff --git a/wpiutil/src/main/native/cpp/sha1.cpp b/wpiutil/src/main/native/cpp/sha1.cpp
index 8ec7cb1..98dc543 100644
--- a/wpiutil/src/main/native/cpp/sha1.cpp
+++ b/wpiutil/src/main/native/cpp/sha1.cpp
@@ -217,7 +217,7 @@
}
void SHA1::Update(std::string_view s) {
- raw_mem_istream is(span<const char>(s.data(), s.size()));
+ raw_mem_istream is(std::span<const char>(s.data(), s.size()));
Update(is);
}
diff --git a/wpiutil/src/main/native/cpp/uv/Async.cpp b/wpiutil/src/main/native/cpp/uv/Async.cpp
deleted file mode 100644
index c9d698e..0000000
--- a/wpiutil/src/main/native/cpp/uv/Async.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// 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/uv/Async.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-Async<>::~Async() noexcept {
- if (auto loop = m_loop.lock()) {
- Close();
- } else {
- ForceClosed();
- }
-}
-
-std::shared_ptr<Async<>> Async<>::Create(const std::shared_ptr<Loop>& loop) {
- auto h = std::make_shared<Async>(loop, private_init{});
- int err = uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
- Async& h = *static_cast<Async*>(handle->data);
- h.wakeup();
- });
- if (err < 0) {
- loop->ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Check.cpp b/wpiutil/src/main/native/cpp/uv/Check.cpp
deleted file mode 100644
index 97265d4..0000000
--- a/wpiutil/src/main/native/cpp/uv/Check.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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/uv/Check.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Check> Check::Create(Loop& loop) {
- auto h = std::make_shared<Check>(private_init{});
- int err = uv_check_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Check::Start() {
- Invoke(&uv_check_start, GetRaw(), [](uv_check_t* handle) {
- Check& h = *static_cast<Check*>(handle->data);
- h.check();
- });
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/FsEvent.cpp b/wpiutil/src/main/native/cpp/uv/FsEvent.cpp
deleted file mode 100644
index 3c83d1d..0000000
--- a/wpiutil/src/main/native/cpp/uv/FsEvent.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-// 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/uv/FsEvent.h"
-
-#include <cstdlib>
-
-#include "wpi/SmallString.h"
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<FsEvent> FsEvent::Create(Loop& loop) {
- auto h = std::make_shared<FsEvent>(private_init{});
- int err = uv_fs_event_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void FsEvent::Start(std::string_view path, unsigned int flags) {
- SmallString<128> pathBuf{path};
- Invoke(
- &uv_fs_event_start, GetRaw(),
- [](uv_fs_event_t* handle, const char* filename, int events, int status) {
- FsEvent& h = *static_cast<FsEvent*>(handle->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.fsEvent(filename, events);
- }
- },
- pathBuf.c_str(), flags);
-}
-
-std::string FsEvent::GetPath() {
- // Per the libuv docs, GetPath() always gives us a null-terminated string.
- // common case should be small
- char buf[128];
- size_t size = 128;
- int r = uv_fs_event_getpath(GetRaw(), buf, &size);
- if (r == 0) {
- return buf;
- } else if (r == UV_ENOBUFS) {
- // need to allocate a big enough buffer
- char* buf2 = static_cast<char*>(std::malloc(size));
- r = uv_fs_event_getpath(GetRaw(), buf2, &size);
- if (r == 0) {
- std::string out{buf2};
- std::free(buf2);
- return out;
- }
- std::free(buf2);
- }
- ReportError(r);
- return std::string{};
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/GetAddrInfo.cpp b/wpiutil/src/main/native/cpp/uv/GetAddrInfo.cpp
deleted file mode 100644
index 2e6e38f..0000000
--- a/wpiutil/src/main/native/cpp/uv/GetAddrInfo.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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/uv/GetAddrInfo.h"
-
-#include "wpi/SmallString.h"
-#include "wpi/uv/Loop.h"
-#include "wpi/uv/util.h"
-
-namespace wpi::uv {
-
-GetAddrInfoReq::GetAddrInfoReq() {
- error = [this](Error err) { GetLoop().error(err); };
-}
-
-void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
- std::string_view node, std::string_view service,
- const addrinfo* hints) {
- SmallString<128> nodeStr{node};
- SmallString<128> serviceStr{service};
- int err = uv_getaddrinfo(
- loop.GetRaw(), req->GetRaw(),
- [](uv_getaddrinfo_t* req, int status, addrinfo* res) {
- auto& h = *static_cast<GetAddrInfoReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.resolved(*res);
- }
- uv_freeaddrinfo(res);
- h.Release(); // this is always a one-shot
- },
- node.empty() ? nullptr : nodeStr.c_str(),
- service.empty() ? nullptr : serviceStr.c_str(), hints);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- req->Keep();
- }
-}
-
-void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
- std::string_view node, std::string_view service,
- const addrinfo* hints) {
- auto req = std::make_shared<GetAddrInfoReq>();
- req->resolved.connect(std::move(callback));
- GetAddrInfo(loop, req, node, service, hints);
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/GetNameInfo.cpp b/wpiutil/src/main/native/cpp/uv/GetNameInfo.cpp
deleted file mode 100644
index 4e662f3..0000000
--- a/wpiutil/src/main/native/cpp/uv/GetNameInfo.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-// 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/uv/GetNameInfo.h"
-
-#include "wpi/uv/Loop.h"
-#include "wpi/uv/util.h"
-
-namespace wpi::uv {
-
-GetNameInfoReq::GetNameInfoReq() {
- error = [this](Error err) { GetLoop().error(err); };
-}
-
-void GetNameInfo(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- const sockaddr& addr, int flags) {
- int err = uv_getnameinfo(
- loop.GetRaw(), req->GetRaw(),
- [](uv_getnameinfo_t* req, int status, const char* hostname,
- const char* service) {
- auto& h = *static_cast<GetNameInfoReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.resolved(hostname, service);
- }
- h.Release(); // this is always a one-shot
- },
- &addr, flags);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- req->Keep();
- }
-}
-
-void GetNameInfo(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- const sockaddr& addr, int flags) {
- auto req = std::make_shared<GetNameInfoReq>();
- req->resolved.connect(std::move(callback));
- GetNameInfo(loop, req, addr, flags);
-}
-
-void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port, int flags) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- GetNameInfo(loop, req, reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void GetNameInfo4(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port, int flags) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- GetNameInfo(loop, std::move(callback),
- reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port, int flags) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- GetNameInfo(loop, req, reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void GetNameInfo6(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port, int flags) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- loop.ReportError(err);
- } else {
- GetNameInfo(loop, std::move(callback),
- reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Handle.cpp b/wpiutil/src/main/native/cpp/uv/Handle.cpp
deleted file mode 100644
index 74c4c60..0000000
--- a/wpiutil/src/main/native/cpp/uv/Handle.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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/uv/Handle.h"
-
-using namespace wpi::uv;
-
-Handle::~Handle() noexcept {
- if (!m_closed && m_uv_handle->type != UV_UNKNOWN_HANDLE) {
- uv_close(m_uv_handle, [](uv_handle_t* uv_handle) { std::free(uv_handle); });
- } else {
- std::free(m_uv_handle);
- }
-}
-
-void Handle::Close() noexcept {
- if (!IsClosing()) {
- uv_close(m_uv_handle, [](uv_handle_t* handle) {
- Handle& h = *static_cast<Handle*>(handle->data);
- h.closed();
- h.Release(); // free ourselves
- });
- m_closed = true;
- }
-}
-
-void Handle::AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf) {
- auto& h = *static_cast<Handle*>(handle->data);
- *buf = h.m_allocBuf(size);
-}
-
-void Handle::DefaultFreeBuf(Buffer& buf) {
- buf.Deallocate();
-}
diff --git a/wpiutil/src/main/native/cpp/uv/Idle.cpp b/wpiutil/src/main/native/cpp/uv/Idle.cpp
deleted file mode 100644
index 6bf8602..0000000
--- a/wpiutil/src/main/native/cpp/uv/Idle.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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/uv/Idle.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Idle> Idle::Create(Loop& loop) {
- auto h = std::make_shared<Idle>(private_init{});
- int err = uv_idle_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Idle::Start() {
- Invoke(&uv_idle_start, GetRaw(), [](uv_idle_t* handle) {
- Idle& h = *static_cast<Idle*>(handle->data);
- h.idle();
- });
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Loop.cpp b/wpiutil/src/main/native/cpp/uv/Loop.cpp
deleted file mode 100644
index c5b7163..0000000
--- a/wpiutil/src/main/native/cpp/uv/Loop.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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/uv/Loop.h"
-
-using namespace wpi::uv;
-
-Loop::Loop(const private_init&) noexcept {
-#ifndef _WIN32
- // Ignore SIGPIPE (see https://github.com/joyent/libuv/issues/1254)
- static bool once = []() {
- signal(SIGPIPE, SIG_IGN);
- return true;
- }();
- (void)once;
-#endif
-}
-
-Loop::~Loop() noexcept {
- if (m_loop) {
- m_loop->data = nullptr;
- Close();
- }
-}
-
-std::shared_ptr<Loop> Loop::Create() {
- auto loop = std::make_shared<Loop>(private_init{});
- if (uv_loop_init(&loop->m_loopStruct) < 0) {
- return nullptr;
- }
- loop->m_loop = &loop->m_loopStruct;
- loop->m_loop->data = loop.get();
- return loop;
-}
-
-std::shared_ptr<Loop> Loop::GetDefault() {
- static std::shared_ptr<Loop> loop = std::make_shared<Loop>(private_init{});
- loop->m_loop = uv_default_loop();
- if (!loop->m_loop) {
- return nullptr;
- }
- loop->m_loop->data = loop.get();
- return loop;
-}
-
-void Loop::Close() {
- int err = uv_loop_close(m_loop);
- if (err < 0) {
- ReportError(err);
- }
-}
-
-void Loop::Walk(function_ref<void(Handle&)> callback) {
- uv_walk(
- m_loop,
- [](uv_handle_t* handle, void* func) {
- auto& h = *static_cast<Handle*>(handle->data);
- auto& f = *static_cast<function_ref<void(Handle&)>*>(func);
- f(h);
- },
- &callback);
-}
-
-void Loop::Fork() {
- int err = uv_loop_fork(m_loop);
- if (err < 0) {
- ReportError(err);
- }
-}
diff --git a/wpiutil/src/main/native/cpp/uv/NameToAddr.cpp b/wpiutil/src/main/native/cpp/uv/NameToAddr.cpp
deleted file mode 100644
index 23ec6da..0000000
--- a/wpiutil/src/main/native/cpp/uv/NameToAddr.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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/uv/util.h" // NOLINT(build/include_order)
-
-#include <cstring>
-
-#include "wpi/SmallString.h"
-
-namespace wpi::uv {
-
-int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in* addr) {
- if (ip.empty()) {
- std::memset(addr, 0, sizeof(sockaddr_in));
- addr->sin_family = PF_INET;
- addr->sin_addr.s_addr = INADDR_ANY;
- addr->sin_port = htons(port);
- return 0;
- } else {
- SmallString<128> ipBuf{ip};
- return uv_ip4_addr(ipBuf.c_str(), port, addr);
- }
-}
-
-int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in6* addr) {
- if (ip.empty()) {
- std::memset(addr, 0, sizeof(sockaddr_in6));
- addr->sin6_family = PF_INET6;
- addr->sin6_addr = in6addr_any;
- addr->sin6_port = htons(port);
- return 0;
- } else {
- SmallString<128> ipBuf{ip};
- return uv_ip6_addr(ipBuf.c_str(), port, addr);
- }
-}
-
-int NameToAddr(std::string_view ip, in_addr* addr) {
- if (ip.empty()) {
- addr->s_addr = INADDR_ANY;
- return 0;
- } else {
- SmallString<128> ipBuf{ip};
- return uv_inet_pton(AF_INET, ipBuf.c_str(), addr);
- }
-}
-
-int NameToAddr(std::string_view ip, in6_addr* addr) {
- if (ip.empty()) {
- *addr = in6addr_any;
- return 0;
- } else {
- SmallString<128> ipBuf{ip};
- return uv_inet_pton(AF_INET6, ipBuf.c_str(), addr);
- }
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/NetworkStream.cpp b/wpiutil/src/main/native/cpp/uv/NetworkStream.cpp
deleted file mode 100644
index 0bc3337..0000000
--- a/wpiutil/src/main/native/cpp/uv/NetworkStream.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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/uv/NetworkStream.h"
-
-namespace wpi::uv {
-
-ConnectReq::ConnectReq() {
- error = [this](Error err) { GetStream().error(err); };
-}
-
-void NetworkStream::Listen(int backlog) {
- Invoke(&uv_listen, GetRawStream(), backlog,
- [](uv_stream_t* handle, int status) {
- auto& h = *static_cast<NetworkStream*>(handle->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.connection();
- }
- });
-}
-
-void NetworkStream::Listen(std::function<void()> callback, int backlog) {
- connection.connect(std::move(callback));
- Listen(backlog);
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Pipe.cpp b/wpiutil/src/main/native/cpp/uv/Pipe.cpp
deleted file mode 100644
index b5ca673..0000000
--- a/wpiutil/src/main/native/cpp/uv/Pipe.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-// 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/uv/Pipe.h"
-
-#include <cstdlib>
-
-#include "wpi/SmallString.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Pipe> Pipe::Create(Loop& loop, bool ipc) {
- auto h = std::make_shared<Pipe>(private_init{});
- int err = uv_pipe_init(loop.GetRaw(), h->GetRaw(), ipc ? 1 : 0);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Pipe::Reuse(std::function<void()> callback, bool ipc) {
- if (IsClosing()) {
- return;
- }
- if (!m_reuseData) {
- m_reuseData = std::make_unique<ReuseData>();
- }
- m_reuseData->callback = std::move(callback);
- m_reuseData->ipc = ipc;
- uv_close(GetRawHandle(), [](uv_handle_t* handle) {
- Pipe& h = *static_cast<Pipe*>(handle->data);
- if (!h.m_reuseData) {
- return;
- }
- auto data = std::move(h.m_reuseData);
- auto err =
- uv_pipe_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->ipc ? 1 : 0);
- if (err < 0) {
- h.ReportError(err);
- return;
- }
- data->callback();
- });
-}
-
-std::shared_ptr<Pipe> Pipe::Accept() {
- auto client = Create(GetLoopRef(), GetRaw()->ipc);
- if (!client) {
- return nullptr;
- }
- if (!Accept(client)) {
- client->Release();
- return nullptr;
- }
- return client;
-}
-
-Pipe* Pipe::DoAccept() {
- return Accept().get();
-}
-
-void Pipe::Bind(std::string_view name) {
- SmallString<128> nameBuf{name};
- Invoke(&uv_pipe_bind, GetRaw(), nameBuf.c_str());
-}
-
-void Pipe::Connect(std::string_view name,
- const std::shared_ptr<PipeConnectReq>& req) {
- SmallString<128> nameBuf{name};
- uv_pipe_connect(req->GetRaw(), GetRaw(), nameBuf.c_str(),
- [](uv_connect_t* req, int status) {
- auto& h = *static_cast<PipeConnectReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.connected();
- }
- h.Release(); // this is always a one-shot
- });
- req->Keep();
-}
-
-void Pipe::Connect(std::string_view name, std::function<void()> callback) {
- auto req = std::make_shared<PipeConnectReq>();
- req->connected.connect(std::move(callback));
- Connect(name, req);
-}
-
-std::string Pipe::GetSock() {
- // Per libuv docs, the returned buffer is NOT null terminated.
- // common case should be small
- char buf[128];
- size_t size = 128;
- int r = uv_pipe_getsockname(GetRaw(), buf, &size);
- if (r == 0) {
- return std::string{buf, size};
- } else if (r == UV_ENOBUFS) {
- // need to allocate a big enough buffer
- char* buf2 = static_cast<char*>(std::malloc(size));
- r = uv_pipe_getsockname(GetRaw(), buf2, &size);
- if (r == 0) {
- std::string out{buf2, size};
- std::free(buf2);
- return out;
- }
- std::free(buf2);
- }
- ReportError(r);
- return std::string{};
-}
-
-std::string Pipe::GetPeer() {
- // Per libuv docs, the returned buffer is NOT null terminated.
- // common case should be small
- char buf[128];
- size_t size = 128;
- int r = uv_pipe_getpeername(GetRaw(), buf, &size);
- if (r == 0) {
- return std::string{buf, size};
- } else if (r == UV_ENOBUFS) {
- // need to allocate a big enough buffer
- char* buf2 = static_cast<char*>(std::malloc(size));
- r = uv_pipe_getpeername(GetRaw(), buf2, &size);
- if (r == 0) {
- std::string out{buf2, size};
- std::free(buf2);
- return out;
- }
- std::free(buf2);
- }
- ReportError(r);
- return std::string{};
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Poll.cpp b/wpiutil/src/main/native/cpp/uv/Poll.cpp
deleted file mode 100644
index 090a40b..0000000
--- a/wpiutil/src/main/native/cpp/uv/Poll.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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/uv/Poll.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Poll> Poll::Create(Loop& loop, int fd) {
- auto h = std::make_shared<Poll>(private_init{});
- int err = uv_poll_init(loop.GetRaw(), h->GetRaw(), fd);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-std::shared_ptr<Poll> Poll::CreateSocket(Loop& loop, uv_os_sock_t sock) {
- auto h = std::make_shared<Poll>(private_init{});
- int err = uv_poll_init_socket(loop.GetRaw(), h->GetRaw(), sock);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Poll::Reuse(int fd, std::function<void()> callback) {
- if (IsClosing()) {
- return;
- }
- if (!m_reuseData) {
- m_reuseData = std::make_unique<ReuseData>();
- }
- m_reuseData->callback = std::move(callback);
- m_reuseData->isSocket = false;
- m_reuseData->fd = fd;
- uv_close(GetRawHandle(), [](uv_handle_t* handle) {
- Poll& h = *static_cast<Poll*>(handle->data);
- if (!h.m_reuseData || h.m_reuseData->isSocket) {
- return; // just in case
- }
- auto data = std::move(h.m_reuseData);
- int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->fd);
- if (err < 0) {
- h.ReportError(err);
- return;
- }
- data->callback();
- });
-}
-
-void Poll::ReuseSocket(uv_os_sock_t sock, std::function<void()> callback) {
- if (IsClosing()) {
- return;
- }
- if (!m_reuseData) {
- m_reuseData = std::make_unique<ReuseData>();
- }
- m_reuseData->callback = std::move(callback);
- m_reuseData->isSocket = true;
- m_reuseData->sock = sock;
- uv_close(GetRawHandle(), [](uv_handle_t* handle) {
- Poll& h = *static_cast<Poll*>(handle->data);
- if (!h.m_reuseData || !h.m_reuseData->isSocket) {
- return; // just in case
- }
- auto data = std::move(h.m_reuseData);
- int err = uv_poll_init(h.GetLoopRef().GetRaw(), h.GetRaw(), data->sock);
- if (err < 0) {
- h.ReportError(err);
- return;
- }
- data->callback();
- });
-}
-
-void Poll::Start(int events) {
- Invoke(&uv_poll_start, GetRaw(), events,
- [](uv_poll_t* handle, int status, int events) {
- Poll& h = *static_cast<Poll*>(handle->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.pollEvent(events);
- }
- });
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Prepare.cpp b/wpiutil/src/main/native/cpp/uv/Prepare.cpp
deleted file mode 100644
index 048fd08..0000000
--- a/wpiutil/src/main/native/cpp/uv/Prepare.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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/uv/Prepare.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Prepare> Prepare::Create(Loop& loop) {
- auto h = std::make_shared<Prepare>(private_init{});
- int err = uv_prepare_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Prepare::Start() {
- Invoke(&uv_prepare_start, GetRaw(), [](uv_prepare_t* handle) {
- Prepare& h = *static_cast<Prepare*>(handle->data);
- h.prepare();
- });
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Process.cpp b/wpiutil/src/main/native/cpp/uv/Process.cpp
deleted file mode 100644
index c8d5229..0000000
--- a/wpiutil/src/main/native/cpp/uv/Process.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-// 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/uv/Process.h"
-
-#include "wpi/SmallString.h"
-#include "wpi/uv/Loop.h"
-#include "wpi/uv/Pipe.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Process> Process::SpawnArray(Loop& loop, std::string_view file,
- span<const Option> options) {
- // convert Option array to libuv structure
- uv_process_options_t coptions;
-
- coptions.exit_cb = [](uv_process_t* handle, int64_t status, int signal) {
- auto& h = *static_cast<Process*>(handle->data);
- h.exited(status, signal);
- };
-
- SmallString<128> fileBuf{file};
- coptions.file = fileBuf.c_str();
- coptions.cwd = nullptr;
- coptions.flags = 0;
- coptions.uid = 0;
- coptions.gid = 0;
-
- SmallVector<char*, 4> argsBuf;
- SmallVector<char*, 4> envBuf;
- struct StdioContainer : public uv_stdio_container_t {
- StdioContainer() {
- flags = UV_IGNORE;
- data.fd = 0;
- }
- };
- SmallVector<StdioContainer, 4> stdioBuf;
-
- for (auto&& o : options) {
- switch (o.m_type) {
- case Option::kArg:
- argsBuf.push_back(const_cast<char*>(o.m_data.str));
- break;
- case Option::kEnv:
- envBuf.push_back(const_cast<char*>(o.m_data.str));
- break;
- case Option::kCwd:
- coptions.cwd = o.m_data.str[0] == '\0' ? nullptr : o.m_data.str;
- break;
- case Option::kUid:
- coptions.uid = o.m_data.uid;
- coptions.flags |= UV_PROCESS_SETUID;
- break;
- case Option::kGid:
- coptions.gid = o.m_data.gid;
- coptions.flags |= UV_PROCESS_SETGID;
- break;
- case Option::kSetFlags:
- coptions.flags |= o.m_data.flags;
- break;
- case Option::kClearFlags:
- coptions.flags &= ~o.m_data.flags;
- break;
- case Option::kStdioIgnore: {
- size_t index = o.m_data.stdio.index;
- if (index >= stdioBuf.size()) {
- stdioBuf.resize(index + 1);
- }
- stdioBuf[index].flags = UV_IGNORE;
- stdioBuf[index].data.fd = 0;
- break;
- }
- case Option::kStdioInheritFd: {
- size_t index = o.m_data.stdio.index;
- if (index >= stdioBuf.size()) {
- stdioBuf.resize(index + 1);
- }
- stdioBuf[index].flags = UV_INHERIT_FD;
- stdioBuf[index].data.fd = o.m_data.stdio.fd;
- break;
- }
- case Option::kStdioInheritPipe: {
- size_t index = o.m_data.stdio.index;
- if (index >= stdioBuf.size()) {
- stdioBuf.resize(index + 1);
- }
- stdioBuf[index].flags = UV_INHERIT_STREAM;
- stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream();
- break;
- }
- case Option::kStdioCreatePipe: {
- size_t index = o.m_data.stdio.index;
- if (index >= stdioBuf.size()) {
- stdioBuf.resize(index + 1);
- }
- stdioBuf[index].flags =
- static_cast<uv_stdio_flags>(UV_CREATE_PIPE | o.m_data.stdio.flags);
- stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream();
- break;
- }
- default:
- break;
- }
- }
-
- if (argsBuf.empty()) {
- argsBuf.push_back(const_cast<char*>(coptions.file));
- }
- argsBuf.push_back(nullptr);
- coptions.args = argsBuf.data();
-
- if (envBuf.empty()) {
- coptions.env = nullptr;
- } else {
- envBuf.push_back(nullptr);
- coptions.env = envBuf.data();
- }
-
- coptions.stdio_count = stdioBuf.size();
- coptions.stdio = static_cast<uv_stdio_container_t*>(stdioBuf.data());
-
- auto h = std::make_shared<Process>(private_init{});
- int err = uv_spawn(loop.GetRaw(), h->GetRaw(), &coptions);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Signal.cpp b/wpiutil/src/main/native/cpp/uv/Signal.cpp
deleted file mode 100644
index 81d7c3e..0000000
--- a/wpiutil/src/main/native/cpp/uv/Signal.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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/uv/Signal.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Signal> Signal::Create(Loop& loop) {
- auto h = std::make_shared<Signal>(private_init{});
- int err = uv_signal_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Signal::Start(int signum) {
- Invoke(
- &uv_signal_start, GetRaw(),
- [](uv_signal_t* handle, int signum) {
- Signal& h = *static_cast<Signal*>(handle->data);
- h.signal(signum);
- },
- signum);
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Stream.cpp b/wpiutil/src/main/native/cpp/uv/Stream.cpp
deleted file mode 100644
index a37750b..0000000
--- a/wpiutil/src/main/native/cpp/uv/Stream.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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/uv/Stream.h"
-
-#include "wpi/SmallVector.h"
-
-using namespace wpi;
-using namespace wpi::uv;
-
-namespace {
-class CallbackWriteReq : public WriteReq {
- public:
- CallbackWriteReq(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback)
- : m_bufs{bufs.begin(), bufs.end()} {
- finish.connect(
- [this, f = std::move(callback)](Error err) { f(m_bufs, err); });
- }
-
- private:
- SmallVector<Buffer, 4> m_bufs;
-};
-} // namespace
-
-namespace wpi::uv {
-
-ShutdownReq::ShutdownReq() {
- error = [this](Error err) { GetStream().error(err); };
-}
-
-WriteReq::WriteReq() {
- error = [this](Error err) { GetStream().error(err); };
-}
-
-void Stream::Shutdown(const std::shared_ptr<ShutdownReq>& req) {
- if (Invoke(&uv_shutdown, req->GetRaw(), GetRawStream(),
- [](uv_shutdown_t* req, int status) {
- auto& h = *static_cast<ShutdownReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.complete();
- }
- h.Release(); // this is always a one-shot
- })) {
- req->Keep();
- }
-}
-
-void Stream::Shutdown(std::function<void()> callback) {
- auto req = std::make_shared<ShutdownReq>();
- if (callback) {
- req->complete.connect(std::move(callback));
- }
- Shutdown(req);
-}
-
-void Stream::StartRead() {
- Invoke(&uv_read_start, GetRawStream(), &Handle::AllocBuf,
- [](uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
- auto& h = *static_cast<Stream*>(stream->data);
- Buffer data = *buf;
-
- // nread=0 is simply ignored
- if (nread == UV_EOF) {
- h.end();
- } else if (nread > 0) {
- h.data(data, static_cast<size_t>(nread));
- } else if (nread < 0) {
- h.ReportError(nread);
- }
-
- // free the buffer
- h.FreeBuf(data);
- });
-}
-
-void Stream::Write(span<const Buffer> bufs,
- const std::shared_ptr<WriteReq>& req) {
- if (Invoke(&uv_write, req->GetRaw(), GetRawStream(), bufs.data(), bufs.size(),
- [](uv_write_t* r, int status) {
- auto& h = *static_cast<WriteReq*>(r->data);
- if (status < 0) {
- h.ReportError(status);
- }
- h.finish(Error(status));
- h.Release(); // this is always a one-shot
- })) {
- req->Keep();
- }
-}
-
-void Stream::Write(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Write(bufs, std::make_shared<CallbackWriteReq>(bufs, std::move(callback)));
-}
-
-int Stream::TryWrite(span<const Buffer> bufs) {
- int val = uv_try_write(GetRawStream(), bufs.data(), bufs.size());
- if (val < 0) {
- this->ReportError(val);
- return 0;
- }
- return val;
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Tcp.cpp b/wpiutil/src/main/native/cpp/uv/Tcp.cpp
deleted file mode 100644
index 6f92557..0000000
--- a/wpiutil/src/main/native/cpp/uv/Tcp.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-// 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/uv/Tcp.h"
-
-#include <cstring>
-
-#include "wpi/uv/util.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Tcp> Tcp::Create(Loop& loop, unsigned int flags) {
- auto h = std::make_shared<Tcp>(private_init{});
- int err = uv_tcp_init_ex(loop.GetRaw(), h->GetRaw(), flags);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Tcp::Reuse(std::function<void()> callback, unsigned int flags) {
- if (IsClosing()) {
- return;
- }
- if (!m_reuseData) {
- m_reuseData = std::make_unique<ReuseData>();
- }
- m_reuseData->callback = std::move(callback);
- m_reuseData->flags = flags;
- uv_close(GetRawHandle(), [](uv_handle_t* handle) {
- Tcp& h = *static_cast<Tcp*>(handle->data);
- if (!h.m_reuseData) {
- return; // just in case
- }
- auto data = std::move(h.m_reuseData);
- int err = uv_tcp_init_ex(h.GetLoopRef().GetRaw(), h.GetRaw(), data->flags);
- if (err < 0) {
- h.ReportError(err);
- return;
- }
- data->callback();
- });
-}
-
-std::shared_ptr<Tcp> Tcp::Accept() {
- auto client = Create(GetLoopRef());
- if (!client) {
- return nullptr;
- }
- if (!Accept(client)) {
- client->Release();
- return nullptr;
- }
- return client;
-}
-
-Tcp* Tcp::DoAccept() {
- return Accept().get();
-}
-
-void Tcp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void Tcp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-sockaddr_storage Tcp::GetSock() {
- sockaddr_storage name;
- int len = sizeof(name);
- if (!Invoke(&uv_tcp_getsockname, GetRaw(), reinterpret_cast<sockaddr*>(&name),
- &len)) {
- std::memset(&name, 0, sizeof(name));
- }
- return name;
-}
-
-sockaddr_storage Tcp::GetPeer() {
- sockaddr_storage name;
- int len = sizeof(name);
- if (!Invoke(&uv_tcp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
- &len)) {
- std::memset(&name, 0, sizeof(name));
- }
- return name;
-}
-
-void Tcp::Connect(const sockaddr& addr,
- const std::shared_ptr<TcpConnectReq>& req) {
- if (Invoke(&uv_tcp_connect, req->GetRaw(), GetRaw(), &addr,
- [](uv_connect_t* req, int status) {
- auto& h = *static_cast<TcpConnectReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.connected();
- }
- h.Release(); // this is always a one-shot
- })) {
- req->Keep();
- }
-}
-
-void Tcp::Connect(const sockaddr& addr, std::function<void()> callback) {
- auto req = std::make_shared<TcpConnectReq>();
- req->connected.connect(std::move(callback));
- Connect(addr, req);
-}
-
-void Tcp::Connect(std::string_view ip, unsigned int port,
- const std::shared_ptr<TcpConnectReq>& req) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr), req);
- }
-}
-
-void Tcp::Connect(std::string_view ip, unsigned int port,
- std::function<void()> callback) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
- }
-}
-
-void Tcp::Connect6(std::string_view ip, unsigned int port,
- const std::shared_ptr<TcpConnectReq>& req) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr), req);
- }
-}
-
-void Tcp::Connect6(std::string_view ip, unsigned int port,
- std::function<void()> callback) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
- }
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Timer.cpp b/wpiutil/src/main/native/cpp/uv/Timer.cpp
deleted file mode 100644
index 33fd851..0000000
--- a/wpiutil/src/main/native/cpp/uv/Timer.cpp
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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/uv/Timer.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Timer> Timer::Create(Loop& loop) {
- auto h = std::make_shared<Timer>(private_init{});
- int err = uv_timer_init(loop.GetRaw(), h->GetRaw());
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Timer::SingleShot(Loop& loop, Time timeout, std::function<void()> func) {
- auto h = Create(loop);
- if (!h) {
- return;
- }
- h->timeout.connect([theTimer = h.get(), f = std::move(func)]() {
- f();
- theTimer->Close();
- });
- h->Start(timeout);
-}
-
-void Timer::Start(Time timeout, Time repeat) {
- Invoke(
- &uv_timer_start, GetRaw(),
- [](uv_timer_t* handle) {
- Timer& h = *static_cast<Timer*>(handle->data);
- h.timeout();
- },
- timeout.count(), repeat.count());
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Tty.cpp b/wpiutil/src/main/native/cpp/uv/Tty.cpp
deleted file mode 100644
index 4531ded..0000000
--- a/wpiutil/src/main/native/cpp/uv/Tty.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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/uv/Tty.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-std::shared_ptr<Tty> Tty::Create(Loop& loop, uv_file fd, bool readable) {
- auto h = std::make_shared<Tty>(private_init{});
- int err = uv_tty_init(loop.GetRaw(), h->GetRaw(), fd, readable ? 1 : 0);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Udp.cpp b/wpiutil/src/main/native/cpp/uv/Udp.cpp
deleted file mode 100644
index bea2b57..0000000
--- a/wpiutil/src/main/native/cpp/uv/Udp.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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/uv/Udp.h"
-
-#include <cstring>
-
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/uv/util.h"
-
-namespace {
-
-using namespace wpi;
-using namespace wpi::uv;
-
-class CallbackUdpSendReq : public UdpSendReq {
- public:
- CallbackUdpSendReq(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback)
- : m_bufs{bufs.begin(), bufs.end()} {
- complete.connect(
- [this, f = std::move(callback)](Error err) { f(m_bufs, err); });
- }
-
- private:
- SmallVector<Buffer, 4> m_bufs;
-};
-
-} // namespace
-
-namespace wpi::uv {
-
-UdpSendReq::UdpSendReq() {
- error = [this](Error err) { GetUdp().error(err); };
-}
-
-std::shared_ptr<Udp> Udp::Create(Loop& loop, unsigned int flags) {
- auto h = std::make_shared<Udp>(private_init{});
- int err = uv_udp_init_ex(loop.GetRaw(), h->GetRaw(), flags);
- if (err < 0) {
- loop.ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
-}
-
-void Udp::Bind(std::string_view ip, unsigned int port, unsigned int flags) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void Udp::Bind6(std::string_view ip, unsigned int port, unsigned int flags) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-}
-
-void Udp::Connect(std::string_view ip, unsigned int port) {
- sockaddr_in addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr));
- }
-}
-
-void Udp::Connect6(std::string_view ip, unsigned int port) {
- sockaddr_in6 addr;
- int err = NameToAddr(ip, port, &addr);
- if (err < 0) {
- ReportError(err);
- } else {
- Connect(reinterpret_cast<const sockaddr&>(addr));
- }
-}
-
-sockaddr_storage Udp::GetPeer() {
- sockaddr_storage name;
- int len = sizeof(name);
- if (!Invoke(&uv_udp_getpeername, GetRaw(), reinterpret_cast<sockaddr*>(&name),
- &len)) {
- std::memset(&name, 0, sizeof(name));
- }
- return name;
-}
-
-sockaddr_storage Udp::GetSock() {
- sockaddr_storage name;
- int len = sizeof(name);
- if (!Invoke(&uv_udp_getsockname, GetRaw(), reinterpret_cast<sockaddr*>(&name),
- &len)) {
- std::memset(&name, 0, sizeof(name));
- }
- return name;
-}
-
-void Udp::SetMembership(std::string_view multicastAddr,
- std::string_view interfaceAddr,
- uv_membership membership) {
- SmallString<128> multicastAddrBuf{multicastAddr};
- SmallString<128> interfaceAddrBuf{interfaceAddr};
- Invoke(&uv_udp_set_membership, GetRaw(), multicastAddrBuf.c_str(),
- interfaceAddrBuf.c_str(), membership);
-}
-
-void Udp::SetMulticastInterface(std::string_view interfaceAddr) {
- SmallString<128> interfaceAddrBuf{interfaceAddr};
- Invoke(&uv_udp_set_multicast_interface, GetRaw(), interfaceAddrBuf.c_str());
-}
-
-void Udp::Send(const sockaddr& addr, span<const Buffer> bufs,
- const std::shared_ptr<UdpSendReq>& req) {
- if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(),
- &addr, [](uv_udp_send_t* r, int status) {
- auto& h = *static_cast<UdpSendReq*>(r->data);
- if (status < 0) {
- h.ReportError(status);
- }
- h.complete(Error(status));
- h.Release(); // this is always a one-shot
- })) {
- req->Keep();
- }
-}
-
-void Udp::Send(const sockaddr& addr, span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Send(addr, bufs,
- std::make_shared<CallbackUdpSendReq>(bufs, std::move(callback)));
-}
-
-void Udp::Send(span<const Buffer> bufs,
- const std::shared_ptr<UdpSendReq>& req) {
- if (Invoke(&uv_udp_send, req->GetRaw(), GetRaw(), bufs.data(), bufs.size(),
- nullptr, [](uv_udp_send_t* r, int status) {
- auto& h = *static_cast<UdpSendReq*>(r->data);
- if (status < 0) {
- h.ReportError(status);
- }
- h.complete(Error(status));
- h.Release(); // this is always a one-shot
- })) {
- req->Keep();
- }
-}
-
-void Udp::Send(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Send(bufs, std::make_shared<CallbackUdpSendReq>(bufs, std::move(callback)));
-}
-
-void Udp::StartRecv() {
- Invoke(&uv_udp_recv_start, GetRaw(), &AllocBuf,
- [](uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf,
- const sockaddr* addr, unsigned flags) {
- auto& h = *static_cast<Udp*>(handle->data);
- Buffer data = *buf;
-
- // nread=0 is simply ignored
- if (nread > 0) {
- h.received(data, static_cast<size_t>(nread), *addr, flags);
- } else if (nread < 0) {
- h.ReportError(nread);
- }
-
- // free the buffer
- h.FreeBuf(data);
- });
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/cpp/uv/Work.cpp b/wpiutil/src/main/native/cpp/uv/Work.cpp
deleted file mode 100644
index 0fc254e..0000000
--- a/wpiutil/src/main/native/cpp/uv/Work.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-// 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/uv/Work.h"
-
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-WorkReq::WorkReq() {
- error = [this](Error err) { GetLoop().error(err); };
-}
-
-void QueueWork(Loop& loop, const std::shared_ptr<WorkReq>& req) {
- int err = uv_queue_work(
- loop.GetRaw(), req->GetRaw(),
- [](uv_work_t* req) {
- auto& h = *static_cast<WorkReq*>(req->data);
- h.work();
- },
- [](uv_work_t* req, int status) {
- auto& h = *static_cast<WorkReq*>(req->data);
- if (status < 0) {
- h.ReportError(status);
- } else {
- h.afterWork();
- }
- h.Release(); // this is always a one-shot
- });
- if (err < 0) {
- loop.ReportError(err);
- } else {
- req->Keep();
- }
-}
-
-void QueueWork(Loop& loop, std::function<void()> work,
- std::function<void()> afterWork) {
- auto req = std::make_shared<WorkReq>();
- if (work) {
- req->work.connect(std::move(work));
- }
- if (afterWork) {
- req->afterWork.connect(std::move(afterWork));
- }
- QueueWork(loop, req);
-}
-
-} // namespace wpi::uv
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/format-inl.h b/wpiutil/src/main/native/fmtlib/include/fmt/format-inl.h
deleted file mode 100644
index cc89abd..0000000
--- a/wpiutil/src/main/native/fmtlib/include/fmt/format-inl.h
+++ /dev/null
@@ -1,2642 +0,0 @@
-// Formatting library for C++ - implementation
-//
-// Copyright (c) 2012 - 2016, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-
-#ifndef FMT_FORMAT_INL_H_
-#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
-# include <locale>
-#endif
-
-#ifdef _WIN32
-# include <io.h> // _isatty
-#endif
-
-#include "format.h"
-
-FMT_BEGIN_NAMESPACE
-namespace detail {
-
-FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
- // Use unchecked std::fprintf to avoid triggering another assertion when
- // writing to stderr fails
- std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
- // Chosen instead of std::abort to satisfy Clang in CUDA mode during device
- // code pass.
- std::terminate();
-}
-
-FMT_FUNC void throw_format_error(const char* message) {
- FMT_THROW(format_error(message));
-}
-
-#ifndef _MSC_VER
-# define FMT_SNPRINTF snprintf
-#else // _MSC_VER
-inline int fmt_snprintf(char* buffer, size_t size, const char* format, ...) {
- va_list args;
- va_start(args, format);
- int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args);
- va_end(args);
- return result;
-}
-# define FMT_SNPRINTF fmt_snprintf
-#endif // _MSC_VER
-
-FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
- string_view message) FMT_NOEXCEPT {
- // Report error code making sure that the output fits into
- // inline_buffer_size to avoid dynamic memory allocation and potential
- // bad_alloc.
- out.try_resize(0);
- static const char SEP[] = ": ";
- static const char ERROR_STR[] = "error ";
- // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
- size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
- auto abs_value = static_cast<uint32_or_64_or_128_t<int>>(error_code);
- if (detail::is_negative(error_code)) {
- abs_value = 0 - abs_value;
- ++error_code_size;
- }
- error_code_size += detail::to_unsigned(detail::count_digits(abs_value));
- auto it = buffer_appender<char>(out);
- if (message.size() <= inline_buffer_size - error_code_size)
- format_to(it, FMT_STRING("{}{}"), message, SEP);
- format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code);
- FMT_ASSERT(out.size() <= inline_buffer_size, "");
-}
-
-FMT_FUNC void report_error(format_func func, int error_code,
- const char* message) FMT_NOEXCEPT {
- memory_buffer full_message;
- func(full_message, error_code, message);
- // Don't use fwrite_fully because the latter may throw.
- if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0)
- std::fputc('\n', stderr);
-}
-
-// A wrapper around fwrite that throws on error.
-inline void fwrite_fully(const void* ptr, size_t size, size_t count,
- FILE* stream) {
- std::fwrite(ptr, size, count, stream);
-}
-
-#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
-template <typename Locale>
-locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
- static_assert(std::is_same<Locale, std::locale>::value, "");
-}
-
-template <typename Locale> Locale locale_ref::get() const {
- static_assert(std::is_same<Locale, std::locale>::value, "");
- return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
-}
-
-template <typename Char>
-FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
- auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>());
- auto grouping = facet.grouping();
- auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep();
- return {std::move(grouping), thousands_sep};
-}
-template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
- return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
- .decimal_point();
-}
-#else
-template <typename Char>
-FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> {
- return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR};
-}
-template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
- return '.';
-}
-#endif
-} // namespace detail
-
-#if !FMT_MSC_VER
-FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT = default;
-#endif
-
-FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str,
- format_args args) {
- auto ec = std::error_code(error_code, std::generic_category());
- return std::system_error(ec, vformat(format_str, args));
-}
-
-namespace detail {
-
-template <> FMT_FUNC int count_digits<4>(detail::fallback_uintptr n) {
- // fallback_uintptr is always stored in little endian.
- int i = static_cast<int>(sizeof(void*)) - 1;
- while (i > 0 && n.value[i] == 0) --i;
- auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
- return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1;
-}
-
-// log10(2) = 0x0.4d104d427de7fbcc...
-static constexpr uint64_t log10_2_significand = 0x4d104d427de7fbcc;
-
-template <typename T = void> struct basic_impl_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,
- };
-
-#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};
-};
-
-// This is a struct rather than an alias to avoid shadowing warnings in gcc.
-struct impl_data : basic_impl_data<> {};
-
-#if __cplusplus < 201703L
-template <typename T>
-constexpr uint64_t basic_impl_data<T>::pow10_significands[];
-template <typename T> constexpr int16_t basic_impl_data<T>::pow10_exponents[];
-template <typename T> constexpr uint64_t basic_impl_data<T>::power_of_10_64[];
-#endif
-
-template <typename T> struct bits {
- static FMT_CONSTEXPR_DECL const int value =
- static_cast<int>(sizeof(T) * std::numeric_limits<unsigned char>::digits);
-};
-
-// Returns the number of significand bits in Float excluding the implicit bit.
-template <typename Float> constexpr int num_significand_bits() {
- // Subtract 1 to account for an implicit most significant bit in the
- // normalized form.
- return std::numeric_limits<Float>::digits - 1;
-}
-
-// A floating-point number f * pow(2, e).
-struct fp {
- uint64_t f;
- int e;
-
- static constexpr const int num_significand_bits = bits<decltype(f)>::value;
-
- constexpr fp() : f(0), e(0) {}
- constexpr fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
-
- // Constructs fp from an IEEE754 floating-point number. It is a template to
- // prevent compile errors on systems where n is not IEEE754.
- template <typename Float> explicit FMT_CONSTEXPR fp(Float n) { assign(n); }
-
- template <typename Float>
- using is_supported = bool_constant<sizeof(Float) == sizeof(uint64_t) ||
- sizeof(Float) == sizeof(uint32_t)>;
-
- // Assigns d to this and return true iff predecessor is closer than successor.
- template <typename Float, FMT_ENABLE_IF(is_supported<Float>::value)>
- FMT_CONSTEXPR bool assign(Float n) {
- // Assume float is in the format [sign][exponent][significand].
- const int num_float_significand_bits =
- detail::num_significand_bits<Float>();
- const uint64_t implicit_bit = 1ULL << num_float_significand_bits;
- const uint64_t significand_mask = implicit_bit - 1;
- constexpr bool is_double = sizeof(Float) == sizeof(uint64_t);
- auto u = bit_cast<conditional_t<is_double, uint64_t, uint32_t>>(n);
- f = u & significand_mask;
- const uint64_t exponent_mask = (~0ULL >> 1) & ~significand_mask;
- int biased_e =
- static_cast<int>((u & exponent_mask) >> num_float_significand_bits);
- // The predecessor is closer if n is a normalized power of 2 (f == 0) other
- // than the smallest normalized number (biased_e > 1).
- bool is_predecessor_closer = f == 0 && biased_e > 1;
- if (biased_e != 0)
- f += implicit_bit;
- else
- biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
- const int exponent_bias = std::numeric_limits<Float>::max_exponent - 1;
- e = biased_e - exponent_bias - num_float_significand_bits;
- return is_predecessor_closer;
- }
-
- template <typename Float, FMT_ENABLE_IF(!is_supported<Float>::value)>
- bool assign(Float) {
- FMT_ASSERT(false, "");
- return false;
- }
-};
-
-// Normalizes the value converted from double and multiplied by (1 << SHIFT).
-template <int SHIFT = 0> FMT_CONSTEXPR fp normalize(fp value) {
- // Handle subnormals.
- const uint64_t implicit_bit = 1ULL << num_significand_bits<double>();
- const auto shifted_implicit_bit = implicit_bit << SHIFT;
- while ((value.f & shifted_implicit_bit) == 0) {
- value.f <<= 1;
- --value.e;
- }
- // Subtract 1 to account for hidden bit.
- const auto offset =
- fp::num_significand_bits - num_significand_bits<double>() - SHIFT - 1;
- value.f <<= offset;
- value.e -= offset;
- return value;
-}
-
-inline bool operator==(fp x, fp y) { return x.f == y.f && x.e == y.e; }
-
-// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking.
-FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) {
-#if FMT_USE_INT128
- auto product = static_cast<__uint128_t>(lhs) * rhs;
- auto f = static_cast<uint64_t>(product >> 64);
- return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
-#else
- // Multiply 32-bit parts of significands.
- uint64_t mask = (1ULL << 32) - 1;
- uint64_t a = lhs >> 32, b = lhs & mask;
- uint64_t c = rhs >> 32, d = rhs & mask;
- uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
- // Compute mid 64-bit of result and round.
- uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
- return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
-#endif
-}
-
-FMT_CONSTEXPR inline fp operator*(fp x, fp y) {
- return {multiply(x.f, y.f), x.e + y.e + 64};
-}
-
-// 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;
- const auto significand = static_cast<int64_t>(log10_2_significand);
- 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;
- return {impl_data::pow10_significands[index],
- impl_data::pow10_exponents[index]};
-}
-
-// A simple accumulator to hold the sums of terms in bigint::square if uint128_t
-// is not available.
-struct accumulator {
- uint64_t lower;
- uint64_t upper;
-
- constexpr accumulator() : lower(0), upper(0) {}
- constexpr explicit operator uint32_t() const {
- return static_cast<uint32_t>(lower);
- }
-
- FMT_CONSTEXPR void operator+=(uint64_t n) {
- lower += n;
- if (lower < n) ++upper;
- }
- FMT_CONSTEXPR void operator>>=(int shift) {
- FMT_ASSERT(shift == 32, "");
- (void)shift;
- lower = (upper << 32) | (lower >> 32);
- upper >>= 32;
- }
-};
-
-class bigint {
- private:
- // A bigint is stored as an array of bigits (big digits), with bigit at index
- // 0 being the least significant one.
- using bigit = uint32_t;
- using double_bigit = uint64_t;
- enum { bigits_capacity = 32 };
- basic_memory_buffer<bigit, bigits_capacity> bigits_;
- int exp_;
-
- FMT_CONSTEXPR20 bigit operator[](int index) const {
- return bigits_[to_unsigned(index)];
- }
- FMT_CONSTEXPR20 bigit& operator[](int index) {
- return bigits_[to_unsigned(index)];
- }
-
- static FMT_CONSTEXPR_DECL const int bigit_bits = bits<bigit>::value;
-
- friend struct formatter<bigint>;
-
- FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) {
- auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
- (*this)[index] = static_cast<bigit>(result);
- borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
- }
-
- FMT_CONSTEXPR20 void remove_leading_zeros() {
- int num_bigits = static_cast<int>(bigits_.size()) - 1;
- while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
- bigits_.resize(to_unsigned(num_bigits + 1));
- }
-
- // Computes *this -= other assuming aligned bigints and *this >= other.
- FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) {
- FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
- FMT_ASSERT(compare(*this, other) >= 0, "");
- bigit borrow = 0;
- int i = other.exp_ - exp_;
- for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j)
- subtract_bigits(i, other.bigits_[j], borrow);
- while (borrow > 0) subtract_bigits(i, 0, borrow);
- remove_leading_zeros();
- }
-
- FMT_CONSTEXPR20 void multiply(uint32_t value) {
- const double_bigit wide_value = value;
- bigit carry = 0;
- for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
- double_bigit result = bigits_[i] * wide_value + carry;
- bigits_[i] = static_cast<bigit>(result);
- carry = static_cast<bigit>(result >> bigit_bits);
- }
- if (carry != 0) bigits_.push_back(carry);
- }
-
- FMT_CONSTEXPR20 void multiply(uint64_t value) {
- const bigit mask = ~bigit(0);
- const double_bigit lower = value & mask;
- const double_bigit upper = value >> bigit_bits;
- double_bigit carry = 0;
- for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
- double_bigit result = bigits_[i] * lower + (carry & mask);
- carry =
- bigits_[i] * upper + (result >> bigit_bits) + (carry >> bigit_bits);
- bigits_[i] = static_cast<bigit>(result);
- }
- while (carry != 0) {
- bigits_.push_back(carry & mask);
- carry >>= bigit_bits;
- }
- }
-
- public:
- FMT_CONSTEXPR20 bigint() : exp_(0) {}
- explicit bigint(uint64_t n) { assign(n); }
- FMT_CONSTEXPR20 ~bigint() {
- FMT_ASSERT(bigits_.capacity() <= bigits_capacity, "");
- }
-
- bigint(const bigint&) = delete;
- void operator=(const bigint&) = delete;
-
- FMT_CONSTEXPR20 void assign(const bigint& other) {
- auto size = other.bigits_.size();
- bigits_.resize(size);
- auto data = other.bigits_.data();
- std::copy(data, data + size, make_checked(bigits_.data(), size));
- exp_ = other.exp_;
- }
-
- FMT_CONSTEXPR20 void assign(uint64_t n) {
- size_t num_bigits = 0;
- do {
- bigits_[num_bigits++] = n & ~bigit(0);
- n >>= bigit_bits;
- } while (n != 0);
- bigits_.resize(num_bigits);
- exp_ = 0;
- }
-
- FMT_CONSTEXPR20 int num_bigits() const {
- return static_cast<int>(bigits_.size()) + exp_;
- }
-
- FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) {
- FMT_ASSERT(shift >= 0, "");
- exp_ += shift / bigit_bits;
- shift %= bigit_bits;
- if (shift == 0) return *this;
- bigit carry = 0;
- for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
- bigit c = bigits_[i] >> (bigit_bits - shift);
- bigits_[i] = (bigits_[i] << shift) + carry;
- carry = c;
- }
- if (carry != 0) bigits_.push_back(carry);
- return *this;
- }
-
- template <typename Int> FMT_CONSTEXPR20 bigint& operator*=(Int value) {
- FMT_ASSERT(value > 0, "");
- multiply(uint32_or_64_or_128_t<Int>(value));
- return *this;
- }
-
- friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) {
- int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
- if (num_lhs_bigits != num_rhs_bigits)
- return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
- int i = static_cast<int>(lhs.bigits_.size()) - 1;
- int j = static_cast<int>(rhs.bigits_.size()) - 1;
- int end = i - j;
- if (end < 0) end = 0;
- for (; i >= end; --i, --j) {
- bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
- if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
- }
- if (i != j) return i > j ? 1 : -1;
- return 0;
- }
-
- // Returns compare(lhs1 + lhs2, rhs).
- friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2,
- const bigint& rhs) {
- int max_lhs_bigits = (std::max)(lhs1.num_bigits(), lhs2.num_bigits());
- int num_rhs_bigits = rhs.num_bigits();
- if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
- if (max_lhs_bigits > num_rhs_bigits) return 1;
- auto get_bigit = [](const bigint& n, int i) -> bigit {
- return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
- };
- double_bigit borrow = 0;
- int min_exp = (std::min)((std::min)(lhs1.exp_, lhs2.exp_), rhs.exp_);
- for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
- double_bigit sum =
- static_cast<double_bigit>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
- bigit rhs_bigit = get_bigit(rhs, i);
- if (sum > rhs_bigit + borrow) return 1;
- borrow = rhs_bigit + borrow - sum;
- if (borrow > 1) return -1;
- borrow <<= bigit_bits;
- }
- return borrow != 0 ? -1 : 0;
- }
-
- // Assigns pow(10, exp) to this bigint.
- FMT_CONSTEXPR20 void assign_pow10(int exp) {
- FMT_ASSERT(exp >= 0, "");
- if (exp == 0) return assign(1);
- // Find the top bit.
- int bitmask = 1;
- while (exp >= bitmask) bitmask <<= 1;
- bitmask >>= 1;
- // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by
- // repeated squaring and multiplication.
- assign(5);
- bitmask >>= 1;
- while (bitmask != 0) {
- square();
- if ((exp & bitmask) != 0) *this *= 5;
- bitmask >>= 1;
- }
- *this <<= exp; // Multiply by pow(2, exp) by shifting.
- }
-
- FMT_CONSTEXPR20 void square() {
- int num_bigits = static_cast<int>(bigits_.size());
- int num_result_bigits = 2 * num_bigits;
- basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
- bigits_.resize(to_unsigned(num_result_bigits));
- using accumulator_t = conditional_t<FMT_USE_INT128, uint128_t, accumulator>;
- auto sum = accumulator_t();
- for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
- // Compute bigit at position bigit_index of the result by adding
- // cross-product terms n[i] * n[j] such that i + j == bigit_index.
- for (int i = 0, j = bigit_index; j >= 0; ++i, --j) {
- // Most terms are multiplied twice which can be optimized in the future.
- sum += static_cast<double_bigit>(n[i]) * n[j];
- }
- (*this)[bigit_index] = static_cast<bigit>(sum);
- sum >>= bits<bigit>::value; // Compute the carry.
- }
- // Do the same for the top half.
- for (int bigit_index = num_bigits; bigit_index < num_result_bigits;
- ++bigit_index) {
- for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
- sum += static_cast<double_bigit>(n[i++]) * n[j--];
- (*this)[bigit_index] = static_cast<bigit>(sum);
- sum >>= bits<bigit>::value;
- }
- remove_leading_zeros();
- exp_ *= 2;
- }
-
- // If this bigint has a bigger exponent than other, adds trailing zero to make
- // exponents equal. This simplifies some operations such as subtraction.
- FMT_CONSTEXPR20 void align(const bigint& other) {
- int exp_difference = exp_ - other.exp_;
- if (exp_difference <= 0) return;
- int num_bigits = static_cast<int>(bigits_.size());
- bigits_.resize(to_unsigned(num_bigits + exp_difference));
- for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
- bigits_[j] = bigits_[i];
- std::uninitialized_fill_n(bigits_.data(), exp_difference, 0);
- exp_ -= exp_difference;
- }
-
- // Divides this bignum by divisor, assigning the remainder to this and
- // returning the quotient.
- FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) {
- FMT_ASSERT(this != &divisor, "");
- if (compare(*this, divisor) < 0) return 0;
- FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
- align(divisor);
- int quotient = 0;
- do {
- subtract_aligned(divisor);
- ++quotient;
- } while (compare(*this, divisor) >= 0);
- return quotient;
- }
-};
-
-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;
- }
-};
-
-// 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 digits::result grisu_gen_digits(
- fp value, uint64_t error, int& exp, gen_digits_handler& handler) {
- 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 fixed precision by exponent because it is relative to decimal
- // point.
- int precision_offset = exp + handler.exp10;
- if (precision_offset > 0 &&
- handler.precision > max_value<int>() - precision_offset) {
- FMT_THROW(format_error("number is too big"));
- }
- handler.precision += precision_offset;
- // 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 = impl_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),
- impl_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;
- }
-}
-
-// A 128-bit integer type used internally,
-struct uint128_wrapper {
- uint128_wrapper() = default;
-
-#if FMT_USE_INT128
- uint128_t internal_;
-
- constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT
- : internal_{static_cast<uint128_t>(low) |
- (static_cast<uint128_t>(high) << 64)} {}
-
- constexpr uint128_wrapper(uint128_t u) : internal_{u} {}
-
- constexpr uint64_t high() const FMT_NOEXCEPT {
- return uint64_t(internal_ >> 64);
- }
- constexpr uint64_t low() const FMT_NOEXCEPT { return uint64_t(internal_); }
-
- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT {
- internal_ += n;
- return *this;
- }
-#else
- uint64_t high_;
- uint64_t low_;
-
- constexpr uint128_wrapper(uint64_t high, uint64_t low) FMT_NOEXCEPT
- : high_{high},
- low_{low} {}
-
- constexpr uint64_t high() const FMT_NOEXCEPT { return high_; }
- constexpr uint64_t low() const FMT_NOEXCEPT { return low_; }
-
- uint128_wrapper& operator+=(uint64_t n) FMT_NOEXCEPT {
-# if defined(_MSC_VER) && defined(_M_X64)
- unsigned char carry = _addcarry_u64(0, low_, n, &low_);
- _addcarry_u64(carry, high_, 0, &high_);
- return *this;
-# else
- uint64_t sum = low_ + n;
- high_ += (sum < low_ ? 1 : 0);
- low_ = sum;
- return *this;
-# endif
- }
-#endif
-};
-
-// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox.
-namespace dragonbox {
-// Computes 128-bit result of multiplication of two 64-bit unsigned integers.
-inline uint128_wrapper umul128(uint64_t x, uint64_t y) FMT_NOEXCEPT {
-#if FMT_USE_INT128
- return static_cast<uint128_t>(x) * static_cast<uint128_t>(y);
-#elif defined(_MSC_VER) && defined(_M_X64)
- uint128_wrapper result;
- result.low_ = _umul128(x, y, &result.high_);
- return result;
-#else
- const uint64_t mask = (uint64_t(1) << 32) - uint64_t(1);
-
- 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
-}
-
-// Computes upper 64 bits of multiplication of two 64-bit unsigned integers.
-inline uint64_t umul128_upper64(uint64_t x, uint64_t y) FMT_NOEXCEPT {
-#if FMT_USE_INT128
- auto p = static_cast<uint128_t>(x) * static_cast<uint128_t>(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 64 bits of multiplication of a 64-bit unsigned integer and a
-// 128-bit unsigned integer.
-inline uint64_t umul192_upper64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
- uint128_wrapper g0 = umul128(x, y.high());
- g0 += umul128_upper64(x, y.low());
- return g0.high();
-}
-
-// Computes upper 32 bits of multiplication of a 32-bit unsigned integer and a
-// 64-bit unsigned integer.
-inline uint32_t umul96_upper32(uint32_t x, uint64_t y) FMT_NOEXCEPT {
- return static_cast<uint32_t>(umul128_upper64(x, y));
-}
-
-// Computes middle 64 bits of multiplication of a 64-bit unsigned integer and a
-// 128-bit unsigned integer.
-inline uint64_t umul192_middle64(uint64_t x, uint128_wrapper y) FMT_NOEXCEPT {
- uint64_t g01 = x * y.high();
- uint64_t g10 = umul128_upper64(x, y.low());
- return g01 + g10;
-}
-
-// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a
-// 64-bit unsigned integer.
-inline uint64_t umul96_lower64(uint32_t x, uint64_t y) FMT_NOEXCEPT {
- return x * y;
-}
-
-// Computes floor(log10(pow(2, e))) for e in [-1700, 1700] using the method from
-// https://fmt.dev/papers/Grisu-Exact.pdf#page=5, section 3.4.
-inline int floor_log10_pow2(int e) FMT_NOEXCEPT {
- FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent");
- const int shift = 22;
- return (e * static_cast<int>(log10_2_significand >> (64 - shift))) >> shift;
-}
-
-// Various fast log computations.
-inline int floor_log2_pow10(int e) FMT_NOEXCEPT {
- FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent");
- const uint64_t log2_10_integer_part = 3;
- const uint64_t log2_10_fractional_digits = 0x5269e12f346e2bf9;
- const int shift_amount = 19;
- return (e * static_cast<int>(
- (log2_10_integer_part << shift_amount) |
- (log2_10_fractional_digits >> (64 - shift_amount)))) >>
- shift_amount;
-}
-inline int floor_log10_pow2_minus_log10_4_over_3(int e) FMT_NOEXCEPT {
- FMT_ASSERT(e <= 1700 && e >= -1700, "too large exponent");
- const uint64_t log10_4_over_3_fractional_digits = 0x1ffbfc2bbc780375;
- const int shift_amount = 22;
- return (e * static_cast<int>(log10_2_significand >> (64 - shift_amount)) -
- static_cast<int>(log10_4_over_3_fractional_digits >>
- (64 - shift_amount))) >>
- shift_amount;
-}
-
-// Returns true iff x is divisible by pow(2, exp).
-inline bool divisible_by_power_of_2(uint32_t x, int exp) FMT_NOEXCEPT {
- FMT_ASSERT(exp >= 1, "");
- FMT_ASSERT(x != 0, "");
-#ifdef FMT_BUILTIN_CTZ
- return FMT_BUILTIN_CTZ(x) >= exp;
-#else
- return exp < num_bits<uint32_t>() && x == ((x >> exp) << exp);
-#endif
-}
-inline bool divisible_by_power_of_2(uint64_t x, int exp) FMT_NOEXCEPT {
- FMT_ASSERT(exp >= 1, "");
- FMT_ASSERT(x != 0, "");
-#ifdef FMT_BUILTIN_CTZLL
- return FMT_BUILTIN_CTZLL(x) >= exp;
-#else
- return exp < num_bits<uint64_t>() && x == ((x >> exp) << exp);
-#endif
-}
-
-// Table entry type for divisibility test.
-template <typename T> struct divtest_table_entry {
- T mod_inv;
- T max_quotient;
-};
-
-// Returns true iff x is divisible by pow(5, exp).
-inline bool divisible_by_power_of_5(uint32_t x, int exp) FMT_NOEXCEPT {
- FMT_ASSERT(exp <= 10, "too large exponent");
- static constexpr const divtest_table_entry<uint32_t> divtest_table[] = {
- {0x00000001, 0xffffffff}, {0xcccccccd, 0x33333333},
- {0xc28f5c29, 0x0a3d70a3}, {0x26e978d5, 0x020c49ba},
- {0x3afb7e91, 0x0068db8b}, {0x0bcbe61d, 0x0014f8b5},
- {0x68c26139, 0x000431bd}, {0xae8d46a5, 0x0000d6bf},
- {0x22e90e21, 0x00002af3}, {0x3a2e9c6d, 0x00000897},
- {0x3ed61f49, 0x000001b7}};
- return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient;
-}
-inline bool divisible_by_power_of_5(uint64_t x, int exp) FMT_NOEXCEPT {
- FMT_ASSERT(exp <= 23, "too large exponent");
- static constexpr const divtest_table_entry<uint64_t> divtest_table[] = {
- {0x0000000000000001, 0xffffffffffffffff},
- {0xcccccccccccccccd, 0x3333333333333333},
- {0x8f5c28f5c28f5c29, 0x0a3d70a3d70a3d70},
- {0x1cac083126e978d5, 0x020c49ba5e353f7c},
- {0xd288ce703afb7e91, 0x0068db8bac710cb2},
- {0x5d4e8fb00bcbe61d, 0x0014f8b588e368f0},
- {0x790fb65668c26139, 0x000431bde82d7b63},
- {0xe5032477ae8d46a5, 0x0000d6bf94d5e57a},
- {0xc767074b22e90e21, 0x00002af31dc46118},
- {0x8e47ce423a2e9c6d, 0x0000089705f4136b},
- {0x4fa7f60d3ed61f49, 0x000001b7cdfd9d7b},
- {0x0fee64690c913975, 0x00000057f5ff85e5},
- {0x3662e0e1cf503eb1, 0x000000119799812d},
- {0xa47a2cf9f6433fbd, 0x0000000384b84d09},
- {0x54186f653140a659, 0x00000000b424dc35},
- {0x7738164770402145, 0x0000000024075f3d},
- {0xe4a4d1417cd9a041, 0x000000000734aca5},
- {0xc75429d9e5c5200d, 0x000000000170ef54},
- {0xc1773b91fac10669, 0x000000000049c977},
- {0x26b172506559ce15, 0x00000000000ec1e4},
- {0xd489e3a9addec2d1, 0x000000000002f394},
- {0x90e860bb892c8d5d, 0x000000000000971d},
- {0x502e79bf1b6f4f79, 0x0000000000001e39},
- {0xdcd618596be30fe5, 0x000000000000060b}};
- return x * divtest_table[exp].mod_inv <= divtest_table[exp].max_quotient;
-}
-
-// Replaces n by floor(n / pow(5, N)) returning true if and only if n is
-// divisible by pow(5, N).
-// Precondition: n <= 2 * pow(5, N + 1).
-template <int N>
-bool check_divisibility_and_divide_by_pow5(uint32_t& n) FMT_NOEXCEPT {
- static constexpr struct {
- uint32_t magic_number;
- int bits_for_comparison;
- uint32_t threshold;
- int shift_amount;
- } infos[] = {{0xcccd, 16, 0x3333, 18}, {0xa429, 8, 0x0a, 20}};
- constexpr auto info = infos[N - 1];
- n *= info.magic_number;
- const uint32_t comparison_mask = (1u << info.bits_for_comparison) - 1;
- bool result = (n & comparison_mask) <= info.threshold;
- n >>= info.shift_amount;
- return result;
-}
-
-// Computes floor(n / pow(10, N)) for small n and N.
-// Precondition: n <= pow(10, N + 1).
-template <int N> uint32_t small_division_by_pow10(uint32_t n) FMT_NOEXCEPT {
- static constexpr struct {
- uint32_t magic_number;
- int shift_amount;
- uint32_t divisor_times_10;
- } infos[] = {{0xcccd, 19, 100}, {0xa3d8, 22, 1000}};
- constexpr auto info = infos[N - 1];
- FMT_ASSERT(n <= info.divisor_times_10, "n is too large");
- return n * info.magic_number >> info.shift_amount;
-}
-
-// Computes floor(n / 10^(kappa + 1)) (float)
-inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) FMT_NOEXCEPT {
- return n / float_info<float>::big_divisor;
-}
-// Computes floor(n / 10^(kappa + 1)) (double)
-inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) FMT_NOEXCEPT {
- return umul128_upper64(n, 0x83126e978d4fdf3c) >> 9;
-}
-
-// Various subroutines using pow10 cache
-template <class T> struct cache_accessor;
-
-template <> struct cache_accessor<float> {
- using carrier_uint = float_info<float>::carrier_uint;
- using cache_entry_type = uint64_t;
-
- static uint64_t get_cached_power(int k) FMT_NOEXCEPT {
- FMT_ASSERT(k >= float_info<float>::min_k && k <= float_info<float>::max_k,
- "k is out of range");
- static constexpr const uint64_t pow10_significands[] = {
- 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f,
- 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb,
- 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28,
- 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb,
- 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a,
- 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810,
- 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff,
- 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd,
- 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424,
- 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b,
- 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000,
- 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000,
- 0xc350000000000000, 0xf424000000000000, 0x9896800000000000,
- 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000,
- 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000,
- 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000,
- 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000,
- 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000,
- 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0,
- 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940984,
- 0xa18f07d736b90be5, 0xc9f2c9cd04674ede, 0xfc6f7c4045812296,
- 0x9dc5ada82b70b59d, 0xc5371912364ce305, 0xf684df56c3e01bc6,
- 0x9a130b963a6c115c, 0xc097ce7bc90715b3, 0xf0bdc21abb48db20,
- 0x96769950b50d88f4, 0xbc143fa4e250eb31, 0xeb194f8e1ae525fd,
- 0x92efd1b8d0cf37be, 0xb7abc627050305ad, 0xe596b7b0c643c719,
- 0x8f7e32ce7bea5c6f, 0xb35dbf821ae4f38b, 0xe0352f62a19e306e};
- return pow10_significands[k - float_info<float>::min_k];
- }
-
- static carrier_uint compute_mul(carrier_uint u,
- const cache_entry_type& cache) FMT_NOEXCEPT {
- return umul96_upper32(u, cache);
- }
-
- static uint32_t compute_delta(const cache_entry_type& cache,
- int beta_minus_1) FMT_NOEXCEPT {
- return static_cast<uint32_t>(cache >> (64 - 1 - beta_minus_1));
- }
-
- static bool compute_mul_parity(carrier_uint two_f,
- const cache_entry_type& cache,
- int beta_minus_1) FMT_NOEXCEPT {
- FMT_ASSERT(beta_minus_1 >= 1, "");
- FMT_ASSERT(beta_minus_1 < 64, "");
-
- return ((umul96_lower64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0;
- }
-
- static carrier_uint compute_left_endpoint_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return static_cast<carrier_uint>(
- (cache - (cache >> (float_info<float>::significand_bits + 2))) >>
- (64 - float_info<float>::significand_bits - 1 - beta_minus_1));
- }
-
- static carrier_uint compute_right_endpoint_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return static_cast<carrier_uint>(
- (cache + (cache >> (float_info<float>::significand_bits + 1))) >>
- (64 - float_info<float>::significand_bits - 1 - beta_minus_1));
- }
-
- static carrier_uint compute_round_up_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return (static_cast<carrier_uint>(
- cache >>
- (64 - float_info<float>::significand_bits - 2 - beta_minus_1)) +
- 1) /
- 2;
- }
-};
-
-template <> struct cache_accessor<double> {
- using carrier_uint = float_info<double>::carrier_uint;
- using cache_entry_type = uint128_wrapper;
-
- static uint128_wrapper get_cached_power(int k) FMT_NOEXCEPT {
- FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k,
- "k is out of range");
-
- static constexpr const uint128_wrapper pow10_significands[] = {
-#if FMT_USE_FULL_CACHE_DRAGONBOX
- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
- {0x9faacf3df73609b1, 0x77b191618c54e9ad},
- {0xc795830d75038c1d, 0xd59df5b9ef6a2418},
- {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e},
- {0x9becce62836ac577, 0x4ee367f9430aec33},
- {0xc2e801fb244576d5, 0x229c41f793cda740},
- {0xf3a20279ed56d48a, 0x6b43527578c11110},
- {0x9845418c345644d6, 0x830a13896b78aaaa},
- {0xbe5691ef416bd60c, 0x23cc986bc656d554},
- {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9},
- {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa},
- {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54},
- {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69},
- {0x91376c36d99995be, 0x23100809b9c21fa2},
- {0xb58547448ffffb2d, 0xabd40a0c2832a78b},
- {0xe2e69915b3fff9f9, 0x16c90c8f323f516d},
- {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4},
- {0xb1442798f49ffb4a, 0x99cd11cfdf41779d},
- {0xdd95317f31c7fa1d, 0x40405643d711d584},
- {0x8a7d3eef7f1cfc52, 0x482835ea666b2573},
- {0xad1c8eab5ee43b66, 0xda3243650005eed0},
- {0xd863b256369d4a40, 0x90bed43e40076a83},
- {0x873e4f75e2224e68, 0x5a7744a6e804a292},
- {0xa90de3535aaae202, 0x711515d0a205cb37},
- {0xd3515c2831559a83, 0x0d5a5b44ca873e04},
- {0x8412d9991ed58091, 0xe858790afe9486c3},
- {0xa5178fff668ae0b6, 0x626e974dbe39a873},
- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
- {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a},
- {0xa139029f6a239f72, 0x1c1fffc1ebc44e81},
- {0xc987434744ac874e, 0xa327ffb266b56221},
- {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9},
- {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa},
- {0xc4ce17b399107c22, 0xcb550fb4384d21d4},
- {0xf6019da07f549b2b, 0x7e2a53a146606a49},
- {0x99c102844f94e0fb, 0x2eda7444cbfc426e},
- {0xc0314325637a1939, 0xfa911155fefb5309},
- {0xf03d93eebc589f88, 0x793555ab7eba27cb},
- {0x96267c7535b763b5, 0x4bc1558b2f3458df},
- {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17},
- {0xea9c227723ee8bcb, 0x465e15a979c1cadd},
- {0x92a1958a7675175f, 0x0bfacd89ec191eca},
- {0xb749faed14125d36, 0xcef980ec671f667c},
- {0xe51c79a85916f484, 0x82b7e12780e7401b},
- {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811},
- {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16},
- {0xdfbdcece67006ac9, 0x67a791e093e1d49b},
- {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1},
- {0xaecc49914078536d, 0x58fae9f773886e19},
- {0xda7f5bf590966848, 0xaf39a475506a899f},
- {0x888f99797a5e012d, 0x6d8406c952429604},
- {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84},
- {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65},
- {0x855c3be0a17fcd26, 0x5cf2eea09a550680},
- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f},
- {0xd0601d8efc57b08b, 0xf13b94daf124da27},
- {0x823c12795db6ce57, 0x76c53d08d6b70859},
- {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f},
- {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a},
- {0xfe5d54150b090b02, 0xd3f93b35435d7c4d},
- {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0},
- {0xc6b8e9b0709f109a, 0x359ab6419ca1091c},
- {0xf867241c8cc6d4c0, 0xc30163d203c94b63},
- {0x9b407691d7fc44f8, 0x79e0de63425dcf1e},
- {0xc21094364dfb5636, 0x985915fc12f542e5},
- {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e},
- {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43},
- {0xbd8430bd08277231, 0x50c6ff782a838354},
- {0xece53cec4a314ebd, 0xa4f8bf5635246429},
- {0x940f4613ae5ed136, 0x871b7795e136be9a},
- {0xb913179899f68584, 0x28e2557b59846e40},
- {0xe757dd7ec07426e5, 0x331aeada2fe589d0},
- {0x9096ea6f3848984f, 0x3ff0d2c85def7622},
- {0xb4bca50b065abe63, 0x0fed077a756b53aa},
- {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895},
- {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d},
- {0xb080392cc4349dec, 0xbd8d794d96aacfb4},
- {0xdca04777f541c567, 0xecf0d7a0fc5583a1},
- {0x89e42caaf9491b60, 0xf41686c49db57245},
- {0xac5d37d5b79b6239, 0x311c2875c522ced6},
- {0xd77485cb25823ac7, 0x7d633293366b828c},
- {0x86a8d39ef77164bc, 0xae5dff9c02033198},
- {0xa8530886b54dbdeb, 0xd9f57f830283fdfd},
- {0xd267caa862a12d66, 0xd072df63c324fd7c},
- {0x8380dea93da4bc60, 0x4247cb9e59f71e6e},
- {0xa46116538d0deb78, 0x52d9be85f074e609},
- {0xcd795be870516656, 0x67902e276c921f8c},
- {0x806bd9714632dff6, 0x00ba1cd8a3db53b7},
- {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5},
- {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce},
- {0xfad2a4b13d1b5d6c, 0x796b805720085f82},
- {0x9cc3a6eec6311a63, 0xcbe3303674053bb1},
- {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d},
- {0xf4f1b4d515acb93b, 0xee92fb5515482d45},
- {0x991711052d8bf3c5, 0x751bdd152d4d1c4b},
- {0xbf5cd54678eef0b6, 0xd262d45a78a0635e},
- {0xef340a98172aace4, 0x86fb897116c87c35},
- {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1},
- {0xbae0a846d2195712, 0x8974836059cca10a},
- {0xe998d258869facd7, 0x2bd1a438703fc94c},
- {0x91ff83775423cc06, 0x7b6306a34627ddd0},
- {0xb67f6455292cbf08, 0x1a3bc84c17b1d543},
- {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94},
- {0x8e938662882af53e, 0x547eb47b7282ee9d},
- {0xb23867fb2a35b28d, 0xe99e619a4f23aa44},
- {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5},
- {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05},
- {0xae0b158b4738705e, 0x9624ab50b148d446},
- {0xd98ddaee19068c76, 0x3badd624dd9b0958},
- {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7},
- {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d},
- {0xd47487cc8470652b, 0x7647c32000696720},
- {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074},
- {0xa5fb0a17c777cf09, 0xf468107100525891},
- {0xcf79cc9db955c2cc, 0x7182148d4066eeb5},
- {0x81ac1fe293d599bf, 0xc6f14cd848405531},
- {0xa21727db38cb002f, 0xb8ada00e5a506a7d},
- {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d},
- {0xfd442e4688bd304a, 0x908f4a166d1da664},
- {0x9e4a9cec15763e2e, 0x9a598e4e043287ff},
- {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe},
- {0xf7549530e188c128, 0xd12bee59e68ef47d},
- {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf},
- {0xc13a148e3032d6e7, 0xe36a52363c1faf02},
- {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2},
- {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba},
- {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8},
- {0xebdf661791d60f56, 0x111b495b3464ad22},
- {0x936b9fcebb25c995, 0xcab10dd900beec35},
- {0xb84687c269ef3bfb, 0x3d5d514f40eea743},
- {0xe65829b3046b0afa, 0x0cb4a5a3112a5113},
- {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac},
- {0xb3f4e093db73a093, 0x59ed216765690f57},
- {0xe0f218b8d25088b8, 0x306869c13ec3532d},
- {0x8c974f7383725573, 0x1e414218c73a13fc},
- {0xafbd2350644eeacf, 0xe5d1929ef90898fb},
- {0xdbac6c247d62a583, 0xdf45f746b74abf3a},
- {0x894bc396ce5da772, 0x6b8bba8c328eb784},
- {0xab9eb47c81f5114f, 0x066ea92f3f326565},
- {0xd686619ba27255a2, 0xc80a537b0efefebe},
- {0x8613fd0145877585, 0xbd06742ce95f5f37},
- {0xa798fc4196e952e7, 0x2c48113823b73705},
- {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6},
- {0x82ef85133de648c4, 0x9a984d73dbe722fc},
- {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb},
- {0xcc963fee10b7d1b3, 0x318df905079926a9},
- {0xffbbcfe994e5c61f, 0xfdf17746497f7053},
- {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634},
- {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1},
- {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1},
- {0x9c1661a651213e2d, 0x06bea10ca65c084f},
- {0xc31bfa0fe5698db8, 0x486e494fcff30a63},
- {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb},
- {0x986ddb5c6b3a76b7, 0xf89629465a75e01d},
- {0xbe89523386091465, 0xf6bbb397f1135824},
- {0xee2ba6c0678b597f, 0x746aa07ded582e2d},
- {0x94db483840b717ef, 0xa8c2a44eb4571cdd},
- {0xba121a4650e4ddeb, 0x92f34d62616ce414},
- {0xe896a0d7e51e1566, 0x77b020baf9c81d18},
- {0x915e2486ef32cd60, 0x0ace1474dc1d122f},
- {0xb5b5ada8aaff80b8, 0x0d819992132456bb},
- {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a},
- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2},
- {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3},
- {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf},
- {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c},
- {0xad4ab7112eb3929d, 0x86c16c98d2c953c7},
- {0xd89d64d57a607744, 0xe871c7bf077ba8b8},
- {0x87625f056c7c4a8b, 0x11471cd764ad4973},
- {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0},
- {0xd389b47879823479, 0x4aff1d108d4ec2c4},
- {0x843610cb4bf160cb, 0xcedf722a585139bb},
- {0xa54394fe1eedb8fe, 0xc2974eb4ee658829},
- {0xce947a3da6a9273e, 0x733d226229feea33},
- {0x811ccc668829b887, 0x0806357d5a3f5260},
- {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8},
- {0xc9bcff6034c13052, 0xfc89b393dd02f0b6},
- {0xfc2c3f3841f17c67, 0xbbac2078d443ace3},
- {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e},
- {0xc5029163f384a931, 0x0a9e795e65d4df12},
- {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6},
- {0x99ea0196163fa42e, 0x504bced1bf8e4e46},
- {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7},
- {0xf07da27a82c37088, 0x5d767327bb4e5a4d},
- {0x964e858c91ba2655, 0x3a6a07f8d510f870},
- {0xbbe226efb628afea, 0x890489f70a55368c},
- {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f},
- {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e},
- {0xb77ada0617e3bbcb, 0x09ce6ebb40173745},
- {0xe55990879ddcaabd, 0xcc420a6a101d0516},
- {0x8f57fa54c2a9eab6, 0x9fa946824a12232e},
- {0xb32df8e9f3546564, 0x47939822dc96abfa},
- {0xdff9772470297ebd, 0x59787e2b93bc56f8},
- {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b},
- {0xaefae51477a06b03, 0xede622920b6b23f2},
- {0xdab99e59958885c4, 0xe95fab368e45ecee},
- {0x88b402f7fd75539b, 0x11dbcb0218ebb415},
- {0xaae103b5fcd2a881, 0xd652bdc29f26a11a},
- {0xd59944a37c0752a2, 0x4be76d3346f04960},
- {0x857fcae62d8493a5, 0x6f70a4400c562ddc},
- {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953},
- {0xd097ad07a71f26b2, 0x7e2000a41346a7a8},
- {0x825ecc24c873782f, 0x8ed400668c0c28c9},
- {0xa2f67f2dfa90563b, 0x728900802f0f32fb},
- {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba},
- {0xfea126b7d78186bc, 0xe2f610c84987bfa9},
- {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca},
- {0xc6ede63fa05d3143, 0x91503d1c79720dbc},
- {0xf8a95fcf88747d94, 0x75a44c6397ce912b},
- {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb},
- {0xc24452da229b021b, 0xfbe85badce996169},
- {0xf2d56790ab41c2a2, 0xfae27299423fb9c4},
- {0x97c560ba6b0919a5, 0xdccd879fc967d41b},
- {0xbdb6b8e905cb600f, 0x5400e987bbc1c921},
- {0xed246723473e3813, 0x290123e9aab23b69},
- {0x9436c0760c86e30b, 0xf9a0b6720aaf6522},
- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a},
- {0xe7958cb87392c2c2, 0xb60b1d1230b20e05},
- {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3},
- {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4},
- {0xe2280b6c20dd5232, 0x25c6da63c38de1b1},
- {0x8d590723948a535f, 0x579c487e5a38ad0f},
- {0xb0af48ec79ace837, 0x2d835a9df0c6d852},
- {0xdcdb1b2798182244, 0xf8e431456cf88e66},
- {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900},
- {0xac8b2d36eed2dac5, 0xe272467e3d222f40},
- {0xd7adf884aa879177, 0x5b0ed81dcc6abb10},
- {0x86ccbb52ea94baea, 0x98e947129fc2b4ea},
- {0xa87fea27a539e9a5, 0x3f2398d747b36225},
- {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae},
- {0x83a3eeeef9153e89, 0x1953cf68300424ad},
- {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8},
- {0xcdb02555653131b6, 0x3792f412cb06794e},
- {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1},
- {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5},
- {0xc8de047564d20a8b, 0xf245825a5a445276},
- {0xfb158592be068d2e, 0xeed6e2f0f0d56713},
- {0x9ced737bb6c4183d, 0x55464dd69685606c},
- {0xc428d05aa4751e4c, 0xaa97e14c3c26b887},
- {0xf53304714d9265df, 0xd53dd99f4b3066a9},
- {0x993fe2c6d07b7fab, 0xe546a8038efe402a},
- {0xbf8fdb78849a5f96, 0xde98520472bdd034},
- {0xef73d256a5c0f77c, 0x963e66858f6d4441},
- {0x95a8637627989aad, 0xdde7001379a44aa9},
- {0xbb127c53b17ec159, 0x5560c018580d5d53},
- {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7},
- {0x9226712162ab070d, 0xcab3961304ca70e9},
- {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23},
- {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b},
- {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243},
- {0xb267ed1940f1c61c, 0x55f038b237591ed4},
- {0xdf01e85f912e37a3, 0x6b6c46dec52f6689},
- {0x8b61313bbabce2c6, 0x2323ac4b3b3da016},
- {0xae397d8aa96c1b77, 0xabec975e0a0d081b},
- {0xd9c7dced53c72255, 0x96e7bd358c904a22},
- {0x881cea14545c7575, 0x7e50d64177da2e55},
- {0xaa242499697392d2, 0xdde50bd1d5d0b9ea},
- {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865},
- {0x84ec3c97da624ab4, 0xbd5af13bef0b113f},
- {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f},
- {0xcfb11ead453994ba, 0x67de18eda5814af3},
- {0x81ceb32c4b43fcf4, 0x80eacf948770ced8},
- {0xa2425ff75e14fc31, 0xa1258379a94d028e},
- {0xcad2f7f5359a3b3e, 0x096ee45813a04331},
- {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd},
- {0x9e74d1b791e07e48, 0x775ea264cf55347e},
- {0xc612062576589dda, 0x95364afe032a819e},
- {0xf79687aed3eec551, 0x3a83ddbd83f52205},
- {0x9abe14cd44753b52, 0xc4926a9672793543},
- {0xc16d9a0095928a27, 0x75b7053c0f178294},
- {0xf1c90080baf72cb1, 0x5324c68b12dd6339},
- {0x971da05074da7bee, 0xd3f6fc16ebca5e04},
- {0xbce5086492111aea, 0x88f4bb1ca6bcf585},
- {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6},
- {0x9392ee8e921d5d07, 0x3aff322e62439fd0},
- {0xb877aa3236a4b449, 0x09befeb9fad487c3},
- {0xe69594bec44de15b, 0x4c2ebe687989a9b4},
- {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11},
- {0xb424dc35095cd80f, 0x538484c19ef38c95},
- {0xe12e13424bb40e13, 0x2865a5f206b06fba},
- {0x8cbccc096f5088cb, 0xf93f87b7442e45d4},
- {0xafebff0bcb24aafe, 0xf78f69a51539d749},
- {0xdbe6fecebdedd5be, 0xb573440e5a884d1c},
- {0x89705f4136b4a597, 0x31680a88f8953031},
- {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e},
- {0xd6bf94d5e57a42bc, 0x3d32907604691b4d},
- {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110},
- {0xa7c5ac471b478423, 0x0fcf80dc33721d54},
- {0xd1b71758e219652b, 0xd3c36113404ea4a9},
- {0x83126e978d4fdf3b, 0x645a1cac083126ea},
- {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4},
- {0xcccccccccccccccc, 0xcccccccccccccccd},
- {0x8000000000000000, 0x0000000000000000},
- {0xa000000000000000, 0x0000000000000000},
- {0xc800000000000000, 0x0000000000000000},
- {0xfa00000000000000, 0x0000000000000000},
- {0x9c40000000000000, 0x0000000000000000},
- {0xc350000000000000, 0x0000000000000000},
- {0xf424000000000000, 0x0000000000000000},
- {0x9896800000000000, 0x0000000000000000},
- {0xbebc200000000000, 0x0000000000000000},
- {0xee6b280000000000, 0x0000000000000000},
- {0x9502f90000000000, 0x0000000000000000},
- {0xba43b74000000000, 0x0000000000000000},
- {0xe8d4a51000000000, 0x0000000000000000},
- {0x9184e72a00000000, 0x0000000000000000},
- {0xb5e620f480000000, 0x0000000000000000},
- {0xe35fa931a0000000, 0x0000000000000000},
- {0x8e1bc9bf04000000, 0x0000000000000000},
- {0xb1a2bc2ec5000000, 0x0000000000000000},
- {0xde0b6b3a76400000, 0x0000000000000000},
- {0x8ac7230489e80000, 0x0000000000000000},
- {0xad78ebc5ac620000, 0x0000000000000000},
- {0xd8d726b7177a8000, 0x0000000000000000},
- {0x878678326eac9000, 0x0000000000000000},
- {0xa968163f0a57b400, 0x0000000000000000},
- {0xd3c21bcecceda100, 0x0000000000000000},
- {0x84595161401484a0, 0x0000000000000000},
- {0xa56fa5b99019a5c8, 0x0000000000000000},
- {0xcecb8f27f4200f3a, 0x0000000000000000},
- {0x813f3978f8940984, 0x4000000000000000},
- {0xa18f07d736b90be5, 0x5000000000000000},
- {0xc9f2c9cd04674ede, 0xa400000000000000},
- {0xfc6f7c4045812296, 0x4d00000000000000},
- {0x9dc5ada82b70b59d, 0xf020000000000000},
- {0xc5371912364ce305, 0x6c28000000000000},
- {0xf684df56c3e01bc6, 0xc732000000000000},
- {0x9a130b963a6c115c, 0x3c7f400000000000},
- {0xc097ce7bc90715b3, 0x4b9f100000000000},
- {0xf0bdc21abb48db20, 0x1e86d40000000000},
- {0x96769950b50d88f4, 0x1314448000000000},
- {0xbc143fa4e250eb31, 0x17d955a000000000},
- {0xeb194f8e1ae525fd, 0x5dcfab0800000000},
- {0x92efd1b8d0cf37be, 0x5aa1cae500000000},
- {0xb7abc627050305ad, 0xf14a3d9e40000000},
- {0xe596b7b0c643c719, 0x6d9ccd05d0000000},
- {0x8f7e32ce7bea5c6f, 0xe4820023a2000000},
- {0xb35dbf821ae4f38b, 0xdda2802c8a800000},
- {0xe0352f62a19e306e, 0xd50b2037ad200000},
- {0x8c213d9da502de45, 0x4526f422cc340000},
- {0xaf298d050e4395d6, 0x9670b12b7f410000},
- {0xdaf3f04651d47b4c, 0x3c0cdd765f114000},
- {0x88d8762bf324cd0f, 0xa5880a69fb6ac800},
- {0xab0e93b6efee0053, 0x8eea0d047a457a00},
- {0xd5d238a4abe98068, 0x72a4904598d6d880},
- {0x85a36366eb71f041, 0x47a6da2b7f864750},
- {0xa70c3c40a64e6c51, 0x999090b65f67d924},
- {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d},
- {0x82818f1281ed449f, 0xbff8f10e7a8921a4},
- {0xa321f2d7226895c7, 0xaff72d52192b6a0d},
- {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490},
- {0xfee50b7025c36a08, 0x02f236d04753d5b4},
- {0x9f4f2726179a2245, 0x01d762422c946590},
- {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5},
- {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2},
- {0x9b934c3b330c8577, 0x63cc55f49f88eb2f},
- {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb},
- {0xf316271c7fc3908a, 0x8bef464e3945ef7a},
- {0x97edd871cfda3a56, 0x97758bf0e3cbb5ac},
- {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317},
- {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd},
- {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a},
- {0xb975d6b6ee39e436, 0xb3e2fd538e122b44},
- {0xe7d34c64a9c85d44, 0x60dbbca87196b616},
- {0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd},
- {0xb51d13aea4a488dd, 0x6babab6398bdbe41},
- {0xe264589a4dcdab14, 0xc696963c7eed2dd1},
- {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2},
- {0xb0de65388cc8ada8, 0x3b25a55f43294bcb},
- {0xdd15fe86affad912, 0x49ef0eb713f39ebe},
- {0x8a2dbf142dfcc7ab, 0x6e3569326c784337},
- {0xacb92ed9397bf996, 0x49c2c37f07965404},
- {0xd7e77a8f87daf7fb, 0xdc33745ec97be906},
- {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3},
- {0xa8acd7c0222311bc, 0xc40832ea0d68ce0c},
- {0xd2d80db02aabd62b, 0xf50a3fa490c30190},
- {0x83c7088e1aab65db, 0x792667c6da79e0fa},
- {0xa4b8cab1a1563f52, 0x577001b891185938},
- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86},
- {0x80b05e5ac60b6178, 0x544f8158315b05b4},
- {0xa0dc75f1778e39d6, 0x696361ae3db1c721},
- {0xc913936dd571c84c, 0x03bc3a19cd1e38e9},
- {0xfb5878494ace3a5f, 0x04ab48a04065c723},
- {0x9d174b2dcec0e47b, 0x62eb0d64283f9c76},
- {0xc45d1df942711d9a, 0x3ba5d0bd324f8394},
- {0xf5746577930d6500, 0xca8f44ec7ee36479},
- {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb},
- {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e},
- {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e},
- {0x95d04aee3b80ece5, 0xbba1f1d158724a12},
- {0xbb445da9ca61281f, 0x2a8a6e45ae8edc97},
- {0xea1575143cf97226, 0xf52d09d71a3293bd},
- {0x924d692ca61be758, 0x593c2626705f9c56},
- {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c},
- {0xe498f455c38b997a, 0x0b6dfb9c0f956447},
- {0x8edf98b59a373fec, 0x4724bd4189bd5eac},
- {0xb2977ee300c50fe7, 0x58edec91ec2cb657},
- {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed},
- {0x8b865b215899f46c, 0xbd79e0d20082ee74},
- {0xae67f1e9aec07187, 0xecd8590680a3aa11},
- {0xda01ee641a708de9, 0xe80e6f4820cc9495},
- {0x884134fe908658b2, 0x3109058d147fdcdd},
- {0xaa51823e34a7eede, 0xbd4b46f0599fd415},
- {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a},
- {0x850fadc09923329e, 0x03e2cf6bc604ddb0},
- {0xa6539930bf6bff45, 0x84db8346b786151c},
- {0xcfe87f7cef46ff16, 0xe612641865679a63},
- {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e},
- {0xa26da3999aef7749, 0xe3be5e330f38f09d},
- {0xcb090c8001ab551c, 0x5cadf5bfd3072cc5},
- {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6},
- {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa},
- {0xc646d63501a1511d, 0xb281e1fd541501b8},
- {0xf7d88bc24209a565, 0x1f225a7ca91a4226},
- {0x9ae757596946075f, 0x3375788de9b06958},
- {0xc1a12d2fc3978937, 0x0052d6b1641c83ae},
- {0xf209787bb47d6b84, 0xc0678c5dbd23a49a},
- {0x9745eb4d50ce6332, 0xf840b7ba963646e0},
- {0xbd176620a501fbff, 0xb650e5a93bc3d898},
- {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe},
- {0x93ba47c980e98cdf, 0xc66f336c36b10137},
- {0xb8a8d9bbe123f017, 0xb80b0047445d4184},
- {0xe6d3102ad96cec1d, 0xa60dc059157491e5},
- {0x9043ea1ac7e41392, 0x87c89837ad68db2f},
- {0xb454e4a179dd1877, 0x29babe4598c311fb},
- {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a},
- {0x8ce2529e2734bb1d, 0x1899e4a65f58660c},
- {0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f},
- {0xdc21a1171d42645d, 0x76707543f4fa1f73},
- {0x899504ae72497eba, 0x6a06494a791c53a8},
- {0xabfa45da0edbde69, 0x0487db9d17636892},
- {0xd6f8d7509292d603, 0x45a9d2845d3c42b6},
- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2},
- {0xa7f26836f282b732, 0x8e6cac7768d7141e},
- {0xd1ef0244af2364ff, 0x3207d795430cd926},
- {0x8335616aed761f1f, 0x7f44e6bd49e807b8},
- {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6},
- {0xcd036837130890a1, 0x36dba887c37a8c0f},
- {0x802221226be55a64, 0xc2494954da2c9789},
- {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c},
- {0xc83553c5c8965d3d, 0x6f92829494e5acc7},
- {0xfa42a8b73abbf48c, 0xcb772339ba1f17f9},
- {0x9c69a97284b578d7, 0xff2a760414536efb},
- {0xc38413cf25e2d70d, 0xfef5138519684aba},
- {0xf46518c2ef5b8cd1, 0x7eb258665fc25d69},
- {0x98bf2f79d5993802, 0xef2f773ffbd97a61},
- {0xbeeefb584aff8603, 0xaafb550ffacfd8fa},
- {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38},
- {0x952ab45cfa97a0b2, 0xdd945a747bf26183},
- {0xba756174393d88df, 0x94f971119aeef9e4},
- {0xe912b9d1478ceb17, 0x7a37cd5601aab85d},
- {0x91abb422ccb812ee, 0xac62e055c10ab33a},
- {0xb616a12b7fe617aa, 0x577b986b314d6009},
- {0xe39c49765fdf9d94, 0xed5a7e85fda0b80b},
- {0x8e41ade9fbebc27d, 0x14588f13be847307},
- {0xb1d219647ae6b31c, 0x596eb2d8ae258fc8},
- {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb},
- {0x8aec23d680043bee, 0x25de7bb9480d5854},
- {0xada72ccc20054ae9, 0xaf561aa79a10ae6a},
- {0xd910f7ff28069da4, 0x1b2ba1518094da04},
- {0x87aa9aff79042286, 0x90fb44d2f05d0842},
- {0xa99541bf57452b28, 0x353a1607ac744a53},
- {0xd3fa922f2d1675f2, 0x42889b8997915ce8},
- {0x847c9b5d7c2e09b7, 0x69956135febada11},
- {0xa59bc234db398c25, 0x43fab9837e699095},
- {0xcf02b2c21207ef2e, 0x94f967e45e03f4bb},
- {0x8161afb94b44f57d, 0x1d1be0eebac278f5},
- {0xa1ba1ba79e1632dc, 0x6462d92a69731732},
- {0xca28a291859bbf93, 0x7d7b8f7503cfdcfe},
- {0xfcb2cb35e702af78, 0x5cda735244c3d43e},
- {0x9defbf01b061adab, 0x3a0888136afa64a7},
- {0xc56baec21c7a1916, 0x088aaa1845b8fdd0},
- {0xf6c69a72a3989f5b, 0x8aad549e57273d45},
- {0x9a3c2087a63f6399, 0x36ac54e2f678864b},
- {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd},
- {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5},
- {0x969eb7c47859e743, 0x9f644ae5a4b1b325},
- {0xbc4665b596706114, 0x873d5d9f0dde1fee},
- {0xeb57ff22fc0c7959, 0xa90cb506d155a7ea},
- {0x9316ff75dd87cbd8, 0x09a7f12442d588f2},
- {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb2f},
- {0xe5d3ef282a242e81, 0x8f1668c8a86da5fa},
- {0x8fa475791a569d10, 0xf96e017d694487bc},
- {0xb38d92d760ec4455, 0x37c981dcc395a9ac},
- {0xe070f78d3927556a, 0x85bbe253f47b1417},
- {0x8c469ab843b89562, 0x93956d7478ccec8e},
- {0xaf58416654a6babb, 0x387ac8d1970027b2},
- {0xdb2e51bfe9d0696a, 0x06997b05fcc0319e},
- {0x88fcf317f22241e2, 0x441fece3bdf81f03},
- {0xab3c2fddeeaad25a, 0xd527e81cad7626c3},
- {0xd60b3bd56a5586f1, 0x8a71e223d8d3b074},
- {0x85c7056562757456, 0xf6872d5667844e49},
- {0xa738c6bebb12d16c, 0xb428f8ac016561db},
- {0xd106f86e69d785c7, 0xe13336d701beba52},
- {0x82a45b450226b39c, 0xecc0024661173473},
- {0xa34d721642b06084, 0x27f002d7f95d0190},
- {0xcc20ce9bd35c78a5, 0x31ec038df7b441f4},
- {0xff290242c83396ce, 0x7e67047175a15271},
- {0x9f79a169bd203e41, 0x0f0062c6e984d386},
- {0xc75809c42c684dd1, 0x52c07b78a3e60868},
- {0xf92e0c3537826145, 0xa7709a56ccdf8a82},
- {0x9bbcc7a142b17ccb, 0x88a66076400bb691},
- {0xc2abf989935ddbfe, 0x6acff893d00ea435},
- {0xf356f7ebf83552fe, 0x0583f6b8c4124d43},
- {0x98165af37b2153de, 0xc3727a337a8b704a},
- {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c},
- {0xeda2ee1c7064130c, 0x1162def06f79df73},
- {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8},
- {0xb9a74a0637ce2ee1, 0x6d953e2bd7173692},
- {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437},
- {0x910ab1d4db9914a0, 0x1d9c9892400a22a2},
- {0xb54d5e4a127f59c8, 0x2503beb6d00cab4b},
- {0xe2a0b5dc971f303a, 0x2e44ae64840fd61d},
- {0x8da471a9de737e24, 0x5ceaecfed289e5d2},
- {0xb10d8e1456105dad, 0x7425a83e872c5f47},
- {0xdd50f1996b947518, 0xd12f124e28f77719},
- {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f},
- {0xace73cbfdc0bfb7b, 0x636cc64d1001550b},
- {0xd8210befd30efa5a, 0x3c47f7e05401aa4e},
- {0x8714a775e3e95c78, 0x65acfaec34810a71},
- {0xa8d9d1535ce3b396, 0x7f1839a741a14d0d},
- {0xd31045a8341ca07c, 0x1ede48111209a050},
- {0x83ea2b892091e44d, 0x934aed0aab460432},
- {0xa4e4b66b68b65d60, 0xf81da84d5617853f},
- {0xce1de40642e3f4b9, 0x36251260ab9d668e},
- {0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019},
- {0xa1075a24e4421730, 0xb24cf65b8612f81f},
- {0xc94930ae1d529cfc, 0xdee033f26797b627},
- {0xfb9b7cd9a4a7443c, 0x169840ef017da3b1},
- {0x9d412e0806e88aa5, 0x8e1f289560ee864e},
- {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2},
- {0xf5b5d7ec8acb58a2, 0xae10af696774b1db},
- {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29},
- {0xbff610b0cc6edd3f, 0x17fd090a58d32af3},
- {0xeff394dcff8a948e, 0xddfc4b4cef07f5b0},
- {0x95f83d0a1fb69cd9, 0x4abdaf101564f98e},
- {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1},
- {0xea53df5fd18d5513, 0x84c86189216dc5ed},
- {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4},
- {0xb7118682dbb66a77, 0x3fbc8c33221dc2a1},
- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a},
- {0x8f05b1163ba6832d, 0x29cb4d87f2a7400e},
- {0xb2c71d5bca9023f8, 0x743e20e9ef511012},
- {0xdf78e4b2bd342cf6, 0x914da9246b255416},
- {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e},
- {0xae9672aba3d0c320, 0xa184ac2473b529b1},
- {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e},
- {0x8865899617fb1871, 0x7e2fa67c7a658892},
- {0xaa7eebfb9df9de8d, 0xddbb901b98feeab7},
- {0xd51ea6fa85785631, 0x552a74227f3ea565},
- {0x8533285c936b35de, 0xd53a88958f87275f},
- {0xa67ff273b8460356, 0x8a892abaf368f137},
- {0xd01fef10a657842c, 0x2d2b7569b0432d85},
- {0x8213f56a67f6b29b, 0x9c3b29620e29fc73},
- {0xa298f2c501f45f42, 0x8349f3ba91b47b8f},
- {0xcb3f2f7642717713, 0x241c70a936219a73},
- {0xfe0efb53d30dd4d7, 0xed238cd383aa0110},
- {0x9ec95d1463e8a506, 0xf4363804324a40aa},
- {0xc67bb4597ce2ce48, 0xb143c6053edcd0d5},
- {0xf81aa16fdc1b81da, 0xdd94b7868e94050a},
- {0x9b10a4e5e9913128, 0xca7cf2b4191c8326},
- {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0},
- {0xf24a01a73cf2dccf, 0xbc633b39673c8cec},
- {0x976e41088617ca01, 0xd5be0503e085d813},
- {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18},
- {0xec9c459d51852ba2, 0xddf8e7d60ed1219e},
- {0x93e1ab8252f33b45, 0xcabb90e5c942b503},
- {0xb8da1662e7b00a17, 0x3d6a751f3b936243},
- {0xe7109bfba19c0c9d, 0x0cc512670a783ad4},
- {0x906a617d450187e2, 0x27fb2b80668b24c5},
- {0xb484f9dc9641e9da, 0xb1f9f660802dedf6},
- {0xe1a63853bbd26451, 0x5e7873f8a0396973},
- {0x8d07e33455637eb2, 0xdb0b487b6423e1e8},
- {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62},
- {0xdc5c5301c56b75f7, 0x7641a140cc7810fb},
- {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d},
- {0xac2820d9623bf429, 0x546345fa9fbdcd44},
- {0xd732290fbacaf133, 0xa97c177947ad4095},
- {0x867f59a9d4bed6c0, 0x49ed8eabcccc485d},
- {0xa81f301449ee8c70, 0x5c68f256bfff5a74},
- {0xd226fc195c6a2f8c, 0x73832eec6fff3111},
- {0x83585d8fd9c25db7, 0xc831fd53c5ff7eab},
- {0xa42e74f3d032f525, 0xba3e7ca8b77f5e55},
- {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb},
- {0x80444b5e7aa7cf85, 0x7980d163cf5b81b3},
- {0xa0555e361951c366, 0xd7e105bcc332621f},
- {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7},
- {0xfa856334878fc150, 0xb14f98f6f0feb951},
- {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3},
- {0xc3b8358109e84f07, 0x0a862f80ec4700c8},
- {0xf4a642e14c6262c8, 0xcd27bb612758c0fa},
- {0x98e7e9cccfbd7dbd, 0x8038d51cb897789c},
- {0xbf21e44003acdd2c, 0xe0470a63e6bd56c3},
- {0xeeea5d5004981478, 0x1858ccfce06cac74},
- {0x95527a5202df0ccb, 0x0f37801e0c43ebc8},
- {0xbaa718e68396cffd, 0xd30560258f54e6ba},
- {0xe950df20247c83fd, 0x47c6b82ef32a2069},
- {0x91d28b7416cdd27e, 0x4cdc331d57fa5441},
- {0xb6472e511c81471d, 0xe0133fe4adf8e952},
- {0xe3d8f9e563a198e5, 0x58180fddd97723a6},
- {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648},
- {0xb201833b35d63f73, 0x2cd2cc6551e513da},
- {0xde81e40a034bcf4f, 0xf8077f7ea65e58d1},
- {0x8b112e86420f6191, 0xfb04afaf27faf782},
- {0xadd57a27d29339f6, 0x79c5db9af1f9b563},
- {0xd94ad8b1c7380874, 0x18375281ae7822bc},
- {0x87cec76f1c830548, 0x8f2293910d0b15b5},
- {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb22},
- {0xd433179d9c8cb841, 0x5fa60692a46151eb},
- {0x849feec281d7f328, 0xdbc7c41ba6bcd333},
- {0xa5c7ea73224deff3, 0x12b9b522906c0800},
- {0xcf39e50feae16bef, 0xd768226b34870a00},
- {0x81842f29f2cce375, 0xe6a1158300d46640},
- {0xa1e53af46f801c53, 0x60495ae3c1097fd0},
- {0xca5e89b18b602368, 0x385bb19cb14bdfc4},
- {0xfcf62c1dee382c42, 0x46729e03dd9ed7b5},
- {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d1},
- {0xc5a05277621be293, 0xc7098b7305241885},
- { 0xf70867153aa2db38,
- 0xb8cbee4fc66d1ea7 }
-#else
- {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
- {0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
- {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f},
- {0x86a8d39ef77164bc, 0xae5dff9c02033198},
- {0xd98ddaee19068c76, 0x3badd624dd9b0958},
- {0xafbd2350644eeacf, 0xe5d1929ef90898fb},
- {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2},
- {0xe55990879ddcaabd, 0xcc420a6a101d0516},
- {0xb94470938fa89bce, 0xf808e40e8d5b3e6a},
- {0x95a8637627989aad, 0xdde7001379a44aa9},
- {0xf1c90080baf72cb1, 0x5324c68b12dd6339},
- {0xc350000000000000, 0x0000000000000000},
- {0x9dc5ada82b70b59d, 0xf020000000000000},
- {0xfee50b7025c36a08, 0x02f236d04753d5b4},
- {0xcde6fd5e09abcf26, 0xed4c0226b55e6f86},
- {0xa6539930bf6bff45, 0x84db8346b786151c},
- {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b2},
- {0xd910f7ff28069da4, 0x1b2ba1518094da04},
- {0xaf58416654a6babb, 0x387ac8d1970027b2},
- {0x8da471a9de737e24, 0x5ceaecfed289e5d2},
- {0xe4d5e82392a40515, 0x0fabaf3feaa5334a},
- {0xb8da1662e7b00a17, 0x3d6a751f3b936243},
- { 0x95527a5202df0ccb,
- 0x0f37801e0c43ebc8 }
-#endif
- };
-
-#if FMT_USE_FULL_CACHE_DRAGONBOX
- return pow10_significands[k - float_info<double>::min_k];
-#else
- static constexpr const uint64_t powers_of_5_64[] = {
- 0x0000000000000001, 0x0000000000000005, 0x0000000000000019,
- 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35,
- 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1,
- 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd,
- 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9,
- 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5,
- 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631,
- 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed,
- 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9};
-
- static constexpr const uint32_t pow10_recovery_errors[] = {
- 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 0x00000001,
- 0x50000000, 0x00104000, 0x54010004, 0x05004001, 0x55555544, 0x41545555,
- 0x54040551, 0x15445545, 0x51555514, 0x10000015, 0x00101100, 0x01100015,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x04450514, 0x45414110,
- 0x55555145, 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454,
- 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 0x55551014,
- 0x69514555, 0x05151109, 0x00155555};
-
- static const int compression_ratio = 27;
-
- // Compute base index.
- int cache_index = (k - float_info<double>::min_k) / compression_ratio;
- int kb = cache_index * compression_ratio + float_info<double>::min_k;
- int offset = k - kb;
-
- // Get base cache.
- uint128_wrapper base_cache = pow10_significands[cache_index];
- if (offset == 0) return base_cache;
-
- // Compute the required amount of bit-shift.
- int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset;
- FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected");
-
- // Try to recover the real cache.
- uint64_t pow5 = powers_of_5_64[offset];
- uint128_wrapper recovered_cache = umul128(base_cache.high(), pow5);
- uint128_wrapper middle_low =
- umul128(base_cache.low() - (kb < 0 ? 1u : 0u), pow5);
-
- recovered_cache += middle_low.high();
-
- uint64_t high_to_middle = recovered_cache.high() << (64 - alpha);
- uint64_t middle_to_low = recovered_cache.low() << (64 - alpha);
-
- recovered_cache =
- uint128_wrapper{(recovered_cache.low() >> alpha) | high_to_middle,
- ((middle_low.low() >> alpha) | middle_to_low)};
-
- if (kb < 0) recovered_cache += 1;
-
- // Get error.
- int error_idx = (k - float_info<double>::min_k) / 16;
- uint32_t error = (pow10_recovery_errors[error_idx] >>
- ((k - float_info<double>::min_k) % 16) * 2) &
- 0x3;
-
- // Add the error back.
- FMT_ASSERT(recovered_cache.low() + error >= recovered_cache.low(), "");
- return {recovered_cache.high(), recovered_cache.low() + error};
-#endif
- }
-
- static carrier_uint compute_mul(carrier_uint u,
- const cache_entry_type& cache) FMT_NOEXCEPT {
- return umul192_upper64(u, cache);
- }
-
- static uint32_t compute_delta(cache_entry_type const& cache,
- int beta_minus_1) FMT_NOEXCEPT {
- return static_cast<uint32_t>(cache.high() >> (64 - 1 - beta_minus_1));
- }
-
- static bool compute_mul_parity(carrier_uint two_f,
- const cache_entry_type& cache,
- int beta_minus_1) FMT_NOEXCEPT {
- FMT_ASSERT(beta_minus_1 >= 1, "");
- FMT_ASSERT(beta_minus_1 < 64, "");
-
- return ((umul192_middle64(two_f, cache) >> (64 - beta_minus_1)) & 1) != 0;
- }
-
- static carrier_uint compute_left_endpoint_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return (cache.high() -
- (cache.high() >> (float_info<double>::significand_bits + 2))) >>
- (64 - float_info<double>::significand_bits - 1 - beta_minus_1);
- }
-
- static carrier_uint compute_right_endpoint_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return (cache.high() +
- (cache.high() >> (float_info<double>::significand_bits + 1))) >>
- (64 - float_info<double>::significand_bits - 1 - beta_minus_1);
- }
-
- static carrier_uint compute_round_up_for_shorter_interval_case(
- const cache_entry_type& cache, int beta_minus_1) FMT_NOEXCEPT {
- return ((cache.high() >>
- (64 - float_info<double>::significand_bits - 2 - beta_minus_1)) +
- 1) /
- 2;
- }
-};
-
-// Various integer checks
-template <class T>
-bool is_left_endpoint_integer_shorter_interval(int exponent) FMT_NOEXCEPT {
- return exponent >=
- float_info<
- T>::case_shorter_interval_left_endpoint_lower_threshold &&
- exponent <=
- float_info<T>::case_shorter_interval_left_endpoint_upper_threshold;
-}
-template <class T>
-bool is_endpoint_integer(typename float_info<T>::carrier_uint two_f,
- int exponent, int minus_k) FMT_NOEXCEPT {
- if (exponent < float_info<T>::case_fc_pm_half_lower_threshold) return false;
- // For k >= 0.
- if (exponent <= float_info<T>::case_fc_pm_half_upper_threshold) return true;
- // For k < 0.
- if (exponent > float_info<T>::divisibility_check_by_5_threshold) return false;
- return divisible_by_power_of_5(two_f, minus_k);
-}
-
-template <class T>
-bool is_center_integer(typename float_info<T>::carrier_uint two_f, int exponent,
- int minus_k) FMT_NOEXCEPT {
- // Exponent for 5 is negative.
- if (exponent > float_info<T>::divisibility_check_by_5_threshold) return false;
- if (exponent > float_info<T>::case_fc_upper_threshold)
- return divisible_by_power_of_5(two_f, minus_k);
- // Both exponents are nonnegative.
- if (exponent >= float_info<T>::case_fc_lower_threshold) return true;
- // Exponent for 2 is negative.
- return divisible_by_power_of_2(two_f, minus_k - exponent + 1);
-}
-
-// Remove trailing zeros from n and return the number of zeros removed (float)
-FMT_INLINE int remove_trailing_zeros(uint32_t& n) FMT_NOEXCEPT {
-#ifdef FMT_BUILTIN_CTZ
- int t = FMT_BUILTIN_CTZ(n);
-#else
- int t = ctz(n);
-#endif
- if (t > float_info<float>::max_trailing_zeros)
- t = float_info<float>::max_trailing_zeros;
-
- const uint32_t mod_inv1 = 0xcccccccd;
- const uint32_t max_quotient1 = 0x33333333;
- const uint32_t mod_inv2 = 0xc28f5c29;
- const uint32_t max_quotient2 = 0x0a3d70a3;
-
- int s = 0;
- for (; s < t - 1; s += 2) {
- if (n * mod_inv2 > max_quotient2) break;
- n *= mod_inv2;
- }
- if (s < t && n * mod_inv1 <= max_quotient1) {
- n *= mod_inv1;
- ++s;
- }
- n >>= s;
- return s;
-}
-
-// Removes trailing zeros and returns the number of zeros removed (double)
-FMT_INLINE int remove_trailing_zeros(uint64_t& n) FMT_NOEXCEPT {
-#ifdef FMT_BUILTIN_CTZLL
- int t = FMT_BUILTIN_CTZLL(n);
-#else
- int t = ctzll(n);
-#endif
- if (t > float_info<double>::max_trailing_zeros)
- t = float_info<double>::max_trailing_zeros;
- // Divide by 10^8 and reduce to 32-bits
- // Since ret_value.significand <= (2^64 - 1) / 1000 < 10^17,
- // both of the quotient and the r should fit in 32-bits
-
- const uint32_t mod_inv1 = 0xcccccccd;
- const uint32_t max_quotient1 = 0x33333333;
- const uint64_t mod_inv8 = 0xc767074b22e90e21;
- const uint64_t max_quotient8 = 0x00002af31dc46118;
-
- // If the number is divisible by 1'0000'0000, work with the quotient
- if (t >= 8) {
- auto quotient_candidate = n * mod_inv8;
-
- if (quotient_candidate <= max_quotient8) {
- auto quotient = static_cast<uint32_t>(quotient_candidate >> 8);
-
- int s = 8;
- for (; s < t; ++s) {
- if (quotient * mod_inv1 > max_quotient1) break;
- quotient *= mod_inv1;
- }
- quotient >>= (s - 8);
- n = quotient;
- return s;
- }
- }
-
- // Otherwise, work with the remainder
- auto quotient = static_cast<uint32_t>(n / 100000000);
- auto remainder = static_cast<uint32_t>(n - 100000000 * quotient);
-
- if (t == 0 || remainder * mod_inv1 > max_quotient1) {
- return 0;
- }
- remainder *= mod_inv1;
-
- if (t == 1 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 1) + quotient * 10000000ull;
- return 1;
- }
- remainder *= mod_inv1;
-
- if (t == 2 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 2) + quotient * 1000000ull;
- return 2;
- }
- remainder *= mod_inv1;
-
- if (t == 3 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 3) + quotient * 100000ull;
- return 3;
- }
- remainder *= mod_inv1;
-
- if (t == 4 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 4) + quotient * 10000ull;
- return 4;
- }
- remainder *= mod_inv1;
-
- if (t == 5 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 5) + quotient * 1000ull;
- return 5;
- }
- remainder *= mod_inv1;
-
- if (t == 6 || remainder * mod_inv1 > max_quotient1) {
- n = (remainder >> 6) + quotient * 100ull;
- return 6;
- }
- remainder *= mod_inv1;
-
- n = (remainder >> 7) + quotient * 10ull;
- return 7;
-}
-
-// The main algorithm for shorter interval case
-template <class T>
-FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) FMT_NOEXCEPT {
- decimal_fp<T> ret_value;
- // Compute k and beta
- const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
- const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k);
-
- // Compute xi and zi
- using cache_entry_type = typename cache_accessor<T>::cache_entry_type;
- const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
-
- auto xi = cache_accessor<T>::compute_left_endpoint_for_shorter_interval_case(
- cache, beta_minus_1);
- auto zi = cache_accessor<T>::compute_right_endpoint_for_shorter_interval_case(
- cache, beta_minus_1);
-
- // If the left endpoint is not an integer, increase it
- if (!is_left_endpoint_integer_shorter_interval<T>(exponent)) ++xi;
-
- // Try bigger divisor
- ret_value.significand = zi / 10;
-
- // If succeed, remove trailing zeros if necessary and return
- if (ret_value.significand * 10 >= xi) {
- ret_value.exponent = minus_k + 1;
- ret_value.exponent += remove_trailing_zeros(ret_value.significand);
- return ret_value;
- }
-
- // Otherwise, compute the round-up of y
- ret_value.significand =
- cache_accessor<T>::compute_round_up_for_shorter_interval_case(
- cache, beta_minus_1);
- ret_value.exponent = minus_k;
-
- // When tie occurs, choose one of them according to the rule
- if (exponent >= float_info<T>::shorter_interval_tie_lower_threshold &&
- exponent <= float_info<T>::shorter_interval_tie_upper_threshold) {
- ret_value.significand = ret_value.significand % 2 == 0
- ? ret_value.significand
- : ret_value.significand - 1;
- } else if (ret_value.significand < xi) {
- ++ret_value.significand;
- }
- return ret_value;
-}
-
-template <typename T> decimal_fp<T> to_decimal(T x) FMT_NOEXCEPT {
- // Step 1: integer promotion & Schubfach multiplier calculation.
-
- using carrier_uint = typename float_info<T>::carrier_uint;
- using cache_entry_type = typename cache_accessor<T>::cache_entry_type;
- auto br = bit_cast<carrier_uint>(x);
-
- // Extract significand bits and exponent bits.
- const carrier_uint significand_mask =
- (static_cast<carrier_uint>(1) << float_info<T>::significand_bits) - 1;
- carrier_uint significand = (br & significand_mask);
- int exponent = static_cast<int>((br & exponent_mask<T>()) >>
- float_info<T>::significand_bits);
-
- if (exponent != 0) { // Check if normal.
- exponent += float_info<T>::exponent_bias - float_info<T>::significand_bits;
-
- // Shorter interval case; proceed like Schubfach.
- if (significand == 0) return shorter_interval_case<T>(exponent);
-
- significand |=
- (static_cast<carrier_uint>(1) << float_info<T>::significand_bits);
- } else {
- // Subnormal case; the interval is always regular.
- if (significand == 0) return {0, 0};
- exponent = float_info<T>::min_exponent - float_info<T>::significand_bits;
- }
-
- const bool include_left_endpoint = (significand % 2 == 0);
- const bool include_right_endpoint = include_left_endpoint;
-
- // Compute k and beta.
- const int minus_k = floor_log10_pow2(exponent) - float_info<T>::kappa;
- const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
- const int beta_minus_1 = exponent + floor_log2_pow10(-minus_k);
-
- // Compute zi and deltai
- // 10^kappa <= deltai < 10^(kappa + 1)
- const uint32_t deltai = cache_accessor<T>::compute_delta(cache, beta_minus_1);
- const carrier_uint two_fc = significand << 1;
- const carrier_uint two_fr = two_fc | 1;
- const carrier_uint zi =
- cache_accessor<T>::compute_mul(two_fr << beta_minus_1, cache);
-
- // Step 2: Try larger divisor; remove trailing zeros if necessary
-
- // Using an upper bound on zi, we might be able to optimize the division
- // better than the compiler; we are computing zi / big_divisor here
- decimal_fp<T> ret_value;
- ret_value.significand = divide_by_10_to_kappa_plus_1(zi);
- uint32_t r = static_cast<uint32_t>(zi - float_info<T>::big_divisor *
- ret_value.significand);
-
- if (r > deltai) {
- goto small_divisor_case_label;
- } else if (r < deltai) {
- // Exclude the right endpoint if necessary
- if (r == 0 && !include_right_endpoint &&
- is_endpoint_integer<T>(two_fr, exponent, minus_k)) {
- --ret_value.significand;
- r = float_info<T>::big_divisor;
- goto small_divisor_case_label;
- }
- } else {
- // r == deltai; compare fractional parts
- // Check conditions in the order different from the paper
- // to take advantage of short-circuiting
- const carrier_uint two_fl = two_fc - 1;
- if ((!include_left_endpoint ||
- !is_endpoint_integer<T>(two_fl, exponent, minus_k)) &&
- !cache_accessor<T>::compute_mul_parity(two_fl, cache, beta_minus_1)) {
- goto small_divisor_case_label;
- }
- }
- ret_value.exponent = minus_k + float_info<T>::kappa + 1;
-
- // We may need to remove trailing zeros
- ret_value.exponent += remove_trailing_zeros(ret_value.significand);
- return ret_value;
-
- // Step 3: Find the significand with the smaller divisor
-
-small_divisor_case_label:
- ret_value.significand *= 10;
- ret_value.exponent = minus_k + float_info<T>::kappa;
-
- const uint32_t mask = (1u << float_info<T>::kappa) - 1;
- auto dist = r - (deltai / 2) + (float_info<T>::small_divisor / 2);
-
- // Is dist divisible by 2^kappa?
- if ((dist & mask) == 0) {
- const bool approx_y_parity =
- ((dist ^ (float_info<T>::small_divisor / 2)) & 1) != 0;
- dist >>= float_info<T>::kappa;
-
- // Is dist divisible by 5^kappa?
- if (check_divisibility_and_divide_by_pow5<float_info<T>::kappa>(dist)) {
- ret_value.significand += dist;
-
- // Check z^(f) >= epsilon^(f)
- // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1,
- // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f)
- // Since there are only 2 possibilities, we only need to care about the
- // parity. Also, zi and r should have the same parity since the divisor
- // is an even number
- if (cache_accessor<T>::compute_mul_parity(two_fc, cache, beta_minus_1) !=
- approx_y_parity) {
- --ret_value.significand;
- } else {
- // If z^(f) >= epsilon^(f), we might have a tie
- // when z^(f) == epsilon^(f), or equivalently, when y is an integer
- if (is_center_integer<T>(two_fc, exponent, minus_k)) {
- ret_value.significand = ret_value.significand % 2 == 0
- ? ret_value.significand
- : ret_value.significand - 1;
- }
- }
- }
- // Is dist not divisible by 5^kappa?
- else {
- ret_value.significand += dist;
- }
- }
- // Is dist not divisible by 2^kappa?
- else {
- // Since we know dist is small, we might be able to optimize the division
- // better than the compiler; we are computing dist / small_divisor here
- ret_value.significand +=
- small_division_by_pow10<float_info<T>::kappa>(dist);
- }
- return ret_value;
-}
-} // namespace dragonbox
-
-// Formats a floating-point number using a variation of the Fixed-Precision
-// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White:
-// https://fmt.dev/papers/p372-steele.pdf.
-FMT_CONSTEXPR20 inline void format_dragon(fp value, bool is_predecessor_closer,
- int num_digits, buffer<char>& buf,
- int& exp10) {
- bigint numerator; // 2 * R in (FPP)^2.
- bigint denominator; // 2 * S in (FPP)^2.
- // lower and upper are differences between value and corresponding boundaries.
- bigint lower; // (M^- in (FPP)^2).
- bigint upper_store; // upper's value if different from lower.
- bigint* upper = nullptr; // (M^+ in (FPP)^2).
- // Shift numerator and denominator by an extra bit or two (if lower boundary
- // is closer) to make lower and upper integers. This eliminates multiplication
- // by 2 during later computations.
- int shift = is_predecessor_closer ? 2 : 1;
- uint64_t significand = value.f << shift;
- if (value.e >= 0) {
- numerator.assign(significand);
- numerator <<= value.e;
- lower.assign(1);
- lower <<= value.e;
- if (shift != 1) {
- upper_store.assign(1);
- upper_store <<= value.e + 1;
- upper = &upper_store;
- }
- denominator.assign_pow10(exp10);
- denominator <<= shift;
- } else if (exp10 < 0) {
- numerator.assign_pow10(-exp10);
- lower.assign(numerator);
- if (shift != 1) {
- upper_store.assign(numerator);
- upper_store <<= 1;
- upper = &upper_store;
- }
- numerator *= significand;
- denominator.assign(1);
- denominator <<= shift - value.e;
- } else {
- numerator.assign(significand);
- denominator.assign_pow10(exp10);
- denominator <<= shift - value.e;
- lower.assign(1);
- if (shift != 1) {
- upper_store.assign(1ULL << 1);
- upper = &upper_store;
- }
- }
- // Invariant: value == (numerator / denominator) * pow(10, exp10).
- if (num_digits < 0) {
- // Generate the shortest representation.
- if (!upper) upper = &lower;
- bool even = (value.f & 1) == 0;
- num_digits = 0;
- char* data = buf.data();
- for (;;) {
- int digit = numerator.divmod_assign(denominator);
- bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower.
- // numerator + upper >[=] pow10:
- bool high = add_compare(numerator, *upper, denominator) + even > 0;
- data[num_digits++] = static_cast<char>('0' + digit);
- if (low || high) {
- if (!low) {
- ++data[num_digits - 1];
- } else if (high) {
- int result = add_compare(numerator, numerator, denominator);
- // Round half to even.
- if (result > 0 || (result == 0 && (digit % 2) != 0))
- ++data[num_digits - 1];
- }
- buf.try_resize(to_unsigned(num_digits));
- exp10 -= num_digits - 1;
- return;
- }
- numerator *= 10;
- lower *= 10;
- if (upper != &lower) *upper *= 10;
- }
- }
- // Generate the given number of digits.
- exp10 -= num_digits - 1;
- if (num_digits == 0) {
- denominator *= 10;
- auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0';
- buf.push_back(digit);
- return;
- }
- buf.try_resize(to_unsigned(num_digits));
- for (int i = 0; i < num_digits - 1; ++i) {
- int digit = numerator.divmod_assign(denominator);
- buf[i] = static_cast<char>('0' + digit);
- numerator *= 10;
- }
- int digit = numerator.divmod_assign(denominator);
- auto result = add_compare(numerator, numerator, denominator);
- if (result > 0 || (result == 0 && (digit % 2) != 0)) {
- if (digit == 9) {
- const auto overflow = '0' + 10;
- buf[num_digits - 1] = overflow;
- // Propagate the carry.
- for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
- buf[i] = '0';
- ++buf[i - 1];
- }
- if (buf[0] == overflow) {
- buf[0] = '1';
- ++exp10;
- }
- return;
- }
- ++digit;
- }
- buf[num_digits - 1] = static_cast<char>('0' + digit);
-}
-
-template <typename Float>
-FMT_HEADER_ONLY_CONSTEXPR20 int format_float(Float value, int precision,
- float_specs specs,
- buffer<char>& buf) {
- // float is passed as double to reduce the number of instantiations.
- static_assert(!std::is_same<Float, float>::value, "");
- FMT_ASSERT(value >= 0, "value is negative");
-
- const bool fixed = specs.format == float_format::fixed;
- if (value <= 0) { // <= instead of == to silence a warning.
- if (precision <= 0 || !fixed) {
- buf.push_back('0');
- return 0;
- }
- buf.try_resize(to_unsigned(precision));
- fill_n(buf.data(), precision, '0');
- return -precision;
- }
-
- if (specs.fallback) return snprintf_float(value, precision, specs, buf);
-
- if (!is_constant_evaluated() && precision < 0) {
- // Use Dragonbox for the shortest format.
- if (specs.binary32) {
- auto dec = dragonbox::to_decimal(static_cast<float>(value));
- write<char>(buffer_appender<char>(buf), dec.significand);
- return dec.exponent;
- }
- auto dec = dragonbox::to_decimal(static_cast<double>(value));
- write<char>(buffer_appender<char>(buf), dec.significand);
- return dec.exponent;
- }
-
- int exp = 0;
- bool use_dragon = true;
- if (is_fast_float<Float>()) {
- // 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(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;
- } else {
- exp += handler.size - cached_exp10 - 1;
- precision = handler.precision;
- }
- }
- if (use_dragon) {
- auto f = fp();
- bool is_predecessor_closer =
- specs.binary32 ? f.assign(static_cast<float>(value)) : f.assign(value);
- // Limit precision to the maximum possible number of significant digits in
- // an IEEE754 double because we don't need to generate zeros.
- const int max_double_digits = 767;
- if (precision > max_double_digits) precision = max_double_digits;
- format_dragon(f, is_predecessor_closer, precision, buf, exp);
- }
- if (!fixed && !specs.showpoint) {
- // Remove trailing zeros.
- auto num_digits = buf.size();
- while (num_digits > 0 && buf[num_digits - 1] == '0') {
- --num_digits;
- ++exp;
- }
- buf.try_resize(num_digits);
- }
- return exp;
-}
-
-template <typename T>
-int snprintf_float(T value, int precision, float_specs specs,
- buffer<char>& buf) {
- // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
- FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
- static_assert(!std::is_same<T, float>::value, "");
-
- // Subtract 1 to account for the difference in precision since we use %e for
- // both general and exponent format.
- if (specs.format == float_format::general ||
- specs.format == float_format::exp)
- precision = (precision >= 0 ? precision : 6) - 1;
-
- // Build the format string.
- enum { max_format_size = 7 }; // The longest format is "%#.*Le".
- char format[max_format_size];
- char* format_ptr = format;
- *format_ptr++ = '%';
- if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#';
- if (precision >= 0) {
- *format_ptr++ = '.';
- *format_ptr++ = '*';
- }
- if (std::is_same<T, long double>()) *format_ptr++ = 'L';
- *format_ptr++ = specs.format != float_format::hex
- ? (specs.format == float_format::fixed ? 'f' : 'e')
- : (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;
-#ifdef FMT_FUZZ
- if (precision > 100000)
- throw std::runtime_error(
- "fuzz mode - avoid large allocation inside snprintf");
-#endif
- // 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_reserve(size + offset + 1); // Add 1 for the terminating '\0'.
- continue;
- }
- auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
- if (specs.format == float_format::fixed) {
- if (precision == 0) {
- buf.try_resize(size);
- return 0;
- }
- // Find and remove the decimal point.
- auto end = begin + size, p = end;
- do {
- --p;
- } while (is_digit(*p));
- int fraction_size = static_cast<int>(end - p - 1);
- std::memmove(p, p + 1, to_unsigned(fraction_size));
- buf.try_resize(size - 1);
- return -fraction_size;
- }
- if (specs.format == float_format::hex) {
- buf.try_resize(size + offset);
- return 0;
- }
- // Find and parse the exponent.
- auto end = begin + size, exp_pos = end;
- do {
- --exp_pos;
- } while (*exp_pos != 'e');
- char sign = exp_pos[1];
- FMT_ASSERT(sign == '+' || sign == '-', "");
- int exp = 0;
- auto p = exp_pos + 2; // Skip 'e' and sign.
- do {
- FMT_ASSERT(is_digit(*p), "");
- exp = exp * 10 + (*p++ - '0');
- } while (p != end);
- if (sign == '-') exp = -exp;
- int fraction_size = 0;
- if (exp_pos != begin + 1) {
- // Remove trailing zeros.
- auto fraction_end = exp_pos - 1;
- while (*fraction_end == '0') --fraction_end;
- // Move the fractional part left to get rid of the decimal point.
- fraction_size = static_cast<int>(fraction_end - begin - 1);
- std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size));
- }
- buf.try_resize(to_unsigned(fraction_size) + offset + 1);
- return exp - fraction_size;
- }
-}
-} // namespace detail
-
-template <> struct formatter<detail::bigint> {
- FMT_CONSTEXPR format_parse_context::iterator parse(
- format_parse_context& ctx) {
- return ctx.begin();
- }
-
- format_context::iterator format(const detail::bigint& n,
- format_context& ctx) {
- auto out = ctx.out();
- bool first = true;
- for (auto i = n.bigits_.size(); i > 0; --i) {
- auto value = n.bigits_[i - 1u];
- if (first) {
- out = format_to(out, FMT_STRING("{:x}"), value);
- first = false;
- continue;
- }
- out = format_to(out, FMT_STRING("{:08x}"), value);
- }
- if (n.exp_ > 0)
- out = format_to(out, FMT_STRING("p{}"),
- n.exp_ * detail::bigint::bigit_bits);
- return out;
- }
-};
-
-FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
- for_each_codepoint(s, [this](uint32_t cp, string_view) {
- if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8"));
- if (cp <= 0xFFFF) {
- buffer_.push_back(static_cast<wchar_t>(cp));
- } else {
- cp -= 0x10000;
- buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
- buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
- }
- return true;
- });
- buffer_.push_back(0);
-}
-
-FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
- const char* message) FMT_NOEXCEPT {
- FMT_TRY {
- auto ec = std::error_code(error_code, std::generic_category());
- write(std::back_inserter(out), std::system_error(ec, message).what());
- return;
- }
- FMT_CATCH(...) {}
- format_error_code(out, error_code, message);
-}
-
-FMT_FUNC void report_system_error(int error_code,
- const char* message) FMT_NOEXCEPT {
- report_error(format_system_error, error_code, message);
-}
-
-// DEPRECATED!
-// This function is defined here and not inline for ABI compatiblity.
-FMT_FUNC void detail::error_handler::on_error(const char* message) {
- throw_format_error(message);
-}
-
-FMT_FUNC std::string vformat(string_view fmt, format_args args) {
- // Don't optimize the "{}" case to keep the binary size small and because it
- // can be better optimized in fmt::format anyway.
- auto buffer = memory_buffer();
- detail::vformat_to(buffer, fmt, args);
- return to_string(buffer);
-}
-
-#ifdef _WIN32
-namespace detail {
-using dword = conditional_t<sizeof(long) == 4, unsigned long, unsigned>;
-extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( //
- void*, const void*, dword, dword*, void*);
-} // namespace detail
-#endif
-
-namespace detail {
-FMT_FUNC void print(std::FILE* f, string_view text) {
-#ifdef _WIN32
- 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;
- }
- // Fallback to fwrite on failure. It can happen if the output has been
- // redirected to NUL.
- }
-#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()});
-}
-
-#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,
- 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_END_NAMESPACE
-
-#endif // FMT_FORMAT_INL_H_
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/locale.h b/wpiutil/src/main/native/fmtlib/include/fmt/locale.h
deleted file mode 100644
index 7571b52..0000000
--- a/wpiutil/src/main/native/fmtlib/include/fmt/locale.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#include "xchar.h"
-#warning fmt/locale.h is deprecated, include fmt/format.h or fmt/xchar.h instead
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/ostream.h b/wpiutil/src/main/native/fmtlib/include/fmt/ostream.h
deleted file mode 100644
index 3d716ec..0000000
--- a/wpiutil/src/main/native/fmtlib/include/fmt/ostream.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// Formatting library for C++ - std::ostream support
-//
-// Copyright (c) 2012 - present, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-
-#ifndef FMT_OSTREAM_H_
-#define FMT_OSTREAM_H_
-
-#include <ostream>
-
-#include "format.h"
-
-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_same<T, std::basic_string<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 {};
-
-// Write the content of buf to os.
-// It is a separate function rather than a part of vprint to simplify testing.
-template <typename Char>
-void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
- const Char* buf_data = buf.data();
- using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
- unsigned_streamsize size = buf.size();
- unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
- do {
- unsigned_streamsize n = size <= max_size ? size : max_size;
- os.write(buf_data, static_cast<std::streamsize>(n));
- buf_data += n;
- size -= n;
- } while (size != 0);
-}
-
-template <typename Char, typename T>
-void format_value(buffer<Char>& buf, const T& value,
- locale_ref loc = locale_ref()) {
- auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
- auto&& output = std::basic_ostream<Char>(&format_buf);
-#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
- if (loc) output.imbue(loc.get<std::locale>());
-#endif
- output << value;
- output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
- buf.try_resize(buf.size());
-}
-
-// 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>>
- : private formatter<basic_string_view<Char>, Char> {
- using formatter<basic_string_view<Char>, Char>::parse;
-
- template <typename OutputIt>
- auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
- -> OutputIt {
- auto buffer = basic_memory_buffer<Char>();
- format_value(buffer, value, ctx.locale());
- return formatter<basic_string_view<Char>, Char>::format(
- {buffer.data(), buffer.size()}, ctx);
- }
-
- // DEPRECATED!
- template <typename OutputIt>
- auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
- -> OutputIt {
- auto buffer = basic_memory_buffer<Char>();
- format_value(buffer, value, ctx.locale());
- return std::copy(buffer.begin(), buffer.end(), ctx.out());
- }
-};
-} // namespace detail
-
-FMT_MODULE_EXPORT
-template <typename Char>
-void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
- basic_format_args<buffer_context<type_identity_t<Char>>> args) {
- auto buffer = basic_memory_buffer<Char>();
- detail::vformat_to(buffer, format_str, args);
- detail::write_buffer(os, buffer);
-}
-
-/**
- \rst
- Prints formatted data to the stream *os*.
-
- **Example**::
-
- fmt::print(cerr, "Don't {}!", "panic");
- \endrst
- */
-FMT_MODULE_EXPORT
-template <typename S, typename... Args,
- typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
-void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
- vprint(os, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
-}
-FMT_END_NAMESPACE
-
-#endif // FMT_OSTREAM_H_
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/ranges.h b/wpiutil/src/main/native/fmtlib/include/fmt/ranges.h
deleted file mode 100644
index eb9fb8a..0000000
--- a/wpiutil/src/main/native/fmtlib/include/fmt/ranges.h
+++ /dev/null
@@ -1,793 +0,0 @@
-// Formatting library for C++ - experimental range support
-//
-// Copyright (c) 2012 - present, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-//
-// Copyright (c) 2018 - present, Remotion (Igor Schulz)
-// All Rights Reserved
-// {fmt} support for ranges, containers and types tuple interface.
-
-#ifndef FMT_RANGES_H_
-#define FMT_RANGES_H_
-
-#include <initializer_list>
-#include <tuple>
-#include <type_traits>
-
-#include "format.h"
-
-FMT_BEGIN_NAMESPACE
-
-namespace detail {
-
-template <typename RangeT, typename OutputIterator>
-OutputIterator copy(const RangeT& range, OutputIterator out) {
- 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) {
- while (*str) *out++ = *str++;
- return out;
-}
-
-template <typename OutputIterator>
-OutputIterator copy(char ch, OutputIterator out) {
- *out++ = ch;
- return out;
-}
-
-template <typename OutputIterator>
-OutputIterator copy(wchar_t ch, OutputIterator out) {
- *out++ = ch;
- return out;
-}
-
-// Returns true if T has a std::string-like interface, like std::string_view.
-template <typename T> class is_std_string_like {
- template <typename U>
- static auto check(U* p)
- -> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
- template <typename> static void check(...);
-
- public:
- static FMT_CONSTEXPR_DECL const bool value =
- is_string<T>::value ||
- std::is_convertible<T, std_string_view<char>>::value ||
- !std::is_void<decltype(check<T>(nullptr))>::value;
-};
-
-template <typename Char>
-struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
-
-template <typename T> class is_map {
- template <typename U> static auto check(U*) -> typename U::mapped_type;
- template <typename> static void check(...);
-
- public:
-#ifdef FMT_FORMAT_MAP_AS_LIST
- static FMT_CONSTEXPR_DECL const bool value = false;
-#else
- static FMT_CONSTEXPR_DECL const bool value =
- !std::is_void<decltype(check<T>(nullptr))>::value;
-#endif
-};
-
-template <typename T> class is_set {
- template <typename U> static auto check(U*) -> typename U::key_type;
- template <typename> static void check(...);
-
- public:
-#ifdef FMT_FORMAT_SET_AS_LIST
- static FMT_CONSTEXPR_DECL const bool value = false;
-#else
- static FMT_CONSTEXPR_DECL const bool value =
- !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
-#endif
-};
-
-template <typename... Ts> struct conditional_helper {};
-
-template <typename T, typename _ = void> struct is_range_ : std::false_type {};
-
-#if !FMT_MSC_VER || FMT_MSC_VER > 1800
-
-# define FMT_DECLTYPE_RETURN(val) \
- ->decltype(val) { return val; } \
- static_assert( \
- true, "") // This makes it so that a semicolon is required after the
- // macro, which helps clang-format handle the formatting.
-
-// C array overload
-template <typename T, std::size_t N>
-auto range_begin(const T (&arr)[N]) -> const T* {
- return arr;
-}
-template <typename T, std::size_t N>
-auto range_end(const T (&arr)[N]) -> const T* {
- return arr + N;
-}
-
-template <typename T, typename Enable = void>
-struct has_member_fn_begin_end_t : std::false_type {};
-
-template <typename T>
-struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
- decltype(std::declval<T>().end())>>
- : std::true_type {};
-
-// Member function overload
-template <typename T>
-auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
-template <typename T>
-auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
-
-// ADL overload. Only participates in overload resolution if member functions
-// are not found.
-template <typename T>
-auto range_begin(T&& rng)
- -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
- decltype(begin(static_cast<T&&>(rng)))> {
- return begin(static_cast<T&&>(rng));
-}
-template <typename T>
-auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
- decltype(end(static_cast<T&&>(rng)))> {
- return end(static_cast<T&&>(rng));
-}
-
-template <typename T, typename Enable = void>
-struct has_const_begin_end : std::false_type {};
-template <typename T, typename Enable = void>
-struct has_mutable_begin_end : std::false_type {};
-
-template <typename T>
-struct has_const_begin_end<
- T,
- void_t<
- decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
- decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
- : std::true_type {};
-
-template <typename T>
-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 {};
-
-template <typename T>
-struct is_range_<T, void>
- : std::integral_constant<bool, (has_const_begin_end<T>::value ||
- has_mutable_begin_end<T>::value)> {};
-# undef FMT_DECLTYPE_RETURN
-#endif
-
-// tuple_size and tuple_element check.
-template <typename T> class is_tuple_like_ {
- template <typename U>
- static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
- template <typename> static void check(...);
-
- public:
- static FMT_CONSTEXPR_DECL const bool value =
- !std::is_void<decltype(check<T>(nullptr))>::value;
-};
-
-// Check for integer_sequence
-#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
-template <typename T, T... N>
-using integer_sequence = std::integer_sequence<T, N...>;
-template <size_t... N> using index_sequence = std::index_sequence<N...>;
-template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
-#else
-template <typename T, T... N> struct integer_sequence {
- using value_type = T;
-
- static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
-};
-
-template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
-
-template <typename T, size_t N, T... Ns>
-struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
-template <typename T, T... Ns>
-struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
-
-template <size_t N>
-using make_index_sequence = make_integer_sequence<size_t, N>;
-#endif
-
-template <class Tuple, class F, size_t... Is>
-void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
- using std::get;
- // using free function get<I>(T) now.
- const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
- (void)_; // blocks warnings
-}
-
-template <class T>
-FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
- T const&) {
- return {};
-}
-
-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 Range>
-using value_type =
- remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
-
-template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
- *out++ = ',';
- *out++ = ' ';
- return out;
-}
-
-struct singleton {
- unsigned char upper;
- unsigned char lower_count;
-};
-
-inline auto is_printable(uint16_t x, const singleton* singletons,
- size_t singletons_size,
- const unsigned char* singleton_lowers,
- const unsigned char* normal, size_t normal_size)
- -> bool {
- auto upper = x >> 8;
- auto lower_start = 0;
- for (size_t i = 0; i < singletons_size; ++i) {
- auto s = singletons[i];
- auto lower_end = lower_start + s.lower_count;
- if (upper < s.upper) break;
- if (upper == s.upper) {
- for (auto j = lower_start; j < lower_end; ++j) {
- if (singleton_lowers[j] == (x & 0xff)) return false;
- }
- }
- lower_start = lower_end;
- }
-
- auto xsigned = static_cast<int>(x);
- auto current = true;
- for (size_t i = 0; i < normal_size; ++i) {
- auto v = static_cast<int>(normal[i]);
- auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v;
- xsigned -= len;
- if (xsigned < 0) break;
- current = !current;
- }
- return current;
-}
-
-// Returns true iff the code point cp is printable.
-// This code is generated by support/printable.py.
-inline auto is_printable(uint32_t cp) -> bool {
- static constexpr singleton singletons0[] = {
- {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
- {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
- {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
- {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
- {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
- {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
- {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
- };
- static constexpr unsigned char singletons0_lower[] = {
- 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
- 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
- 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
- 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
- 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
- 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
- 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
- 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
- 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
- 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
- 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
- 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
- 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
- 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
- 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
- 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
- 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
- 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
- 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
- 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
- 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
- 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
- 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
- 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
- 0xfe, 0xff,
- };
- static constexpr singleton singletons1[] = {
- {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
- {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
- {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
- {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
- {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
- {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
- {0xfa, 2}, {0xfb, 1},
- };
- static constexpr unsigned char singletons1_lower[] = {
- 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
- 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
- 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
- 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
- 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
- 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
- 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
- 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
- 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
- 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
- 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
- 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
- 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
- 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
- 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
- };
- static constexpr unsigned char normal0[] = {
- 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
- 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
- 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
- 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
- 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
- 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
- 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
- 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
- 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
- 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
- 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
- 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
- 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
- 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
- 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
- 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
- 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
- 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
- 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
- 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
- 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
- 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
- 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
- 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
- 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
- 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
- };
- static constexpr unsigned char normal1[] = {
- 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
- 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
- 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
- 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
- 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
- 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
- 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
- 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
- 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
- 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
- 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
- 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
- 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
- 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
- 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
- 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
- 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
- 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
- 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
- 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
- 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
- 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
- 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
- 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
- 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
- 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
- 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
- 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
- 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
- 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
- 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
- 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
- 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
- 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
- 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
- };
- auto lower = static_cast<uint16_t>(cp);
- if (cp < 0x10000) {
- return is_printable(lower, singletons0,
- sizeof(singletons0) / sizeof(*singletons0),
- singletons0_lower, normal0, sizeof(normal0));
- }
- if (cp < 0x20000) {
- return is_printable(lower, singletons1,
- sizeof(singletons1) / sizeof(*singletons1),
- singletons1_lower, normal1, sizeof(normal1));
- }
- if (0x2a6de <= cp && cp < 0x2a700) return false;
- if (0x2b735 <= cp && cp < 0x2b740) return false;
- if (0x2b81e <= cp && cp < 0x2b820) return false;
- if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
- if (0x2ebe1 <= cp && cp < 0x2f800) return false;
- if (0x2fa1e <= cp && cp < 0x30000) return false;
- if (0x3134b <= cp && cp < 0xe0100) return false;
- if (0xe01f0 <= cp && cp < 0x110000) return false;
- return cp < 0x110000;
-}
-
-inline auto needs_escape(uint32_t cp) -> bool {
- return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
- !is_printable(cp);
-}
-
-template <typename Char> struct find_escape_result {
- const Char* begin;
- const Char* end;
- uint32_t cp;
-};
-
-template <typename Char>
-auto find_escape(const Char* begin, const Char* end)
- -> find_escape_result<Char> {
- for (; begin != end; ++begin) {
- auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
- if (sizeof(Char) == 1 && cp >= 0x80) continue;
- if (needs_escape(cp)) return {begin, begin + 1, cp};
- }
- return {begin, nullptr, 0};
-}
-
-inline auto find_escape(const char* begin, const char* end)
- -> find_escape_result<char> {
- if (!is_utf8()) return find_escape<char>(begin, end);
- auto result = find_escape_result<char>{end, nullptr, 0};
- for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
- [&](uint32_t cp, string_view sv) {
- if (needs_escape(cp)) {
- result = {sv.begin(), sv.end(), cp};
- return false;
- }
- return true;
- });
- return result;
-}
-
-template <typename Char, typename OutputIt>
-auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
- *out++ = '"';
- auto begin = str.begin(), end = str.end();
- do {
- auto escape = find_escape(begin, end);
- out = copy_str<Char>(begin, escape.begin, out);
- begin = escape.end;
- if (!begin) break;
- auto c = static_cast<Char>(escape.cp);
- switch (escape.cp) {
- case '\n':
- *out++ = '\\';
- c = 'n';
- break;
- case '\r':
- *out++ = '\\';
- c = 'r';
- break;
- case '\t':
- *out++ = '\\';
- c = 't';
- break;
- case '"':
- FMT_FALLTHROUGH;
- case '\\':
- *out++ = '\\';
- break;
- default:
- if (is_utf8()) {
- if (escape.cp < 0x100) {
- out = format_to(out, "\\x{:02x}", escape.cp);
- continue;
- }
- if (escape.cp < 0x10000) {
- out = format_to(out, "\\u{:04x}", escape.cp);
- continue;
- }
- if (escape.cp < 0x110000) {
- out = format_to(out, "\\U{:08x}", escape.cp);
- continue;
- }
- }
- for (Char escape_char : basic_string_view<Char>(
- escape.begin, to_unsigned(escape.end - escape.begin))) {
- out = format_to(
- out, "\\x{:02x}",
- static_cast<typename std::make_unsigned<Char>::type>(escape_char));
- }
- continue;
- }
- *out++ = c;
- } while (begin != end);
- *out++ = '"';
- return out;
-}
-
-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 Char, typename OutputIt, typename Arg,
- FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
-OutputIt write_range_entry(OutputIt out, const Arg v) {
- *out++ = '\'';
- *out++ = v;
- *out++ = '\'';
- return out;
-}
-
-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);
-}
-
-} // namespace detail
-
-template <typename T> struct is_tuple_like {
- static FMT_CONSTEXPR_DECL const bool value =
- detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
-};
-
-template <typename TupleT, typename Char>
-struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
- private:
- // 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::write_delimiter(out);
- out = detail::write_range_entry<Char>(out, v);
- ++i;
- }
- int i;
- typename FormatContext::iterator& out;
- };
-
- public:
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-
- template <typename FormatContext = format_context>
- auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
- auto out = ctx.out();
- *out++ = '(';
- detail::for_each(values, format_each<FormatContext>{0, out});
- *out++ = ')';
- return out;
- }
-};
-
-template <typename T, typename Char> struct is_range {
- static FMT_CONSTEXPR_DECL const bool value =
- detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
- !detail::is_map<T>::value &&
- !std::is_convertible<T, std::basic_string<Char>>::value &&
- !std::is_constructible<detail::std_string_view<Char>, T>::value;
-};
-
-template <typename T, typename Char>
-struct formatter<
- T, Char,
- enable_if_t<
- fmt::is_range<T, Char>::value
-// Workaround a bug in MSVC 2019 and earlier.
-#if !FMT_MSC_VER
- && (is_formattable<detail::value_type<T>, Char>::value ||
- detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
-#endif
- >> {
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-
- template <
- typename FormatContext, typename U,
- FMT_ENABLE_IF(
- std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
- const T, T>>::value)>
- auto format(U& range, FormatContext& ctx) -> decltype(ctx.out()) {
-#ifdef FMT_DEPRECATED_BRACED_RANGES
- Char prefix = '{';
- Char postfix = '}';
-#else
- Char prefix = detail::is_set<T>::value ? '{' : '[';
- Char postfix = detail::is_set<T>::value ? '}' : ']';
-#endif
- auto out = ctx.out();
- *out++ = prefix;
- int i = 0;
- auto it = std::begin(range);
- auto end = std::end(range);
- for (; it != end; ++it) {
- if (i > 0) out = detail::write_delimiter(out);
- out = detail::write_range_entry<Char>(out, *it);
- ++i;
- }
- *out++ = postfix;
- return out;
- }
-};
-
-template <typename T, typename Char>
-struct formatter<
- T, Char,
- enable_if_t<
- detail::is_map<T>::value
-// Workaround a bug in MSVC 2019 and earlier.
-#if !FMT_MSC_VER
- && (is_formattable<detail::value_type<T>, Char>::value ||
- detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
-#endif
- >> {
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-
- template <
- typename FormatContext, typename U,
- FMT_ENABLE_IF(
- std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
- const T, T>>::value)>
- auto format(U& map, FormatContext& ctx) -> decltype(ctx.out()) {
- auto out = ctx.out();
- *out++ = '{';
- int i = 0;
- for (const auto& item : map) {
- if (i > 0) out = detail::write_delimiter(out);
- out = detail::write_range_entry<Char>(out, item.first);
- *out++ = ':';
- *out++ = ' ';
- out = detail::write_range_entry<Char>(out, item.second);
- ++i;
- }
- *out++ = '}';
- return out;
- }
-};
-
-template <typename Char, typename... T> struct tuple_join_view : detail::view {
- const std::tuple<T...>& tuple;
- basic_string_view<Char> sep;
-
- tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
- : 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.
-#ifndef FMT_TUPLE_JOIN_SPECIFIERS
-# define FMT_TUPLE_JOIN_SPECIFIERS 0
-#endif
-
-template <typename Char, typename... T>
-struct formatter<tuple_join_view<Char, T...>, Char> {
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
- }
-
- template <typename FormatContext>
- auto format(const tuple_join_view<Char, T...>& value,
- FormatContext& ctx) const -> typename FormatContext::iterator {
- return do_format(value, ctx,
- std::integral_constant<size_t, sizeof...(T)>());
- }
-
- private:
- std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
-
- template <typename ParseContext>
- FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
- std::integral_constant<size_t, 0>)
- -> decltype(ctx.begin()) {
- return ctx.begin();
- }
-
- template <typename ParseContext, size_t N>
- FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
- std::integral_constant<size_t, N>)
- -> decltype(ctx.begin()) {
- auto end = ctx.begin();
-#if FMT_TUPLE_JOIN_SPECIFIERS
- end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
- if (N > 1) {
- auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
- if (end != end1)
- FMT_THROW(format_error("incompatible format specs for tuple elements"));
- }
-#endif
- return end;
- }
-
- template <typename FormatContext>
- auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
- std::integral_constant<size_t, 0>) const ->
- typename FormatContext::iterator {
- return ctx.out();
- }
-
- template <typename FormatContext, size_t N>
- auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
- std::integral_constant<size_t, N>) const ->
- typename FormatContext::iterator {
- auto out = std::get<sizeof...(T) - N>(formatters_)
- .format(std::get<sizeof...(T) - N>(value.tuple), ctx);
- if (N > 1) {
- out = std::copy(value.sep.begin(), value.sep.end(), out);
- ctx.advance_to(out);
- return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
- }
- return out;
- }
-};
-
-FMT_MODULE_EXPORT_BEGIN
-
-/**
- \rst
- Returns an object that formats `tuple` with elements separated by `sep`.
-
- **Example**::
-
- std::tuple<int, char> t = {1, 'a'};
- fmt::print("{}", fmt::join(t, ", "));
- // Output: "1, a"
- \endrst
- */
-template <typename... T>
-FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
- -> tuple_join_view<char, T...> {
- return {tuple, sep};
-}
-
-template <typename... T>
-FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
- basic_string_view<wchar_t> sep)
- -> tuple_join_view<wchar_t, T...> {
- return {tuple, sep};
-}
-
-/**
- \rst
- Returns an object that formats `initializer_list` with elements separated by
- `sep`.
-
- **Example**::
-
- fmt::print("{}", fmt::join({1, 2, 3}, ", "));
- // Output: "1, 2, 3"
- \endrst
- */
-template <typename T>
-auto join(std::initializer_list<T> list, string_view sep)
- -> join_view<const T*, const T*> {
- return join(std::begin(list), std::end(list), sep);
-}
-
-FMT_MODULE_EXPORT_END
-FMT_END_NAMESPACE
-
-#endif // FMT_RANGES_H_
diff --git a/wpiutil/src/main/native/fmtlib/src/format.cpp b/wpiutil/src/main/native/fmtlib/src/format.cpp
deleted file mode 100644
index ecb8cc7..0000000
--- a/wpiutil/src/main/native/fmtlib/src/format.cpp
+++ /dev/null
@@ -1,124 +0,0 @@
-// Formatting library for C++
-//
-// Copyright (c) 2012 - 2016, Victor Zverovich
-// All rights reserved.
-//
-// For the license information refer to format.h.
-
-#include "fmt/format-inl.h"
-
-FMT_BEGIN_NAMESPACE
-namespace detail {
-
-// DEPRECATED!
-template <typename T = void> struct basic_data {
- FMT_API static constexpr const char 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'}};
- FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
- FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
- FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
- 0};
- FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
- 0};
- FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
- 0x1000000u | ' '};
-};
-
-#ifdef FMT_SHARED
-// Required for -flto, -fivisibility=hidden and -shared to work
-extern template struct basic_data<void>;
-#endif
-
-#if __cplusplus < 201703L
-// DEPRECATED! These are here only for ABI compatiblity.
-template <typename T> constexpr const char basic_data<T>::digits[][2];
-template <typename T> constexpr const char basic_data<T>::hex_digits[];
-template <typename T> constexpr const char basic_data<T>::signs[];
-template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
-template <typename T>
-constexpr const char basic_data<T>::right_padding_shifts[];
-template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
-#endif
-
-template <typename T>
-int format_float(char* buf, std::size_t size, const char* format, int precision,
- T value) {
-#ifdef FMT_FUZZ
- if (precision > 100000)
- throw std::runtime_error(
- "fuzz mode - avoid large allocation inside snprintf");
-#endif
- // Suppress the warning about nonliteral format string.
- int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
- return precision < 0 ? snprintf_ptr(buf, size, format, value)
- : snprintf_ptr(buf, size, format, precision, value);
-}
-
-template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
- FMT_NOEXCEPT;
-template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
- FMT_NOEXCEPT;
-} // namespace detail
-
-// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
-int (*instantiate_format_float)(double, int, detail::float_specs,
- detail::buffer<char>&) = detail::format_float;
-
-#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
-template FMT_API detail::locale_ref::locale_ref(const std::locale& loc);
-template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
-#endif
-
-// Explicit instantiations for char.
-
-template FMT_API auto detail::thousands_sep_impl(locale_ref)
- -> thousands_sep_result<char>;
-template FMT_API char detail::decimal_point_impl(locale_ref);
-
-template FMT_API void detail::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 detail::vformat_to(
- detail::buffer<char>&, string_view,
- basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
-
-template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
- detail::buffer<char>&);
-template FMT_API int detail::snprintf_float(long double, int,
- detail::float_specs,
- detail::buffer<char>&);
-template FMT_API int detail::format_float(double, int, detail::float_specs,
- detail::buffer<char>&);
-template FMT_API int detail::format_float(long double, int, detail::float_specs,
- detail::buffer<char>&);
-
-// Explicit instantiations for wchar_t.
-
-template FMT_API auto detail::thousands_sep_impl(locale_ref)
- -> thousands_sep_result<wchar_t>;
-template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
-
-template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
- const wchar_t*);
-
-template struct detail::basic_data<void>;
-
-FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/include/wpi/Algorithm.h b/wpiutil/src/main/native/include/wpi/Algorithm.h
index d0744dc..1fd2502 100644
--- a/wpiutil/src/main/native/include/wpi/Algorithm.h
+++ b/wpiutil/src/main/native/include/wpi/Algorithm.h
@@ -9,7 +9,7 @@
namespace wpi {
-// Binary insortion into vector; std::log(n) efficiency.
+// Binary insertion into vector; std::log(n) efficiency.
template <typename T>
typename std::vector<T>::iterator insert_sorted(std::vector<T>& vec,
T const& item) {
diff --git a/wpiutil/src/main/native/include/wpi/AlignOf.h b/wpiutil/src/main/native/include/wpi/AlignOf.h
deleted file mode 100644
index adddd13..0000000
--- a/wpiutil/src/main/native/include/wpi/AlignOf.h
+++ /dev/null
@@ -1,146 +0,0 @@
-//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the AlignedCharArray and AlignedCharArrayUnion classes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_ALIGNOF_H
-#define WPIUTIL_WPI_ALIGNOF_H
-
-#include "wpi/Compiler.h"
-#include <cstddef>
-
-namespace wpi {
-
-/// \struct AlignedCharArray
-/// Helper for building an aligned character array type.
-///
-/// This template is used to explicitly build up a collection of aligned
-/// character array types. We have to build these up using a macro and explicit
-/// specialization to cope with MSVC (at least till 2015) where only an
-/// integer literal can be used to specify an alignment constraint. Once built
-/// up here, we can then begin to indirect between these using normal C++
-/// template parameters.
-
-// MSVC requires special handling here.
-#ifndef _MSC_VER
-
-template<std::size_t Alignment, std::size_t Size>
-struct AlignedCharArray {
- alignas(Alignment) char buffer[Size];
-};
-
-#else // _MSC_VER
-
-/// Create a type with an aligned char buffer.
-template<std::size_t Alignment, std::size_t Size>
-struct AlignedCharArray;
-
-// We provide special variations of this template for the most common
-// alignments because __declspec(align(...)) doesn't actually work when it is
-// a member of a by-value function argument in MSVC, even if the alignment
-// request is something reasonably like 8-byte or 16-byte. Note that we can't
-// even include the declspec with the union that forces the alignment because
-// MSVC warns on the existence of the declspec despite the union member forcing
-// proper alignment.
-
-template<std::size_t Size>
-struct AlignedCharArray<1, Size> {
- union {
- char aligned;
- char buffer[Size];
- };
-};
-
-template<std::size_t Size>
-struct AlignedCharArray<2, Size> {
- union {
- short aligned;
- char buffer[Size];
- };
-};
-
-template<std::size_t Size>
-struct AlignedCharArray<4, Size> {
- union {
- int aligned;
- char buffer[Size];
- };
-};
-
-template<std::size_t Size>
-struct AlignedCharArray<8, Size> {
- union {
- double aligned;
- char buffer[Size];
- };
-};
-
-
-// The rest of these are provided with a __declspec(align(...)) and we simply
-// can't pass them by-value as function arguments on MSVC.
-
-#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
- template<std::size_t Size> \
- struct AlignedCharArray<x, Size> { \
- __declspec(align(x)) char buffer[Size]; \
- };
-
-LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
-LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
-LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
-LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
-
-#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
-
-#endif // _MSC_VER
-
-namespace detail {
-template <typename T1,
- typename T2 = char, typename T3 = char, typename T4 = char,
- typename T5 = char, typename T6 = char, typename T7 = char,
- typename T8 = char, typename T9 = char, typename T10 = char>
-class AlignerImpl {
- T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10;
-
- AlignerImpl() = delete;
-};
-
-template <typename T1,
- typename T2 = char, typename T3 = char, typename T4 = char,
- typename T5 = char, typename T6 = char, typename T7 = char,
- typename T8 = char, typename T9 = char, typename T10 = char>
-union SizerImpl {
- char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
- arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
- arr9[sizeof(T9)], arr10[sizeof(T10)];
-};
-} // end namespace detail
-
-/// This union template exposes a suitably aligned and sized character
-/// array member which can hold elements of any of up to ten types.
-///
-/// These types may be arrays, structs, or any other types. The goal is to
-/// expose a char array buffer member which can be used as suitable storage for
-/// a placement new of any of these types. Support for more than ten types can
-/// be added at the cost of more boilerplate.
-template <typename T1,
- typename T2 = char, typename T3 = char, typename T4 = char,
- typename T5 = char, typename T6 = char, typename T7 = char,
- typename T8 = char, typename T9 = char, typename T10 = char>
-struct AlignedCharArrayUnion : wpi::AlignedCharArray<
- alignof(wpi::detail::AlignerImpl<T1, T2, T3, T4, T5,
- T6, T7, T8, T9, T10>),
- sizeof(::wpi::detail::SizerImpl<T1, T2, T3, T4, T5,
- T6, T7, T8, T9, T10>)> {
-};
-} // end namespace wpi
-
-#endif // LLVM_SUPPORT_ALIGNOF_H
diff --git a/wpiutil/src/main/native/include/wpi/Base64.h b/wpiutil/src/main/native/include/wpi/Base64.h
index 41b0062..c410bd0 100644
--- a/wpiutil/src/main/native/include/wpi/Base64.h
+++ b/wpiutil/src/main/native/include/wpi/Base64.h
@@ -6,12 +6,11 @@
#define WPIUTIL_WPI_BASE64_H_
#include <cstddef>
+#include <span>
#include <string>
#include <string_view>
#include <vector>
-#include "wpi/span.h"
-
namespace wpi {
template <typename T>
class SmallVectorImpl;
@@ -26,8 +25,8 @@
size_t Base64Decode(std::string_view encoded, std::vector<uint8_t>* plain);
-span<uint8_t> Base64Decode(std::string_view encoded, size_t* num_read,
- SmallVectorImpl<uint8_t>& buf);
+std::span<uint8_t> Base64Decode(std::string_view encoded, size_t* num_read,
+ SmallVectorImpl<uint8_t>& buf);
void Base64Encode(raw_ostream& os, std::string_view plain);
@@ -36,11 +35,11 @@
std::string_view Base64Encode(std::string_view plain,
SmallVectorImpl<char>& buf);
-void Base64Encode(raw_ostream& os, span<const uint8_t> plain);
+void Base64Encode(raw_ostream& os, std::span<const uint8_t> plain);
-void Base64Encode(span<const uint8_t> plain, std::string* encoded);
+void Base64Encode(std::span<const uint8_t> plain, std::string* encoded);
-std::string_view Base64Encode(span<const uint8_t> plain,
+std::string_view Base64Encode(std::span<const uint8_t> plain,
SmallVectorImpl<char>& buf);
} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/Compiler.h b/wpiutil/src/main/native/include/wpi/Compiler.h
deleted file mode 100644
index 5ceb605..0000000
--- a/wpiutil/src/main/native/include/wpi/Compiler.h
+++ /dev/null
@@ -1,516 +0,0 @@
-//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines several macros, based on the current compiler. This allows
-// use of compiler-specific features in a way that remains portable.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_COMPILER_H
-#define WPIUTIL_WPI_COMPILER_H
-
-#include <new>
-#include <stddef.h>
-
-#if defined(_MSC_VER)
-#include <sal.h>
-#endif
-
-#ifndef __has_feature
-# define __has_feature(x) 0
-#endif
-
-#ifndef __has_extension
-# define __has_extension(x) 0
-#endif
-
-#ifndef __has_attribute
-# define __has_attribute(x) 0
-#endif
-
-#ifndef __has_cpp_attribute
-# define __has_cpp_attribute(x) 0
-#endif
-
-#ifndef __has_builtin
-# define __has_builtin(x) 0
-#endif
-
-/// \macro LLVM_GNUC_PREREQ
-/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
-/// available.
-#ifndef LLVM_GNUC_PREREQ
-# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
-# define LLVM_GNUC_PREREQ(maj, min, patch) \
- ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
- ((maj) << 20) + ((min) << 10) + (patch))
-# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
-# define LLVM_GNUC_PREREQ(maj, min, patch) \
- ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
-# else
-# define LLVM_GNUC_PREREQ(maj, min, patch) 0
-# endif
-#endif
-
-/// \macro LLVM_MSC_PREREQ
-/// Is the compiler MSVC of at least the specified version?
-/// The common \param version values to check for are:
-/// * 1900: Microsoft Visual Studio 2015 / 14.0
-#ifndef LLVM_MSC_PREREQ
-#ifdef _MSC_VER
-#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
-
-// We require at least MSVC 2015.
-#if !LLVM_MSC_PREREQ(1900)
-#error wpiutil requires at least MSVC 2015.
-#endif
-
-#else
-#define LLVM_MSC_PREREQ(version) 0
-#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.
-#ifndef LLVM_HAS_RVALUE_REFERENCE_THIS
-#if __has_feature(cxx_rvalue_references) || LLVM_GNUC_PREREQ(4, 8, 1)
-#define LLVM_HAS_RVALUE_REFERENCE_THIS 1
-#else
-#define LLVM_HAS_RVALUE_REFERENCE_THIS 0
-#endif
-#endif
-
-/// 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
-
-#ifndef LLVM_PREFETCH
-#if defined(__GNUC__)
-#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
-#else
-#define LLVM_PREFETCH(addr, rw, locality)
-#endif
-#endif
-
-#ifndef LLVM_ATTRIBUTE_USED
-#if __has_attribute(used) || LLVM_GNUC_PREREQ(3, 1, 0)
-#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
-#else
-#define LLVM_ATTRIBUTE_USED
-#endif
-#endif
-
-/// LLVM_NODISCARD - Warn if a type or return value is discarded.
-#ifndef LLVM_NODISCARD
-#if __cplusplus > 201402L && __has_cpp_attribute(nodiscard)
-#define LLVM_NODISCARD [[nodiscard]]
-// Detect MSVC directly, since __cplusplus still defaults to old version
-#elif _MSVC_LANG >= 201703L
-#define LLVM_NODISCARD [[nodiscard]]
-#elif _MSC_VER
-#define LLVM_NODISCARD
-#elif !__cplusplus
-// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
-// error when __has_cpp_attribute is given a scoped attribute in C mode.
-#define LLVM_NODISCARD
-#elif __has_cpp_attribute(clang::warn_unused_result)
-#define LLVM_NODISCARD [[clang::warn_unused_result]]
-#else
-#define LLVM_NODISCARD
-#endif
-#endif
-
-// Some compilers warn about unused functions. When a function is sometimes
-// used or not depending on build settings (e.g. a function only called from
-// within "assert"), this attribute can be used to suppress such warnings.
-//
-// However, it shouldn't be used for unused *variables*, as those have a much
-// more portable solution:
-// (void)unused_var_name;
-// Prefer cast-to-void wherever it is sufficient.
-#ifndef LLVM_ATTRIBUTE_UNUSED
-#if __has_attribute(unused) || LLVM_GNUC_PREREQ(3, 1, 0)
-#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
-#else
-#define LLVM_ATTRIBUTE_UNUSED
-#endif
-#endif
-
-#ifndef LLVM_READNONE
-// Prior to clang 3.2, clang did not accept any spelling of
-// __has_attribute(const), so assume it is supported.
-#if defined(__clang__) || defined(__GNUC__)
-// aka 'CONST' but following LLVM Conventions.
-#define LLVM_READNONE __attribute__((__const__))
-#else
-#define LLVM_READNONE
-#endif
-#endif
-
-#ifndef LLVM_READONLY
-#if __has_attribute(pure) || defined(__GNUC__)
-// aka 'PURE' but following LLVM Conventions.
-#define LLVM_READONLY __attribute__((__pure__))
-#else
-#define LLVM_READONLY
-#endif
-#endif
-
-#ifndef LLVM_LIKELY
-#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0)
-#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
-#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
-#else
-#define LLVM_LIKELY(EXPR) (EXPR)
-#define LLVM_UNLIKELY(EXPR) (EXPR)
-#endif
-#endif
-
-/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
-/// mark a method "not for inlining".
-#ifndef LLVM_ATTRIBUTE_NOINLINE
-#if __has_attribute(noinline) || LLVM_GNUC_PREREQ(3, 4, 0)
-#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
-#elif defined(_MSC_VER)
-#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
-#else
-#define LLVM_ATTRIBUTE_NOINLINE
-#endif
-#endif
-
-/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
-/// so, mark a method "always inline" because it is performance sensitive. GCC
-/// 3.4 supported this but is buggy in various cases and produces unimplemented
-/// errors, just use it in GCC 4.0 and later.
-#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
-#if __has_attribute(always_inline) || LLVM_GNUC_PREREQ(4, 0, 0)
-#define LLVM_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline)) inline
-#elif defined(_MSC_VER)
-#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
-#else
-#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
-#endif
-#endif
-
-#ifndef LLVM_ATTRIBUTE_NORETURN
-#ifdef __GNUC__
-#define LLVM_ATTRIBUTE_NORETURN __attribute__((noreturn))
-#elif defined(_MSC_VER)
-#define LLVM_ATTRIBUTE_NORETURN __declspec(noreturn)
-#else
-#define LLVM_ATTRIBUTE_NORETURN
-#endif
-#endif
-
-#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
-#if __has_attribute(returns_nonnull) || LLVM_GNUC_PREREQ(4, 9, 0)
-#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
-#elif defined(_MSC_VER)
-#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
-#else
-#define LLVM_ATTRIBUTE_RETURNS_NONNULL
-#endif
-#endif
-
-/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
-/// pointer that does not alias any other valid pointer.
-#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
-#ifdef __GNUC__
-#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
-#elif defined(_MSC_VER)
-#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
-#else
-#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
-#endif
-#endif
-
-/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
-#ifndef LLVM_FALLTHROUGH
-#if __cplusplus > 201402L && __has_cpp_attribute(fallthrough)
-#define LLVM_FALLTHROUGH [[fallthrough]]
-// Detect MSVC directly, since __cplusplus still defaults to old version
-#elif _MSVC_LANG >= 201703L
-#define LLVM_FALLTHROUGH [[fallthrough]]
-#elif _MSC_VER
-#define LLVM_FALLTHROUGH
-#elif __has_cpp_attribute(gnu::fallthrough)
-#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
-#elif !__cplusplus
-// Workaround for llvm.org/PR23435, since clang 3.6 and below emit a spurious
-// error when __has_cpp_attribute is given a scoped attribute in C mode.
-#define LLVM_FALLTHROUGH
-#elif __has_cpp_attribute(clang::fallthrough)
-#define LLVM_FALLTHROUGH [[clang::fallthrough]]
-#else
-#define LLVM_FALLTHROUGH
-#endif
-#endif
-
-/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
-/// pedantic diagnostics.
-#ifndef LLVM_EXTENSION
-#ifdef __GNUC__
-#define LLVM_EXTENSION __extension__
-#else
-#define LLVM_EXTENSION
-#endif
-#endif
-
-// LLVM_ATTRIBUTE_DEPRECATED(decl, "message")
-#ifndef LLVM_ATTRIBUTE_DEPRECATED
-#if __has_feature(attribute_deprecated_with_message)
-# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
- decl __attribute__((deprecated(message)))
-#elif defined(__GNUC__)
-# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
- decl __attribute__((deprecated))
-#elif defined(_MSC_VER)
-# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
- __declspec(deprecated(message)) decl
-#else
-# define LLVM_ATTRIBUTE_DEPRECATED(decl, message) \
- decl
-#endif
-#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.
-#ifndef LLVM_BUILTIN_UNREACHABLE
-#if __has_builtin(__builtin_unreachable) || LLVM_GNUC_PREREQ(4, 5, 0)
-# define LLVM_BUILTIN_UNREACHABLE __builtin_unreachable()
-#elif defined(_MSC_VER)
-# define LLVM_BUILTIN_UNREACHABLE __assume(false)
-#endif
-#endif
-
-/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
-/// which causes the program to exit abnormally.
-#ifndef LLVM_BUILTIN_TRAP
-#if __has_builtin(__builtin_trap) || LLVM_GNUC_PREREQ(4, 3, 0)
-# define LLVM_BUILTIN_TRAP __builtin_trap()
-#elif defined(_MSC_VER)
-// The __debugbreak intrinsic is supported by MSVC, does not require forward
-// declarations involving platform-specific typedefs (unlike RaiseException),
-// results in a call to vectored exception handlers, and encodes to a short
-// instruction that still causes the trapping behavior we want.
-# define LLVM_BUILTIN_TRAP __debugbreak()
-#else
-# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
-#endif
-#endif
-
-/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
-/// an expression which causes the program to break while running
-/// under a debugger.
-#ifndef LLVM_BUILTIN_DEBUGTRAP
-#if __has_builtin(__builtin_debugtrap)
-# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
-#elif defined(_MSC_VER)
-// The __debugbreak intrinsic is supported by MSVC and breaks while
-// running under the debugger, and also supports invoking a debugger
-// when the OS is configured appropriately.
-# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
-#else
-// Just continue execution when built with compilers that have no
-// support. This is a debugging aid and not intended to force the
-// program to abort if encountered.
-# define LLVM_BUILTIN_DEBUGTRAP
-#endif
-#endif
-
-/// \macro LLVM_ASSUME_ALIGNED
-/// Returns a pointer with an assumed alignment.
-#ifndef LLVM_ASSUME_ALIGNED
-#if __has_builtin(__builtin_assume_aligned) || LLVM_GNUC_PREREQ(4, 7, 0)
-# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
-#elif defined(LLVM_BUILTIN_UNREACHABLE)
-// As of today, clang does not support __builtin_assume_aligned.
-# define LLVM_ASSUME_ALIGNED(p, a) \
- (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
-#else
-# define LLVM_ASSUME_ALIGNED(p, a) (p)
-#endif
-#endif
-
-/// \macro LLVM_ALIGNAS
-/// Used to specify a minimum alignment for a structure or variable.
-#ifndef LLVM_ALIGNAS
-#if __GNUC__ && !__has_feature(cxx_alignas) && !LLVM_GNUC_PREREQ(4, 8, 1)
-# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
-#else
-# define LLVM_ALIGNAS(x) alignas(x)
-#endif
-#endif
-
-/// \macro LLVM_PACKED
-/// Used to specify a packed structure.
-/// LLVM_PACKED(
-/// struct A {
-/// int i;
-/// int j;
-/// int k;
-/// long long l;
-/// });
-///
-/// LLVM_PACKED_START
-/// struct B {
-/// int i;
-/// int j;
-/// int k;
-/// long long l;
-/// };
-/// LLVM_PACKED_END
-#ifndef LLVM_PACKED
-#ifdef _MSC_VER
-# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
-# define LLVM_PACKED_START __pragma(pack(push, 1))
-# define LLVM_PACKED_END __pragma(pack(pop))
-#else
-# define LLVM_PACKED(d) d __attribute__((packed))
-# define LLVM_PACKED_START _Pragma("pack(push, 1)")
-# define LLVM_PACKED_END _Pragma("pack(pop)")
-#endif
-#endif
-
-/// \macro LLVM_PTR_SIZE
-/// A constant integer equivalent to the value of sizeof(void*).
-/// Generally used in combination with LLVM_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_NO_SANITIZE
-/// Disable a particular sanitizer for a function.
-#ifndef LLVM_NO_SANITIZE
-#if __has_attribute(no_sanitize)
-#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
-#else
-#define LLVM_NO_SANITIZE(KIND)
-#endif
-#endif
-
-/// Mark debug helper function definitions like dump() that should not be
-/// stripped from debug builds.
-/// Note that you should also surround dump() functions with
-/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
-/// get stripped in release builds.
-// FIXME: Move this to a private config.h as it's not usable in public headers.
-#ifndef LLVM_DUMP_METHOD
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
-#else
-#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
-#endif
-#endif
-
-/// \macro LLVM_PRETTY_FUNCTION
-/// Gets a user-friendly looking function signature for the current scope
-/// using the best available method on each platform. The exact format of the
-/// resulting string is implementation specific and non-portable, so this should
-/// only be used, for example, for logging or diagnostics.
-#ifndef LLVM_PRETTY_FUNCTION
-#if defined(_MSC_VER)
-#define LLVM_PRETTY_FUNCTION __FUNCSIG__
-#elif defined(__GNUC__) || defined(__clang__)
-#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
-#else
-#define LLVM_PRETTY_FUNCTION __func__
-#endif
-#endif
-
-/// \macro LLVM_THREAD_LOCAL
-/// A thread-local storage specifier which can be used with globals,
-/// extern globals, and static globals.
-///
-/// This is essentially an extremely restricted analog to C++11's thread_local
-/// support, and uses that when available. However, it falls back on
-/// platform-specific or vendor-provided extensions when necessary. These
-/// extensions don't support many of the C++11 thread_local's features. You
-/// should only use this for PODs that you can statically initialize to
-/// some constant value. In almost all circumstances this is most appropriate
-/// for use with a pointer, integer, or small aggregation of pointers and
-/// integers.
-#ifndef LLVM_THREAD_LOCAL
-#if __has_feature(cxx_thread_local)
-#define LLVM_THREAD_LOCAL thread_local
-#elif defined(_MSC_VER)
-// MSVC supports this with a __declspec.
-#define LLVM_THREAD_LOCAL __declspec(thread)
-#else
-// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
-// we only need the restricted functionality that provides.
-#define LLVM_THREAD_LOCAL __thread
-#endif
-#endif
-
-namespace wpi {
-
-/// Allocate a buffer of memory with the given size and alignment.
-///
-/// When the compiler supports aligned operator new, this will use it to to
-/// handle even over-aligned allocations.
-///
-/// However, this doesn't make any attempt to leverage the fancier techniques
-/// like posix_memalign due to portability. It is mostly intended to allow
-/// compatibility with platforms that, after aligned allocation was added, use
-/// reduced default alignment.
-inline void *allocate_buffer(size_t Size, size_t Alignment) {
- return ::operator new(Size
-#ifdef __cpp_aligned_new
- ,
- std::align_val_t(Alignment)
-#endif
- );
-}
-
-/// Deallocate a buffer of memory with the given size and alignment.
-///
-/// If supported, this will used the sized delete operator. Also if supported,
-/// this will pass the alignment to the delete operator.
-///
-/// The pointer must have been allocated with the corresponding new operator,
-/// most likely using the above helper.
-inline void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
- ::operator delete(Ptr
-#ifdef __cpp_sized_deallocation
- ,
- Size
-#endif
-#ifdef __cpp_aligned_new
- ,
- std::align_val_t(Alignment)
-#endif
- );
-}
-
-} // End namespace wpi
-
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/DataLog.h b/wpiutil/src/main/native/include/wpi/DataLog.h
new file mode 100644
index 0000000..cac273c
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/DataLog.h
@@ -0,0 +1,696 @@
+// 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 <functional>
+#include <initializer_list>
+#include <memory>
+#include <span>
+#include <string>
+#include <string_view>
+#include <thread>
+#include <vector>
+
+#include "wpi/DenseMap.h"
+#include "wpi/StringMap.h"
+#include "wpi/condition_variable.h"
+#include "wpi/mutex.h"
+
+namespace wpi {
+class Logger;
+} // namespace wpi
+
+namespace wpi::log {
+
+namespace impl {
+
+enum ControlRecordType {
+ kControlStart = 0,
+ kControlFinish,
+ kControlSetMetadata
+};
+
+} // namespace impl
+
+/**
+ * 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.
+ *
+ * The lifetime of the data log object must be longer than any data log entry
+ * objects that refer to it.
+ *
+ * The data log is periodically flushed to disk. It can also be explicitly
+ * flushed to disk by using the Flush() function.
+ *
+ * Finish() is needed only to indicate in the log that a particular entry is
+ * no longer being used (it releases the name to ID mapping). Finish() is not
+ * required to be called for data to be flushed to disk; entries in the log
+ * are written as Append() calls are being made. In fact, Finish() does not
+ * need to be called at all; this is helpful to avoid shutdown races where the
+ * DataLog object might be destroyed before other objects. It's often not a
+ * good idea to call Finish() from destructors for this reason.
+ *
+ * DataLog calls are thread safe. DataLog uses a typical multiple-supplier,
+ * single-consumer setup. Writes to the log are atomic, but there is no
+ * guaranteed order in the log when multiple threads are writing to it;
+ * whichever thread grabs the write mutex first will get written first.
+ * For this reason (as well as the fact that timestamps can be set to
+ * arbitrary values), records in the log are not guaranteed to be sorted by
+ * timestamp.
+ */
+class DataLog final {
+ public:
+ /**
+ * 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
+ */
+ explicit DataLog(std::string_view dir = "", std::string_view filename = "",
+ double period = 0.25, std::string_view extraHeader = "");
+
+ /**
+ * Construct a new Data Log. The log will be initially created with a
+ * temporary filename.
+ *
+ * @param msglog message logger (will be called from separate thread)
+ * @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
+ */
+ explicit DataLog(wpi::Logger& msglog, std::string_view dir = "",
+ std::string_view filename = "", double period = 0.25,
+ std::string_view 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 when the thread is terminating.
+ *
+ * @param write write function
+ * @param period time between automatic calls to write, in seconds;
+ * this is a time/storage tradeoff
+ * @param extraHeader extra header data
+ */
+ explicit DataLog(std::function<void(std::span<const uint8_t> data)> write,
+ double period = 0.25, std::string_view 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 when the thread is terminating.
+ *
+ * @param msglog message logger (will be called from separate thread)
+ * @param write write function
+ * @param period time between automatic calls to write, in seconds;
+ * this is a time/storage tradeoff
+ * @param extraHeader extra header data
+ */
+ explicit DataLog(wpi::Logger& msglog,
+ std::function<void(std::span<const uint8_t> data)> write,
+ double period = 0.25, std::string_view extraHeader = "");
+
+ ~DataLog();
+ DataLog(const DataLog&) = delete;
+ DataLog& operator=(const DataLog&) = delete;
+ DataLog(DataLog&&) = delete;
+ DataLog& operator=(const DataLog&&) = delete;
+
+ /**
+ * Change log filename.
+ *
+ * @param filename filename
+ */
+ void SetFilename(std::string_view filename);
+
+ /**
+ * Explicitly flushes the log data to disk.
+ */
+ void Flush();
+
+ /**
+ * 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.
+ */
+ void Pause();
+
+ /**
+ * Resumes appending of data records to the log.
+ */
+ void Resume();
+
+ /**
+ * 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 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 Start(std::string_view name, std::string_view type,
+ std::string_view metadata = {}, int64_t timestamp = 0);
+
+ /**
+ * Finish an entry.
+ *
+ * @param entry Entry index
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Finish(int entry, int64_t timestamp = 0);
+
+ /**
+ * Updates the metadata for an entry.
+ *
+ * @param entry Entry index
+ * @param metadata New metadata for the entry
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void SetMetadata(int entry, std::string_view metadata, int64_t timestamp = 0);
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param entry Entry index, as returned by Start()
+ * @param data Data 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.
+ *
+ * @param entry Entry index, as returned by Start()
+ * @param data Data 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);
+
+ void AppendBoolean(int entry, bool value, int64_t timestamp);
+ void AppendInteger(int entry, int64_t value, int64_t timestamp);
+ void AppendFloat(int entry, float value, int64_t timestamp);
+ void AppendDouble(int entry, double value, int64_t timestamp);
+ void AppendString(int entry, std::string_view value, int64_t timestamp);
+ void AppendBooleanArray(int entry, std::span<const bool> arr,
+ int64_t timestamp);
+ void AppendBooleanArray(int entry, std::span<const int> arr,
+ int64_t timestamp);
+ void AppendBooleanArray(int entry, std::span<const uint8_t> arr,
+ int64_t timestamp);
+ void AppendIntegerArray(int entry, std::span<const int64_t> arr,
+ int64_t timestamp);
+ void AppendFloatArray(int entry, std::span<const float> arr,
+ int64_t timestamp);
+ void AppendDoubleArray(int entry, std::span<const double> arr,
+ int64_t timestamp);
+ void AppendStringArray(int entry, std::span<const std::string> arr,
+ int64_t timestamp);
+ void AppendStringArray(int entry, std::span<const std::string_view> arr,
+ int64_t timestamp);
+
+ private:
+ 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
+ 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);
+
+ 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};
+ double m_period;
+ std::string m_extraHeader;
+ std::string m_newFilename;
+ class Buffer;
+ std::vector<Buffer> m_free;
+ std::vector<Buffer> m_outgoing;
+ struct EntryInfo {
+ std::string type;
+ int id{0};
+ };
+ wpi::StringMap<EntryInfo> m_entries;
+ wpi::DenseMap<int, unsigned int> m_entryCounts;
+ int m_lastId = 0;
+ std::thread m_thread;
+};
+
+/**
+ * Log entry base class.
+ */
+class DataLogEntry {
+ protected:
+ DataLogEntry() = default;
+ DataLogEntry(DataLog& log, std::string_view name, std::string_view type,
+ std::string_view metadata = {}, int64_t timestamp = 0)
+ : m_log{&log}, m_entry{log.Start(name, type, metadata, timestamp)} {}
+
+ public:
+ DataLogEntry(const DataLogEntry&) = delete;
+ DataLogEntry& operator=(const DataLogEntry&) = delete;
+
+ DataLogEntry(DataLogEntry&& rhs) : m_log{rhs.m_log}, m_entry{rhs.m_entry} {
+ rhs.m_log = nullptr;
+ }
+ DataLogEntry& operator=(DataLogEntry&& rhs) {
+ if (m_log) {
+ m_log->Finish(m_entry);
+ }
+ m_log = rhs.m_log;
+ rhs.m_log = nullptr;
+ m_entry = rhs.m_entry;
+ return *this;
+ }
+
+ explicit operator bool() const { return m_log != nullptr; }
+
+ /**
+ * Updates the metadata for the entry.
+ *
+ * @param metadata New metadata for the entry
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void SetMetadata(std::string_view metadata, int64_t timestamp = 0) {
+ m_log->SetMetadata(m_entry, metadata, timestamp);
+ }
+
+ /**
+ * Finishes the entry.
+ *
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Finish(int64_t timestamp = 0) { m_log->Finish(m_entry, timestamp); }
+
+ protected:
+ DataLog* m_log = nullptr;
+ int m_entry = 0;
+};
+
+/**
+ * Log arbitrary byte data.
+ */
+class RawLogEntry : public DataLogEntry {
+ public:
+ static constexpr std::string_view kDataType = "raw";
+
+ RawLogEntry() = default;
+ RawLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : RawLogEntry{log, name, {}, kDataType, timestamp} {}
+ RawLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ int64_t timestamp = 0)
+ : RawLogEntry{log, name, metadata, kDataType, timestamp} {}
+ RawLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ std::string_view type, int64_t timestamp = 0)
+ : DataLogEntry{log, name, type, 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(std::span<const uint8_t> data, int64_t timestamp = 0) {
+ m_log->AppendRaw(m_entry, data, timestamp);
+ }
+};
+
+/**
+ * Log boolean values.
+ */
+class BooleanLogEntry : public DataLogEntry {
+ public:
+ static constexpr std::string_view kDataType = "boolean";
+
+ BooleanLogEntry() = default;
+ BooleanLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : BooleanLogEntry{log, name, {}, timestamp} {}
+ BooleanLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param value Value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(bool value, int64_t timestamp = 0) {
+ m_log->AppendBoolean(m_entry, value, timestamp);
+ }
+};
+
+/**
+ * Log integer values.
+ */
+class IntegerLogEntry : public DataLogEntry {
+ public:
+ static constexpr std::string_view kDataType = "int64";
+
+ IntegerLogEntry() = default;
+ IntegerLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : IntegerLogEntry{log, name, {}, timestamp} {}
+ IntegerLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param value Value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(int64_t value, int64_t timestamp = 0) {
+ m_log->AppendInteger(m_entry, value, timestamp);
+ }
+};
+
+/**
+ * Log float values.
+ */
+class FloatLogEntry : public DataLogEntry {
+ public:
+ static constexpr std::string_view kDataType = "float";
+
+ FloatLogEntry() = default;
+ FloatLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : FloatLogEntry{log, name, {}, timestamp} {}
+ FloatLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param value Value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(float value, int64_t timestamp = 0) {
+ m_log->AppendFloat(m_entry, value, timestamp);
+ }
+};
+
+/**
+ * Log double values.
+ */
+class DoubleLogEntry : public DataLogEntry {
+ public:
+ static constexpr std::string_view kDataType = "double";
+
+ DoubleLogEntry() = default;
+ DoubleLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : DoubleLogEntry{log, name, {}, timestamp} {}
+ DoubleLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param value Value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(double value, int64_t timestamp = 0) {
+ m_log->AppendDouble(m_entry, value, timestamp);
+ }
+};
+
+/**
+ * Log string values.
+ */
+class StringLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "string";
+
+ StringLogEntry() = default;
+ StringLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : StringLogEntry{log, name, {}, kDataType, timestamp} {}
+ StringLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ int64_t timestamp = 0)
+ : StringLogEntry{log, name, metadata, kDataType, timestamp} {}
+ StringLogEntry(DataLog& log, std::string_view name, std::string_view metadata,
+ std::string_view type, int64_t timestamp = 0)
+ : DataLogEntry{log, name, type, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param value Value to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::string_view value, int64_t timestamp = 0) {
+ m_log->AppendString(m_entry, value, timestamp);
+ }
+};
+
+/**
+ * Log array of boolean values.
+ */
+class BooleanArrayLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "boolean[]";
+
+ BooleanArrayLogEntry() = default;
+ BooleanArrayLogEntry(DataLog& log, std::string_view name,
+ int64_t timestamp = 0)
+ : BooleanArrayLogEntry{log, name, {}, timestamp} {}
+ BooleanArrayLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log. For find functions to work, timestamp
+ * must be monotonically increasing.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const bool> arr, int64_t timestamp = 0) {
+ m_log->AppendBooleanArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<bool> arr, int64_t timestamp = 0) {
+ Append(std::span{arr.begin(), arr.end()}, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const int> arr, int64_t timestamp = 0) {
+ m_log->AppendBooleanArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<int> arr, int64_t timestamp = 0) {
+ Append(std::span{arr.begin(), arr.end()}, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const uint8_t> arr, int64_t timestamp = 0) {
+ m_log->AppendBooleanArray(m_entry, arr, timestamp);
+ }
+};
+
+/**
+ * Log array of integer values.
+ */
+class IntegerArrayLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "int64[]";
+
+ IntegerArrayLogEntry() = default;
+ IntegerArrayLogEntry(DataLog& log, std::string_view name,
+ int64_t timestamp = 0)
+ : IntegerArrayLogEntry{log, name, {}, timestamp} {}
+ IntegerArrayLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const int64_t> arr, int64_t timestamp = 0) {
+ m_log->AppendIntegerArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<int64_t> arr, int64_t timestamp = 0) {
+ Append({arr.begin(), arr.end()}, timestamp);
+ }
+};
+
+/**
+ * Log array of float values.
+ */
+class FloatArrayLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "float[]";
+
+ FloatArrayLogEntry() = default;
+ FloatArrayLogEntry(DataLog& log, std::string_view name, int64_t timestamp = 0)
+ : FloatArrayLogEntry{log, name, {}, timestamp} {}
+ FloatArrayLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const float> arr, int64_t timestamp = 0) {
+ m_log->AppendFloatArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<float> arr, int64_t timestamp = 0) {
+ Append({arr.begin(), arr.end()}, timestamp);
+ }
+};
+
+/**
+ * Log array of double values.
+ */
+class DoubleArrayLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "double[]";
+
+ DoubleArrayLogEntry() = default;
+ DoubleArrayLogEntry(DataLog& log, std::string_view name,
+ int64_t timestamp = 0)
+ : DoubleArrayLogEntry{log, name, {}, timestamp} {}
+ DoubleArrayLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const double> arr, int64_t timestamp = 0) {
+ m_log->AppendDoubleArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<double> arr, int64_t timestamp = 0) {
+ Append({arr.begin(), arr.end()}, timestamp);
+ }
+};
+
+/**
+ * Log array of string values.
+ */
+class StringArrayLogEntry : public DataLogEntry {
+ public:
+ static constexpr const char* kDataType = "string[]";
+
+ StringArrayLogEntry() = default;
+ StringArrayLogEntry(DataLog& log, std::string_view name,
+ int64_t timestamp = 0)
+ : StringArrayLogEntry{log, name, {}, timestamp} {}
+ StringArrayLogEntry(DataLog& log, std::string_view name,
+ std::string_view metadata, int64_t timestamp = 0)
+ : DataLogEntry{log, name, kDataType, metadata, timestamp} {}
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const std::string> arr, int64_t timestamp = 0) {
+ m_log->AppendStringArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::span<const std::string_view> arr, int64_t timestamp = 0) {
+ m_log->AppendStringArray(m_entry, arr, timestamp);
+ }
+
+ /**
+ * Appends a record to the log.
+ *
+ * @param arr Values to record
+ * @param timestamp Time stamp (may be 0 to indicate now)
+ */
+ void Append(std::initializer_list<std::string_view> arr,
+ int64_t timestamp = 0) {
+ Append(std::span<const std::string_view>{arr.begin(), arr.end()},
+ timestamp);
+ }
+};
+
+} // namespace wpi::log
diff --git a/wpiutil/src/main/native/include/wpi/DataLogReader.h b/wpiutil/src/main/native/include/wpi/DataLogReader.h
new file mode 100644
index 0000000..b1153e4
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/DataLogReader.h
@@ -0,0 +1,369 @@
+// 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 <iterator>
+#include <memory>
+#include <span>
+#include <utility>
+#include <vector>
+
+#include "wpi/MemoryBuffer.h"
+
+namespace wpi::log {
+
+/**
+ * Data contained in a start control record as created by DataLog::Start() when
+ * writing the log. This can be read by calling DataLogRecord::GetStartData().
+ */
+struct StartRecordData {
+ /** Entry ID; this will be used for this entry in future records. */
+ int entry;
+
+ /** Entry name. */
+ std::string_view name;
+
+ /** Type of the stored data for this entry, as a string, e.g. "double". */
+ std::string_view type;
+
+ /** Initial metadata. */
+ std::string_view metadata;
+};
+
+/**
+ * Data contained in a set metadata control record as created by
+ * DataLog::SetMetadata(). This can be read by calling
+ * DataLogRecord::GetSetMetadataData().
+ */
+struct MetadataRecordData {
+ /** Entry ID. */
+ int entry;
+
+ /** New metadata for the entry. */
+ std::string_view metadata;
+};
+
+/**
+ * A record in the data log. May represent either a control record (entry == 0)
+ * or a data record. Used only for reading (e.g. with DataLogReader).
+ */
+class DataLogRecord {
+ public:
+ DataLogRecord() = default;
+ DataLogRecord(int entry, int64_t timestamp, std::span<const uint8_t> data)
+ : m_timestamp{timestamp}, m_data{data}, m_entry{entry} {}
+
+ /**
+ * Gets the entry ID.
+ *
+ * @return entry ID
+ */
+ int GetEntry() const { return m_entry; }
+
+ /**
+ * Gets the record timestamp.
+ *
+ * @return Timestamp, in integer microseconds
+ */
+ int64_t GetTimestamp() const { return m_timestamp; }
+
+ /**
+ * Gets the size of the raw data.
+ *
+ * @return size
+ */
+ size_t GetSize() const { return m_data.size(); }
+
+ /**
+ * Gets the raw data. Use the GetX functions to decode based on the data type
+ * in the entry's start record.
+ */
+ std::span<const uint8_t> GetRaw() const { return m_data; }
+
+ /**
+ * Returns true if the record is a control record.
+ *
+ * @return True if control record, false if normal data record.
+ */
+ bool IsControl() const { return m_entry == 0; }
+
+ /**
+ * Returns true if the record is a start control record. Use GetStartData()
+ * to decode the contents.
+ *
+ * @return True if start control record, false otherwise.
+ */
+ bool IsStart() const;
+
+ /**
+ * Returns true if the record is a finish control record. Use GetFinishEntry()
+ * to decode the contents.
+ *
+ * @return True if finish control record, false otherwise.
+ */
+ bool IsFinish() const;
+
+ /**
+ * Returns true if the record is a set metadata control record. Use
+ * GetSetMetadataData() to decode the contents.
+ *
+ * @return True if set metadata control record, false otherwise.
+ */
+ bool IsSetMetadata() const;
+
+ /**
+ * Decodes a start control record.
+ *
+ * @param[out] out start record decoded data (if successful)
+ * @return True on success, false on error
+ */
+ bool GetStartData(StartRecordData* out) const;
+
+ /**
+ * Decodes a finish control record.
+ *
+ * @param[out] out finish record entry ID (if successful)
+ * @return True on success, false on error
+ */
+ bool GetFinishEntry(int* out) const;
+
+ /**
+ * Decodes a set metadata control record.
+ *
+ * @param[out] out set metadata record decoded data (if successful)
+ * @return True on success, false on error
+ */
+ bool GetSetMetadataData(MetadataRecordData* out) const;
+
+ /**
+ * Decodes a data record as a boolean. Note if the data type (as indicated in
+ * the corresponding start control record for this entry) is not "boolean",
+ * invalid results may be returned.
+ *
+ * @param[out] value boolean value (if successful)
+ * @return True on success, false on error
+ */
+ bool GetBoolean(bool* value) const;
+
+ /**
+ * Decodes a data record as an integer. Note if the data type (as indicated in
+ * the corresponding start control record for this entry) is not "int64",
+ * invalid results may be returned.
+ *
+ * @param[out] value integer value (if successful)
+ * @return True on success, false on error
+ */
+ bool GetInteger(int64_t* value) const;
+
+ /**
+ * Decodes a data record as a float. Note if the data type (as indicated in
+ * the corresponding start control record for this entry) is not "float",
+ * invalid results may be returned.
+ *
+ * @param[out] value float value (if successful)
+ * @return True on success, false on error
+ */
+ bool GetFloat(float* value) const;
+
+ /**
+ * Decodes a data record as a double. Note if the data type (as indicated in
+ * the corresponding start control record for this entry) is not "double",
+ * invalid results may be returned.
+ *
+ * @param[out] value double value (if successful)
+ * @return True on success, false on error
+ */
+ bool GetDouble(double* value) const;
+
+ /**
+ * Decodes a data record as a string. Note if the data type (as indicated in
+ * the corresponding start control record for this entry) is not "string",
+ * invalid results may be returned.
+ *
+ * @param[out] value string value
+ * @return True (never fails)
+ */
+ bool GetString(std::string_view* value) const;
+
+ /**
+ * Decodes a data record as a boolean array. Note if the data type (as
+ * indicated in the corresponding start control record for this entry) is not
+ * "boolean[]", invalid results may be returned.
+ *
+ * @param[out] arr boolean array
+ * @return True (never fails)
+ */
+ bool GetBooleanArray(std::vector<int>* arr) const;
+
+ /**
+ * Decodes a data record as an integer array. Note if the data type (as
+ * indicated in the corresponding start control record for this entry) is not
+ * "int64[]", invalid results may be returned.
+ *
+ * @param[out] arr integer array (if successful)
+ * @return True on success, false on error
+ */
+ bool GetIntegerArray(std::vector<int64_t>* arr) const;
+
+ /**
+ * Decodes a data record as a float array. Note if the data type (as
+ * indicated in the corresponding start control record for this entry) is not
+ * "float[]", invalid results may be returned.
+ *
+ * @param[out] arr float array (if successful)
+ * @return True on success, false on error
+ */
+ bool GetFloatArray(std::vector<float>* arr) const;
+
+ /**
+ * Decodes a data record as a double array. Note if the data type (as
+ * indicated in the corresponding start control record for this entry) is not
+ * "double[]", invalid results may be returned.
+ *
+ * @param[out] arr double array (if successful)
+ * @return True on success, false on error
+ */
+ bool GetDoubleArray(std::vector<double>* arr) const;
+
+ /**
+ * Decodes a data record as a string array. Note if the data type (as
+ * indicated in the corresponding start control record for this entry) is not
+ * "string[]", invalid results may be returned.
+ *
+ * @param[out] arr string array (if successful)
+ * @return True on success, false on error
+ */
+ bool GetStringArray(std::vector<std::string_view>* arr) const;
+
+ private:
+ int64_t m_timestamp{0};
+ std::span<const uint8_t> m_data;
+ int m_entry{-1};
+};
+
+class DataLogReader;
+
+/** DataLogReader iterator. */
+class DataLogIterator {
+ public:
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = DataLogRecord;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ DataLogIterator(const DataLogReader* reader, size_t pos)
+ : m_reader{reader}, m_pos{pos} {}
+
+ bool operator==(const DataLogIterator& oth) const {
+ return m_reader == oth.m_reader && m_pos == oth.m_pos;
+ }
+ bool operator!=(const DataLogIterator& oth) const {
+ return !this->operator==(oth);
+ }
+
+ bool operator<(const DataLogIterator& oth) const { return m_pos < oth.m_pos; }
+ bool operator>(const DataLogIterator& oth) const {
+ return !this->operator<(oth) && !this->operator==(oth);
+ }
+ bool operator<=(const DataLogIterator& oth) const {
+ return !this->operator>(oth);
+ }
+ bool operator>=(const DataLogIterator& oth) const {
+ return !this->operator<(oth);
+ }
+
+ DataLogIterator& operator++();
+
+ DataLogIterator operator++(int) {
+ DataLogIterator tmp = *this;
+ ++*this;
+ return tmp;
+ }
+
+ reference operator*() const;
+
+ pointer operator->() const { return &this->operator*(); }
+
+ private:
+ const DataLogReader* m_reader;
+ size_t m_pos;
+ mutable bool m_valid = false;
+ mutable DataLogRecord m_value;
+};
+
+/** Data log reader (reads logs written by the DataLog class). */
+class DataLogReader {
+ friend class DataLogIterator;
+
+ public:
+ using iterator = DataLogIterator;
+
+ /** Constructs from a memory buffer. */
+ explicit DataLogReader(std::unique_ptr<MemoryBuffer> buffer);
+
+ /** Returns true if the data log is valid (e.g. has a valid header). */
+ explicit operator bool() const { return IsValid(); }
+
+ /** Returns true if the data log is valid (e.g. has a valid header). */
+ bool IsValid() const;
+
+ /**
+ * Gets the data log version. Returns 0 if data log is invalid.
+ *
+ * @return Version number; most significant byte is major, least significant
+ * is minor (so version 1.0 will be 0x0100)
+ */
+ uint16_t GetVersion() const;
+
+ /**
+ * Gets the extra header data.
+ *
+ * @return Extra header data
+ */
+ std::string_view GetExtraHeader() const;
+
+ /**
+ * Gets the buffer identifier, typically the filename.
+ *
+ * @return Identifier string
+ */
+ std::string_view GetBufferIdentifier() const {
+ return m_buf ? m_buf->GetBufferIdentifier() : "Invalid";
+ }
+
+ /** Returns iterator to first record. */
+ iterator begin() const;
+
+ /** Returns end iterator. */
+ iterator end() const { return DataLogIterator{this, SIZE_MAX}; }
+
+ private:
+ std::unique_ptr<MemoryBuffer> m_buf;
+
+ bool GetRecord(size_t* pos, DataLogRecord* out) const;
+ bool GetNextRecord(size_t* pos) const;
+};
+
+inline DataLogIterator& DataLogIterator::operator++() {
+ if (!m_reader->GetNextRecord(&m_pos)) {
+ m_pos = SIZE_MAX;
+ }
+ m_valid = false;
+ return *this;
+}
+
+inline DataLogIterator::reference DataLogIterator::operator*() const {
+ if (!m_valid) {
+ size_t pos = m_pos;
+ if (m_reader->GetRecord(&pos, &m_value)) {
+ m_valid = true;
+ }
+ }
+ return m_value;
+}
+
+} // namespace wpi::log
diff --git a/wpiutil/src/main/native/include/wpi/DenseMapInfo.h b/wpiutil/src/main/native/include/wpi/DenseMapInfo.h
deleted file mode 100644
index b6525a3..0000000
--- a/wpiutil/src/main/native/include/wpi/DenseMapInfo.h
+++ /dev/null
@@ -1,274 +0,0 @@
-//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines DenseMapInfo traits for DenseMap.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
-#define WPIUTIL_WPI_DENSEMAPINFO_H
-
-#include "wpi/Hashing.h"
-#include "wpi/PointerLikeTypeTraits.h"
-#include "wpi/span.h"
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <string_view>
-#include <utility>
-
-namespace wpi {
-
-template<typename T>
-struct DenseMapInfo {
- //static inline T getEmptyKey();
- //static inline T getTombstoneKey();
- //static unsigned getHashValue(const T &Val);
- //static bool isEqual(const T &LHS, const T &RHS);
-};
-
-// Provide DenseMapInfo for all pointers.
-template<typename T>
-struct DenseMapInfo<T*> {
- static inline T* getEmptyKey() {
- uintptr_t Val = static_cast<uintptr_t>(-1);
- Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
- return reinterpret_cast<T*>(Val);
- }
-
- static inline T* getTombstoneKey() {
- uintptr_t Val = static_cast<uintptr_t>(-2);
- Val <<= PointerLikeTypeTraits<T*>::NumLowBitsAvailable;
- return reinterpret_cast<T*>(Val);
- }
-
- static unsigned getHashValue(const T *PtrVal) {
- return (unsigned((uintptr_t)PtrVal) >> 4) ^
- (unsigned((uintptr_t)PtrVal) >> 9);
- }
-
- static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
-};
-
-// Provide DenseMapInfo for chars.
-template<> struct DenseMapInfo<char> {
- static inline char getEmptyKey() { return ~0; }
- static inline char getTombstoneKey() { return ~0 - 1; }
- static unsigned getHashValue(const char& Val) { return Val * 37U; }
-
- static bool isEqual(const char &LHS, const char &RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for unsigned shorts.
-template <> struct DenseMapInfo<unsigned short> {
- static inline unsigned short getEmptyKey() { return 0xFFFF; }
- static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
- static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
-
- static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for unsigned ints.
-template<> struct DenseMapInfo<unsigned> {
- static inline unsigned getEmptyKey() { return ~0U; }
- static inline unsigned getTombstoneKey() { return ~0U - 1; }
- static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
-
- static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for unsigned longs.
-template<> struct DenseMapInfo<unsigned long> {
- static inline unsigned long getEmptyKey() { return ~0UL; }
- static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
-
- static unsigned getHashValue(const unsigned long& Val) {
- return (unsigned)(Val * 37UL);
- }
-
- static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for unsigned long longs.
-template<> struct DenseMapInfo<unsigned long long> {
- static inline unsigned long long getEmptyKey() { return ~0ULL; }
- static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
-
- static unsigned getHashValue(const unsigned long long& Val) {
- return (unsigned)(Val * 37ULL);
- }
-
- static bool isEqual(const unsigned long long& LHS,
- const unsigned long long& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for shorts.
-template <> struct DenseMapInfo<short> {
- static inline short getEmptyKey() { return 0x7FFF; }
- static inline short getTombstoneKey() { return -0x7FFF - 1; }
- static unsigned getHashValue(const short &Val) { return Val * 37U; }
- static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
-};
-
-// Provide DenseMapInfo for ints.
-template<> struct DenseMapInfo<int> {
- static inline int getEmptyKey() { return 0x7fffffff; }
- static inline int getTombstoneKey() { return -0x7fffffff - 1; }
- static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
-
- static bool isEqual(const int& LHS, const int& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for longs.
-template<> struct DenseMapInfo<long> {
- static inline long getEmptyKey() {
- return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
- }
-
- static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
-
- static unsigned getHashValue(const long& Val) {
- return (unsigned)(Val * 37UL);
- }
-
- static bool isEqual(const long& LHS, const long& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for long longs.
-template<> struct DenseMapInfo<long long> {
- static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
- static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
-
- static unsigned getHashValue(const long long& Val) {
- return (unsigned)(Val * 37ULL);
- }
-
- static bool isEqual(const long long& LHS,
- const long long& RHS) {
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for all pairs whose members have info.
-template<typename T, typename U>
-struct DenseMapInfo<std::pair<T, U>> {
- using Pair = std::pair<T, U>;
- using FirstInfo = DenseMapInfo<T>;
- using SecondInfo = DenseMapInfo<U>;
-
- static inline Pair getEmptyKey() {
- return std::make_pair(FirstInfo::getEmptyKey(),
- SecondInfo::getEmptyKey());
- }
-
- static inline Pair getTombstoneKey() {
- return std::make_pair(FirstInfo::getTombstoneKey(),
- SecondInfo::getTombstoneKey());
- }
-
- static unsigned getHashValue(const Pair& PairVal) {
- uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32
- | (uint64_t)SecondInfo::getHashValue(PairVal.second);
- key += ~(key << 32);
- key ^= (key >> 22);
- key += ~(key << 13);
- key ^= (key >> 8);
- key += (key << 3);
- key ^= (key >> 15);
- key += ~(key << 27);
- key ^= (key >> 31);
- return (unsigned)key;
- }
-
- static bool isEqual(const Pair &LHS, const Pair &RHS) {
- return FirstInfo::isEqual(LHS.first, RHS.first) &&
- SecondInfo::isEqual(LHS.second, RHS.second);
- }
-};
-
-// Provide DenseMapInfo for std::string_view.
-template <> struct DenseMapInfo<std::string_view> {
- static inline std::string_view getEmptyKey() {
- return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)),
- 0);
- }
-
- static inline std::string_view getTombstoneKey() {
- return std::string_view(reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)),
- 0);
- }
-
- static unsigned getHashValue(std::string_view Val) {
- assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
- assert(Val.data() != getTombstoneKey().data() &&
- "Cannot hash the tombstone key!");
- return (unsigned)(hash_value(Val));
- }
-
- static bool isEqual(std::string_view LHS, std::string_view RHS) {
- if (RHS.data() == getEmptyKey().data())
- return LHS.data() == getEmptyKey().data();
- if (RHS.data() == getTombstoneKey().data())
- return LHS.data() == getTombstoneKey().data();
- return LHS == RHS;
- }
-};
-
-// Provide DenseMapInfo for spans.
-template <typename T> struct DenseMapInfo<span<T>> {
- static inline span<T> getEmptyKey() {
- return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(0)),
- size_t(0));
- }
-
- static inline span<T> getTombstoneKey() {
- return span<T>(reinterpret_cast<const T *>(~static_cast<uintptr_t>(1)),
- size_t(0));
- }
-
- static unsigned getHashValue(span<T> Val) {
- assert(Val.data() != getEmptyKey().data() && "Cannot hash the empty key!");
- assert(Val.data() != getTombstoneKey().data() &&
- "Cannot hash the tombstone key!");
- return (unsigned)(hash_value(Val));
- }
-
- static bool isEqual(span<T> LHS, span<T> RHS) {
- if (RHS.data() == getEmptyKey().data())
- return LHS.data() == getEmptyKey().data();
- if (RHS.data() == getTombstoneKey().data())
- return LHS.data() == getTombstoneKey().data();
- return LHS == RHS;
- }
-};
-
-template <> struct DenseMapInfo<hash_code> {
- static inline hash_code getEmptyKey() { return hash_code(-1); }
- static inline hash_code getTombstoneKey() { return hash_code(-2); }
- static unsigned getHashValue(hash_code val) { return static_cast<unsigned>(val); }
- static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
-};
-
-} // end namespace wpi
-
-#endif // LLVM_ADT_DENSEMAPINFO_H
diff --git a/wpiutil/src/main/native/include/wpi/DsClient.h b/wpiutil/src/main/native/include/wpi/DsClient.h
deleted file mode 100644
index c24ba3b..0000000
--- a/wpiutil/src/main/native/include/wpi/DsClient.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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 <string>
-#include <string_view>
-
-#include "wpi/Signal.h"
-
-namespace wpi {
-
-class Logger;
-
-namespace uv {
-class Loop;
-class Tcp;
-class Timer;
-} // namespace uv
-
-class DsClient : public std::enable_shared_from_this<DsClient> {
- struct private_init {};
-
- public:
- static std::shared_ptr<DsClient> Create(wpi::uv::Loop& loop,
- wpi::Logger& logger) {
- return std::make_shared<DsClient>(loop, logger, private_init{});
- }
-
- DsClient(wpi::uv::Loop& loop, wpi::Logger& logger, const private_init&);
- ~DsClient();
- DsClient(const DsClient&) = delete;
- DsClient& operator=(const DsClient&) = delete;
-
- void Close();
-
- sig::Signal<std::string_view> setIp;
- sig::Signal<> clearIp;
-
- private:
- void Connect();
- void HandleIncoming(std::string_view in);
- void ParseJson();
-
- wpi::Logger& m_logger;
-
- std::shared_ptr<wpi::uv::Tcp> m_tcp;
- std::shared_ptr<wpi::uv::Timer> m_timer;
-
- std::string m_json;
-};
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/EventLoopRunner.h b/wpiutil/src/main/native/include/wpi/EventLoopRunner.h
deleted file mode 100644
index 5d35d40..0000000
--- a/wpiutil/src/main/native/include/wpi/EventLoopRunner.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_EVENTLOOPRUNNER_H_
-#define WPIUTIL_WPI_EVENTLOOPRUNNER_H_
-
-#include <functional>
-#include <memory>
-
-#include "wpi/SafeThread.h"
-#include "wpi/uv/Loop.h"
-
-namespace wpi {
-
-/**
- * Executes an event loop on a separate thread.
- */
-class EventLoopRunner {
- public:
- using LoopFunc = std::function<void(uv::Loop&)>;
-
- EventLoopRunner();
- virtual ~EventLoopRunner();
-
- /**
- * Stop the loop. Once the loop is stopped it cannot be restarted.
- * This function does not return until the loop has exited.
- */
- void Stop();
-
- /**
- * Run a function asynchronously (once) on the loop.
- * This is safe to call from any thread, but is NOT safe to call from the
- * provided function (it will deadlock).
- * @param func function to execute on the loop
- */
- void ExecAsync(LoopFunc func);
-
- /**
- * Run a function synchronously (once) on the loop.
- * This is safe to call from any thread, but is NOT safe to call from the
- * provided function (it will deadlock).
- * This does not return until the function finishes executing.
- * @param func function to execute on the loop
- */
- void ExecSync(LoopFunc func);
-
- /**
- * Get the loop. If the loop thread is not running, returns nullptr.
- * @return The loop
- */
- std::shared_ptr<uv::Loop> GetLoop();
-
- private:
- class Thread;
- SafeThreadOwner<Thread> m_owner;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_EVENTLOOPRUNNER_H_
diff --git a/wpiutil/src/main/native/include/wpi/EventVector.h b/wpiutil/src/main/native/include/wpi/EventVector.h
new file mode 100644
index 0000000..fc54df7
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/EventVector.h
@@ -0,0 +1,51 @@
+// 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 "wpi/SmallVector.h"
+#include "wpi/Synchronization.h"
+#include "wpi/mutex.h"
+
+namespace wpi {
+struct EventVector {
+ wpi::mutex mutex;
+ wpi::SmallVector<WPI_EventHandle, 4> events;
+
+ /**
+ * Adds an event to the event vector.
+ *
+ * @param handle the event to add
+ */
+ void Add(WPI_EventHandle handle) {
+ std::scoped_lock lock{mutex};
+ events.emplace_back(handle);
+ }
+
+ /**
+ * Removes an event from the event vector.
+ *
+ * @param handle The event to remove
+ */
+ void Remove(WPI_EventHandle handle) {
+ std::scoped_lock lock{mutex};
+ auto it = std::find_if(
+ events.begin(), events.end(),
+ [=](const WPI_EventHandle fromHandle) { return fromHandle == handle; });
+ if (it != events.end()) {
+ events.erase(it);
+ }
+ }
+
+ /**
+ * Wakes up all events in the event vector.
+ */
+ void Wakeup() {
+ std::scoped_lock lock{mutex};
+ for (auto&& handle : events) {
+ wpi::SetEvent(handle);
+ }
+ }
+};
+} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/FunctionExtras.h b/wpiutil/src/main/native/include/wpi/FunctionExtras.h
deleted file mode 100644
index 57bc8dc..0000000
--- a/wpiutil/src/main/native/include/wpi/FunctionExtras.h
+++ /dev/null
@@ -1,308 +0,0 @@
-//===- FunctionExtras.h - Function type erasure utilities -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-/// This file provides a collection of function (or more generally, callable)
-/// type erasure utilities supplementing those provided by the standard library
-/// in `<function>`.
-///
-/// It provides `unique_function`, which works like `std::function` but supports
-/// move-only callable objects.
-///
-/// Future plans:
-/// - Add a `function` that provides const, volatile, and ref-qualified support,
-/// which doesn't work with `std::function`.
-/// - Provide support for specifying multiple signatures to type erase callable
-/// objects with an overload set, such as those produced by generic lambdas.
-/// - Expand to include a copyable utility that directly replaces std::function
-/// but brings the above improvements.
-///
-/// Note that LLVM's utilities are greatly simplified by not supporting
-/// allocators.
-///
-/// If the standard library ever begins to provide comparable facilities we can
-/// consider switching to those.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_FUNCTION_EXTRAS_H
-#define WPIUTIL_WPI_FUNCTION_EXTRAS_H
-
-#include "wpi/Compiler.h"
-#include "wpi/PointerIntPair.h"
-#include "wpi/PointerUnion.h"
-#include <memory>
-#include <type_traits>
-
-namespace wpi {
-
-template <typename FunctionT> class unique_function;
-
-// GCC warns on OutOfLineStorage
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
-#endif
-
-template <typename ReturnT, typename... ParamTs>
-class unique_function<ReturnT(ParamTs...)> {
- static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
-
- // MSVC has a bug and ICEs if we give it a particular dependent value
- // expression as part of the `std::conditional` below. To work around this,
- // we build that into a template struct's constexpr bool.
- template <typename T> struct IsSizeLessThanThresholdT {
- static constexpr bool value = sizeof(T) <= (2 * sizeof(void *));
- };
-
- // Provide a type function to map parameters that won't observe extra copies
- // or moves and which are small enough to likely pass in register to values
- // and all other types to l-value reference types. We use this to compute the
- // types used in our erased call utility to minimize copies and moves unless
- // doing so would force things unnecessarily into memory.
- //
- // The heuristic used is related to common ABI register passing conventions.
- // It doesn't have to be exact though, and in one way it is more strict
- // because we want to still be able to observe either moves *or* copies.
- template <typename T>
- using AdjustedParamT = typename std::conditional<
- !std::is_reference<T>::value &&
- std::is_trivially_copy_constructible<T>::value &&
- std::is_trivially_move_constructible<T>::value &&
- IsSizeLessThanThresholdT<T>::value,
- T, T &>::type;
-
- // The type of the erased function pointer we use as a callback to dispatch to
- // the stored callable when it is trivial to move and destroy.
- using CallPtrT = ReturnT (*)(void *CallableAddr,
- AdjustedParamT<ParamTs>... Params);
- using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
- using DestroyPtrT = void (*)(void *CallableAddr);
-
- /// A struct to hold a single trivial callback with sufficient alignment for
- /// our bitpacking.
- struct alignas(8) TrivialCallback {
- CallPtrT CallPtr;
- };
-
- /// A struct we use to aggregate three callbacks when we need full set of
- /// operations.
- struct alignas(8) NonTrivialCallbacks {
- CallPtrT CallPtr;
- MovePtrT MovePtr;
- DestroyPtrT DestroyPtr;
- };
-
- // Create a pointer union between either a pointer to a static trivial call
- // pointer in a struct or a pointer to a static struct of the call, move, and
- // destroy pointers.
- using CallbackPointerUnionT =
- PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
-
- // The main storage buffer. This will either have a pointer to out-of-line
- // storage or an inline buffer storing the callable.
- union StorageUnionT {
- // For out-of-line storage we keep a pointer to the underlying storage and
- // the size. This is enough to deallocate the memory.
- struct OutOfLineStorageT {
- void *StoragePtr;
- size_t Size;
- size_t Alignment;
- } OutOfLineStorage;
- static_assert(
- sizeof(OutOfLineStorageT) <= InlineStorageSize,
- "Should always use all of the out-of-line storage for inline storage!");
-
- // For in-line storage, we just provide an aligned character buffer. We
- // provide four pointers worth of storage here.
- typename std::aligned_storage<InlineStorageSize, alignof(void *)>::type
- InlineStorage;
- } StorageUnion;
-
- // A compressed pointer to either our dispatching callback or our table of
- // dispatching callbacks and the flag for whether the callable itself is
- // stored inline or not.
- PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
-
- bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
-
- bool isTrivialCallback() const {
- return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
- }
-
- CallPtrT getTrivialCallback() const {
- return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
- }
-
- NonTrivialCallbacks *getNonTrivialCallbacks() const {
- return CallbackAndInlineFlag.getPointer()
- .template get<NonTrivialCallbacks *>();
- }
-
- void *getInlineStorage() { return &StorageUnion.InlineStorage; }
-
- void *getOutOfLineStorage() {
- return StorageUnion.OutOfLineStorage.StoragePtr;
- }
- size_t getOutOfLineStorageSize() const {
- return StorageUnion.OutOfLineStorage.Size;
- }
- size_t getOutOfLineStorageAlignment() const {
- return StorageUnion.OutOfLineStorage.Alignment;
- }
-
- void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
- StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
- }
-
- template <typename CallableT>
- static ReturnT CallImpl(void *CallableAddr, AdjustedParamT<ParamTs>... Params) {
- return (*reinterpret_cast<CallableT *>(CallableAddr))(
- std::forward<ParamTs>(Params)...);
- }
-
- template <typename CallableT>
- static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
- new (LHSCallableAddr)
- CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
- }
-
- template <typename CallableT>
- static void DestroyImpl(void *CallableAddr) noexcept {
- reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
- }
-
-public:
- unique_function() = default;
- unique_function(std::nullptr_t /*null_callable*/) {}
-
- ~unique_function() {
- if (!CallbackAndInlineFlag.getPointer())
- return;
-
- // Cache this value so we don't re-check it after type-erased operations.
- bool IsInlineStorage = isInlineStorage();
-
- if (!isTrivialCallback())
- getNonTrivialCallbacks()->DestroyPtr(
- IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
-
- if (!IsInlineStorage)
- deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
- getOutOfLineStorageAlignment());
- }
-
- unique_function(unique_function &&RHS) noexcept {
- // Copy the callback and inline flag.
- CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
-
- // If the RHS is empty, just copying the above is sufficient.
- if (!RHS)
- return;
-
- if (!isInlineStorage()) {
- // The out-of-line case is easiest to move.
- StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
- } else if (isTrivialCallback()) {
- // Move is trivial, just memcpy the bytes across.
- memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
- } else {
- // Non-trivial move, so dispatch to a type-erased implementation.
- getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
- RHS.getInlineStorage());
- }
-
- // Clear the old callback and inline flag to get back to as-if-null.
- RHS.CallbackAndInlineFlag = {};
-
-#ifndef NDEBUG
- // In debug builds, we also scribble across the rest of the storage.
- memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
-#endif
- }
-
- unique_function &operator=(unique_function &&RHS) noexcept {
- if (this == &RHS)
- return *this;
-
- // Because we don't try to provide any exception safety guarantees we can
- // implement move assignment very simply by first destroying the current
- // object and then move-constructing over top of it.
- this->~unique_function();
- new (this) unique_function(std::move(RHS));
- return *this;
- }
-
- template <typename CallableT>
- unique_function(CallableT Callable,
- std::enable_if_t<
- std::is_invocable_r_v<
- ReturnT, CallableT, ParamTs...>>* = nullptr) {
- bool IsInlineStorage = true;
- void *CallableAddr = getInlineStorage();
- if (sizeof(CallableT) > InlineStorageSize ||
- alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
- IsInlineStorage = false;
- // Allocate out-of-line storage. FIXME: Use an explicit alignment
- // parameter in C++17 mode.
- auto Size = sizeof(CallableT);
- auto Alignment = alignof(CallableT);
- CallableAddr = allocate_buffer(Size, Alignment);
- setOutOfLineStorage(CallableAddr, Size, Alignment);
- }
-
- // Now move into the storage.
- new (CallableAddr) CallableT(std::move(Callable));
-
- // See if we can create a trivial callback. We need the callable to be
- // trivially moved and trivially destroyed so that we don't have to store
- // type erased callbacks for those operations.
- //
- // FIXME: We should use constexpr if here and below to avoid instantiating
- // the non-trivial static objects when unnecessary. While the linker should
- // remove them, it is still wasteful.
- if (std::is_trivially_move_constructible<CallableT>::value &&
- std::is_trivially_destructible<CallableT>::value) {
- // We need to create a nicely aligned object. We use a static variable
- // for this because it is a trivial struct.
- static TrivialCallback Callback = { &CallImpl<CallableT> };
-
- CallbackAndInlineFlag = {&Callback, IsInlineStorage};
- return;
- }
-
- // Otherwise, we need to point at an object that contains all the different
- // type erased behaviors needed. Create a static instance of the struct type
- // here and then use a pointer to that.
- static NonTrivialCallbacks Callbacks = {
- &CallImpl<CallableT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
-
- CallbackAndInlineFlag = {&Callbacks, IsInlineStorage};
- }
-
- ReturnT operator()(ParamTs... Params) {
- void *CallableAddr =
- isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
-
- return (isTrivialCallback()
- ? getTrivialCallback()
- : getNonTrivialCallbacks()->CallPtr)(CallableAddr, Params...);
- }
-
- explicit operator bool() const {
- return (bool)CallbackAndInlineFlag.getPointer();
- }
-};
-
-#if defined(__GNUC__) && !defined(__clang__)
-#pragma GCC diagnostic pop
-#endif
-
-} // end namespace wpi
-
-#endif // WPIUTIL_WPI_FUNCTION_H
diff --git a/wpiutil/src/main/native/include/wpi/HttpParser.h b/wpiutil/src/main/native/include/wpi/HttpParser.h
deleted file mode 100644
index 72e5dad..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpParser.h
+++ /dev/null
@@ -1,227 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPPARSER_H_
-#define WPIUTIL_WPI_HTTPPARSER_H_
-
-#include <stdint.h>
-
-#include <string_view>
-
-#include "wpi/Signal.h"
-#include "wpi/SmallString.h"
-#include "wpi/http_parser.h"
-
-namespace wpi {
-
-/**
- * HTTP protocol parser. Performs incremental parsing with callbacks for each
- * part of the HTTP protocol. As this is incremental, it's suitable for use
- * with event based frameworks that provide arbitrary chunks of data.
- */
-class HttpParser {
- public:
- enum Type {
- kRequest = HTTP_REQUEST,
- kResponse = HTTP_RESPONSE,
- kBoth = HTTP_BOTH
- };
-
- /**
- * Returns the library version. Bits 16-23 contain the major version number,
- * bits 8-15 the minor version number and bits 0-7 the patch level.
- */
- static uint32_t GetParserVersion();
-
- /**
- * Constructor.
- * @param type Type of parser (request or response or both)
- */
- explicit HttpParser(Type type);
-
- /**
- * Reset the parser to initial state.
- * This allows reusing the same parser object from request to request.
- * @param type Type of parser (request or response or both)
- */
- void Reset(Type type);
-
- /**
- * Set the maximum accepted length for URLs, field names, and field values.
- * The default is 1024.
- * @param len maximum length
- */
- void SetMaxLength(size_t len) { m_maxLength = len; }
-
- /**
- * Executes the parser. An empty input is treated as EOF.
- * @param in input data
- * @return Trailing input data after the parse.
- */
- std::string_view Execute(std::string_view in) {
- in.remove_prefix(
- http_parser_execute(&m_parser, &m_settings, in.data(), in.size()));
- return in;
- }
-
- /**
- * Get HTTP major version.
- */
- unsigned int GetMajor() const { return m_parser.http_major; }
-
- /**
- * Get HTTP minor version.
- */
- unsigned int GetMinor() const { return m_parser.http_minor; }
-
- /**
- * Get HTTP status code. Valid only on responses. Valid in and after
- * the OnStatus() callback has been called.
- */
- unsigned int GetStatusCode() const { return m_parser.status_code; }
-
- /**
- * Get HTTP method. Valid only on requests.
- */
- http_method GetMethod() const {
- return static_cast<http_method>(m_parser.method);
- }
-
- /**
- * Determine if an error occurred.
- * @return False if no error.
- */
- bool HasError() const { return m_parser.http_errno != HPE_OK; }
-
- /**
- * Get error number.
- */
- http_errno GetError() const {
- return static_cast<http_errno>(m_parser.http_errno);
- }
-
- /**
- * Abort the parse. Call this from a callback handler to indicate an error.
- * This will result in GetError() returning one of the callback-related
- * errors (e.g. HPE_CB_message_begin).
- */
- void Abort() { m_aborted = true; }
-
- /**
- * Determine if an upgrade header was present and the parser has exited
- * because of that. Should be checked when Execute() returns in addition to
- * checking GetError().
- * @return True if upgrade header, false otherwise.
- */
- bool IsUpgrade() const { return m_parser.upgrade; }
-
- /**
- * If this returns false in the headersComplete or messageComplete
- * callback, then this should be the last message on the connection.
- * If you are the server, respond with the "Connection: close" header.
- * If you are the client, close the connection.
- */
- bool ShouldKeepAlive() const { return http_should_keep_alive(&m_parser); }
-
- /**
- * Pause the parser.
- * @param paused True to pause, false to unpause.
- */
- void Pause(bool paused) { http_parser_pause(&m_parser, paused); }
-
- /**
- * Checks if this is the final chunk of the body.
- */
- bool IsBodyFinal() const { return http_body_is_final(&m_parser); }
-
- /**
- * Get URL. Valid in and after the url callback has been called.
- */
- std::string_view GetUrl() const { return m_urlBuf.str(); }
-
- /**
- * Message begin callback.
- */
- sig::Signal<> messageBegin;
-
- /**
- * URL callback.
- *
- * The parameter to the callback is the complete URL string.
- */
- sig::Signal<std::string_view> url;
-
- /**
- * Status callback.
- *
- * The parameter to the callback is the complete status string.
- * GetStatusCode() can be used to get the numeric status code.
- */
- sig::Signal<std::string_view> status;
-
- /**
- * Header field callback.
- *
- * The parameters to the callback are the field name and field value.
- */
- sig::Signal<std::string_view, std::string_view> header;
-
- /**
- * Headers complete callback.
- *
- * The parameter to the callback is whether the connection should be kept
- * alive. If this is false, then this should be the last message on the
- * connection. If you are the server, respond with the "Connection: close"
- * header. If you are the client, close the connection.
- */
- sig::Signal<bool> headersComplete;
-
- /**
- * Body data callback.
- *
- * The parameters to the callback is the data chunk and whether this is the
- * final chunk of data in the message. Note this callback will be called
- * multiple times arbitrarily (e.g. it's possible that it may be called with
- * just a few characters at a time).
- */
- sig::Signal<std::string_view, bool> body;
-
- /**
- * Headers complete callback.
- *
- * The parameter to the callback is whether the connection should be kept
- * alive. If this is false, then this should be the last message on the
- * connection. If you are the server, respond with the "Connection: close"
- * header. If you are the client, close the connection.
- */
- sig::Signal<bool> messageComplete;
-
- /**
- * Chunk header callback.
- *
- * The parameter to the callback is the chunk size.
- */
- sig::Signal<uint64_t> chunkHeader;
-
- /**
- * Chunk complete callback.
- */
- sig::Signal<> chunkComplete;
-
- private:
- http_parser m_parser;
- http_parser_settings m_settings;
-
- size_t m_maxLength = 1024;
- enum { kStart, kUrl, kStatus, kField, kValue } m_state = kStart;
- SmallString<128> m_urlBuf;
- SmallString<32> m_fieldBuf;
- SmallString<128> m_valueBuf;
-
- bool m_aborted = false;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_HTTPPARSER_H_
diff --git a/wpiutil/src/main/native/include/wpi/HttpServerConnection.h b/wpiutil/src/main/native/include/wpi/HttpServerConnection.h
deleted file mode 100644
index a4d4cf8..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpServerConnection.h
+++ /dev/null
@@ -1,152 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPSERVERCONNECTION_H_
-#define WPIUTIL_WPI_HTTPSERVERCONNECTION_H_
-
-#include <memory>
-#include <string_view>
-
-#include "wpi/HttpParser.h"
-#include "wpi/span.h"
-#include "wpi/uv/Stream.h"
-
-namespace wpi {
-
-class raw_ostream;
-
-class HttpServerConnection {
- public:
- explicit HttpServerConnection(std::shared_ptr<uv::Stream> stream);
- virtual ~HttpServerConnection() = default;
-
- protected:
- /**
- * Process an incoming HTTP request. This is called after the incoming
- * message completes (e.g. from the HttpParser::messageComplete callback).
- *
- * The implementation should read request details from m_request and call the
- * appropriate Send() functions to send a response back to the client.
- */
- virtual void ProcessRequest() = 0;
-
- /**
- * Build common response headers.
- *
- * Called by SendHeader() to send headers common to every response.
- * Each line must be terminated with "\r\n".
- *
- * The default implementation sends the following:
- * "Server: WebServer/1.0\r\n"
- * "Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, "
- * "post-check=0, max-age=0\r\n"
- * "Pragma: no-cache\r\n"
- * "Expires: Mon, 3 Jan 2000 12:34:56 GMT\r\n"
- *
- * These parameters should ensure the browser does not cache the response.
- * A browser should connect for each file and not serve files from its cache.
- *
- * @param os response stream
- */
- virtual void BuildCommonHeaders(raw_ostream& os);
-
- /**
- * Build HTTP response header, along with other header information like
- * mimetype. Calls BuildCommonHeaders().
- *
- * @param os response stream
- * @param code HTTP response code (e.g. 200)
- * @param codeText HTTP response code text (e.g. "OK")
- * @param contentType MIME content type (e.g. "text/plain")
- * @param contentLength Length of content. If 0 is provided, m_keepAlive will
- * be set to false.
- * @param extra Extra HTTP headers to send, including final "\r\n"
- */
- virtual void BuildHeader(raw_ostream& os, int code, std::string_view codeText,
- std::string_view contentType, uint64_t contentLength,
- std::string_view extra = {});
-
- /**
- * Send data to client.
- *
- * This is a convenience wrapper around m_stream.Write() to provide
- * auto-close functionality.
- *
- * @param bufs Buffers to write. Deallocate() will be called on each
- * buffer after the write completes. If different behavior
- * is desired, call m_stream.Write() directly instead.
- * @param closeAfter close the connection after the write completes
- */
- void SendData(span<const uv::Buffer> bufs, bool closeAfter = false);
-
- /**
- * Send HTTP response, along with other header information like mimetype.
- * Calls BuildHeader().
- *
- * @param code HTTP response code (e.g. 200)
- * @param codeText HTTP response code text (e.g. "OK")
- * @param contentType MIME content type (e.g. "text/plain")
- * @param content Response message content
- * @param extraHeader Extra HTTP headers to send, including final "\r\n"
- */
- virtual void SendResponse(int code, std::string_view codeText,
- std::string_view contentType,
- std::string_view content,
- std::string_view extraHeader = {});
-
- /**
- * Send HTTP response from static data, along with other header information
- * like mimetype. Calls BuildHeader(). Supports gzip pre-compressed data
- * (it will decompress if the client does not accept gzip encoded data).
- * Unlike SendResponse(), content is not copied and its contents must remain
- * valid for an unspecified lifetime.
- *
- * @param code HTTP response code (e.g. 200)
- * @param codeText HTTP response code text (e.g. "OK")
- * @param contentType MIME content type (e.g. "text/plain")
- * @param content Response message content
- * @param gzipped True if content is gzip compressed
- * @param extraHeader Extra HTTP headers to send, including final "\r\n"
- */
- virtual void SendStaticResponse(int code, std::string_view codeText,
- std::string_view contentType,
- std::string_view content, bool gzipped,
- std::string_view extraHeader = {});
-
- /**
- * Send error header and message.
- * This provides standard code responses for 400, 401, 403, 404, 500, and 503.
- * Other codes will be reported as 501. For arbitrary code handling, use
- * SendResponse() instead.
- *
- * @param code HTTP error code (e.g. 404)
- * @param message Additional message text
- */
- virtual void SendError(int code, std::string_view message = {});
-
- /** The HTTP request. */
- HttpParser m_request{HttpParser::kRequest};
-
- /** Whether the connection should be kept alive. */
- bool m_keepAlive = false;
-
- /** If gzip is an acceptable encoding for responses. */
- bool m_acceptGzip = false;
-
- /** The underlying stream for the connection. */
- uv::Stream& m_stream;
-
- /** The header reader connection. */
- sig::ScopedConnection m_dataConn;
-
- /** The end stream connection. */
- sig::ScopedConnection m_endConn;
-
- /** The message complete connection. */
- sig::Connection m_messageCompleteConn;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_HTTPSERVERCONNECTION_H_
diff --git a/wpiutil/src/main/native/include/wpi/HttpUtil.h b/wpiutil/src/main/native/include/wpi/HttpUtil.h
deleted file mode 100644
index b10d127..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpUtil.h
+++ /dev/null
@@ -1,422 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPUTIL_H_
-#define WPIUTIL_WPI_HTTPUTIL_H_
-
-#include <initializer_list>
-#include <memory>
-#include <optional>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-#include "wpi/NetworkStream.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/StringMap.h"
-#include "wpi/raw_istream.h"
-#include "wpi/raw_socket_istream.h"
-#include "wpi/raw_socket_ostream.h"
-#include "wpi/span.h"
-
-namespace wpi {
-
-// Unescape a %xx-encoded URI.
-// @param buf Buffer for output
-// @param error Set to true if an error occurred
-// @return Escaped string
-std::string_view UnescapeURI(std::string_view str, SmallVectorImpl<char>& buf,
- bool* error);
-
-// Escape a string with %xx-encoding.
-// @param buf Buffer for output
-// @param spacePlus If true, encodes spaces to '+' rather than "%20"
-// @return Escaped string
-std::string_view EscapeURI(std::string_view str, SmallVectorImpl<char>& buf,
- bool spacePlus = true);
-
-// Parse a set of HTTP headers. Saves just the Content-Type and Content-Length
-// fields.
-// @param is Input stream
-// @param contentType If not null, Content-Type contents are saved here.
-// @param contentLength If not null, Content-Length contents are saved here.
-// @return False if error occurred in input stream
-bool ParseHttpHeaders(raw_istream& is, SmallVectorImpl<char>* contentType,
- SmallVectorImpl<char>* contentLength);
-
-// Look for a MIME multi-part boundary. On return, the input stream will
-// be located at the character following the boundary (usually "\r\n").
-// @param is Input stream
-// @param boundary Boundary string to scan for (not including "--" prefix)
-// @param saveBuf If not null, all scanned characters up to but not including
-// the boundary are saved to this string
-// @return False if error occurred on input stream, true if boundary found.
-bool FindMultipartBoundary(wpi::raw_istream& is, std::string_view boundary,
- std::string* saveBuf);
-
-/**
- * Map for looking up elements of the query portion of a URI. Does not
- * handle multiple elements with the same name. This is a reference type;
- * it does not make a copy of the query string, so it is important that the
- * query string has a lifetime at least as long as this object.
- */
-class HttpQueryMap {
- public:
- /**
- * Constructs an empty map (with no entries).
- */
- HttpQueryMap() = default;
-
- /**
- * Constructs from an escaped query string. Note: does not make a copy of
- * the query string, so it must not be a temporary.
- *
- * @param query query string
- */
- explicit HttpQueryMap(std::string_view query);
-
- /**
- * Gets an element of the query string. Both the name and the returned
- * value are unescaped strings.
- *
- * @param name name (unescaped)
- * @param buf result buffer for value
- * @return Optional unescaped value. Returns an empty optional if the
- * name is not present in the query map.
- */
- std::optional<std::string_view> Get(std::string_view name,
- SmallVectorImpl<char>& buf) const;
-
- private:
- StringMap<std::string_view> m_elems;
-};
-
-class HttpPathRef;
-
-/**
- * Class for HTTP path matching. A root path is represented as a single
- * empty element, otherwise the path consists of each non-empty element
- * between the '/' characters:
- * - "" -> []
- * - "/" -> [""]
- * - "/foo" -> ["foo"]
- * - "/foo/bar" -> ["foo", "bar"]
- * - "/foo//bar/" -> ["foo", "bar"]
- *
- * All path elements are unescaped.
- */
-class HttpPath {
- public:
- /**
- * Constructs an empty HTTP path.
- */
- HttpPath() = default;
-
- /**
- * Constructs a HTTP path from an escaped path string. Makes a copy of the
- * path, so it's safe to be a temporary.
- */
- explicit HttpPath(std::string_view path);
-
- /**
- * Evaluates to true if the path is not empty.
- */
- explicit operator bool() const { return !empty(); }
-
- /**
- * Returns true if the path has no elements.
- */
- bool empty() const { return m_pathEnds.empty(); }
-
- /**
- * Returns number of elements in the path.
- */
- size_t size() const { return m_pathEnds.size(); }
-
- /**
- * Returns true if the path exactly matches the provided match list.
- *
- * @param match match list
- * @return True if path equals match list
- */
- bool equals(std::initializer_list<std::string_view> match) const {
- return equals(0, {match.begin(), match.end()});
- }
- bool equals(span<const std::string_view> match) const {
- return equals(0, match);
- }
- bool equals(std::string_view match) const { return equals(0, {match}); }
-
- /**
- * Returns true if the elements of the path starting at the "start" element
- * match the provided match list, and there are no additional elements.
- *
- * @param start element to start matching at
- * @param match match list
- * @return True if match
- */
- bool equals(size_t start,
- std::initializer_list<std::string_view> match) const {
- return equals(start, {match.begin(), match.end()});
- }
- bool equals(size_t start, span<const std::string_view> match) const {
- if (m_pathEnds.size() != (start + match.size())) {
- return false;
- }
- return startswith(start, match);
- }
- bool equals(size_t start, std::string_view match) const {
- return equals(start, {match});
- }
-
- /**
- * Returns true if the first elements of the path match the provided match
- * list. The path may have additional elements.
- *
- * @param match match list
- * @return True if path starts with match list
- */
- bool startswith(std::initializer_list<std::string_view> match) const {
- return startswith(0, {match.begin(), match.end()});
- }
- bool startswith(span<const std::string_view> match) const {
- return startswith(0, match);
- }
- bool startswith(std::string_view match) const {
- return startswith(0, {match});
- }
-
- /**
- * Returns true if the elements of the path starting at the "start" element
- * match the provided match list. The path may have additional elements.
- *
- * @param start element to start matching at
- * @param match match list
- * @return True if path starting at the start element matches the match list
- */
- bool startswith(size_t start,
- std::initializer_list<std::string_view> match) const {
- return startswith(start, {match.begin(), match.end()});
- }
-
- bool startswith(size_t start, span<const std::string_view> match) const;
-
- bool startswith(size_t start, std::string_view match) const {
- return startswith(start, {match});
- }
-
- /**
- * Gets a single element of the path.
- */
- std::string_view operator[](size_t n) const;
-
- /**
- * Returns a path reference with the first N elements of the path removed.
- */
- HttpPathRef drop_front(size_t n) const;
-
- private:
- SmallString<128> m_pathBuf;
- SmallVector<size_t, 16> m_pathEnds;
-};
-
-/**
- * Proxy reference object for a portion of a HttpPath.
- */
-class HttpPathRef {
- public:
- HttpPathRef() = default;
- /*implicit*/ HttpPathRef(const HttpPath& path, // NOLINT
- size_t start = 0)
- : m_path(&path), m_start(start) {}
-
- explicit operator bool() const { return !empty(); }
- bool empty() const { return m_path && m_path->size() == m_start; }
- size_t size() const { return m_path ? m_path->size() - m_start : 0; }
-
- bool equals(std::initializer_list<std::string_view> match) const {
- return equals(0, {match.begin(), match.end()});
- }
- bool equals(span<const std::string_view> match) const {
- return equals(0, match);
- }
- bool equals(std::string_view match) const { return equals(0, {match}); }
-
- bool equals(size_t start,
- std::initializer_list<std::string_view> match) const {
- return equals(start, {match.begin(), match.end()});
- }
- bool equals(size_t start, span<const std::string_view> match) const {
- return m_path ? m_path->equals(m_start + start, match) : false;
- }
- bool equals(size_t start, std::string_view match) const {
- return equals(start, {match});
- }
-
- bool startswith(std::initializer_list<std::string_view> match) const {
- return startswith(0, {match.begin(), match.end()});
- }
- bool startswith(span<const std::string_view> match) const {
- return startswith(0, match);
- }
- bool startswith(std::string_view match) const {
- return startswith(0, {match});
- }
-
- bool startswith(size_t start,
- std::initializer_list<std::string_view> match) const {
- return startswith(start, {match.begin(), match.end()});
- }
- bool startswith(size_t start, span<const std::string_view> match) const {
- return m_path ? m_path->startswith(m_start + start, match) : false;
- }
- bool startswith(size_t start, std::string_view match) const {
- return startswith(start, {match});
- }
-
- std::string_view operator[](size_t n) const {
- return m_path ? m_path->operator[](m_start + n) : std::string_view{};
- }
- HttpPathRef drop_front(size_t n) const {
- return m_path ? m_path->drop_front(m_start + n) : HttpPathRef{};
- }
-
- private:
- const HttpPath* m_path = nullptr;
- size_t m_start = 0;
-};
-
-class HttpLocation {
- public:
- HttpLocation() = default;
- HttpLocation(std::string_view url_, bool* error, std::string* errorMsg);
-
- std::string url; // retain copy
- std::string user; // unescaped
- std::string password; // unescaped
- std::string host;
- int port;
- std::string path; // escaped, not including leading '/'
- std::vector<std::pair<std::string, std::string>> params; // unescaped
- std::string fragment;
-};
-
-class HttpRequest {
- public:
- HttpRequest() = default;
-
- explicit HttpRequest(const HttpLocation& loc)
- : host{loc.host}, port{loc.port} {
- SetPath(loc.path, loc.params);
- SetAuth(loc);
- }
-
- template <typename T>
- HttpRequest(const HttpLocation& loc, const T& extraParams);
-
- HttpRequest(const HttpLocation& loc, std::string_view path_)
- : host{loc.host}, port{loc.port}, path{path_} {
- SetAuth(loc);
- }
-
- template <typename T>
- HttpRequest(const HttpLocation& loc, std::string_view path_, const T& params)
- : host{loc.host}, port{loc.port} {
- SetPath(path_, params);
- SetAuth(loc);
- }
-
- SmallString<128> host;
- int port;
- std::string auth;
- SmallString<128> path;
-
- private:
- void SetAuth(const HttpLocation& loc);
- template <typename T>
- void SetPath(std::string_view path_, const T& params);
-
- template <typename T>
- static std::string_view GetFirst(const T& elem) {
- return elem.first;
- }
- template <typename T>
- static std::string_view GetFirst(const StringMapEntry<T>& elem) {
- return elem.getKey();
- }
- template <typename T>
- static std::string_view GetSecond(const T& elem) {
- return elem.second;
- }
-};
-
-class HttpConnection {
- public:
- HttpConnection(std::unique_ptr<wpi::NetworkStream> stream_, int timeout)
- : stream{std::move(stream_)}, is{*stream, timeout}, os{*stream, true} {}
-
- bool Handshake(const HttpRequest& request, std::string* warnMsg);
-
- std::unique_ptr<wpi::NetworkStream> stream;
- wpi::raw_socket_istream is;
- wpi::raw_socket_ostream os;
-
- // Valid after Handshake() is successful
- SmallString<64> contentType;
- SmallString<64> contentLength;
-
- explicit operator bool() const { return stream && !is.has_error(); }
-};
-
-class HttpMultipartScanner {
- public:
- explicit HttpMultipartScanner(std::string_view boundary,
- bool saveSkipped = false) {
- Reset(saveSkipped);
- SetBoundary(boundary);
- }
-
- // Change the boundary. This is only safe to do when IsDone() is true (or
- // immediately after construction).
- void SetBoundary(std::string_view boundary);
-
- // Reset the scanner. This allows reuse of internal buffers.
- void Reset(bool saveSkipped = false);
-
- // Execute the scanner. Will automatically call Reset() on entry if IsDone()
- // is true.
- // @param in input data
- // @return the input not consumed; empty if all input consumed
- std::string_view Execute(std::string_view in);
-
- // Returns true when the boundary has been found.
- bool IsDone() const { return m_state == kDone; }
-
- // Get the skipped data. Will be empty if saveSkipped was false.
- std::string_view GetSkipped() const {
- return m_saveSkipped ? std::string_view{m_buf} : std::string_view{};
- }
-
- private:
- SmallString<64> m_boundaryWith, m_boundaryWithout;
-
- // Internal state
- enum State { kBoundary, kPadding, kDone };
- State m_state;
- size_t m_posWith, m_posWithout;
- enum Dashes { kUnknown, kWith, kWithout };
- Dashes m_dashes;
-
- // Buffer
- bool m_saveSkipped;
- std::string m_buf;
-};
-
-} // namespace wpi
-
-#include "HttpUtil.inc"
-
-#endif // WPIUTIL_WPI_HTTPUTIL_H_
diff --git a/wpiutil/src/main/native/include/wpi/HttpUtil.inc b/wpiutil/src/main/native/include/wpi/HttpUtil.inc
deleted file mode 100644
index 726cdfb..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpUtil.inc
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPUTIL_INC_
-#define WPIUTIL_WPI_HTTPUTIL_INC_
-
-#include <utility>
-
-#include "wpi/HttpUtil.h"
-
-namespace wpi {
-
-inline HttpPathRef HttpPath::drop_front(size_t n) const {
- return HttpPathRef(*this, n);
-}
-
-template <typename T>
-HttpRequest::HttpRequest(const HttpLocation& loc, const T& extraParams)
- : host{loc.host}, port{loc.port} {
- StringMap<std::string_view> params;
- for (const auto& p : loc.params) {
- params.insert(std::make_pair(GetFirst(p), GetSecond(p)));
- }
- for (const auto& p : extraParams) {
- params.insert(std::make_pair(GetFirst(p), GetSecond(p)));
- }
- SetPath(loc.path, params);
- SetAuth(loc);
-}
-
-template <typename T>
-void HttpRequest::SetPath(std::string_view path_, const T& params) {
- // Build location including query string
- raw_svector_ostream pathOs{path};
- pathOs << path_;
- bool first = true;
- for (const auto& param : params) {
- if (first) {
- pathOs << '?';
- first = false;
- } else {
- pathOs << '&';
- }
- SmallString<64> escapeBuf;
- pathOs << EscapeURI(GetFirst(param), escapeBuf, false);
- if (!GetSecond(param).empty()) {
- pathOs << '=' << EscapeURI(GetSecond(param), escapeBuf, false);
- }
- }
-}
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_HTTPUTIL_INC_
diff --git a/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.h b/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.h
deleted file mode 100644
index d89b61f..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_H_
-#define WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_H_
-
-#include <initializer_list>
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/HttpServerConnection.h"
-#include "wpi/SmallVector.h"
-#include "wpi/WebSocket.h"
-#include "wpi/WebSocketServer.h"
-#include "wpi/span.h"
-#include "wpi/uv/Stream.h"
-
-namespace wpi {
-
-/**
- * A server-side HTTP connection that also accepts WebSocket upgrades.
- *
- * @tparam Derived derived class for std::enable_shared_from_this.
- */
-template <typename Derived>
-class HttpWebSocketServerConnection
- : public HttpServerConnection,
- public std::enable_shared_from_this<Derived> {
- public:
- /**
- * Constructor.
- *
- * @param stream network stream
- * @param protocols Acceptable subprotocols
- */
- HttpWebSocketServerConnection(std::shared_ptr<uv::Stream> stream,
- span<const std::string_view> protocols);
-
- /**
- * Constructor.
- *
- * @param stream network stream
- * @param protocols Acceptable subprotocols
- */
- HttpWebSocketServerConnection(
- std::shared_ptr<uv::Stream> stream,
- std::initializer_list<std::string_view> protocols)
- : HttpWebSocketServerConnection(stream,
- {protocols.begin(), protocols.end()}) {}
-
- protected:
- /**
- * Check that an incoming WebSocket upgrade is okay. This is called prior
- * to accepting the upgrade (so prior to ProcessWsUpgrade()).
- *
- * The implementation should check other headers and return true if the
- * WebSocket connection should be accepted.
- *
- * @param protocol negotiated subprotocol
- */
- virtual bool IsValidWsUpgrade(std::string_view protocol) { return true; }
-
- /**
- * Process an incoming WebSocket upgrade. This is called after the header
- * reader has been disconnected and the websocket has been accepted.
- *
- * The implementation should set up appropriate callbacks on the websocket
- * object to continue communication.
- *
- * @note When a WebSocket upgrade occurs, the stream user data is replaced
- * with the websocket, and the websocket user data points to "this".
- * Replace the websocket user data with caution!
- */
- virtual void ProcessWsUpgrade() = 0;
-
- /**
- * WebSocket connection; not valid until ProcessWsUpgrade is called.
- */
- WebSocket* m_websocket = nullptr;
-
- private:
- WebSocketServerHelper m_helper;
- SmallVector<std::string, 2> m_protocols;
-};
-
-} // namespace wpi
-
-#include "HttpWebSocketServerConnection.inc"
-
-#endif // WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_H_
diff --git a/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.inc b/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.inc
deleted file mode 100644
index 68b9f2d..0000000
--- a/wpiutil/src/main/native/include/wpi/HttpWebSocketServerConnection.inc
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_INC_
-#define WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_INC_
-
-#include <memory>
-
-#include "wpi/HttpWebSocketServerConnection.h"
-
-namespace wpi {
-
-template <typename Derived>
-HttpWebSocketServerConnection<Derived>::HttpWebSocketServerConnection(
- std::shared_ptr<uv::Stream> stream, span<const std::string_view> protocols)
- : HttpServerConnection{stream},
- m_helper{m_request},
- m_protocols{protocols.begin(), protocols.end()} {
- // Handle upgrade event
- m_helper.upgrade.connect([this] {
- // Negotiate sub-protocol
- SmallVector<std::string_view, 2> protocols{m_protocols.begin(),
- m_protocols.end()};
- std::string_view protocol = m_helper.MatchProtocol(protocols).second;
-
- // Check that the upgrade is valid
- if (!IsValidWsUpgrade(protocol)) {
- return;
- }
-
- // Disconnect HttpServerConnection header reader
- m_dataConn.disconnect();
- m_messageCompleteConn.disconnect();
-
- // Accepting the stream may destroy this (as it replaces the stream user
- // data), so grab a shared pointer first.
- auto self = this->shared_from_this();
-
- // Accept the upgrade
- auto ws = m_helper.Accept(m_stream, protocol);
-
- // Set this as the websocket user data to keep it around
- ws->SetData(self);
-
- // Store in member
- m_websocket = ws.get();
-
- // Call derived class function
- ProcessWsUpgrade();
- });
-}
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_HTTPWEBSOCKETSERVERCONNECTION_INC_
diff --git a/wpiutil/src/main/native/include/wpi/Logger.h b/wpiutil/src/main/native/include/wpi/Logger.h
index 807e472..883336f 100644
--- a/wpiutil/src/main/native/include/wpi/Logger.h
+++ b/wpiutil/src/main/native/include/wpi/Logger.h
@@ -45,12 +45,11 @@
void LogV(unsigned int level, const char* file, unsigned int line,
fmt::string_view format, fmt::format_args args);
- template <typename S, typename... Args>
+ template <typename... Args>
void Log(unsigned int level, const char* file, unsigned int line,
- const S& format, Args&&... args) {
+ fmt::string_view format, Args&&... args) {
if (m_func && level >= m_min_level) {
- LogV(level, file, line, format,
- fmt::make_args_checked<Args...>(format, args...));
+ LogV(level, file, line, format, fmt::make_format_args(args...));
}
}
@@ -61,15 +60,25 @@
unsigned int m_min_level = 20;
};
-#define WPI_LOG(logger_inst, level, format, ...) \
- logger_inst.Log(level, __FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
+// C++20 relaxed the number of arguments to variadics, but Apple Clang's
+// warnings haven't caught up yet: https://stackoverflow.com/a/67996331
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#endif
+
+#define WPI_LOG(logger_inst, level, format, ...) \
+ if ((logger_inst).HasLogger() && level >= (logger_inst).min_level()) { \
+ (logger_inst) \
+ .Log(level, __FILE__, __LINE__, \
+ FMT_STRING(format) __VA_OPT__(, ) __VA_ARGS__); \
+ }
#define WPI_ERROR(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, format, __VA_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, format __VA_OPT__(, ) __VA_ARGS__)
#define WPI_WARNING(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, format, __VA_ARGS__)
+ 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_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_INFO, format __VA_OPT__(, ) __VA_ARGS__)
#ifdef NDEBUG
#define WPI_DEBUG(inst, format, ...) \
@@ -89,15 +98,15 @@
} while (0)
#else
#define WPI_DEBUG(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, format, __VA_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, format __VA_OPT__(, ) __VA_ARGS__)
#define WPI_DEBUG1(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, format, __VA_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, format __VA_OPT__(, ) __VA_ARGS__)
#define WPI_DEBUG2(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, format, __VA_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, format __VA_OPT__(, ) __VA_ARGS__)
#define WPI_DEBUG3(inst, format, ...) \
- WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, format, __VA_ARGS__)
+ 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_ARGS__)
+ WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, format __VA_OPT__(, ) __VA_ARGS__)
#endif
} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/ManagedStatic.h b/wpiutil/src/main/native/include/wpi/ManagedStatic.h
deleted file mode 100644
index 28c11fa..0000000
--- a/wpiutil/src/main/native/include/wpi/ManagedStatic.h
+++ /dev/null
@@ -1,104 +0,0 @@
-//===-- llvm/Support/ManagedStatic.h - Static Global wrapper ----*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the ManagedStatic class and the wpi_shutdown() function.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_MANAGEDSTATIC_H
-#define WPIUTIL_WPI_MANAGEDSTATIC_H
-
-#include <atomic>
-#include <cstddef>
-
-namespace wpi {
-
-/// object_creator - Helper method for ManagedStatic.
-template <class C> struct object_creator {
- static void *call() { return new C(); }
-};
-
-/// object_deleter - Helper method for ManagedStatic.
-///
-template <typename T> struct object_deleter {
- static void call(void *Ptr) { delete (T *)Ptr; }
-};
-template <typename T, size_t N> struct object_deleter<T[N]> {
- static void call(void *Ptr) { delete[](T *)Ptr; }
-};
-
-/// ManagedStaticBase - Common base class for ManagedStatic instances.
-class ManagedStaticBase {
-protected:
- // This should only be used as a static variable, which guarantees that this
- // will be zero initialized.
- mutable std::atomic<void *> Ptr;
- mutable void (*DeleterFn)(void*);
- mutable const ManagedStaticBase *Next;
-
- void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
- void RegisterManagedStatic(void *created, void (*deleter)(void*)) const;
-
-public:
- /// isConstructed - Return true if this object has not been created yet.
- bool isConstructed() const { return Ptr != nullptr; }
-
- void destroy() const;
-};
-
-/// ManagedStatic - This transparently changes the behavior of global statics to
-/// be lazily constructed on demand (good for reducing startup times of dynamic
-/// libraries that link in LLVM components) and for making destruction be
-/// explicit through the wpi_shutdown() function call.
-///
-template <class C, class Creator = object_creator<C>,
- class Deleter = object_deleter<C>>
-class ManagedStatic : public ManagedStaticBase {
-public:
- ManagedStatic() = default;
-
- ManagedStatic(C* created, void(*deleter)(void*)) {
- RegisterManagedStatic(created, deleter);
- }
-
- // Accessors.
- C &operator*() {
- void *Tmp = Ptr.load(std::memory_order_acquire);
- if (!Tmp)
- RegisterManagedStatic(Creator::call, Deleter::call);
-
- return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
- }
-
- C *operator->() { return &**this; }
-
- const C &operator*() const {
- void *Tmp = Ptr.load(std::memory_order_acquire);
- if (!Tmp)
- RegisterManagedStatic(Creator::call, Deleter::call);
-
- return *static_cast<C *>(Ptr.load(std::memory_order_relaxed));
- }
-
- const C *operator->() const { return &**this; }
-};
-
-/// wpi_shutdown - Deallocate and destroy all ManagedStatic variables.
-void wpi_shutdown();
-
-/// wpi_shutdown_obj - This is a simple helper class that calls
-/// wpi_shutdown() when it is destroyed.
-struct wpi_shutdown_obj {
- wpi_shutdown_obj() = default;
- ~wpi_shutdown_obj() { wpi_shutdown(); }
-};
-
-} // end namespace wpi
-
-#endif // WPIUTIL_WPI_MANAGEDSTATIC_H
diff --git a/wpiutil/src/main/native/include/wpi/MappedFileRegion.h b/wpiutil/src/main/native/include/wpi/MappedFileRegion.h
new file mode 100644
index 0000000..05e487e
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/MappedFileRegion.h
@@ -0,0 +1,92 @@
+// 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 <system_error>
+
+// Duplicated from fs.h to avoid a dependency
+namespace fs {
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void*;
+#else
+using file_t = int;
+#endif
+} // namespace fs
+
+namespace wpi {
+
+class MappedFileRegion {
+ public:
+ enum MapMode {
+ kReadOnly, ///< May only access map via const_data as read only.
+ kReadWrite, ///< May access map via data and modify it. Written to path.
+ kPriv ///< May modify via data, but changes are lost on destruction.
+ };
+
+ MappedFileRegion() = default;
+ MappedFileRegion(fs::file_t f, uint64_t length, uint64_t offset,
+ MapMode mapMode, std::error_code& ec);
+ ~MappedFileRegion() { Unmap(); }
+
+ MappedFileRegion(const MappedFileRegion&) = delete;
+ MappedFileRegion& operator=(const MappedFileRegion&) = delete;
+
+ MappedFileRegion(MappedFileRegion&& rhs)
+ : m_size(rhs.m_size), m_mapping(rhs.m_mapping) {
+ rhs.m_mapping = nullptr;
+#ifdef _WIN32
+ m_fileHandle = rhs.m_fileHandle;
+ rhs.m_fileHandle = nullptr;
+#endif
+ }
+
+ MappedFileRegion& operator=(MappedFileRegion&& rhs) {
+ if (m_mapping) {
+ Unmap();
+ }
+ m_size = rhs.m_size;
+ m_mapping = rhs.m_mapping;
+ rhs.m_mapping = nullptr;
+#ifdef _WIN32
+ m_fileHandle = rhs.m_fileHandle;
+ rhs.m_fileHandle = nullptr;
+#endif
+ return *this;
+ }
+
+ 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);
+ }
+ const uint8_t* const_data() const {
+ return static_cast<const uint8_t*>(m_mapping);
+ }
+
+ /**
+ * Returns required alignment.
+ */
+ static size_t GetAlignment();
+
+ private:
+ uint64_t m_size = 0;
+ void* m_mapping = nullptr;
+#ifdef _WIN32
+ fs::file_t m_fileHandle = nullptr;
+#endif
+};
+
+} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/MemAlloc.h b/wpiutil/src/main/native/include/wpi/MemAlloc.h
deleted file mode 100644
index addccb5..0000000
--- a/wpiutil/src/main/native/include/wpi/MemAlloc.h
+++ /dev/null
@@ -1,61 +0,0 @@
-//===- MemAlloc.h - Memory allocation functions -----------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-/// \file
-///
-/// This file defines counterparts of C library allocation functions defined in
-/// the namespace 'std'. The new allocation functions crash on allocation
-/// failure instead of returning null pointer.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_MEMALLOC_H
-#define WPIUTIL_WPI_MEMALLOC_H
-
-#include "wpi/Compiler.h"
-#include "wpi/ErrorHandling.h"
-#include <cstdlib>
-
-namespace wpi {
-
-#ifdef _WIN32
-#pragma warning(push)
-// Warning on NONNULL, report is not known to abort
-#pragma warning(disable : 6387)
-#pragma warning(disable : 28196)
-#pragma warning(disable : 28183)
-#endif
-
-LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
- void *Result = std::malloc(Sz);
- if (Result == nullptr)
- report_bad_alloc_error("Allocation failed");
- return Result;
-}
-
-LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
- size_t Sz) {
- void *Result = std::calloc(Count, Sz);
- if (Result == nullptr)
- report_bad_alloc_error("Allocation failed");
- return Result;
-}
-
-LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
- void *Result = std::realloc(Ptr, Sz);
- if (Result == nullptr)
- report_bad_alloc_error("Allocation failed");
- return Result;
-}
-
-#ifdef _WIN32
-#pragma warning(pop)
-#endif
-
-}
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/MessagePack.h b/wpiutil/src/main/native/include/wpi/MessagePack.h
new file mode 100644
index 0000000..e1f54e5
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/MessagePack.h
@@ -0,0 +1,39 @@
+// 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 <span>
+#include <string>
+#include <string_view>
+
+#include "wpi/mpack.h"
+
+namespace mpack {
+
+inline void mpack_write_str(mpack_writer_t* writer, std::string_view str) {
+ mpack_write_str(writer, str.data(), str.size());
+}
+
+inline void mpack_write_bytes(mpack_writer_t* writer,
+ std::span<const uint8_t> data) {
+ mpack_write_bytes(writer, reinterpret_cast<const char*>(data.data()),
+ data.size());
+}
+
+inline void mpack_reader_init_data(mpack_reader_t* reader,
+ std::span<const uint8_t> data) {
+ mpack_reader_init_data(reader, reinterpret_cast<const char*>(data.data()),
+ data.size());
+}
+
+mpack_error_t mpack_expect_str(mpack_reader_t* reader, std::string* out,
+ uint32_t maxLen = 1024);
+
+mpack_error_t mpack_read_str(mpack_reader_t* reader, mpack_tag_t* tag,
+ std::string* out, uint32_t maxLen = 1024);
+
+} // namespace mpack
diff --git a/wpiutil/src/main/native/include/wpi/MimeTypes.h b/wpiutil/src/main/native/include/wpi/MimeTypes.h
deleted file mode 100644
index ce36ea2..0000000
--- a/wpiutil/src/main/native/include/wpi/MimeTypes.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_MIMETYPES_H_
-#define WPIUTIL_WPI_MIMETYPES_H_
-
-#include <string_view>
-
-namespace wpi {
-
-std::string_view MimeTypeFromPath(std::string_view path);
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_MIMETYPES_H_
diff --git a/wpiutil/src/main/native/include/wpi/MulticastServiceAnnouncer.h b/wpiutil/src/main/native/include/wpi/MulticastServiceAnnouncer.h
deleted file mode 100644
index 5d2048d..0000000
--- a/wpiutil/src/main/native/include/wpi/MulticastServiceAnnouncer.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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>
-
-#ifdef __cplusplus
-#include <memory>
-#include <string>
-#include <string_view>
-#include <utility>
-
-#include "wpi/span.h"
-namespace wpi {
-class MulticastServiceAnnouncer {
- public:
- MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string, std::string>> txt);
- MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string_view, std::string_view>> txt);
- ~MulticastServiceAnnouncer() noexcept;
- void Start();
- void Stop();
- bool HasImplementation() const;
- struct Impl;
-
- private:
- std::unique_ptr<Impl> pImpl;
-};
-} // namespace wpi
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned int WPI_MulticastServiceAnnouncerHandle; // NOLINT
-
-WPI_MulticastServiceAnnouncerHandle WPI_CreateMulticastServiceAnnouncer(
- const char* serviceName, const char* serviceType, int32_t port,
- int32_t txtCount, const char** keys, const char** values);
-
-void WPI_FreeMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle);
-
-void WPI_StartMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle);
-
-void WPI_StopMulticastServiceAnnouncer(
- WPI_MulticastServiceAnnouncerHandle handle);
-
-int32_t WPI_GetMulticastServiceAnnouncerHasImplementation(
- WPI_MulticastServiceAnnouncerHandle handle);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h b/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h
deleted file mode 100644
index 0b63c2f..0000000
--- a/wpiutil/src/main/native/include/wpi/MulticastServiceResolver.h
+++ /dev/null
@@ -1,102 +0,0 @@
-// 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 "wpi/Synchronization.h"
-
-#ifdef __cplusplus
-#include <functional>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <utility>
-#include <vector>
-
-#include "wpi/mutex.h"
-#include "wpi/span.h"
-namespace wpi {
-class MulticastServiceResolver {
- public:
- explicit MulticastServiceResolver(std::string_view serviceType);
- ~MulticastServiceResolver() noexcept;
- struct ServiceData {
- unsigned int ipv4Address;
- int port;
- std::string serviceName;
- std::string hostName;
- std::vector<std::pair<std::string, std::string>> txt;
- };
- void Start();
- void Stop();
- WPI_EventHandle GetEventHandle() const { return event.GetHandle(); }
- std::vector<ServiceData> GetData() {
- std::scoped_lock lock{mutex};
- event.Reset();
- if (queue.empty()) {
- return {};
- }
- std::vector<ServiceData> ret;
- queue.swap(ret);
- return ret;
- }
- bool HasImplementation() const;
- struct Impl;
-
- private:
- void PushData(ServiceData&& data) {
- std::scoped_lock lock{mutex};
- queue.emplace_back(std::forward<ServiceData>(data));
- event.Set();
- }
- wpi::Event event{true};
- std::vector<ServiceData> queue;
- wpi::mutex mutex;
- std::unique_ptr<Impl> pImpl;
-};
-} // namespace wpi
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef unsigned int WPI_MulticastServiceResolverHandle; // NOLINT
-
-WPI_MulticastServiceResolverHandle WPI_CreateMulticastServiceResolver(
- const char* serviceType);
-
-void WPI_FreeMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle);
-
-void WPI_StartMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle);
-
-void WPI_StopMulticastServiceResolver(
- WPI_MulticastServiceResolverHandle handle);
-
-int32_t WPI_GetMulticastServiceResolverHasImplementation(
- WPI_MulticastServiceResolverHandle handle);
-
-WPI_EventHandle WPI_GetMulticastServiceResolverEventHandle(
- WPI_MulticastServiceResolverHandle handle);
-
-typedef struct WPI_ServiceData { // NOLINT
- uint32_t ipv4Address;
- int32_t port;
- const char* serviceName;
- const char* hostName;
- int32_t txtCount;
- const char** txtKeys;
- const char** txtValues;
-} WPI_ServiceData;
-
-WPI_ServiceData* WPI_GetMulticastServiceResolverData(
- WPI_MulticastServiceResolverHandle handle, int32_t* dataCount);
-
-void WPI_FreeServiceData(WPI_ServiceData* serviceData, int32_t length);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/NetworkAcceptor.h b/wpiutil/src/main/native/include/wpi/NetworkAcceptor.h
deleted file mode 100644
index 9982360..0000000
--- a/wpiutil/src/main/native/include/wpi/NetworkAcceptor.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_NETWORKACCEPTOR_H_
-#define WPIUTIL_WPI_NETWORKACCEPTOR_H_
-
-#include <memory>
-
-#include "wpi/NetworkStream.h"
-
-namespace wpi {
-
-class NetworkAcceptor {
- public:
- NetworkAcceptor() = default;
- virtual ~NetworkAcceptor() = default;
-
- virtual int start() = 0;
- virtual void shutdown() = 0;
- virtual std::unique_ptr<NetworkStream> accept() = 0;
-
- NetworkAcceptor(const NetworkAcceptor&) = delete;
- NetworkAcceptor& operator=(const NetworkAcceptor&) = delete;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_NETWORKACCEPTOR_H_
diff --git a/wpiutil/src/main/native/include/wpi/NetworkStream.h b/wpiutil/src/main/native/include/wpi/NetworkStream.h
deleted file mode 100644
index b842ecd..0000000
--- a/wpiutil/src/main/native/include/wpi/NetworkStream.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_NETWORKSTREAM_H_
-#define WPIUTIL_WPI_NETWORKSTREAM_H_
-
-#include <cstddef>
-#include <string_view>
-
-namespace wpi {
-
-class NetworkStream {
- public:
- NetworkStream() = default;
- virtual ~NetworkStream() = default;
-
- enum Error {
- kConnectionClosed = 0,
- kConnectionReset = -1,
- kConnectionTimedOut = -2,
- kWouldBlock = -3
- };
-
- virtual size_t send(const char* buffer, size_t len, Error* err) = 0;
- virtual size_t receive(char* buffer, size_t len, Error* err,
- int timeout = 0) = 0;
- virtual void close() = 0;
-
- virtual std::string_view getPeerIP() const = 0;
- virtual int getPeerPort() const = 0;
- virtual void setNoDelay() = 0;
-
- // returns false on failure
- virtual bool setBlocking(bool enabled) = 0;
- virtual int getNativeHandle() const = 0;
-
- NetworkStream(const NetworkStream&) = delete;
- NetworkStream& operator=(const NetworkStream&) = delete;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_NETWORKSTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/ParallelTcpConnector.h b/wpiutil/src/main/native/include/wpi/ParallelTcpConnector.h
deleted file mode 100644
index 47c29d0..0000000
--- a/wpiutil/src/main/native/include/wpi/ParallelTcpConnector.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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 <functional>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "wpi/span.h"
-#include "wpi/uv/Timer.h"
-
-namespace wpi {
-
-class Logger;
-
-namespace uv {
-class GetAddrInfoReq;
-class Loop;
-class Tcp;
-class Timer;
-} // namespace uv
-
-/**
- * Parallel TCP connector. Attempts parallel resolution and connection to
- * multiple servers with automatic retry if none connect.
- *
- * Each successful TCP connection results in a call to the connected callback.
- * For correct operation, the consuming code (either the connected callback or
- * e.g. task it starts) must call Succeeded() to indicate if the connection has
- * succeeded prior to the reconnect rate timeout. A successful connection
- * results in the connector terminating all other connection attempts.
- *
- * After the reconnect rate times out, all remaining active connection attempts
- * are canceled and new ones started.
- */
-class ParallelTcpConnector
- : public std::enable_shared_from_this<ParallelTcpConnector> {
- struct private_init {};
-
- public:
- /**
- * Create.
- *
- * @param loop loop
- * @param reconnectRate how long to wait after starting connection attempts
- * to cancel and attempt connecting again
- * @param logger logger
- * @param connected callback function when a connection succeeds; may be
- * called multiple times if it does not call Succeeded()
- * before returning
- * @return Parallel connector
- */
- static std::shared_ptr<ParallelTcpConnector> Create(
- wpi::uv::Loop& loop, wpi::uv::Timer::Time reconnectRate,
- wpi::Logger& logger, std::function<void(wpi::uv::Tcp& tcp)> connected) {
- return std::make_shared<ParallelTcpConnector>(
- loop, reconnectRate, logger, std::move(connected), private_init{});
- }
-
- ParallelTcpConnector(wpi::uv::Loop& loop, wpi::uv::Timer::Time reconnectRate,
- wpi::Logger& logger,
- std::function<void(wpi::uv::Tcp& tcp)> connected,
- const private_init&);
- ~ParallelTcpConnector();
-
- ParallelTcpConnector(const ParallelTcpConnector&) = delete;
- ParallelTcpConnector& operator=(const ParallelTcpConnector&) = delete;
-
- /**
- * Closes resources, canceling all pending action attempts.
- */
- void Close();
-
- /**
- * Changes the servers/ports to connect to. Starts connection attempts if not
- * already connected.
- *
- * @param servers array of server/port pairs
- */
- void SetServers(
- wpi::span<const std::pair<std::string, unsigned int>> servers);
-
- /**
- * Tells the parallel connector that the current connection has terminated and
- * it is necessary to start reconnection attempts.
- */
- void Disconnected();
-
- /**
- * Tells the parallel connector that a particular connection has succeeded and
- * it should stop trying to connect.
- *
- * @param tcp connection passed to connected callback
- */
- void Succeeded(wpi::uv::Tcp& tcp);
-
- private:
- bool IsConnected() const { return m_isConnected || m_servers.empty(); }
- void Connect();
- void CancelAll(wpi::uv::Tcp* except = nullptr);
-
- wpi::uv::Loop& m_loop;
- wpi::Logger& m_logger;
- wpi::uv::Timer::Time m_reconnectRate;
- std::function<void(wpi::uv::Tcp& tcp)> m_connected;
- std::shared_ptr<wpi::uv::Timer> m_reconnectTimer;
- std::vector<std::pair<std::string, unsigned int>> m_servers;
- std::vector<std::weak_ptr<wpi::uv::GetAddrInfoReq>> m_resolvers;
- std::vector<std::weak_ptr<wpi::uv::Tcp>> m_attempts;
- bool m_isConnected{false};
-};
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/PointerUnion.h b/wpiutil/src/main/native/include/wpi/PointerUnion.h
deleted file mode 100644
index 8d6e580..0000000
--- a/wpiutil/src/main/native/include/wpi/PointerUnion.h
+++ /dev/null
@@ -1,491 +0,0 @@
-//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the PointerUnion class, which is a discriminated union of
-// pointer types.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_POINTERUNION_H
-#define WPIUTIL_WPI_POINTERUNION_H
-
-#include "wpi/DenseMapInfo.h"
-#include "wpi/PointerIntPair.h"
-#include "wpi/PointerLikeTypeTraits.h"
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-
-namespace wpi {
-
-template <typename T> struct PointerUnionTypeSelectorReturn {
- using Return = T;
-};
-
-/// Get a type based on whether two types are the same or not.
-///
-/// For:
-///
-/// \code
-/// using Ret = typename PointerUnionTypeSelector<T1, T2, EQ, NE>::Return;
-/// \endcode
-///
-/// Ret will be EQ type if T1 is same as T2 or NE type otherwise.
-template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
-struct PointerUnionTypeSelector {
- using Return = typename PointerUnionTypeSelectorReturn<RET_NE>::Return;
-};
-
-template <typename T, typename RET_EQ, typename RET_NE>
-struct PointerUnionTypeSelector<T, T, RET_EQ, RET_NE> {
- using Return = typename PointerUnionTypeSelectorReturn<RET_EQ>::Return;
-};
-
-template <typename T1, typename T2, typename RET_EQ, typename RET_NE>
-struct PointerUnionTypeSelectorReturn<
- PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>> {
- using Return =
- typename PointerUnionTypeSelector<T1, T2, RET_EQ, RET_NE>::Return;
-};
-
-/// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
-/// for the two template arguments.
-template <typename PT1, typename PT2> class PointerUnionUIntTraits {
-public:
- static inline void *getAsVoidPointer(void *P) { return P; }
- static inline void *getFromVoidPointer(void *P) { return P; }
-
- enum {
- PT1BitsAv = (int)(PointerLikeTypeTraits<PT1>::NumLowBitsAvailable),
- PT2BitsAv = (int)(PointerLikeTypeTraits<PT2>::NumLowBitsAvailable),
- NumLowBitsAvailable = PT1BitsAv < PT2BitsAv ? PT1BitsAv : PT2BitsAv
- };
-};
-
-/// A discriminated union of two pointer types, with the discriminator in the
-/// low bit of the pointer.
-///
-/// This implementation is extremely efficient in space due to leveraging the
-/// low bits of the pointer, while exposing a natural and type-safe API.
-///
-/// Common use patterns would be something like this:
-/// PointerUnion<int*, float*> P;
-/// P = (int*)0;
-/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
-/// X = P.get<int*>(); // ok.
-/// Y = P.get<float*>(); // runtime assertion failure.
-/// Z = P.get<double*>(); // compile time failure.
-/// P = (float*)0;
-/// Y = P.get<float*>(); // ok.
-/// X = P.get<int*>(); // runtime assertion failure.
-template <typename PT1, typename PT2> class PointerUnion {
-public:
- using ValTy =
- PointerIntPair<void *, 1, bool, PointerUnionUIntTraits<PT1, PT2>>;
-
-private:
- ValTy Val;
-
- struct IsPT1 {
- static const int Num = 0;
- };
- struct IsPT2 {
- static const int Num = 1;
- };
- template <typename T> struct UNION_DOESNT_CONTAIN_TYPE {};
-
-public:
- PointerUnion() = default;
- PointerUnion(PT1 V)
- : Val(const_cast<void *>(
- PointerLikeTypeTraits<PT1>::getAsVoidPointer(V))) {}
- PointerUnion(PT2 V)
- : Val(const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(V)),
- 1) {}
-
- /// Test if the pointer held in the union is null, regardless of
- /// which type it is.
- bool isNull() const {
- // Convert from the void* to one of the pointer types, to make sure that
- // we recursively strip off low bits if we have a nested PointerUnion.
- return !PointerLikeTypeTraits<PT1>::getFromVoidPointer(Val.getPointer());
- }
-
- explicit operator bool() const { return !isNull(); }
-
- /// Test if the Union currently holds the type matching T.
- template <typename T> int is() const {
- using Ty = typename ::wpi::PointerUnionTypeSelector<
- PT1, T, IsPT1,
- ::wpi::PointerUnionTypeSelector<PT2, T, IsPT2,
- UNION_DOESNT_CONTAIN_TYPE<T>>>::Return;
- int TyNo = Ty::Num;
- return static_cast<int>(Val.getInt()) == TyNo;
- }
-
- /// 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(Val.getPointer());
- }
-
- /// Returns the current pointer if it is of the specified pointer type,
- /// otherwises returns null.
- template <typename T> T dyn_cast() const {
- if (is<T>())
- return get<T>();
- return T();
- }
-
- /// If the union is set to the first pointer type get an address pointing to
- /// it.
- PT1 const *getAddrOfPtr1() const {
- return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
- }
-
- /// If the union is set to the first pointer type get an address pointing to
- /// it.
- PT1 *getAddrOfPtr1() {
- assert(is<PT1>() && "Val is not the first pointer");
- assert(
- get<PT1>() == Val.getPointer() &&
- "Can't get the address because PointerLikeTypeTraits changes the ptr");
- return const_cast<PT1 *>(
- reinterpret_cast<const PT1 *>(Val.getAddrOfPointer()));
- }
-
- /// Assignment from nullptr which just clears the union.
- const PointerUnion &operator=(std::nullptr_t) {
- Val.initWithPointer(nullptr);
- return *this;
- }
-
- /// Assignment operators - Allow assigning into this union from either
- /// pointer type, setting the discriminator to remember what it came from.
- const PointerUnion &operator=(const PT1 &RHS) {
- Val.initWithPointer(
- const_cast<void *>(PointerLikeTypeTraits<PT1>::getAsVoidPointer(RHS)));
- return *this;
- }
- const PointerUnion &operator=(const PT2 &RHS) {
- Val.setPointerAndInt(
- const_cast<void *>(PointerLikeTypeTraits<PT2>::getAsVoidPointer(RHS)),
- 1);
- return *this;
- }
-
- void *getOpaqueValue() const { return Val.getOpaqueValue(); }
- static inline PointerUnion getFromOpaqueValue(void *VP) {
- PointerUnion V;
- V.Val = ValTy::getFromOpaqueValue(VP);
- return V;
- }
-};
-
-template <typename PT1, typename PT2>
-bool operator==(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
- return lhs.getOpaqueValue() == rhs.getOpaqueValue();
-}
-
-template <typename PT1, typename PT2>
-bool operator!=(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
- return lhs.getOpaqueValue() != rhs.getOpaqueValue();
-}
-
-template <typename PT1, typename PT2>
-bool operator<(PointerUnion<PT1, PT2> lhs, PointerUnion<PT1, PT2> rhs) {
- return lhs.getOpaqueValue() < rhs.getOpaqueValue();
-}
-
-// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
-// # low bits available = min(PT1bits,PT2bits)-1.
-template <typename PT1, typename PT2>
-struct PointerLikeTypeTraits<PointerUnion<PT1, PT2>> {
- static inline void *getAsVoidPointer(const PointerUnion<PT1, PT2> &P) {
- return P.getOpaqueValue();
- }
-
- static inline PointerUnion<PT1, PT2> getFromVoidPointer(void *P) {
- return PointerUnion<PT1, PT2>::getFromOpaqueValue(P);
- }
-
- // The number of bits available are the min of the two pointer types.
- enum {
- NumLowBitsAvailable = PointerLikeTypeTraits<
- typename PointerUnion<PT1, PT2>::ValTy>::NumLowBitsAvailable
- };
-};
-
-/// A pointer union of three pointer types. See documentation for PointerUnion
-/// for usage.
-template <typename PT1, typename PT2, typename PT3> class PointerUnion3 {
-public:
- using InnerUnion = PointerUnion<PT1, PT2>;
- using ValTy = PointerUnion<InnerUnion, PT3>;
-
-private:
- ValTy Val;
-
- struct IsInnerUnion {
- ValTy Val;
-
- IsInnerUnion(ValTy val) : Val(val) {}
-
- template <typename T> int is() const {
- return Val.template is<InnerUnion>() &&
- Val.template get<InnerUnion>().template is<T>();
- }
-
- template <typename T> T get() const {
- return Val.template get<InnerUnion>().template get<T>();
- }
- };
-
- struct IsPT3 {
- ValTy Val;
-
- IsPT3(ValTy val) : Val(val) {}
-
- template <typename T> int is() const { return Val.template is<T>(); }
- template <typename T> T get() const { return Val.template get<T>(); }
- };
-
-public:
- PointerUnion3() = default;
- PointerUnion3(PT1 V) { Val = InnerUnion(V); }
- PointerUnion3(PT2 V) { Val = InnerUnion(V); }
- PointerUnion3(PT3 V) { Val = V; }
-
- /// Test if the pointer held in the union is null, regardless of
- /// which type it is.
- bool isNull() const { return Val.isNull(); }
- explicit operator bool() const { return !isNull(); }
-
- /// Test if the Union currently holds the type matching T.
- template <typename T> int is() const {
- // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
- using Ty = typename ::wpi::PointerUnionTypeSelector<
- PT1, T, IsInnerUnion,
- ::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
- return Ty(Val).template is<T>();
- }
-
- /// 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");
- // If T is PT1/PT2 choose IsInnerUnion otherwise choose IsPT3.
- using Ty = typename ::wpi::PointerUnionTypeSelector<
- PT1, T, IsInnerUnion,
- ::wpi::PointerUnionTypeSelector<PT2, T, IsInnerUnion, IsPT3>>::Return;
- return Ty(Val).template get<T>();
- }
-
- /// Returns the current pointer if it is of the specified pointer type,
- /// otherwises returns null.
- template <typename T> T dyn_cast() const {
- if (is<T>())
- return get<T>();
- return T();
- }
-
- /// Assignment from nullptr which just clears the union.
- const PointerUnion3 &operator=(std::nullptr_t) {
- Val = nullptr;
- return *this;
- }
-
- /// Assignment operators - Allow assigning into this union from either
- /// pointer type, setting the discriminator to remember what it came from.
- const PointerUnion3 &operator=(const PT1 &RHS) {
- Val = InnerUnion(RHS);
- return *this;
- }
- const PointerUnion3 &operator=(const PT2 &RHS) {
- Val = InnerUnion(RHS);
- return *this;
- }
- const PointerUnion3 &operator=(const PT3 &RHS) {
- Val = RHS;
- return *this;
- }
-
- void *getOpaqueValue() const { return Val.getOpaqueValue(); }
- static inline PointerUnion3 getFromOpaqueValue(void *VP) {
- PointerUnion3 V;
- V.Val = ValTy::getFromOpaqueValue(VP);
- return V;
- }
-};
-
-// Teach SmallPtrSet that PointerUnion3 is "basically a pointer", that has
-// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
-template <typename PT1, typename PT2, typename PT3>
-struct PointerLikeTypeTraits<PointerUnion3<PT1, PT2, PT3>> {
- static inline void *getAsVoidPointer(const PointerUnion3<PT1, PT2, PT3> &P) {
- return P.getOpaqueValue();
- }
-
- static inline PointerUnion3<PT1, PT2, PT3> getFromVoidPointer(void *P) {
- return PointerUnion3<PT1, PT2, PT3>::getFromOpaqueValue(P);
- }
-
- // The number of bits available are the min of the two pointer types.
- enum {
- NumLowBitsAvailable = PointerLikeTypeTraits<
- typename PointerUnion3<PT1, PT2, PT3>::ValTy>::NumLowBitsAvailable
- };
-};
-
-template <typename PT1, typename PT2, typename PT3>
-bool operator<(PointerUnion3<PT1, PT2, PT3> lhs,
- PointerUnion3<PT1, PT2, PT3> rhs) {
- return lhs.getOpaqueValue() < rhs.getOpaqueValue();
-}
-
-/// A pointer union of four pointer types. See documentation for PointerUnion
-/// for usage.
-template <typename PT1, typename PT2, typename PT3, typename PT4>
-class PointerUnion4 {
-public:
- using InnerUnion1 = PointerUnion<PT1, PT2>;
- using InnerUnion2 = PointerUnion<PT3, PT4>;
- using ValTy = PointerUnion<InnerUnion1, InnerUnion2>;
-
-private:
- ValTy Val;
-
-public:
- PointerUnion4() = default;
- PointerUnion4(PT1 V) { Val = InnerUnion1(V); }
- PointerUnion4(PT2 V) { Val = InnerUnion1(V); }
- PointerUnion4(PT3 V) { Val = InnerUnion2(V); }
- PointerUnion4(PT4 V) { Val = InnerUnion2(V); }
-
- /// Test if the pointer held in the union is null, regardless of
- /// which type it is.
- bool isNull() const { return Val.isNull(); }
- explicit operator bool() const { return !isNull(); }
-
- /// Test if the Union currently holds the type matching T.
- template <typename T> int is() const {
- // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
- using Ty = typename ::wpi::PointerUnionTypeSelector<
- PT1, T, InnerUnion1,
- ::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
- InnerUnion2>>::Return;
- return Val.template is<Ty>() && Val.template get<Ty>().template is<T>();
- }
-
- /// 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");
- // If T is PT1/PT2 choose InnerUnion1 otherwise choose InnerUnion2.
- using Ty = typename ::wpi::PointerUnionTypeSelector<
- PT1, T, InnerUnion1,
- ::wpi::PointerUnionTypeSelector<PT2, T, InnerUnion1,
- InnerUnion2>>::Return;
- return Val.template get<Ty>().template get<T>();
- }
-
- /// Returns the current pointer if it is of the specified pointer type,
- /// otherwises returns null.
- template <typename T> T dyn_cast() const {
- if (is<T>())
- return get<T>();
- return T();
- }
-
- /// Assignment from nullptr which just clears the union.
- const PointerUnion4 &operator=(std::nullptr_t) {
- Val = nullptr;
- return *this;
- }
-
- /// Assignment operators - Allow assigning into this union from either
- /// pointer type, setting the discriminator to remember what it came from.
- const PointerUnion4 &operator=(const PT1 &RHS) {
- Val = InnerUnion1(RHS);
- return *this;
- }
- const PointerUnion4 &operator=(const PT2 &RHS) {
- Val = InnerUnion1(RHS);
- return *this;
- }
- const PointerUnion4 &operator=(const PT3 &RHS) {
- Val = InnerUnion2(RHS);
- return *this;
- }
- const PointerUnion4 &operator=(const PT4 &RHS) {
- Val = InnerUnion2(RHS);
- return *this;
- }
-
- void *getOpaqueValue() const { return Val.getOpaqueValue(); }
- static inline PointerUnion4 getFromOpaqueValue(void *VP) {
- PointerUnion4 V;
- V.Val = ValTy::getFromOpaqueValue(VP);
- return V;
- }
-};
-
-// Teach SmallPtrSet that PointerUnion4 is "basically a pointer", that has
-// # low bits available = min(PT1bits,PT2bits,PT2bits)-2.
-template <typename PT1, typename PT2, typename PT3, typename PT4>
-struct PointerLikeTypeTraits<PointerUnion4<PT1, PT2, PT3, PT4>> {
- static inline void *
- getAsVoidPointer(const PointerUnion4<PT1, PT2, PT3, PT4> &P) {
- return P.getOpaqueValue();
- }
-
- static inline PointerUnion4<PT1, PT2, PT3, PT4> getFromVoidPointer(void *P) {
- return PointerUnion4<PT1, PT2, PT3, PT4>::getFromOpaqueValue(P);
- }
-
- // The number of bits available are the min of the two pointer types.
- enum {
- NumLowBitsAvailable = PointerLikeTypeTraits<
- typename PointerUnion4<PT1, PT2, PT3, PT4>::ValTy>::NumLowBitsAvailable
- };
-};
-
-// Teach DenseMap how to use PointerUnions as keys.
-template <typename T, typename U> struct DenseMapInfo<PointerUnion<T, U>> {
- using Pair = PointerUnion<T, U>;
- using FirstInfo = DenseMapInfo<T>;
- using SecondInfo = DenseMapInfo<U>;
-
- static inline Pair getEmptyKey() { return Pair(FirstInfo::getEmptyKey()); }
-
- static inline Pair getTombstoneKey() {
- return Pair(FirstInfo::getTombstoneKey());
- }
-
- static unsigned getHashValue(const Pair &PairVal) {
- intptr_t key = (intptr_t)PairVal.getOpaqueValue();
- return DenseMapInfo<intptr_t>::getHashValue(key);
- }
-
- static bool isEqual(const Pair &LHS, const Pair &RHS) {
- return LHS.template is<T>() == RHS.template is<T>() &&
- (LHS.template is<T>() ? FirstInfo::isEqual(LHS.template get<T>(),
- RHS.template get<T>())
- : SecondInfo::isEqual(LHS.template get<U>(),
- RHS.template get<U>()));
- }
-};
-
-} // end namespace wpi
-
-#endif // WPIUTIL_WPI_POINTERUNION_H
diff --git a/wpiutil/src/main/native/include/wpi/PortForwarder.h b/wpiutil/src/main/native/include/wpi/PortForwarder.h
deleted file mode 100644
index 9e445a0..0000000
--- a/wpiutil/src/main/native/include/wpi/PortForwarder.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_PORTFORWARDER_H_
-#define WPIUTIL_WPI_PORTFORWARDER_H_
-
-#pragma once
-
-#include <memory>
-#include <string_view>
-
-namespace wpi {
-
-/**
- * Forward ports to another host. This is primarily useful for accessing
- * Ethernet-connected devices from a computer tethered to the RoboRIO USB port.
- */
-class PortForwarder {
- public:
- PortForwarder(const PortForwarder&) = delete;
- PortForwarder& operator=(const PortForwarder&) = delete;
-
- /**
- * Get an instance of the PortForwarder class.
- *
- * This is a singleton to guarantee that there is only a single instance
- * regardless of how many times GetInstance is called.
- */
- static PortForwarder& GetInstance();
-
- /**
- * Forward a local TCP port to a remote host and port.
- * Note that local ports less than 1024 won't work as a normal user.
- *
- * @param port local port number
- * @param remoteHost remote IP address / DNS name
- * @param remotePort remote port number
- */
- void Add(unsigned int port, std::string_view remoteHost,
- unsigned int remotePort);
-
- /**
- * Stop TCP forwarding on a port.
- *
- * @param port local port number
- */
- void Remove(unsigned int port);
-
- private:
- PortForwarder();
-
- struct Impl;
- std::unique_ptr<Impl> m_impl;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_PORTFORWARDER_H_
diff --git a/wpiutil/src/main/native/include/wpi/SafeThread.h b/wpiutil/src/main/native/include/wpi/SafeThread.h
index bf37732..753dc6c 100644
--- a/wpiutil/src/main/native/include/wpi/SafeThread.h
+++ b/wpiutil/src/main/native/include/wpi/SafeThread.h
@@ -10,6 +10,7 @@
#include <thread>
#include <utility>
+#include "wpi/Synchronization.h"
#include "wpi/condition_variable.h"
#include "wpi/mutex.h"
@@ -18,17 +19,33 @@
/**
* Base class for SafeThreadOwner threads.
*/
-class SafeThread {
+class SafeThreadBase {
public:
- virtual ~SafeThread() = default;
+ virtual ~SafeThreadBase() = default;
virtual void Main() = 0;
+ virtual void Stop() = 0;
mutable wpi::mutex m_mutex;
std::atomic_bool m_active{true};
- wpi::condition_variable m_cond;
std::thread::id m_threadId;
};
+class SafeThread : public SafeThreadBase {
+ public:
+ void Stop() override;
+
+ wpi::condition_variable m_cond;
+};
+
+class SafeThreadEvent : public SafeThreadBase {
+ public:
+ SafeThreadEvent() : m_stopEvent{true} {}
+
+ void Stop() override;
+
+ Event m_stopEvent;
+};
+
namespace detail {
/**
@@ -36,12 +53,12 @@
*/
class SafeThreadProxyBase {
public:
- explicit SafeThreadProxyBase(std::shared_ptr<SafeThread> thr);
+ explicit SafeThreadProxyBase(std::shared_ptr<SafeThreadBase> thr);
explicit operator bool() const { return m_thread != nullptr; }
std::unique_lock<wpi::mutex>& GetLock() { return m_lock; }
protected:
- std::shared_ptr<SafeThread> m_thread;
+ std::shared_ptr<SafeThreadBase> m_thread;
std::unique_lock<wpi::mutex> m_lock;
};
@@ -53,7 +70,7 @@
template <typename T>
class SafeThreadProxy : public SafeThreadProxyBase {
public:
- explicit SafeThreadProxy(std::shared_ptr<SafeThread> thr)
+ explicit SafeThreadProxy(std::shared_ptr<SafeThreadBase> thr)
: SafeThreadProxyBase(std::move(thr)) {}
T& operator*() const { return *static_cast<T*>(m_thread.get()); }
T* operator->() const { return static_cast<T*>(m_thread.get()); }
@@ -89,13 +106,13 @@
void SetJoinAtExit(bool joinAtExit) { m_joinAtExit = joinAtExit; }
protected:
- void Start(std::shared_ptr<SafeThread> thr);
- std::shared_ptr<SafeThread> GetThreadSharedPtr() const;
+ void Start(std::shared_ptr<SafeThreadBase> thr);
+ std::shared_ptr<SafeThreadBase> GetThreadSharedPtr() const;
private:
mutable wpi::mutex m_mutex;
std::thread m_stdThread;
- std::weak_ptr<SafeThread> m_thread;
+ std::weak_ptr<SafeThreadBase> m_thread;
std::atomic_bool m_joinAtExit{true};
};
diff --git a/wpiutil/src/main/native/include/wpi/SmallVector.h b/wpiutil/src/main/native/include/wpi/SmallVector.h
deleted file mode 100644
index 430f85a..0000000
--- a/wpiutil/src/main/native/include/wpi/SmallVector.h
+++ /dev/null
@@ -1,949 +0,0 @@
-//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the SmallVector class.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_SMALLVECTOR_H
-#define WPIUTIL_WPI_SMALLVECTOR_H
-
-// This file uses std::memcpy() to copy std::pair<unsigned int, unsigned int>.
-// That type is POD, but the standard doesn't guarantee that. GCC doesn't treat
-// the type as POD so it throws a warning. We want to consider this a warning
-// instead of an error.
-#if __GNUC__ >= 8
-#pragma GCC diagnostic warning "-Wclass-memaccess"
-#endif
-
-#include "wpi/iterator_range.h"
-#include "wpi/AlignOf.h"
-#include "wpi/Compiler.h"
-#include "wpi/MathExtras.h"
-#include "wpi/MemAlloc.h"
-#include "wpi/type_traits.h"
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdlib>
-#include <cstring>
-#include <initializer_list>
-#include <iterator>
-#include <memory>
-#include <new>
-#include <type_traits>
-#include <utility>
-
-namespace wpi {
-
-/// This is all the non-templated stuff common to all SmallVectors.
-class SmallVectorBase {
-protected:
- void *BeginX;
- unsigned Size = 0, Capacity;
-
- SmallVectorBase() = delete;
- SmallVectorBase(void *FirstEl, size_t Capacity)
- : BeginX(FirstEl), Capacity(static_cast<unsigned>(Capacity)) {}
-
- /// 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.
- void grow_pod(void *FirstEl, size_t MinCapacity, size_t TSize);
-
-public:
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- size_t size() const { return Size; }
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- size_t capacity() const { return Capacity; }
-
- LLVM_NODISCARD bool empty() const { return !Size; }
-
- /// Set the array size to \p N, which the current array must have enough
- /// capacity for.
- ///
- /// This does not construct or destroy any elements in the vector.
- ///
- /// Clients can use this in conjunction with capacity() to write past the end
- /// of the buffer when they know that more elements are available, and only
- /// update the size later. This avoids the cost of value initializing elements
- /// which will only be overwritten.
- void set_size(size_t Size) {
- assert(Size <= capacity());
- this->Size = static_cast<unsigned>(Size);
- }
-};
-
-/// Figure out the offset of the first element.
-template <class T, typename = void> struct SmallVectorAlignmentAndSize {
- AlignedCharArrayUnion<SmallVectorBase> Base;
- AlignedCharArrayUnion<T> FirstEl;
-};
-
-/// 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
-/// to avoid unnecessarily requiring T to be complete.
-template <typename T, typename = void>
-class SmallVectorTemplateCommon : public SmallVectorBase {
- /// 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.
- void *getFirstEl() const {
- return const_cast<void *>(reinterpret_cast<const void *>(
- reinterpret_cast<const char *>(this) +
- offsetof(SmallVectorAlignmentAndSize<T>, FirstEl)));
- }
- // Space after 'FirstEl' is clobbered, do not add any instance vars after it.
-
-protected:
- SmallVectorTemplateCommon(size_t Size)
- : SmallVectorBase(getFirstEl(), Size) {}
-
- void grow_pod(size_t MinCapacity, size_t TSize) {
- SmallVectorBase::grow_pod(getFirstEl(), MinCapacity, TSize);
- }
-
- /// Return true if this is a smallvector which has not had dynamic
- /// memory allocated for it.
- bool isSmall() const { return BeginX == getFirstEl(); }
-
- /// Put this vector in a state of being small.
- void resetToSmall() {
- BeginX = getFirstEl();
- Size = Capacity = 0; // FIXME: Setting Capacity to 0 is suspect.
- }
-
-public:
- using size_type = size_t;
- using difference_type = ptrdiff_t;
- using value_type = T;
- using iterator = T *;
- using const_iterator = const T *;
-
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- using reference = T &;
- using const_reference = const T &;
- using pointer = T *;
- using const_pointer = const T *;
-
- // forward iterator creation methods.
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- iterator begin() { return (iterator)this->BeginX; }
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- const_iterator begin() const { return (const_iterator)this->BeginX; }
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- iterator end() { return begin() + size(); }
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- const_iterator end() const { return begin() + size(); }
-
- // reverse iterator creation methods.
- 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());}
-
- size_type size_in_bytes() const { return size() * sizeof(T); }
- size_type max_size() const { return size_type(-1) / sizeof(T); }
-
- size_t capacity_in_bytes() const { return capacity() * sizeof(T); }
-
- /// Return a pointer to the vector's buffer, even if empty().
- pointer data() { return pointer(begin()); }
- /// Return a pointer to the vector's buffer, even if empty().
- const_pointer data() const { return const_pointer(begin()); }
-
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- reference operator[](size_type idx) {
- assert(idx < size());
- return begin()[idx];
- }
- LLVM_ATTRIBUTE_ALWAYS_INLINE
- const_reference operator[](size_type idx) const {
- assert(idx < size());
- return begin()[idx];
- }
-
- reference front() {
- assert(!empty());
- return begin()[0];
- }
- const_reference front() const {
- assert(!empty());
- return begin()[0];
- }
-
- reference back() {
- assert(!empty());
- return end()[-1];
- }
- const_reference back() const {
- assert(!empty());
- return end()[-1];
- }
-};
-
-/// SmallVectorTemplateBase<isPodLike = false> - This is where we put method
-/// implementations that are designed to work with non-POD-like T's.
-template <typename T, bool = isPodLike<T>::value>
-class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
-protected:
- SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
-
- static void destroy_range(T *S, T *E) {
- while (S != E) {
- --E;
- E->~T();
- }
- }
-
- /// Move the range [I, E) into the uninitialized memory starting with "Dest",
- /// 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);
- }
-
- /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
- /// constructing elements as needed.
- template<typename It1, typename It2>
- static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
- std::uninitialized_copy(I, E, Dest);
- }
-
- /// Grow the allocated memory (without initializing new elements), doubling
- /// the size of the allocated memory. Guarantees space for at least one more
- /// element, or MinSize more elements if specified.
- void grow(size_t MinSize = 0);
-
-public:
- void push_back(const T &Elt) {
- if (LLVM_UNLIKELY(this->size() >= this->capacity()))
- this->grow();
- ::new ((void*) this->end()) T(Elt);
- this->set_size(this->size() + 1);
- }
-
- void push_back(T &&Elt) {
- if (LLVM_UNLIKELY(this->size() >= this->capacity()))
- this->grow();
- ::new ((void*) this->end()) T(::std::move(Elt));
- this->set_size(this->size() + 1);
- }
-
- void pop_back() {
- this->set_size(this->size() - 1);
- this->end()->~T();
- }
-};
-
-// Define this out-of-line to dissuade the C++ compiler from inlining it.
-template <typename T, bool isPodLike>
-void SmallVectorTemplateBase<T, isPodLike>::grow(size_t MinSize) {
- if (MinSize > UINT32_MAX)
- report_bad_alloc_error("SmallVector capacity overflow during allocation");
-
- // Always grow, even from zero.
- size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
- NewCapacity = (std::min)((std::max)(NewCapacity, MinSize), size_t(UINT32_MAX));
- T *NewElts = static_cast<T*>(wpi::safe_malloc(NewCapacity*sizeof(T)));
-
- // Move the elements over.
- this->uninitialized_move(this->begin(), this->end(), NewElts);
-
- // Destroy the original elements.
- destroy_range(this->begin(), this->end());
-
- // If this wasn't grown from the inline copy, deallocate the old space.
- if (!this->isSmall())
- free(this->begin());
-
- this->BeginX = NewElts;
- this->Capacity = static_cast<unsigned>(NewCapacity);
-}
-
-
-/// SmallVectorTemplateBase<isPodLike = true> - This is where we put method
-/// implementations that are designed to work with POD-like T's.
-template <typename T>
-class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
-protected:
- SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
-
- // No need to do a destroy loop for POD's.
- static void destroy_range(T *, T *) {}
-
- /// Move the range [I, E) onto the uninitialized memory
- /// starting with "Dest", constructing elements into it as needed.
- template<typename It1, typename It2>
- static void uninitialized_move(It1 I, It1 E, It2 Dest) {
- // Just do a copy.
- uninitialized_copy(I, E, Dest);
- }
-
- /// Copy the range [I, E) onto the uninitialized memory
- /// starting with "Dest", constructing elements into it as needed.
- template<typename It1, typename It2>
- static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
- // Arbitrary iterator types; just use the basic implementation.
- std::uninitialized_copy(I, E, Dest);
- }
-
- /// Copy the range [I, E) onto the uninitialized memory
- /// starting with "Dest", constructing elements into it as needed.
- template <typename T1, typename T2>
- static void uninitialized_copy(
- T1 *I, T1 *E, T2 *Dest,
- typename std::enable_if<std::is_same<typename std::remove_const<T1>::type,
- T2>::value>::type * = 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
- // invalid for memcpy if they are equal.
- if (I != E)
- memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
- }
-
- /// Double the size of the allocated memory, guaranteeing space for at
- /// least one more element or MinSize if specified.
- void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); }
-
-public:
- void push_back(const T &Elt) {
- if (LLVM_UNLIKELY(this->size() >= this->capacity()))
- this->grow();
- memcpy(reinterpret_cast<void *>(this->end()), &Elt, sizeof(T));
- this->set_size(this->size() + 1);
- }
-
- void pop_back() { this->set_size(this->size() - 1); }
-};
-
-/// This class consists of common code factored out of the SmallVector class to
-/// reduce code duplication based on the SmallVector 'N' template parameter.
-template <typename T>
-class SmallVectorImpl : public SmallVectorTemplateBase<T> {
- using SuperClass = SmallVectorTemplateBase<T>;
-
-public:
- using iterator = typename SuperClass::iterator;
- using const_iterator = typename SuperClass::const_iterator;
- using size_type = typename SuperClass::size_type;
-
-protected:
- // Default ctor - Initialize to empty.
- explicit SmallVectorImpl(unsigned N)
- : SmallVectorTemplateBase<T, isPodLike<T>::value>(N) {}
-
-public:
- SmallVectorImpl(const SmallVectorImpl &) = delete;
-
- ~SmallVectorImpl() {
- // Subclass has already destructed this vector's elements.
- // If this wasn't grown from the inline copy, deallocate the old space.
- if (!this->isSmall())
- free(this->begin());
- }
-
- void clear() {
- this->destroy_range(this->begin(), this->end());
- this->Size = 0;
- }
-
- void resize(size_type N) {
- if (N < this->size()) {
- this->destroy_range(this->begin()+N, this->end());
- this->set_size(N);
- } else if (N > this->size()) {
- if (this->capacity() < N)
- this->grow(N);
- for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
- new (&*I) T();
- this->set_size(N);
- }
- }
-
- void resize(size_type N, const T &NV) {
- if (N < this->size()) {
- this->destroy_range(this->begin()+N, this->end());
- this->set_size(N);
- } else if (N > this->size()) {
- if (this->capacity() < N)
- this->grow(N);
- std::uninitialized_fill(this->end(), this->begin()+N, NV);
- this->set_size(N);
- }
- }
-
- void reserve(size_type N) {
- if (this->capacity() < N)
- this->grow(N);
- }
-
- LLVM_NODISCARD T pop_back_val() {
- T Result = ::std::move(this->back());
- this->pop_back();
- return Result;
- }
-
- void swap(SmallVectorImpl &RHS);
-
- /// Add the specified range to the end of the SmallVector.
- template <typename in_iter,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<in_iter>::iterator_category,
- std::input_iterator_tag>::value>::type>
- void append(in_iter in_start, in_iter in_end) {
- size_type NumInputs = std::distance(in_start, in_end);
- // Grow allocated space if needed.
- if (NumInputs > this->capacity() - this->size())
- this->grow(this->size()+NumInputs);
-
- // Copy the new elements over.
- this->uninitialized_copy(in_start, in_end, this->end());
- this->set_size(this->size() + NumInputs);
- }
-
- /// Add the specified range to the end of the SmallVector.
- void append(size_type NumInputs, const T &Elt) {
- // Grow allocated space if needed.
- if (NumInputs > this->capacity() - this->size())
- this->grow(this->size()+NumInputs);
-
- // Copy the new elements over.
- std::uninitialized_fill_n(this->end(), NumInputs, Elt);
- this->set_size(this->size() + NumInputs);
- }
-
- void append(std::initializer_list<T> IL) {
- append(IL.begin(), IL.end());
- }
-
- // FIXME: Consider assigning over existing elements, rather than clearing &
- // re-initializing them - for all assign(...) variants.
-
- void assign(size_type NumElts, const T &Elt) {
- clear();
- if (this->capacity() < NumElts)
- this->grow(NumElts);
- this->set_size(NumElts);
- std::uninitialized_fill(this->begin(), this->end(), Elt);
- }
-
- template <typename in_iter,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<in_iter>::iterator_category,
- std::input_iterator_tag>::value>::type>
- void assign(in_iter in_start, in_iter in_end) {
- clear();
- append(in_start, in_end);
- }
-
- void assign(std::initializer_list<T> IL) {
- clear();
- append(IL);
- }
-
- iterator erase(const_iterator CI) {
- // Just cast away constness because this is a non-const member function.
- iterator I = const_cast<iterator>(CI);
-
- assert(I >= this->begin() && "Iterator to erase is out of bounds.");
- assert(I < this->end() && "Erasing at past-the-end iterator.");
-
- iterator N = I;
- // Shift all elts down one.
- std::move(I+1, this->end(), I);
- // Drop the last elt.
- this->pop_back();
- return(N);
- }
-
- iterator erase(const_iterator CS, const_iterator CE) {
- // Just cast away constness because this is a non-const member function.
- iterator S = const_cast<iterator>(CS);
- iterator E = const_cast<iterator>(CE);
-
- assert(S >= this->begin() && "Range to erase is out of bounds.");
- assert(S <= E && "Trying to erase invalid range.");
- assert(E <= this->end() && "Trying to erase past the end.");
-
- iterator N = S;
- // Shift all elts down.
- iterator I = std::move(E, this->end(), S);
- // Drop the last elts.
- this->destroy_range(I, this->end());
- this->set_size(I - this->begin());
- return(N);
- }
-
- iterator insert(iterator I, T &&Elt) {
- if (I == this->end()) { // Important special case for empty vector.
- this->push_back(::std::move(Elt));
- return this->end()-1;
- }
-
- assert(I >= this->begin() && "Insertion iterator is out of bounds.");
- assert(I <= this->end() && "Inserting past the end of the vector.");
-
- if (this->size() >= this->capacity()) {
- size_t EltNo = I-this->begin();
- this->grow();
- I = this->begin()+EltNo;
- }
-
- ::new ((void*) this->end()) T(::std::move(this->back()));
- // Push everything else over.
- std::move_backward(I, this->end()-1, this->end());
- this->set_size(this->size() + 1);
-
- // If we just moved the element we're inserting, be sure to update
- // the reference.
- T *EltPtr = &Elt;
- if (I <= EltPtr && EltPtr < this->end())
- ++EltPtr;
-
- *I = ::std::move(*EltPtr);
- return I;
- }
-
- iterator insert(iterator I, const T &Elt) {
- if (I == this->end()) { // Important special case for empty vector.
- this->push_back(Elt);
- return this->end()-1;
- }
-
- assert(I >= this->begin() && "Insertion iterator is out of bounds.");
- assert(I <= this->end() && "Inserting past the end of the vector.");
-
- if (this->size() >= this->capacity()) {
- size_t EltNo = I-this->begin();
- this->grow();
- I = this->begin()+EltNo;
- }
- ::new ((void*) this->end()) T(std::move(this->back()));
- // Push everything else over.
- std::move_backward(I, this->end()-1, this->end());
- this->set_size(this->size() + 1);
-
- // If we just moved the element we're inserting, be sure to update
- // the reference.
- const T *EltPtr = &Elt;
- if (I <= EltPtr && EltPtr < this->end())
- ++EltPtr;
-
- *I = *EltPtr;
- return I;
- }
-
- iterator insert(iterator I, size_type NumToInsert, const T &Elt) {
- // Convert iterator to elt# to avoid invalidating iterator when we reserve()
- size_t InsertElt = I - this->begin();
-
- if (I == this->end()) { // Important special case for empty vector.
- append(NumToInsert, Elt);
- return this->begin()+InsertElt;
- }
-
- assert(I >= this->begin() && "Insertion iterator is out of bounds.");
- assert(I <= this->end() && "Inserting past the end of the vector.");
-
- // Ensure there is enough space.
- reserve(this->size() + NumToInsert);
-
- // Uninvalidate the iterator.
- I = this->begin()+InsertElt;
-
- // If there are more elements between the insertion point and the end of the
- // range than there are being inserted, we can use a simple approach to
- // insertion. Since we already reserved space, we know that this won't
- // reallocate the vector.
- if (size_t(this->end()-I) >= NumToInsert) {
- T *OldEnd = this->end();
- append(std::move_iterator<iterator>(this->end() - NumToInsert),
- std::move_iterator<iterator>(this->end()));
-
- // Copy the existing elements that get replaced.
- std::move_backward(I, OldEnd-NumToInsert, OldEnd);
-
- std::fill_n(I, NumToInsert, Elt);
- return I;
- }
-
- // Otherwise, we're inserting more elements than exist already, and we're
- // not inserting at the end.
-
- // Move over the elements that we're about to overwrite.
- T *OldEnd = this->end();
- this->set_size(this->size() + NumToInsert);
- size_t NumOverwritten = OldEnd-I;
- this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
-
- // Replace the overwritten part.
- std::fill_n(I, NumOverwritten, Elt);
-
- // Insert the non-overwritten middle part.
- std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt);
- return I;
- }
-
- template <typename ItTy,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<ItTy>::iterator_category,
- std::input_iterator_tag>::value>::type>
- 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();
-
- if (I == this->end()) { // Important special case for empty vector.
- append(From, To);
- return this->begin()+InsertElt;
- }
-
- assert(I >= this->begin() && "Insertion iterator is out of bounds.");
- assert(I <= this->end() && "Inserting past the end of the vector.");
-
- size_t NumToInsert = std::distance(From, To);
-
- // Ensure there is enough space.
- reserve(this->size() + NumToInsert);
-
- // Uninvalidate the iterator.
- I = this->begin()+InsertElt;
-
- // If there are more elements between the insertion point and the end of the
- // range than there are being inserted, we can use a simple approach to
- // insertion. Since we already reserved space, we know that this won't
- // reallocate the vector.
- if (size_t(this->end()-I) >= NumToInsert) {
- T *OldEnd = this->end();
- append(std::move_iterator<iterator>(this->end() - NumToInsert),
- std::move_iterator<iterator>(this->end()));
-
- // Copy the existing elements that get replaced.
- std::move_backward(I, OldEnd-NumToInsert, OldEnd);
-
- std::copy(From, To, I);
- return I;
- }
-
- // Otherwise, we're inserting more elements than exist already, and we're
- // not inserting at the end.
-
- // Move over the elements that we're about to overwrite.
- T *OldEnd = this->end();
- this->set_size(this->size() + NumToInsert);
- size_t NumOverwritten = OldEnd-I;
- this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
-
- // Replace the overwritten part.
- for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
- *J = *From;
- ++J; ++From;
- }
-
- // Insert the non-overwritten middle part.
- this->uninitialized_copy(From, To, OldEnd);
- return I;
- }
-
- void insert(iterator I, std::initializer_list<T> IL) {
- insert(I, IL.begin(), IL.end());
- }
-
- template <typename... ArgTypes> void emplace_back(ArgTypes &&... Args) {
- if (LLVM_UNLIKELY(this->size() >= this->capacity()))
- this->grow();
- ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
- this->set_size(this->size() + 1);
- }
-
- SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
-
- SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
-
- bool operator==(const SmallVectorImpl &RHS) const {
- if (this->size() != RHS.size()) return false;
- return std::equal(this->begin(), this->end(), RHS.begin());
- }
- bool operator!=(const SmallVectorImpl &RHS) const {
- return !(*this == RHS);
- }
-
- bool operator<(const SmallVectorImpl &RHS) const {
- return std::lexicographical_compare(this->begin(), this->end(),
- RHS.begin(), RHS.end());
- }
-};
-
-template <typename T>
-void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
- if (this == &RHS) return;
-
- // We can only avoid copying elements if neither vector is small.
- if (!this->isSmall() && !RHS.isSmall()) {
- std::swap(this->BeginX, RHS.BeginX);
- std::swap(this->Size, RHS.Size);
- std::swap(this->Capacity, RHS.Capacity);
- return;
- }
- if (RHS.size() > this->capacity())
- this->grow(RHS.size());
- if (this->size() > RHS.capacity())
- RHS.grow(this->size());
-
- // Swap the shared elements.
- size_t NumShared = this->size();
- if (NumShared > RHS.size()) NumShared = RHS.size();
- for (size_type i = 0; i != NumShared; ++i)
- std::swap((*this)[i], RHS[i]);
-
- // Copy over the extra elts.
- if (this->size() > RHS.size()) {
- size_t EltDiff = this->size() - RHS.size();
- this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
- RHS.set_size(RHS.size() + EltDiff);
- this->destroy_range(this->begin()+NumShared, this->end());
- this->set_size(NumShared);
- } else if (RHS.size() > this->size()) {
- size_t EltDiff = RHS.size() - this->size();
- this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
- this->set_size(this->size() + EltDiff);
- this->destroy_range(RHS.begin()+NumShared, RHS.end());
- RHS.set_size(NumShared);
- }
-}
-
-template <typename T>
-SmallVectorImpl<T> &SmallVectorImpl<T>::
- operator=(const SmallVectorImpl<T> &RHS) {
- // Avoid self-assignment.
- if (this == &RHS) return *this;
-
- // If we already have sufficient space, assign the common elements, then
- // destroy any excess.
- size_t RHSSize = RHS.size();
- size_t CurSize = this->size();
- if (CurSize >= RHSSize) {
- // Assign common elements.
- iterator NewEnd;
- if (RHSSize)
- NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin());
- else
- NewEnd = this->begin();
-
- // Destroy excess elements.
- this->destroy_range(NewEnd, this->end());
-
- // Trim.
- this->set_size(RHSSize);
- return *this;
- }
-
- // If we have to grow to have enough elements, destroy the current elements.
- // This allows us to avoid copying them during the grow.
- // FIXME: don't do this if they're efficiently moveable.
- if (this->capacity() < RHSSize) {
- // Destroy current elements.
- this->destroy_range(this->begin(), this->end());
- this->set_size(0);
- CurSize = 0;
- this->grow(RHSSize);
- } else if (CurSize) {
- // Otherwise, use assignment for the already-constructed elements.
- std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin());
- }
-
- // Copy construct the new elements in place.
- this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
- this->begin()+CurSize);
-
- // Set end.
- this->set_size(RHSSize);
- return *this;
-}
-
-template <typename T>
-SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
- // Avoid self-assignment.
- if (this == &RHS) return *this;
-
- // If the RHS isn't small, clear this vector and then steal its buffer.
- if (!RHS.isSmall()) {
- this->destroy_range(this->begin(), this->end());
- if (!this->isSmall()) free(this->begin());
- this->BeginX = RHS.BeginX;
- this->Size = RHS.Size;
- this->Capacity = RHS.Capacity;
- RHS.resetToSmall();
- return *this;
- }
-
- // If we already have sufficient space, assign the common elements, then
- // destroy any excess.
- size_t RHSSize = RHS.size();
- size_t CurSize = this->size();
- if (CurSize >= RHSSize) {
- // Assign common elements.
- iterator NewEnd = this->begin();
- if (RHSSize)
- NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
-
- // Destroy excess elements and trim the bounds.
- this->destroy_range(NewEnd, this->end());
- this->set_size(RHSSize);
-
- // Clear the RHS.
- RHS.clear();
-
- return *this;
- }
-
- // If we have to grow to have enough elements, destroy the current elements.
- // This allows us to avoid copying them during the grow.
- // FIXME: this may not actually make any sense if we can efficiently move
- // elements.
- if (this->capacity() < RHSSize) {
- // Destroy current elements.
- this->destroy_range(this->begin(), this->end());
- this->set_size(0);
- CurSize = 0;
- this->grow(RHSSize);
- } else if (CurSize) {
- // Otherwise, use assignment for the already-constructed elements.
- std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
- }
-
- // Move-construct the new elements in place.
- this->uninitialized_move(RHS.begin()+CurSize, RHS.end(),
- this->begin()+CurSize);
-
- // Set end.
- this->set_size(RHSSize);
-
- RHS.clear();
- return *this;
-}
-
-/// Storage for the SmallVector elements. This is specialized for the N=0 case
-/// to avoid allocating unnecessary storage.
-template <typename T, unsigned N>
-struct SmallVectorStorage {
- AlignedCharArrayUnion<T> InlineElts[N];
-};
-
-/// We need the storage to be properly aligned even for small-size of 0 so that
-/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
-/// well-defined.
-template <typename T> struct alignas(alignof(T)) SmallVectorStorage<T, 0> {};
-
-/// This is a 'vector' (really, a variable-sized array), optimized
-/// for the case when the array is small. It contains some number of elements
-/// in-place, which allows it to avoid heap allocation when the actual number of
-/// elements is below that threshold. This allows normal "small" cases to be
-/// fast without losing generality for large inputs.
-///
-/// Note that this does not attempt to be exception safe.
-///
-template <typename T, unsigned N>
-class SmallVector : public SmallVectorImpl<T>, SmallVectorStorage<T, N> {
-public:
- SmallVector() : SmallVectorImpl<T>(N) {}
-
- ~SmallVector() {
- // Destroy the constructed elements in the vector.
- this->destroy_range(this->begin(), this->end());
- }
-
- explicit SmallVector(size_t Size, const T &Value = T())
- : SmallVectorImpl<T>(N) {
- this->assign(Size, Value);
- }
-
- template <typename ItTy,
- typename = typename std::enable_if<std::is_convertible<
- typename std::iterator_traits<ItTy>::iterator_category,
- std::input_iterator_tag>::value>::type>
- SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
- this->append(S, E);
- }
-
- template <typename RangeTy>
- explicit SmallVector(const iterator_range<RangeTy> &R)
- : SmallVectorImpl<T>(N) {
- this->append(R.begin(), R.end());
- }
-
- SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
- this->assign(IL);
- }
-
- SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
- if (!RHS.empty())
- SmallVectorImpl<T>::operator=(RHS);
- }
-
- const SmallVector &operator=(const SmallVector &RHS) {
- SmallVectorImpl<T>::operator=(RHS);
- return *this;
- }
-
- SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
- if (!RHS.empty())
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- }
-
- SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
- if (!RHS.empty())
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- }
-
- const SmallVector &operator=(SmallVector &&RHS) {
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- return *this;
- }
-
- const SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
- SmallVectorImpl<T>::operator=(::std::move(RHS));
- return *this;
- }
-
- const SmallVector &operator=(std::initializer_list<T> IL) {
- this->assign(IL);
- return *this;
- }
-};
-
-template <typename T, unsigned N>
-inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
- return X.capacity_in_bytes();
-}
-
-} // end namespace wpi
-
-namespace std {
-
- /// Implement std::swap in terms of SmallVector swap.
- template<typename T>
- inline void
- swap(wpi::SmallVectorImpl<T> &LHS, wpi::SmallVectorImpl<T> &RHS) {
- LHS.swap(RHS);
- }
-
- /// Implement std::swap in terms of SmallVector swap.
- template<typename T, unsigned N>
- inline void
- swap(wpi::SmallVector<T, N> &LHS, wpi::SmallVector<T, N> &RHS) {
- LHS.swap(RHS);
- }
-
-} // end namespace std
-
-#endif // LLVM_ADT_SMALLVECTOR_H
diff --git a/wpiutil/src/main/native/include/wpi/SocketError.h b/wpiutil/src/main/native/include/wpi/SocketError.h
deleted file mode 100644
index b893ac6..0000000
--- a/wpiutil/src/main/native/include/wpi/SocketError.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_SOCKETERROR_H_
-#define WPIUTIL_WPI_SOCKETERROR_H_
-
-#include <string>
-
-namespace wpi {
-
-int SocketErrno();
-
-std::string SocketStrerror(int code);
-
-inline std::string SocketStrerror() {
- return SocketStrerror(SocketErrno());
-}
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_SOCKETERROR_H_
diff --git a/wpiutil/src/main/native/include/wpi/SpanExtras.h b/wpiutil/src/main/native/include/wpi/SpanExtras.h
index 41e4014..aa7b9ab 100644
--- a/wpiutil/src/main/native/include/wpi/SpanExtras.h
+++ b/wpiutil/src/main/native/include/wpi/SpanExtras.h
@@ -5,21 +5,22 @@
#pragma once
#include <cassert>
-
-#include "wpi/span.h"
+#include <span>
namespace wpi {
/// Drop the first \p N elements of the array.
template <typename T>
-constexpr span<T> drop_front(span<T> in, typename span<T>::size_type n = 1) {
+constexpr std::span<T> drop_front(std::span<T> 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 span<T> drop_back(span<T> in, typename span<T>::size_type n = 1) {
+constexpr std::span<T> drop_back(std::span<T> 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);
}
diff --git a/wpiutil/src/main/native/include/wpi/SwapByteOrder.h b/wpiutil/src/main/native/include/wpi/SwapByteOrder.h
deleted file mode 100644
index 50ad832..0000000
--- a/wpiutil/src/main/native/include/wpi/SwapByteOrder.h
+++ /dev/null
@@ -1,127 +0,0 @@
-//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file declares generic and optimized functions to swap the byte order of
-// an integral type.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
-#define WPIUTIL_WPI_SWAPBYTEORDER_H
-
-#include "wpi/Compiler.h"
-#include <cstddef>
-#include <stdint.h>
-#if defined(_MSC_VER) && !defined(_DEBUG)
-#include <stdlib.h>
-#endif
-
-namespace wpi {
-namespace sys {
-
-/// SwapByteOrder_16 - This function returns a byte-swapped representation of
-/// the 16-bit argument.
-inline uint16_t SwapByteOrder_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
-}
-
-/// SwapByteOrder_32 - This function returns a byte-swapped representation of
-/// the 32-bit argument.
-inline uint32_t SwapByteOrder_32(uint32_t value) {
-#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !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
-}
-
-/// SwapByteOrder_64 - This function returns a byte-swapped representation of
-/// the 64-bit argument.
-inline uint64_t SwapByteOrder_64(uint64_t value) {
-#if defined(__llvm__) || (LLVM_GNUC_PREREQ(4, 3, 0) && !defined(__ICC))
- return __builtin_bswap64(value);
-#elif defined(_MSC_VER) && !defined(_DEBUG)
- return _byteswap_uint64(value);
-#else
- uint64_t Hi = SwapByteOrder_32(uint32_t(value));
- uint32_t Lo = SwapByteOrder_32(uint32_t(value >> 32));
- return (Hi << 32) | Lo;
-#endif
-}
-
-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 short getSwappedBytes(unsigned short C) { return SwapByteOrder_16(C); }
-inline signed short getSwappedBytes( signed short C) { return SwapByteOrder_16(C); }
-
-inline unsigned int getSwappedBytes(unsigned int C) { return SwapByteOrder_32(C); }
-inline signed int getSwappedBytes( signed int C) { return SwapByteOrder_32(C); }
-
-#if __LONG_MAX__ == __INT_MAX__
-inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_32(C); }
-inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_32(C); }
-#elif __LONG_MAX__ == __LONG_LONG_MAX__
-inline unsigned long getSwappedBytes(unsigned long C) { return SwapByteOrder_64(C); }
-inline signed long getSwappedBytes( signed long C) { return SwapByteOrder_64(C); }
-#else
-#error "Unknown long size!"
-#endif
-
-inline unsigned long long getSwappedBytes(unsigned long long C) {
- return SwapByteOrder_64(C);
-}
-inline signed long long getSwappedBytes(signed long long C) {
- return SwapByteOrder_64(C);
-}
-
-inline float getSwappedBytes(float C) {
- union {
- uint32_t i;
- float f;
- } in, out;
- in.f = C;
- out.i = SwapByteOrder_32(in.i);
- return out.f;
-}
-
-inline double getSwappedBytes(double C) {
- union {
- uint64_t i;
- double d;
- } in, out;
- in.d = C;
- out.i = SwapByteOrder_64(in.i);
- return out.d;
-}
-
-template<typename T>
-inline void swapByteOrder(T &Value) {
- Value = getSwappedBytes(Value);
-}
-
-} // end namespace sys
-} // end namespace wpi
-
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/SymbolExports.h b/wpiutil/src/main/native/include/wpi/SymbolExports.h
index 4e84825..9ffc936 100644
--- a/wpiutil/src/main/native/include/wpi/SymbolExports.h
+++ b/wpiutil/src/main/native/include/wpi/SymbolExports.h
@@ -14,10 +14,179 @@
#define WPILIB_DLLEXPORT __declspec(dllexport)
#endif
+#elif defined(WPILIB_IMPORTS)
+
+#ifdef __GNUC__
+#define WPILIB_DLLEXPORT __attribute__((dllimport))
+#else
+#define WPILIB_DLLEXPORT __declspec(dllimport)
+#endif
+
#else
#define WPILIB_DLLEXPORT
#endif
-#else
+#else // _WIN32
+
+#ifdef WPILIB_EXPORTS
#define WPILIB_DLLEXPORT __attribute__((visibility("default")))
+#else
+#define WPILIB_DLLEXPORT
#endif
+
+#endif // _WIN32
+
+// Synopsis
+//
+// This header provides macros for using FOO_EXPORT macros with explicit
+// template instantiation declarations and definitions.
+// Generally, the FOO_EXPORT macros are used at declarations,
+// and GCC requires them to be used at explicit instantiation declarations,
+// but MSVC requires __declspec(dllexport) to be used at the explicit
+// instantiation definitions instead.
+
+// Usage
+//
+// In a header file, write:
+//
+// extern template class EXPORT_TEMPLATE_DECLARE(FOO_EXPORT) foo<bar>;
+//
+// In a source file, write:
+//
+// template class EXPORT_TEMPLATE_DEFINE(FOO_EXPORT) foo<bar>;
+
+// Implementation notes
+//
+// The implementation of this header uses some subtle macro semantics to
+// detect what the provided FOO_EXPORT value was defined as and then
+// to dispatch to appropriate macro definitions. Unfortunately,
+// MSVC's C preprocessor is rather non-compliant and requires special
+// care to make it work.
+//
+// Issue 1.
+//
+// #define F(x)
+// F()
+//
+// MSVC emits warning C4003 ("not enough actual parameters for macro
+// 'F'), even though it's a valid macro invocation. This affects the
+// macros below that take just an "export" parameter, because export
+// may be empty.
+//
+// As a workaround, we can add a dummy parameter and arguments:
+//
+// #define F(x,_)
+// F(,)
+//
+// Issue 2.
+//
+// #define F(x) G##x
+// #define Gj() ok
+// F(j())
+//
+// The correct replacement for "F(j())" is "ok", but MSVC replaces it
+// with "Gj()". As a workaround, we can pass the result to an
+// identity macro to force MSVC to look for replacements again. (This
+// is why EXPORT_TEMPLATE_STYLE_3 exists.)
+
+#define EXPORT_TEMPLATE_DECLARE(export) \
+ EXPORT_TEMPLATE_INVOKE(DECLARE, EXPORT_TEMPLATE_STYLE(export, ), export)
+#define EXPORT_TEMPLATE_DEFINE(export) \
+ EXPORT_TEMPLATE_INVOKE(DEFINE, EXPORT_TEMPLATE_STYLE(export, ), export)
+
+// INVOKE is an internal helper macro to perform parameter replacements
+// and token pasting to chain invoke another macro. E.g.,
+// EXPORT_TEMPLATE_INVOKE(DECLARE, DEFAULT, FOO_EXPORT)
+// will export to call
+// EXPORT_TEMPLATE_DECLARE_DEFAULT(FOO_EXPORT, )
+// (but with FOO_EXPORT expanded too).
+#define EXPORT_TEMPLATE_INVOKE(which, style, export) \
+ EXPORT_TEMPLATE_INVOKE_2(which, style, export)
+#define EXPORT_TEMPLATE_INVOKE_2(which, style, export) \
+ EXPORT_TEMPLATE_##which##_##style(export, )
+
+// Default style is to apply the FOO_EXPORT macro at declaration sites.
+#define EXPORT_TEMPLATE_DECLARE_DEFAULT(export, _) export
+#define EXPORT_TEMPLATE_DEFINE_DEFAULT(export, _)
+
+// The "MSVC hack" style is used when FOO_EXPORT is defined
+// as __declspec(dllexport), which MSVC requires to be used at
+// definition sites instead.
+#define EXPORT_TEMPLATE_DECLARE_MSVC_HACK(export, _)
+#define EXPORT_TEMPLATE_DEFINE_MSVC_HACK(export, _) export
+
+// EXPORT_TEMPLATE_STYLE is an internal helper macro that identifies which
+// export style needs to be used for the provided FOO_EXPORT macro definition.
+// "", "__attribute__(...)", and "__declspec(dllimport)" are mapped
+// to "DEFAULT"; while "__declspec(dllexport)" is mapped to "MSVC_HACK".
+//
+// It's implemented with token pasting to transform the __attribute__ and
+// __declspec annotations into macro invocations. E.g., if FOO_EXPORT is
+// defined as "__declspec(dllimport)", it undergoes the following sequence of
+// macro substitutions:
+// EXPORT_TEMPLATE_STYLE(FOO_EXPORT, )
+// EXPORT_TEMPLATE_STYLE_2(__declspec(dllimport), )
+// EXPORT_TEMPLATE_STYLE_3(EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport))
+// EXPORT_TEMPLATE_STYLE_MATCH__declspec(dllimport)
+// EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport
+// DEFAULT
+#define EXPORT_TEMPLATE_STYLE(export, _) EXPORT_TEMPLATE_STYLE_2(export, )
+#define EXPORT_TEMPLATE_STYLE_2(export, _) \
+ EXPORT_TEMPLATE_STYLE_3( \
+ EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA##export)
+#define EXPORT_TEMPLATE_STYLE_3(style) style
+
+// Internal helper macros for EXPORT_TEMPLATE_STYLE.
+//
+// XXX: C++ reserves all identifiers containing "__" for the implementation,
+// but "__attribute__" and "__declspec" already contain "__" and the token-paste
+// operator can only add characters; not remove them. To minimize the risk of
+// conflict with implementations, we include "foj3FJo5StF0OvIzl7oMxA" (a random
+// 128-bit string, encoded in Base64) in the macro name.
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA DEFAULT
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__attribute__(...) \
+ DEFAULT
+#define EXPORT_TEMPLATE_STYLE_MATCH_foj3FJo5StF0OvIzl7oMxA__declspec(arg) \
+ EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_##arg
+
+// Internal helper macros for EXPORT_TEMPLATE_STYLE.
+#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllexport MSVC_HACK
+#define EXPORT_TEMPLATE_STYLE_MATCH_DECLSPEC_dllimport DEFAULT
+
+// Sanity checks.
+//
+// EXPORT_TEMPLATE_TEST uses the same macro invocation pattern as
+// EXPORT_TEMPLATE_DECLARE and EXPORT_TEMPLATE_DEFINE do to check that they're
+// working correctly. When they're working correctly, the sequence of macro
+// replacements should go something like:
+//
+// EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
+//
+// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
+// EXPORT_TEMPLATE_STYLE(__declspec(dllimport), ),
+// __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(EXPORT_TEMPLATE_INVOKE(TEST_DEFAULT,
+// DEFAULT, __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(
+// __declspec(dllimport)), "__declspec(dllimport)");
+//
+// static_assert(true, "__declspec(dllimport)");
+//
+// When they're not working correctly, a syntax error should occur instead.
+#define EXPORT_TEMPLATE_TEST(want, export) \
+ static_assert(EXPORT_TEMPLATE_INVOKE( \
+ TEST_##want, EXPORT_TEMPLATE_STYLE(export, ), export), \
+ #export)
+#define EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT(...) true
+#define EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK(...) true
+
+EXPORT_TEMPLATE_TEST(DEFAULT, );
+EXPORT_TEMPLATE_TEST(DEFAULT, __attribute__((visibility("default"))));
+EXPORT_TEMPLATE_TEST(MSVC_HACK, __declspec(dllexport));
+EXPORT_TEMPLATE_TEST(DEFAULT, __declspec(dllimport));
+
+#undef EXPORT_TEMPLATE_TEST
+#undef EXPORT_TEMPLATE_TEST_DEFAULT_DEFAULT
+#undef EXPORT_TEMPLATE_TEST_MSVC_HACK_MSVC_HACK
diff --git a/wpiutil/src/main/native/include/wpi/Synchronization.h b/wpiutil/src/main/native/include/wpi/Synchronization.h
index 57fc4ee..4ac3c8c 100644
--- a/wpiutil/src/main/native/include/wpi/Synchronization.h
+++ b/wpiutil/src/main/native/include/wpi/Synchronization.h
@@ -4,12 +4,11 @@
#pragma once
+#ifdef __cplusplus
#include <climits> // NOLINT
-#ifdef __cplusplus
#include <initializer_list>
-
-#include "wpi/span.h"
+#include <span>
#endif
/**
@@ -43,8 +42,8 @@
constexpr int kHandleTypeSemaphore = 2;
constexpr int kHandleTypeCSBase = 3;
constexpr int kHandleTypeNTBase = 16;
-constexpr int kHandleTypeHALBase = 32;
-constexpr int kHandleTypeUserBase = 64;
+constexpr int kHandleTypeHALBase = 48;
+constexpr int kHandleTypeUserBase = 80;
/** @} */
/**
@@ -149,8 +148,8 @@
* least the size of the handles input array
* @return array of signaled handles (points into signaled array)
*/
-wpi::span<WPI_Handle> WaitForObjects(wpi::span<const WPI_Handle> handles,
- wpi::span<WPI_Handle> signaled);
+std::span<WPI_Handle> WaitForObjects(std::span<const WPI_Handle> handles,
+ std::span<WPI_Handle> signaled);
/**
* Waits for one or more handles to be signaled.
@@ -163,9 +162,9 @@
* least the size of the handles input array
* @return array of signaled handles (points into signaled array)
*/
-inline wpi::span<WPI_Handle> WaitForObjects(
- std::initializer_list<WPI_Handle> handles, wpi::span<WPI_Handle> signaled) {
- return WaitForObjects(wpi::span{handles.begin(), handles.size()}, signaled);
+inline std::span<WPI_Handle> WaitForObjects(
+ std::initializer_list<WPI_Handle> handles, std::span<WPI_Handle> signaled) {
+ return WaitForObjects(std::span{handles.begin(), handles.size()}, signaled);
}
/**
@@ -182,8 +181,8 @@
* handle being signaled; set to false otherwise (output)
* @return array of signaled handles (points into signaled array)
*/
-wpi::span<WPI_Handle> WaitForObjects(wpi::span<const WPI_Handle> handles,
- wpi::span<WPI_Handle> signaled,
+std::span<WPI_Handle> WaitForObjects(std::span<const WPI_Handle> handles,
+ std::span<WPI_Handle> signaled,
double timeout, bool* timedOut);
/**
* Waits for one or more handles to be signaled, with timeout.
@@ -199,10 +198,10 @@
* handle being signaled; set to false otherwise (output)
* @return array of signaled handles (points into signaled array)
*/
-inline wpi::span<WPI_Handle> WaitForObjects(
- std::initializer_list<WPI_Handle> handles, wpi::span<WPI_Handle> signaled,
+inline std::span<WPI_Handle> WaitForObjects(
+ std::initializer_list<WPI_Handle> handles, std::span<WPI_Handle> signaled,
double timeout, bool* timedOut) {
- return WaitForObjects(wpi::span{handles.begin(), handles.size()}, signaled,
+ return WaitForObjects(std::span{handles.begin(), handles.size()}, signaled,
timeout, timedOut);
}
diff --git a/wpiutil/src/main/native/include/wpi/TCPAcceptor.h b/wpiutil/src/main/native/include/wpi/TCPAcceptor.h
deleted file mode 100644
index 083897a..0000000
--- a/wpiutil/src/main/native/include/wpi/TCPAcceptor.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- TCPAcceptor.h
-
- TCPAcceptor class interface. TCPAcceptor provides methods to passively
- establish TCP/IP connections with clients.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#ifndef WPIUTIL_WPI_TCPACCEPTOR_H_
-#define WPIUTIL_WPI_TCPACCEPTOR_H_
-
-#include <atomic>
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/NetworkAcceptor.h"
-#include "wpi/TCPStream.h"
-
-namespace wpi {
-
-class Logger;
-
-class TCPAcceptor : public NetworkAcceptor {
- int m_lsd;
- int m_port;
- std::string m_address;
- bool m_listening;
- std::atomic_bool m_shutdown;
- Logger& m_logger;
-
- public:
- TCPAcceptor(int port, std::string_view address, Logger& logger);
- ~TCPAcceptor() override;
-
- int start() override;
- void shutdown() final;
- std::unique_ptr<NetworkStream> accept() override;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_TCPACCEPTOR_H_
diff --git a/wpiutil/src/main/native/include/wpi/TCPConnector.h b/wpiutil/src/main/native/include/wpi/TCPConnector.h
deleted file mode 100644
index 63e8906..0000000
--- a/wpiutil/src/main/native/include/wpi/TCPConnector.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- TCPConnector.h
-
- TCPConnector class interface. TCPConnector provides methods to actively
- establish TCP/IP connections with a server.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License
-*/
-
-#ifndef WPIUTIL_WPI_TCPCONNECTOR_H_
-#define WPIUTIL_WPI_TCPCONNECTOR_H_
-
-#include <memory>
-#include <utility>
-
-#include "wpi/NetworkStream.h"
-#include "wpi/span.h"
-
-namespace wpi {
-
-class Logger;
-
-class TCPConnector {
- public:
- static std::unique_ptr<NetworkStream> connect(const char* server, int port,
- Logger& logger,
- int timeout = 0);
- static std::unique_ptr<NetworkStream> connect_parallel(
- span<const std::pair<const char*, int>> servers, Logger& logger,
- int timeout = 0);
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_TCPCONNECTOR_H_
diff --git a/wpiutil/src/main/native/include/wpi/TCPStream.h b/wpiutil/src/main/native/include/wpi/TCPStream.h
deleted file mode 100644
index 2d54300..0000000
--- a/wpiutil/src/main/native/include/wpi/TCPStream.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- TCPStream.h
-
- TCPStream class interface. TCPStream provides methods to transfer
- data between peers over a TCP/IP connection.
-
- ------------------------------------------
-
- Copyright (c) 2013 [Vic Hargrave - http://vichargrave.com]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-#ifndef WPIUTIL_WPI_TCPSTREAM_H_
-#define WPIUTIL_WPI_TCPSTREAM_H_
-
-#include <cstddef>
-#include <string>
-#include <string_view>
-
-#include "wpi/NetworkStream.h"
-
-struct sockaddr_in;
-
-namespace wpi {
-
-class TCPStream : public NetworkStream {
- int m_sd;
- std::string m_peerIP;
- int m_peerPort;
- bool m_blocking;
-
- public:
- friend class TCPAcceptor;
- friend class TCPConnector;
-
- ~TCPStream() override;
-
- size_t send(const char* buffer, size_t len, Error* err) override;
- size_t receive(char* buffer, size_t len, Error* err,
- int timeout = 0) override;
- void close() final;
-
- std::string_view getPeerIP() const override;
- int getPeerPort() const override;
- void setNoDelay() override;
- bool setBlocking(bool enabled) override;
- int getNativeHandle() const override;
-
- TCPStream(const TCPStream& stream) = delete;
- TCPStream& operator=(const TCPStream&) = delete;
-
- private:
- bool WaitForReadEvent(int timeout);
-
- TCPStream(int sd, sockaddr_in* address);
- TCPStream() = delete;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_TCPSTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/UDPClient.h b/wpiutil/src/main/native/include/wpi/UDPClient.h
deleted file mode 100644
index fd2e30b..0000000
--- a/wpiutil/src/main/native/include/wpi/UDPClient.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UDPCLIENT_H_
-#define WPIUTIL_WPI_UDPCLIENT_H_
-
-#include <string>
-#include <string_view>
-
-#include "wpi/SmallVector.h"
-#include "wpi/mutex.h"
-#include "wpi/span.h"
-
-namespace wpi {
-
-class Logger;
-
-class UDPClient {
- int m_lsd;
- int m_port;
- std::string m_address;
- Logger& m_logger;
-
- public:
- explicit UDPClient(Logger& logger);
- UDPClient(std::string_view address, Logger& logger);
- UDPClient(const UDPClient& other) = delete;
- UDPClient(UDPClient&& other);
- ~UDPClient();
-
- UDPClient& operator=(const UDPClient& other) = delete;
- UDPClient& operator=(UDPClient&& other);
-
- int start();
- int start(int port);
- void shutdown();
- // The passed in address MUST be a resolved IP address.
- int send(span<const uint8_t> data, std::string_view server, int port);
- int send(std::string_view data, std::string_view server, int port);
- int receive(uint8_t* data_received, int receive_len);
- int receive(uint8_t* data_received, int receive_len,
- SmallVectorImpl<char>* addr_received, int* port_received);
- int set_timeout(double timeout);
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_UDPCLIENT_H_
diff --git a/wpiutil/src/main/native/include/wpi/UrlParser.h b/wpiutil/src/main/native/include/wpi/UrlParser.h
deleted file mode 100644
index 1932c3e..0000000
--- a/wpiutil/src/main/native/include/wpi/UrlParser.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_URLPARSER_H_
-#define WPIUTIL_WPI_URLPARSER_H_
-
-#include <string_view>
-
-#include "wpi/StringExtras.h"
-#include "wpi/http_parser.h"
-
-namespace wpi {
-
-/**
- * Parses a URL into its constiuent components.
- * `schema://userinfo@host:port/the/path?query#fragment`
- */
-class UrlParser {
- public:
- /**
- * Parse a URL.
- * @param in input
- * @param isConnect
- */
- UrlParser(std::string_view in, bool isConnect) {
- m_data = in;
- http_parser_url_init(&m_url);
- m_error = http_parser_parse_url(in.data(), in.size(), isConnect, &m_url);
- }
-
- /**
- * Determine if the URL is valid (e.g. the parse was successful).
- */
- bool IsValid() const { return !m_error; }
-
- bool HasSchema() const { return (m_url.field_set & (1 << UF_SCHEMA)) != 0; }
-
- bool HasHost() const { return (m_url.field_set & (1 << UF_HOST)) != 0; }
-
- bool HasPort() const { return (m_url.field_set & (1 << UF_PORT)) != 0; }
-
- bool HasPath() const { return (m_url.field_set & (1 << UF_PATH)) != 0; }
-
- bool HasQuery() const { return (m_url.field_set & (1 << UF_QUERY)) != 0; }
-
- bool HasFragment() const {
- return (m_url.field_set & (1 << UF_FRAGMENT)) != 0;
- }
-
- bool HasUserInfo() const {
- return (m_url.field_set & (1 << UF_USERINFO)) != 0;
- }
-
- std::string_view GetSchema() const {
- return wpi::substr(m_data, m_url.field_data[UF_SCHEMA].off,
- m_url.field_data[UF_SCHEMA].len);
- }
-
- std::string_view GetHost() const {
- return wpi::substr(m_data, m_url.field_data[UF_HOST].off,
- m_url.field_data[UF_HOST].len);
- }
-
- unsigned int GetPort() const { return m_url.port; }
-
- std::string_view GetPath() const {
- return wpi::substr(m_data, m_url.field_data[UF_PATH].off,
- m_url.field_data[UF_PATH].len);
- }
-
- std::string_view GetQuery() const {
- return wpi::substr(m_data, m_url.field_data[UF_QUERY].off,
- m_url.field_data[UF_QUERY].len);
- }
-
- std::string_view GetFragment() const {
- return wpi::substr(m_data, m_url.field_data[UF_FRAGMENT].off,
- m_url.field_data[UF_FRAGMENT].len);
- }
-
- std::string_view GetUserInfo() const {
- return wpi::substr(m_data, m_url.field_data[UF_USERINFO].off,
- m_url.field_data[UF_USERINFO].len);
- }
-
- private:
- bool m_error;
- std::string_view m_data;
- http_parser_url m_url;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_URLPARSER_H_
diff --git a/wpiutil/src/main/native/include/wpi/WebSocket.h b/wpiutil/src/main/native/include/wpi/WebSocket.h
deleted file mode 100644
index fc2ae4a..0000000
--- a/wpiutil/src/main/native/include/wpi/WebSocket.h
+++ /dev/null
@@ -1,477 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_WEBSOCKET_H_
-#define WPIUTIL_WPI_WEBSOCKET_H_
-
-#include <stdint.h>
-
-#include <functional>
-#include <initializer_list>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/SmallVector.h"
-#include "wpi/span.h"
-#include "wpi/uv/Buffer.h"
-#include "wpi/uv/Error.h"
-#include "wpi/uv/Timer.h"
-
-namespace wpi {
-
-namespace uv {
-class Stream;
-} // namespace uv
-
-/**
- * RFC 6455 compliant WebSocket client and server implementation.
- */
-class WebSocket : public std::enable_shared_from_this<WebSocket> {
- struct private_init {};
-
- static constexpr uint8_t kOpCont = 0x00;
- static constexpr uint8_t kOpText = 0x01;
- static constexpr uint8_t kOpBinary = 0x02;
- static constexpr uint8_t kOpClose = 0x08;
- static constexpr uint8_t kOpPing = 0x09;
- static constexpr uint8_t kOpPong = 0x0A;
- static constexpr uint8_t kOpMask = 0x0F;
- static constexpr uint8_t kFlagFin = 0x80;
- static constexpr uint8_t kFlagMasking = 0x80;
- static constexpr uint8_t kLenMask = 0x7f;
-
- public:
- WebSocket(uv::Stream& stream, bool server, const private_init&);
- WebSocket(const WebSocket&) = delete;
- WebSocket(WebSocket&&) = delete;
- WebSocket& operator=(const WebSocket&) = delete;
- WebSocket& operator=(WebSocket&&) = delete;
- ~WebSocket();
-
- /**
- * Connection states.
- */
- enum State {
- /** The connection is not yet open. */
- CONNECTING = 0,
- /** The connection is open and ready to communicate. */
- OPEN,
- /** The connection is in the process of closing. */
- CLOSING,
- /** The connection failed. */
- FAILED,
- /** The connection is closed. */
- CLOSED
- };
-
- /**
- * Client connection options.
- */
- struct ClientOptions {
- ClientOptions() : handshakeTimeout{(uv::Timer::Time::max)()} {}
-
- /** Timeout for the handshake request. */
- uv::Timer::Time handshakeTimeout; // NOLINT
-
- /** Additional headers to include in handshake. */
- span<const std::pair<std::string_view, std::string_view>> extraHeaders;
- };
-
- /**
- * Starts a client connection by performing the initial client handshake.
- * An open event is emitted when the handshake completes.
- * This sets the stream user data to the websocket.
- * @param stream Connection stream
- * @param uri The Request-URI to send
- * @param host The host or host:port to send
- * @param protocols The list of subprotocols
- * @param options Handshake options
- */
- static std::shared_ptr<WebSocket> CreateClient(
- uv::Stream& stream, std::string_view uri, std::string_view host,
- span<const std::string_view> protocols = {},
- const ClientOptions& options = {});
-
- /**
- * Starts a client connection by performing the initial client handshake.
- * An open event is emitted when the handshake completes.
- * This sets the stream user data to the websocket.
- * @param stream Connection stream
- * @param uri The Request-URI to send
- * @param host The host or host:port to send
- * @param protocols The list of subprotocols
- * @param options Handshake options
- */
- static std::shared_ptr<WebSocket> CreateClient(
- uv::Stream& stream, std::string_view uri, std::string_view host,
- std::initializer_list<std::string_view> protocols,
- const ClientOptions& options = {}) {
- return CreateClient(stream, uri, host, {protocols.begin(), protocols.end()},
- options);
- }
-
- /**
- * Starts a server connection by performing the initial server side handshake.
- * This should be called after the HTTP headers have been received.
- * An open event is emitted when the handshake completes.
- * This sets the stream user data to the websocket.
- * @param stream Connection stream
- * @param key The value of the Sec-WebSocket-Key header field in the client
- * request
- * @param version The value of the Sec-WebSocket-Version header field in the
- * client request
- * @param protocol The subprotocol to send to the client (in the
- * Sec-WebSocket-Protocol header field).
- */
- static std::shared_ptr<WebSocket> CreateServer(
- uv::Stream& stream, std::string_view key, std::string_view version,
- std::string_view protocol = {});
-
- /**
- * Get connection state.
- */
- State GetState() const { return m_state; }
-
- /**
- * Return if the connection is open. Messages can only be sent on open
- * connections.
- */
- bool IsOpen() const { return m_state == OPEN; }
-
- /**
- * Get the underlying stream.
- */
- uv::Stream& GetStream() const { return m_stream; }
-
- /**
- * Get the selected sub-protocol. Only valid in or after the open() event.
- */
- std::string_view GetProtocol() const { return m_protocol; }
-
- /**
- * Set the maximum message size. Default is 128 KB. If configured to combine
- * fragments this maximum applies to the entire message (all combined
- * fragments).
- * @param size Maximum message size in bytes
- */
- void SetMaxMessageSize(size_t size) { m_maxMessageSize = size; }
-
- /**
- * Set whether or not fragmented frames should be combined. Default is to
- * combine. If fragmented frames are combined, the text and binary callbacks
- * will always have the second parameter (fin) set to true.
- * @param combine True if fragmented frames should be combined.
- */
- void SetCombineFragments(bool combine) { m_combineFragments = combine; }
-
- /**
- * Initiate a closing handshake.
- * @param code A numeric status code (defaults to 1005, no status code)
- * @param reason A human-readable string explaining why the connection is
- * closing (optional).
- */
- void Close(uint16_t code = 1005, std::string_view reason = {});
-
- /**
- * Send a text message.
- * @param data UTF-8 encoded data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendText(span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kFlagFin | kOpText, data, std::move(callback));
- }
-
- /**
- * Send a text message.
- * @param data UTF-8 encoded data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendText(std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendText({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Send a binary message.
- * @param data Data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendBinary(span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kFlagFin | kOpBinary, data, std::move(callback));
- }
-
- /**
- * Send a binary message.
- * @param data Data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendBinary(std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendBinary({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Send a text message fragment. This must be followed by one or more
- * SendFragment() calls, where the last one has fin=True, to complete the
- * message.
- * @param data UTF-8 encoded data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendTextFragment(
- span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kOpText, data, std::move(callback));
- }
-
- /**
- * Send a text message fragment. This must be followed by one or more
- * SendFragment() calls, where the last one has fin=True, to complete the
- * message.
- * @param data UTF-8 encoded data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendTextFragment(
- std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendTextFragment({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Send a text message fragment. This must be followed by one or more
- * SendFragment() calls, where the last one has fin=True, to complete the
- * message.
- * @param data Data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendBinaryFragment(
- span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kOpBinary, data, std::move(callback));
- }
-
- /**
- * Send a text message fragment. This must be followed by one or more
- * SendFragment() calls, where the last one has fin=True, to complete the
- * message.
- * @param data Data to send
- * @param callback Callback which is invoked when the write completes.
- */
- void SendBinaryFragment(
- std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendBinaryFragment({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Send a continuation frame. This is used to send additional parts of a
- * message started with SendTextFragment() or SendBinaryFragment().
- * @param data Data to send
- * @param fin Set to true if this is the final fragment of the message
- * @param callback Callback which is invoked when the write completes.
- */
- void SendFragment(span<const uv::Buffer> data, bool fin,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kOpCont | (fin ? kFlagFin : 0), data, std::move(callback));
- }
-
- /**
- * Send a continuation frame. This is used to send additional parts of a
- * message started with SendTextFragment() or SendBinaryFragment().
- * @param data Data to send
- * @param fin Set to true if this is the final fragment of the message
- * @param callback Callback which is invoked when the write completes.
- */
- void SendFragment(std::initializer_list<uv::Buffer> data, bool fin,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendFragment({data.begin(), data.end()}, fin, std::move(callback));
- }
-
- /**
- * Send a ping frame with no data.
- * @param callback Optional callback which is invoked when the ping frame
- * write completes.
- */
- void SendPing(std::function<void(uv::Error)> callback = nullptr) {
- SendPing({}, [f = std::move(callback)](auto bufs, uv::Error err) {
- if (f) {
- f(err);
- }
- });
- }
-
- /**
- * Send a ping frame.
- * @param data Data to send in the ping frame
- * @param callback Callback which is invoked when the ping frame
- * write completes.
- */
- void SendPing(span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kFlagFin | kOpPing, data, std::move(callback));
- }
-
- /**
- * Send a ping frame.
- * @param data Data to send in the ping frame
- * @param callback Callback which is invoked when the ping frame
- * write completes.
- */
- void SendPing(std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendPing({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Send a pong frame with no data.
- * @param callback Optional callback which is invoked when the pong frame
- * write completes.
- */
- void SendPong(std::function<void(uv::Error)> callback = nullptr) {
- SendPong({}, [f = std::move(callback)](auto bufs, uv::Error err) {
- if (f) {
- f(err);
- }
- });
- }
-
- /**
- * Send a pong frame.
- * @param data Data to send in the pong frame
- * @param callback Callback which is invoked when the pong frame
- * write completes.
- */
- void SendPong(span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- Send(kFlagFin | kOpPong, data, std::move(callback));
- }
-
- /**
- * Send a pong frame.
- * @param data Data to send in the pong frame
- * @param callback Callback which is invoked when the pong frame
- * write completes.
- */
- void SendPong(std::initializer_list<uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback) {
- SendPong({data.begin(), data.end()}, std::move(callback));
- }
-
- /**
- * Fail the connection.
- */
- void Fail(uint16_t code = 1002, std::string_view reason = "protocol error");
-
- /**
- * Forcibly close the connection.
- */
- void Terminate(uint16_t code = 1006, std::string_view reason = "terminated");
-
- /**
- * Gets user-defined data.
- * @return User-defined data if any, nullptr otherwise.
- */
- template <typename T = void>
- std::shared_ptr<T> GetData() const {
- return std::static_pointer_cast<T>(m_data);
- }
-
- /**
- * Sets user-defined data.
- * @param data User-defined arbitrary data.
- */
- void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
-
- /**
- * Shuts down and closes the underlying stream.
- */
- void Shutdown();
-
- /**
- * Open event. Emitted when the connection is open and ready to communicate.
- * The parameter is the selected subprotocol.
- */
- sig::Signal<std::string_view> open;
-
- /**
- * Close event. Emitted when the connection is closed. The first parameter
- * is a numeric value indicating the status code explaining why the connection
- * has been closed. The second parameter is a human-readable string
- * explaining the reason why the connection has been closed.
- */
- sig::Signal<uint16_t, std::string_view> closed;
-
- /**
- * Text message event. Emitted when a text message is received.
- * The first parameter is the data, the second parameter is true if the
- * data is the last fragment of the message.
- */
- sig::Signal<std::string_view, bool> text;
-
- /**
- * Binary message event. Emitted when a binary message is received.
- * The first parameter is the data, the second parameter is true if the
- * data is the last fragment of the message.
- */
- sig::Signal<span<const uint8_t>, bool> binary;
-
- /**
- * Ping event. Emitted when a ping message is received.
- */
- sig::Signal<span<const uint8_t>> ping;
-
- /**
- * Pong event. Emitted when a pong message is received.
- */
- sig::Signal<span<const uint8_t>> pong;
-
- private:
- // user data
- std::shared_ptr<void> m_data;
-
- // constructor parameters
- uv::Stream& m_stream;
- bool m_server;
-
- // subprotocol, set via constructor (server) or handshake (client)
- std::string m_protocol;
-
- // user-settable configuration
- size_t m_maxMessageSize = 128 * 1024;
- bool m_combineFragments = true;
-
- // operating state
- State m_state = CONNECTING;
-
- // incoming message buffers/state
- SmallVector<uint8_t, 14> m_header;
- size_t m_headerSize = 0;
- SmallVector<uint8_t, 1024> m_payload;
- size_t m_frameStart = 0;
- uint64_t m_frameSize = UINT64_MAX;
- uint8_t m_fragmentOpcode = 0;
-
- // temporary data used only during client handshake
- class ClientHandshakeData;
- std::unique_ptr<ClientHandshakeData> m_clientHandshake;
-
- void StartClient(std::string_view uri, std::string_view host,
- span<const std::string_view> protocols,
- const ClientOptions& options);
- void StartServer(std::string_view key, std::string_view version,
- std::string_view protocol);
- void SendClose(uint16_t code, std::string_view reason);
- void SetClosed(uint16_t code, std::string_view reason, bool failed = false);
- void HandleIncoming(uv::Buffer& buf, size_t size);
- void Send(uint8_t opcode, span<const uv::Buffer> data,
- std::function<void(span<uv::Buffer>, uv::Error)> callback);
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_WEBSOCKET_H_
diff --git a/wpiutil/src/main/native/include/wpi/WebSocketServer.h b/wpiutil/src/main/native/include/wpi/WebSocketServer.h
deleted file mode 100644
index 1f76d16..0000000
--- a/wpiutil/src/main/native/include/wpi/WebSocketServer.h
+++ /dev/null
@@ -1,177 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_WEBSOCKETSERVER_H_
-#define WPIUTIL_WPI_WEBSOCKETSERVER_H_
-
-#include <functional>
-#include <initializer_list>
-#include <memory>
-#include <string>
-#include <string_view>
-#include <utility>
-
-#include "wpi/HttpParser.h"
-#include "wpi/Signal.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/WebSocket.h"
-#include "wpi/span.h"
-
-namespace wpi {
-
-namespace uv {
-class Stream;
-} // namespace uv
-
-/**
- * WebSocket HTTP server helper. Handles websocket-specific headers. User
- * must provide the HttpParser.
- */
-class WebSocketServerHelper {
- public:
- /**
- * Constructor.
- * @param req HttpParser for request
- */
- explicit WebSocketServerHelper(HttpParser& req);
-
- /**
- * Get whether or not this was a websocket upgrade.
- * Only valid during and after the upgrade event.
- */
- bool IsWebsocket() const { return m_websocket; }
-
- /**
- * Try to find a match to the list of sub-protocols provided by the client.
- * The list is priority ordered, so the first match wins.
- * Only valid during and after the upgrade event.
- * @param protocols Acceptable protocols
- * @return Pair; first item is true if a match was made, false if not.
- * Second item is the matched protocol if a match was made, otherwise
- * is empty.
- */
- std::pair<bool, std::string_view> MatchProtocol(
- span<const std::string_view> protocols);
-
- /**
- * Try to find a match to the list of sub-protocols provided by the client.
- * The list is priority ordered, so the first match wins.
- * Only valid during and after the upgrade event.
- * @param protocols Acceptable protocols
- * @return Pair; first item is true if a match was made, false if not.
- * Second item is the matched protocol if a match was made, otherwise
- * is empty.
- */
- std::pair<bool, std::string_view> MatchProtocol(
- std::initializer_list<std::string_view> protocols) {
- return MatchProtocol({protocols.begin(), protocols.end()});
- }
-
- /**
- * Accept the upgrade. Disconnect other readers (such as the HttpParser
- * reader) before calling this. See also WebSocket::CreateServer().
- * @param stream Connection stream
- * @param protocol The subprotocol to send to the client
- */
- std::shared_ptr<WebSocket> Accept(uv::Stream& stream,
- std::string_view protocol = {}) {
- return WebSocket::CreateServer(stream, m_key, m_version, protocol);
- }
-
- bool IsUpgrade() const { return m_gotHost && m_websocket; }
-
- /**
- * Upgrade event. Call Accept() to accept the upgrade.
- */
- sig::Signal<> upgrade;
-
- private:
- bool m_gotHost = false;
- bool m_websocket = false;
- SmallVector<std::string, 2> m_protocols;
- SmallString<64> m_key;
- SmallString<16> m_version;
-};
-
-/**
- * Dedicated WebSocket server.
- */
-class WebSocketServer : public std::enable_shared_from_this<WebSocketServer> {
- struct private_init {};
-
- public:
- /**
- * Server options.
- */
- struct ServerOptions {
- /**
- * Checker for URL. Return true if URL should be accepted. By default all
- * URLs are accepted.
- */
- std::function<bool(std::string_view)> checkUrl;
-
- /**
- * Checker for Host header. Return true if Host should be accepted. By
- * default all hosts are accepted.
- */
- std::function<bool(std::string_view)> checkHost;
- };
-
- /**
- * Private constructor.
- */
- WebSocketServer(uv::Stream& stream, span<const std::string_view> protocols,
- ServerOptions options, const private_init&);
-
- /**
- * Starts a dedicated WebSocket server on the provided connection. The
- * connection should be an accepted client stream.
- * This also sets the stream user data to the socket server.
- * A connected event is emitted when the connection is opened.
- * @param stream Connection stream
- * @param protocols Acceptable subprotocols
- * @param options Handshake options
- */
- static std::shared_ptr<WebSocketServer> Create(
- uv::Stream& stream, span<const std::string_view> protocols = {},
- const ServerOptions& options = {});
-
- /**
- * Starts a dedicated WebSocket server on the provided connection. The
- * connection should be an accepted client stream.
- * This also sets the stream user data to the socket server.
- * A connected event is emitted when the connection is opened.
- * @param stream Connection stream
- * @param protocols Acceptable subprotocols
- * @param options Handshake options
- */
- static std::shared_ptr<WebSocketServer> Create(
- uv::Stream& stream, std::initializer_list<std::string_view> protocols,
- const ServerOptions& options = {}) {
- return Create(stream, {protocols.begin(), protocols.end()}, options);
- }
-
- /**
- * Connected event. First parameter is the URL, second is the websocket.
- */
- sig::Signal<std::string_view, WebSocket&> connected;
-
- private:
- uv::Stream& m_stream;
- HttpParser m_req{HttpParser::kRequest};
- WebSocketServerHelper m_helper;
- SmallVector<std::string, 2> m_protocols;
- ServerOptions m_options;
- bool m_aborted = false;
- sig::ScopedConnection m_dataConn;
- sig::ScopedConnection m_errorConn;
- sig::ScopedConnection m_endConn;
-
- void Abort(uint16_t code, std::string_view reason);
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_WEBSOCKETSERVER_H_
diff --git a/wpiutil/src/main/native/include/wpi/WorkerThread.h b/wpiutil/src/main/native/include/wpi/WorkerThread.h
deleted file mode 100644
index 6c8852e..0000000
--- a/wpiutil/src/main/native/include/wpi/WorkerThread.h
+++ /dev/null
@@ -1,285 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_WORKERTHREAD_H_
-#define WPIUTIL_WPI_WORKERTHREAD_H_
-
-#include <functional>
-#include <memory>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "wpi/SafeThread.h"
-#include "wpi/future.h"
-#include "wpi/uv/Async.h"
-
-namespace wpi {
-
-namespace detail {
-
-template <typename R>
-struct WorkerThreadAsync {
- using AfterWorkFunction = std::function<void(R)>;
-
- ~WorkerThreadAsync() { UnsetLoop(); }
-
- void SetLoop(uv::Loop& loop) {
- auto async = uv::Async<AfterWorkFunction, R>::Create(loop);
- async->wakeup.connect(
- [](AfterWorkFunction func, R result) { func(result); });
- m_async = async;
- }
-
- void UnsetLoop() {
- if (auto async = m_async.lock()) {
- async->Close();
- m_async.reset();
- }
- }
-
- std::weak_ptr<uv::Async<AfterWorkFunction, R>> m_async;
-};
-
-template <>
-struct WorkerThreadAsync<void> {
- using AfterWorkFunction = std::function<void()>;
-
- ~WorkerThreadAsync() { RemoveLoop(); }
-
- void SetLoop(uv::Loop& loop) {
- auto async = uv::Async<AfterWorkFunction>::Create(loop);
- async->wakeup.connect([](AfterWorkFunction func) { func(); });
- m_async = async;
- }
-
- void RemoveLoop() {
- if (auto async = m_async.lock()) {
- async->Close();
- m_async.reset();
- }
- }
-
- std::weak_ptr<uv::Async<AfterWorkFunction>> m_async;
-};
-
-template <typename R, typename... T>
-struct WorkerThreadRequest {
- using WorkFunction = std::function<R(T...)>;
- using AfterWorkFunction = typename WorkerThreadAsync<R>::AfterWorkFunction;
-
- WorkerThreadRequest() = default;
- WorkerThreadRequest(uint64_t promiseId_, WorkFunction work_,
- std::tuple<T...> params_)
- : promiseId(promiseId_),
- work(std::move(work_)),
- params(std::move(params_)) {}
- WorkerThreadRequest(WorkFunction work_, AfterWorkFunction afterWork_,
- std::tuple<T...> params_)
- : promiseId(0),
- work(std::move(work_)),
- afterWork(std::move(afterWork_)),
- params(std::move(params_)) {}
-
- uint64_t promiseId;
- WorkFunction work;
- AfterWorkFunction afterWork;
- std::tuple<T...> params;
-};
-
-template <typename R, typename... T>
-class WorkerThreadThread : public SafeThread {
- public:
- using Request = WorkerThreadRequest<R, T...>;
-
- void Main() override;
-
- std::vector<Request> m_requests;
- PromiseFactory<R> m_promises;
- detail::WorkerThreadAsync<R> m_async;
-};
-
-template <typename R, typename... T>
-void RunWorkerThreadRequest(WorkerThreadThread<R, T...>& thr,
- WorkerThreadRequest<R, T...>& req) {
- R result = std::apply(req.work, std::move(req.params));
- if (req.afterWork) {
- if (auto async = thr.m_async.m_async.lock()) {
- async->Send(std::move(req.afterWork), std::move(result));
- }
- } else {
- thr.m_promises.SetValue(req.promiseId, std::move(result));
- }
-}
-
-template <typename... T>
-void RunWorkerThreadRequest(WorkerThreadThread<void, T...>& thr,
- WorkerThreadRequest<void, T...>& req) {
- std::apply(req.work, req.params);
- if (req.afterWork) {
- if (auto async = thr.m_async.m_async.lock()) {
- async->Send(std::move(req.afterWork));
- }
- } else {
- thr.m_promises.SetValue(req.promiseId);
- }
-}
-
-template <typename R, typename... T>
-void WorkerThreadThread<R, T...>::Main() {
- std::vector<Request> requests;
- while (m_active) {
- std::unique_lock lock(m_mutex);
- m_cond.wait(lock, [&] { return !m_active || !m_requests.empty(); });
- if (!m_active) {
- break;
- }
-
- // don't want to hold the lock while executing the callbacks
- requests.swap(m_requests);
- lock.unlock();
-
- for (auto&& req : requests) {
- if (!m_active) {
- break; // requests may be long-running
- }
- RunWorkerThreadRequest(*this, req);
- }
- requests.clear();
- m_promises.Notify();
- }
-}
-
-} // namespace detail
-
-template <typename T>
-class WorkerThread;
-
-template <typename R, typename... T>
-class WorkerThread<R(T...)> final {
- using Thread = detail::WorkerThreadThread<R, T...>;
-
- public:
- using WorkFunction = std::function<R(T...)>;
- using AfterWorkFunction =
- typename detail::WorkerThreadAsync<R>::AfterWorkFunction;
-
- WorkerThread() { m_owner.Start(); }
-
- /**
- * Set the loop. This must be called from the loop thread.
- * Subsequent calls to QueueWorkThen will run afterWork on the provided
- * loop (via an async handle).
- *
- * @param loop the loop to use for running afterWork routines
- */
- void SetLoop(uv::Loop& loop) {
- if (auto thr = m_owner.GetThread()) {
- thr->m_async.SetLoop(loop);
- }
- }
-
- /**
- * Set the loop. This must be called from the loop thread.
- * Subsequent calls to QueueWorkThen will run afterWork on the provided
- * loop (via an async handle).
- *
- * @param loop the loop to use for running afterWork routines
- */
- void SetLoop(std::shared_ptr<uv::Loop> loop) { SetLoop(*loop); }
-
- /**
- * Unset the loop. This must be called from the loop thread.
- * Subsequent calls to QueueWorkThen will no longer run afterWork.
- */
- void UnsetLoop() {
- if (auto thr = m_owner.GetThread()) {
- thr->m_async.UnsetLoop();
- }
- }
-
- /**
- * Get the handle used by QueueWorkThen() to run afterWork.
- * This handle is set by SetLoop().
- * Calling Close() on this handle is the same as calling UnsetLoop().
- *
- * @return The handle (if nullptr, no handle is set)
- */
- std::shared_ptr<uv::Handle> GetHandle() const {
- if (auto thr = m_owner.GetThread()) {
- return thr->m_async.m_async.lock();
- } else {
- return nullptr;
- }
- }
-
- /**
- * Wakeup the worker thread, call the work function, and return a future for
- * the result.
- *
- * It’s safe to call this function from any thread.
- * The work function will be called on the worker thread.
- *
- * The future will return a default-constructed result if this class is
- * destroyed while waiting for a result.
- *
- * @param work Work function (called on worker thread)
- * @param u Arguments to work function
- */
- template <typename... U>
- future<R> QueueWork(WorkFunction work, U&&... u) {
- if (auto thr = m_owner.GetThread()) {
- // create the future
- uint64_t req = thr->m_promises.CreateRequest();
-
- // add the parameters to the input queue
- thr->m_requests.emplace_back(
- req, std::move(work), std::forward_as_tuple(std::forward<U>(u)...));
-
- // signal the thread
- thr->m_cond.notify_one();
-
- // return future
- return thr->m_promises.CreateFuture(req);
- }
-
- // XXX: is this the right thing to do?
- return future<R>();
- }
-
- /**
- * Wakeup the worker thread, call the work function, and call the afterWork
- * function with the result on the loop set by SetLoop().
- *
- * It’s safe to call this function from any thread.
- * The work function will be called on the worker thread, and the afterWork
- * function will be called on the loop thread.
- *
- * SetLoop() must be called prior to calling this function for afterWork to
- * be called.
- *
- * @param work Work function (called on worker thread)
- * @param afterWork After work function (called on loop thread)
- * @param u Arguments to work function
- */
- template <typename... U>
- void QueueWorkThen(WorkFunction work, AfterWorkFunction afterWork, U&&... u) {
- if (auto thr = m_owner.GetThread()) {
- // add the parameters to the input queue
- thr->m_requests.emplace_back(
- std::move(work), std::move(afterWork),
- std::forward_as_tuple(std::forward<U>(u)...));
-
- // signal the thread
- thr->m_cond.notify_one();
- }
- }
-
- private:
- SafeThreadOwner<Thread> m_owner;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_WORKERTHREAD_H_
diff --git a/wpiutil/src/main/native/include/wpi/array.h b/wpiutil/src/main/native/include/wpi/array.h
index f2604ec..cfbb7b0 100644
--- a/wpiutil/src/main/native/include/wpi/array.h
+++ b/wpiutil/src/main/native/include/wpi/array.h
@@ -24,33 +24,33 @@
template <typename T, size_t N>
class array : public std::array<T, N> {
public:
- explicit array(empty_array_t) {}
+ constexpr explicit array(empty_array_t) {}
template <typename... Ts>
- array(T arg, Ts&&... args) // NOLINT
+ 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");
}
- array(const array<T, N>&) = default;
- array& operator=(const array<T, N>&) = default;
- array(array<T, N>&&) = default;
- array& operator=(array<T, N>&&) = default;
+ constexpr array(const array<T, N>&) = default;
+ constexpr array& operator=(const array<T, N>&) = default;
+ constexpr array(array<T, N>&&) = default;
+ constexpr array& operator=(array<T, N>&&) = default;
- array(const std::array<T, N>& rhs) { // NOLINT
+ constexpr array(const std::array<T, N>& rhs) { // NOLINT
*static_cast<std::array<T, N>*>(this) = rhs;
}
- array& operator=(const std::array<T, N>& rhs) {
+ constexpr array& operator=(const std::array<T, N>& rhs) {
*static_cast<std::array<T, N>*>(this) = rhs;
return *this;
}
- array(std::array<T, N>&& rhs) { // NOLINT
+ constexpr array(std::array<T, N>&& rhs) { // NOLINT
*static_cast<std::array<T, N>*>(this) = rhs;
}
- array& operator=(std::array<T, N>&& rhs) {
+ constexpr array& operator=(std::array<T, N>&& rhs) {
*static_cast<std::array<T, N>*>(this) = rhs;
return *this;
}
diff --git a/wpiutil/src/main/native/include/wpi/circular_buffer.h b/wpiutil/src/main/native/include/wpi/circular_buffer.h
index 40913f9..c54e2f5 100644
--- a/wpiutil/src/main/native/include/wpi/circular_buffer.h
+++ b/wpiutil/src/main/native/include/wpi/circular_buffer.h
@@ -43,10 +43,7 @@
++(*this);
return retval;
}
- bool operator==(const iterator& other) const {
- return m_buffer == other.m_buffer && m_index == other.m_index;
- }
- bool operator!=(const iterator& other) const { return !(*this == other); }
+ bool operator==(const iterator&) const = default;
reference operator*() { return (*m_buffer)[m_index]; }
private:
@@ -74,12 +71,7 @@
++(*this);
return retval;
}
- bool operator==(const const_iterator& other) const {
- return m_buffer == other.m_buffer && m_index == other.m_index;
- }
- bool operator!=(const const_iterator& other) const {
- return !(*this == other);
- }
+ bool operator==(const const_iterator&) const = default;
const_reference operator*() const { return (*m_buffer)[m_index]; }
private:
diff --git a/wpiutil/src/main/native/include/wpi/deprecated.h b/wpiutil/src/main/native/include/wpi/deprecated.h
index 6e6a3bf..c5b4af2 100644
--- a/wpiutil/src/main/native/include/wpi/deprecated.h
+++ b/wpiutil/src/main/native/include/wpi/deprecated.h
@@ -9,4 +9,23 @@
#define WPI_DEPRECATED(msg) [[deprecated(msg)]]
#endif
+#ifndef WPI_IGNORE_DEPRECATED
+#ifdef __GNUC__
+#define WPI_IGNORE_DEPRECATED \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
+#elif defined(_WIN32)
+#define WPI_IGNORE_DEPRECATED _Pragma("warning(disable : 4996)")
+#endif
+
+#endif
+
+#ifndef WPI_UNIGNORE_DEPRECATED
+#ifdef __GNUC__
+#define WPI_UNIGNORE_DEPRECATED _Pragma("GCC diagnostic pop")
+#elif defined(_WIN32)
+#define WPI_UNIGNORE_DEPRECATED _Pragma("warning(default : 4996)")
+#endif
+#endif
+
#endif // WPIUTIL_WPI_DEPRECATED_H_
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 8779bfc..024e04c 100644
--- a/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
+++ b/wpiutil/src/main/native/include/wpi/fmt/raw_ostream.h
@@ -22,7 +22,7 @@
*/
template <typename S, typename... Args>
void print(wpi::raw_ostream& os, const S& format_str, Args&&... args) {
- vprint(os, format_str, fmt::make_args_checked<Args...>(format_str, args...));
+ vprint(os, format_str, fmt::make_format_args(args...));
}
FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/include/wpi/fs.h b/wpiutil/src/main/native/include/wpi/fs.h
index fca8069..587a23c 100644
--- a/wpiutil/src/main/native/include/wpi/fs.h
+++ b/wpiutil/src/main/native/include/wpi/fs.h
@@ -40,7 +40,7 @@
#ifndef GHC_USE_STD_FS
// #define GHC_WIN_DISABLE_WSTRING_STORAGE_TYPE
#define GHC_FILESYSTEM_FWD
-#include "ghc/filesystem.hpp"
+#include "wpi/ghc/filesystem.hpp"
namespace fs {
using namespace ghc::filesystem;
using ifstream = ghc::filesystem::ifstream;
diff --git a/wpiutil/src/main/native/include/wpi/future.h b/wpiutil/src/main/native/include/wpi/future.h
index 5cb4a8d..70dc60f 100644
--- a/wpiutil/src/main/native/include/wpi/future.h
+++ b/wpiutil/src/main/native/include/wpi/future.h
@@ -334,7 +334,7 @@
}
}
- template <typename F, typename R = typename std::result_of<F && (T &&)>::type>
+ template <typename F, typename R = typename std::invoke_result_t<F&&, T&&>>
future<R> then(F&& func) {
return then(PromiseFactory<R>::GetInstance(), std::forward<F>(func));
}
@@ -457,7 +457,7 @@
}
}
- template <typename F, typename R = typename std::result_of<F && ()>::type>
+ template <typename F, typename R = typename std::invoke_result_t<F&&>>
future<R> then(F&& func) {
return then(PromiseFactory<R>::GetInstance(), std::forward<F>(func));
}
diff --git a/wpiutil/src/main/native/include/wpi/hostname.h b/wpiutil/src/main/native/include/wpi/hostname.h
deleted file mode 100644
index bd93b4a..0000000
--- a/wpiutil/src/main/native/include/wpi/hostname.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_HOSTNAME_H_
-#define WPIUTIL_WPI_HOSTNAME_H_
-
-#include <string>
-#include <string_view>
-
-namespace wpi {
-template <typename T>
-class SmallVectorImpl;
-
-std::string GetHostname();
-std::string_view GetHostname(SmallVectorImpl<char>& name);
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_HOSTNAME_H_
diff --git a/wpiutil/src/main/native/include/wpi/http_parser.h b/wpiutil/src/main/native/include/wpi/http_parser.h
deleted file mode 100644
index 2189b8f..0000000
--- a/wpiutil/src/main/native/include/wpi/http_parser.h
+++ /dev/null
@@ -1,421 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-#ifndef wpi_http_parser_h
-#define wpi_http_parser_h
-
-/* Also update SONAME in the Makefile whenever you change these. */
-#define HTTP_PARSER_VERSION_MAJOR 2
-#define HTTP_PARSER_VERSION_MINOR 8
-#define HTTP_PARSER_VERSION_PATCH 1
-
-#include <stddef.h>
-#include <stdint.h>
-
-/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
- * faster
- */
-#ifndef HTTP_PARSER_STRICT
-# define HTTP_PARSER_STRICT 1
-#endif
-
-/* Maximium header size allowed. If the macro is not defined
- * before including this header then the default is used. To
- * change the maximum header size, define the macro in the build
- * environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
- * the effective limit on the size of the header, define the macro
- * to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
- */
-#ifndef HTTP_MAX_HEADER_SIZE
-# define HTTP_MAX_HEADER_SIZE (80*1024)
-#endif
-
-namespace wpi {
-
-struct http_parser;
-struct http_parser_settings;
-
-
-/* Callbacks should return non-zero to indicate an error. The parser will
- * then halt execution.
- *
- * The one exception is on_headers_complete. In a HTTP_RESPONSE parser
- * returning '1' from on_headers_complete will tell the parser that it
- * should not expect a body. This is used when receiving a response to a
- * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
- * chunked' headers that indicate the presence of a body.
- *
- * Returning `2` from on_headers_complete will tell parser that it should not
- * expect neither a body nor any further responses on this connection. This is
- * useful for handling responses to a CONNECT request which may not contain
- * `Upgrade` or `Connection: upgrade` headers.
- *
- * http_data_cb does not return data chunks. It will be called arbitrarily
- * many times for each string. E.G. you might get 10 callbacks for "on_url"
- * each providing just a few characters more data.
- */
-typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
-typedef int (*http_cb) (http_parser*);
-
-
-/* Status Codes */
-#define HTTP_STATUS_MAP(XX) \
- XX(100, CONTINUE, Continue) \
- XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
- XX(102, PROCESSING, Processing) \
- XX(200, OK, OK) \
- XX(201, CREATED, Created) \
- XX(202, ACCEPTED, Accepted) \
- XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
- XX(204, NO_CONTENT, No Content) \
- XX(205, RESET_CONTENT, Reset Content) \
- XX(206, PARTIAL_CONTENT, Partial Content) \
- XX(207, MULTI_STATUS, Multi-Status) \
- XX(208, ALREADY_REPORTED, Already Reported) \
- XX(226, IM_USED, IM Used) \
- XX(300, MULTIPLE_CHOICES, Multiple Choices) \
- XX(301, MOVED_PERMANENTLY, Moved Permanently) \
- XX(302, FOUND, Found) \
- XX(303, SEE_OTHER, See Other) \
- XX(304, NOT_MODIFIED, Not Modified) \
- XX(305, USE_PROXY, Use Proxy) \
- XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
- XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
- XX(400, BAD_REQUEST, Bad Request) \
- XX(401, UNAUTHORIZED, Unauthorized) \
- XX(402, PAYMENT_REQUIRED, Payment Required) \
- XX(403, FORBIDDEN, Forbidden) \
- XX(404, NOT_FOUND, Not Found) \
- XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
- XX(406, NOT_ACCEPTABLE, Not Acceptable) \
- XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
- XX(408, REQUEST_TIMEOUT, Request Timeout) \
- XX(409, CONFLICT, Conflict) \
- XX(410, GONE, Gone) \
- XX(411, LENGTH_REQUIRED, Length Required) \
- XX(412, PRECONDITION_FAILED, Precondition Failed) \
- XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
- XX(414, URI_TOO_LONG, URI Too Long) \
- XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
- XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
- XX(417, EXPECTATION_FAILED, Expectation Failed) \
- XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
- XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
- XX(423, LOCKED, Locked) \
- XX(424, FAILED_DEPENDENCY, Failed Dependency) \
- XX(426, UPGRADE_REQUIRED, Upgrade Required) \
- XX(428, PRECONDITION_REQUIRED, Precondition Required) \
- XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
- XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
- XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
- XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
- XX(501, NOT_IMPLEMENTED, Not Implemented) \
- XX(502, BAD_GATEWAY, Bad Gateway) \
- XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
- XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
- XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
- XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
- XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
- XX(508, LOOP_DETECTED, Loop Detected) \
- XX(510, NOT_EXTENDED, Not Extended) \
- XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
-
-enum http_status
- {
-#define XX(num, name, string) HTTP_STATUS_##name = num,
- HTTP_STATUS_MAP(XX)
-#undef XX
- };
-
-
-/* Request Methods */
-#define HTTP_METHOD_MAP(XX) \
- XX(0, DELETE, DELETE) \
- XX(1, GET, GET) \
- XX(2, HEAD, HEAD) \
- XX(3, POST, POST) \
- XX(4, PUT, PUT) \
- /* pathological */ \
- XX(5, CONNECT, CONNECT) \
- XX(6, OPTIONS, OPTIONS) \
- XX(7, TRACE, TRACE) \
- /* WebDAV */ \
- XX(8, COPY, COPY) \
- XX(9, LOCK, LOCK) \
- XX(10, MKCOL, MKCOL) \
- XX(11, MOVE, MOVE) \
- XX(12, PROPFIND, PROPFIND) \
- XX(13, PROPPATCH, PROPPATCH) \
- XX(14, SEARCH, SEARCH) \
- XX(15, UNLOCK, UNLOCK) \
- XX(16, BIND, BIND) \
- XX(17, REBIND, REBIND) \
- XX(18, UNBIND, UNBIND) \
- XX(19, ACL, ACL) \
- /* subversion */ \
- XX(20, REPORT, REPORT) \
- XX(21, MKACTIVITY, MKACTIVITY) \
- XX(22, CHECKOUT, CHECKOUT) \
- XX(23, MERGE, MERGE) \
- /* upnp */ \
- XX(24, MSEARCH, M-SEARCH) \
- XX(25, NOTIFY, NOTIFY) \
- XX(26, SUBSCRIBE, SUBSCRIBE) \
- XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
- /* RFC-5789 */ \
- XX(28, PATCH, PATCH) \
- XX(29, PURGE, PURGE) \
- /* CalDAV */ \
- XX(30, MKCALENDAR, MKCALENDAR) \
- /* RFC-2068, section 19.6.1.2 */ \
- XX(31, LINK, LINK) \
- XX(32, UNLINK, UNLINK) \
- /* icecast */ \
- XX(33, SOURCE, SOURCE) \
-
-enum http_method
- {
-#define XX(num, name, string) HTTP_##name = num,
- HTTP_METHOD_MAP(XX)
-#undef XX
- };
-
-
-enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
-
-
-/* Flag values for http_parser.flags field */
-enum flags
- { F_CHUNKED = 1 << 0
- , F_CONNECTION_KEEP_ALIVE = 1 << 1
- , F_CONNECTION_CLOSE = 1 << 2
- , F_CONNECTION_UPGRADE = 1 << 3
- , F_TRAILING = 1 << 4
- , F_UPGRADE = 1 << 5
- , F_SKIPBODY = 1 << 6
- , F_CONTENTLENGTH = 1 << 7
- };
-
-
-/* Map for errno-related constants
- *
- * The provided argument should be a macro that takes 2 arguments.
- */
-#define HTTP_ERRNO_MAP(XX) \
- /* No error */ \
- XX(OK, "success") \
- \
- /* Callback-related errors */ \
- XX(CB_message_begin, "the on_message_begin callback failed") \
- XX(CB_url, "the on_url callback failed") \
- XX(CB_header_field, "the on_header_field callback failed") \
- XX(CB_header_value, "the on_header_value callback failed") \
- XX(CB_headers_complete, "the on_headers_complete callback failed") \
- XX(CB_body, "the on_body callback failed") \
- XX(CB_message_complete, "the on_message_complete callback failed") \
- XX(CB_status, "the on_status callback failed") \
- XX(CB_chunk_header, "the on_chunk_header callback failed") \
- XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
- \
- /* Parsing-related errors */ \
- XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
- XX(HEADER_OVERFLOW, \
- "too many header bytes seen; overflow detected") \
- XX(CLOSED_CONNECTION, \
- "data received after completed connection: close message") \
- XX(INVALID_VERSION, "invalid HTTP version") \
- XX(INVALID_STATUS, "invalid HTTP status code") \
- XX(INVALID_METHOD, "invalid HTTP method") \
- XX(INVALID_URL, "invalid URL") \
- XX(INVALID_HOST, "invalid host") \
- XX(INVALID_PORT, "invalid port") \
- XX(INVALID_PATH, "invalid path") \
- XX(INVALID_QUERY_STRING, "invalid query string") \
- XX(INVALID_FRAGMENT, "invalid fragment") \
- XX(LF_EXPECTED, "LF character expected") \
- XX(INVALID_HEADER_TOKEN, "invalid character in header") \
- XX(INVALID_CONTENT_LENGTH, \
- "invalid character in content-length header") \
- XX(UNEXPECTED_CONTENT_LENGTH, \
- "unexpected content-length header") \
- XX(INVALID_CHUNK_SIZE, \
- "invalid character in chunk size header") \
- XX(INVALID_CONSTANT, "invalid constant string") \
- XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
- XX(STRICT, "strict mode assertion failed") \
- XX(PAUSED, "parser is paused") \
- XX(UNKNOWN, "an unknown error occurred")
-
-
-/* Define HPE_* values for each errno value above */
-#define HTTP_ERRNO_GEN(n, s) HPE_##n,
-enum http_errno {
- HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
-};
-#undef HTTP_ERRNO_GEN
-
-
-/* Get an http_errno value from an http_parser */
-#define HTTP_PARSER_ERRNO(p) ((::wpi::http_errno) (p)->http_errno)
-
-
-struct http_parser {
- /** PRIVATE **/
- unsigned int type : 2; /* enum http_parser_type */
- unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
- unsigned int state : 7; /* enum state from http_parser.c */
- unsigned int header_state : 7; /* enum header_state from http_parser.c */
- unsigned int index : 7; /* index into current matcher */
- unsigned int lenient_http_headers : 1;
-
- uint32_t nread; /* # bytes read in various scenarios */
- uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */
-
- /** READ-ONLY **/
- unsigned short http_major;
- unsigned short http_minor;
- unsigned int status_code : 16; /* responses only */
- unsigned int method : 8; /* requests only */
- unsigned int http_errno : 7;
-
- /* 1 = Upgrade header was present and the parser has exited because of that.
- * 0 = No upgrade header present.
- * Should be checked when http_parser_execute() returns in addition to
- * error checking.
- */
- unsigned int upgrade : 1;
-
- /** PUBLIC **/
- void *data; /* A pointer to get hook to the "connection" or "socket" object */
-};
-
-
-struct http_parser_settings {
- http_cb on_message_begin;
- http_data_cb on_url;
- http_data_cb on_status;
- http_data_cb on_header_field;
- http_data_cb on_header_value;
- http_cb on_headers_complete;
- http_data_cb on_body;
- http_cb on_message_complete;
- /* When on_chunk_header is called, the current chunk length is stored
- * in parser->content_length.
- */
- http_cb on_chunk_header;
- http_cb on_chunk_complete;
-};
-
-
-enum http_parser_url_fields
- { UF_SCHEMA = 0
- , UF_HOST = 1
- , UF_PORT = 2
- , UF_PATH = 3
- , UF_QUERY = 4
- , UF_FRAGMENT = 5
- , UF_USERINFO = 6
- , UF_MAX = 7
- };
-
-
-/* Result structure for http_parser_parse_url().
- *
- * Callers should index into field_data[] with UF_* values iff field_set
- * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
- * because we probably have padding left over), we convert any port to
- * a uint16_t.
- */
-struct http_parser_url {
- uint16_t field_set; /* Bitmask of (1 << UF_*) values */
- uint16_t port; /* Converted UF_PORT string */
-
- struct {
- uint16_t off; /* Offset into buffer in which field starts */
- uint16_t len; /* Length of run in buffer */
- } field_data[UF_MAX];
-};
-
-
-/* Returns the library version. Bits 16-23 contain the major version number,
- * bits 8-15 the minor version number and bits 0-7 the patch level.
- * Usage example:
- *
- * unsigned long version = http_parser_version();
- * unsigned major = (version >> 16) & 255;
- * unsigned minor = (version >> 8) & 255;
- * unsigned patch = version & 255;
- * printf("http_parser v%u.%u.%u\n", major, minor, patch);
- */
-unsigned long http_parser_version(void);
-
-void http_parser_init(http_parser *parser, enum http_parser_type type);
-
-
-/* Initialize http_parser_settings members to 0
- */
-void http_parser_settings_init(http_parser_settings *settings);
-
-
-/* Executes the parser. Returns number of parsed bytes. Sets
- * `parser->http_errno` on error. */
-size_t http_parser_execute(http_parser *parser,
- const http_parser_settings *settings,
- const char *data,
- size_t len);
-
-
-/* If http_should_keep_alive() in the on_headers_complete or
- * on_message_complete callback returns 0, then this should be
- * the last message on the connection.
- * If you are the server, respond with the "Connection: close" header.
- * If you are the client, close the connection.
- */
-int http_should_keep_alive(const http_parser *parser);
-
-/* Returns a string version of the HTTP method. */
-const char *http_method_str(enum http_method m);
-
-/* Returns a string version of the HTTP status code. */
-const char *http_status_str(enum http_status s);
-
-/* Return a string name of the given error */
-const char *http_errno_name(enum http_errno err);
-
-/* Return a string description of the given error */
-const char *http_errno_description(enum http_errno err);
-
-/* Initialize all http_parser_url members to 0 */
-void http_parser_url_init(struct http_parser_url *u);
-
-/* Parse a URL; return nonzero on failure */
-int http_parser_parse_url(const char *buf, size_t buflen,
- int is_connect,
- struct http_parser_url *u);
-
-/* Pause or un-pause the parser; a nonzero value pauses */
-void http_parser_pause(http_parser *parser, int paused);
-
-/* Checks if this is the final chunk of the body. */
-int http_body_is_final(const http_parser *parser);
-
-} // namespace wpi
-
-#endif
diff --git a/wpiutil/src/main/native/include/wpi/interpolating_map.h b/wpiutil/src/main/native/include/wpi/interpolating_map.h
new file mode 100644
index 0000000..5eff514
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/interpolating_map.h
@@ -0,0 +1,87 @@
+// 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 <map>
+#include <utility>
+
+namespace wpi {
+
+/**
+ * Implements a table of key-value pairs with linear interpolation between
+ * values.
+ *
+ * If there's no matching key, the value returned will be a linear interpolation
+ * between the keys before and after the provided one.
+ *
+ * @tparam Key The key type.
+ * @tparam Value The value type.
+ */
+template <typename Key, typename Value>
+class interpolating_map {
+ public:
+ /**
+ * Inserts a key-value pair.
+ *
+ * @param key The key.
+ * @param value The value.
+ */
+ void insert(const Key& key, const Value& value) {
+ m_container.insert(std::make_pair(key, value));
+ }
+
+ /**
+ * Inserts a key-value pair.
+ *
+ * @param key The key.
+ * @param value The value.
+ */
+ void insert(Key&& key, Value&& value) {
+ m_container.insert(std::make_pair(key, value));
+ }
+
+ /**
+ * Returns the value associated with a given key.
+ *
+ * If there's no matching key, the value returned will be a linear
+ * interpolation between the keys before and after the provided one.
+ *
+ * @param key The key.
+ */
+ Value operator[](const Key& key) const {
+ using const_iterator = typename std::map<Key, Value>::const_iterator;
+
+ // Get iterator to upper bound key-value pair for the given key
+ const_iterator upper = m_container.upper_bound(key);
+
+ // If key > largest key in table, return value for largest table key
+ if (upper == m_container.end()) {
+ return (--upper)->second;
+ }
+
+ // If key <= smallest key in table, return value for smallest table key
+ if (upper == m_container.begin()) {
+ return upper->second;
+ }
+
+ // Get iterator to lower bound key-value pair
+ const_iterator lower = upper;
+ --lower;
+
+ // Perform linear interpolation between lower and upper bound
+ const double delta = (key - lower->first) / (upper->first - lower->first);
+ return delta * upper->second + (1.0 - delta) * lower->second;
+ }
+
+ /**
+ * Clears the contents.
+ */
+ void clear() { m_container.clear(); }
+
+ private:
+ std::map<Key, Value> m_container;
+};
+
+} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/jni_util.h b/wpiutil/src/main/native/include/wpi/jni_util.h
index 585c1c6..8d50fdd 100644
--- a/wpiutil/src/main/native/include/wpi/jni_util.h
+++ b/wpiutil/src/main/native/include/wpi/jni_util.h
@@ -8,6 +8,7 @@
#include <jni.h>
#include <queue>
+#include <span>
#include <string>
#include <string_view>
#include <type_traits>
@@ -21,7 +22,6 @@
#include "wpi/StringExtras.h"
#include "wpi/mutex.h"
#include "wpi/raw_ostream.h"
-#include "wpi/span.h"
/** Java Native Interface (JNI) utility functions */
namespace wpi::java {
@@ -154,7 +154,7 @@
jsize size = env->GetStringLength(str);
const jchar* chars = env->GetStringCritical(str, nullptr);
if (chars) {
- convertUTF16ToUTF8String(wpi::span<const jchar>(chars, size), m_str);
+ convertUTF16ToUTF8String(std::span<const jchar>(chars, size), m_str);
env->ReleaseStringCritical(str, chars);
}
} else {
@@ -179,10 +179,16 @@
namespace detail {
template <typename C, typename T>
-class JArrayRefInner {};
+class JArrayRefInner {
+ public:
+ operator std::span<const T>() const { // NOLINT
+ return static_cast<const C*>(this)->array();
+ }
+};
/**
- * Specialization of JArrayRefBase to provide std::string_view conversion.
+ * Specialization of JArrayRefBase to provide std::string_view conversion
+ * and span<const uint8_t> conversion.
*/
template <typename C>
class JArrayRefInner<C, jbyte> {
@@ -196,6 +202,33 @@
}
return {reinterpret_cast<const char*>(arr.data()), arr.size()};
}
+
+ std::span<const uint8_t> uarray() const {
+ auto arr = static_cast<const C*>(this)->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();
+ if (arr.empty()) {
+ return {};
+ }
+ return {reinterpret_cast<const U*>(arr.data()), arr.size()};
+ }
};
/**
@@ -206,9 +239,7 @@
public:
explicit operator bool() const { return this->m_elements != nullptr; }
- operator span<const T>() const { return array(); } // NOLINT
-
- span<const T> array() const {
+ std::span<const T> array() const {
if (!this->m_elements) {
return {};
}
@@ -375,7 +406,7 @@
template <typename T,
bool = (std::is_integral<T>::value && sizeof(jint) == sizeof(T))>
struct ConvertIntArray {
- static jintArray ToJava(JNIEnv* env, span<const T> arr) {
+ static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
jintArray jarr = env->NewIntArray(arr.size());
if (!jarr) {
return nullptr;
@@ -398,7 +429,7 @@
*/
template <typename T>
struct ConvertIntArray<T, true> {
- static jintArray ToJava(JNIEnv* env, span<const T> arr) {
+ static jintArray ToJava(JNIEnv* env, std::span<const T> arr) {
jintArray jarr = env->NewIntArray(arr.size());
if (!jarr) {
return nullptr;
@@ -418,7 +449,7 @@
* @param arr Span to convert.
*/
template <typename T>
-inline jintArray MakeJIntArray(JNIEnv* env, span<const T> arr) {
+inline jintArray MakeJIntArray(JNIEnv* env, std::span<const T> arr) {
return detail::ConvertIntArray<T>::ToJava(env, arr);
}
@@ -429,7 +460,7 @@
* @param arr Span to convert.
*/
template <typename T>
-inline jintArray MakeJIntArray(JNIEnv* env, span<T> arr) {
+inline jintArray MakeJIntArray(JNIEnv* env, std::span<T> arr) {
return detail::ConvertIntArray<T>::ToJava(env, arr);
}
@@ -462,12 +493,12 @@
}
/**
- * Convert a std::string_view into a jbyteArray.
+ * Convert a span into a jbyteArray.
*
* @param env JRE environment.
- * @param str std::string_view to convert.
+ * @param str span to convert.
*/
-inline jbyteArray MakeJByteArray(JNIEnv* env, std::string_view str) {
+inline jbyteArray MakeJByteArray(JNIEnv* env, std::span<const uint8_t> str) {
jbyteArray jarr = env->NewByteArray(str.size());
if (!jarr) {
return nullptr;
@@ -483,7 +514,7 @@
* @param env JRE environment.
* @param arr Array to convert.
*/
-inline jbooleanArray MakeJBooleanArray(JNIEnv* env, span<const int> arr) {
+inline jbooleanArray MakeJBooleanArray(JNIEnv* env, std::span<const int> arr) {
jbooleanArray jarr = env->NewBooleanArray(arr.size());
if (!jarr) {
return nullptr;
@@ -506,7 +537,7 @@
* @param env JRE environment.
* @param arr Array to convert.
*/
-inline jbooleanArray MakeJBooleanArray(JNIEnv* env, span<const bool> arr) {
+inline jbooleanArray MakeJBooleanArray(JNIEnv* env, std::span<const bool> arr) {
jbooleanArray jarr = env->NewBooleanArray(arr.size());
if (!jarr) {
return nullptr;
@@ -525,32 +556,45 @@
// Other MakeJ*Array conversions.
-#define WPI_JNI_MAKEJARRAY(T, F) \
- inline T##Array MakeJ##F##Array(JNIEnv* env, span<const T> arr) { \
- T##Array jarr = env->New##F##Array(arr.size()); \
- if (!jarr) { \
- return nullptr; \
- } \
- env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
- return jarr; \
+#define WPI_JNI_MAKEJARRAY(T, F) \
+ inline T##Array MakeJ##F##Array(JNIEnv* env, std::span<const T> arr) { \
+ T##Array jarr = env->New##F##Array(arr.size()); \
+ if (!jarr) { \
+ return nullptr; \
+ } \
+ env->Set##F##ArrayRegion(jarr, 0, arr.size(), arr.data()); \
+ return jarr; \
}
WPI_JNI_MAKEJARRAY(jboolean, Boolean)
WPI_JNI_MAKEJARRAY(jbyte, Byte)
WPI_JNI_MAKEJARRAY(jshort, Short)
-WPI_JNI_MAKEJARRAY(jlong, Long)
WPI_JNI_MAKEJARRAY(jfloat, Float)
WPI_JNI_MAKEJARRAY(jdouble, Double)
#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>>>
+inline jlongArray MakeJLongArray(JNIEnv* env, const T& arr) {
+ jlongArray jarr = env->NewLongArray(arr.size());
+ if (!jarr) {
+ return nullptr;
+ }
+ env->SetLongArrayRegion(jarr, 0, arr.size(),
+ reinterpret_cast<const jlong*>(arr.data()));
+ return jarr;
+}
+
/**
* Convert an array of std::string into a jarray of jstring.
*
* @param env JRE environment.
* @param arr Array to convert.
*/
-inline jobjectArray MakeJStringArray(JNIEnv* env, span<const std::string> arr) {
+inline jobjectArray MakeJStringArray(JNIEnv* env,
+ std::span<const std::string> arr) {
static JClass stringCls{env, "java/lang/String"};
if (!stringCls) {
return nullptr;
@@ -572,7 +616,8 @@
* @param env JRE environment.
* @param arr Array to convert.
*/
-inline jobjectArray MakeJStringArray(JNIEnv* env, span<std::string_view> arr) {
+inline jobjectArray MakeJStringArray(JNIEnv* env,
+ std::span<std::string_view> arr) {
static JClass stringCls{env, "java/lang/String"};
if (!stringCls) {
return nullptr;
diff --git a/wpiutil/src/main/native/include/wpi/leb128.h b/wpiutil/src/main/native/include/wpi/leb128.h
index 04752c6..e89d505 100644
--- a/wpiutil/src/main/native/include/wpi/leb128.h
+++ b/wpiutil/src/main/native/include/wpi/leb128.h
@@ -8,8 +8,7 @@
#include <stdint.h>
#include <optional>
-
-#include "wpi/span.h"
+#include <span>
namespace wpi {
@@ -100,7 +99,7 @@
* is left when function returns).
* @return value (in std::optional)
*/
- std::optional<uint64_t> ReadOne(span<const uint8_t>* in);
+ std::optional<uint64_t> ReadOne(std::span<const uint8_t>* in);
private:
uint64_t m_result = 0;
diff --git a/wpiutil/src/main/native/include/wpi/math b/wpiutil/src/main/native/include/wpi/math
deleted file mode 100644
index 25f2a64..0000000
--- a/wpiutil/src/main/native/include/wpi/math
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 "wpi/numbers"
-
-// clang-format off
-#ifdef _MSC_VER
-#pragma message("warning: Use <wpi/numbers> and wpi::numbers instead to reflect C++20 <numbers> and std::numbers")
-#else
-#warning "Use <wpi/numbers> and wpi::numbers instead to reflect C++20 <numbers> and std::numbers"
-#endif
-
-// clang-format on
-
-namespace wpi::math {
-using namespace wpi::numbers;
-} // namespace wpi::math
diff --git a/wpiutil/src/main/native/include/wpi/numbers b/wpiutil/src/main/native/include/wpi/numbers
deleted file mode 100644
index d45aee0..0000000
--- a/wpiutil/src/main/native/include/wpi/numbers
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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 <type_traits>
-
-namespace wpi::numbers {
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T e_v = 2.718281828459045235360287471352662498L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T log2e_v = 1.442695040888963407359924681001892137L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T log10e_v = 0.434294481903251827651128918916605082L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T pi_v = 3.141592653589793238462643383279502884L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T inv_pi_v = 0.318309886183790671537767526745028724L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T inv_sqrtpi_v = 0.564189583547756286948079451560772586L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T ln2_v = 0.693147180559945309417232121458176568L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T ln10_v = 2.302585092994045684017991454684364208L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T sqrt2_v = 1.414213562373095048801688724209698078L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T sqrt3_v = 1.732050807568877293527446341505872366L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T inv_sqrt3_v = 0.577350269189625764509148780501957456L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T egamma_v = 0.577215664901532860606512090082402431L;
-
-template <typename T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
-inline constexpr T phi_v = 1.618033988749894848204586834365638117L;
-
-inline constexpr double e = e_v<double>;
-inline constexpr double log2e = log2e_v<double>;
-inline constexpr double log10e = log10e_v<double>;
-inline constexpr double pi = pi_v<double>;
-inline constexpr double inv_pi = inv_pi_v<double>;
-inline constexpr double inv_sqrtpi = inv_sqrtpi_v<double>;
-inline constexpr double ln2 = ln2_v<double>;
-inline constexpr double ln10 = ln10_v<double>;
-inline constexpr double sqrt2 = sqrt2_v<double>;
-inline constexpr double sqrt3 = sqrt3_v<double>;
-inline constexpr double inv_sqrt3 = inv_sqrt3_v<double>;
-inline constexpr double egamma = egamma_v<double>;
-inline constexpr double phi = phi_v<double>;
-
-} // namespace wpi::numbers
diff --git a/wpiutil/src/main/native/include/wpi/raw_istream.h b/wpiutil/src/main/native/include/wpi/raw_istream.h
index 2371fc6..2f278c8 100644
--- a/wpiutil/src/main/native/include/wpi/raw_istream.h
+++ b/wpiutil/src/main/native/include/wpi/raw_istream.h
@@ -9,13 +9,13 @@
#include <algorithm>
#include <cstddef>
+#include <span>
#include <string>
#include <string_view>
#include <system_error>
#include <vector>
#include "wpi/SmallVector.h"
-#include "wpi/span.h"
namespace wpi {
@@ -133,9 +133,9 @@
// not const as we don't want to allow temporaries
explicit raw_mem_istream(std::string& str)
: raw_mem_istream(str.data(), str.size()) {}
- explicit raw_mem_istream(span<const char> mem)
+ explicit raw_mem_istream(std::span<const char> mem)
: raw_mem_istream(mem.data(), mem.size()) {}
- explicit raw_mem_istream(span<const uint8_t> mem)
+ explicit raw_mem_istream(std::span<const uint8_t> mem)
: raw_mem_istream(reinterpret_cast<const char*>(mem.data()), mem.size()) {
}
explicit raw_mem_istream(const char* str)
diff --git a/wpiutil/src/main/native/include/wpi/raw_socket_istream.h b/wpiutil/src/main/native/include/wpi/raw_socket_istream.h
deleted file mode 100644
index f6899e2..0000000
--- a/wpiutil/src/main/native/include/wpi/raw_socket_istream.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_RAW_SOCKET_ISTREAM_H_
-#define WPIUTIL_WPI_RAW_SOCKET_ISTREAM_H_
-
-#include "wpi/raw_istream.h"
-
-namespace wpi {
-
-class NetworkStream;
-
-class raw_socket_istream : public raw_istream {
- public:
- explicit raw_socket_istream(NetworkStream& stream, int timeout = 0)
- : m_stream(stream), m_timeout(timeout) {}
-
- void close() override;
- size_t in_avail() const override;
-
- private:
- void read_impl(void* data, size_t len) override;
-
- NetworkStream& m_stream;
- int m_timeout;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_RAW_SOCKET_ISTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/raw_socket_ostream.h b/wpiutil/src/main/native/include/wpi/raw_socket_ostream.h
deleted file mode 100644
index 5cdeb41..0000000
--- a/wpiutil/src/main/native/include/wpi/raw_socket_ostream.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_RAW_SOCKET_OSTREAM_H_
-#define WPIUTIL_WPI_RAW_SOCKET_OSTREAM_H_
-
-#include "wpi/raw_ostream.h"
-
-namespace wpi {
-
-class NetworkStream;
-
-class raw_socket_ostream : public raw_ostream {
- public:
- raw_socket_ostream(NetworkStream& stream, bool shouldClose)
- : m_stream(stream), m_shouldClose(shouldClose) {}
- ~raw_socket_ostream() override;
-
- void close();
-
- bool has_error() const { return m_error; }
- void clear_error() { m_error = false; }
-
- protected:
- void error_detected() { m_error = true; }
-
- private:
- void write_impl(const char* data, size_t len) override;
- uint64_t current_pos() const override;
-
- NetworkStream& m_stream;
- bool m_error = false;
- bool m_shouldClose;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_RAW_SOCKET_OSTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/raw_uv_ostream.h b/wpiutil/src/main/native/include/wpi/raw_uv_ostream.h
deleted file mode 100644
index 4773c61..0000000
--- a/wpiutil/src/main/native/include/wpi/raw_uv_ostream.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_RAW_UV_OSTREAM_H_
-#define WPIUTIL_WPI_RAW_UV_OSTREAM_H_
-
-#include <functional>
-#include <utility>
-
-#include "wpi/SmallVector.h"
-#include "wpi/raw_ostream.h"
-#include "wpi/span.h"
-#include "wpi/uv/Buffer.h"
-
-namespace wpi {
-
-/**
- * raw_ostream style output to a SmallVector of uv::Buffer buffers. Fixed-size
- * buffers are allocated and appended as necessary to fit the data being output.
- * The SmallVector need not be empty at start.
- */
-class raw_uv_ostream : public raw_ostream {
- public:
- /**
- * Construct a new raw_uv_ostream.
- * @param bufs Buffers vector. NOT cleared on construction.
- * @param allocSize Size to allocate for each buffer; allocation will be
- * performed using Buffer::Allocate().
- */
- raw_uv_ostream(SmallVectorImpl<uv::Buffer>& bufs, size_t allocSize)
- : m_bufs(bufs), m_alloc([=] { return uv::Buffer::Allocate(allocSize); }) {
- SetUnbuffered();
- }
-
- /**
- * Construct a new raw_uv_ostream.
- * @param bufs Buffers vector. NOT cleared on construction.
- * @param alloc Allocator.
- */
- raw_uv_ostream(SmallVectorImpl<uv::Buffer>& bufs,
- std::function<uv::Buffer()> alloc)
- : m_bufs(bufs), m_alloc(std::move(alloc)) {
- SetUnbuffered();
- }
-
- ~raw_uv_ostream() override = default;
-
- /**
- * Returns an span to the buffers.
- */
- span<uv::Buffer> bufs() { return m_bufs; }
-
- void flush() = delete;
-
- /**
- * Resets the amount of allocated space.
- */
- void reset() { m_left = 0; }
-
- private:
- void write_impl(const char* data, size_t len) override;
- uint64_t current_pos() const override;
-
- SmallVectorImpl<uv::Buffer>& m_bufs;
- std::function<uv::Buffer()> m_alloc;
-
- // How much allocated space is left in the current buffer.
- size_t m_left = 0;
-};
-
-} // namespace wpi
-
-#endif // WPIUTIL_WPI_RAW_UV_OSTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/scope b/wpiutil/src/main/native/include/wpi/scope
new file mode 100644
index 0000000..e25badb
--- /dev/null
+++ b/wpiutil/src/main/native/include/wpi/scope
@@ -0,0 +1,37 @@
+// 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 <utility>
+
+namespace wpi {
+
+template <typename F>
+class scope_exit {
+ public:
+ explicit scope_exit(F&& f) noexcept : m_f{std::forward<F>(f)} {}
+
+ ~scope_exit() {
+ if (m_active) {
+ m_f();
+ }
+ }
+
+ scope_exit(scope_exit&& rhs) noexcept
+ : m_f{std::move(rhs.m_f)}, m_active{rhs.m_active} {
+ rhs.release();
+ }
+
+ scope_exit(const scope_exit&) = delete;
+ scope_exit& operator=(const scope_exit&) = delete;
+
+ void release() noexcept { m_active = false; }
+
+ private:
+ F m_f;
+ bool m_active = true;
+};
+
+} // 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 e092a1e..2287b73 100644
--- a/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
+++ b/wpiutil/src/main/native/include/wpi/sendable/SendableBuilder.h
@@ -6,12 +6,12 @@
#include <functional>
#include <memory>
+#include <span>
#include <string>
#include <string_view>
#include <vector>
#include "wpi/SmallVector.h"
-#include "wpi/span.h"
namespace wpi {
@@ -60,6 +60,28 @@
std::function<void(bool)> setter) = 0;
/**
+ * Add an integer property.
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddIntegerProperty(std::string_view key,
+ std::function<int64_t()> getter,
+ std::function<void(int64_t)> setter) = 0;
+
+ /**
+ * Add a float property.
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddFloatProperty(std::string_view key,
+ std::function<float()> getter,
+ std::function<void(float)> setter) = 0;
+
+ /**
* Add a double property.
*
* @param key property name
@@ -90,7 +112,29 @@
*/
virtual void AddBooleanArrayProperty(
std::string_view key, std::function<std::vector<int>()> getter,
- std::function<void(wpi::span<const int>)> setter) = 0;
+ std::function<void(std::span<const int>)> setter) = 0;
+
+ /**
+ * Add an integer array property.
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddIntegerArrayProperty(
+ std::string_view key, std::function<std::vector<int64_t>()> getter,
+ std::function<void(std::span<const int64_t>)> setter) = 0;
+
+ /**
+ * Add a float array property.
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddFloatArrayProperty(
+ std::string_view key, std::function<std::vector<float>()> getter,
+ std::function<void(std::span<const float>)> setter) = 0;
/**
* Add a double array property.
@@ -101,7 +145,7 @@
*/
virtual void AddDoubleArrayProperty(
std::string_view key, std::function<std::vector<double>()> getter,
- std::function<void(wpi::span<const double>)> setter) = 0;
+ std::function<void(std::span<const double>)> setter) = 0;
/**
* Add a string array property.
@@ -112,18 +156,20 @@
*/
virtual void AddStringArrayProperty(
std::string_view key, std::function<std::vector<std::string>()> getter,
- std::function<void(wpi::span<const std::string>)> setter) = 0;
+ std::function<void(std::span<const std::string>)> setter) = 0;
/**
* Add a raw property.
*
- * @param key property name
- * @param getter getter function (returns current value)
- * @param setter setter function (sets new value)
+ * @param key property name
+ * @param typeString type string
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
*/
- virtual void AddRawProperty(std::string_view key,
- std::function<std::string()> getter,
- std::function<void(std::string_view)> setter) = 0;
+ virtual void AddRawProperty(
+ std::string_view key, std::string_view typeString,
+ std::function<std::vector<uint8_t>()> getter,
+ std::function<void(std::span<const uint8_t>)> setter) = 0;
/**
* Add a string property (SmallString form).
@@ -146,9 +192,36 @@
*/
virtual void AddSmallBooleanArrayProperty(
std::string_view key,
- std::function<wpi::span<const int>(wpi::SmallVectorImpl<int>& buf)>
+ std::function<std::span<const int>(wpi::SmallVectorImpl<int>& buf)>
getter,
- std::function<void(wpi::span<const int>)> setter) = 0;
+ std::function<void(std::span<const int>)> setter) = 0;
+
+ /**
+ * Add an integer array property (SmallVector form).
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddSmallIntegerArrayProperty(
+ std::string_view key,
+ std::function<
+ std::span<const int64_t>(wpi::SmallVectorImpl<int64_t>& buf)>
+ getter,
+ std::function<void(std::span<const int64_t>)> setter) = 0;
+
+ /**
+ * Add a float array property (SmallVector form).
+ *
+ * @param key property name
+ * @param getter getter function (returns current value)
+ * @param setter setter function (sets new value)
+ */
+ virtual void AddSmallFloatArrayProperty(
+ std::string_view key,
+ std::function<std::span<const float>(wpi::SmallVectorImpl<float>& buf)>
+ getter,
+ std::function<void(std::span<const float>)> setter) = 0;
/**
* Add a double array property (SmallVector form).
@@ -159,9 +232,9 @@
*/
virtual void AddSmallDoubleArrayProperty(
std::string_view key,
- std::function<wpi::span<const double>(wpi::SmallVectorImpl<double>& buf)>
+ std::function<std::span<const double>(wpi::SmallVectorImpl<double>& buf)>
getter,
- std::function<void(wpi::span<const double>)> setter) = 0;
+ std::function<void(std::span<const double>)> setter) = 0;
/**
* Add a string array property (SmallVector form).
@@ -173,21 +246,23 @@
virtual void AddSmallStringArrayProperty(
std::string_view key,
std::function<
- wpi::span<const std::string>(wpi::SmallVectorImpl<std::string>& buf)>
+ std::span<const std::string>(wpi::SmallVectorImpl<std::string>& buf)>
getter,
- std::function<void(wpi::span<const std::string>)> setter) = 0;
+ std::function<void(std::span<const std::string>)> setter) = 0;
/**
* Add a raw property (SmallVector form).
*
* @param key property name
+ * @param typeString type string
* @param getter getter function (returns current value)
* @param setter setter function (sets new value)
*/
virtual void AddSmallRawProperty(
- std::string_view key,
- std::function<std::string_view(wpi::SmallVectorImpl<char>& buf)> getter,
- std::function<void(std::string_view)> setter) = 0;
+ std::string_view key, std::string_view typeString,
+ std::function<std::span<uint8_t>(wpi::SmallVectorImpl<uint8_t>& buf)>
+ getter,
+ std::function<void(std::span<const uint8_t>)> setter) = 0;
/**
* Gets the kind of backend being used.
diff --git a/wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h b/wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h
index 5b6bbe3..f8dd703 100644
--- a/wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h
+++ b/wpiutil/src/main/native/include/wpi/sendable/SendableHelper.h
@@ -4,11 +4,6 @@
#pragma once
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/deprecated.h"
#include "wpi/sendable/SendableRegistry.h"
namespace wpi {
@@ -48,123 +43,6 @@
return *this;
}
- /**
- * Gets the name of this Sendable object.
- *
- * @deprecated use SendableRegistry::GetName()
- *
- * @return Name
- */
- WPI_DEPRECATED("use SendableRegistry::GetName()")
- std::string GetName() const {
- return SendableRegistry::GetName(static_cast<const Derived*>(this));
- }
-
- /**
- * Sets the name of this Sendable object.
- *
- * @deprecated use SendableRegistry::SetName()
- *
- * @param name name
- */
- WPI_DEPRECATED("use SendableRegistry::SetName()")
- void SetName(std::string_view name) {
- SendableRegistry::SetName(static_cast<Derived*>(this), name);
- }
-
- /**
- * Sets both the subsystem name and device name of this Sendable object.
- *
- * @deprecated use SendableRegistry::SetName()
- *
- * @param subsystem subsystem name
- * @param name device name
- */
- WPI_DEPRECATED("use SendableRegistry::SetName()")
- void SetName(std::string_view subsystem, std::string_view name) {
- SendableRegistry::SetName(static_cast<Derived*>(this), subsystem, name);
- }
-
- /**
- * Gets the subsystem name of this Sendable object.
- *
- * @deprecated use SendableRegistry::GetSubsystem().
- *
- * @return Subsystem name
- */
- WPI_DEPRECATED("use SendableRegistry::GetSubsystem()")
- std::string GetSubsystem() const {
- return SendableRegistry::GetSubsystem(static_cast<const Derived*>(this));
- }
-
- /**
- * Sets the subsystem name of this Sendable object.
- *
- * @deprecated use SendableRegistry::SetSubsystem()
- *
- * @param subsystem subsystem name
- */
- WPI_DEPRECATED("use SendableRegistry::SetSubsystem()")
- void SetSubsystem(std::string_view subsystem) {
- SendableRegistry::SetSubsystem(static_cast<Derived*>(this), subsystem);
- }
-
- protected:
- /**
- * Add a child component.
- *
- * @deprecated use SendableRegistry::AddChild()
- *
- * @param child child component
- */
- WPI_DEPRECATED("use SendableRegistry::AddChild()")
- void AddChild(std::shared_ptr<Sendable> child) {
- SendableRegistry::AddChild(static_cast<Derived*>(this), child.get());
- }
-
- /**
- * Add a child component.
- *
- * @deprecated use SendableRegistry::AddChild()
- *
- * @param child child component
- */
- WPI_DEPRECATED("use SendableRegistry::AddChild()")
- void AddChild(void* child) {
- SendableRegistry::AddChild(static_cast<Derived*>(this), child);
- }
-
- /**
- * Sets the name of the sensor with a channel number.
- *
- * @deprecated use SendableRegistry::SetName()
- *
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param channel The channel number the device is plugged into
- */
- WPI_DEPRECATED("use SendableRegistry::SetName()")
- void SetName(std::string_view moduleType, int channel) {
- SendableRegistry::SetName(static_cast<Derived*>(this), moduleType, channel);
- }
-
- /**
- * Sets the name of the sensor with a module and channel number.
- *
- * @deprecated use SendableRegistry::SetName()
- *
- * @param moduleType A string that defines the module name in the label for
- * the value
- * @param moduleNumber The number of the particular module type
- * @param channel The channel number the device is plugged into (usually
- * PWM)
- */
- WPI_DEPRECATED("use SendableRegistry::SetName()")
- void SetName(std::string_view moduleType, int moduleNumber, int channel) {
- SendableRegistry::SetName(static_cast<Derived*>(this), moduleType,
- moduleNumber, channel);
- }
-
protected:
SendableHelper() = default;
diff --git a/wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h b/wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h
index a08f9e9..4639749 100644
--- a/wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h
+++ b/wpiutil/src/main/native/include/wpi/sendable/SendableRegistry.h
@@ -20,7 +20,7 @@
* The SendableRegistry class is the public interface for registering sensors
* and actuators for use on dashboards and LiveWindow.
*/
-class SendableRegistry {
+class SendableRegistry final {
public:
SendableRegistry() = delete;
diff --git a/wpiutil/src/main/native/include/wpi/span.h b/wpiutil/src/main/native/include/wpi/span.h
deleted file mode 100644
index cf71d79..0000000
--- a/wpiutil/src/main/native/include/wpi/span.h
+++ /dev/null
@@ -1,415 +0,0 @@
-
-/*
-This is an implementation of C++20's std::span
-http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/n4820.pdf
-*/
-
-// Copyright Tristan Brindle 2018.
-// Distributed under the Boost Software License, Version 1.0.
-// (See accompanying file ../../LICENSE_1_0.txt or copy at
-// https://www.boost.org/LICENSE_1_0.txt)
-
-#ifndef WPIUTIL_WPI_SPAN_HPP_INCLUDED
-#define WPIUTIL_WPI_SPAN_HPP_INCLUDED
-
-#include <array>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <type_traits>
-#if __cplusplus >= 202002L && __has_include(<span>)
-#include <span>
-#endif
-
-namespace wpi {
-
-inline constexpr std::size_t dynamic_extent = SIZE_MAX;
-
-template <typename ElementType, std::size_t Extent = dynamic_extent>
-class span;
-
-namespace detail {
-
-template <typename E, std::size_t S>
-struct span_storage {
- constexpr span_storage() noexcept = default;
-
- constexpr span_storage(E* p_ptr, std::size_t /*unused*/) noexcept
- : ptr(p_ptr)
- {}
-
- E* ptr = nullptr;
- static constexpr std::size_t size = S;
-};
-
-template <typename E>
-struct span_storage<E, dynamic_extent> {
- constexpr span_storage() noexcept = default;
-
- constexpr span_storage(E* p_ptr, std::size_t p_size) noexcept
- : ptr(p_ptr), size(p_size)
- {}
-
- E* ptr = nullptr;
- std::size_t size = 0;
-};
-
-template <typename T>
-using uncvref_t =
- typename std::remove_cv<typename std::remove_reference<T>::type>::type;
-
-template <typename>
-struct is_span : std::false_type {};
-
-template <typename T, std::size_t S>
-struct is_span<span<T, S>> : std::true_type {};
-
-template <typename>
-struct is_std_array : std::false_type {};
-
-template <typename T, std::size_t N>
-struct is_std_array<std::array<T, N>> : std::true_type {};
-
-template <typename, typename = void>
-struct has_size_and_data : std::false_type {};
-
-template <typename T>
-struct has_size_and_data<T, std::void_t<decltype(std::size(std::declval<T>())),
- decltype(std::data(std::declval<T>()))>>
- : std::true_type {};
-
-template <typename C, typename U = uncvref_t<C>>
-struct is_container {
- static constexpr bool value =
- !is_span<U>::value && !is_std_array<U>::value &&
- !std::is_array<U>::value && has_size_and_data<C>::value;
-};
-
-template <typename T>
-using remove_pointer_t = typename std::remove_pointer<T>::type;
-
-template <typename, typename, typename = void>
-struct is_container_element_type_compatible : std::false_type {};
-
-template <typename T, typename E>
-struct is_container_element_type_compatible<
- T, E,
- typename std::enable_if<
- !std::is_same<typename std::remove_cv<decltype(
- std::data(std::declval<T>()))>::type,
- void>::value>::type>
- : std::is_convertible<
- remove_pointer_t<decltype(std::data(std::declval<T>()))> (*)[],
- E (*)[]> {};
-
-template <typename, typename = size_t>
-struct is_complete : std::false_type {};
-
-template <typename T>
-struct is_complete<T, decltype(sizeof(T))> : std::true_type {};
-
-} // namespace detail
-
-template <typename ElementType, std::size_t Extent>
-class span {
- static_assert(std::is_object<ElementType>::value,
- "A span's ElementType must be an object type (not a "
- "reference type or void)");
- static_assert(detail::is_complete<ElementType>::value,
- "A span's ElementType must be a complete type (not a forward "
- "declaration)");
- static_assert(!std::is_abstract<ElementType>::value,
- "A span's ElementType cannot be an abstract class type");
-
- using storage_type = detail::span_storage<ElementType, Extent>;
-
-public:
- // constants and types
- using element_type = ElementType;
- using value_type = typename std::remove_cv<ElementType>::type;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- using pointer = element_type*;
- using const_pointer = const element_type*;
- using reference = element_type&;
- using const_reference = const element_type&;
- using iterator = pointer;
- using reverse_iterator = std::reverse_iterator<iterator>;
-
- static constexpr size_type extent = Extent;
-
- // [span.cons], span constructors, copy, assignment, and destructor
- template <
- std::size_t E = Extent,
- typename std::enable_if<(E == dynamic_extent || E <= 0), int>::type = 0>
- constexpr span() noexcept
- {}
-
- constexpr span(pointer ptr, size_type count)
- : storage_(ptr, count)
- {
- assert(extent == dynamic_extent || count == extent);
- }
-
- constexpr span(pointer first_elem, pointer last_elem)
- : storage_(first_elem, last_elem - first_elem)
- {
- assert(extent == dynamic_extent ||
- last_elem - first_elem ==
- static_cast<std::ptrdiff_t>(extent));
- }
-
- template <std::size_t N, std::size_t E = Extent,
- typename std::enable_if<
- (E == dynamic_extent || N == E) &&
- detail::is_container_element_type_compatible<
- element_type (&)[N], ElementType>::value,
- int>::type = 0>
- constexpr span(element_type (&arr)[N]) noexcept : storage_(arr, N)
- {}
-
- template <std::size_t N, std::size_t E = Extent,
- typename std::enable_if<
- (E == dynamic_extent || N == E) &&
- detail::is_container_element_type_compatible<
- std::array<value_type, N>&, ElementType>::value,
- int>::type = 0>
- constexpr span(std::array<value_type, N>& arr) noexcept
- : storage_(arr.data(), N)
- {}
-
- template <std::size_t N, std::size_t E = Extent,
- typename std::enable_if<
- (E == dynamic_extent || N == E) &&
- detail::is_container_element_type_compatible<
- const std::array<value_type, N>&, ElementType>::value,
- int>::type = 0>
- constexpr span(const std::array<value_type, N>& arr) noexcept
- : storage_(arr.data(), N)
- {}
-
- template <
- typename Container, std::size_t E = Extent,
- typename std::enable_if<
- E == dynamic_extent && detail::is_container<Container>::value &&
- detail::is_container_element_type_compatible<
- Container&, ElementType>::value,
- int>::type = 0>
- constexpr span(Container& cont)
- : storage_(std::data(cont), std::size(cont))
- {}
-
- template <
- typename Container, std::size_t E = Extent,
- typename std::enable_if<
- E == dynamic_extent && detail::is_container<Container>::value &&
- detail::is_container_element_type_compatible<
- const Container&, ElementType>::value,
- int>::type = 0>
- constexpr span(const Container& cont)
- : storage_(std::data(cont), std::size(cont))
- {}
-
- constexpr span(const span& other) noexcept = default;
-
- template <typename OtherElementType, std::size_t OtherExtent,
- typename std::enable_if<
- (Extent == OtherExtent || Extent == dynamic_extent) &&
- std::is_convertible<OtherElementType (*)[],
- ElementType (*)[]>::value,
- int>::type = 0>
- constexpr span(const span<OtherElementType, OtherExtent>& other) noexcept
- : storage_(other.data(), other.size())
- {}
-
-#ifdef __cpp_lib_span
- constexpr span(std::span<ElementType> other) noexcept
- : storage_(other.data(), other.size())
- {}
-#endif
-
- ~span() noexcept = default;
-
- constexpr span&
- operator=(const span& other) noexcept = default;
-
- // [span.sub], span subviews
- template <std::size_t Count>
- constexpr span<element_type, Count> first() const
- {
- assert(Count <= size());
- return {data(), Count};
- }
-
- template <std::size_t Count>
- constexpr span<element_type, Count> last() const
- {
- assert(Count <= size());
- return {data() + (size() - Count), Count};
- }
-
- template <std::size_t Offset, std::size_t Count = dynamic_extent>
- using subspan_return_t =
- span<ElementType, Count != dynamic_extent
- ? Count
- : (Extent != dynamic_extent ? Extent - Offset
- : dynamic_extent)>;
-
- template <std::size_t Offset, std::size_t Count = dynamic_extent>
- constexpr subspan_return_t<Offset, Count> subspan() const
- {
- assert(Offset <= size() &&
- (Count == dynamic_extent || Offset + Count <= size()));
- return {data() + Offset,
- Count != dynamic_extent ? Count : size() - Offset};
- }
-
- constexpr span<element_type, dynamic_extent>
- first(size_type count) const
- {
- assert(count <= size());
- return {data(), count};
- }
-
- constexpr span<element_type, dynamic_extent>
- last(size_type count) const
- {
- assert(count <= size());
- return {data() + (size() - count), count};
- }
-
- constexpr span<element_type, dynamic_extent>
- subspan(size_type offset, size_type count = dynamic_extent) const
- {
- assert(offset <= size() &&
- (count == dynamic_extent || offset + count <= size()));
- return {data() + offset,
- count == dynamic_extent ? size() - offset : count};
- }
-
- // [span.obs], span observers
- constexpr size_type size() const noexcept { return storage_.size; }
-
- constexpr size_type size_bytes() const noexcept
- {
- return size() * sizeof(element_type);
- }
-
- [[nodiscard]] constexpr bool empty() const noexcept
- {
- return size() == 0;
- }
-
- // [span.elem], span element access
- constexpr reference operator[](size_type idx) const
- {
- assert(idx < size());
- return *(data() + idx);
- }
-
- constexpr reference front() const
- {
- assert(!empty());
- return *data();
- }
-
- constexpr reference back() const
- {
- assert(!empty());
- return *(data() + (size() - 1));
- }
-
- constexpr pointer data() const noexcept { return storage_.ptr; }
-
- // [span.iterators], span iterator support
- constexpr iterator begin() const noexcept { return data(); }
-
- constexpr iterator end() const noexcept { return data() + size(); }
-
- constexpr reverse_iterator rbegin() const noexcept
- {
- return reverse_iterator(end());
- }
-
- constexpr reverse_iterator rend() const noexcept
- {
- return reverse_iterator(begin());
- }
-
-#ifdef __cpp_lib_span
- constexpr operator auto() const {
- return std::span < ElementType,
- (Extent == dynamic_extent)
- ? std::dynamic_extent
- : Extent > (storage_.ptr, storage_.size);
- }
-#endif
-
-private:
- storage_type storage_{};
-};
-
-/* Deduction Guides */
-template <class T, size_t N>
-span(T (&)[N])->span<T, N>;
-
-template <class T, size_t N>
-span(std::array<T, N>&)->span<T, N>;
-
-template <class T, size_t N>
-span(const std::array<T, N>&)->span<const T, N>;
-
-template <class Container>
-span(Container&)->span<typename Container::value_type>;
-
-template <class Container>
-span(const Container&)->span<const typename Container::value_type>;
-
-template <typename ElementType, std::size_t Extent>
-span<const std::byte, ((Extent == dynamic_extent) ? dynamic_extent
- : sizeof(ElementType) * Extent)>
-as_bytes(span<ElementType, Extent> s) noexcept
-{
- return {reinterpret_cast<const std::byte*>(s.data()), s.size_bytes()};
-}
-
-template <
- class ElementType, size_t Extent,
- typename std::enable_if<!std::is_const<ElementType>::value, int>::type = 0>
-span<std::byte, ((Extent == dynamic_extent) ? dynamic_extent
- : sizeof(ElementType) * Extent)>
-as_writable_bytes(span<ElementType, Extent> s) noexcept
-{
- return {reinterpret_cast<std::byte*>(s.data()), s.size_bytes()};
-}
-
-template <std::size_t N, typename E, std::size_t S>
-constexpr auto get(span<E, S> s) -> decltype(s[N])
-{
- return s[N];
-}
-
-} // namespace wpi
-
-namespace std {
-
-template <typename ElementType, size_t Extent>
-class tuple_size<wpi::span<ElementType, Extent>>
- : public integral_constant<size_t, Extent> {};
-
-template <typename ElementType>
-class tuple_size<wpi::span<
- ElementType, wpi::dynamic_extent>>; // not defined
-
-template <size_t I, typename ElementType, size_t Extent>
-class tuple_element<I, wpi::span<ElementType, Extent>> {
-public:
- static_assert(Extent != wpi::dynamic_extent &&
- I < Extent,
- "");
- using type = ElementType;
-};
-
-} // end namespace std
-
-#endif // WPIUTIL_WPI_SPAN_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/include/wpi/spinlock.h b/wpiutil/src/main/native/include/wpi/spinlock.h
index 9e777fa..7128a18 100644
--- a/wpiutil/src/main/native/include/wpi/spinlock.h
+++ b/wpiutil/src/main/native/include/wpi/spinlock.h
@@ -9,7 +9,7 @@
#include <mutex>
#include <thread>
-#include "Compiler.h"
+#include "wpi/Compiler.h"
namespace wpi {
diff --git a/wpiutil/src/main/native/include/wpi/static_circular_buffer.h b/wpiutil/src/main/native/include/wpi/static_circular_buffer.h
index 8cbf3fe..76498a1 100644
--- a/wpiutil/src/main/native/include/wpi/static_circular_buffer.h
+++ b/wpiutil/src/main/native/include/wpi/static_circular_buffer.h
@@ -38,10 +38,7 @@
++(*this);
return retval;
}
- bool operator==(const iterator& other) const {
- return m_buffer == other.m_buffer && m_index == other.m_index;
- }
- bool operator!=(const iterator& other) const { return !(*this == other); }
+ bool operator==(const iterator&) const = default;
reference operator*() { return (*m_buffer)[m_index]; }
private:
@@ -69,12 +66,7 @@
++(*this);
return retval;
}
- bool operator==(const const_iterator& other) const {
- return m_buffer == other.m_buffer && m_index == other.m_index;
- }
- bool operator!=(const const_iterator& other) const {
- return !(*this == other);
- }
+ bool operator==(const const_iterator&) const = default;
const_reference operator*() const { return (*m_buffer)[m_index]; }
private:
diff --git a/wpiutil/src/main/native/include/wpi/type_traits.h b/wpiutil/src/main/native/include/wpi/type_traits.h
deleted file mode 100644
index 5d35ee1..0000000
--- a/wpiutil/src/main/native/include/wpi/type_traits.h
+++ /dev/null
@@ -1,125 +0,0 @@
-//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file provides useful additions to the standard type_traits library.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
-#define WPIUTIL_WPI_TYPE_TRAITS_H
-
-#include "wpi/Compiler.h"
-#include <type_traits>
-#include <utility>
-
-#ifndef __has_feature
-#define WPI_DEFINED_HAS_FEATURE
-#define __has_feature(x) 0
-#endif
-
-namespace wpi {
-
-/// isPodLike - This is a type trait that is used to determine whether a given
-/// type can be copied around with memcpy instead of running ctors etc.
-template <typename T>
-struct isPodLike {
- // std::is_trivially_copyable is available in libc++ with clang, libstdc++
- // that comes with GCC 5.
-#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \
- (defined(__GNUC__) && __GNUC__ >= 5)
- // If the compiler supports the is_trivially_copyable trait use it, as it
- // matches the definition of isPodLike closely.
- static const bool value = std::is_trivially_copyable<T>::value;
-#elif __has_feature(is_trivially_copyable)
- // Use the internal name if the compiler supports is_trivially_copyable but we
- // don't know if the standard library does. This is the case for clang in
- // conjunction with libstdc++ from GCC 4.x.
- static const bool value = __is_trivially_copyable(T);
-#else
- // If we don't know anything else, we can (at least) assume that all non-class
- // types are PODs.
- static const bool value = !std::is_class<T>::value;
-#endif
-};
-
-// std::pair's are pod-like if their elements are.
-template<typename T, typename U>
-struct isPodLike<std::pair<T, U>> {
- static const bool value = isPodLike<T>::value && isPodLike<U>::value;
-};
-
-/// Metafunction that determines whether the given type is either an
-/// integral type or an enumeration type, including enum classes.
-///
-/// Note that this accepts potentially more integral types than is_integral
-/// because it is based on being implicitly convertible to an integral type.
-/// Also note that enum classes aren't implicitly convertible to integral types,
-/// the value may therefore need to be explicitly converted before being used.
-template <typename T> class is_integral_or_enum {
- using UnderlyingT = typename std::remove_reference<T>::type;
-
-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);
-};
-
-/// If T is a pointer, just return it. If it is not, return T&.
-template<typename T, typename Enable = void>
-struct add_lvalue_reference_if_not_pointer { using type = T &; };
-
-template <typename T>
-struct add_lvalue_reference_if_not_pointer<
- T, typename std::enable_if<std::is_pointer<T>::value>::type> {
- using type = T;
-};
-
-/// If T is a pointer to X, return a pointer to const X. If it is not,
-/// return const T.
-template<typename T, typename Enable = void>
-struct add_const_past_pointer { using type = const T; };
-
-template <typename T>
-struct add_const_past_pointer<
- T, typename std::enable_if<std::is_pointer<T>::value>::type> {
- using type = const typename std::remove_pointer<T>::type *;
-};
-
-template <typename T, typename Enable = void>
-struct const_pointer_or_const_ref {
- using type = const T &;
-};
-template <typename T>
-struct const_pointer_or_const_ref<
- T, typename std::enable_if<std::is_pointer<T>::value>::type> {
- using type = typename add_const_past_pointer<T>::type;
-};
-
-} // namespace wpi
-
-// If the compiler supports detecting whether a class is final, define
-// an LLVM_IS_FINAL macro. If it cannot be defined properly, this
-// macro will be left undefined.
-#ifndef LLVM_IS_FINAL
-#if __cplusplus >= 201402L || defined(_MSC_VER)
-#define LLVM_IS_FINAL(Ty) std::is_final<Ty>()
-#elif __has_feature(is_final) || LLVM_GNUC_PREREQ(4, 7, 0)
-#define LLVM_IS_FINAL(Ty) __is_final(Ty)
-#endif
-#endif
-
-#ifdef WPI_DEFINED_HAS_FEATURE
-#undef __has_feature
-#undef WPI_DEFINED_HAS_FEATURE
-#endif
-
-#endif // LLVM_SUPPORT_TYPE_TRAITS_H
diff --git a/wpiutil/src/main/native/include/wpi/uv/Async.h b/wpiutil/src/main/native/include/wpi/uv/Async.h
deleted file mode 100644
index 49f3dde..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Async.h
+++ /dev/null
@@ -1,174 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_ASYNC_H_
-#define WPIUTIL_WPI_UV_ASYNC_H_
-
-#include <uv.h>
-
-#include <memory>
-#include <thread>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "wpi/Signal.h"
-#include "wpi/mutex.h"
-#include "wpi/uv/Handle.h"
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-/**
- * Async handle.
- * Async handles allow the user to "wakeup" the event loop and have a signal
- * generated from another thread.
- *
- * Data may be passed into the callback called on the event loop by using
- * template parameters. If data parameters are used, the async callback will
- * be called once for every call to Send(). If no data parameters are used,
- * the async callback may or may not be called for every call to Send() (e.g.
- * the calls may be coaleasced).
- */
-template <typename... T>
-class Async final : public HandleImpl<Async<T...>, uv_async_t> {
- struct private_init {};
-
- public:
- Async(const std::shared_ptr<Loop>& loop, const private_init&)
- : m_loop{loop} {}
- ~Async() noexcept override {
- if (auto loop = m_loop.lock()) {
- this->Close();
- } else {
- this->ForceClosed();
- }
- }
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Async> Create(Loop& loop) {
- return Create(loop.shared_from_this());
- }
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop) {
- auto h = std::make_shared<Async>(loop, private_init{});
- int err =
- uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
- auto& h = *static_cast<Async*>(handle->data);
- std::scoped_lock lock(h.m_mutex);
- for (auto&& v : h.m_data) {
- std::apply(h.wakeup, v);
- }
- h.m_data.clear();
- });
- if (err < 0) {
- loop->ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
- }
-
- /**
- * Wakeup the event loop and emit the event.
- *
- * It’s safe to call this function from any thread including the loop thread.
- * An async event will be emitted on the loop thread.
- */
- template <typename... U>
- void Send(U&&... u) {
- auto loop = m_loop.lock();
- if (loop && loop->GetThreadId() == std::this_thread::get_id()) {
- // called from within the loop, just call the function directly
- wakeup(std::forward<U>(u)...);
- return;
- }
-
- {
- std::scoped_lock lock(m_mutex);
- m_data.emplace_back(std::forward_as_tuple(std::forward<U>(u)...));
- }
- if (loop) {
- this->Invoke(&uv_async_send, this->GetRaw());
- }
- }
-
- /**
- * Signal generated (on event loop thread) when the async event occurs.
- */
- sig::Signal<T...> wakeup;
-
- private:
- wpi::mutex m_mutex;
- std::vector<std::tuple<T...>> m_data;
- std::weak_ptr<Loop> m_loop;
-};
-
-/**
- * Async specialization for no data parameters. The async callback may or may
- * not be called for every call to Send() (e.g. the calls may be coaleasced).
- */
-template <>
-class Async<> final : public HandleImpl<Async<>, uv_async_t> {
- struct private_init {};
-
- public:
- Async(const std::shared_ptr<Loop>& loop, const private_init&)
- : m_loop(loop) {}
- ~Async() noexcept override;
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Async> Create(Loop& loop) {
- return Create(loop.shared_from_this());
- }
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Async> Create(const std::shared_ptr<Loop>& loop);
-
- /**
- * Wakeup the event loop and emit the event.
- *
- * It’s safe to call this function from any thread.
- * An async event will be emitted on the loop thread.
- */
- void Send() {
- if (auto loop = m_loop.lock()) {
- if (loop->GetThreadId() == std::this_thread::get_id()) {
- // called from within the loop, just call the function directly
- wakeup();
- } else {
- Invoke(&uv_async_send, GetRaw());
- }
- }
- }
-
- /**
- * Signal generated (on event loop thread) when the async event occurs.
- */
- sig::Signal<> wakeup;
-
- private:
- std::weak_ptr<Loop> m_loop;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_ASYNC_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/AsyncFunction.h b/wpiutil/src/main/native/include/wpi/uv/AsyncFunction.h
deleted file mode 100644
index fa4eb90..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/AsyncFunction.h
+++ /dev/null
@@ -1,167 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
-#define WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
-
-#include <stdint.h>
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <thread>
-#include <tuple>
-#include <utility>
-#include <vector>
-
-#include "wpi/future.h"
-#include "wpi/mutex.h"
-#include "wpi/uv/Handle.h"
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-template <typename T>
-class AsyncFunction;
-
-/**
- * Function async handle.
- * Async handles allow the user to "wakeup" the event loop and have a function
- * called from another thread that returns a result to the calling thread.
- */
-template <typename R, typename... T>
-class AsyncFunction<R(T...)> final
- : public HandleImpl<AsyncFunction<R(T...)>, uv_async_t> {
- struct private_init {};
-
- public:
- AsyncFunction(const std::shared_ptr<Loop>& loop,
- std::function<void(promise<R>, T...)> func, const private_init&)
- : wakeup{std::move(func)}, m_loop{loop} {}
- ~AsyncFunction() noexcept override {
- if (auto loop = m_loop.lock()) {
- this->Close();
- } else {
- this->ForceClosed();
- }
- }
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- * @param func wakeup function to be called (sets wakeup value); the function
- * needs to return void, and its first parameter is the promise
- * for the result. If no value is set on the promise by the
- * wakeup function, a default-constructed value is "returned".
- */
- static std::shared_ptr<AsyncFunction> Create(
- Loop& loop, std::function<void(promise<R>, T...)> func = nullptr) {
- return Create(loop.shared_from_this(), std::move(func));
- }
-
- /**
- * Create an async handle.
- *
- * @param loop Loop object where this handle runs.
- * @param func wakeup function to be called (sets wakeup value); the function
- * needs to return void, and its first parameter is the promise
- * for the result. If no value is set on the promise by the
- * wakeup function, a default-constructed value is "returned".
- */
- static std::shared_ptr<AsyncFunction> Create(
- const std::shared_ptr<Loop>& loop,
- std::function<void(promise<R>, T...)> func = nullptr) {
- auto h =
- std::make_shared<AsyncFunction>(loop, std::move(func), private_init{});
- int err =
- uv_async_init(loop->GetRaw(), h->GetRaw(), [](uv_async_t* handle) {
- auto& h = *static_cast<AsyncFunction*>(handle->data);
- std::unique_lock lock(h.m_mutex);
-
- if (!h.m_params.empty()) {
- // for each set of parameters in the input queue, call the wakeup
- // function and put the result in the output queue if the caller is
- // waiting for it
- for (auto&& v : h.m_params) {
- auto p = h.m_promises.CreatePromise(v.first);
- if (h.wakeup) {
- std::apply(h.wakeup,
- std::tuple_cat(std::make_tuple(std::move(p)),
- std::move(v.second)));
- }
- }
- h.m_params.clear();
- // wake up any threads that might be waiting for the result
- lock.unlock();
- h.m_promises.Notify();
- }
- });
- if (err < 0) {
- loop->ReportError(err);
- return nullptr;
- }
- h->Keep();
- return h;
- }
-
- /**
- * Wakeup the event loop, call the async function, and return a future for
- * the result.
- *
- * It’s safe to call this function from any thread including the loop thread.
- * The async function will be called on the loop thread.
- *
- * The future will return a default-constructed result if this handle is
- * destroyed while waiting for a result.
- */
- template <typename... U>
- future<R> Call(U&&... u) {
- // create the future
- uint64_t req = m_promises.CreateRequest();
-
- auto loop = m_loop.lock();
- if (loop && loop->GetThreadId() == std::this_thread::get_id()) {
- // called from within the loop, just call the function directly
- wakeup(m_promises.CreatePromise(req), std::forward<U>(u)...);
- return m_promises.CreateFuture(req);
- }
-
- // add the parameters to the input queue
- {
- std::scoped_lock lock(m_mutex);
- m_params.emplace_back(std::piecewise_construct,
- std::forward_as_tuple(req),
- std::forward_as_tuple(std::forward<U>(u)...));
- }
-
- // signal the loop
- if (loop) {
- this->Invoke(&uv_async_send, this->GetRaw());
- }
-
- // return future
- return m_promises.CreateFuture(req);
- }
-
- template <typename... U>
- future<R> operator()(U&&... u) {
- return Call(std::forward<U>(u)...);
- }
-
- /**
- * Function called (on event loop thread) when the async is called.
- */
- std::function<void(promise<R>, T...)> wakeup;
-
- private:
- wpi::mutex m_mutex;
- std::vector<std::pair<uint64_t, std::tuple<T...>>> m_params;
- PromiseFactory<R> m_promises;
- std::weak_ptr<Loop> m_loop;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_ASYNCFUNCTION_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Buffer.h b/wpiutil/src/main/native/include/wpi/uv/Buffer.h
deleted file mode 100644
index 5126841..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Buffer.h
+++ /dev/null
@@ -1,163 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_BUFFER_H_
-#define WPIUTIL_WPI_UV_BUFFER_H_
-
-#include <uv.h>
-
-#include <cstring>
-#include <initializer_list>
-#include <string_view>
-#include <utility>
-
-#include "wpi/SmallVector.h"
-#include "wpi/span.h"
-
-namespace wpi::uv {
-
-/**
- * Data buffer. Convenience wrapper around uv_buf_t.
- */
-class Buffer : public uv_buf_t {
- public:
- Buffer() {
- base = nullptr;
- len = 0;
- }
- /*implicit*/ Buffer(const uv_buf_t& oth) { // NOLINT
- base = oth.base;
- len = oth.len;
- }
- /*implicit*/ Buffer(std::string_view str) // NOLINT
- : Buffer{str.data(), str.size()} {}
- /*implicit*/ Buffer(span<const uint8_t> arr) // NOLINT
- : Buffer{reinterpret_cast<const char*>(arr.data()), arr.size()} {}
- Buffer(char* base_, size_t len_) {
- base = base_;
- len = static_cast<decltype(len)>(len_);
- }
- Buffer(const char* base_, size_t len_) {
- base = const_cast<char*>(base_);
- len = static_cast<decltype(len)>(len_);
- }
-
- span<const char> data() const { return {base, len}; }
- span<char> data() { return {base, len}; }
-
- operator span<const char>() const { return data(); } // NOLINT
- operator span<char>() { return data(); } // NOLINT
-
- static Buffer Allocate(size_t size) { return Buffer{new char[size], size}; }
-
- static Buffer Dup(std::string_view in) {
- Buffer buf = Allocate(in.size());
- std::memcpy(buf.base, in.data(), in.size());
- return buf;
- }
-
- static Buffer Dup(span<const uint8_t> in) {
- Buffer buf = Allocate(in.size());
- std::memcpy(buf.base, in.begin(), in.size());
- return buf;
- }
-
- Buffer Dup() const {
- Buffer buf = Allocate(len);
- std::memcpy(buf.base, base, len);
- return buf;
- }
-
- void Deallocate() {
- delete[] base;
- base = nullptr;
- len = 0;
- }
-
- Buffer Move() {
- Buffer buf = *this;
- base = nullptr;
- len = 0;
- return buf;
- }
-
- friend void swap(Buffer& a, Buffer& b) {
- using std::swap;
- swap(a.base, b.base);
- swap(a.len, b.len);
- }
-};
-
-/**
- * A simple pool allocator for Buffers.
- * Buffers are allocated individually but are reused rather than returned
- * to the heap.
- * @tparam DEPTH depth of pool
- */
-template <size_t DEPTH = 4>
-class SimpleBufferPool {
- public:
- /**
- * Constructor.
- * @param size Size of each buffer to allocate.
- */
- explicit SimpleBufferPool(size_t size = 4096) : m_size{size} {}
- ~SimpleBufferPool() { Clear(); }
-
- SimpleBufferPool(const SimpleBufferPool& other) = delete;
- SimpleBufferPool& operator=(const SimpleBufferPool& other) = delete;
-
- /**
- * Allocate a buffer.
- */
- Buffer Allocate() {
- if (m_pool.empty()) {
- return Buffer::Allocate(m_size);
- }
- auto buf = m_pool.back();
- m_pool.pop_back();
- buf.len = m_size;
- return buf;
- }
-
- /**
- * Allocate a buffer.
- */
- Buffer operator()() { return Allocate(); }
-
- /**
- * Release allocated buffers back into the pool.
- * This is NOT safe to use with arbitrary buffers unless they were
- * allocated with the same size as the buffer pool allocation size.
- */
- void Release(span<Buffer> bufs) {
- for (auto& buf : bufs) {
- m_pool.emplace_back(buf.Move());
- }
- }
-
- /**
- * Clear the pool, releasing all buffers.
- */
- void Clear() {
- for (auto& buf : m_pool) {
- buf.Deallocate();
- }
- m_pool.clear();
- }
-
- /**
- * Get number of buffers left in the pool before a new buffer will be
- * allocated from the heap.
- */
- size_t Remaining() const { return m_pool.size(); }
-
- private:
- SmallVector<Buffer, DEPTH> m_pool;
- size_t m_size; // NOLINT
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_BUFFER_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Check.h b/wpiutil/src/main/native/include/wpi/uv/Check.h
deleted file mode 100644
index 7555452..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Check.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_CHECK_H_
-#define WPIUTIL_WPI_UV_CHECK_H_
-
-#include <uv.h>
-
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Check handle.
- * Check handles will generate a signal once per loop iteration, right
- * after polling for I/O.
- */
-class Check final : public HandleImpl<Check, uv_check_t> {
- struct private_init {};
-
- public:
- explicit Check(const private_init&) {}
- ~Check() noexcept override = default;
-
- /**
- * Create a check handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Check> Create(Loop& loop);
-
- /**
- * Create a check handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Check> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Start the handle.
- */
- void Start();
-
- /**
- * Stop the handle. The signal will no longer be generated.
- */
- void Stop() { Invoke(&uv_check_stop, GetRaw()); }
-
- /**
- * Signal generated once per loop iteration after polling for I/O.
- */
- sig::Signal<> check;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_CHECK_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Error.h b/wpiutil/src/main/native/include/wpi/uv/Error.h
deleted file mode 100644
index 1e717a4..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Error.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_ERROR_H_
-#define WPIUTIL_WPI_UV_ERROR_H_
-
-#include <uv.h>
-
-namespace wpi::uv {
-
-/**
- * Error code.
- */
-class Error {
- public:
- Error() = default;
- explicit Error(int err) : m_err(err) {}
-
- /**
- * Boolean conversion. Returns true if error, false if ok.
- */
- explicit operator bool() const { return m_err < 0; }
-
- /**
- * Returns the error code.
- */
- int code() const { return m_err; }
-
- /**
- * Returns the error message.
- */
- const char* str() const { return uv_strerror(m_err); }
-
- /**
- * Returns the error name.
- */
- const char* name() const { return uv_err_name(m_err); }
-
- private:
- int m_err{UV_UNKNOWN};
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_ERROR_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/FsEvent.h b/wpiutil/src/main/native/include/wpi/uv/FsEvent.h
deleted file mode 100644
index 0ed2dcb..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/FsEvent.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_FSEVENT_H_
-#define WPIUTIL_WPI_UV_FSEVENT_H_
-
-#include <uv.h>
-
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Filesystem Event handle.
- */
-class FsEvent final : public HandleImpl<FsEvent, uv_fs_event_t> {
- struct private_init {};
-
- public:
- explicit FsEvent(const private_init&) {}
- ~FsEvent() noexcept override = default;
-
- /**
- * Create a filesystem event handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<FsEvent> Create(Loop& loop);
-
- /**
- * Create a filesystem event handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<FsEvent> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Start watching the specified path for changes.
- *
- * @param path Path to watch for changes
- * @param events Bitmask of event flags. Only UV_FS_EVENT_RECURSIVE is
- * supported (and only on OSX and Windows).
- */
- void Start(std::string_view path, unsigned int flags = 0);
-
- /**
- * Stop watching for changes.
- */
- void Stop() { Invoke(&uv_fs_event_stop, GetRaw()); }
-
- /**
- * Get the path being monitored. Signals error and returns empty string if
- * an error occurs.
- * @return Monitored path.
- */
- std::string GetPath();
-
- /**
- * Signal generated when a filesystem change occurs. The first parameter
- * is the filename (if a directory was passed to Start(), the filename is
- * relative to that directory). The second parameter is an ORed mask of
- * UV_RENAME and UV_CHANGE.
- */
- sig::Signal<const char*, int> fsEvent;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_FSEVENT_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/GetAddrInfo.h b/wpiutil/src/main/native/include/wpi/uv/GetAddrInfo.h
deleted file mode 100644
index 18d4f32..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/GetAddrInfo.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_GETADDRINFO_H_
-#define WPIUTIL_WPI_UV_GETADDRINFO_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Request.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * GetAddrInfo request.
- * For use with `GetAddrInfo()` function family.
- */
-class GetAddrInfoReq : public RequestImpl<GetAddrInfoReq, uv_getaddrinfo_t> {
- public:
- GetAddrInfoReq();
-
- Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
-
- /**
- * Resolved lookup signal.
- * Parameter is resolved address info.
- */
- sig::Signal<const addrinfo&> resolved;
-};
-
-/**
- * Asynchronous getaddrinfo(3). HandleResolvedAddress() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * Either node or service may be empty but not both.
- *
- * @param loop Event loop
- * @param req request
- * @param node Either a numerical network address or a network hostname.
- * @param service Either a service name or a port number as a string.
- * @param hints Optional `addrinfo` data structure with additional address
- * type constraints.
- */
-void GetAddrInfo(Loop& loop, const std::shared_ptr<GetAddrInfoReq>& req,
- std::string_view node, std::string_view service = {},
- const addrinfo* hints = nullptr);
-
-/**
- * Asynchronous getaddrinfo(3). HandleResolvedAddress() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * Either node or service may be empty but not both.
- *
- * @param loop Event loop
- * @param req request
- * @param node Either a numerical network address or a network hostname.
- * @param service Either a service name or a port number as a string.
- * @param hints Optional `addrinfo` data structure with additional address
- * type constraints.
- */
-inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
- const std::shared_ptr<GetAddrInfoReq>& req,
- std::string_view node, std::string_view service = {},
- const addrinfo* hints = nullptr) {
- GetAddrInfo(*loop, req, node, service, hints);
-}
-
-/**
- * Asynchronous getaddrinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop. This is a convenience
- * wrapper.
- *
- * Either node or service may be empty but not both.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param node Either a numerical network address or a network hostname.
- * @param service Either a service name or a port number as a string.
- * @param hints Optional `addrinfo` data structure with additional address
- * type constraints.
- */
-void GetAddrInfo(Loop& loop, std::function<void(const addrinfo&)> callback,
- std::string_view node, std::string_view service = {},
- const addrinfo* hints = nullptr);
-
-/**
- * Asynchronous getaddrinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop. This is a convenience
- * wrapper.
- *
- * Either node or service may be empty but not both.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param node Either a numerical network address or a network hostname.
- * @param service Either a service name or a port number as a string.
- * @param hints Optional `addrinfo` data structure with additional address
- * type constraints.
- */
-inline void GetAddrInfo(const std::shared_ptr<Loop>& loop,
- std::function<void(const addrinfo&)> callback,
- std::string_view node, std::string_view service = {},
- const addrinfo* hints = nullptr) {
- GetAddrInfo(*loop, std::move(callback), node, service, hints);
-}
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_GETADDRINFO_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/GetNameInfo.h b/wpiutil/src/main/native/include/wpi/uv/GetNameInfo.h
deleted file mode 100644
index d35dd95..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/GetNameInfo.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_GETNAMEINFO_H_
-#define WPIUTIL_WPI_UV_GETNAMEINFO_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Request.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * GetNameInfo request.
- * For use with `GetNameInfo()` function family.
- */
-class GetNameInfoReq : public RequestImpl<GetNameInfoReq, uv_getnameinfo_t> {
- public:
- GetNameInfoReq();
-
- Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
-
- /**
- * Resolved lookup signal.
- * Parameters are hostname and service.
- */
- sig::Signal<const char*, const char*> resolved;
-};
-
-/**
- * Asynchronous getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- const sockaddr& addr, int flags = 0);
-
-/**
- * Asynchronous getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-inline void GetNameInfo(const std::shared_ptr<Loop>& loop,
- const std::shared_ptr<GetNameInfoReq>& req,
- const sockaddr& addr, int flags = 0) {
- GetNameInfo(*loop, req, addr, flags);
-}
-
-/**
- * Asynchronous getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- const sockaddr& addr, int flags = 0);
-
-/**
- * Asynchronous getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- * @return Connection object for the callback
- */
-inline void GetNameInfo(const std::shared_ptr<Loop>& loop,
- std::function<void(const char*, const char*)> callback,
- const sockaddr& addr, int flags = 0) {
- GetNameInfo(*loop, std::move(callback), addr, flags);
-}
-
-/**
- * Asynchronous IPv4 getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param ip A valid IPv4 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo4(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port, int flags = 0);
-
-/**
- * Asynchronous IPv4 getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param ip A valid IPv4 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
- const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port,
- int flags = 0) {
- return GetNameInfo4(*loop, req, ip, port, flags);
-}
-
-/**
- * Asynchronous IPv4 getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param ip A valid IPv4 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo4(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port, int flags = 0);
-
-/**
- * Asynchronous IPv4 getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop. This is a convenience
- * wrapper.
- *
- * @param loop Event loop
- * @param ip A valid IPv4 address
- * @param port A valid port number
- * @param callback Callback function to call when resolution completes
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-inline void GetNameInfo4(const std::shared_ptr<Loop>& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port,
- int flags = 0) {
- return GetNameInfo4(*loop, std::move(callback), ip, port, flags);
-}
-
-/**
- * Asynchronous IPv6 getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param ip A valid IPv6 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo6(Loop& loop, const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port, int flags = 0);
-
-/**
- * Asynchronous IPv6 getnameinfo(3). HandleResolvedName() is called on the
- * request when the resolution completes. HandleError() is called on the
- * request if any errors occur.
- *
- * @param loop Event loop
- * @param req request
- * @param ip A valid IPv6 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
- const std::shared_ptr<GetNameInfoReq>& req,
- std::string_view ip, unsigned int port,
- int flags = 0) {
- GetNameInfo6(*loop, req, ip, port, flags);
-}
-
-/**
- * Asynchronous IPv6 getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop. This is a convenience
- * wrapper.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param ip A valid IPv6 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-void GetNameInfo6(Loop& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port, int flags = 0);
-
-/**
- * Asynchronous IPv6 getnameinfo(3). The callback is called when the resolution
- * completes, and errors are forwarded to the loop. This is a convenience
- * wrapper.
- *
- * @param loop Event loop
- * @param callback Callback function to call when resolution completes
- * @param ip A valid IPv6 address
- * @param port A valid port number
- * @param flags Optional flags to modify the behavior of `getnameinfo`.
- */
-inline void GetNameInfo6(const std::shared_ptr<Loop>& loop,
- std::function<void(const char*, const char*)> callback,
- std::string_view ip, unsigned int port,
- int flags = 0) {
- return GetNameInfo6(*loop, std::move(callback), ip, port, flags);
-}
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_GETNAMEINFO_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Handle.h b/wpiutil/src/main/native/include/wpi/uv/Handle.h
deleted file mode 100644
index b61cd81..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Handle.h
+++ /dev/null
@@ -1,297 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_HANDLE_H_
-#define WPIUTIL_WPI_UV_HANDLE_H_
-
-#include <uv.h>
-
-#include <cstdlib>
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Buffer.h"
-#include "wpi/uv/Error.h"
-#include "wpi/uv/Loop.h"
-
-namespace wpi::uv {
-
-/**
- * Handle.
- * Handles are not moveable or copyable and cannot be directly constructed.
- * This class provides shared_ptr ownership and shared_from_this.
- * Use the specific handle type Create() functions to create handles.
- */
-class Handle : public std::enable_shared_from_this<Handle> {
- public:
- using Type = uv_handle_type;
-
- Handle(const Handle&) = delete;
- Handle(Handle&&) = delete;
- Handle& operator=(const Handle&) = delete;
- Handle& operator=(Handle&&) = delete;
- virtual ~Handle() noexcept;
-
- /**
- * Get the type of the handle.
- *
- * A base handle offers no functionality to promote it to the actual handle
- * type. By means of this function, the type of the underlying handle as
- * specified by Type is made available.
- *
- * @return The actual type of the handle.
- */
- Type GetType() const noexcept { return m_uv_handle->type; }
-
- /**
- * Get the name of the type of the handle. E.g. "pipe" for pipe handles.
- */
- std::string_view GetTypeName() const noexcept {
- return uv_handle_type_name(m_uv_handle->type);
- }
-
- /**
- * Get the loop where this handle runs.
- *
- * @return The loop.
- */
- std::shared_ptr<Loop> GetLoop() const noexcept {
- return GetLoopRef().shared_from_this();
- }
-
- /**
- * Get the loop where this handle runs.
- *
- * @return The loop.
- */
- Loop& GetLoopRef() const noexcept {
- return *static_cast<Loop*>(m_uv_handle->loop->data);
- }
-
- /**
- * Check if the handle is active.
- *
- * What _active_ means depends on the type of handle:
- *
- * * An AsyncHandle handle is always active and cannot be deactivated,
- * except by closing it with uv_close().
- * * A PipeHandle, TcpHandle, UDPHandle, etc. handle - basically any handle
- * that deals with I/O - is active when it is doing something that involves
- * I/O, like reading, writing, connecting, accepting new connections, etc.
- * * A CheckHandle, IdleHandle, TimerHandle, etc. handle is active when it
- * has been started with a call to `Start()`.
- *
- * Rule of thumb: if a handle of type `FooHandle` has a `Start()` member
- * method, then it’s active from the moment that method is called. Likewise,
- * `Stop()` deactivates the handle again.
- *
- * @return True if the handle is active, false otherwise.
- */
- bool IsActive() const noexcept { return uv_is_active(m_uv_handle) != 0; }
-
- /**
- * Check if a handle is closing or closed.
- *
- * This function should only be used between the initialization of the
- * handle and the arrival of the close callback.
- *
- * @return True if the handle is closing or closed, false otherwise.
- */
- bool IsClosing() const noexcept {
- return m_closed || uv_is_closing(m_uv_handle) != 0;
- }
-
- /**
- * Request handle to be closed.
- *
- * This **must** be called on each handle before memory is released.
- * In-progress requests are cancelled and this can result in error() being
- * emitted.
- *
- * The handle will emit closed() when finished.
- */
- void Close() noexcept;
-
- /**
- * Set if the loop is closing.
- *
- * This is set during EventLoopRunner.Stop(), and can be used for other cases
- * to indicate the loop should be closing. For instance for a uv_walk loop can
- * use this to close existing handles.
- *
- * @param loopClosing true to set the loop currently in closing stages.
- */
- void SetLoopClosing(bool loopClosing) noexcept {
- m_loopClosing = loopClosing;
- }
-
- /**
- * Get the loop closing status.
- *
- * This can be used from closed() in order to tell if a closing loop is the
- * reason for the close, or another reason.
- *
- * @return true if the loop is closing, otherwise false.
- */
- bool IsLoopClosing() const noexcept { return m_loopClosing; }
-
- /**
- * Reference the given handle.
- *
- * References are idempotent, that is, if a handle is already referenced
- * calling this function again will have no effect.
- */
- void Reference() noexcept { uv_ref(m_uv_handle); }
-
- /**
- * Unreference the given handle.
- *
- * References are idempotent, that is, if a handle is not referenced calling
- * this function again will have no effect.
- */
- void Unreference() noexcept { uv_unref(m_uv_handle); }
-
- /**
- * Check if the given handle is referenced.
- * @return True if the handle is referenced, false otherwise.
- */
- bool HasReference() const noexcept { return uv_has_ref(m_uv_handle) != 0; }
-
- /**
- * Return the size of the underlying handle type.
- * @return The size of the underlying handle type.
- */
- size_t RawSize() const noexcept { return uv_handle_size(m_uv_handle->type); }
-
- /**
- * Get the underlying handle data structure.
- *
- * @return The underlying handle data structure.
- */
- uv_handle_t* GetRawHandle() const noexcept { return m_uv_handle; }
-
- /**
- * Set the functions used for allocating and releasing buffers. The size
- * passed to the allocator function is a "suggested" size--it's just an
- * indication, not related in any way to the pending data to be read. The
- * user is free to allocate the amount of memory they decide. For example,
- * applications with custom allocation schemes may decide to use a different
- * size which matches the memory chunks they already have for other purposes.
- *
- * @warning Be very careful changing the allocator after the loop has started
- * running; there are no interlocks between this and buffers currently in
- * flight.
- *
- * @param alloc Allocation function
- * @param dealloc Deallocation function
- */
- void SetBufferAllocator(std::function<Buffer(size_t)> alloc,
- std::function<void(Buffer&)> dealloc) {
- m_allocBuf = std::move(alloc);
- m_freeBuf = std::move(dealloc);
- }
-
- /**
- * Free a buffer. Uses the function provided to SetBufFree() or
- * Buffer::Deallocate by default.
- *
- * @param buf The buffer
- */
- void FreeBuf(Buffer& buf) const noexcept { m_freeBuf(buf); }
-
- /**
- * Gets user-defined data.
- * @return User-defined data if any, nullptr otherwise.
- */
- template <typename T = void>
- std::shared_ptr<T> GetData() const {
- return std::static_pointer_cast<T>(m_data);
- }
-
- /**
- * Sets user-defined data.
- * @param data User-defined arbitrary data.
- */
- void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
-
- /**
- * Error signal
- */
- sig::Signal<Error> error;
-
- /**
- * Closed signal
- */
- sig::Signal<> closed;
-
- /**
- * Report an error.
- * @param err Error code
- */
- void ReportError(int err) const { error(Error(err)); }
-
- protected:
- explicit Handle(uv_handle_t* uv_handle) : m_uv_handle{uv_handle} {
- m_uv_handle->data = this;
- }
-
- void Keep() noexcept { m_self = shared_from_this(); }
- void Release() noexcept { m_self.reset(); }
- void ForceClosed() noexcept { m_closed = true; }
-
- static void AllocBuf(uv_handle_t* handle, size_t size, uv_buf_t* buf);
- static void DefaultFreeBuf(Buffer& buf);
-
- template <typename F, typename... Args>
- bool Invoke(F&& f, Args&&... args) const {
- auto err = std::forward<F>(f)(std::forward<Args>(args)...);
- if (err < 0) {
- ReportError(err);
- }
- return err == 0;
- }
-
- private:
- std::shared_ptr<Handle> m_self;
- uv_handle_t* m_uv_handle;
- bool m_closed = false;
- bool m_loopClosing = false;
- std::function<Buffer(size_t)> m_allocBuf{&Buffer::Allocate};
- std::function<void(Buffer&)> m_freeBuf{&DefaultFreeBuf};
- std::shared_ptr<void> m_data;
-};
-
-/**
- * Handle.
- */
-template <typename T, typename U>
-class HandleImpl : public Handle {
- public:
- std::shared_ptr<T> shared_from_this() {
- return std::static_pointer_cast<T>(Handle::shared_from_this());
- }
-
- std::shared_ptr<const T> shared_from_this() const {
- return std::static_pointer_cast<const T>(Handle::shared_from_this());
- }
-
- /**
- * Get the underlying handle data structure.
- *
- * @return The underlying handle data structure.
- */
- U* GetRaw() const noexcept {
- return reinterpret_cast<U*>(this->GetRawHandle());
- }
-
- protected:
- HandleImpl() : Handle{static_cast<uv_handle_t*>(std::malloc(sizeof(U)))} {}
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_HANDLE_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Idle.h b/wpiutil/src/main/native/include/wpi/uv/Idle.h
deleted file mode 100644
index 869d43d..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Idle.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_IDLE_H_
-#define WPIUTIL_WPI_UV_IDLE_H_
-
-#include <uv.h>
-
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Idle handle.
- *
- * Idle handles will generate a signal once per loop iteration, right
- * before the Prepare handles.
- *
- * The notable difference with Prepare handles is that when there are active
- * idle handles, the loop will perform a zero timeout poll instead of blocking
- * for I/O.
- *
- * @warning Despite the name, idle handles will signal every loop iteration,
- * not when the loop is actually "idle". This also means they can easly become
- * CPU hogs.
- */
-class Idle final : public HandleImpl<Idle, uv_idle_t> {
- struct private_init {};
-
- public:
- explicit Idle(const private_init&) {}
- ~Idle() noexcept override = default;
-
- /**
- * Create an idle handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Idle> Create(Loop& loop);
-
- /**
- * Create an idle handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Idle> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Start the handle.
- */
- void Start();
-
- /**
- * Stop the handle. The signal will no longer be generated.
- */
- void Stop() { Invoke(&uv_idle_stop, GetRaw()); }
-
- /**
- * Signal generated once per loop iteration prior to Prepare signals.
- */
- sig::Signal<> idle;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_IDLE_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Loop.h b/wpiutil/src/main/native/include/wpi/uv/Loop.h
deleted file mode 100644
index 9693053..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Loop.h
+++ /dev/null
@@ -1,253 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_LOOP_H_
-#define WPIUTIL_WPI_UV_LOOP_H_
-
-#include <uv.h>
-
-#include <atomic>
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <thread>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/function_ref.h"
-#include "wpi/uv/Error.h"
-
-namespace wpi::uv {
-
-class Handle;
-
-/**
- * Event loop.
- *
- * The event loop is the central part of uv functionality. It takes care of
- * polling for I/O and scheduling signals to be generated based on different
- * sources of events.
- *
- * The event loop is not moveable, copyable, or directly constructible. Use
- * Create() to create an event loop, or GetDefault() to get the default loop
- * if you know your program will only have a single one.
- */
-class Loop final : public std::enable_shared_from_this<Loop> {
- struct private_init {};
-
- public:
- using Time = std::chrono::duration<uint64_t, std::milli>;
-
- enum Mode {
- kDefault = UV_RUN_DEFAULT,
- kOnce = UV_RUN_ONCE,
- kNoWait = UV_RUN_NOWAIT
- };
-
- explicit Loop(const private_init&) noexcept;
-
- Loop(const Loop&) = delete;
- Loop& operator=(const Loop&) = delete;
- Loop(Loop&& oth) = delete;
- Loop& operator=(Loop&& oth) = delete;
-
- ~Loop() noexcept;
-
- /**
- * Create a new event loop. The created loop is not the default event loop.
- *
- * @return The newly created loop. May return nullptr if a failure occurs.
- */
- static std::shared_ptr<Loop> Create();
-
- /**
- * Create the default event loop. Only use this event loop if a single loop
- * is needed for the entire application.
- *
- * @return The newly created loop. May return nullptr if a failure occurs.
- */
- static std::shared_ptr<Loop> GetDefault();
-
- /**
- * Release all internal loop resources.
- *
- * Call this function only when the loop has finished executing and all open
- * handles and requests have been closed, or the loop will emit an error.
- *
- * error() will be emitted in case of errors.
- */
- void Close();
-
- /**
- * Run the event loop.
- *
- * Available modes are:
- *
- * * `Loop::kDefault`: Run the event loop until there are no
- * active and referenced handles or requests.
- * * `Loop::kOnce`: Run a single event loop iteration. Note that this
- * function blocksif there are no pending callbacks.
- * * `Loop::kNoWait`: Run a single event loop iteration, but don't block
- * if there are no pending callbacks.
- *
- * @return True when done, false in all other cases.
- */
- bool Run(Mode mode = kDefault) {
- m_tid = std::this_thread::get_id();
- int rv = uv_run(m_loop, static_cast<uv_run_mode>(static_cast<int>(mode)));
- m_tid = std::thread::id{};
- return rv == 0;
- }
-
- /**
- * Check if there are active resources.
- *
- * @return True if there are active resources in the loop.
- */
- bool IsAlive() const noexcept { return uv_loop_alive(m_loop) != 0; }
-
- /**
- * Stop the event loop.
- *
- * This will cause Run() to end as soon as possible.
- * This will happen not sooner than the next loop iteration.
- * If this function was called before blocking for I/O, the loop won’t block
- * for I/O on this iteration.
- */
- void Stop() noexcept { uv_stop(m_loop); }
-
- /**
- * Get backend file descriptor.
- *
- * Only kqueue, epoll and event ports are supported.
- * This can be used in conjunction with `run(Loop::kNoWait)` to poll
- * in one thread and run the event loop’s callbacks in another.
- *
- * @return The backend file descriptor.
- */
- int GetDescriptor() const noexcept { return uv_backend_fd(m_loop); }
-
- /**
- * Get the poll timeout.
- *
- * @return A `std::pair` composed of a boolean value that is true in case of
- * valid timeout, false otherwise, and the timeout
- * (`std::chrono::duration<uint64_t, std::milli>`).
- */
- std::pair<bool, Time> GetTimeout() const noexcept {
- auto to = uv_backend_timeout(m_loop);
- return std::make_pair(to == -1, Time{to});
- }
-
- /**
- * Return the current timestamp in milliseconds.
- *
- * The timestamp is cached at the start of the event loop tick.
- * The timestamp increases monotonically from some arbitrary point in
- * time.
- * Don’t make assumptions about the starting point, you will only get
- * disappointed.
- *
- * @return The current timestamp in milliseconds (actual type is
- * `std::chrono::duration<uint64_t, std::milli>`).
- */
- Time Now() const noexcept { return Time{uv_now(m_loop)}; }
-
- /**
- * Update the event loop’s concept of _now_.
- *
- * The current time is cached at the start of the event loop tick in order
- * to reduce the number of time-related system calls.
- * You won’t normally need to call this function unless you have callbacks
- * that block the event loop for longer periods of time, where _longer_ is
- * somewhat subjective but probably on the order of a millisecond or more.
- */
- void UpdateTime() noexcept { uv_update_time(m_loop); }
-
- /**
- * Walk the list of handles.
- *
- * The callback will be executed once for each handle that is still active.
- *
- * @param callback A function to be invoked once for each active handle.
- */
- void Walk(function_ref<void(Handle&)> callback);
-
- /**
- * Reinitialize any kernel state necessary in the child process after
- * a fork(2) system call.
- *
- * Previously started watchers will continue to be started in the child
- * process.
- *
- * It is necessary to explicitly call this function on every event loop
- * created in the parent process that you plan to continue to use in the
- * child, including the default loop (even if you don’t continue to use it
- * in the parent). This function must be called before calling any API
- * function using the loop in the child. Failure to do so will result in
- * undefined behaviour, possibly including duplicate events delivered to
- * both parent and child or aborting the child process.
- *
- * When possible, it is preferred to create a new loop in the child process
- * instead of reusing a loop created in the parent. New loops created in the
- * child process after the fork should not use this function.
- *
- * Note that this function is not implemented on Windows.
- * Note also that this function is experimental in `libuv`. It may contain
- * bugs, and is subject to change or removal. API and ABI stability is not
- * guaranteed.
- *
- * error() will be emitted in case of errors.
- */
- void Fork();
-
- /**
- * Get the underlying event loop data structure.
- *
- * @return The underlying event loop data structure.
- */
- uv_loop_t* GetRaw() const noexcept { return m_loop; }
-
- /**
- * Gets user-defined data.
- * @return User-defined data if any, nullptr otherwise.
- */
- template <typename T = void>
- std::shared_ptr<T> GetData() const {
- return std::static_pointer_cast<T>(m_data);
- }
-
- /**
- * Sets user-defined data.
- * @param data User-defined arbitrary data.
- */
- void SetData(std::shared_ptr<void> data) { m_data = std::move(data); }
-
- /**
- * Get the thread id of the loop thread. If the loop is not currently
- * running, returns default-constructed thread id.
- */
- std::thread::id GetThreadId() const { return m_tid; }
-
- /**
- * Error signal
- */
- sig::Signal<Error> error;
-
- /**
- * Reports error.
- * @param err Error code
- */
- void ReportError(int err) { error(Error(err)); }
-
- private:
- std::shared_ptr<void> m_data;
- uv_loop_t* m_loop;
- uv_loop_t m_loopStruct;
- std::atomic<std::thread::id> m_tid;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_LOOP_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/NetworkStream.h b/wpiutil/src/main/native/include/wpi/uv/NetworkStream.h
deleted file mode 100644
index faac9fe..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/NetworkStream.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_NETWORKSTREAM_H_
-#define WPIUTIL_WPI_UV_NETWORKSTREAM_H_
-
-#include <uv.h>
-
-#include <cstdlib>
-#include <functional>
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Stream.h"
-
-namespace wpi::uv {
-
-class NetworkStream;
-
-/**
- * Connection request.
- */
-class ConnectReq : public RequestImpl<ConnectReq, uv_connect_t> {
- public:
- ConnectReq();
-
- NetworkStream& GetStream() const {
- return *static_cast<NetworkStream*>(GetRaw()->handle->data);
- }
-
- /**
- * Connection completed signal.
- */
- sig::Signal<> connected;
-};
-
-/**
- * Network stream handle.
- * This is an abstract type; there are two network stream implementations (Tcp
- * and Pipe).
- */
-class NetworkStream : public Stream {
- public:
- static constexpr int kDefaultBacklog = 128;
-
- std::shared_ptr<NetworkStream> shared_from_this() {
- return std::static_pointer_cast<NetworkStream>(Handle::shared_from_this());
- }
-
- std::shared_ptr<const NetworkStream> shared_from_this() const {
- return std::static_pointer_cast<const NetworkStream>(
- Handle::shared_from_this());
- }
-
- /**
- * Start listening for incoming connections. When a new incoming connection
- * is received the connection signal is generated.
- * @param backlog the number of connections the kernel might queue, same as
- * listen(2).
- */
- void Listen(int backlog = kDefaultBacklog);
-
- /**
- * Start listening for incoming connections. This is a convenience wrapper
- * around `Listen(int)` that also connects a callback to the connection
- * signal. When a new incoming connection is received the connection signal
- * is generated (and the callback is called).
- * @param callback the callback to call when a connection is received.
- * `Accept()` should be called from this callback.
- * @param backlog the number of connections the kernel might queue, same as
- * listen(2).
- */
- void Listen(std::function<void()> callback, int backlog = kDefaultBacklog);
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a ListenEvent event to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @return The stream handle for the accepted connection, or nullptr on error.
- */
- std::shared_ptr<NetworkStream> Accept() {
- return DoAccept()->shared_from_this();
- }
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a connection signal to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @param client Client stream object.
- * @return False on error.
- */
- bool Accept(const std::shared_ptr<NetworkStream>& client) {
- return Invoke(&uv_accept, GetRawStream(), client->GetRawStream());
- }
-
- /**
- * Signal generated when an incoming connection is received.
- */
- sig::Signal<> connection;
-
- protected:
- explicit NetworkStream(uv_stream_t* uv_stream) : Stream{uv_stream} {}
-
- virtual NetworkStream* DoAccept() = 0;
-};
-
-template <typename T, typename U>
-class NetworkStreamImpl : public NetworkStream {
- public:
- std::shared_ptr<T> shared_from_this() {
- return std::static_pointer_cast<T>(Handle::shared_from_this());
- }
-
- std::shared_ptr<const T> shared_from_this() const {
- return std::static_pointer_cast<const T>(Handle::shared_from_this());
- }
-
- /**
- * Get the underlying handle data structure.
- *
- * @return The underlying handle data structure.
- */
- U* GetRaw() const noexcept {
- return reinterpret_cast<U*>(this->GetRawHandle());
- }
-
- protected:
- NetworkStreamImpl()
- : NetworkStream{static_cast<uv_stream_t*>(std::malloc(sizeof(U)))} {}
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_NETWORKSTREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Pipe.h b/wpiutil/src/main/native/include/wpi/uv/Pipe.h
deleted file mode 100644
index e223268..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Pipe.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_PIPE_H_
-#define WPIUTIL_WPI_UV_PIPE_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/uv/NetworkStream.h"
-
-namespace wpi::uv {
-
-class Loop;
-class PipeConnectReq;
-
-/**
- * Pipe handle.
- * Pipe handles provide an abstraction over local domain sockets on Unix and
- * named pipes on Windows.
- */
-class Pipe final : public NetworkStreamImpl<Pipe, uv_pipe_t> {
- struct private_init {};
-
- public:
- explicit Pipe(const private_init&) {}
- ~Pipe() noexcept override = default;
-
- /**
- * Create a pipe handle.
- *
- * @param loop Loop object where this handle runs.
- * @param ipc Indicates if this pipe will be used for handle passing between
- * processes.
- */
- static std::shared_ptr<Pipe> Create(Loop& loop, bool ipc = false);
-
- /**
- * Create a pipe handle.
- *
- * @param loop Loop object where this handle runs.
- * @param ipc Indicates if this pipe will be used for handle passing between
- * processes.
- */
- static std::shared_ptr<Pipe> Create(const std::shared_ptr<Loop>& loop,
- bool ipc = false) {
- return Create(*loop, ipc);
- }
-
- /**
- * Reuse this handle. This closes the handle, and after the close completes,
- * reinitializes it (identically to Create) and calls the provided callback.
- * Unlike Close(), it does NOT emit the closed signal, however, IsClosing()
- * will return true until the callback is called. This does nothing if
- * IsClosing() is true (e.g. if Close() was called).
- *
- * @param ipc IPC
- * @param callback Callback
- */
- void Reuse(std::function<void()> callback, bool ipc = false);
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a ListenEvent event to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @return The stream handle for the accepted connection, or nullptr on error.
- */
- std::shared_ptr<Pipe> Accept();
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a connection signal to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @param client Client stream object.
- * @return False on error.
- */
- bool Accept(const std::shared_ptr<Pipe>& client) {
- return NetworkStream::Accept(client);
- }
-
- /**
- * Open an existing file descriptor or HANDLE as a pipe.
- *
- * @note The passed file descriptor or HANDLE is not checked for its type, but
- * it's required that it represents a valid pipe.
- *
- * @param file A valid file handle (either a file descriptor or a HANDLE).
- */
- void Open(uv_file file) { Invoke(&uv_pipe_open, GetRaw(), file); }
-
- /**
- * Bind the pipe to a file path (Unix) or a name (Windows).
- *
- * @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
- * typically between 92 and 108 bytes.
- *
- * @param name File path (Unix) or name (Windows).
- */
- void Bind(std::string_view name);
-
- /**
- * Connect to the Unix domain socket or the named pipe.
- *
- * @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
- * typically between 92 and 108 bytes.
- *
- * HandleConnected() is called on the request when the connection has been
- * established.
- * HandleError() is called on the request in case of errors during the
- * connection.
- *
- * @param name File path (Unix) or name (Windows).
- * @param req connection request
- */
- void Connect(std::string_view name,
- const std::shared_ptr<PipeConnectReq>& req);
-
- /**
- * Connect to the Unix domain socket or the named pipe.
- *
- * @note Paths on Unix get truncated to `sizeof(sockaddr_un.sun_path)` bytes,
- * typically between 92 and 108 bytes.
- *
- * The callback is called when the connection has been established. Errors
- * are reported to the stream error handler.
- *
- * @param name File path (Unix) or name (Windows).
- * @param callback Callback function to call when connection established
- */
- void Connect(std::string_view name, std::function<void()> callback);
-
- /**
- * Get the name of the Unix domain socket or the named pipe.
- * @return The name (will be empty if an error occurred).
- */
- std::string GetSock();
-
- /**
- * Get the name of the Unix domain socket or the named pipe to which the
- * handle is connected.
- * @return The name (will be empty if an error occurred).
- */
- std::string GetPeer();
-
- /**
- * Set the number of pending pipe instance handles when the pipe server is
- * waiting for connections.
- * @note This setting applies to Windows only.
- * @param count Number of pending handles.
- */
- void SetPendingInstances(int count) {
- uv_pipe_pending_instances(GetRaw(), count);
- }
-
- /**
- * Alters pipe permissions, allowing it to be accessed from processes run
- * by different users. Makes the pipe writable or readable by all users.
- * Mode can be UV_WRITABLE, UV_READABLE, or both. This function is blocking.
- * @param flags chmod flags
- */
- void Chmod(int flags) { Invoke(&uv_pipe_chmod, GetRaw(), flags); }
-
- private:
- Pipe* DoAccept() override;
-
- struct ReuseData {
- std::function<void()> callback;
- bool ipc;
- };
- std::unique_ptr<ReuseData> m_reuseData;
-};
-
-/**
- * Pipe connection request.
- */
-class PipeConnectReq : public ConnectReq {
- public:
- Pipe& GetStream() const {
- return *static_cast<Pipe*>(&ConnectReq::GetStream());
- }
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_PIPE_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Poll.h b/wpiutil/src/main/native/include/wpi/uv/Poll.h
deleted file mode 100644
index 6e1e26d..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Poll.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_POLL_H_
-#define WPIUTIL_WPI_UV_POLL_H_
-
-#include <uv.h>
-
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Poll handle.
- */
-class Poll final : public HandleImpl<Poll, uv_poll_t> {
- struct private_init {};
-
- public:
- explicit Poll(const private_init&) {}
- ~Poll() noexcept override = default;
-
- /**
- * Create a poll handle using a file descriptor.
- *
- * @param loop Loop object where this handle runs.
- * @param fd File descriptor.
- */
- static std::shared_ptr<Poll> Create(Loop& loop, int fd);
-
- /**
- * Create a poll handle using a file descriptor.
- *
- * @param loop Loop object where this handle runs.
- * @param fd File descriptor.
- */
- static std::shared_ptr<Poll> Create(const std::shared_ptr<Loop>& loop,
- int fd) {
- return Create(*loop, fd);
- }
-
- /**
- * Create a poll handle using a socket descriptor.
- *
- * @param loop Loop object where this handle runs.
- * @param sock Socket descriptor.
- */
- static std::shared_ptr<Poll> CreateSocket(Loop& loop, uv_os_sock_t sock);
-
- /**
- * Create a poll handle using a socket descriptor.
- *
- * @param loop Loop object where this handle runs.
- * @param sock Socket descriptor.
- */
- static std::shared_ptr<Poll> CreateSocket(const std::shared_ptr<Loop>& loop,
- uv_os_sock_t sock) {
- return CreateSocket(*loop, sock);
- }
-
- /**
- * Reuse this handle. This closes the handle, and after the close completes,
- * reinitializes it (identically to Create) and calls the provided callback.
- * Unlike Close(), it does NOT emit the closed signal, however, IsClosing()
- * will return true until the callback is called. This does nothing if
- * IsClosing() is true (e.g. if Close() was called).
- *
- * @param fd File descriptor
- * @param callback Callback
- */
- void Reuse(int fd, std::function<void()> callback);
-
- /**
- * Reuse this handle. This closes the handle, and after the close completes,
- * reinitializes it (identically to CreateSocket) and calls the provided
- * callback. Unlike Close(), it does NOT emit the closed signal, however,
- * IsClosing() will return true until the callback is called. This does
- * nothing if IsClosing() is true (e.g. if Close() was called).
- *
- * @param sock Socket descriptor.
- * @param callback Callback
- */
- void ReuseSocket(uv_os_sock_t sock, std::function<void()> callback);
-
- /**
- * Start polling the file descriptor.
- *
- * @param events Bitmask of events (UV_READABLE, UV_WRITEABLE, UV_PRIORITIZED,
- * and UV_DISCONNECT).
- */
- void Start(int events);
-
- /**
- * Stop polling the file descriptor.
- */
- void Stop() { Invoke(&uv_poll_stop, GetRaw()); }
-
- /**
- * Signal generated when a poll event occurs.
- */
- sig::Signal<int> pollEvent;
-
- private:
- struct ReuseData {
- std::function<void()> callback;
- bool isSocket;
- int fd;
- uv_os_sock_t sock;
- };
- std::unique_ptr<ReuseData> m_reuseData;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_POLL_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Prepare.h b/wpiutil/src/main/native/include/wpi/uv/Prepare.h
deleted file mode 100644
index 88ae2d9..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Prepare.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_PREPARE_H_
-#define WPIUTIL_WPI_UV_PREPARE_H_
-
-#include <uv.h>
-
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Prepare handle.
- * Prepare handles will generate a signal once per loop iteration, right
- * before polling for I/O.
- */
-class Prepare final : public HandleImpl<Prepare, uv_prepare_t> {
- struct private_init {};
-
- public:
- explicit Prepare(const private_init&) {}
- ~Prepare() noexcept override = default;
-
- /**
- * Create a prepare handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Prepare> Create(Loop& loop);
-
- /**
- * Create a prepare handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Prepare> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Start the handle.
- */
- void Start();
-
- /**
- * Stop the handle. The signal will no longer be generated.
- */
- void Stop() { Invoke(&uv_prepare_stop, GetRaw()); }
-
- /**
- * Signal generated once per loop iteration prior to polling for I/O.
- */
- sig::Signal<> prepare;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_PREPARE_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Process.h b/wpiutil/src/main/native/include/wpi/uv/Process.h
deleted file mode 100644
index fc2315e..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Process.h
+++ /dev/null
@@ -1,310 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_PROCESS_H_
-#define WPIUTIL_WPI_UV_PROCESS_H_
-
-#include <uv.h>
-
-#include <initializer_list>
-#include <memory>
-#include <string>
-#include <string_view>
-
-#include "wpi/Signal.h"
-#include "wpi/SmallVector.h"
-#include "wpi/span.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-class Pipe;
-
-/**
- * Process handle.
- * Process handles will spawn a new process and allow the user to control it
- * and establish communication channels with it using streams.
- */
-class Process final : public HandleImpl<Process, uv_process_t> {
- struct private_init {};
-
- public:
- explicit Process(const private_init&) {}
- ~Process() noexcept override = default;
-
- /**
- * Structure for Spawn() option temporaries. This is a reference type, so if
- * this value is stored outside of a temporary, be careful about overwriting
- * what it points to.
- */
- struct Option {
- enum Type {
- kNone,
- kArg,
- kEnv,
- kCwd,
- kUid,
- kGid,
- kSetFlags,
- kClearFlags,
- kStdioIgnore,
- kStdioInheritFd,
- kStdioInheritPipe,
- kStdioCreatePipe
- };
-
- Option() : m_type(kNone) {}
-
- /*implicit*/ Option(const char* arg) { // NOLINT
- m_data.str = arg;
- }
-
- /*implicit*/ Option(const std::string& arg) { // NOLINT
- m_data.str = arg.data();
- }
-
- /*implicit*/ Option(std::string_view arg) // NOLINT
- : m_strData(arg) {
- m_data.str = m_strData.c_str();
- }
-
- /*implicit*/ Option(const SmallVectorImpl<char>& arg) // NOLINT
- : m_strData(arg.data(), arg.size()) {
- m_data.str = m_strData.c_str();
- }
-
- explicit Option(Type type) : m_type(type) {}
-
- Type m_type = kArg;
- std::string m_strData;
- union {
- const char* str;
- uv_uid_t uid;
- uv_gid_t gid;
- unsigned int flags;
- struct {
- size_t index;
- union {
- int fd;
- Pipe* pipe;
- };
- unsigned int flags;
- } stdio;
- } m_data;
- };
-
- /**
- * Set environment variable for the subprocess. If not set, the parent's
- * environment is used.
- * @param env environment variable
- */
- static Option Env(std::string_view env) {
- Option o(Option::kEnv);
- o.m_strData = env;
- o.m_data.str = o.m_strData.c_str();
- return o;
- }
-
- /**
- * Set the current working directory for the subprocess.
- * @param cwd current working directory
- */
- static Option Cwd(std::string_view cwd) {
- Option o(Option::kCwd);
- o.m_strData = cwd;
- o.m_data.str = o.m_strData.c_str();
- return o;
- }
-
- /**
- * Set the child process' user id.
- * @param uid user id
- */
- static Option Uid(uv_uid_t uid) {
- Option o(Option::kUid);
- o.m_data.uid = uid;
- return o;
- }
-
- /**
- * Set the child process' group id.
- * @param gid group id
- */
- static Option Gid(uv_gid_t gid) {
- Option o(Option::kGid);
- o.m_data.gid = gid;
- return o;
- }
-
- /**
- * Set spawn flags.
- * @param flags Bitmask values from uv_process_flags.
- */
- static Option SetFlags(unsigned int flags) {
- Option o(Option::kSetFlags);
- o.m_data.flags = flags;
- return o;
- }
-
- /**
- * Clear spawn flags.
- * @param flags Bitmask values from uv_process_flags.
- */
- static Option ClearFlags(unsigned int flags) {
- Option o(Option::kClearFlags);
- o.m_data.flags = flags;
- return o;
- }
-
- /**
- * Explicitly ignore a stdio.
- * @param index stdio index
- */
- static Option StdioIgnore(size_t index) {
- Option o(Option::kStdioIgnore);
- o.m_data.stdio.index = index;
- return o;
- }
-
- /**
- * Inherit a file descriptor from the parent process.
- * @param index stdio index
- * @param fd parent file descriptor
- */
- static Option StdioInherit(size_t index, int fd) {
- Option o(Option::kStdioInheritFd);
- o.m_data.stdio.index = index;
- o.m_data.stdio.fd = fd;
- return o;
- }
-
- /**
- * Inherit a pipe from the parent process.
- * @param index stdio index
- * @param pipe pipe
- */
- static Option StdioInherit(size_t index, Pipe& pipe) {
- Option o(Option::kStdioInheritPipe);
- o.m_data.stdio.index = index;
- o.m_data.stdio.pipe = &pipe;
- return o;
- }
-
- /**
- * Create a pipe between the child and the parent.
- * @param index stdio index
- * @param pipe pipe
- * @param flags Some combination of UV_READABLE_PIPE, UV_WRITABLE_PIPE, and
- * UV_OVERLAPPED_PIPE (Windows only, ignored on Unix).
- */
- static Option StdioCreatePipe(size_t index, Pipe& pipe, unsigned int flags) {
- Option o(Option::kStdioCreatePipe);
- o.m_data.stdio.index = index;
- o.m_data.stdio.pipe = &pipe;
- o.m_data.stdio.flags = flags;
- return o;
- }
-
- /**
- * Disables inheritance for file descriptors / handles that this process
- * inherited from its parent. The effect is that child processes spawned
- * by this process don't accidentally inherit these handles.
- *
- * It is recommended to call this function as early in your program as
- * possible, before the inherited file descriptors can be closed or
- * duplicated.
- */
- static void DisableStdioInheritance() { uv_disable_stdio_inheritance(); }
-
- /**
- * Starts a process. If the process is not successfully spawned, an error
- * is generated on the loop and this function returns nullptr.
- *
- * Possible reasons for failing to spawn would include (but not be limited to)
- * the file to execute not existing, not having permissions to use the setuid
- * or setgid specified, or not having enough memory to allocate for the new
- * process.
- *
- * @param loop Loop object where this handle runs.
- * @param file Path pointing to the program to be executed
- * @param options Process options
- */
- static std::shared_ptr<Process> SpawnArray(Loop& loop, std::string_view file,
- span<const Option> options);
-
- static std::shared_ptr<Process> SpawnArray(
- Loop& loop, std::string_view file,
- std::initializer_list<Option> options) {
- return SpawnArray(loop, file, {options.begin(), options.end()});
- }
-
- template <typename... Args>
- static std::shared_ptr<Process> Spawn(Loop& loop, std::string_view file,
- const Args&... options) {
- return SpawnArray(loop, file, {options...});
- }
-
- /**
- * Starts a process. If the process is not successfully spawned, an error
- * is generated on the loop and this function returns nullptr.
- *
- * Possible reasons for failing to spawn would include (but not be limited to)
- * the file to execute not existing, not having permissions to use the setuid
- * or setgid specified, or not having enough memory to allocate for the new
- * process.
- *
- * @param loop Loop object where this handle runs.
- * @param file Path pointing to the program to be executed
- * @param options Process options
- */
- static std::shared_ptr<Process> SpawnArray(const std::shared_ptr<Loop>& loop,
- std::string_view file,
- span<const Option> options) {
- return SpawnArray(*loop, file, options);
- }
-
- static std::shared_ptr<Process> SpawnArray(
- const std::shared_ptr<Loop>& loop, std::string_view file,
- std::initializer_list<Option> options) {
- return SpawnArray(*loop, file, options);
- }
-
- template <typename... Args>
- static std::shared_ptr<Process> Spawn(const std::shared_ptr<Loop>& loop,
- std::string_view file,
- const Args&... options) {
- return SpawnArray(*loop, file, {options...});
- }
-
- /**
- * Sends the specified signal to the process.
- * @param signum signal number
- */
- void Kill(int signum) { Invoke(&uv_process_kill, GetRaw(), signum); }
-
- /**
- * Sends the specified signal to the given PID.
- * @param pid process ID
- * @param signum signal number
- * @return 0 on success, otherwise error code.
- */
- static int Kill(int pid, int signum) noexcept { return uv_kill(pid, signum); }
-
- /**
- * Get the process ID.
- * @return Process ID.
- */
- uv_pid_t GetPid() const noexcept { return GetRaw()->pid; }
-
- /**
- * Signal generated when the process exits. The parameters are the exit
- * status and the signal that caused the process to terminate, if any.
- */
- sig::Signal<int64_t, int> exited;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_PROCESS_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Request.h b/wpiutil/src/main/native/include/wpi/uv/Request.h
deleted file mode 100644
index 3f6a19d..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Request.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_REQUEST_H_
-#define WPIUTIL_WPI_UV_REQUEST_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-
-#include "wpi/uv/Error.h"
-
-namespace wpi::uv {
-
-/**
- * Request. Requests are not moveable or copyable.
- * This class provides shared_ptr ownership and shared_from_this.
- */
-class Request : public std::enable_shared_from_this<Request> {
- public:
- using Type = uv_req_type;
-
- Request(const Request&) = delete;
- Request(Request&&) = delete;
- Request& operator=(const Request&) = delete;
- Request& operator=(Request&&) = delete;
- virtual ~Request() noexcept = default;
-
- /**
- * Get the type of the request.
- *
- * A base request offers no functionality to promote it to the actual request
- * type. By means of this function, the type of the underlying request as
- * specified by Type is made available.
- *
- * @return The actual type of the request.
- */
- Type GetType() const noexcept { return m_uv_req->type; }
-
- /**
- * Get the name of the type of the request. E.g. "connect" for connect.
- */
- const char* GetTypeName() const noexcept {
- return uv_req_type_name(m_uv_req->type);
- }
-
- /**
- * Cancel a pending request.
- *
- * This method fails if the request is executing or has finished
- * executing.
- * It can emit an error signal in case of errors.
- *
- * @return True in case of success, false otherwise.
- */
- bool Cancel() { return uv_cancel(m_uv_req) == 0; }
-
- /**
- * Return the size of the underlying request type.
- * @return The size of the underlying request type.
- */
- size_t RawSize() const noexcept { return uv_req_size(m_uv_req->type); }
-
- /**
- * Get the underlying request data structure.
- *
- * @return The underlying request data structure.
- */
- uv_req_t* GetRawReq() noexcept { return m_uv_req; }
-
- /**
- * Get the underlying request data structure.
- *
- * @return The underlying request data structure.
- */
- const uv_req_t* GetRawReq() const noexcept { return m_uv_req; }
-
- /**
- * Keep this request in memory even if no outside shared_ptr references
- * remain. To release call Release().
- *
- * Derived classes can override this method for different memory management
- * approaches (e.g. pooled storage of requests).
- */
- virtual void Keep() noexcept { m_self = shared_from_this(); }
-
- /**
- * No longer force holding this request in memory. Does not immediately
- * destroy the object unless no outside shared_ptr references remain.
- *
- * Derived classes can override this method for different memory management
- * approaches (e.g. pooled storage of requests).
- */
- virtual void Release() noexcept { m_self.reset(); }
-
- /**
- * Error callback. By default, this is set up to report errors to the handle
- * that created this request.
- * @param err error code
- */
- std::function<void(Error)> error;
-
- /**
- * Report an error.
- * @param err Error code
- */
- void ReportError(int err) { error(Error(err)); }
-
- protected:
- /**
- * Constructor.
- */
- explicit Request(uv_req_t* uv_req) : m_uv_req{uv_req} {
- m_uv_req->data = this;
- }
-
- private:
- std::shared_ptr<Request> m_self;
- uv_req_t* m_uv_req;
-};
-
-/**
- * Request. Requests are not moveable or copyable.
- * @tparam T CRTP derived class
- * @tparam U underlying libuv request type
- */
-template <typename T, typename U>
-class RequestImpl : public Request {
- public:
- std::shared_ptr<T> shared_from_this() {
- return std::static_pointer_cast<T>(this->shared_from_this());
- }
-
- std::shared_ptr<const T> shared_from_this() const {
- return std::static_pointer_cast<const T>(this->shared_from_this());
- }
-
- /**
- * Get the underlying request data structure.
- *
- * @return The underlying request data structure.
- */
- U* GetRaw() noexcept { return &m_uv_req; }
-
- /**
- * Get the underlying request data structure.
- *
- * @return The underlying request data structure.
- */
- const U* GetRaw() const noexcept { return &m_uv_req; }
-
- protected:
- /**
- * Constructor.
- */
- RequestImpl() : Request{reinterpret_cast<uv_req_t*>(&m_uv_req)} {}
-
- private:
- U m_uv_req;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_REQUEST_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Signal.h b/wpiutil/src/main/native/include/wpi/uv/Signal.h
deleted file mode 100644
index 9abcad3..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Signal.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_SIGNAL_H_
-#define WPIUTIL_WPI_UV_SIGNAL_H_
-
-#include <uv.h>
-
-#include <memory>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Signal handle.
- */
-class Signal final : public HandleImpl<Signal, uv_signal_t> {
- struct private_init {};
-
- public:
- explicit Signal(const private_init&) {}
- ~Signal() noexcept override = default;
-
- /**
- * Create a signal handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Signal> Create(Loop& loop);
-
- /**
- * Create a signal handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Signal> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Start watching for the given signal.
- *
- * @param signum Signal to watch for.
- */
- void Start(int signum);
-
- /**
- * Start watching for the given signal. Same as Start() but the signal
- * handler is reset the moment the signal is received.
- *
- * @param signum Signal to watch for.
- */
- void StartOneshot(int signum);
-
- /**
- * Stop watching for the signal.
- */
- void Stop() { Invoke(&uv_signal_stop, GetRaw()); }
-
- /**
- * Get the signal being monitored.
- * @return Signal number.
- */
- int GetSignal() const { return GetRaw()->signum; }
-
- /**
- * Signal generated when a signal occurs.
- */
- sig::Signal<int> signal;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_SIGNAL_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Stream.h b/wpiutil/src/main/native/include/wpi/uv/Stream.h
deleted file mode 100644
index 0ade972..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Stream.h
+++ /dev/null
@@ -1,302 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_STREAM_H_
-#define WPIUTIL_WPI_UV_STREAM_H_
-
-#include <uv.h>
-
-#include <cstdlib>
-#include <functional>
-#include <initializer_list>
-#include <memory>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/span.h"
-#include "wpi/uv/Buffer.h"
-#include "wpi/uv/Handle.h"
-#include "wpi/uv/Request.h"
-
-namespace wpi::uv {
-
-class Stream;
-
-/**
- * Shutdown request.
- */
-class ShutdownReq : public RequestImpl<ShutdownReq, uv_shutdown_t> {
- public:
- ShutdownReq();
-
- Stream& GetStream() const {
- return *static_cast<Stream*>(GetRaw()->handle->data);
- }
-
- /**
- * Shutdown completed signal.
- */
- sig::Signal<> complete;
-};
-
-/**
- * Write request.
- */
-class WriteReq : public RequestImpl<WriteReq, uv_write_t> {
- public:
- WriteReq();
-
- Stream& GetStream() const {
- return *static_cast<Stream*>(GetRaw()->handle->data);
- }
-
- /**
- * Write completed signal. This is called even if an error occurred.
- * @param err error value
- */
- sig::Signal<Error> finish;
-};
-
-/**
- * Stream handle.
- * Stream handles provide an abstraction of a duplex communication channel.
- * This is an abstract type; there are three stream implementations (Tcp,
- * Pipe, and Tty).
- */
-class Stream : public Handle {
- public:
- std::shared_ptr<Stream> shared_from_this() {
- return std::static_pointer_cast<Stream>(Handle::shared_from_this());
- }
-
- std::shared_ptr<const Stream> shared_from_this() const {
- return std::static_pointer_cast<const Stream>(Handle::shared_from_this());
- }
-
- /**
- * Shutdown the outgoing (write) side of a duplex stream. It waits for pending
- * write requests to complete. HandleShutdownComplete() is called on the
- * request after shutdown is complete.
- *
- * @param req shutdown request
- */
- void Shutdown(const std::shared_ptr<ShutdownReq>& req);
-
- /**
- * Shutdown the outgoing (write) side of a duplex stream. It waits for pending
- * write requests to complete. The callback is called after shutdown is
- * complete. Errors will be reported to the stream error handler.
- *
- * @param callback Callback function to call when shutdown completes
- * @return Connection object for the callback
- */
- void Shutdown(std::function<void()> callback = nullptr);
-
- /**
- * Start reading data from an incoming stream.
- *
- * This will only succeed after a connection has been established.
- *
- * A data signal will be emitted several times until there is no more
- * data to read or `StopRead()` is called.
- * An end signal will be emitted when there is no more data to read.
- */
- void StartRead();
-
- /**
- * Stop reading data from the stream.
- *
- * This function is idempotent and may be safely called on a stopped stream.
- */
- void StopRead() { Invoke(&uv_read_stop, GetRawStream()); }
-
- /**
- * Write data to the stream.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the write request.
- * An easy way to ensure this is to have the write request keep track of
- * the data and use either its Complete() function or destructor to free the
- * data.
- *
- * The finish signal will be emitted on the request object when the data
- * has been written (or if an error occurs).
- * The error signal will be emitted on the request object in case of errors.
- *
- * @param bufs The buffers to be written to the stream.
- * @param req write request
- */
- void Write(span<const Buffer> bufs, const std::shared_ptr<WriteReq>& req);
-
- /**
- * Write data to the stream.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the write request.
- * An easy way to ensure this is to have the write request keep track of
- * the data and use either its Complete() function or destructor to free the
- * data.
- *
- * The finish signal will be emitted on the request object when the data
- * has been written (or if an error occurs).
- * The error signal will be emitted on the request object in case of errors.
- *
- * @param bufs The buffers to be written to the stream.
- * @param req write request
- */
- void Write(std::initializer_list<Buffer> bufs,
- const std::shared_ptr<WriteReq>& req) {
- Write({bufs.begin(), bufs.end()}, req);
- }
-
- /**
- * Write data to the stream.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the write request.
- * The callback can be used to free data after the request completes.
- *
- * The callback will be called when the data has been written (even if an
- * error occurred). Errors will be reported to the stream error handler.
- *
- * @param bufs The buffers to be written to the stream.
- * @param callback Callback function to call when the write completes
- */
- void Write(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback);
-
- /**
- * Write data to the stream.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the write request.
- * The callback can be used to free data after the request completes.
- *
- * The callback will be called when the data has been written (even if an
- * error occurred). Errors will be reported to the stream error handler.
- *
- * @param bufs The buffers to be written to the stream.
- * @param callback Callback function to call when the write completes
- */
- void Write(std::initializer_list<Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Write({bufs.begin(), bufs.end()}, std::move(callback));
- }
-
- /**
- * Queue a write request if it can be completed immediately.
- *
- * Same as `Write()`, but won’t queue a write request if it can’t be
- * completed immediately.
- * An error signal will be emitted in case of errors.
- *
- * @param bufs The buffers to be written to the stream.
- * @return Number of bytes written.
- */
- int TryWrite(span<const Buffer> bufs);
-
- /**
- * Queue a write request if it can be completed immediately.
- *
- * Same as `Write()`, but won’t queue a write request if it can’t be
- * completed immediately.
- * An error signal will be emitted in case of errors.
- *
- * @param bufs The buffers to be written to the stream.
- * @return Number of bytes written.
- */
- int TryWrite(std::initializer_list<Buffer> bufs) {
- return TryWrite({bufs.begin(), bufs.end()});
- }
-
- /**
- * Check if the stream is readable.
- * @return True if the stream is readable, false otherwise.
- */
- bool IsReadable() const noexcept {
- return uv_is_readable(GetRawStream()) == 1;
- }
-
- /**
- * @brief Checks if the stream is writable.
- * @return True if the stream is writable, false otherwise.
- */
- bool IsWritable() const noexcept {
- return uv_is_writable(GetRawStream()) == 1;
- }
-
- /**
- * Enable or disable blocking mode for a stream.
- *
- * When blocking mode is enabled all writes complete synchronously. The
- * interface remains unchanged otherwise, e.g. completion or failure of the
- * operation will still be reported through events which are emitted
- * asynchronously.
- *
- * @param enable True to enable blocking mode, false otherwise.
- * @return True in case of success, false otherwise.
- */
- bool SetBlocking(bool enable) noexcept {
- return uv_stream_set_blocking(GetRawStream(), enable) == 0;
- }
-
- /**
- * Gets the amount of queued bytes waiting to be sent.
- * @return Amount of queued bytes waiting to be sent.
- */
- size_t GetWriteQueueSize() const noexcept {
- return GetRawStream()->write_queue_size;
- }
-
- /**
- * Get the underlying stream data structure.
- *
- * @return The underlying stream data structure.
- */
- uv_stream_t* GetRawStream() const noexcept {
- return reinterpret_cast<uv_stream_t*>(GetRawHandle());
- }
-
- /**
- * Signal generated when data was read on a stream.
- */
- sig::Signal<Buffer&, size_t> data;
-
- /**
- * Signal generated when no more read data is available.
- */
- sig::Signal<> end;
-
- protected:
- explicit Stream(uv_stream_t* uv_stream)
- : Handle{reinterpret_cast<uv_handle_t*>(uv_stream)} {}
-};
-
-template <typename T, typename U>
-class StreamImpl : public Stream {
- public:
- std::shared_ptr<T> shared_from_this() {
- return std::static_pointer_cast<T>(Handle::shared_from_this());
- }
-
- std::shared_ptr<const T> shared_from_this() const {
- return std::static_pointer_cast<const T>(Handle::shared_from_this());
- }
-
- /**
- * Get the underlying handle data structure.
- *
- * @return The underlying handle data structure.
- */
- U* GetRaw() const noexcept {
- return reinterpret_cast<U*>(this->GetRawHandle());
- }
-
- protected:
- StreamImpl() : Stream{static_cast<uv_stream_t*>(std::malloc(sizeof(U)))} {}
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_STREAM_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Tcp.h b/wpiutil/src/main/native/include/wpi/uv/Tcp.h
deleted file mode 100644
index c712f0b..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Tcp.h
+++ /dev/null
@@ -1,363 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_TCP_H_
-#define WPIUTIL_WPI_UV_TCP_H_
-
-#include <uv.h>
-
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "wpi/uv/NetworkStream.h"
-
-namespace wpi::uv {
-
-class Loop;
-class TcpConnectReq;
-
-/**
- * TCP handle.
- * TCP handles are used to represent both TCP streams and servers.
- */
-class Tcp final : public NetworkStreamImpl<Tcp, uv_tcp_t> {
- struct private_init {};
-
- public:
- using Time = std::chrono::duration<uint64_t, std::milli>;
-
- explicit Tcp(const private_init&) {}
- ~Tcp() noexcept override = default;
-
- /**
- * Create a TCP handle.
- *
- * @param loop Loop object where this handle runs.
- * @param flags Flags
- */
- static std::shared_ptr<Tcp> Create(Loop& loop,
- unsigned int flags = AF_UNSPEC);
-
- /**
- * Create a TCP handle.
- *
- * @param loop Loop object where this handle runs.
- * @param flags Flags
- */
- static std::shared_ptr<Tcp> Create(const std::shared_ptr<Loop>& loop,
- unsigned int flags = AF_UNSPEC) {
- return Create(*loop, flags);
- }
-
- /**
- * Reuse this handle. This closes the handle, and after the close completes,
- * reinitializes it (identically to Create) and calls the provided callback.
- * Unlike Close(), it does NOT emit the closed signal, however, IsClosing()
- * will return true until the callback is called. This does nothing if
- * IsClosing() is true (e.g. if Close() was called).
- *
- * @param flags Flags
- * @param callback Callback
- */
- void Reuse(std::function<void()> callback, unsigned int flags = AF_UNSPEC);
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a ListenEvent event to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @return The stream handle for the accepted connection, or nullptr on error.
- */
- std::shared_ptr<Tcp> Accept();
-
- /**
- * Accept incoming connection.
- *
- * This call is used in conjunction with `Listen()` to accept incoming
- * connections. Call this function after receiving a connection signal to
- * accept the connection.
- * An error signal will be emitted in case of errors.
- *
- * When the connection signal is emitted it is guaranteed that this
- * function will complete successfully the first time. If you attempt to use
- * it more than once, it may fail.
- * It is suggested to only call this function once per connection signal.
- *
- * @param client Client stream object.
- * @return False on error.
- */
- bool Accept(const std::shared_ptr<Tcp>& client) {
- return NetworkStream::Accept(client);
- }
-
- /**
- * Open an existing file descriptor or SOCKET as a TCP handle.
- *
- * @note The passed file descriptor or SOCKET is not checked for its type, but
- * it's required that it represents a valid stream socket.
- *
- * @param sock A valid socket handle (either a file descriptor or a SOCKET).
- */
- void Open(uv_os_sock_t sock) { Invoke(&uv_tcp_open, GetRaw(), sock); }
-
- /**
- * Enable no delay operation (turns off Nagle's algorithm).
- * @param enable True to enable it, false otherwise.
- * @return True in case of success, false otherwise.
- */
- bool SetNoDelay(bool enable) { return uv_tcp_nodelay(GetRaw(), enable) == 0; }
-
- /**
- * Enable/Disable TCP keep-alive.
- * @param enable True to enable it, false otherwise.
- * @param time Initial delay in seconds (use
- * `std::chrono::duration<unsigned int>`).
- * @return True in case of success, false otherwise.
- */
- bool SetKeepAlive(bool enable, Time time = Time{0}) {
- return uv_tcp_keepalive(GetRaw(), enable,
- static_cast<unsigned>(time.count())) == 0;
- }
-
- /**
- * Enable/Disable simultaneous asynchronous accept requests.
- *
- * Enable/Disable simultaneous asynchronous accept requests that are
- * queued by the operating system when listening for new TCP
- * connections.
- * This setting is used to tune a TCP server for the desired performance.
- * Having simultaneous accepts can significantly improve the rate of
- * accepting connections (which is why it is enabled by default) but may
- * lead to uneven load distribution in multi-process setups.
- *
- * @param enable True to enable it, false otherwise.
- * @return True in case of success, false otherwise.
- */
- bool SetSimultaneousAccepts(bool enable) {
- return uv_tcp_simultaneous_accepts(GetRaw(), enable) == 0;
- }
-
- /**
- * Bind the handle to an IPv4 or IPv6 address and port.
- *
- * A successful call to this function does not guarantee that the call to
- * `Listen()` or `Connect()` will work properly.
- * An error signal can be emitted because of either this function or the
- * ones mentioned above.
- *
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional additional flags.
- */
- void Bind(const sockaddr& addr, unsigned int flags = 0) {
- Invoke(&uv_tcp_bind, GetRaw(), &addr, flags);
- }
-
- void Bind(const sockaddr_in& addr, unsigned int flags = 0) {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-
- void Bind(const sockaddr_in6& addr, unsigned int flags = 0) {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-
- /**
- * Bind the handle to an IPv4 address and port.
- *
- * A successful call to this function does not guarantee that the call to
- * `Listen()` or `Connect()` will work properly.
- * An error signal can be emitted because of either this function or the
- * ones mentioned above.
- *
- * Available flags are:
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- * @param flags Optional additional flags.
- */
- void Bind(std::string_view ip, unsigned int port, unsigned int flags = 0);
-
- /**
- * Bind the handle to an IPv6 address and port.
- *
- * A successful call to this function does not guarantee that the call to
- * `Listen()` or `Connect()` will work properly.
- * An error signal can be emitted because of either this function or the
- * ones mentioned above.
- *
- * Available flags are:
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- * @param flags Optional additional flags.
- */
- void Bind6(std::string_view ip, unsigned int port, unsigned int flags = 0);
-
- /**
- * Get the current address to which the handle is bound.
- * @return The address (will be zeroed if an error occurred).
- */
- sockaddr_storage GetSock();
-
- /**
- * Get the address of the peer connected to the handle.
- * @return The address (will be zeroed if an error occurred).
- */
- sockaddr_storage GetPeer();
-
- /**
- * Establish an IPv4 or IPv6 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The connected signal is emitted on the request when the connection has been
- * established.
- * The error signal is emitted on the request in case of errors during the
- * connection.
- *
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param req connection request
- */
- void Connect(const sockaddr& addr, const std::shared_ptr<TcpConnectReq>& req);
-
- void Connect(const sockaddr_in& addr,
- const std::shared_ptr<TcpConnectReq>& req) {
- Connect(reinterpret_cast<const sockaddr&>(addr), req);
- }
-
- void Connect(const sockaddr_in6& addr,
- const std::shared_ptr<TcpConnectReq>& req) {
- Connect(reinterpret_cast<const sockaddr&>(addr), req);
- }
-
- /**
- * Establish an IPv4 or IPv6 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The callback is called when the connection has been established. Errors
- * are reported to the stream error handler.
- *
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param callback Callback function to call when connection established
- */
- void Connect(const sockaddr& addr, std::function<void()> callback);
-
- void Connect(const sockaddr_in& addr, std::function<void()> callback) {
- Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
- }
-
- void Connect(const sockaddr_in6& addr, std::function<void()> callback) {
- Connect(reinterpret_cast<const sockaddr&>(addr), std::move(callback));
- }
-
- /**
- * Establish an IPv4 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The connected signal is emitted on the request when the connection has been
- * established.
- * The error signal is emitted on the request in case of errors during the
- * connection.
- *
- * @param ip The address to which to connect to.
- * @param port The port to which to connect to.
- * @param req connection request
- */
- void Connect(std::string_view ip, unsigned int port,
- const std::shared_ptr<TcpConnectReq>& req);
-
- /**
- * Establish an IPv4 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The callback is called when the connection has been established. Errors
- * are reported to the stream error handler.
- *
- * @param ip The address to which to connect to.
- * @param port The port to which to connect to.
- * @param callback Callback function to call when connection established
- */
- void Connect(std::string_view ip, unsigned int port,
- std::function<void()> callback);
-
- /**
- * Establish an IPv6 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The connected signal is emitted on the request when the connection has been
- * established.
- * The error signal is emitted on the request in case of errors during the
- * connection.
- *
- * @param ip The address to which to connect to.
- * @param port The port to which to connect to.
- * @param req connection request
- */
- void Connect6(std::string_view ip, unsigned int port,
- const std::shared_ptr<TcpConnectReq>& req);
-
- /**
- * Establish an IPv6 TCP connection.
- *
- * On Windows if the addr is initialized to point to an unspecified address
- * (`0.0.0.0` or `::`) it will be changed to point to localhost. This is
- * done to match the behavior of Linux systems.
- *
- * The callback is called when the connection has been established. Errors
- * are reported to the stream error handler.
- *
- * @param ip The address to which to connect to.
- * @param port The port to which to connect to.
- * @param callback Callback function to call when connection established
- */
- void Connect6(std::string_view ip, unsigned int port,
- std::function<void()> callback);
-
- private:
- Tcp* DoAccept() override;
-
- struct ReuseData {
- std::function<void()> callback;
- unsigned int flags;
- };
- std::unique_ptr<ReuseData> m_reuseData;
-};
-
-/**
- * TCP connection request.
- */
-class TcpConnectReq : public ConnectReq {
- public:
- Tcp& GetStream() const {
- return *static_cast<Tcp*>(&ConnectReq::GetStream());
- }
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_TCP_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Timer.h b/wpiutil/src/main/native/include/wpi/uv/Timer.h
deleted file mode 100644
index 00363a5..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Timer.h
+++ /dev/null
@@ -1,135 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_TIMER_H_
-#define WPIUTIL_WPI_UV_TIMER_H_
-
-#include <uv.h>
-
-#include <chrono>
-#include <functional>
-#include <memory>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Handle.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Timer handle.
- * Timer handles are used to schedule signals to be called in the future.
- */
-class Timer final : public HandleImpl<Timer, uv_timer_t> {
- struct private_init {};
-
- public:
- using Time = std::chrono::duration<uint64_t, std::milli>;
-
- explicit Timer(const private_init&) {}
- ~Timer() noexcept override = default;
-
- /**
- * Create a timer handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Timer> Create(Loop& loop);
-
- /**
- * Create a timer handle.
- *
- * @param loop Loop object where this handle runs.
- */
- static std::shared_ptr<Timer> Create(const std::shared_ptr<Loop>& loop) {
- return Create(*loop);
- }
-
- /**
- * Create a timer that calls a functor after a given time interval.
- *
- * @param loop Loop object where the timer should run.
- * @param timeout Time interval
- * @param func Functor
- */
- static void SingleShot(Loop& loop, Time timeout, std::function<void()> func);
-
- /**
- * Create a timer that calls a functor after a given time interval.
- *
- * @param loop Loop object where the timer should run.
- * @param timeout Time interval
- * @param func Functor
- */
- static void SingleShot(const std::shared_ptr<Loop>& loop, Time timeout,
- std::function<void()> func) {
- return SingleShot(*loop, timeout, std::move(func));
- }
-
- /**
- * Start the timer.
- *
- * If timeout is zero, an event is emitted on the next event loop
- * iteration. If repeat is non-zero, an event is emitted first
- * after timeout milliseconds and then repeatedly after repeat milliseconds.
- *
- * @param timeout Milliseconds before to emit an event (use
- * `std::chrono::duration<uint64_t, std::milli>`).
- * @param repeat Milliseconds between successive events (use
- * `std::chrono::duration<uint64_t, std::milli>`).
- */
- void Start(Time timeout, Time repeat = Time{0});
-
- /**
- * Stop the timer.
- */
- void Stop() { Invoke(&uv_timer_stop, GetRaw()); }
-
- /**
- * Stop the timer and restart it if it was repeating.
- *
- * Stop the timer, and if it is repeating restart it using the repeat value
- * as the timeout.
- * If the timer has never been started before it emits sigError.
- */
- void Again() { Invoke(&uv_timer_again, GetRaw()); }
-
- /**
- * Set the repeat interval value.
- *
- * The timer will be scheduled to run on the given interval and will follow
- * normal timer semantics in the case of a time-slice overrun.
- * For example, if a 50ms repeating timer first runs for 17ms, it will be
- * scheduled to run again 33ms later. If other tasks consume more than the
- * 33ms following the first timer event, then another event will be emitted
- * as soon as possible.
- *
- * If the repeat value is set from a listener bound to an event, it does
- * not immediately take effect. If the timer was non-repeating before, it
- * will have been stopped. If it was repeating, then the old repeat value
- * will have been used to schedule the next timeout.
- *
- * @param repeat Repeat interval in milliseconds (use
- * `std::chrono::duration<uint64_t, std::milli>`).
- */
- void SetRepeat(Time repeat) { uv_timer_set_repeat(GetRaw(), repeat.count()); }
-
- /**
- * Get the timer repeat value.
- * @return Timer repeat value in milliseconds (as a
- * `std::chrono::duration<uint64_t, std::milli>`).
- */
- Time GetRepeat() const { return Time{uv_timer_get_repeat(GetRaw())}; }
-
- /**
- * Signal generated when the timeout event occurs.
- */
- sig::Signal<> timeout;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_TIMER_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Tty.h b/wpiutil/src/main/native/include/wpi/uv/Tty.h
deleted file mode 100644
index bb0a6db..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Tty.h
+++ /dev/null
@@ -1,85 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_TTY_H_
-#define WPIUTIL_WPI_UV_TTY_H_
-
-#include <uv.h>
-
-#include <memory>
-#include <utility>
-
-#include "wpi/uv/Stream.h"
-
-namespace wpi::uv {
-
-class Loop;
-class Tty;
-
-/**
- * TTY handle.
- * TTY handles represent a stream for the console.
- */
-class Tty final : public StreamImpl<Tty, uv_tty_t> {
- struct private_init {};
-
- public:
- explicit Tty(const private_init&) {}
- ~Tty() noexcept override = default;
-
- /**
- * Create a TTY handle.
- *
- * @param loop Loop object where this handle runs.
- * @param fd File descriptor, usually 0=stdin, 1=stdout, 2=stderr
- * @param readable Specifies if you plan on calling StartRead(). stdin is
- * readable, stdout is not.
- */
- static std::shared_ptr<Tty> Create(Loop& loop, uv_file fd, bool readable);
-
- /**
- * Create a TTY handle.
- *
- * @param loop Loop object where this handle runs.
- * @param fd File descriptor, usually 0=stdin, 1=stdout, 2=stderr
- * @param readable Specifies if you plan on calling StartRead(). stdin is
- * readable, stdout is not.
- */
- static std::shared_ptr<Tty> Create(const std::shared_ptr<Loop>& loop,
- uv_file fd, bool readable) {
- return Create(*loop, fd, readable);
- }
-
- /**
- * Set the TTY using the specified terminal mode.
- *
- * @param mode terminal mode
- */
- void SetMode(uv_tty_mode_t mode) {
- int err = uv_tty_set_mode(GetRaw(), mode);
- if (err < 0) {
- ReportError(err);
- }
- }
-
- /**
- * Reset TTY settings to default values for the next process to take over.
- * Typically called when the program exits.
- */
- void ResetMode() { Invoke(&uv_tty_reset_mode); }
-
- /**
- * Gets the current window size.
- * @return Window size (pair of width and height).
- */
- std::pair<int, int> GetWindowSize() {
- int width = 0, height = 0;
- Invoke(&uv_tty_get_winsize, GetRaw(), &width, &height);
- return std::make_pair(width, height);
- }
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_TTY_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Udp.h b/wpiutil/src/main/native/include/wpi/uv/Udp.h
deleted file mode 100644
index 71fab13..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Udp.h
+++ /dev/null
@@ -1,378 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_UDP_H_
-#define WPIUTIL_WPI_UV_UDP_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <string_view>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/span.h"
-#include "wpi/uv/Handle.h"
-#include "wpi/uv/Request.h"
-
-namespace wpi::uv {
-
-class Loop;
-class Udp;
-
-/**
- * UDP send request.
- */
-class UdpSendReq : public RequestImpl<UdpSendReq, uv_udp_send_t> {
- public:
- UdpSendReq();
-
- Udp& GetUdp() const { return *static_cast<Udp*>(GetRaw()->handle->data); }
-
- /**
- * Send completed signal. This is called even if an error occurred.
- * @param err error value
- */
- sig::Signal<Error> complete;
-};
-
-/**
- * UDP handle.
- * UDP handles encapsulate UDP communication for both clients and servers.
- */
-class Udp final : public HandleImpl<Udp, uv_udp_t> {
- struct private_init {};
-
- public:
- explicit Udp(const private_init&) {}
- ~Udp() noexcept override = default;
-
- /**
- * Create a UDP handle.
- *
- * @param loop Loop object where this handle runs.
- * @param flags Flags
- */
- static std::shared_ptr<Udp> Create(Loop& loop,
- unsigned int flags = AF_UNSPEC);
-
- /**
- * Create a UDP handle.
- *
- * @param loop Loop object where this handle runs.
- * @param flags Flags
- */
- static std::shared_ptr<Udp> Create(const std::shared_ptr<Loop>& loop,
- unsigned int flags = AF_UNSPEC) {
- return Create(*loop, flags);
- }
-
- /**
- * Open an existing file descriptor or SOCKET as a UDP handle.
- *
- * @param sock A valid socket handle (either a file descriptor or a SOCKET).
- */
- void Open(uv_os_sock_t sock) { Invoke(&uv_udp_open, GetRaw(), sock); }
-
- /**
- * Bind the handle to an IPv4 or IPv6 address and port.
- *
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- * @param flags Optional additional flags.
- */
- void Bind(const sockaddr& addr, unsigned int flags = 0) {
- Invoke(&uv_udp_bind, GetRaw(), &addr, flags);
- }
-
- void Bind(const sockaddr_in& addr, unsigned int flags = 0) {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-
- void Bind(const sockaddr_in6& addr, unsigned int flags = 0) {
- Bind(reinterpret_cast<const sockaddr&>(addr), flags);
- }
-
- /**
- * Bind the handle to an IPv4 address and port.
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- * @param flags Optional additional flags.
- */
- void Bind(std::string_view ip, unsigned int port, unsigned int flags = 0);
-
- /**
- * Bind the handle to an IPv6 address and port.
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- * @param flags Optional additional flags.
- */
- void Bind6(std::string_view ip, unsigned int port, unsigned int flags = 0);
-
- /**
- * Associate the handle to a remote address and port, so every message sent
- * by this handle is automatically sent to that destination.
- *
- * @param addr Initialized `sockaddr_in` or `sockaddr_in6` data structure.
- */
- void Connect(const sockaddr& addr) {
- Invoke(&uv_udp_connect, GetRaw(), &addr);
- }
-
- void Connect(const sockaddr_in& addr) {
- Connect(reinterpret_cast<const sockaddr&>(addr));
- }
-
- void Connect(const sockaddr_in6& addr) {
- Connect(reinterpret_cast<const sockaddr&>(addr));
- }
-
- /**
- * Associate the handle to an IPv4 address and port, so every message sent
- * by this handle is automatically sent to that destination.
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- */
- void Connect(std::string_view ip, unsigned int port);
-
- /**
- * Associate the handle to an IPv6 address and port, so every message sent
- * by this handle is automatically sent to that destination.
- *
- * @param ip The address to which to bind.
- * @param port The port to which to bind.
- * @param flags Optional additional flags.
- */
- void Connect6(std::string_view ip, unsigned int port);
-
- /**
- * Get the remote IP and port on connected UDP handles.
- * @return The address (will be zeroed if an error occurred).
- */
- sockaddr_storage GetPeer();
-
- /**
- * Get the current address to which the handle is bound.
- * @return The address (will be zeroed if an error occurred).
- */
- sockaddr_storage GetSock();
-
- /**
- * Set membership for a multicast address.
- *
- * @param multicastAddr Multicast address to set membership for
- * @param interfaceAddr Interface address
- * @param membership Should be UV_JOIN_GROUP or UV_LEAVE_GROUP
- */
- void SetMembership(std::string_view multicastAddr,
- std::string_view interfaceAddr, uv_membership membership);
-
- /**
- * Set IP multicast loop flag. Makes multicast packets loop back to local
- * sockets.
- *
- * @param enabled True for enabled, false for disabled
- */
- void SetMulticastLoop(bool enabled) {
- Invoke(&uv_udp_set_multicast_loop, GetRaw(), enabled ? 1 : 0);
- }
-
- /**
- * Set the multicast TTL.
- *
- * @param ttl Time to live (1-255)
- */
- void SetMulticastTtl(int ttl) {
- Invoke(&uv_udp_set_multicast_ttl, GetRaw(), ttl);
- }
-
- /**
- * Set the multicast interface to send or receive data on.
- *
- * @param interfaceAddr Interface address
- */
- void SetMulticastInterface(std::string_view interfaceAddr);
-
- /**
- * Set broadcast on or off.
- *
- * @param enabled True for enabled, false for disabled
- */
- void SetBroadcast(bool enabled) {
- Invoke(&uv_udp_set_broadcast, GetRaw(), enabled ? 1 : 0);
- }
-
- /**
- * Set the time to live (TTL).
- *
- * @param ttl Time to live (1-255)
- */
- void SetTtl(int ttl) { Invoke(&uv_udp_set_ttl, GetRaw(), ttl); }
-
- /**
- * Send data over the UDP socket. If the socket has not previously been bound
- * with Bind() it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address)
- * and a random port number.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the send request.
- * The callback can be used to free data after the request completes.
- *
- * HandleSendComplete() will be called on the request object when the data
- * has been written. HandleSendComplete() is called even if an error occurs.
- * HandleError() will be called on the request object in case of errors.
- *
- * @param addr sockaddr_in or sockaddr_in6 with the address and port of the
- * remote peer.
- * @param bufs The buffers to be written to the stream.
- * @param req write request
- */
- void Send(const sockaddr& addr, span<const Buffer> bufs,
- const std::shared_ptr<UdpSendReq>& req);
-
- void Send(const sockaddr_in& addr, span<const Buffer> bufs,
- const std::shared_ptr<UdpSendReq>& req) {
- Send(reinterpret_cast<const sockaddr&>(addr), bufs, req);
- }
-
- void Send(const sockaddr_in6& addr, span<const Buffer> bufs,
- const std::shared_ptr<UdpSendReq>& req) {
- Send(reinterpret_cast<const sockaddr&>(addr), bufs, req);
- }
-
- /**
- * Variant of Send() for connected sockets. Cannot be used with
- * connectionless sockets.
- *
- * @param bufs The buffers to be written to the stream.
- * @param req write request
- */
- void Send(span<const Buffer> bufs, const std::shared_ptr<UdpSendReq>& req);
-
- /**
- * Send data over the UDP socket. If the socket has not previously been bound
- * with Bind() it will be bound to 0.0.0.0 (the "all interfaces" IPv4 address)
- * and a random port number.
- *
- * Data are written in order. The lifetime of the data pointers passed in
- * the `bufs` parameter must exceed the lifetime of the send request.
- * The callback can be used to free data after the request completes.
- *
- * The callback will be called when the data has been sent. Errors will
- * be reported via the error signal.
- *
- * @param addr sockaddr_in or sockaddr_in6 with the address and port of the
- * remote peer.
- * @param bufs The buffers to be sent.
- * @param callback Callback function to call when the data has been sent.
- */
- void Send(const sockaddr& addr, span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback);
-
- void Send(const sockaddr_in& addr, span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Send(reinterpret_cast<const sockaddr&>(addr), bufs, std::move(callback));
- }
-
- void Send(const sockaddr_in6& addr, span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback) {
- Send(reinterpret_cast<const sockaddr&>(addr), bufs, std::move(callback));
- }
-
- /**
- * Variant of Send() for connected sockets. Cannot be used with
- * connectionless sockets.
- *
- * @param bufs The buffers to be written to the stream.
- * @param callback Callback function to call when the data has been sent.
- */
- void Send(span<const Buffer> bufs,
- std::function<void(span<Buffer>, Error)> callback);
-
- /**
- * Same as Send(), but won't queue a send request if it can't be completed
- * immediately.
- *
- * @param addr sockaddr_in or sockaddr_in6 with the address and port of the
- * remote peer.
- * @param bufs The buffers to be send.
- * @return Number of bytes sent.
- */
- int TrySend(const sockaddr& addr, span<const Buffer> bufs) {
- int val = uv_udp_try_send(GetRaw(), bufs.data(),
- static_cast<unsigned>(bufs.size()), &addr);
- if (val < 0) {
- this->ReportError(val);
- return 0;
- }
- return val;
- }
-
- int TrySend(const sockaddr_in& addr, span<const Buffer> bufs) {
- return TrySend(reinterpret_cast<const sockaddr&>(addr), bufs);
- }
-
- int TrySend(const sockaddr_in6& addr, span<const Buffer> bufs) {
- return TrySend(reinterpret_cast<const sockaddr&>(addr), bufs);
- }
-
- /**
- * Variant of TrySend() for connected sockets. Cannot be used with
- * connectionless sockets.
- *
- * @param bufs The buffers to be written to the stream.
- * @return Number of bytes sent.
- */
- int TrySend(span<const Buffer> bufs) {
- int val = uv_udp_try_send(GetRaw(), bufs.data(),
- static_cast<unsigned>(bufs.size()), nullptr);
- if (val < 0) {
- this->ReportError(val);
- return 0;
- }
- return val;
- }
-
- /**
- * Prepare for receiving data. If the socket has not previously been bound
- * with Bind() it is bound to 0.0.0.0 (the "all interfaces" IPv4 address) and
- * a random port number.
- *
- * A received signal will be emitted for each received data packet until
- * `StopRecv()` is called.
- */
- void StartRecv();
-
- /**
- * Stop listening for incoming datagrams.
- */
- void StopRecv() { Invoke(&uv_udp_recv_stop, GetRaw()); }
-
- /**
- * Gets the amount of queued bytes waiting to be sent.
- * @return Amount of queued bytes waiting to be sent.
- */
- size_t GetSendQueueSize() const noexcept { return GetRaw()->send_queue_size; }
-
- /**
- * Gets the amount of queued packets waiting to be sent.
- * @return Amount of queued packets waiting to be sent.
- */
- size_t GetSendQueueCount() const noexcept {
- return GetRaw()->send_queue_count;
- }
-
- /**
- * Signal generated for each incoming datagram. Parameters are the buffer,
- * the number of bytes received, the address of the sender, and flags.
- */
- sig::Signal<Buffer&, size_t, const sockaddr&, unsigned> received;
-};
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_UDP_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/Work.h b/wpiutil/src/main/native/include/wpi/uv/Work.h
deleted file mode 100644
index 5a3a5d2..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/Work.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_WORK_H_
-#define WPIUTIL_WPI_UV_WORK_H_
-
-#include <uv.h>
-
-#include <functional>
-#include <memory>
-#include <utility>
-
-#include "wpi/Signal.h"
-#include "wpi/uv/Request.h"
-
-namespace wpi::uv {
-
-class Loop;
-
-/**
- * Work request.
- * For use with `QueueWork()` function family.
- */
-class WorkReq : public RequestImpl<WorkReq, uv_work_t> {
- public:
- WorkReq();
-
- Loop& GetLoop() const { return *static_cast<Loop*>(GetRaw()->loop->data); }
-
- /**
- * Function(s) that will be run on the thread pool.
- */
- sig::Signal<> work;
-
- /**
- * Function(s) that will be run on the loop thread after the work on the
- * thread pool has been completed by the work callback.
- */
- sig::Signal<> afterWork;
-};
-
-/**
- * Initializes a work request which will run on the thread pool.
- *
- * @param loop Event loop
- * @param req request
- */
-void QueueWork(Loop& loop, const std::shared_ptr<WorkReq>& req);
-
-/**
- * Initializes a work request which will run on the thread pool.
- *
- * @param loop Event loop
- * @param req request
- */
-inline void QueueWork(const std::shared_ptr<Loop>& loop,
- const std::shared_ptr<WorkReq>& req) {
- QueueWork(*loop, req);
-}
-
-/**
- * Initializes a work request which will run on the thread pool. The work
- * callback will be run on a thread from the thread pool, and the afterWork
- * callback will be called on the loop thread after the work completes. Any
- * errors are forwarded to the loop.
- *
- * @param loop Event loop
- * @param work Work callback (called from separate thread)
- * @param afterWork After work callback (called on loop thread)
- */
-void QueueWork(Loop& loop, std::function<void()> work,
- std::function<void()> afterWork);
-
-/**
- * Initializes a work request which will run on the thread pool. The work
- * callback will be run on a thread from the thread pool, and the afterWork
- * callback will be called on the loop thread after the work completes. Any
- * errors are forwarded to the loop.
- *
- * @param loop Event loop
- * @param work Work callback (called from separate thread)
- * @param afterWork After work callback (called on loop thread)
- */
-inline void QueueWork(const std::shared_ptr<Loop>& loop,
- std::function<void()> work,
- std::function<void()> afterWork) {
- QueueWork(*loop, std::move(work), std::move(afterWork));
-}
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_WORK_H_
diff --git a/wpiutil/src/main/native/include/wpi/uv/util.h b/wpiutil/src/main/native/include/wpi/uv/util.h
deleted file mode 100644
index 01dec0b..0000000
--- a/wpiutil/src/main/native/include/wpi/uv/util.h
+++ /dev/null
@@ -1,147 +0,0 @@
-// 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.
-
-#ifndef WPIUTIL_WPI_UV_UTIL_H_
-#define WPIUTIL_WPI_UV_UTIL_H_
-
-#include <uv.h>
-
-#include <cstring>
-#include <string_view>
-
-namespace wpi::uv {
-
-/**
- * Convert a binary structure containing an IPv4 address to a string.
- * @param addr Binary structure
- * @param ip Output string (any type that has `assign(char*, char*)`)
- * @param port Output port number
- * @return Error (same as `uv_ip4_name()`).
- */
-template <typename T>
-int AddrToName(const sockaddr_in& addr, T* ip, unsigned int* port) {
- char name[128];
- int err = uv_ip4_name(&addr, name, 128);
- if (err == 0) {
- ip->assign(name, name + std::strlen(name));
- *port = ntohs(addr.sin_port);
- } else {
- ip->assign(name, name);
- }
- return err;
-}
-
-/**
- * Convert a binary structure containing an IPv6 address to a string.
- * @param addr Binary structure
- * @param ip Output string (any type that has `assign(char*, char*)`)
- * @param port Output port number
- * @return Error (same as `uv_ip6_name()`).
- */
-template <typename T>
-int AddrToName(const sockaddr_in6& addr, T* ip, unsigned int* port) {
- char name[128];
- int err = uv_ip6_name(&addr, name, 128);
- if (err == 0) {
- ip->assign(name, name + std::strlen(name));
- *port = ntohs(addr.sin6_port);
- } else {
- ip->assign(name, name);
- }
- return err;
-}
-
-/**
- * Convert a binary structure containing an IPv4 or IPv6 address to a string.
- * @param addr Binary structure
- * @param ip Output string (any type that has `assign(char*, char*)`)
- * @param port Output port number
- * @return Error (same as `uv_ip6_name()`).
- */
-template <typename T>
-int AddrToName(const sockaddr_storage& addr, T* ip, unsigned int* port) {
- if (addr.ss_family == AF_INET) {
- return AddrToName(reinterpret_cast<const sockaddr_in&>(addr), ip, port);
- }
- if (addr.ss_family == AF_INET6) {
- return AddrToName(reinterpret_cast<const sockaddr_in6&>(addr), ip, port);
- }
- char name[1];
- ip->assign(name, name);
- return -1;
-}
-
-/**
- * Convert a binary IPv4 address to a string.
- * @param addr Binary address
- * @param ip Output string (any type that has `assign(char*, char*)`)
- * @return Error (same as `uv_inet_ntop()`).
- */
-template <typename T>
-int AddrToName(const in_addr& addr, T* ip) {
- char name[128];
- int err = uv_inet_ntop(AF_INET, &addr, name, 128);
- if (err == 0) {
- ip->assign(name, name + std::strlen(name));
- } else {
- ip->assign(name, name);
- }
- return err;
-}
-
-/**
- * Convert a binary IPv6 address to a string.
- * @param addr Binary address
- * @param ip Output string (any type that has `assign(char*, char*)`)
- * @return Error (same as `uv_inet_ntop()`).
- */
-template <typename T>
-int AddrToName(const in6_addr& addr, T* ip) {
- char name[128];
- int err = uv_inet_ntop(AF_INET6, &addr, name, 128);
- if (err == 0) {
- ip->assign(name, name + std::strlen(name));
- } else {
- ip->assign(name, name);
- }
- return err;
-}
-
-/**
- * Convert a string containing an IPv4 address to a binary structure.
- * @param ip IPv4 address string
- * @param port Port number
- * @param addr Output binary structure
- * @return Error (same as `uv_ip4_addr()`).
- */
-int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in* addr);
-
-/**
- * Convert a string containing an IPv6 address to a binary structure.
- * @param ip IPv6 address string
- * @param port Port number
- * @param addr Output binary structure
- * @return Error (same as `uv_ip6_addr()`).
- */
-int NameToAddr(std::string_view ip, unsigned int port, sockaddr_in6* addr);
-
-/**
- * Convert a string containing an IPv4 address to binary format.
- * @param ip IPv4 address string
- * @param addr Output binary
- * @return Error (same as `uv_inet_pton()`).
- */
-int NameToAddr(std::string_view ip, in_addr* addr);
-
-/**
- * Convert a string containing an IPv6 address to binary format.
- * @param ip IPv6 address string
- * @param addr Output binary
- * @return Error (same as `uv_inet_pton()`).
- */
-int NameToAddr(std::string_view ip, in6_addr* addr);
-
-} // namespace wpi::uv
-
-#endif // WPIUTIL_WPI_UV_UTIL_H_
diff --git a/wpiutil/src/main/native/libuv/include/uv.h b/wpiutil/src/main/native/libuv/include/uv.h
deleted file mode 100644
index ccf62c8..0000000
--- a/wpiutil/src/main/native/libuv/include/uv.h
+++ /dev/null
@@ -1,1683 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-/* See https://github.com/libuv/libuv#documentation for documentation. */
-
-#ifndef UV_H
-#define UV_H
-
-#ifdef _WIN32
- /* Windows - set up dll import/export decorators. */
-# if defined(BUILDING_UV_SHARED)
- /* Building shared library. */
-# define UV_EXTERN __declspec(dllexport)
-# elif defined(USING_UV_SHARED)
- /* Using shared library. */
-# define UV_EXTERN __declspec(dllimport)
-# else
- /* Building static library. */
-# define UV_EXTERN /* nothing */
-# endif
-#elif __GNUC__ >= 4
-# define UV_EXTERN __attribute__((visibility("default")))
-#else
-# define UV_EXTERN /* nothing */
-#endif
-
-#include "uv/errno.h"
-#include "uv/version.h"
-#include <stddef.h>
-#include <stdio.h>
-
-#include <stdint.h>
-
-#if defined(_WIN32)
-# include "uv/win.h"
-#else
-# include "uv/unix.h"
-#endif
-
-/* Expand this list if necessary. */
-#define UV_ERRNO_MAP(XX) \
- XX(E2BIG, "argument list too long") \
- XX(EACCES, "permission denied") \
- XX(EADDRINUSE, "address already in use") \
- XX(EADDRNOTAVAIL, "address not available") \
- XX(EAFNOSUPPORT, "address family not supported") \
- XX(EAGAIN, "resource temporarily unavailable") \
- XX(EAI_ADDRFAMILY, "address family not supported") \
- XX(EAI_AGAIN, "temporary failure") \
- XX(EAI_BADFLAGS, "bad ai_flags value") \
- XX(EAI_BADHINTS, "invalid value for hints") \
- XX(EAI_CANCELED, "request canceled") \
- XX(EAI_FAIL, "permanent failure") \
- XX(EAI_FAMILY, "ai_family not supported") \
- XX(EAI_MEMORY, "out of memory") \
- XX(EAI_NODATA, "no address") \
- XX(EAI_NONAME, "unknown node or service") \
- XX(EAI_OVERFLOW, "argument buffer overflow") \
- XX(EAI_PROTOCOL, "resolved protocol is unknown") \
- XX(EAI_SERVICE, "service not available for socket type") \
- XX(EAI_SOCKTYPE, "socket type not supported") \
- XX(EALREADY, "connection already in progress") \
- XX(EBADF, "bad file descriptor") \
- XX(EBUSY, "resource busy or locked") \
- XX(ECANCELED, "operation canceled") \
- XX(ECHARSET, "invalid Unicode character") \
- XX(ECONNABORTED, "software caused connection abort") \
- XX(ECONNREFUSED, "connection refused") \
- XX(ECONNRESET, "connection reset by peer") \
- XX(EDESTADDRREQ, "destination address required") \
- XX(EEXIST, "file already exists") \
- XX(EFAULT, "bad address in system call argument") \
- XX(EFBIG, "file too large") \
- XX(EHOSTUNREACH, "host is unreachable") \
- XX(EINTR, "interrupted system call") \
- XX(EINVAL, "invalid argument") \
- XX(EIO, "i/o error") \
- XX(EISCONN, "socket is already connected") \
- XX(EISDIR, "illegal operation on a directory") \
- XX(ELOOP, "too many symbolic links encountered") \
- XX(EMFILE, "too many open files") \
- XX(EMSGSIZE, "message too long") \
- XX(ENAMETOOLONG, "name too long") \
- XX(ENETDOWN, "network is down") \
- XX(ENETUNREACH, "network is unreachable") \
- XX(ENFILE, "file table overflow") \
- XX(ENOBUFS, "no buffer space available") \
- XX(ENODEV, "no such device") \
- XX(ENOENT, "no such file or directory") \
- XX(ENOMEM, "not enough memory") \
- XX(ENONET, "machine is not on the network") \
- XX(ENOPROTOOPT, "protocol not available") \
- XX(ENOSPC, "no space left on device") \
- XX(ENOSYS, "function not implemented") \
- XX(ENOTCONN, "socket is not connected") \
- XX(ENOTDIR, "not a directory") \
- XX(ENOTEMPTY, "directory not empty") \
- XX(ENOTSOCK, "socket operation on non-socket") \
- XX(ENOTSUP, "operation not supported on socket") \
- XX(EPERM, "operation not permitted") \
- XX(EPIPE, "broken pipe") \
- XX(EPROTO, "protocol error") \
- XX(EPROTONOSUPPORT, "protocol not supported") \
- XX(EPROTOTYPE, "protocol wrong type for socket") \
- XX(ERANGE, "result too large") \
- XX(EROFS, "read-only file system") \
- XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
- XX(ESPIPE, "invalid seek") \
- XX(ESRCH, "no such process") \
- XX(ETIMEDOUT, "connection timed out") \
- XX(ETXTBSY, "text file is busy") \
- XX(EXDEV, "cross-device link not permitted") \
- XX(UNKNOWN, "unknown error") \
- XX(EOF, "end of file") \
- XX(ENXIO, "no such device or address") \
- XX(EMLINK, "too many links") \
- XX(EHOSTDOWN, "host is down") \
- XX(EREMOTEIO, "remote I/O error") \
- XX(ENOTTY, "inappropriate ioctl for device") \
- XX(EFTYPE, "inappropriate file type or format") \
-
-#define UV_HANDLE_TYPE_MAP(XX) \
- XX(ASYNC, async) \
- XX(CHECK, check) \
- XX(FS_EVENT, fs_event) \
- XX(FS_POLL, fs_poll) \
- XX(HANDLE, handle) \
- XX(IDLE, idle) \
- XX(NAMED_PIPE, pipe) \
- XX(POLL, poll) \
- XX(PREPARE, prepare) \
- XX(PROCESS, process) \
- XX(STREAM, stream) \
- XX(TCP, tcp) \
- XX(TIMER, timer) \
- XX(TTY, tty) \
- XX(UDP, udp) \
- XX(SIGNAL, signal) \
-
-#define UV_REQ_TYPE_MAP(XX) \
- XX(REQ, req) \
- XX(CONNECT, connect) \
- XX(WRITE, write) \
- XX(SHUTDOWN, shutdown) \
- XX(UDP_SEND, udp_send) \
- XX(FS, fs) \
- XX(WORK, work) \
- XX(GETADDRINFO, getaddrinfo) \
- XX(GETNAMEINFO, getnameinfo) \
-
-typedef enum {
-#define XX(code, _) UV_ ## code = UV__ ## code,
- UV_ERRNO_MAP(XX)
-#undef XX
- UV_ERRNO_MAX = UV__EOF - 1
-} uv_errno_t;
-
-typedef enum {
- UV_UNKNOWN_HANDLE = 0,
-#define XX(uc, lc) UV_##uc,
- UV_HANDLE_TYPE_MAP(XX)
-#undef XX
- UV_FILE,
- UV_HANDLE_TYPE_MAX
-} uv_handle_type;
-
-typedef enum {
- UV_UNKNOWN_REQ = 0,
-#define XX(uc, lc) UV_##uc,
- UV_REQ_TYPE_MAP(XX)
-#undef XX
- UV_REQ_TYPE_PRIVATE
- UV_REQ_TYPE_MAX
-} uv_req_type;
-
-
-/* Handle types. */
-typedef struct uv_loop_s uv_loop_t;
-typedef struct uv_handle_s uv_handle_t;
-typedef struct uv_dir_s uv_dir_t;
-typedef struct uv_stream_s uv_stream_t;
-typedef struct uv_tcp_s uv_tcp_t;
-typedef struct uv_udp_s uv_udp_t;
-typedef struct uv_pipe_s uv_pipe_t;
-typedef struct uv_tty_s uv_tty_t;
-typedef struct uv_poll_s uv_poll_t;
-typedef struct uv_timer_s uv_timer_t;
-typedef struct uv_prepare_s uv_prepare_t;
-typedef struct uv_check_s uv_check_t;
-typedef struct uv_idle_s uv_idle_t;
-typedef struct uv_async_s uv_async_t;
-typedef struct uv_process_s uv_process_t;
-typedef struct uv_fs_event_s uv_fs_event_t;
-typedef struct uv_fs_poll_s uv_fs_poll_t;
-typedef struct uv_signal_s uv_signal_t;
-
-/* Request types. */
-typedef struct uv_req_s uv_req_t;
-typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
-typedef struct uv_getnameinfo_s uv_getnameinfo_t;
-typedef struct uv_shutdown_s uv_shutdown_t;
-typedef struct uv_write_s uv_write_t;
-typedef struct uv_connect_s uv_connect_t;
-typedef struct uv_udp_send_s uv_udp_send_t;
-typedef struct uv_fs_s uv_fs_t;
-typedef struct uv_work_s uv_work_t;
-
-/* None of the above. */
-typedef struct uv_cpu_info_s uv_cpu_info_t;
-typedef struct uv_interface_address_s uv_interface_address_t;
-typedef struct uv_dirent_s uv_dirent_t;
-typedef struct uv_passwd_s uv_passwd_t;
-typedef struct uv_utsname_s uv_utsname_t;
-
-typedef enum {
- UV_LOOP_BLOCK_SIGNAL
-} uv_loop_option;
-
-typedef enum {
- UV_RUN_DEFAULT = 0,
- UV_RUN_ONCE,
- UV_RUN_NOWAIT
-} uv_run_mode;
-
-
-UV_EXTERN unsigned int uv_version(void);
-UV_EXTERN const char* uv_version_string(void);
-
-typedef void* (*uv_malloc_func)(size_t size);
-typedef void* (*uv_realloc_func)(void* ptr, size_t size);
-typedef void* (*uv_calloc_func)(size_t count, size_t size);
-typedef void (*uv_free_func)(void* ptr);
-
-UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
- uv_realloc_func realloc_func,
- uv_calloc_func calloc_func,
- uv_free_func free_func);
-
-UV_EXTERN uv_loop_t* uv_default_loop(void);
-UV_EXTERN int uv_loop_init(uv_loop_t* loop);
-UV_EXTERN int uv_loop_close(uv_loop_t* loop);
-/*
- * NOTE:
- * This function is DEPRECATED (to be removed after 0.12), users should
- * allocate the loop manually and use uv_loop_init instead.
- */
-UV_EXTERN uv_loop_t* uv_loop_new(void);
-/*
- * NOTE:
- * This function is DEPRECATED (to be removed after 0.12). Users should use
- * uv_loop_close and free the memory manually instead.
- */
-UV_EXTERN void uv_loop_delete(uv_loop_t*);
-UV_EXTERN size_t uv_loop_size(void);
-UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
-UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
-UV_EXTERN int uv_loop_fork(uv_loop_t* loop);
-
-UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
-UV_EXTERN void uv_stop(uv_loop_t*);
-
-UV_EXTERN void uv_ref(uv_handle_t*);
-UV_EXTERN void uv_unref(uv_handle_t*);
-UV_EXTERN int uv_has_ref(const uv_handle_t*);
-
-UV_EXTERN void uv_update_time(uv_loop_t*);
-UV_EXTERN uint64_t uv_now(const uv_loop_t*);
-
-UV_EXTERN int uv_backend_fd(const uv_loop_t*);
-UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
-
-typedef void (*uv_alloc_cb)(uv_handle_t* handle,
- size_t suggested_size,
- uv_buf_t* buf);
-typedef void (*uv_read_cb)(uv_stream_t* stream,
- ssize_t nread,
- const uv_buf_t* buf);
-typedef void (*uv_write_cb)(uv_write_t* req, int status);
-typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
-typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
-typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
-typedef void (*uv_close_cb)(uv_handle_t* handle);
-typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
-typedef void (*uv_timer_cb)(uv_timer_t* handle);
-typedef void (*uv_async_cb)(uv_async_t* handle);
-typedef void (*uv_prepare_cb)(uv_prepare_t* handle);
-typedef void (*uv_check_cb)(uv_check_t* handle);
-typedef void (*uv_idle_cb)(uv_idle_t* handle);
-typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal);
-typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
-typedef void (*uv_fs_cb)(uv_fs_t* req);
-typedef void (*uv_work_cb)(uv_work_t* req);
-typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
-typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
- int status,
- struct addrinfo* res);
-typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
- int status,
- const char* hostname,
- const char* service);
-
-typedef struct {
- long tv_sec;
- long tv_nsec;
-} uv_timespec_t;
-
-
-typedef struct {
- uint64_t st_dev;
- uint64_t st_mode;
- uint64_t st_nlink;
- uint64_t st_uid;
- uint64_t st_gid;
- uint64_t st_rdev;
- uint64_t st_ino;
- uint64_t st_size;
- uint64_t st_blksize;
- uint64_t st_blocks;
- uint64_t st_flags;
- uint64_t st_gen;
- uv_timespec_t st_atim;
- uv_timespec_t st_mtim;
- uv_timespec_t st_ctim;
- uv_timespec_t st_birthtim;
-} uv_stat_t;
-
-
-typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
- const char* filename,
- int events,
- int status);
-
-typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
- int status,
- const uv_stat_t* prev,
- const uv_stat_t* curr);
-
-typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
-
-
-typedef enum {
- UV_LEAVE_GROUP = 0,
- UV_JOIN_GROUP
-} uv_membership;
-
-
-UV_EXTERN int uv_translate_sys_error(int sys_errno);
-
-UV_EXTERN const char* uv_strerror(int err);
-UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen);
-
-UV_EXTERN const char* uv_err_name(int err);
-UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen);
-
-
-#define UV_REQ_FIELDS \
- /* public */ \
- void* data; \
- /* read-only */ \
- uv_req_type type; \
- /* private */ \
- void* reserved[6]; \
- UV_REQ_PRIVATE_FIELDS \
-
-/* Abstract base class of all requests. */
-struct uv_req_s {
- UV_REQ_FIELDS
-};
-
-
-/* Platform-specific request types. */
-UV_PRIVATE_REQ_TYPES
-
-
-UV_EXTERN int uv_shutdown(uv_shutdown_t* req,
- uv_stream_t* handle,
- uv_shutdown_cb cb);
-
-struct uv_shutdown_s {
- UV_REQ_FIELDS
- uv_stream_t* handle;
- uv_shutdown_cb cb;
- UV_SHUTDOWN_PRIVATE_FIELDS
-};
-
-
-#define UV_HANDLE_FIELDS \
- /* public */ \
- void* data; \
- /* read-only */ \
- uv_loop_t* loop; \
- uv_handle_type type; \
- /* private */ \
- uv_close_cb close_cb; \
- void* handle_queue[2]; \
- union { \
- int fd; \
- void* reserved[4]; \
- } u; \
- UV_HANDLE_PRIVATE_FIELDS \
-
-/* The abstract base class of all handles. */
-struct uv_handle_s {
- UV_HANDLE_FIELDS
-};
-
-UV_EXTERN size_t uv_handle_size(uv_handle_type type);
-UV_EXTERN uv_handle_type uv_handle_get_type(const uv_handle_t* handle);
-UV_EXTERN const char* uv_handle_type_name(uv_handle_type type);
-UV_EXTERN void* uv_handle_get_data(const uv_handle_t* handle);
-UV_EXTERN uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle);
-UV_EXTERN void uv_handle_set_data(uv_handle_t* handle, void* data);
-
-UV_EXTERN size_t uv_req_size(uv_req_type type);
-UV_EXTERN void* uv_req_get_data(const uv_req_t* req);
-UV_EXTERN void uv_req_set_data(uv_req_t* req, void* data);
-UV_EXTERN uv_req_type uv_req_get_type(const uv_req_t* req);
-UV_EXTERN const char* uv_req_type_name(uv_req_type type);
-
-UV_EXTERN int uv_is_active(const uv_handle_t* handle);
-
-UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
-
-/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */
-UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream);
-UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream);
-
-UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
-
-UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
-UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value);
-
-UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
-
-UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
-
-
-#define UV_STREAM_FIELDS \
- /* number of bytes queued for writing */ \
- size_t write_queue_size; \
- uv_alloc_cb alloc_cb; \
- uv_read_cb read_cb; \
- /* private */ \
- UV_STREAM_PRIVATE_FIELDS
-
-/*
- * uv_stream_t is a subclass of uv_handle_t.
- *
- * uv_stream is an abstract class.
- *
- * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t.
- */
-struct uv_stream_s {
- UV_HANDLE_FIELDS
- UV_STREAM_FIELDS
-};
-
-UV_EXTERN size_t uv_stream_get_write_queue_size(const uv_stream_t* stream);
-
-UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
-UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
-
-UV_EXTERN int uv_read_start(uv_stream_t*,
- uv_alloc_cb alloc_cb,
- uv_read_cb read_cb);
-UV_EXTERN int uv_read_stop(uv_stream_t*);
-
-UV_EXTERN int uv_write(uv_write_t* req,
- uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_write_cb cb);
-UV_EXTERN int uv_write2(uv_write_t* req,
- uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb);
-UV_EXTERN int uv_try_write(uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs);
-
-/* uv_write_t is a subclass of uv_req_t. */
-struct uv_write_s {
- UV_REQ_FIELDS
- uv_write_cb cb;
- uv_stream_t* send_handle; /* TODO: make private and unix-only in v2.x. */
- uv_stream_t* handle;
- UV_WRITE_PRIVATE_FIELDS
-};
-
-
-UV_EXTERN int uv_is_readable(const uv_stream_t* handle);
-UV_EXTERN int uv_is_writable(const uv_stream_t* handle);
-
-UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking);
-
-UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
-
-
-/*
- * uv_tcp_t is a subclass of uv_stream_t.
- *
- * Represents a TCP stream or TCP server.
- */
-struct uv_tcp_s {
- UV_HANDLE_FIELDS
- UV_STREAM_FIELDS
- UV_TCP_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
-UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
-UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
-UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
-UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
- int enable,
- unsigned int delay);
-UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
-
-enum uv_tcp_flags {
- /* Used with uv_tcp_bind, when an IPv6 address is used. */
- UV_TCP_IPV6ONLY = 1
-};
-
-UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int flags);
-UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen);
-UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen);
-UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- uv_connect_cb cb);
-
-/* uv_connect_t is a subclass of uv_req_t. */
-struct uv_connect_s {
- UV_REQ_FIELDS
- uv_connect_cb cb;
- uv_stream_t* handle;
- UV_CONNECT_PRIVATE_FIELDS
-};
-
-
-/*
- * UDP support.
- */
-
-enum uv_udp_flags {
- /* Disables dual stack mode. */
- UV_UDP_IPV6ONLY = 1,
- /*
- * Indicates message was truncated because read buffer was too small. The
- * remainder was discarded by the OS. Used in uv_udp_recv_cb.
- */
- UV_UDP_PARTIAL = 2,
- /*
- * Indicates if SO_REUSEADDR will be set when binding the handle.
- * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
- * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
- * multiple threads or processes can bind to the same address without error
- * (provided they all set the flag) but only the last one to bind will receive
- * any traffic, in effect "stealing" the port from the previous listener.
- */
- UV_UDP_REUSEADDR = 4
-};
-
-typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
-typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
- ssize_t nread,
- const uv_buf_t* buf,
- const struct sockaddr* addr,
- unsigned flags);
-
-/* uv_udp_t is a subclass of uv_handle_t. */
-struct uv_udp_s {
- UV_HANDLE_FIELDS
- /* read-only */
- /*
- * Number of bytes queued for sending. This field strictly shows how much
- * information is currently queued.
- */
- size_t send_queue_size;
- /*
- * Number of send requests currently in the queue awaiting to be processed.
- */
- size_t send_queue_count;
- UV_UDP_PRIVATE_FIELDS
-};
-
-/* uv_udp_send_t is a subclass of uv_req_t. */
-struct uv_udp_send_s {
- UV_REQ_FIELDS
- uv_udp_t* handle;
- uv_udp_send_cb cb;
- UV_UDP_SEND_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
-UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
-UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
-UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int flags);
-UV_EXTERN int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr);
-
-UV_EXTERN int uv_udp_getpeername(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen);
-UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen);
-UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
- const char* multicast_addr,
- const char* interface_addr,
- uv_membership membership);
-UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
-UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
-UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
- const char* interface_addr);
-UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
-UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl);
-UV_EXTERN int uv_udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- uv_udp_send_cb send_cb);
-UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr);
-UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
- uv_alloc_cb alloc_cb,
- uv_udp_recv_cb recv_cb);
-UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
-UV_EXTERN size_t uv_udp_get_send_queue_size(const uv_udp_t* handle);
-UV_EXTERN size_t uv_udp_get_send_queue_count(const uv_udp_t* handle);
-
-
-/*
- * uv_tty_t is a subclass of uv_stream_t.
- *
- * Representing a stream for the console.
- */
-struct uv_tty_s {
- UV_HANDLE_FIELDS
- UV_STREAM_FIELDS
- UV_TTY_PRIVATE_FIELDS
-};
-
-typedef enum {
- /* Initial/normal terminal mode */
- UV_TTY_MODE_NORMAL,
- /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
- UV_TTY_MODE_RAW,
- /* Binary-safe I/O mode for IPC (Unix-only) */
- UV_TTY_MODE_IO
-} uv_tty_mode_t;
-
-UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
-UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
-UV_EXTERN int uv_tty_reset_mode(void);
-UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
-
-inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
- return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
-}
-
-UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
-
-/*
- * uv_pipe_t is a subclass of uv_stream_t.
- *
- * Representing a pipe stream or pipe server. On Windows this is a Named
- * Pipe. On Unix this is a Unix domain socket.
- */
-struct uv_pipe_s {
- UV_HANDLE_FIELDS
- UV_STREAM_FIELDS
- int ipc; /* non-zero if this pipe is used for passing handles */
- UV_PIPE_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
-UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
-UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
-UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
- uv_pipe_t* handle,
- const char* name,
- uv_connect_cb cb);
-UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
- char* buffer,
- size_t* size);
-UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
- char* buffer,
- size_t* size);
-UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
-UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
-UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
-UV_EXTERN int uv_pipe_chmod(uv_pipe_t* handle, int flags);
-
-
-struct uv_poll_s {
- UV_HANDLE_FIELDS
- uv_poll_cb poll_cb;
- UV_POLL_PRIVATE_FIELDS
-};
-
-enum uv_poll_event {
- UV_READABLE = 1,
- UV_WRITABLE = 2,
- UV_DISCONNECT = 4,
- UV_PRIORITIZED = 8
-};
-
-UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
-UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop,
- uv_poll_t* handle,
- uv_os_sock_t socket);
-UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
-UV_EXTERN int uv_poll_stop(uv_poll_t* handle);
-
-
-struct uv_prepare_s {
- UV_HANDLE_FIELDS
- UV_PREPARE_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
-UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
-UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare);
-
-
-struct uv_check_s {
- UV_HANDLE_FIELDS
- UV_CHECK_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check);
-UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb);
-UV_EXTERN int uv_check_stop(uv_check_t* check);
-
-
-struct uv_idle_s {
- UV_HANDLE_FIELDS
- UV_IDLE_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
-UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
-UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
-
-
-struct uv_async_s {
- UV_HANDLE_FIELDS
- UV_ASYNC_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_async_init(uv_loop_t*,
- uv_async_t* async,
- uv_async_cb async_cb);
-UV_EXTERN int uv_async_send(uv_async_t* async);
-
-
-/*
- * uv_timer_t is a subclass of uv_handle_t.
- *
- * Used to get woken up at a specified time in the future.
- */
-struct uv_timer_s {
- UV_HANDLE_FIELDS
- UV_TIMER_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
-UV_EXTERN int uv_timer_start(uv_timer_t* handle,
- uv_timer_cb cb,
- uint64_t timeout,
- uint64_t repeat);
-UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
-UV_EXTERN int uv_timer_again(uv_timer_t* handle);
-UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
-UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
-
-
-/*
- * uv_getaddrinfo_t is a subclass of uv_req_t.
- *
- * Request object for uv_getaddrinfo.
- */
-struct uv_getaddrinfo_s {
- UV_REQ_FIELDS
- /* read-only */
- uv_loop_t* loop;
- /* struct addrinfo* addrinfo is marked as private, but it really isn't. */
- UV_GETADDRINFO_PRIVATE_FIELDS
-};
-
-
-UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop,
- uv_getaddrinfo_t* req,
- uv_getaddrinfo_cb getaddrinfo_cb,
- const char* node,
- const char* service,
- const struct addrinfo* hints);
-UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
-
-
-/*
-* uv_getnameinfo_t is a subclass of uv_req_t.
-*
-* Request object for uv_getnameinfo.
-*/
-struct uv_getnameinfo_s {
- UV_REQ_FIELDS
- /* read-only */
- uv_loop_t* loop;
- /* host and service are marked as private, but they really aren't. */
- UV_GETNAMEINFO_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
- uv_getnameinfo_t* req,
- uv_getnameinfo_cb getnameinfo_cb,
- const struct sockaddr* addr,
- int flags);
-
-
-/* uv_spawn() options. */
-typedef enum {
- UV_IGNORE = 0x00,
- UV_CREATE_PIPE = 0x01,
- UV_INHERIT_FD = 0x02,
- UV_INHERIT_STREAM = 0x04,
-
- /*
- * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
- * determine the direction of flow, from the child process' perspective. Both
- * flags may be specified to create a duplex data stream.
- */
- UV_READABLE_PIPE = 0x10,
- UV_WRITABLE_PIPE = 0x20,
-
- /*
- * Open the child pipe handle in overlapped mode on Windows.
- * On Unix it is silently ignored.
- */
- UV_OVERLAPPED_PIPE = 0x40
-} uv_stdio_flags;
-
-typedef struct uv_stdio_container_s {
- uv_stdio_flags flags;
-
- union {
- uv_stream_t* stream;
- int fd;
- } data;
-} uv_stdio_container_t;
-
-typedef struct uv_process_options_s {
- uv_exit_cb exit_cb; /* Called after the process exits. */
- const char* file; /* Path to program to execute. */
- /*
- * Command line arguments. args[0] should be the path to the program. On
- * Windows this uses CreateProcess which concatenates the arguments into a
- * string this can cause some strange errors. See the note at
- * windows_verbatim_arguments.
- */
- char** args;
- /*
- * This will be set as the environ variable in the subprocess. If this is
- * NULL then the parents environ will be used.
- */
- char** env;
- /*
- * If non-null this represents a directory the subprocess should execute
- * in. Stands for current working directory.
- */
- const char* cwd;
- /*
- * Various flags that control how uv_spawn() behaves. See the definition of
- * `enum uv_process_flags` below.
- */
- unsigned int flags;
- /*
- * The `stdio` field points to an array of uv_stdio_container_t structs that
- * describe the file descriptors that will be made available to the child
- * process. The convention is that stdio[0] points to stdin, fd 1 is used for
- * stdout, and fd 2 is stderr.
- *
- * Note that on windows file descriptors greater than 2 are available to the
- * child process only if the child processes uses the MSVCRT runtime.
- */
- int stdio_count;
- uv_stdio_container_t* stdio;
- /*
- * Libuv can change the child process' user/group id. This happens only when
- * the appropriate bits are set in the flags fields. This is not supported on
- * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
- */
- uv_uid_t uid;
- uv_gid_t gid;
-} uv_process_options_t;
-
-/*
- * These are the flags that can be used for the uv_process_options.flags field.
- */
-enum uv_process_flags {
- /*
- * Set the child process' user id. The user id is supplied in the `uid` field
- * of the options struct. This does not work on windows; setting this flag
- * will cause uv_spawn() to fail.
- */
- UV_PROCESS_SETUID = (1 << 0),
- /*
- * Set the child process' group id. The user id is supplied in the `gid`
- * field of the options struct. This does not work on windows; setting this
- * flag will cause uv_spawn() to fail.
- */
- UV_PROCESS_SETGID = (1 << 1),
- /*
- * Do not wrap any arguments in quotes, or perform any other escaping, when
- * converting the argument list into a command line string. This option is
- * only meaningful on Windows systems. On Unix it is silently ignored.
- */
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
- /*
- * Spawn the child process in a detached state - this will make it a process
- * group leader, and will effectively enable the child to keep running after
- * the parent exits. Note that the child process will still keep the
- * parent's event loop alive unless the parent process calls uv_unref() on
- * the child's process handle.
- */
- UV_PROCESS_DETACHED = (1 << 3),
- /*
- * Hide the subprocess window that would normally be created. This option is
- * only meaningful on Windows systems. On Unix it is silently ignored.
- */
- UV_PROCESS_WINDOWS_HIDE = (1 << 4),
- /*
- * Hide the subprocess console window that would normally be created. This
- * option is only meaningful on Windows systems. On Unix it is silently
- * ignored.
- */
- UV_PROCESS_WINDOWS_HIDE_CONSOLE = (1 << 5),
- /*
- * Hide the subprocess GUI window that would normally be created. This
- * option is only meaningful on Windows systems. On Unix it is silently
- * ignored.
- */
- UV_PROCESS_WINDOWS_HIDE_GUI = (1 << 6)
-};
-
-/*
- * uv_process_t is a subclass of uv_handle_t.
- */
-struct uv_process_s {
- UV_HANDLE_FIELDS
- uv_exit_cb exit_cb;
- int pid;
- UV_PROCESS_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_spawn(uv_loop_t* loop,
- uv_process_t* handle,
- const uv_process_options_t* options);
-UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
-UV_EXTERN int uv_kill(int pid, int signum);
-UV_EXTERN uv_pid_t uv_process_get_pid(const uv_process_t*);
-
-
-/*
- * uv_work_t is a subclass of uv_req_t.
- */
-struct uv_work_s {
- UV_REQ_FIELDS
- uv_loop_t* loop;
- uv_work_cb work_cb;
- uv_after_work_cb after_work_cb;
- UV_WORK_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_queue_work(uv_loop_t* loop,
- uv_work_t* req,
- uv_work_cb work_cb,
- uv_after_work_cb after_work_cb);
-
-UV_EXTERN int uv_cancel(uv_req_t* req);
-
-
-struct uv_cpu_times_s {
- uint64_t user;
- uint64_t nice;
- uint64_t sys;
- uint64_t idle;
- uint64_t irq;
-};
-
-struct uv_cpu_info_s {
- char* model;
- int speed;
- struct uv_cpu_times_s cpu_times;
-};
-
-struct uv_interface_address_s {
- char* name;
- char phys_addr[6];
- int is_internal;
- union {
- struct sockaddr_in address4;
- struct sockaddr_in6 address6;
- } address;
- union {
- struct sockaddr_in netmask4;
- struct sockaddr_in6 netmask6;
- } netmask;
-};
-
-struct uv_passwd_s {
- char* username;
- long uid;
- long gid;
- char* shell;
- char* homedir;
-};
-
-struct uv_utsname_s {
- char sysname[256];
- char release[256];
- char version[256];
- char machine[256];
- /* This struct does not contain the nodename and domainname fields present in
- the utsname type. domainname is a GNU extension. Both fields are referred
- to as meaningless in the docs. */
-};
-
-typedef enum {
- UV_DIRENT_UNKNOWN,
- UV_DIRENT_FILE,
- UV_DIRENT_DIR,
- UV_DIRENT_LINK,
- UV_DIRENT_FIFO,
- UV_DIRENT_SOCKET,
- UV_DIRENT_CHAR,
- UV_DIRENT_BLOCK
-} uv_dirent_type_t;
-
-struct uv_dirent_s {
- const char* name;
- uv_dirent_type_t type;
-};
-
-UV_EXTERN char** uv_setup_args(int argc, char** argv);
-UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
-UV_EXTERN int uv_set_process_title(const char* title);
-UV_EXTERN int uv_resident_set_memory(size_t* rss);
-UV_EXTERN int uv_uptime(double* uptime);
-UV_EXTERN uv_os_fd_t uv_get_osfhandle(int fd);
-UV_EXTERN int uv_open_osfhandle(uv_os_fd_t os_fd);
-
-typedef struct {
- long tv_sec;
- long tv_usec;
-} uv_timeval_t;
-
-typedef struct {
- int64_t tv_sec;
- int32_t tv_usec;
-} uv_timeval64_t;
-
-typedef struct {
- uv_timeval_t ru_utime; /* user CPU time used */
- uv_timeval_t ru_stime; /* system CPU time used */
- uint64_t ru_maxrss; /* maximum resident set size */
- uint64_t ru_ixrss; /* integral shared memory size */
- uint64_t ru_idrss; /* integral unshared data size */
- uint64_t ru_isrss; /* integral unshared stack size */
- uint64_t ru_minflt; /* page reclaims (soft page faults) */
- uint64_t ru_majflt; /* page faults (hard page faults) */
- uint64_t ru_nswap; /* swaps */
- uint64_t ru_inblock; /* block input operations */
- uint64_t ru_oublock; /* block output operations */
- uint64_t ru_msgsnd; /* IPC messages sent */
- uint64_t ru_msgrcv; /* IPC messages received */
- uint64_t ru_nsignals; /* signals received */
- uint64_t ru_nvcsw; /* voluntary context switches */
- uint64_t ru_nivcsw; /* involuntary context switches */
-} uv_rusage_t;
-
-UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
-
-UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
-UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
-UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
-UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
-UV_EXTERN uv_pid_t uv_os_getpid(void);
-UV_EXTERN uv_pid_t uv_os_getppid(void);
-
-#define UV_PRIORITY_LOW 19
-#define UV_PRIORITY_BELOW_NORMAL 10
-#define UV_PRIORITY_NORMAL 0
-#define UV_PRIORITY_ABOVE_NORMAL -7
-#define UV_PRIORITY_HIGH -14
-#define UV_PRIORITY_HIGHEST -20
-
-UV_EXTERN int uv_os_getpriority(uv_pid_t pid, int* priority);
-UV_EXTERN int uv_os_setpriority(uv_pid_t pid, int priority);
-
-UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
-UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
-
-UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
- int* count);
-UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count);
-
-UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
-UV_EXTERN int uv_os_setenv(const char* name, const char* value);
-UV_EXTERN int uv_os_unsetenv(const char* name);
-
-#ifdef MAXHOSTNAMELEN
-# define UV_MAXHOSTNAMESIZE (MAXHOSTNAMELEN + 1)
-#else
- /*
- Fallback for the maximum hostname size, including the null terminator. The
- Windows gethostname() documentation states that 256 bytes will always be
- large enough to hold the null-terminated hostname.
- */
-# define UV_MAXHOSTNAMESIZE 256
-#endif
-
-UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
-
-UV_EXTERN int uv_os_uname(uv_utsname_t* buffer);
-
-
-typedef enum {
- UV_FS_UNKNOWN = -1,
- UV_FS_CUSTOM,
- UV_FS_OPEN,
- UV_FS_CLOSE,
- UV_FS_READ,
- UV_FS_WRITE,
- UV_FS_SENDFILE,
- UV_FS_STAT,
- UV_FS_LSTAT,
- UV_FS_FSTAT,
- UV_FS_FTRUNCATE,
- UV_FS_UTIME,
- UV_FS_FUTIME,
- UV_FS_ACCESS,
- UV_FS_CHMOD,
- UV_FS_FCHMOD,
- UV_FS_FSYNC,
- UV_FS_FDATASYNC,
- UV_FS_UNLINK,
- UV_FS_RMDIR,
- UV_FS_MKDIR,
- UV_FS_MKDTEMP,
- UV_FS_RENAME,
- UV_FS_SCANDIR,
- UV_FS_LINK,
- UV_FS_SYMLINK,
- UV_FS_READLINK,
- UV_FS_CHOWN,
- UV_FS_FCHOWN,
- UV_FS_REALPATH,
- UV_FS_COPYFILE,
- UV_FS_LCHOWN,
- UV_FS_OPENDIR,
- UV_FS_READDIR,
- UV_FS_CLOSEDIR
-} uv_fs_type;
-
-struct uv_dir_s {
- uv_dirent_t* dirents;
- size_t nentries;
- void* reserved[4];
- UV_DIR_PRIVATE_FIELDS
-};
-
-/* uv_fs_t is a subclass of uv_req_t. */
-struct uv_fs_s {
- UV_REQ_FIELDS
- uv_fs_type fs_type;
- uv_loop_t* loop;
- uv_fs_cb cb;
- ssize_t result;
- void* ptr;
- const char* path;
- uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */
- UV_FS_PRIVATE_FIELDS
-};
-
-UV_EXTERN uv_fs_type uv_fs_get_type(const uv_fs_t*);
-UV_EXTERN ssize_t uv_fs_get_result(const uv_fs_t*);
-UV_EXTERN void* uv_fs_get_ptr(const uv_fs_t*);
-UV_EXTERN const char* uv_fs_get_path(const uv_fs_t*);
-UV_EXTERN uv_stat_t* uv_fs_get_statbuf(uv_fs_t*);
-
-UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
-UV_EXTERN int uv_fs_close(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_open(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- int mode,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_read(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t offset,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_unlink(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_write(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t offset,
- uv_fs_cb cb);
-/*
- * This flag can be used with uv_fs_copyfile() to return an error if the
- * destination already exists.
- */
-#define UV_FS_COPYFILE_EXCL 0x0001
-
-/*
- * This flag can be used with uv_fs_copyfile() to attempt to create a reflink.
- * If copy-on-write is not supported, a fallback copy mechanism is used.
- */
-#define UV_FS_COPYFILE_FICLONE 0x0002
-
-/*
- * This flag can be used with uv_fs_copyfile() to attempt to create a reflink.
- * If copy-on-write is not supported, an error is returned.
- */
-#define UV_FS_COPYFILE_FICLONE_FORCE 0x0004
-
-UV_EXTERN int uv_fs_copyfile(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- int flags,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int mode,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
- uv_fs_t* req,
- const char* tpl,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_scandir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req,
- uv_dirent_t* ent);
-UV_EXTERN int uv_fs_opendir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_readdir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_closedir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_stat(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_fstat(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_rename(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_fsync(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- int64_t offset,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file out_fd,
- uv_file in_fd,
- int64_t in_offset,
- size_t length,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_access(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int mode,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int mode,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- double atime,
- double mtime,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- double atime,
- double mtime,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_link(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- uv_fs_cb cb);
-
-/*
- * This flag can be used with uv_fs_symlink() on Windows to specify whether
- * path argument points to a directory.
- */
-#define UV_FS_SYMLINK_DIR 0x0001
-
-/*
- * This flag can be used with uv_fs_symlink() on Windows to specify whether
- * the symlink is to be created using junction points.
- */
-#define UV_FS_SYMLINK_JUNCTION 0x0002
-
-UV_EXTERN int uv_fs_symlink(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- int flags,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_readlink(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_realpath(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- int mode,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_chown(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb);
-UV_EXTERN int uv_fs_lchown(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb);
-
-
-enum uv_fs_event {
- UV_RENAME = 1,
- UV_CHANGE = 2
-};
-
-
-struct uv_fs_event_s {
- UV_HANDLE_FIELDS
- /* private */
- char* path;
- UV_FS_EVENT_PRIVATE_FIELDS
-};
-
-
-/*
- * uv_fs_stat() based polling file watcher.
- */
-struct uv_fs_poll_s {
- UV_HANDLE_FIELDS
- /* Private, don't touch. */
- void* poll_ctx;
-};
-
-UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
-UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
- uv_fs_poll_cb poll_cb,
- const char* path,
- unsigned int interval);
-UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
-UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle,
- char* buffer,
- size_t* size);
-
-
-struct uv_signal_s {
- UV_HANDLE_FIELDS
- uv_signal_cb signal_cb;
- int signum;
- UV_SIGNAL_PRIVATE_FIELDS
-};
-
-UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
-UV_EXTERN int uv_signal_start(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum);
-UV_EXTERN int uv_signal_start_oneshot(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum);
-UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
-
-UV_EXTERN void uv_loadavg(double avg[3]);
-
-
-/*
- * Flags to be passed to uv_fs_event_start().
- */
-enum uv_fs_event_flags {
- /*
- * By default, if the fs event watcher is given a directory name, we will
- * watch for all events in that directory. This flags overrides this behavior
- * and makes fs_event report only changes to the directory entry itself. This
- * flag does not affect individual files watched.
- * This flag is currently not implemented yet on any backend.
- */
- UV_FS_EVENT_WATCH_ENTRY = 1,
-
- /*
- * By default uv_fs_event will try to use a kernel interface such as inotify
- * or kqueue to detect events. This may not work on remote filesystems such
- * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
- * regular interval.
- * This flag is currently not implemented yet on any backend.
- */
- UV_FS_EVENT_STAT = 2,
-
- /*
- * By default, event watcher, when watching directory, is not registering
- * (is ignoring) changes in it's subdirectories.
- * This flag will override this behaviour on platforms that support it.
- */
- UV_FS_EVENT_RECURSIVE = 4
-};
-
-
-UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle);
-UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle,
- uv_fs_event_cb cb,
- const char* path,
- unsigned int flags);
-UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle);
-UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle,
- char* buffer,
- size_t* size);
-
-UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
-UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
-
-UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
-UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
-
-UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
-UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
-
-#if defined(IF_NAMESIZE)
-# define UV_IF_NAMESIZE (IF_NAMESIZE + 1)
-#elif defined(IFNAMSIZ)
-# define UV_IF_NAMESIZE (IFNAMSIZ + 1)
-#else
-# define UV_IF_NAMESIZE (16 + 1)
-#endif
-
-UV_EXTERN int uv_if_indextoname(unsigned int ifindex,
- char* buffer,
- size_t* size);
-UV_EXTERN int uv_if_indextoiid(unsigned int ifindex,
- char* buffer,
- size_t* size);
-
-UV_EXTERN int uv_exepath(char* buffer, size_t* size);
-
-UV_EXTERN int uv_cwd(char* buffer, size_t* size);
-
-UV_EXTERN int uv_chdir(const char* dir);
-
-UV_EXTERN uint64_t uv_get_free_memory(void);
-UV_EXTERN uint64_t uv_get_total_memory(void);
-UV_EXTERN uint64_t uv_get_constrained_memory(void);
-
-UV_EXTERN uint64_t uv_hrtime(void);
-
-UV_EXTERN void uv_disable_stdio_inheritance(void);
-
-UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
-UV_EXTERN void uv_dlclose(uv_lib_t* lib);
-UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
-UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
-
-UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
-UV_EXTERN int uv_mutex_init_recursive(uv_mutex_t* handle);
-UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
-UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
-UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
-UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
-
-UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock);
-UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock);
-UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock);
-UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
-UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
-UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
-UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
-UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
-
-UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
-UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
-UV_EXTERN void uv_sem_post(uv_sem_t* sem);
-UV_EXTERN void uv_sem_wait(uv_sem_t* sem);
-UV_EXTERN int uv_sem_trywait(uv_sem_t* sem);
-
-UV_EXTERN int uv_cond_init(uv_cond_t* cond);
-UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
-UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
-UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
-
-UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
-UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
-UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
-
-UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
-UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond,
- uv_mutex_t* mutex,
- uint64_t timeout);
-
-UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
-
-UV_EXTERN int uv_key_create(uv_key_t* key);
-UV_EXTERN void uv_key_delete(uv_key_t* key);
-UV_EXTERN void* uv_key_get(uv_key_t* key);
-UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
-
-UV_EXTERN int uv_gettimeofday(uv_timeval64_t* tv);
-
-typedef void (*uv_thread_cb)(void* arg);
-
-UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
-
-typedef enum {
- UV_THREAD_NO_FLAGS = 0x00,
- UV_THREAD_HAS_STACK_SIZE = 0x01
-} uv_thread_create_flags;
-
-struct uv_thread_options_s {
- unsigned int flags;
- size_t stack_size;
- /* More fields may be added at any time. */
-};
-
-typedef struct uv_thread_options_s uv_thread_options_t;
-
-UV_EXTERN int uv_thread_create_ex(uv_thread_t* tid,
- const uv_thread_options_t* params,
- uv_thread_cb entry,
- void* arg);
-UV_EXTERN uv_thread_t uv_thread_self(void);
-UV_EXTERN int uv_thread_join(uv_thread_t *tid);
-UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
-
-/* The presence of these unions force similar struct layout. */
-#define XX(_, name) uv_ ## name ## _t name;
-union uv_any_handle {
- UV_HANDLE_TYPE_MAP(XX)
-};
-
-union uv_any_req {
- UV_REQ_TYPE_MAP(XX)
-};
-#undef XX
-
-
-struct uv_loop_s {
- /* User data - use this for whatever. */
- void* data;
- /* Loop reference counting. */
- unsigned int active_handles;
- void* handle_queue[2];
- union {
- void* unused[2];
- unsigned int count;
- } active_reqs;
- /* Internal flag to signal loop stop. */
- unsigned int stop_flag;
- UV_LOOP_PRIVATE_FIELDS
-};
-
-UV_EXTERN void* uv_loop_get_data(const uv_loop_t*);
-UV_EXTERN void uv_loop_set_data(uv_loop_t*, void* data);
-
-/* Don't export the private CPP symbols. */
-#undef UV_HANDLE_TYPE_PRIVATE
-#undef UV_REQ_TYPE_PRIVATE
-#undef UV_REQ_PRIVATE_FIELDS
-#undef UV_STREAM_PRIVATE_FIELDS
-#undef UV_TCP_PRIVATE_FIELDS
-#undef UV_PREPARE_PRIVATE_FIELDS
-#undef UV_CHECK_PRIVATE_FIELDS
-#undef UV_IDLE_PRIVATE_FIELDS
-#undef UV_ASYNC_PRIVATE_FIELDS
-#undef UV_TIMER_PRIVATE_FIELDS
-#undef UV_GETADDRINFO_PRIVATE_FIELDS
-#undef UV_GETNAMEINFO_PRIVATE_FIELDS
-#undef UV_FS_REQ_PRIVATE_FIELDS
-#undef UV_WORK_PRIVATE_FIELDS
-#undef UV_FS_EVENT_PRIVATE_FIELDS
-#undef UV_SIGNAL_PRIVATE_FIELDS
-#undef UV_LOOP_PRIVATE_FIELDS
-#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
-#undef UV__ERR
-
-#endif /* UV_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/android-ifaddrs.h b/wpiutil/src/main/native/libuv/include/uv/android-ifaddrs.h
deleted file mode 100644
index 9cd19fe..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/android-ifaddrs.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 1995, 1999
- * Berkeley Software Design, 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:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
- *
- * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
- */
-
-#ifndef _IFADDRS_H_
-#define _IFADDRS_H_
-
-struct ifaddrs {
- struct ifaddrs *ifa_next;
- char *ifa_name;
- unsigned int ifa_flags;
- struct sockaddr *ifa_addr;
- struct sockaddr *ifa_netmask;
- struct sockaddr *ifa_dstaddr;
- void *ifa_data;
-};
-
-/*
- * This may have been defined in <net/if.h>. Note that if <net/if.h> is
- * to be included it must be included before this header file.
- */
-#ifndef ifa_broadaddr
-#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
-#endif
-
-#include <sys/cdefs.h>
-
-__BEGIN_DECLS
-extern int getifaddrs(struct ifaddrs **ifap);
-extern void freeifaddrs(struct ifaddrs *ifa);
-__END_DECLS
-
-#endif
diff --git a/wpiutil/src/main/native/libuv/include/uv/bsd.h b/wpiutil/src/main/native/libuv/include/uv/bsd.h
deleted file mode 100644
index 2d72b3d..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/bsd.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_BSD_H
-#define UV_BSD_H
-
-#define UV_PLATFORM_FS_EVENT_FIELDS \
- uv__io_t event_watcher; \
-
-#define UV_IO_PRIVATE_PLATFORM_FIELDS \
- int rcount; \
- int wcount; \
-
-#define UV_HAVE_KQUEUE 1
-
-#endif /* UV_BSD_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/darwin.h b/wpiutil/src/main/native/libuv/include/uv/darwin.h
deleted file mode 100644
index d226415..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/darwin.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_DARWIN_H
-#define UV_DARWIN_H
-
-#if defined(__APPLE__) && defined(__MACH__)
-# include <mach/mach.h>
-# include <mach/task.h>
-# include <mach/semaphore.h>
-# include <TargetConditionals.h>
-# define UV_PLATFORM_SEM_T semaphore_t
-#endif
-
-#define UV_IO_PRIVATE_PLATFORM_FIELDS \
- int rcount; \
- int wcount; \
-
-#define UV_PLATFORM_LOOP_FIELDS \
- uv_thread_t cf_thread; \
- void* _cf_reserved; \
- void* cf_state; \
- uv_mutex_t cf_mutex; \
- uv_sem_t cf_sem; \
- void* cf_signals[2]; \
-
-#define UV_PLATFORM_FS_EVENT_FIELDS \
- uv__io_t event_watcher; \
- char* realpath; \
- int realpath_len; \
- int cf_flags; \
- uv_async_t* cf_cb; \
- void* cf_events[2]; \
- void* cf_member[2]; \
- int cf_error; \
- uv_mutex_t cf_mutex; \
-
-#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
- void* select; \
-
-#define UV_HAVE_KQUEUE 1
-
-#endif /* UV_DARWIN_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/errno.h b/wpiutil/src/main/native/libuv/include/uv/errno.h
deleted file mode 100644
index 8eeb95d..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/errno.h
+++ /dev/null
@@ -1,443 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_ERRNO_H_
-#define UV_ERRNO_H_
-
-#include <errno.h>
-#if EDOM > 0
-# define UV__ERR(x) (-(x))
-#else
-# define UV__ERR(x) (x)
-#endif
-
-#define UV__EOF (-4095)
-#define UV__UNKNOWN (-4094)
-
-#define UV__EAI_ADDRFAMILY (-3000)
-#define UV__EAI_AGAIN (-3001)
-#define UV__EAI_BADFLAGS (-3002)
-#define UV__EAI_CANCELED (-3003)
-#define UV__EAI_FAIL (-3004)
-#define UV__EAI_FAMILY (-3005)
-#define UV__EAI_MEMORY (-3006)
-#define UV__EAI_NODATA (-3007)
-#define UV__EAI_NONAME (-3008)
-#define UV__EAI_OVERFLOW (-3009)
-#define UV__EAI_SERVICE (-3010)
-#define UV__EAI_SOCKTYPE (-3011)
-#define UV__EAI_BADHINTS (-3013)
-#define UV__EAI_PROTOCOL (-3014)
-
-/* Only map to the system errno on non-Windows platforms. It's apparently
- * a fairly common practice for Windows programmers to redefine errno codes.
- */
-#if defined(E2BIG) && !defined(_WIN32)
-# define UV__E2BIG UV__ERR(E2BIG)
-#else
-# define UV__E2BIG (-4093)
-#endif
-
-#if defined(EACCES) && !defined(_WIN32)
-# define UV__EACCES UV__ERR(EACCES)
-#else
-# define UV__EACCES (-4092)
-#endif
-
-#if defined(EADDRINUSE) && !defined(_WIN32)
-# define UV__EADDRINUSE UV__ERR(EADDRINUSE)
-#else
-# define UV__EADDRINUSE (-4091)
-#endif
-
-#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
-# define UV__EADDRNOTAVAIL UV__ERR(EADDRNOTAVAIL)
-#else
-# define UV__EADDRNOTAVAIL (-4090)
-#endif
-
-#if defined(EAFNOSUPPORT) && !defined(_WIN32)
-# define UV__EAFNOSUPPORT UV__ERR(EAFNOSUPPORT)
-#else
-# define UV__EAFNOSUPPORT (-4089)
-#endif
-
-#if defined(EAGAIN) && !defined(_WIN32)
-# define UV__EAGAIN UV__ERR(EAGAIN)
-#else
-# define UV__EAGAIN (-4088)
-#endif
-
-#if defined(EALREADY) && !defined(_WIN32)
-# define UV__EALREADY UV__ERR(EALREADY)
-#else
-# define UV__EALREADY (-4084)
-#endif
-
-#if defined(EBADF) && !defined(_WIN32)
-# define UV__EBADF UV__ERR(EBADF)
-#else
-# define UV__EBADF (-4083)
-#endif
-
-#if defined(EBUSY) && !defined(_WIN32)
-# define UV__EBUSY UV__ERR(EBUSY)
-#else
-# define UV__EBUSY (-4082)
-#endif
-
-#if defined(ECANCELED) && !defined(_WIN32)
-# define UV__ECANCELED UV__ERR(ECANCELED)
-#else
-# define UV__ECANCELED (-4081)
-#endif
-
-#if defined(ECHARSET) && !defined(_WIN32)
-# define UV__ECHARSET UV__ERR(ECHARSET)
-#else
-# define UV__ECHARSET (-4080)
-#endif
-
-#if defined(ECONNABORTED) && !defined(_WIN32)
-# define UV__ECONNABORTED UV__ERR(ECONNABORTED)
-#else
-# define UV__ECONNABORTED (-4079)
-#endif
-
-#if defined(ECONNREFUSED) && !defined(_WIN32)
-# define UV__ECONNREFUSED UV__ERR(ECONNREFUSED)
-#else
-# define UV__ECONNREFUSED (-4078)
-#endif
-
-#if defined(ECONNRESET) && !defined(_WIN32)
-# define UV__ECONNRESET UV__ERR(ECONNRESET)
-#else
-# define UV__ECONNRESET (-4077)
-#endif
-
-#if defined(EDESTADDRREQ) && !defined(_WIN32)
-# define UV__EDESTADDRREQ UV__ERR(EDESTADDRREQ)
-#else
-# define UV__EDESTADDRREQ (-4076)
-#endif
-
-#if defined(EEXIST) && !defined(_WIN32)
-# define UV__EEXIST UV__ERR(EEXIST)
-#else
-# define UV__EEXIST (-4075)
-#endif
-
-#if defined(EFAULT) && !defined(_WIN32)
-# define UV__EFAULT UV__ERR(EFAULT)
-#else
-# define UV__EFAULT (-4074)
-#endif
-
-#if defined(EHOSTUNREACH) && !defined(_WIN32)
-# define UV__EHOSTUNREACH UV__ERR(EHOSTUNREACH)
-#else
-# define UV__EHOSTUNREACH (-4073)
-#endif
-
-#if defined(EINTR) && !defined(_WIN32)
-# define UV__EINTR UV__ERR(EINTR)
-#else
-# define UV__EINTR (-4072)
-#endif
-
-#if defined(EINVAL) && !defined(_WIN32)
-# define UV__EINVAL UV__ERR(EINVAL)
-#else
-# define UV__EINVAL (-4071)
-#endif
-
-#if defined(EIO) && !defined(_WIN32)
-# define UV__EIO UV__ERR(EIO)
-#else
-# define UV__EIO (-4070)
-#endif
-
-#if defined(EISCONN) && !defined(_WIN32)
-# define UV__EISCONN UV__ERR(EISCONN)
-#else
-# define UV__EISCONN (-4069)
-#endif
-
-#if defined(EISDIR) && !defined(_WIN32)
-# define UV__EISDIR UV__ERR(EISDIR)
-#else
-# define UV__EISDIR (-4068)
-#endif
-
-#if defined(ELOOP) && !defined(_WIN32)
-# define UV__ELOOP UV__ERR(ELOOP)
-#else
-# define UV__ELOOP (-4067)
-#endif
-
-#if defined(EMFILE) && !defined(_WIN32)
-# define UV__EMFILE UV__ERR(EMFILE)
-#else
-# define UV__EMFILE (-4066)
-#endif
-
-#if defined(EMSGSIZE) && !defined(_WIN32)
-# define UV__EMSGSIZE UV__ERR(EMSGSIZE)
-#else
-# define UV__EMSGSIZE (-4065)
-#endif
-
-#if defined(ENAMETOOLONG) && !defined(_WIN32)
-# define UV__ENAMETOOLONG UV__ERR(ENAMETOOLONG)
-#else
-# define UV__ENAMETOOLONG (-4064)
-#endif
-
-#if defined(ENETDOWN) && !defined(_WIN32)
-# define UV__ENETDOWN UV__ERR(ENETDOWN)
-#else
-# define UV__ENETDOWN (-4063)
-#endif
-
-#if defined(ENETUNREACH) && !defined(_WIN32)
-# define UV__ENETUNREACH UV__ERR(ENETUNREACH)
-#else
-# define UV__ENETUNREACH (-4062)
-#endif
-
-#if defined(ENFILE) && !defined(_WIN32)
-# define UV__ENFILE UV__ERR(ENFILE)
-#else
-# define UV__ENFILE (-4061)
-#endif
-
-#if defined(ENOBUFS) && !defined(_WIN32)
-# define UV__ENOBUFS UV__ERR(ENOBUFS)
-#else
-# define UV__ENOBUFS (-4060)
-#endif
-
-#if defined(ENODEV) && !defined(_WIN32)
-# define UV__ENODEV UV__ERR(ENODEV)
-#else
-# define UV__ENODEV (-4059)
-#endif
-
-#if defined(ENOENT) && !defined(_WIN32)
-# define UV__ENOENT UV__ERR(ENOENT)
-#else
-# define UV__ENOENT (-4058)
-#endif
-
-#if defined(ENOMEM) && !defined(_WIN32)
-# define UV__ENOMEM UV__ERR(ENOMEM)
-#else
-# define UV__ENOMEM (-4057)
-#endif
-
-#if defined(ENONET) && !defined(_WIN32)
-# define UV__ENONET UV__ERR(ENONET)
-#else
-# define UV__ENONET (-4056)
-#endif
-
-#if defined(ENOSPC) && !defined(_WIN32)
-# define UV__ENOSPC UV__ERR(ENOSPC)
-#else
-# define UV__ENOSPC (-4055)
-#endif
-
-#if defined(ENOSYS) && !defined(_WIN32)
-# define UV__ENOSYS UV__ERR(ENOSYS)
-#else
-# define UV__ENOSYS (-4054)
-#endif
-
-#if defined(ENOTCONN) && !defined(_WIN32)
-# define UV__ENOTCONN UV__ERR(ENOTCONN)
-#else
-# define UV__ENOTCONN (-4053)
-#endif
-
-#if defined(ENOTDIR) && !defined(_WIN32)
-# define UV__ENOTDIR UV__ERR(ENOTDIR)
-#else
-# define UV__ENOTDIR (-4052)
-#endif
-
-#if defined(ENOTEMPTY) && !defined(_WIN32)
-# define UV__ENOTEMPTY UV__ERR(ENOTEMPTY)
-#else
-# define UV__ENOTEMPTY (-4051)
-#endif
-
-#if defined(ENOTSOCK) && !defined(_WIN32)
-# define UV__ENOTSOCK UV__ERR(ENOTSOCK)
-#else
-# define UV__ENOTSOCK (-4050)
-#endif
-
-#if defined(ENOTSUP) && !defined(_WIN32)
-# define UV__ENOTSUP UV__ERR(ENOTSUP)
-#else
-# define UV__ENOTSUP (-4049)
-#endif
-
-#if defined(EPERM) && !defined(_WIN32)
-# define UV__EPERM UV__ERR(EPERM)
-#else
-# define UV__EPERM (-4048)
-#endif
-
-#if defined(EPIPE) && !defined(_WIN32)
-# define UV__EPIPE UV__ERR(EPIPE)
-#else
-# define UV__EPIPE (-4047)
-#endif
-
-#if defined(EPROTO) && !defined(_WIN32)
-# define UV__EPROTO UV__ERR(EPROTO)
-#else
-# define UV__EPROTO UV__ERR(4046)
-#endif
-
-#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
-# define UV__EPROTONOSUPPORT UV__ERR(EPROTONOSUPPORT)
-#else
-# define UV__EPROTONOSUPPORT (-4045)
-#endif
-
-#if defined(EPROTOTYPE) && !defined(_WIN32)
-# define UV__EPROTOTYPE UV__ERR(EPROTOTYPE)
-#else
-# define UV__EPROTOTYPE (-4044)
-#endif
-
-#if defined(EROFS) && !defined(_WIN32)
-# define UV__EROFS UV__ERR(EROFS)
-#else
-# define UV__EROFS (-4043)
-#endif
-
-#if defined(ESHUTDOWN) && !defined(_WIN32)
-# define UV__ESHUTDOWN UV__ERR(ESHUTDOWN)
-#else
-# define UV__ESHUTDOWN (-4042)
-#endif
-
-#if defined(ESPIPE) && !defined(_WIN32)
-# define UV__ESPIPE UV__ERR(ESPIPE)
-#else
-# define UV__ESPIPE (-4041)
-#endif
-
-#if defined(ESRCH) && !defined(_WIN32)
-# define UV__ESRCH UV__ERR(ESRCH)
-#else
-# define UV__ESRCH (-4040)
-#endif
-
-#if defined(ETIMEDOUT) && !defined(_WIN32)
-# define UV__ETIMEDOUT UV__ERR(ETIMEDOUT)
-#else
-# define UV__ETIMEDOUT (-4039)
-#endif
-
-#if defined(ETXTBSY) && !defined(_WIN32)
-# define UV__ETXTBSY UV__ERR(ETXTBSY)
-#else
-# define UV__ETXTBSY (-4038)
-#endif
-
-#if defined(EXDEV) && !defined(_WIN32)
-# define UV__EXDEV UV__ERR(EXDEV)
-#else
-# define UV__EXDEV (-4037)
-#endif
-
-#if defined(EFBIG) && !defined(_WIN32)
-# define UV__EFBIG UV__ERR(EFBIG)
-#else
-# define UV__EFBIG (-4036)
-#endif
-
-#if defined(ENOPROTOOPT) && !defined(_WIN32)
-# define UV__ENOPROTOOPT UV__ERR(ENOPROTOOPT)
-#else
-# define UV__ENOPROTOOPT (-4035)
-#endif
-
-#if defined(ERANGE) && !defined(_WIN32)
-# define UV__ERANGE UV__ERR(ERANGE)
-#else
-# define UV__ERANGE (-4034)
-#endif
-
-#if defined(ENXIO) && !defined(_WIN32)
-# define UV__ENXIO UV__ERR(ENXIO)
-#else
-# define UV__ENXIO (-4033)
-#endif
-
-#if defined(EMLINK) && !defined(_WIN32)
-# define UV__EMLINK UV__ERR(EMLINK)
-#else
-# define UV__EMLINK (-4032)
-#endif
-
-/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
- * defined. Fortunately, its value is always 64 so it's possible albeit
- * icky to hard-code it.
- */
-#if defined(EHOSTDOWN) && !defined(_WIN32)
-# define UV__EHOSTDOWN UV__ERR(EHOSTDOWN)
-#elif defined(__APPLE__) || \
- defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || \
- defined(__NetBSD__) || \
- defined(__OpenBSD__)
-# define UV__EHOSTDOWN (-64)
-#else
-# define UV__EHOSTDOWN (-4031)
-#endif
-
-#if defined(EREMOTEIO) && !defined(_WIN32)
-# define UV__EREMOTEIO UV__ERR(EREMOTEIO)
-#else
-# define UV__EREMOTEIO (-4030)
-#endif
-
-#if defined(ENOTTY) && !defined(_WIN32)
-# define UV__ENOTTY UV__ERR(ENOTTY)
-#else
-# define UV__ENOTTY (-4029)
-#endif
-
-#if defined(EFTYPE) && !defined(_WIN32)
-# define UV__EFTYPE UV__ERR(EFTYPE)
-#else
-# define UV__EFTYPE (-4028)
-#endif
-
-
-#endif /* UV_ERRNO_H_ */
diff --git a/wpiutil/src/main/native/libuv/include/uv/linux.h b/wpiutil/src/main/native/libuv/include/uv/linux.h
deleted file mode 100644
index 9b38405..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/linux.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_LINUX_H
-#define UV_LINUX_H
-
-#define UV_PLATFORM_LOOP_FIELDS \
- uv__io_t inotify_read_watcher; \
- void* inotify_watchers; \
- int inotify_fd; \
-
-#define UV_PLATFORM_FS_EVENT_FIELDS \
- void* watchers[2]; \
- int wd; \
-
-#endif /* UV_LINUX_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/posix.h b/wpiutil/src/main/native/libuv/include/uv/posix.h
deleted file mode 100644
index 9a96634..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/posix.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_POSIX_H
-#define UV_POSIX_H
-
-#define UV_PLATFORM_LOOP_FIELDS \
- struct pollfd* poll_fds; \
- size_t poll_fds_used; \
- size_t poll_fds_size; \
- unsigned char poll_fds_iterating; \
-
-#endif /* UV_POSIX_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/threadpool.h b/wpiutil/src/main/native/libuv/include/uv/threadpool.h
deleted file mode 100644
index 9708ebd..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/threadpool.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-/*
- * This file is private to libuv. It provides common functionality to both
- * Windows and Unix backends.
- */
-
-#ifndef UV_THREADPOOL_H_
-#define UV_THREADPOOL_H_
-
-struct uv__work {
- void (*work)(struct uv__work *w);
- void (*done)(struct uv__work *w, int status);
- struct uv_loop_s* loop;
- void* wq[2];
-};
-
-#endif /* UV_THREADPOOL_H_ */
diff --git a/wpiutil/src/main/native/libuv/include/uv/tree.h b/wpiutil/src/main/native/libuv/include/uv/tree.h
deleted file mode 100644
index f936416..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/tree.h
+++ /dev/null
@@ -1,768 +0,0 @@
-/*-
- * Copyright 2002 Niels Provos <provos@citi.umich.edu>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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 AUTHOR ``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 AUTHOR 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 UV_TREE_H_
-#define UV_TREE_H_
-
-#ifndef UV__UNUSED
-# if __GNUC__
-# define UV__UNUSED __attribute__((unused))
-# else
-# define UV__UNUSED
-# endif
-#endif
-
-/*
- * This file defines data structures for different types of trees:
- * splay trees and red-black trees.
- *
- * A splay tree is a self-organizing data structure. Every operation
- * on the tree causes a splay to happen. The splay moves the requested
- * node to the root of the tree and partly rebalances it.
- *
- * This has the benefit that request locality causes faster lookups as
- * the requested nodes move to the top of the tree. On the other hand,
- * every lookup causes memory writes.
- *
- * The Balance Theorem bounds the total access time for m operations
- * and n inserts on an initially empty tree as O((m + n)lg n). The
- * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
- *
- * A red-black tree is a binary search tree with the node color as an
- * extra attribute. It fulfills a set of conditions:
- * - every search path from the root to a leaf consists of the
- * same number of black nodes,
- * - each red node (except for the root) has a black parent,
- * - each leaf node is black.
- *
- * Every operation on a red-black tree is bounded as O(lg n).
- * The maximum height of a red-black tree is 2lg (n+1).
- */
-
-#define SPLAY_HEAD(name, type) \
-struct name { \
- struct type *sph_root; /* root of the tree */ \
-}
-
-#define SPLAY_INITIALIZER(root) \
- { NULL }
-
-#define SPLAY_INIT(root) do { \
- (root)->sph_root = NULL; \
-} while (/*CONSTCOND*/ 0)
-
-#define SPLAY_ENTRY(type) \
-struct { \
- struct type *spe_left; /* left element */ \
- struct type *spe_right; /* right element */ \
-}
-
-#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
-#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
-#define SPLAY_ROOT(head) (head)->sph_root
-#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
-
-/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
-#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
- SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
- SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
- (head)->sph_root = tmp; \
-} while (/*CONSTCOND*/ 0)
-
-#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
- SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
- SPLAY_LEFT(tmp, field) = (head)->sph_root; \
- (head)->sph_root = tmp; \
-} while (/*CONSTCOND*/ 0)
-
-#define SPLAY_LINKLEFT(head, tmp, field) do { \
- SPLAY_LEFT(tmp, field) = (head)->sph_root; \
- tmp = (head)->sph_root; \
- (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
-} while (/*CONSTCOND*/ 0)
-
-#define SPLAY_LINKRIGHT(head, tmp, field) do { \
- SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
- tmp = (head)->sph_root; \
- (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
-} while (/*CONSTCOND*/ 0)
-
-#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
- SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
- SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
- SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
- SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
-} while (/*CONSTCOND*/ 0)
-
-/* Generates prototypes and inline functions */
-
-#define SPLAY_PROTOTYPE(name, type, field, cmp) \
-void name##_SPLAY(struct name *, struct type *); \
-void name##_SPLAY_MINMAX(struct name *, int); \
-struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
-struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
- \
-/* Finds the node with the same key as elm */ \
-static __inline struct type * \
-name##_SPLAY_FIND(struct name *head, struct type *elm) \
-{ \
- if (SPLAY_EMPTY(head)) \
- return(NULL); \
- name##_SPLAY(head, elm); \
- if ((cmp)(elm, (head)->sph_root) == 0) \
- return (head->sph_root); \
- return (NULL); \
-} \
- \
-static __inline struct type * \
-name##_SPLAY_NEXT(struct name *head, struct type *elm) \
-{ \
- name##_SPLAY(head, elm); \
- if (SPLAY_RIGHT(elm, field) != NULL) { \
- elm = SPLAY_RIGHT(elm, field); \
- while (SPLAY_LEFT(elm, field) != NULL) { \
- elm = SPLAY_LEFT(elm, field); \
- } \
- } else \
- elm = NULL; \
- return (elm); \
-} \
- \
-static __inline struct type * \
-name##_SPLAY_MIN_MAX(struct name *head, int val) \
-{ \
- name##_SPLAY_MINMAX(head, val); \
- return (SPLAY_ROOT(head)); \
-}
-
-/* Main splay operation.
- * Moves node close to the key of elm to top
- */
-#define SPLAY_GENERATE(name, type, field, cmp) \
-struct type * \
-name##_SPLAY_INSERT(struct name *head, struct type *elm) \
-{ \
- if (SPLAY_EMPTY(head)) { \
- SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
- } else { \
- int __comp; \
- name##_SPLAY(head, elm); \
- __comp = (cmp)(elm, (head)->sph_root); \
- if(__comp < 0) { \
- SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
- SPLAY_RIGHT(elm, field) = (head)->sph_root; \
- SPLAY_LEFT((head)->sph_root, field) = NULL; \
- } else if (__comp > 0) { \
- SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
- SPLAY_LEFT(elm, field) = (head)->sph_root; \
- SPLAY_RIGHT((head)->sph_root, field) = NULL; \
- } else \
- return ((head)->sph_root); \
- } \
- (head)->sph_root = (elm); \
- return (NULL); \
-} \
- \
-struct type * \
-name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
-{ \
- struct type *__tmp; \
- if (SPLAY_EMPTY(head)) \
- return (NULL); \
- name##_SPLAY(head, elm); \
- if ((cmp)(elm, (head)->sph_root) == 0) { \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
- (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
- } else { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
- name##_SPLAY(head, elm); \
- SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
- } \
- return (elm); \
- } \
- return (NULL); \
-} \
- \
-void \
-name##_SPLAY(struct name *head, struct type *elm) \
-{ \
- struct type __node, *__left, *__right, *__tmp; \
- int __comp; \
- \
- SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
- __left = __right = &__node; \
- \
- while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
- if (__comp < 0) { \
- __tmp = SPLAY_LEFT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if ((cmp)(elm, __tmp) < 0){ \
- SPLAY_ROTATE_RIGHT(head, __tmp, field); \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
- break; \
- } \
- SPLAY_LINKLEFT(head, __right, field); \
- } else if (__comp > 0) { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if ((cmp)(elm, __tmp) > 0){ \
- SPLAY_ROTATE_LEFT(head, __tmp, field); \
- if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
- break; \
- } \
- SPLAY_LINKRIGHT(head, __left, field); \
- } \
- } \
- SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
-} \
- \
-/* Splay with either the minimum or the maximum element \
- * Used to find minimum or maximum element in tree. \
- */ \
-void name##_SPLAY_MINMAX(struct name *head, int __comp) \
-{ \
- struct type __node, *__left, *__right, *__tmp; \
- \
- SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
- __left = __right = &__node; \
- \
- while (1) { \
- if (__comp < 0) { \
- __tmp = SPLAY_LEFT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if (__comp < 0){ \
- SPLAY_ROTATE_RIGHT(head, __tmp, field); \
- if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
- break; \
- } \
- SPLAY_LINKLEFT(head, __right, field); \
- } else if (__comp > 0) { \
- __tmp = SPLAY_RIGHT((head)->sph_root, field); \
- if (__tmp == NULL) \
- break; \
- if (__comp > 0) { \
- SPLAY_ROTATE_LEFT(head, __tmp, field); \
- if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
- break; \
- } \
- SPLAY_LINKRIGHT(head, __left, field); \
- } \
- } \
- SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
-}
-
-#define SPLAY_NEGINF -1
-#define SPLAY_INF 1
-
-#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
-#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
-#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
-#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
-#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
- : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
-#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
- : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
-
-#define SPLAY_FOREACH(x, name, head) \
- for ((x) = SPLAY_MIN(name, head); \
- (x) != NULL; \
- (x) = SPLAY_NEXT(name, head, x))
-
-/* Macros that define a red-black tree */
-#define RB_HEAD(name, type) \
-struct name { \
- struct type *rbh_root; /* root of the tree */ \
-}
-
-#define RB_INITIALIZER(root) \
- { NULL }
-
-#define RB_INIT(root) do { \
- (root)->rbh_root = NULL; \
-} while (/*CONSTCOND*/ 0)
-
-#define RB_BLACK 0
-#define RB_RED 1
-#define RB_ENTRY(type) \
-struct { \
- struct type *rbe_left; /* left element */ \
- struct type *rbe_right; /* right element */ \
- struct type *rbe_parent; /* parent element */ \
- int rbe_color; /* node color */ \
-}
-
-#define RB_LEFT(elm, field) (elm)->field.rbe_left
-#define RB_RIGHT(elm, field) (elm)->field.rbe_right
-#define RB_PARENT(elm, field) (elm)->field.rbe_parent
-#define RB_COLOR(elm, field) (elm)->field.rbe_color
-#define RB_ROOT(head) (head)->rbh_root
-#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
-
-#define RB_SET(elm, parent, field) do { \
- RB_PARENT(elm, field) = parent; \
- RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
- RB_COLOR(elm, field) = RB_RED; \
-} while (/*CONSTCOND*/ 0)
-
-#define RB_SET_BLACKRED(black, red, field) do { \
- RB_COLOR(black, field) = RB_BLACK; \
- RB_COLOR(red, field) = RB_RED; \
-} while (/*CONSTCOND*/ 0)
-
-#ifndef RB_AUGMENT
-#define RB_AUGMENT(x) do {} while (0)
-#endif
-
-#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
- (tmp) = RB_RIGHT(elm, field); \
- if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
- RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
- } \
- RB_AUGMENT(elm); \
- if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
- if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
- RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
- else \
- RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
- } else \
- (head)->rbh_root = (tmp); \
- RB_LEFT(tmp, field) = (elm); \
- RB_PARENT(elm, field) = (tmp); \
- RB_AUGMENT(tmp); \
- if ((RB_PARENT(tmp, field))) \
- RB_AUGMENT(RB_PARENT(tmp, field)); \
-} while (/*CONSTCOND*/ 0)
-
-#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
- (tmp) = RB_LEFT(elm, field); \
- if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
- RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
- } \
- RB_AUGMENT(elm); \
- if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
- if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
- RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
- else \
- RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
- } else \
- (head)->rbh_root = (tmp); \
- RB_RIGHT(tmp, field) = (elm); \
- RB_PARENT(elm, field) = (tmp); \
- RB_AUGMENT(tmp); \
- if ((RB_PARENT(tmp, field))) \
- RB_AUGMENT(RB_PARENT(tmp, field)); \
-} while (/*CONSTCOND*/ 0)
-
-/* Generates prototypes and inline functions */
-#define RB_PROTOTYPE(name, type, field, cmp) \
- RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
-#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
- RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
-#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
-attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
-attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
-attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
-attr struct type *name##_RB_INSERT(struct name *, struct type *); \
-attr struct type *name##_RB_FIND(struct name *, struct type *); \
-attr struct type *name##_RB_NFIND(struct name *, struct type *); \
-attr struct type *name##_RB_NEXT(struct type *); \
-attr struct type *name##_RB_PREV(struct type *); \
-attr struct type *name##_RB_MINMAX(struct name *, int); \
- \
-
-/* Main rb operation.
- * Moves node close to the key of elm to top
- */
-#define RB_GENERATE(name, type, field, cmp) \
- RB_GENERATE_INTERNAL(name, type, field, cmp,)
-#define RB_GENERATE_STATIC(name, type, field, cmp) \
- RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
-#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
-attr void \
-name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
-{ \
- struct type *parent, *gparent, *tmp; \
- while ((parent = RB_PARENT(elm, field)) != NULL && \
- RB_COLOR(parent, field) == RB_RED) { \
- gparent = RB_PARENT(parent, field); \
- if (parent == RB_LEFT(gparent, field)) { \
- tmp = RB_RIGHT(gparent, field); \
- if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
- RB_COLOR(tmp, field) = RB_BLACK; \
- RB_SET_BLACKRED(parent, gparent, field); \
- elm = gparent; \
- continue; \
- } \
- if (RB_RIGHT(parent, field) == elm) { \
- RB_ROTATE_LEFT(head, parent, tmp, field); \
- tmp = parent; \
- parent = elm; \
- elm = tmp; \
- } \
- RB_SET_BLACKRED(parent, gparent, field); \
- RB_ROTATE_RIGHT(head, gparent, tmp, field); \
- } else { \
- tmp = RB_LEFT(gparent, field); \
- if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
- RB_COLOR(tmp, field) = RB_BLACK; \
- RB_SET_BLACKRED(parent, gparent, field); \
- elm = gparent; \
- continue; \
- } \
- if (RB_LEFT(parent, field) == elm) { \
- RB_ROTATE_RIGHT(head, parent, tmp, field); \
- tmp = parent; \
- parent = elm; \
- elm = tmp; \
- } \
- RB_SET_BLACKRED(parent, gparent, field); \
- RB_ROTATE_LEFT(head, gparent, tmp, field); \
- } \
- } \
- RB_COLOR(head->rbh_root, field) = RB_BLACK; \
-} \
- \
-attr void \
-name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
- struct type *elm) \
-{ \
- struct type *tmp; \
- while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
- elm != RB_ROOT(head)) { \
- if (RB_LEFT(parent, field) == elm) { \
- tmp = RB_RIGHT(parent, field); \
- if (RB_COLOR(tmp, field) == RB_RED) { \
- RB_SET_BLACKRED(tmp, parent, field); \
- RB_ROTATE_LEFT(head, parent, tmp, field); \
- tmp = RB_RIGHT(parent, field); \
- } \
- if ((RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
- (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
- RB_COLOR(tmp, field) = RB_RED; \
- elm = parent; \
- parent = RB_PARENT(elm, field); \
- } else { \
- if (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
- struct type *oleft; \
- if ((oleft = RB_LEFT(tmp, field)) \
- != NULL) \
- RB_COLOR(oleft, field) = RB_BLACK; \
- RB_COLOR(tmp, field) = RB_RED; \
- RB_ROTATE_RIGHT(head, tmp, oleft, field); \
- tmp = RB_RIGHT(parent, field); \
- } \
- RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
- RB_COLOR(parent, field) = RB_BLACK; \
- if (RB_RIGHT(tmp, field)) \
- RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
- RB_ROTATE_LEFT(head, parent, tmp, field); \
- elm = RB_ROOT(head); \
- break; \
- } \
- } else { \
- tmp = RB_LEFT(parent, field); \
- if (RB_COLOR(tmp, field) == RB_RED) { \
- RB_SET_BLACKRED(tmp, parent, field); \
- RB_ROTATE_RIGHT(head, parent, tmp, field); \
- tmp = RB_LEFT(parent, field); \
- } \
- if ((RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
- (RB_RIGHT(tmp, field) == NULL || \
- RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
- RB_COLOR(tmp, field) = RB_RED; \
- elm = parent; \
- parent = RB_PARENT(elm, field); \
- } else { \
- if (RB_LEFT(tmp, field) == NULL || \
- RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
- struct type *oright; \
- if ((oright = RB_RIGHT(tmp, field)) \
- != NULL) \
- RB_COLOR(oright, field) = RB_BLACK; \
- RB_COLOR(tmp, field) = RB_RED; \
- RB_ROTATE_LEFT(head, tmp, oright, field); \
- tmp = RB_LEFT(parent, field); \
- } \
- RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
- RB_COLOR(parent, field) = RB_BLACK; \
- if (RB_LEFT(tmp, field)) \
- RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
- RB_ROTATE_RIGHT(head, parent, tmp, field); \
- elm = RB_ROOT(head); \
- break; \
- } \
- } \
- } \
- if (elm) \
- RB_COLOR(elm, field) = RB_BLACK; \
-} \
- \
-attr struct type * \
-name##_RB_REMOVE(struct name *head, struct type *elm) \
-{ \
- struct type *child, *parent, *old = elm; \
- int color; \
- if (RB_LEFT(elm, field) == NULL) \
- child = RB_RIGHT(elm, field); \
- else if (RB_RIGHT(elm, field) == NULL) \
- child = RB_LEFT(elm, field); \
- else { \
- struct type *left; \
- elm = RB_RIGHT(elm, field); \
- while ((left = RB_LEFT(elm, field)) != NULL) \
- elm = left; \
- child = RB_RIGHT(elm, field); \
- parent = RB_PARENT(elm, field); \
- color = RB_COLOR(elm, field); \
- if (child) \
- RB_PARENT(child, field) = parent; \
- if (parent) { \
- if (RB_LEFT(parent, field) == elm) \
- RB_LEFT(parent, field) = child; \
- else \
- RB_RIGHT(parent, field) = child; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = child; \
- if (RB_PARENT(elm, field) == old) \
- parent = elm; \
- (elm)->field = (old)->field; \
- if (RB_PARENT(old, field)) { \
- if (RB_LEFT(RB_PARENT(old, field), field) == old) \
- RB_LEFT(RB_PARENT(old, field), field) = elm; \
- else \
- RB_RIGHT(RB_PARENT(old, field), field) = elm; \
- RB_AUGMENT(RB_PARENT(old, field)); \
- } else \
- RB_ROOT(head) = elm; \
- RB_PARENT(RB_LEFT(old, field), field) = elm; \
- if (RB_RIGHT(old, field)) \
- RB_PARENT(RB_RIGHT(old, field), field) = elm; \
- if (parent) { \
- left = parent; \
- do { \
- RB_AUGMENT(left); \
- } while ((left = RB_PARENT(left, field)) != NULL); \
- } \
- goto color; \
- } \
- parent = RB_PARENT(elm, field); \
- color = RB_COLOR(elm, field); \
- if (child) \
- RB_PARENT(child, field) = parent; \
- if (parent) { \
- if (RB_LEFT(parent, field) == elm) \
- RB_LEFT(parent, field) = child; \
- else \
- RB_RIGHT(parent, field) = child; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = child; \
-color: \
- if (color == RB_BLACK) \
- name##_RB_REMOVE_COLOR(head, parent, child); \
- return (old); \
-} \
- \
-/* Inserts a node into the RB tree */ \
-attr struct type * \
-name##_RB_INSERT(struct name *head, struct type *elm) \
-{ \
- struct type *tmp; \
- struct type *parent = NULL; \
- int comp = 0; \
- tmp = RB_ROOT(head); \
- while (tmp) { \
- parent = tmp; \
- comp = (cmp)(elm, parent); \
- if (comp < 0) \
- tmp = RB_LEFT(tmp, field); \
- else if (comp > 0) \
- tmp = RB_RIGHT(tmp, field); \
- else \
- return (tmp); \
- } \
- RB_SET(elm, parent, field); \
- if (parent != NULL) { \
- if (comp < 0) \
- RB_LEFT(parent, field) = elm; \
- else \
- RB_RIGHT(parent, field) = elm; \
- RB_AUGMENT(parent); \
- } else \
- RB_ROOT(head) = elm; \
- name##_RB_INSERT_COLOR(head, elm); \
- return (NULL); \
-} \
- \
-/* Finds the node with the same key as elm */ \
-attr struct type * \
-name##_RB_FIND(struct name *head, struct type *elm) \
-{ \
- struct type *tmp = RB_ROOT(head); \
- int comp; \
- while (tmp) { \
- comp = cmp(elm, tmp); \
- if (comp < 0) \
- tmp = RB_LEFT(tmp, field); \
- else if (comp > 0) \
- tmp = RB_RIGHT(tmp, field); \
- else \
- return (tmp); \
- } \
- return (NULL); \
-} \
- \
-/* Finds the first node greater than or equal to the search key */ \
-attr struct type * \
-name##_RB_NFIND(struct name *head, struct type *elm) \
-{ \
- struct type *tmp = RB_ROOT(head); \
- struct type *res = NULL; \
- int comp; \
- while (tmp) { \
- comp = cmp(elm, tmp); \
- if (comp < 0) { \
- res = tmp; \
- tmp = RB_LEFT(tmp, field); \
- } \
- else if (comp > 0) \
- tmp = RB_RIGHT(tmp, field); \
- else \
- return (tmp); \
- } \
- return (res); \
-} \
- \
-/* ARGSUSED */ \
-attr struct type * \
-name##_RB_NEXT(struct type *elm) \
-{ \
- if (RB_RIGHT(elm, field)) { \
- elm = RB_RIGHT(elm, field); \
- while (RB_LEFT(elm, field)) \
- elm = RB_LEFT(elm, field); \
- } else { \
- if (RB_PARENT(elm, field) && \
- (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
- elm = RB_PARENT(elm, field); \
- else { \
- while (RB_PARENT(elm, field) && \
- (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
- elm = RB_PARENT(elm, field); \
- elm = RB_PARENT(elm, field); \
- } \
- } \
- return (elm); \
-} \
- \
-/* ARGSUSED */ \
-attr struct type * \
-name##_RB_PREV(struct type *elm) \
-{ \
- if (RB_LEFT(elm, field)) { \
- elm = RB_LEFT(elm, field); \
- while (RB_RIGHT(elm, field)) \
- elm = RB_RIGHT(elm, field); \
- } else { \
- if (RB_PARENT(elm, field) && \
- (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
- elm = RB_PARENT(elm, field); \
- else { \
- while (RB_PARENT(elm, field) && \
- (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
- elm = RB_PARENT(elm, field); \
- elm = RB_PARENT(elm, field); \
- } \
- } \
- return (elm); \
-} \
- \
-attr struct type * \
-name##_RB_MINMAX(struct name *head, int val) \
-{ \
- struct type *tmp = RB_ROOT(head); \
- struct type *parent = NULL; \
- while (tmp) { \
- parent = tmp; \
- if (val < 0) \
- tmp = RB_LEFT(tmp, field); \
- else \
- tmp = RB_RIGHT(tmp, field); \
- } \
- return (parent); \
-}
-
-#define RB_NEGINF -1
-#define RB_INF 1
-
-#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
-#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
-#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
-#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
-#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
-#define RB_PREV(name, x, y) name##_RB_PREV(y)
-#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
-#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
-
-#define RB_FOREACH(x, name, head) \
- for ((x) = RB_MIN(name, head); \
- (x) != NULL; \
- (x) = name##_RB_NEXT(x))
-
-#define RB_FOREACH_FROM(x, name, y) \
- for ((x) = (y); \
- ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
- (x) = (y))
-
-#define RB_FOREACH_SAFE(x, name, head, y) \
- for ((x) = RB_MIN(name, head); \
- ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
- (x) = (y))
-
-#define RB_FOREACH_REVERSE(x, name, head) \
- for ((x) = RB_MAX(name, head); \
- (x) != NULL; \
- (x) = name##_RB_PREV(x))
-
-#define RB_FOREACH_REVERSE_FROM(x, name, y) \
- for ((x) = (y); \
- ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
- (x) = (y))
-
-#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
- for ((x) = RB_MAX(name, head); \
- ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
- (x) = (y))
-
-#endif /* UV_TREE_H_ */
diff --git a/wpiutil/src/main/native/libuv/include/uv/unix.h b/wpiutil/src/main/native/libuv/include/uv/unix.h
deleted file mode 100644
index 504bab7..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/unix.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_UNIX_H
-#define UV_UNIX_H
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <arpa/inet.h>
-#include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
-
-#include <termios.h>
-#include <pwd.h>
-
-#if !defined(__MVS__)
-#include <semaphore.h>
-#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
-#endif
-#include <pthread.h>
-#include <signal.h>
-
-#include "uv/threadpool.h"
-
-#if defined(__linux__)
-# include "uv/linux.h"
-#elif defined(__APPLE__)
-# include "uv/darwin.h"
-#elif defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || \
- defined(__OpenBSD__) || \
- defined(__NetBSD__)
-# include "uv/bsd.h"
-#elif defined(__PASE__) || \
- defined(__CYGWIN__) || \
- defined(__MSYS__) || \
- defined(__GNU__)
-# include "uv/posix.h"
-#elif defined(__HAIKU__)
-# include "uv/posix.h"
-#endif
-
-#ifndef NI_MAXHOST
-# define NI_MAXHOST 1025
-#endif
-
-#ifndef NI_MAXSERV
-# define NI_MAXSERV 32
-#endif
-
-#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
-# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
-#endif
-
-struct uv__io_s;
-struct uv_loop_s;
-
-typedef void (*uv__io_cb)(struct uv_loop_s* loop,
- struct uv__io_s* w,
- unsigned int events);
-typedef struct uv__io_s uv__io_t;
-
-struct uv__io_s {
- uv__io_cb cb;
- void* pending_queue[2];
- void* watcher_queue[2];
- unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
- unsigned int events; /* Current event mask. */
- int fd;
- UV_IO_PRIVATE_PLATFORM_FIELDS
-};
-
-#ifndef UV_PLATFORM_SEM_T
-# define UV_PLATFORM_SEM_T sem_t
-#endif
-
-#ifndef UV_PLATFORM_LOOP_FIELDS
-# define UV_PLATFORM_LOOP_FIELDS /* empty */
-#endif
-
-#ifndef UV_PLATFORM_FS_EVENT_FIELDS
-# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
-#endif
-
-#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS
-# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */
-#endif
-
-/* Note: May be cast to struct iovec. See writev(2). */
-typedef struct uv_buf_t {
- char* base;
- size_t len;
-} uv_buf_t;
-
-typedef int uv_file;
-typedef int uv_os_sock_t;
-typedef int uv_os_fd_t;
-typedef pid_t uv_pid_t;
-
-#define UV_ONCE_INIT PTHREAD_ONCE_INIT
-
-typedef pthread_once_t uv_once_t;
-typedef pthread_t uv_thread_t;
-typedef pthread_mutex_t uv_mutex_t;
-typedef pthread_rwlock_t uv_rwlock_t;
-typedef UV_PLATFORM_SEM_T uv_sem_t;
-typedef pthread_cond_t uv_cond_t;
-typedef pthread_key_t uv_key_t;
-
-/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
-#if defined(_AIX) || \
- defined(__OpenBSD__) || \
- !defined(PTHREAD_BARRIER_SERIAL_THREAD)
-/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */
-struct _uv_barrier {
- uv_mutex_t mutex;
- uv_cond_t cond;
- unsigned threshold;
- unsigned in;
- unsigned out;
-};
-
-typedef struct {
- struct _uv_barrier* b;
-# if defined(PTHREAD_BARRIER_SERIAL_THREAD)
- /* TODO(bnoordhuis) Remove padding in v2. */
- char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)];
-# endif
-} uv_barrier_t;
-#else
-typedef pthread_barrier_t uv_barrier_t;
-#endif
-
-/* Platform-specific definitions for uv_spawn support. */
-typedef gid_t uv_gid_t;
-typedef uid_t uv_uid_t;
-
-typedef struct dirent uv__dirent_t;
-
-#define UV_DIR_PRIVATE_FIELDS \
- DIR* dir;
-
-#if defined(DT_UNKNOWN)
-# define HAVE_DIRENT_TYPES
-# if defined(DT_REG)
-# define UV__DT_FILE DT_REG
-# else
-# define UV__DT_FILE -1
-# endif
-# if defined(DT_DIR)
-# define UV__DT_DIR DT_DIR
-# else
-# define UV__DT_DIR -2
-# endif
-# if defined(DT_LNK)
-# define UV__DT_LINK DT_LNK
-# else
-# define UV__DT_LINK -3
-# endif
-# if defined(DT_FIFO)
-# define UV__DT_FIFO DT_FIFO
-# else
-# define UV__DT_FIFO -4
-# endif
-# if defined(DT_SOCK)
-# define UV__DT_SOCKET DT_SOCK
-# else
-# define UV__DT_SOCKET -5
-# endif
-# if defined(DT_CHR)
-# define UV__DT_CHAR DT_CHR
-# else
-# define UV__DT_CHAR -6
-# endif
-# if defined(DT_BLK)
-# define UV__DT_BLOCK DT_BLK
-# else
-# define UV__DT_BLOCK -7
-# endif
-#endif
-
-/* Platform-specific definitions for uv_dlopen support. */
-#define UV_DYNAMIC /* empty */
-
-typedef struct {
- void* handle;
- char* errmsg;
-} uv_lib_t;
-
-#define UV_LOOP_PRIVATE_FIELDS \
- unsigned long flags; \
- int backend_fd; \
- void* pending_queue[2]; \
- void* watcher_queue[2]; \
- void** watchers; \
- unsigned int nwatchers; \
- unsigned int nfds; \
- void* wq[2]; \
- uv_mutex_t wq_mutex; \
- uv_async_t wq_async; \
- uv_rwlock_t cloexec_lock; \
- uv_handle_t* closing_handles; \
- void* process_handles[2]; \
- void* prepare_handles[2]; \
- void* check_handles[2]; \
- void* idle_handles[2]; \
- void* async_handles[2]; \
- void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
- uv__io_t async_io_watcher; \
- int async_wfd; \
- struct { \
- void* min; \
- unsigned int nelts; \
- } timer_heap; \
- uint64_t timer_counter; \
- uint64_t time; \
- int signal_pipefd[2]; \
- uv__io_t signal_io_watcher; \
- uv_signal_t child_watcher; \
- int emfile_fd; \
- UV_PLATFORM_LOOP_FIELDS \
-
-#define UV_REQ_TYPE_PRIVATE /* empty */
-
-#define UV_REQ_PRIVATE_FIELDS /* empty */
-
-#define UV_PRIVATE_REQ_TYPES /* empty */
-
-#define UV_WRITE_PRIVATE_FIELDS \
- void* queue[2]; \
- unsigned int write_index; \
- uv_buf_t* bufs; \
- unsigned int nbufs; \
- int error; \
- uv_buf_t bufsml[4]; \
-
-#define UV_CONNECT_PRIVATE_FIELDS \
- void* queue[2]; \
-
-#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
-
-#define UV_UDP_SEND_PRIVATE_FIELDS \
- void* queue[2]; \
- struct sockaddr_storage addr; \
- unsigned int nbufs; \
- uv_buf_t* bufs; \
- ssize_t status; \
- uv_udp_send_cb send_cb; \
- uv_buf_t bufsml[4]; \
-
-#define UV_HANDLE_PRIVATE_FIELDS \
- uv_handle_t* next_closing; \
- unsigned int flags; \
-
-#define UV_STREAM_PRIVATE_FIELDS \
- uv_connect_t *connect_req; \
- uv_shutdown_t *shutdown_req; \
- uv__io_t io_watcher; \
- void* write_queue[2]; \
- void* write_completed_queue[2]; \
- uv_connection_cb connection_cb; \
- int delayed_error; \
- int accepted_fd; \
- void* queued_fds; \
- UV_STREAM_PRIVATE_PLATFORM_FIELDS \
-
-#define UV_TCP_PRIVATE_FIELDS /* empty */
-
-#define UV_UDP_PRIVATE_FIELDS \
- uv_alloc_cb alloc_cb; \
- uv_udp_recv_cb recv_cb; \
- uv__io_t io_watcher; \
- void* write_queue[2]; \
- void* write_completed_queue[2]; \
-
-#define UV_PIPE_PRIVATE_FIELDS \
- const char* pipe_fname; /* strdup'ed */
-
-#define UV_POLL_PRIVATE_FIELDS \
- uv__io_t io_watcher;
-
-#define UV_PREPARE_PRIVATE_FIELDS \
- uv_prepare_cb prepare_cb; \
- void* queue[2]; \
-
-#define UV_CHECK_PRIVATE_FIELDS \
- uv_check_cb check_cb; \
- void* queue[2]; \
-
-#define UV_IDLE_PRIVATE_FIELDS \
- uv_idle_cb idle_cb; \
- void* queue[2]; \
-
-#define UV_ASYNC_PRIVATE_FIELDS \
- uv_async_cb async_cb; \
- void* queue[2]; \
- int pending; \
-
-#define UV_TIMER_PRIVATE_FIELDS \
- uv_timer_cb timer_cb; \
- void* heap_node[3]; \
- uint64_t timeout; \
- uint64_t repeat; \
- uint64_t start_id;
-
-#define UV_GETADDRINFO_PRIVATE_FIELDS \
- struct uv__work work_req; \
- uv_getaddrinfo_cb cb; \
- struct addrinfo* hints; \
- char* hostname; \
- char* service; \
- struct addrinfo* addrinfo; \
- int retcode;
-
-#define UV_GETNAMEINFO_PRIVATE_FIELDS \
- struct uv__work work_req; \
- uv_getnameinfo_cb getnameinfo_cb; \
- struct sockaddr_storage storage; \
- int flags; \
- char host[NI_MAXHOST]; \
- char service[NI_MAXSERV]; \
- int retcode;
-
-#define UV_PROCESS_PRIVATE_FIELDS \
- void* queue[2]; \
- int status; \
-
-#define UV_FS_PRIVATE_FIELDS \
- const char *new_path; \
- uv_file file; \
- int flags; \
- mode_t mode; \
- unsigned int nbufs; \
- uv_buf_t* bufs; \
- off_t off; \
- uv_uid_t uid; \
- uv_gid_t gid; \
- double atime; \
- double mtime; \
- struct uv__work work_req; \
- uv_buf_t bufsml[4]; \
-
-#define UV_WORK_PRIVATE_FIELDS \
- struct uv__work work_req;
-
-#define UV_TTY_PRIVATE_FIELDS \
- struct termios orig_termios; \
- int mode;
-
-#define UV_SIGNAL_PRIVATE_FIELDS \
- /* RB_ENTRY(uv_signal_s) tree_entry; */ \
- struct { \
- struct uv_signal_s* rbe_left; \
- struct uv_signal_s* rbe_right; \
- struct uv_signal_s* rbe_parent; \
- int rbe_color; \
- } tree_entry; \
- /* Use two counters here so we don have to fiddle with atomics. */ \
- unsigned int caught_signals; \
- unsigned int dispatched_signals;
-
-#define UV_FS_EVENT_PRIVATE_FIELDS \
- uv_fs_event_cb cb; \
- UV_PLATFORM_FS_EVENT_FIELDS \
-
-/* fs open() flags supported on this platform: */
-#if defined(O_APPEND)
-# define UV_FS_O_APPEND O_APPEND
-#else
-# define UV_FS_O_APPEND 0
-#endif
-#if defined(O_CREAT)
-# define UV_FS_O_CREAT O_CREAT
-#else
-# define UV_FS_O_CREAT 0
-#endif
-#if defined(O_DIRECT)
-# define UV_FS_O_DIRECT O_DIRECT
-#else
-# define UV_FS_O_DIRECT 0
-#endif
-#if defined(O_DIRECTORY)
-# define UV_FS_O_DIRECTORY O_DIRECTORY
-#else
-# define UV_FS_O_DIRECTORY 0
-#endif
-#if defined(O_DSYNC)
-# define UV_FS_O_DSYNC O_DSYNC
-#else
-# define UV_FS_O_DSYNC 0
-#endif
-#if defined(O_EXCL)
-# define UV_FS_O_EXCL O_EXCL
-#else
-# define UV_FS_O_EXCL 0
-#endif
-#if defined(O_EXLOCK)
-# define UV_FS_O_EXLOCK O_EXLOCK
-#else
-# define UV_FS_O_EXLOCK 0
-#endif
-#if defined(O_NOATIME)
-# define UV_FS_O_NOATIME O_NOATIME
-#else
-# define UV_FS_O_NOATIME 0
-#endif
-#if defined(O_NOCTTY)
-# define UV_FS_O_NOCTTY O_NOCTTY
-#else
-# define UV_FS_O_NOCTTY 0
-#endif
-#if defined(O_NOFOLLOW)
-# define UV_FS_O_NOFOLLOW O_NOFOLLOW
-#else
-# define UV_FS_O_NOFOLLOW 0
-#endif
-#if defined(O_NONBLOCK)
-# define UV_FS_O_NONBLOCK O_NONBLOCK
-#else
-# define UV_FS_O_NONBLOCK 0
-#endif
-#if defined(O_RDONLY)
-# define UV_FS_O_RDONLY O_RDONLY
-#else
-# define UV_FS_O_RDONLY 0
-#endif
-#if defined(O_RDWR)
-# define UV_FS_O_RDWR O_RDWR
-#else
-# define UV_FS_O_RDWR 0
-#endif
-#if defined(O_SYMLINK)
-# define UV_FS_O_SYMLINK O_SYMLINK
-#else
-# define UV_FS_O_SYMLINK 0
-#endif
-#if defined(O_SYNC)
-# define UV_FS_O_SYNC O_SYNC
-#else
-# define UV_FS_O_SYNC 0
-#endif
-#if defined(O_TRUNC)
-# define UV_FS_O_TRUNC O_TRUNC
-#else
-# define UV_FS_O_TRUNC 0
-#endif
-#if defined(O_WRONLY)
-# define UV_FS_O_WRONLY O_WRONLY
-#else
-# define UV_FS_O_WRONLY 0
-#endif
-
-/* fs open() flags supported on other platforms: */
-#define UV_FS_O_RANDOM 0
-#define UV_FS_O_SHORT_LIVED 0
-#define UV_FS_O_SEQUENTIAL 0
-#define UV_FS_O_TEMPORARY 0
-
-#endif /* UV_UNIX_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/version.h b/wpiutil/src/main/native/libuv/include/uv/version.h
deleted file mode 100644
index bf992d2..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/version.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_VERSION_H
-#define UV_VERSION_H
-
- /*
- * Versions with the same major number are ABI stable. API is allowed to
- * evolve between minor releases, but only in a backwards compatible way.
- * Make sure you update the -soname directives in configure.ac
- * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
- * not UV_VERSION_PATCH.)
- */
-
-#define UV_VERSION_MAJOR 1
-#define UV_VERSION_MINOR 30
-#define UV_VERSION_PATCH 1
-#define UV_VERSION_IS_RELEASE 1
-#define UV_VERSION_SUFFIX ""
-
-#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
- (UV_VERSION_MINOR << 8) | \
- (UV_VERSION_PATCH))
-
-#endif /* UV_VERSION_H */
diff --git a/wpiutil/src/main/native/libuv/include/uv/win.h b/wpiutil/src/main/native/libuv/include/uv/win.h
deleted file mode 100644
index ca5242f..0000000
--- a/wpiutil/src/main/native/libuv/include/uv/win.h
+++ /dev/null
@@ -1,691 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef _WIN32_WINNT
-# define _WIN32_WINNT 0x0600
-#endif
-
-#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
-typedef intptr_t ssize_t;
-# define SSIZE_MAX INTPTR_MAX
-# define _SSIZE_T_
-# define _SSIZE_T_DEFINED
-#endif
-
-#include <winsock2.h>
-
-#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
-typedef struct pollfd {
- SOCKET fd;
- short events;
- short revents;
-} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
-#endif
-
-#ifndef LOCALE_INVARIANT
-# define LOCALE_INVARIANT 0x007f
-#endif
-
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-
-#include <process.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include <stdint.h>
-
-#include "uv/tree.h"
-#include "uv/threadpool.h"
-
-#define MAX_PIPENAME_LEN 256
-
-#ifndef S_IFLNK
-# define S_IFLNK 0xA000
-#endif
-
-/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
- * the following signals already:
- *
- * #define SIGINT 2
- * #define SIGILL 4
- * #define SIGABRT_COMPAT 6
- * #define SIGFPE 8
- * #define SIGSEGV 11
- * #define SIGTERM 15
- * #define SIGBREAK 21
- * #define SIGABRT 22
- *
- * The additional signals have values that are common on other Unix
- * variants (Linux and Darwin)
- */
-#define SIGHUP 1
-#define SIGKILL 9
-#define SIGWINCH 28
-
-/* Redefine NSIG to take SIGWINCH into consideration */
-#if defined(NSIG) && NSIG <= SIGWINCH
-# undef NSIG
-#endif
-#ifndef NSIG
-# define NSIG SIGWINCH + 1
-#endif
-
-/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many unix-like
- * platforms. However MinGW doesn't define it, so we do. */
-#ifndef SIGABRT_COMPAT
-# define SIGABRT_COMPAT 6
-#endif
-
-/*
- * Guids and typedefs for winsock extension functions
- * Mingw32 doesn't have these :-(
- */
-#ifndef WSAID_ACCEPTEX
-# define WSAID_ACCEPTEX \
- {0xb5367df1, 0xcbac, 0x11cf, \
- {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
-
-# define WSAID_CONNECTEX \
- {0x25a207b9, 0xddf3, 0x4660, \
- {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
-
-# define WSAID_GETACCEPTEXSOCKADDRS \
- {0xb5367df2, 0xcbac, 0x11cf, \
- {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
-
-# define WSAID_DISCONNECTEX \
- {0x7fda2e11, 0x8630, 0x436f, \
- {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
-
-# define WSAID_TRANSMITFILE \
- {0xb5367df0, 0xcbac, 0x11cf, \
- {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
-
- typedef BOOL (PASCAL *LPFN_ACCEPTEX)
- (SOCKET sListenSocket,
- SOCKET sAcceptSocket,
- PVOID lpOutputBuffer,
- DWORD dwReceiveDataLength,
- DWORD dwLocalAddressLength,
- DWORD dwRemoteAddressLength,
- LPDWORD lpdwBytesReceived,
- LPOVERLAPPED lpOverlapped);
-
- typedef BOOL (PASCAL *LPFN_CONNECTEX)
- (SOCKET s,
- const struct sockaddr* name,
- int namelen,
- PVOID lpSendBuffer,
- DWORD dwSendDataLength,
- LPDWORD lpdwBytesSent,
- LPOVERLAPPED lpOverlapped);
-
- typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS)
- (PVOID lpOutputBuffer,
- DWORD dwReceiveDataLength,
- DWORD dwLocalAddressLength,
- DWORD dwRemoteAddressLength,
- LPSOCKADDR* LocalSockaddr,
- LPINT LocalSockaddrLength,
- LPSOCKADDR* RemoteSockaddr,
- LPINT RemoteSockaddrLength);
-
- typedef BOOL (PASCAL *LPFN_DISCONNECTEX)
- (SOCKET hSocket,
- LPOVERLAPPED lpOverlapped,
- DWORD dwFlags,
- DWORD reserved);
-
- typedef BOOL (PASCAL *LPFN_TRANSMITFILE)
- (SOCKET hSocket,
- HANDLE hFile,
- DWORD nNumberOfBytesToWrite,
- DWORD nNumberOfBytesPerSend,
- LPOVERLAPPED lpOverlapped,
- LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
- DWORD dwFlags);
-
- typedef PVOID RTL_SRWLOCK;
- typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
-#endif
-
-typedef int (WSAAPI* LPFN_WSARECV)
- (SOCKET socket,
- LPWSABUF buffers,
- DWORD buffer_count,
- LPDWORD bytes,
- LPDWORD flags,
- LPWSAOVERLAPPED overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
-
-typedef int (WSAAPI* LPFN_WSARECVFROM)
- (SOCKET socket,
- LPWSABUF buffers,
- DWORD buffer_count,
- LPDWORD bytes,
- LPDWORD flags,
- struct sockaddr* addr,
- LPINT addr_len,
- LPWSAOVERLAPPED overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
-
-#pragma warning(push)
-#pragma warning(disable : 28251)
-
-#ifndef _NTDEF_
- typedef LONG NTSTATUS;
- typedef NTSTATUS *PNTSTATUS;
-#endif
-
-#pragma warning(pop)
-
-#ifndef RTL_CONDITION_VARIABLE_INIT
- typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
-#endif
-
-typedef struct _AFD_POLL_HANDLE_INFO {
- HANDLE Handle;
- ULONG Events;
- NTSTATUS Status;
-} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
-
-typedef struct _AFD_POLL_INFO {
- LARGE_INTEGER Timeout;
- ULONG NumberOfHandles;
- ULONG Exclusive;
- AFD_POLL_HANDLE_INFO Handles[1];
-} AFD_POLL_INFO, *PAFD_POLL_INFO;
-
-#define UV_MSAFD_PROVIDER_COUNT 3
-
-
-/**
- * It should be possible to cast uv_buf_t[] to WSABUF[]
- * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx
- */
-typedef struct uv_buf_t {
- ULONG len;
- char* base;
-} uv_buf_t;
-
-typedef int uv_file;
-typedef SOCKET uv_os_sock_t;
-typedef HANDLE uv_os_fd_t;
-typedef int uv_pid_t;
-
-typedef HANDLE uv_thread_t;
-
-typedef HANDLE uv_sem_t;
-
-typedef CRITICAL_SECTION uv_mutex_t;
-
-/* This condition variable implementation is based on the SetEvent solution
- * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
- * We could not use the SignalObjectAndWait solution (section 3.4) because
- * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
- * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
- */
-
-typedef union {
- CONDITION_VARIABLE cond_var;
- struct {
- unsigned int waiters_count;
- CRITICAL_SECTION waiters_count_lock;
- HANDLE signal_event;
- HANDLE broadcast_event;
- } unused_; /* TODO: retained for ABI compatibility; remove me in v2.x. */
-} uv_cond_t;
-
-typedef union {
- struct {
- unsigned int num_readers_;
- CRITICAL_SECTION num_readers_lock_;
- HANDLE write_semaphore_;
- } state_;
- /* TODO: remove me in v2.x. */
- struct {
- SRWLOCK unused_;
- } unused1_;
- /* TODO: remove me in v2.x. */
- struct {
- uv_mutex_t unused1_;
- uv_mutex_t unused2_;
- } unused2_;
-} uv_rwlock_t;
-
-typedef struct {
- unsigned int n;
- unsigned int count;
- uv_mutex_t mutex;
- uv_sem_t turnstile1;
- uv_sem_t turnstile2;
-} uv_barrier_t;
-
-typedef struct {
- DWORD tls_index;
-} uv_key_t;
-
-#define UV_ONCE_INIT { 0, NULL }
-
-typedef struct uv_once_s {
- unsigned char ran;
- HANDLE event;
-} uv_once_t;
-
-/* Platform-specific definitions for uv_spawn support. */
-typedef unsigned char uv_uid_t;
-typedef unsigned char uv_gid_t;
-
-typedef struct uv__dirent_s {
- int d_type;
- char d_name[1];
-} uv__dirent_t;
-
-#define UV_DIR_PRIVATE_FIELDS \
- HANDLE dir_handle; \
- WIN32_FIND_DATAW find_data; \
- BOOL need_find_call;
-
-#define HAVE_DIRENT_TYPES
-#define UV__DT_DIR UV_DIRENT_DIR
-#define UV__DT_FILE UV_DIRENT_FILE
-#define UV__DT_LINK UV_DIRENT_LINK
-#define UV__DT_FIFO UV_DIRENT_FIFO
-#define UV__DT_SOCKET UV_DIRENT_SOCKET
-#define UV__DT_CHAR UV_DIRENT_CHAR
-#define UV__DT_BLOCK UV_DIRENT_BLOCK
-
-/* Platform-specific definitions for uv_dlopen support. */
-#define UV_DYNAMIC FAR WINAPI
-typedef struct {
- HMODULE handle;
- char* errmsg;
-} uv_lib_t;
-
-#define UV_LOOP_PRIVATE_FIELDS \
- /* The loop's I/O completion port */ \
- HANDLE iocp; \
- /* The current time according to the event loop. in msecs. */ \
- uint64_t time; \
- /* Tail of a single-linked circular queue of pending reqs. If the queue */ \
- /* is empty, tail_ is NULL. If there is only one item, */ \
- /* tail_->next_req == tail_ */ \
- uv_req_t* pending_reqs_tail; \
- /* Head of a single-linked list of closed handles */ \
- uv_handle_t* endgame_handles; \
- /* TODO(bnoordhuis) Stop heap-allocating |timer_heap| in libuv v2.x. */ \
- void* timer_heap; \
- /* Lists of active loop (prepare / check / idle) watchers */ \
- uv_prepare_t* prepare_handles; \
- uv_check_t* check_handles; \
- uv_idle_t* idle_handles; \
- /* This pointer will refer to the prepare/check/idle handle whose */ \
- /* callback is scheduled to be called next. This is needed to allow */ \
- /* safe removal from one of the lists above while that list being */ \
- /* iterated over. */ \
- uv_prepare_t* next_prepare_handle; \
- uv_check_t* next_check_handle; \
- uv_idle_t* next_idle_handle; \
- /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
- SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
- /* Counter to keep track of active tcp streams */ \
- unsigned int active_tcp_streams; \
- /* Counter to keep track of active udp streams */ \
- unsigned int active_udp_streams; \
- /* Counter to started timer */ \
- uint64_t timer_counter; \
- /* Threadpool */ \
- void* wq[2]; \
- uv_mutex_t wq_mutex; \
- uv_async_t wq_async;
-
-#define UV_REQ_TYPE_PRIVATE \
- /* TODO: remove the req suffix */ \
- UV_ACCEPT, \
- UV_FS_EVENT_REQ, \
- UV_POLL_REQ, \
- UV_PROCESS_EXIT, \
- UV_READ, \
- UV_UDP_RECV, \
- UV_WAKEUP, \
- UV_SIGNAL_REQ,
-
-#define UV_REQ_PRIVATE_FIELDS \
- union { \
- /* Used by I/O operations */ \
- struct { \
- OVERLAPPED overlapped; \
- size_t queued_bytes; \
- } io; \
- } u; \
- struct uv_req_s* next_req;
-
-#define UV_WRITE_PRIVATE_FIELDS \
- int coalesced; \
- uv_buf_t write_buffer; \
- HANDLE event_handle; \
- HANDLE wait_handle;
-
-#define UV_CONNECT_PRIVATE_FIELDS \
- /* empty */
-
-#define UV_SHUTDOWN_PRIVATE_FIELDS \
- /* empty */
-
-#define UV_UDP_SEND_PRIVATE_FIELDS \
- /* empty */
-
-#define UV_PRIVATE_REQ_TYPES \
- typedef struct uv_pipe_accept_s { \
- UV_REQ_FIELDS \
- HANDLE pipeHandle; \
- struct uv_pipe_accept_s* next_pending; \
- } uv_pipe_accept_t; \
- \
- typedef struct uv_tcp_accept_s { \
- UV_REQ_FIELDS \
- SOCKET accept_socket; \
- char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
- HANDLE event_handle; \
- HANDLE wait_handle; \
- struct uv_tcp_accept_s* next_pending; \
- } uv_tcp_accept_t; \
- \
- typedef struct uv_read_s { \
- UV_REQ_FIELDS \
- HANDLE event_handle; \
- HANDLE wait_handle; \
- } uv_read_t;
-
-#define uv_stream_connection_fields \
- unsigned int write_reqs_pending; \
- uv_shutdown_t* shutdown_req;
-
-#define uv_stream_server_fields \
- uv_connection_cb connection_cb;
-
-#define UV_STREAM_PRIVATE_FIELDS \
- unsigned int reqs_pending; \
- int activecnt; \
- uv_read_t read_req; \
- union { \
- struct { uv_stream_connection_fields } conn; \
- struct { uv_stream_server_fields } serv; \
- } stream;
-
-#define uv_tcp_server_fields \
- uv_tcp_accept_t* accept_reqs; \
- unsigned int processed_accepts; \
- uv_tcp_accept_t* pending_accepts; \
- LPFN_ACCEPTEX func_acceptex;
-
-#define uv_tcp_connection_fields \
- uv_buf_t read_buffer; \
- LPFN_CONNECTEX func_connectex;
-
-#define UV_TCP_PRIVATE_FIELDS \
- SOCKET socket; \
- int delayed_error; \
- union { \
- struct { uv_tcp_server_fields } serv; \
- struct { uv_tcp_connection_fields } conn; \
- } tcp;
-
-#define UV_UDP_PRIVATE_FIELDS \
- SOCKET socket; \
- unsigned int reqs_pending; \
- int activecnt; \
- uv_req_t recv_req; \
- uv_buf_t recv_buffer; \
- struct sockaddr_storage recv_from; \
- int recv_from_len; \
- uv_udp_recv_cb recv_cb; \
- uv_alloc_cb alloc_cb; \
- LPFN_WSARECV func_wsarecv; \
- LPFN_WSARECVFROM func_wsarecvfrom;
-
-#define uv_pipe_server_fields \
- int pending_instances; \
- uv_pipe_accept_t* accept_reqs; \
- uv_pipe_accept_t* pending_accepts;
-
-#define uv_pipe_connection_fields \
- uv_timer_t* eof_timer; \
- uv_write_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
- DWORD ipc_remote_pid; \
- union { \
- uint32_t payload_remaining; \
- uint64_t dummy; /* TODO: retained for ABI compat; remove this in v2.x. */ \
- } ipc_data_frame; \
- void* ipc_xfer_queue[2]; \
- int ipc_xfer_queue_length; \
- uv_write_t* non_overlapped_writes_tail; \
- CRITICAL_SECTION readfile_thread_lock; \
- volatile HANDLE readfile_thread_handle;
-
-#define UV_PIPE_PRIVATE_FIELDS \
- HANDLE handle; \
- WCHAR* name; \
- union { \
- struct { uv_pipe_server_fields } serv; \
- struct { uv_pipe_connection_fields } conn; \
- } pipe;
-
-/* TODO: put the parser states in an union - TTY handles are always half-duplex
- * so read-state can safely overlap write-state. */
-#define UV_TTY_PRIVATE_FIELDS \
- HANDLE handle; \
- union { \
- struct { \
- /* Used for readable TTY handles */ \
- /* TODO: remove me in v2.x. */ \
- HANDLE unused_; \
- uv_buf_t read_line_buffer; \
- HANDLE read_raw_wait; \
- /* Fields used for translating win keystrokes into vt100 characters */ \
- char last_key[8]; \
- unsigned char last_key_offset; \
- unsigned char last_key_len; \
- WCHAR last_utf16_high_surrogate; \
- INPUT_RECORD last_input_record; \
- } rd; \
- struct { \
- /* Used for writable TTY handles */ \
- /* utf8-to-utf16 conversion state */ \
- unsigned int utf8_codepoint; \
- unsigned char utf8_bytes_left; \
- /* eol conversion state */ \
- unsigned char previous_eol; \
- /* ansi parser state */ \
- unsigned char ansi_parser_state; \
- unsigned char ansi_csi_argc; \
- unsigned short ansi_csi_argv[4]; \
- COORD saved_position; \
- WORD saved_attributes; \
- } wr; \
- } tty;
-
-#define UV_POLL_PRIVATE_FIELDS \
- SOCKET socket; \
- /* Used in fast mode */ \
- SOCKET peer_socket; \
- AFD_POLL_INFO afd_poll_info_1; \
- AFD_POLL_INFO afd_poll_info_2; \
- /* Used in fast and slow mode. */ \
- uv_req_t poll_req_1; \
- uv_req_t poll_req_2; \
- unsigned char submitted_events_1; \
- unsigned char submitted_events_2; \
- unsigned char mask_events_1; \
- unsigned char mask_events_2; \
- unsigned char events;
-
-#define UV_TIMER_PRIVATE_FIELDS \
- void* heap_node[3]; \
- int unused; \
- uint64_t timeout; \
- uint64_t repeat; \
- uint64_t start_id; \
- uv_timer_cb timer_cb;
-
-#define UV_ASYNC_PRIVATE_FIELDS \
- struct uv_req_s async_req; \
- uv_async_cb async_cb; \
- /* char to avoid alignment issues */ \
- char volatile async_sent;
-
-#define UV_PREPARE_PRIVATE_FIELDS \
- uv_prepare_t* prepare_prev; \
- uv_prepare_t* prepare_next; \
- uv_prepare_cb prepare_cb;
-
-#define UV_CHECK_PRIVATE_FIELDS \
- uv_check_t* check_prev; \
- uv_check_t* check_next; \
- uv_check_cb check_cb;
-
-#define UV_IDLE_PRIVATE_FIELDS \
- uv_idle_t* idle_prev; \
- uv_idle_t* idle_next; \
- uv_idle_cb idle_cb;
-
-#define UV_HANDLE_PRIVATE_FIELDS \
- uv_handle_t* endgame_next; \
- unsigned int flags;
-
-#define UV_GETADDRINFO_PRIVATE_FIELDS \
- struct uv__work work_req; \
- uv_getaddrinfo_cb getaddrinfo_cb; \
- void* alloc; \
- WCHAR* node; \
- WCHAR* service; \
- /* The addrinfoW field is used to store a pointer to the hints, and */ \
- /* later on to store the result of GetAddrInfoW. The final result will */ \
- /* be converted to struct addrinfo* and stored in the addrinfo field. */ \
- struct addrinfoW* addrinfow; \
- struct addrinfo* addrinfo; \
- int retcode;
-
-#define UV_GETNAMEINFO_PRIVATE_FIELDS \
- struct uv__work work_req; \
- uv_getnameinfo_cb getnameinfo_cb; \
- struct sockaddr_storage storage; \
- int flags; \
- char host[NI_MAXHOST]; \
- char service[NI_MAXSERV]; \
- int retcode;
-
-#define UV_PROCESS_PRIVATE_FIELDS \
- struct uv_process_exit_s { \
- UV_REQ_FIELDS \
- } exit_req; \
- BYTE* child_stdio_buffer; \
- int exit_signal; \
- HANDLE wait_handle; \
- HANDLE process_handle; \
- volatile char exit_cb_pending;
-
-#define UV_FS_PRIVATE_FIELDS \
- struct uv__work work_req; \
- int flags; \
- DWORD sys_errno_; \
- union { \
- /* TODO: remove me in 0.9. */ \
- WCHAR* pathw; \
- int fd; \
- } file; \
- union { \
- struct { \
- int mode; \
- WCHAR* new_pathw; \
- int file_flags; \
- int fd_out; \
- unsigned int nbufs; \
- uv_buf_t* bufs; \
- int64_t offset; \
- uv_buf_t bufsml[4]; \
- } info; \
- struct { \
- double atime; \
- double mtime; \
- } time; \
- } fs;
-
-#define UV_WORK_PRIVATE_FIELDS \
- struct uv__work work_req;
-
-#define UV_FS_EVENT_PRIVATE_FIELDS \
- struct uv_fs_event_req_s { \
- UV_REQ_FIELDS \
- } req; \
- HANDLE dir_handle; \
- int req_pending; \
- uv_fs_event_cb cb; \
- WCHAR* filew; \
- WCHAR* short_filew; \
- WCHAR* dirw; \
- char* buffer;
-
-#define UV_SIGNAL_PRIVATE_FIELDS \
- RB_ENTRY(uv_signal_s) tree_entry; \
- struct uv_req_s signal_req; \
- unsigned long pending_signum;
-
-#ifndef F_OK
-#define F_OK 0
-#endif
-#ifndef R_OK
-#define R_OK 4
-#endif
-#ifndef W_OK
-#define W_OK 2
-#endif
-#ifndef X_OK
-#define X_OK 1
-#endif
-
-/* fs open() flags supported on this platform: */
-#define UV_FS_O_APPEND _O_APPEND
-#define UV_FS_O_CREAT _O_CREAT
-#define UV_FS_O_EXCL _O_EXCL
-#define UV_FS_O_RANDOM _O_RANDOM
-#define UV_FS_O_RDONLY _O_RDONLY
-#define UV_FS_O_RDWR _O_RDWR
-#define UV_FS_O_SEQUENTIAL _O_SEQUENTIAL
-#define UV_FS_O_SHORT_LIVED _O_SHORT_LIVED
-#define UV_FS_O_TEMPORARY _O_TEMPORARY
-#define UV_FS_O_TRUNC _O_TRUNC
-#define UV_FS_O_WRONLY _O_WRONLY
-
-/* fs open() flags supported on other platforms (or mapped on this platform): */
-#define UV_FS_O_DIRECT 0x02000000 /* FILE_FLAG_NO_BUFFERING */
-#define UV_FS_O_DIRECTORY 0
-#define UV_FS_O_DSYNC 0x04000000 /* FILE_FLAG_WRITE_THROUGH */
-#define UV_FS_O_EXLOCK 0x10000000 /* EXCLUSIVE SHARING MODE */
-#define UV_FS_O_NOATIME 0
-#define UV_FS_O_NOCTTY 0
-#define UV_FS_O_NOFOLLOW 0
-#define UV_FS_O_NONBLOCK 0
-#define UV_FS_O_SYMLINK 0
-#define UV_FS_O_SYNC 0x08000000 /* FILE_FLAG_WRITE_THROUGH */
diff --git a/wpiutil/src/main/native/libuv/src/fs-poll.cpp b/wpiutil/src/main/native/libuv/src/fs-poll.cpp
deleted file mode 100644
index 14d64de..0000000
--- a/wpiutil/src/main/native/libuv/src/fs-poll.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "uv-common.h"
-
-#ifdef _WIN32
-#include "win/internal.h"
-#include "win/handle-inl.h"
-#define uv__make_close_pending(h) uv_want_endgame((h)->loop, (h))
-#else
-#include "unix/internal.h"
-#endif
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-struct poll_ctx {
- uv_fs_poll_t* parent_handle;
- int busy_polling;
- unsigned int interval;
- uint64_t start_time;
- uv_loop_t* loop;
- uv_fs_poll_cb poll_cb;
- uv_timer_t timer_handle;
- uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
- uv_stat_t statbuf;
- struct poll_ctx* previous; /* context from previous start()..stop() period */
- char path[1]; /* variable length */
-};
-
-static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
-static void poll_cb(uv_fs_t* req);
-static void timer_cb(uv_timer_t* timer);
-static void timer_close_cb(uv_handle_t* handle);
-
-static uv_stat_t zero_statbuf;
-
-
-int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
- uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
- handle->poll_ctx = NULL;
- return 0;
-}
-
-
-int uv_fs_poll_start(uv_fs_poll_t* handle,
- uv_fs_poll_cb cb,
- const char* path,
- unsigned int interval) {
- struct poll_ctx* ctx;
- uv_loop_t* loop;
- size_t len;
- int err;
-
- if (uv_is_active((uv_handle_t*)handle))
- return 0;
-
- loop = handle->loop;
- len = strlen(path);
- ctx = (struct poll_ctx*)uv__calloc(1, sizeof(*ctx) + len);
-
- if (ctx == NULL)
- return UV_ENOMEM;
-
- ctx->loop = loop;
- ctx->poll_cb = cb;
- ctx->interval = interval ? interval : 1;
- ctx->start_time = uv_now(loop);
- ctx->parent_handle = handle;
- memcpy(ctx->path, path, len + 1);
-
- err = uv_timer_init(loop, &ctx->timer_handle);
- if (err < 0)
- goto error;
-
- ctx->timer_handle.flags |= UV_HANDLE_INTERNAL;
- uv__handle_unref(&ctx->timer_handle);
-
- err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
- if (err < 0)
- goto error;
-
- if (handle->poll_ctx != NULL)
- ctx->previous = (struct poll_ctx*)handle->poll_ctx;
- handle->poll_ctx = ctx;
- uv__handle_start(handle);
-
- return 0;
-
-error:
- uv__free(ctx);
- return err;
-}
-
-
-int uv_fs_poll_stop(uv_fs_poll_t* handle) {
- struct poll_ctx* ctx;
-
- if (!uv_is_active((uv_handle_t*)handle))
- return 0;
-
- ctx = (struct poll_ctx*)handle->poll_ctx;
- assert(ctx != NULL);
- assert(ctx->parent_handle == handle);
-
- /* Close the timer if it's active. If it's inactive, there's a stat request
- * in progress and poll_cb will take care of the cleanup.
- */
- if (uv_is_active((uv_handle_t*)&ctx->timer_handle))
- uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
-
- uv__handle_stop(handle);
-
- return 0;
-}
-
-
-int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
- struct poll_ctx* ctx;
- size_t required_len;
-
- if (!uv_is_active((uv_handle_t*)handle)) {
- *size = 0;
- return UV_EINVAL;
- }
-
- ctx = (struct poll_ctx*)handle->poll_ctx;
- assert(ctx != NULL);
-
- required_len = strlen(ctx->path);
- if (required_len >= *size) {
- *size = required_len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, ctx->path, required_len);
- *size = required_len;
- buffer[required_len] = '\0';
-
- return 0;
-}
-
-
-void uv__fs_poll_close(uv_fs_poll_t* handle) {
- uv_fs_poll_stop(handle);
-
- if (handle->poll_ctx == NULL)
- uv__make_close_pending((uv_handle_t*)handle);
-}
-
-
-static void timer_cb(uv_timer_t* timer) {
- struct poll_ctx* ctx;
-
- ctx = container_of(timer, struct poll_ctx, timer_handle);
- assert(ctx->parent_handle != NULL);
- assert(ctx->parent_handle->poll_ctx == ctx);
- ctx->start_time = uv_now(ctx->loop);
-
- if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
- abort();
-}
-
-
-static void poll_cb(uv_fs_t* req) {
- uv_stat_t* statbuf;
- struct poll_ctx* ctx;
- uint64_t interval;
- uv_fs_poll_t* handle;
-
- ctx = container_of(req, struct poll_ctx, fs_req);
- handle = ctx->parent_handle;
-
- if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle))
- goto out;
-
- if (req->result != 0) {
- if (ctx->busy_polling != req->result) {
- ctx->poll_cb(ctx->parent_handle,
- req->result,
- &ctx->statbuf,
- &zero_statbuf);
- ctx->busy_polling = req->result;
- }
- goto out;
- }
-
- statbuf = &req->statbuf;
-
- if (ctx->busy_polling != 0)
- if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
- ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
-
- ctx->statbuf = *statbuf;
- ctx->busy_polling = 1;
-
-out:
- uv_fs_req_cleanup(req);
-
- if (!uv_is_active((uv_handle_t*)handle) || uv__is_closing(handle)) {
- uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
- return;
- }
-
- /* Reschedule timer, subtract the delay from doing the stat(). */
- interval = ctx->interval;
- interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
-
- if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
- abort();
-}
-
-
-static void timer_close_cb(uv_handle_t* timer) {
- struct poll_ctx* ctx;
- struct poll_ctx* it;
- struct poll_ctx* last;
- uv_fs_poll_t* handle;
-
- ctx = container_of(timer, struct poll_ctx, timer_handle);
- handle = ctx->parent_handle;
- if (ctx == handle->poll_ctx) {
- handle->poll_ctx = ctx->previous;
- if (handle->poll_ctx == NULL && uv__is_closing(handle))
- uv__make_close_pending((uv_handle_t*)handle);
- } else {
- for (last = (struct poll_ctx*)handle->poll_ctx, it = last->previous;
- it != ctx;
- last = it, it = it->previous) {
- assert(last->previous != NULL);
- }
- last->previous = ctx->previous;
- }
- uv__free(ctx);
-}
-
-
-static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
- return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
- && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
- && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
- && a->st_ctim.tv_sec == b->st_ctim.tv_sec
- && a->st_mtim.tv_sec == b->st_mtim.tv_sec
- && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
- && a->st_size == b->st_size
- && a->st_mode == b->st_mode
- && a->st_uid == b->st_uid
- && a->st_gid == b->st_gid
- && a->st_ino == b->st_ino
- && a->st_dev == b->st_dev
- && a->st_flags == b->st_flags
- && a->st_gen == b->st_gen;
-}
-
-
-#if defined(_WIN32)
-
-#include "win/internal.h"
-#include "win/handle-inl.h"
-
-void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- uv__handle_close(handle);
-}
-
-#endif /* _WIN32 */
diff --git a/wpiutil/src/main/native/libuv/src/heap-inl.h b/wpiutil/src/main/native/libuv/src/heap-inl.h
deleted file mode 100644
index 1e2ed60..0000000
--- a/wpiutil/src/main/native/libuv/src/heap-inl.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#ifndef UV_SRC_HEAP_H_
-#define UV_SRC_HEAP_H_
-
-#include <stddef.h> /* NULL */
-
-#if defined(__GNUC__)
-# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
-#else
-# define HEAP_EXPORT(declaration) static declaration
-#endif
-
-struct heap_node {
- struct heap_node* left;
- struct heap_node* right;
- struct heap_node* parent;
-};
-
-/* A binary min heap. The usual properties hold: the root is the lowest
- * element in the set, the height of the tree is at most log2(nodes) and
- * it's always a complete binary tree.
- *
- * The heap function try hard to detect corrupted tree nodes at the cost
- * of a minor reduction in performance. Compile with -DNDEBUG to disable.
- */
-struct heap {
- struct heap_node* min;
- unsigned int nelts;
-};
-
-/* Return non-zero if a < b. */
-typedef int (*heap_compare_fn)(const struct heap_node* a,
- const struct heap_node* b);
-
-/* Public functions. */
-HEAP_EXPORT(void heap_init(struct heap* heap));
-HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
-HEAP_EXPORT(void heap_insert(struct heap* heap,
- struct heap_node* newnode,
- heap_compare_fn less_than));
-HEAP_EXPORT(void heap_remove(struct heap* heap,
- struct heap_node* node,
- heap_compare_fn less_than));
-HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
-
-/* Implementation follows. */
-
-HEAP_EXPORT(void heap_init(struct heap* heap)) {
- heap->min = NULL;
- heap->nelts = 0;
-}
-
-HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
- return heap->min;
-}
-
-/* Swap parent with child. Child moves closer to the root, parent moves away. */
-static void heap_node_swap(struct heap* heap,
- struct heap_node* parent,
- struct heap_node* child) {
- struct heap_node* sibling;
- struct heap_node t;
-
- t = *parent;
- *parent = *child;
- *child = t;
-
- parent->parent = child;
- if (child->left == child) {
- child->left = parent;
- sibling = child->right;
- } else {
- child->right = parent;
- sibling = child->left;
- }
- if (sibling != NULL)
- sibling->parent = child;
-
- if (parent->left != NULL)
- parent->left->parent = parent;
- if (parent->right != NULL)
- parent->right->parent = parent;
-
- if (child->parent == NULL)
- heap->min = child;
- else if (child->parent->left == parent)
- child->parent->left = child;
- else
- child->parent->right = child;
-}
-
-HEAP_EXPORT(void heap_insert(struct heap* heap,
- struct heap_node* newnode,
- heap_compare_fn less_than)) {
- struct heap_node** parent;
- struct heap_node** child;
- unsigned int path;
- unsigned int n;
- unsigned int k;
-
- newnode->left = NULL;
- newnode->right = NULL;
- newnode->parent = NULL;
-
- /* Calculate the path from the root to the insertion point. This is a min
- * heap so we always insert at the left-most free node of the bottom row.
- */
- path = 0;
- for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
- path = (path << 1) | (n & 1);
-
- /* Now traverse the heap using the path we calculated in the previous step. */
- parent = child = &heap->min;
- while (k > 0) {
- parent = child;
- if (path & 1)
- child = &(*child)->right;
- else
- child = &(*child)->left;
- path >>= 1;
- k -= 1;
- }
-
- /* Insert the new node. */
- newnode->parent = *parent;
- *child = newnode;
- heap->nelts += 1;
-
- /* Walk up the tree and check at each node if the heap property holds.
- * It's a min heap so parent < child must be true.
- */
- while (newnode->parent != NULL && less_than(newnode, newnode->parent))
- heap_node_swap(heap, newnode->parent, newnode);
-}
-
-HEAP_EXPORT(void heap_remove(struct heap* heap,
- struct heap_node* node,
- heap_compare_fn less_than)) {
- struct heap_node* smallest;
- struct heap_node** max;
- struct heap_node* child;
- unsigned int path;
- unsigned int k;
- unsigned int n;
-
- if (heap->nelts == 0)
- return;
-
- /* Calculate the path from the min (the root) to the max, the left-most node
- * of the bottom row.
- */
- path = 0;
- for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
- path = (path << 1) | (n & 1);
-
- /* Now traverse the heap using the path we calculated in the previous step. */
- max = &heap->min;
- while (k > 0) {
- if (path & 1)
- max = &(*max)->right;
- else
- max = &(*max)->left;
- path >>= 1;
- k -= 1;
- }
-
- heap->nelts -= 1;
-
- /* Unlink the max node. */
- child = *max;
- *max = NULL;
-
- if (child == node) {
- /* We're removing either the max or the last node in the tree. */
- if (child == heap->min) {
- heap->min = NULL;
- }
- return;
- }
-
- /* Replace the to be deleted node with the max node. */
- child->left = node->left;
- child->right = node->right;
- child->parent = node->parent;
-
- if (child->left != NULL) {
- child->left->parent = child;
- }
-
- if (child->right != NULL) {
- child->right->parent = child;
- }
-
- if (node->parent == NULL) {
- heap->min = child;
- } else if (node->parent->left == node) {
- node->parent->left = child;
- } else {
- node->parent->right = child;
- }
-
- /* Walk down the subtree and check at each node if the heap property holds.
- * It's a min heap so parent < child must be true. If the parent is bigger,
- * swap it with the smallest child.
- */
- for (;;) {
- smallest = child;
- if (child->left != NULL && less_than(child->left, smallest))
- smallest = child->left;
- if (child->right != NULL && less_than(child->right, smallest))
- smallest = child->right;
- if (smallest == child)
- break;
- heap_node_swap(heap, child, smallest);
- }
-
- /* Walk up the subtree and check that each parent is less than the node
- * this is required, because `max` node is not guaranteed to be the
- * actual maximum in tree
- */
- while (child->parent != NULL && less_than(child, child->parent))
- heap_node_swap(heap, child->parent, child);
-}
-
-HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
- heap_remove(heap, heap->min, less_than);
-}
-
-#undef HEAP_EXPORT
-
-#endif /* UV_SRC_HEAP_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/idna.cpp b/wpiutil/src/main/native/libuv/src/idna.cpp
deleted file mode 100644
index 6b2406c..0000000
--- a/wpiutil/src/main/native/libuv/src/idna.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-/* Derived from https://github.com/bnoordhuis/punycode
- * but updated to support IDNA 2008.
- */
-
-#include "uv.h"
-#include "idna.h"
-#include <string.h>
-
-static unsigned uv__utf8_decode1_slow(const char** p,
- const char* pe,
- unsigned a) {
- unsigned b;
- unsigned c;
- unsigned d;
- unsigned min;
-
- if (a > 0xF7)
- return -1;
-
- switch (*p - pe) {
- default:
- if (a > 0xEF) {
- min = 0x10000;
- a = a & 7;
- b = (unsigned char) *(*p)++;
- c = (unsigned char) *(*p)++;
- d = (unsigned char) *(*p)++;
- break;
- }
- /* Fall through. */
- case 2:
- if (a > 0xDF) {
- min = 0x800;
- b = 0x80 | (a & 15);
- c = (unsigned char) *(*p)++;
- d = (unsigned char) *(*p)++;
- a = 0;
- break;
- }
- /* Fall through. */
- case 1:
- if (a > 0xBF) {
- min = 0x80;
- b = 0x80;
- c = 0x80 | (a & 31);
- d = (unsigned char) *(*p)++;
- a = 0;
- break;
- }
- return -1; /* Invalid continuation byte. */
- }
-
- if (0x80 != (0xC0 & (b ^ c ^ d)))
- return -1; /* Invalid sequence. */
-
- b &= 63;
- c &= 63;
- d &= 63;
- a = (a << 18) | (b << 12) | (c << 6) | d;
-
- if (a < min)
- return -1; /* Overlong sequence. */
-
- if (a > 0x10FFFF)
- return -1; /* Four-byte sequence > U+10FFFF. */
-
- if (a >= 0xD800 && a <= 0xDFFF)
- return -1; /* Surrogate pair. */
-
- return a;
-}
-
-unsigned uv__utf8_decode1(const char** p, const char* pe) {
- unsigned a;
-
- a = (unsigned char) *(*p)++;
-
- if (a < 128)
- return a; /* ASCII, common case. */
-
- return uv__utf8_decode1_slow(p, pe, a);
-}
-
-#define foreach_codepoint(c, p, pe) \
- for (; (void) (*p <= pe && (c = uv__utf8_decode1(p, pe))), *p <= pe;)
-
-static int uv__idna_toascii_label(const char* s, const char* se,
- char** d, char* de) {
- static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz0123456789";
- const char* ss;
- unsigned c = 0;
- unsigned h;
- unsigned k;
- unsigned n;
- unsigned m;
- unsigned q;
- unsigned t;
- unsigned x;
- unsigned y;
- unsigned bias;
- unsigned delta;
- unsigned todo;
- int first;
-
- h = 0;
- ss = s;
- todo = 0;
-
- foreach_codepoint(c, &s, se) {
- if (c < 128)
- h++;
- else if (c == (unsigned) -1)
- return UV_EINVAL;
- else
- todo++;
- }
-
- if (todo > 0) {
- if (*d < de) *(*d)++ = 'x';
- if (*d < de) *(*d)++ = 'n';
- if (*d < de) *(*d)++ = '-';
- if (*d < de) *(*d)++ = '-';
- }
-
- x = 0;
- s = ss;
- foreach_codepoint(c, &s, se) {
- if (c > 127)
- continue;
-
- if (*d < de)
- *(*d)++ = c;
-
- if (++x == h)
- break; /* Visited all ASCII characters. */
- }
-
- if (todo == 0)
- return h;
-
- /* Only write separator when we've written ASCII characters first. */
- if (h > 0)
- if (*d < de)
- *(*d)++ = '-';
-
- n = 128;
- bias = 72;
- delta = 0;
- first = 1;
-
- while (todo > 0) {
- m = -1;
- s = ss;
- foreach_codepoint(c, &s, se)
- if (c >= n)
- if (c < m)
- m = c;
-
- x = m - n;
- y = h + 1;
-
- if (x > ~delta / y)
- return UV_E2BIG; /* Overflow. */
-
- delta += x * y;
- n = m;
-
- s = ss;
- foreach_codepoint(c, &s, se) {
- if (c < n)
- if (++delta == 0)
- return UV_E2BIG; /* Overflow. */
-
- if (c != n)
- continue;
-
- for (k = 36, q = delta; /* empty */; k += 36) {
- t = 1;
-
- if (k > bias)
- t = k - bias;
-
- if (t > 26)
- t = 26;
-
- if (q < t)
- break;
-
- /* TODO(bnoordhuis) Since 1 <= t <= 26 and therefore
- * 10 <= y <= 35, we can optimize the long division
- * into a table-based reciprocal multiplication.
- */
- x = q - t;
- y = 36 - t; /* 10 <= y <= 35 since 1 <= t <= 26. */
- q = x / y;
- t = t + x % y; /* 1 <= t <= 35 because of y. */
-
- if (*d < de)
- *(*d)++ = alphabet[t];
- }
-
- if (*d < de)
- *(*d)++ = alphabet[q];
-
- delta /= 2;
-
- if (first) {
- delta /= 350;
- first = 0;
- }
-
- /* No overflow check is needed because |delta| was just
- * divided by 2 and |delta+delta >= delta + delta/h|.
- */
- h++;
- delta += delta / h;
-
- for (bias = 0; delta > 35 * 26 / 2; bias += 36)
- delta /= 35;
-
- bias += 36 * delta / (delta + 38);
- delta = 0;
- todo--;
- }
-
- delta++;
- n++;
- }
-
- return 0;
-}
-
-#undef foreach_codepoint
-
-long uv__idna_toascii(const char* s, const char* se, char* d, char* de) {
- const char* si;
- const char* st;
- unsigned c;
- char* ds;
- int rc;
-
- ds = d;
-
- for (si = s; si < se; /* empty */) {
- st = si;
- c = uv__utf8_decode1(&si, se);
-
- if (c != '.')
- if (c != 0x3002) /* 。 */
- if (c != 0xFF0E) /* . */
- if (c != 0xFF61) /* 。 */
- continue;
-
- rc = uv__idna_toascii_label(s, st, &d, de);
-
- if (rc < 0)
- return rc;
-
- if (d < de)
- *d++ = '.';
-
- s = si;
- }
-
- if (s < se) {
- rc = uv__idna_toascii_label(s, se, &d, de);
-
- if (rc < 0)
- return rc;
- }
-
- if (d < de)
- *d++ = '\0';
-
- return d - ds; /* Number of bytes written. */
-}
diff --git a/wpiutil/src/main/native/libuv/src/idna.h b/wpiutil/src/main/native/libuv/src/idna.h
deleted file mode 100644
index 8e0c592..0000000
--- a/wpiutil/src/main/native/libuv/src/idna.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/* Copyright (c) 2011, 2018 Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#ifndef UV_SRC_IDNA_H_
-#define UV_SRC_IDNA_H_
-
-/* Decode a single codepoint. Returns the codepoint or UINT32_MAX on error.
- * |p| is updated on success _and_ error, i.e., bad multi-byte sequences are
- * skipped in their entirety, not just the first bad byte.
- */
-unsigned uv__utf8_decode1(const char** p, const char* pe);
-
-/* Convert a UTF-8 domain name to IDNA 2008 / Punycode. A return value >= 0
- * is the number of bytes written to |d|, including the trailing nul byte.
- * A return value < 0 is a libuv error code. |s| and |d| can not overlap.
- */
-long uv__idna_toascii(const char* s, const char* se, char* d, char* de);
-
-#endif /* UV_SRC_IDNA_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/inet.cpp b/wpiutil/src/main/native/libuv/src/inet.cpp
deleted file mode 100644
index 167ec11..0000000
--- a/wpiutil/src/main/native/libuv/src/inet.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#include <stdio.h>
-#include <string.h>
-
-#if defined(_MSC_VER) && _MSC_VER < 1600
-# include "uv/stdint-msvc2008.h"
-#else
-# include <stdint.h>
-#endif
-
-#include "uv.h"
-#include "uv-common.h"
-
-#ifdef _WIN32
-#pragma warning(disable : 6001)
-#endif
-
-#define UV__INET_ADDRSTRLEN 16
-#define UV__INET6_ADDRSTRLEN 46
-
-
-static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
-static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
-static int inet_pton4(const char *src, unsigned char *dst);
-static int inet_pton6(const char *src, unsigned char *dst);
-
-
-int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
- switch (af) {
- case AF_INET:
- return (inet_ntop4((const unsigned char*)src, dst, size));
- case AF_INET6:
- return (inet_ntop6((const unsigned char*)src, dst, size));
- default:
- return UV_EAFNOSUPPORT;
- }
- /* NOTREACHED */
-}
-
-
-static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
- static const char fmt[] = "%u.%u.%u.%u";
- char tmp[UV__INET_ADDRSTRLEN];
- int l;
-
- l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
- if (l <= 0 || (size_t) l >= size) {
- return UV_ENOSPC;
- }
- uv__strscpy(dst, tmp, size);
- return 0;
-}
-
-
-static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
- /*
- * Note that int32_t and int16_t need only be "at least" large enough
- * to contain a value of the specified size. On some systems, like
- * Crays, there is no such thing as an integer variable with 16 bits.
- * Keep this in mind if you think this function should have been coded
- * to use pointer overlays. All the world's not a VAX.
- */
- char tmp[UV__INET6_ADDRSTRLEN], *tp;
- struct { int base, len; } best, cur;
- unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
- int i;
-
- /*
- * Preprocess:
- * Copy the input (bytewise) array into a wordwise array.
- * Find the longest run of 0x00's in src[] for :: shorthanding.
- */
- memset(words, '\0', sizeof words);
- for (i = 0; i < (int) sizeof(struct in6_addr); i++)
- words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
- best.base = -1;
- best.len = 0;
- cur.base = -1;
- cur.len = 0;
- for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
- if (words[i] == 0) {
- if (cur.base == -1)
- cur.base = i, cur.len = 1;
- else
- cur.len++;
- } else {
- if (cur.base != -1) {
- if (best.base == -1 || cur.len > best.len)
- best = cur;
- cur.base = -1;
- }
- }
- }
- if (cur.base != -1) {
- if (best.base == -1 || cur.len > best.len)
- best = cur;
- }
- if (best.base != -1 && best.len < 2)
- best.base = -1;
-
- /*
- * Format the result.
- */
- tp = tmp;
- for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
- /* Are we inside the best run of 0x00's? */
- if (best.base != -1 && i >= best.base &&
- i < (best.base + best.len)) {
- if (i == best.base)
- *tp++ = ':';
- continue;
- }
- /* Are we following an initial run of 0x00s or any real hex? */
- if (i != 0)
- *tp++ = ':';
- /* Is this address an encapsulated IPv4? */
- if (i == 6 && best.base == 0 && (best.len == 6 ||
- (best.len == 7 && words[7] != 0x0001) ||
- (best.len == 5 && words[5] == 0xffff))) {
- int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
- if (err)
- return err;
- tp += strlen(tp);
- break;
- }
- tp += sprintf(tp, "%x", words[i]);
- }
- /* Was it a trailing run of 0x00's? */
- if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
- *tp++ = ':';
- *tp++ = '\0';
- if (UV_E2BIG == uv__strscpy(dst, tmp, size))
- return UV_ENOSPC;
- return 0;
-}
-
-
-int uv_inet_pton(int af, const char* src, void* dst) {
- if (src == NULL || dst == NULL)
- return UV_EINVAL;
-
- switch (af) {
- case AF_INET:
- return (inet_pton4(src, (unsigned char*)dst));
- case AF_INET6: {
- int len;
- char tmp[UV__INET6_ADDRSTRLEN], *s;
- const char *p;
- s = (char*) src;
- p = strchr(src, '%');
- if (p != NULL) {
- s = tmp;
- len = p - src;
- if (len > UV__INET6_ADDRSTRLEN-1)
- return UV_EINVAL;
- memcpy(s, src, len);
- s[len] = '\0';
- }
- return inet_pton6(s, (unsigned char*)dst);
- }
- default:
- return UV_EAFNOSUPPORT;
- }
- /* NOTREACHED */
-}
-
-
-static int inet_pton4(const char *src, unsigned char *dst) {
- static const char digits[] = "0123456789";
- int saw_digit, octets, ch;
- unsigned char tmp[sizeof(struct in_addr)], *tp;
-
- saw_digit = 0;
- octets = 0;
- *(tp = tmp) = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
-
- if ((pch = strchr(digits, ch)) != NULL) {
- unsigned int nw = *tp * 10 + (pch - digits);
-
- if (saw_digit && *tp == 0)
- return UV_EINVAL;
- if (nw > 255)
- return UV_EINVAL;
- *tp = nw;
- if (!saw_digit) {
- if (++octets > 4)
- return UV_EINVAL;
- saw_digit = 1;
- }
- } else if (ch == '.' && saw_digit) {
- if (octets == 4)
- return UV_EINVAL;
- *++tp = 0;
- saw_digit = 0;
- } else
- return UV_EINVAL;
- }
- if (octets < 4)
- return UV_EINVAL;
- memcpy(dst, tmp, sizeof(struct in_addr));
- return 0;
-}
-
-
-static int inet_pton6(const char *src, unsigned char *dst) {
- static const char xdigits_l[] = "0123456789abcdef",
- xdigits_u[] = "0123456789ABCDEF";
- unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
- const char *xdigits, *curtok;
- int ch, seen_xdigits;
- unsigned int val;
-
- memset((tp = tmp), '\0', sizeof tmp);
- endp = tp + sizeof tmp;
- colonp = NULL;
- /* Leading :: requires some special handling. */
- if (*src == ':')
- if (*++src != ':')
- return UV_EINVAL;
- curtok = src;
- seen_xdigits = 0;
- val = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
-
- if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
- pch = strchr((xdigits = xdigits_u), ch);
- if (pch != NULL) {
- val <<= 4;
- val |= (pch - xdigits);
- if (++seen_xdigits > 4)
- return UV_EINVAL;
- continue;
- }
- if (ch == ':') {
- curtok = src;
- if (!seen_xdigits) {
- if (colonp)
- return UV_EINVAL;
- colonp = tp;
- continue;
- } else if (*src == '\0') {
- return UV_EINVAL;
- }
- if (tp + sizeof(uint16_t) > endp)
- return UV_EINVAL;
- *tp++ = (unsigned char) (val >> 8) & 0xff;
- *tp++ = (unsigned char) val & 0xff;
- seen_xdigits = 0;
- val = 0;
- continue;
- }
- if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
- int err = inet_pton4(curtok, tp);
- if (err == 0) {
- tp += sizeof(struct in_addr);
- seen_xdigits = 0;
- break; /*%< '\\0' was seen by inet_pton4(). */
- }
- }
- return UV_EINVAL;
- }
- if (seen_xdigits) {
- if (tp + sizeof(uint16_t) > endp)
- return UV_EINVAL;
- *tp++ = (unsigned char) (val >> 8) & 0xff;
- *tp++ = (unsigned char) val & 0xff;
- }
- if (colonp != NULL) {
- /*
- * Since some memmove()'s erroneously fail to handle
- * overlapping regions, we'll do the shift by hand.
- */
- const int n = tp - colonp;
- int i;
-
- if (tp == endp)
- return UV_EINVAL;
- for (i = 1; i <= n; i++) {
- endp[- i] = colonp[n - i];
- colonp[n - i] = 0;
- }
- tp = endp;
- }
- if (tp != endp)
- return UV_EINVAL;
- memcpy(dst, tmp, sizeof tmp);
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/queue.h b/wpiutil/src/main/native/libuv/src/queue.h
deleted file mode 100644
index ff3540a..0000000
--- a/wpiutil/src/main/native/libuv/src/queue.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#ifndef QUEUE_H_
-#define QUEUE_H_
-
-#include <stddef.h>
-
-typedef void *QUEUE[2];
-
-/* Private macros. */
-#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
-#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
-#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
-#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
-
-/* Public macros. */
-#define QUEUE_DATA(ptr, type, field) \
- ((type *) ((char *) (ptr) - offsetof(type, field)))
-
-/* Important note: mutating the list while QUEUE_FOREACH is
- * iterating over its elements results in undefined behavior.
- */
-#define QUEUE_FOREACH(q, h) \
- for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
-
-#define QUEUE_EMPTY(q) \
- ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
-
-#define QUEUE_HEAD(q) \
- (QUEUE_NEXT(q))
-
-#define QUEUE_INIT(q) \
- do { \
- QUEUE_NEXT(q) = (q); \
- QUEUE_PREV(q) = (q); \
- } \
- while (0)
-
-#define QUEUE_ADD(h, n) \
- do { \
- QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
- QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
- QUEUE_PREV(h) = QUEUE_PREV(n); \
- QUEUE_PREV_NEXT(h) = (h); \
- } \
- while (0)
-
-#define QUEUE_SPLIT(h, q, n) \
- do { \
- QUEUE_PREV(n) = QUEUE_PREV(h); \
- QUEUE_PREV_NEXT(n) = (n); \
- QUEUE_NEXT(n) = (q); \
- QUEUE_PREV(h) = QUEUE_PREV(q); \
- QUEUE_PREV_NEXT(h) = (h); \
- QUEUE_PREV(q) = (n); \
- } \
- while (0)
-
-#define QUEUE_MOVE(h, n) \
- do { \
- if (QUEUE_EMPTY(h)) \
- QUEUE_INIT(n); \
- else { \
- QUEUE* q = QUEUE_HEAD(h); \
- QUEUE_SPLIT(h, q, n); \
- } \
- } \
- while (0)
-
-#define QUEUE_INSERT_HEAD(h, q) \
- do { \
- QUEUE_NEXT(q) = QUEUE_NEXT(h); \
- QUEUE_PREV(q) = (h); \
- QUEUE_NEXT_PREV(q) = (q); \
- QUEUE_NEXT(h) = (q); \
- } \
- while (0)
-
-#define QUEUE_INSERT_TAIL(h, q) \
- do { \
- QUEUE_NEXT(q) = (h); \
- QUEUE_PREV(q) = QUEUE_PREV(h); \
- QUEUE_PREV_NEXT(q) = (q); \
- QUEUE_PREV(h) = (q); \
- } \
- while (0)
-
-#define QUEUE_REMOVE(q) \
- do { \
- QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
- QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
- } \
- while (0)
-
-#endif /* QUEUE_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/strscpy.cpp b/wpiutil/src/main/native/libuv/src/strscpy.cpp
deleted file mode 100644
index 4a9e863..0000000
--- a/wpiutil/src/main/native/libuv/src/strscpy.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "strscpy.h"
-#include <limits.h> /* SSIZE_MAX */
-
-ssize_t uv__strscpy(char* d, const char* s, size_t n) {
- size_t i;
-
- for (i = 0; i < n; i++)
- if ('\0' == (d[i] = s[i]))
- return i > SSIZE_MAX ? (ssize_t) UV_E2BIG : (ssize_t) i;
-
- if (i == 0)
- return 0;
-
- d[--i] = '\0';
-
- return UV_E2BIG;
-}
diff --git a/wpiutil/src/main/native/libuv/src/strscpy.h b/wpiutil/src/main/native/libuv/src/strscpy.h
deleted file mode 100644
index fbe0a39..0000000
--- a/wpiutil/src/main/native/libuv/src/strscpy.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef UV_STRSCPY_H_
-#define UV_STRSCPY_H_
-
-/* Include uv.h for its definitions of size_t and ssize_t.
- * size_t can be obtained directly from <stddef.h> but ssize_t requires
- * some hoop jumping on Windows that I didn't want to duplicate here.
- */
-#include "uv.h"
-
-/* Copies up to |n-1| bytes from |d| to |s| and always zero-terminates
- * the result, except when |n==0|. Returns the number of bytes copied
- * or UV_E2BIG if |d| is too small.
- *
- * See https://www.kernel.org/doc/htmldocs/kernel-api/API-strscpy.html
- */
-ssize_t uv__strscpy(char* d, const char* s, size_t n);
-
-#endif /* UV_STRSCPY_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/threadpool.cpp b/wpiutil/src/main/native/libuv/src/threadpool.cpp
deleted file mode 100644
index 515bf40..0000000
--- a/wpiutil/src/main/native/libuv/src/threadpool.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv-common.h"
-
-#if !defined(_WIN32)
-# include "unix/internal.h"
-#endif
-
-#include <stdlib.h>
-
-#ifdef _WIN32
-#pragma warning(disable: 6001 6011)
-#endif
-
-#define MAX_THREADPOOL_SIZE 1024
-
-static uv_once_t once = UV_ONCE_INIT;
-static uv_cond_t cond;
-static uv_mutex_t mutex;
-static unsigned int idle_threads;
-static unsigned int slow_io_work_running;
-static unsigned int nthreads;
-static uv_thread_t* threads;
-static uv_thread_t default_threads[4];
-static QUEUE exit_message;
-static QUEUE wq;
-static QUEUE run_slow_work_message;
-static QUEUE slow_io_pending_wq;
-
-static unsigned int slow_work_thread_threshold(void) {
- return (nthreads + 1) / 2;
-}
-
-static void uv__cancelled(struct uv__work* w) {
- abort();
-}
-
-
-/* To avoid deadlock with uv_cancel() it's crucial that the worker
- * never holds the global mutex and the loop-local mutex at the same time.
- */
-static void worker(void* arg) {
- struct uv__work* w;
- QUEUE* q;
- int is_slow_work;
-
- uv_sem_post((uv_sem_t*) arg);
- arg = NULL;
-
- uv_mutex_lock(&mutex);
- for (;;) {
- /* `mutex` should always be locked at this point. */
-
- /* Keep waiting while either no work is present or only slow I/O
- and we're at the threshold for that. */
- while (QUEUE_EMPTY(&wq) ||
- (QUEUE_HEAD(&wq) == &run_slow_work_message &&
- QUEUE_NEXT(&run_slow_work_message) == &wq &&
- slow_io_work_running >= slow_work_thread_threshold())) {
- idle_threads += 1;
- uv_cond_wait(&cond, &mutex);
- idle_threads -= 1;
- }
-
- q = QUEUE_HEAD(&wq);
- if (q == &exit_message) {
- uv_cond_signal(&cond);
- uv_mutex_unlock(&mutex);
- break;
- }
-
- QUEUE_REMOVE(q);
- QUEUE_INIT(q); /* Signal uv_cancel() that the work req is executing. */
-
- is_slow_work = 0;
- if (q == &run_slow_work_message) {
- /* If we're at the slow I/O threshold, re-schedule until after all
- other work in the queue is done. */
- if (slow_io_work_running >= slow_work_thread_threshold()) {
- QUEUE_INSERT_TAIL(&wq, q);
- continue;
- }
-
- /* If we encountered a request to run slow I/O work but there is none
- to run, that means it's cancelled => Start over. */
- if (QUEUE_EMPTY(&slow_io_pending_wq))
- continue;
-
- is_slow_work = 1;
- slow_io_work_running++;
-
- q = QUEUE_HEAD(&slow_io_pending_wq);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
-
- /* If there is more slow I/O work, schedule it to be run as well. */
- if (!QUEUE_EMPTY(&slow_io_pending_wq)) {
- QUEUE_INSERT_TAIL(&wq, &run_slow_work_message);
- if (idle_threads > 0)
- uv_cond_signal(&cond);
- }
- }
-
- uv_mutex_unlock(&mutex);
-
- w = QUEUE_DATA(q, struct uv__work, wq);
- w->work(w);
-
- uv_mutex_lock(&w->loop->wq_mutex);
- w->work = NULL; /* Signal uv_cancel() that the work req is done
- executing. */
- QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
- uv_async_send(&w->loop->wq_async);
- uv_mutex_unlock(&w->loop->wq_mutex);
-
- /* Lock `mutex` since that is expected at the start of the next
- * iteration. */
- uv_mutex_lock(&mutex);
- if (is_slow_work) {
- /* `slow_io_work_running` is protected by `mutex`. */
- slow_io_work_running--;
- }
- }
-}
-
-
-static void post(QUEUE* q, enum uv__work_kind kind) {
- uv_mutex_lock(&mutex);
- if (kind == UV__WORK_SLOW_IO) {
- /* Insert into a separate queue. */
- QUEUE_INSERT_TAIL(&slow_io_pending_wq, q);
- if (!QUEUE_EMPTY(&run_slow_work_message)) {
- /* Running slow I/O tasks is already scheduled => Nothing to do here.
- The worker that runs said other task will schedule this one as well. */
- uv_mutex_unlock(&mutex);
- return;
- }
- q = &run_slow_work_message;
- }
-
- QUEUE_INSERT_TAIL(&wq, q);
- if (idle_threads > 0)
- uv_cond_signal(&cond);
- uv_mutex_unlock(&mutex);
-}
-
-
-#ifndef _WIN32
-UV_DESTRUCTOR(static void cleanup(void)) {
- unsigned int i;
-
- if (nthreads == 0)
- return;
-
- post(&exit_message, UV__WORK_CPU);
-
- for (i = 0; i < nthreads; i++)
- if (uv_thread_join(threads + i))
- abort();
-
- if (threads != default_threads)
- uv__free(threads);
-
- uv_mutex_destroy(&mutex);
- uv_cond_destroy(&cond);
-
- threads = NULL;
- nthreads = 0;
-}
-#endif
-
-
-static void init_threads(void) {
- unsigned int i;
- const char* val;
- uv_sem_t sem;
-
- nthreads = ARRAY_SIZE(default_threads);
- val = getenv("UV_THREADPOOL_SIZE");
- if (val != NULL)
- nthreads = atoi(val);
- if (nthreads == 0)
- nthreads = 1;
- if (nthreads > MAX_THREADPOOL_SIZE)
- nthreads = MAX_THREADPOOL_SIZE;
-
- threads = default_threads;
- if (nthreads > ARRAY_SIZE(default_threads)) {
- threads = (uv_thread_t*)uv__malloc(nthreads * sizeof(threads[0]));
- if (threads == NULL) {
- nthreads = ARRAY_SIZE(default_threads);
- threads = default_threads;
- }
- }
-
- if (uv_cond_init(&cond))
- abort();
-
- if (uv_mutex_init(&mutex))
- abort();
-
- QUEUE_INIT(&wq);
- QUEUE_INIT(&slow_io_pending_wq);
- QUEUE_INIT(&run_slow_work_message);
-
- if (uv_sem_init(&sem, 0))
- abort();
-
- for (i = 0; i < nthreads; i++)
- if (uv_thread_create(threads + i, worker, &sem))
- abort();
-
- for (i = 0; i < nthreads; i++)
- uv_sem_wait(&sem);
-
- uv_sem_destroy(&sem);
-}
-
-
-#ifndef _WIN32
-static void reset_once(void) {
- uv_once_t child_once = UV_ONCE_INIT;
- memcpy(&once, &child_once, sizeof(child_once));
-}
-#endif
-
-
-static void init_once(void) {
-#ifndef _WIN32
- /* Re-initialize the threadpool after fork.
- * Note that this discards the global mutex and condition as well
- * as the work queue.
- */
- if (pthread_atfork(NULL, NULL, &reset_once))
- abort();
-#endif
- init_threads();
-}
-
-
-void uv__work_submit(uv_loop_t* loop,
- struct uv__work* w,
- enum uv__work_kind kind,
- void (*work)(struct uv__work* w),
- void (*done)(struct uv__work* w, int status)) {
- uv_once(&once, init_once);
- w->loop = loop;
- w->work = work;
- w->done = done;
- post(&w->wq, kind);
-}
-
-
-static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
- int cancelled;
-
- uv_mutex_lock(&mutex);
- uv_mutex_lock(&w->loop->wq_mutex);
-
- cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
- if (cancelled)
- QUEUE_REMOVE(&w->wq);
-
- uv_mutex_unlock(&w->loop->wq_mutex);
- uv_mutex_unlock(&mutex);
-
- if (!cancelled)
- return UV_EBUSY;
-
- w->work = uv__cancelled;
- uv_mutex_lock(&loop->wq_mutex);
- QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
- uv_async_send(&loop->wq_async);
- uv_mutex_unlock(&loop->wq_mutex);
-
- return 0;
-}
-
-
-void uv__work_done(uv_async_t* handle) {
- struct uv__work* w;
- uv_loop_t* loop;
- QUEUE* q;
- QUEUE wq;
- int err;
-
- loop = container_of(handle, uv_loop_t, wq_async);
- uv_mutex_lock(&loop->wq_mutex);
- QUEUE_MOVE(&loop->wq, &wq);
- uv_mutex_unlock(&loop->wq_mutex);
-
- while (!QUEUE_EMPTY(&wq)) {
- q = QUEUE_HEAD(&wq);
- QUEUE_REMOVE(q);
-
- w = container_of(q, struct uv__work, wq);
- err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
- w->done(w, err);
- }
-}
-
-
-static void uv__queue_work(struct uv__work* w) {
- uv_work_t* req = container_of(w, uv_work_t, work_req);
-
- req->work_cb(req);
-}
-
-
-static void uv__queue_done(struct uv__work* w, int err) {
- uv_work_t* req;
-
- req = container_of(w, uv_work_t, work_req);
- uv__req_unregister(req->loop, req);
-
- if (req->after_work_cb == NULL)
- return;
-
- req->after_work_cb(req, err);
-}
-
-
-int uv_queue_work(uv_loop_t* loop,
- uv_work_t* req,
- uv_work_cb work_cb,
- uv_after_work_cb after_work_cb) {
- if (work_cb == NULL)
- return UV_EINVAL;
-
- uv__req_init(loop, req, UV_WORK);
- req->loop = loop;
- req->work_cb = work_cb;
- req->after_work_cb = after_work_cb;
- uv__work_submit(loop,
- &req->work_req,
- UV__WORK_CPU,
- uv__queue_work,
- uv__queue_done);
- return 0;
-}
-
-
-int uv_cancel(uv_req_t* req) {
- struct uv__work* wreq;
- uv_loop_t* loop;
-
- switch (req->type) {
- case UV_FS:
- loop = ((uv_fs_t*) req)->loop;
- wreq = &((uv_fs_t*) req)->work_req;
- break;
- case UV_GETADDRINFO:
- loop = ((uv_getaddrinfo_t*) req)->loop;
- wreq = &((uv_getaddrinfo_t*) req)->work_req;
- break;
- case UV_GETNAMEINFO:
- loop = ((uv_getnameinfo_t*) req)->loop;
- wreq = &((uv_getnameinfo_t*) req)->work_req;
- break;
- case UV_WORK:
- loop = ((uv_work_t*) req)->loop;
- wreq = &((uv_work_t*) req)->work_req;
- break;
- default:
- return UV_EINVAL;
- }
-
- return uv__work_cancel(loop, req, wreq);
-}
diff --git a/wpiutil/src/main/native/libuv/src/timer.cpp b/wpiutil/src/main/native/libuv/src/timer.cpp
deleted file mode 100644
index dd78bcb..0000000
--- a/wpiutil/src/main/native/libuv/src/timer.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "uv-common.h"
-#include "heap-inl.h"
-
-#include <assert.h>
-#include <limits.h>
-
-
-static struct heap *timer_heap(const uv_loop_t* loop) {
-#ifdef _WIN32
- return (struct heap*) loop->timer_heap;
-#else
- return (struct heap*) &loop->timer_heap;
-#endif
-}
-
-
-static int timer_less_than(const struct heap_node* ha,
- const struct heap_node* hb) {
- const uv_timer_t* a;
- const uv_timer_t* b;
-
- a = container_of(ha, uv_timer_t, heap_node);
- b = container_of(hb, uv_timer_t, heap_node);
-
- if (a->timeout < b->timeout)
- return 1;
- if (b->timeout < a->timeout)
- return 0;
-
- /* Compare start_id when both have the same timeout. start_id is
- * allocated with loop->timer_counter in uv_timer_start().
- */
- if (a->start_id < b->start_id)
- return 1;
- if (b->start_id < a->start_id)
- return 0;
-
- return 0;
-}
-
-
-int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
- uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
- handle->timer_cb = NULL;
- handle->repeat = 0;
- return 0;
-}
-
-
-int uv_timer_start(uv_timer_t* handle,
- uv_timer_cb cb,
- uint64_t timeout,
- uint64_t repeat) {
- uint64_t clamped_timeout;
-
- if (cb == NULL)
- return UV_EINVAL;
-
- if (uv__is_active(handle))
- uv_timer_stop(handle);
-
- clamped_timeout = handle->loop->time + timeout;
- if (clamped_timeout < timeout)
- clamped_timeout = (uint64_t) -1;
-
- handle->timer_cb = cb;
- handle->timeout = clamped_timeout;
- handle->repeat = repeat;
- /* start_id is the second index to be compared in uv__timer_cmp() */
- handle->start_id = handle->loop->timer_counter++;
-
- heap_insert(timer_heap(handle->loop),
- (struct heap_node*) &handle->heap_node,
- timer_less_than);
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-int uv_timer_stop(uv_timer_t* handle) {
- if (!uv__is_active(handle))
- return 0;
-
- heap_remove(timer_heap(handle->loop),
- (struct heap_node*) &handle->heap_node,
- timer_less_than);
- uv__handle_stop(handle);
-
- return 0;
-}
-
-
-int uv_timer_again(uv_timer_t* handle) {
- if (handle->timer_cb == NULL)
- return UV_EINVAL;
-
- if (handle->repeat) {
- uv_timer_stop(handle);
- uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
- }
-
- return 0;
-}
-
-
-void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
- handle->repeat = repeat;
-}
-
-
-uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
- return handle->repeat;
-}
-
-
-int uv__next_timeout(const uv_loop_t* loop) {
- const struct heap_node* heap_node;
- const uv_timer_t* handle;
- uint64_t diff;
-
- heap_node = heap_min(timer_heap(loop));
- if (heap_node == NULL)
- return -1; /* block indefinitely */
-
- handle = container_of(heap_node, uv_timer_t, heap_node);
- if (handle->timeout <= loop->time)
- return 0;
-
- diff = handle->timeout - loop->time;
- if (diff > INT_MAX)
- diff = INT_MAX;
-
- return (int) diff;
-}
-
-
-void uv__run_timers(uv_loop_t* loop) {
- struct heap_node* heap_node;
- uv_timer_t* handle;
-
- for (;;) {
- heap_node = heap_min(timer_heap(loop));
- if (heap_node == NULL)
- break;
-
- handle = container_of(heap_node, uv_timer_t, heap_node);
- if (handle->timeout > loop->time)
- break;
-
- uv_timer_stop(handle);
- uv_timer_again(handle);
- handle->timer_cb(handle);
- }
-}
-
-
-void uv__timer_close(uv_timer_t* handle) {
- uv_timer_stop(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/android-ifaddrs.cpp b/wpiutil/src/main/native/libuv/src/unix/android-ifaddrs.cpp
deleted file mode 100644
index ab6b029..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/android-ifaddrs.cpp
+++ /dev/null
@@ -1,710 +0,0 @@
-/*
-Copyright (c) 2013, Kenneth MacKay
-Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
-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.
-
-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 HOLDER 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 "uv/android-ifaddrs.h"
-#include "uv-common.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-typedef struct NetlinkList
-{
- struct NetlinkList *m_next;
- struct nlmsghdr *m_data;
- unsigned int m_size;
-} NetlinkList;
-
-static int netlink_socket(pid_t *p_pid)
-{
- struct sockaddr_nl l_addr;
- socklen_t l_len;
-
- int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if(l_socket < 0)
- {
- return -1;
- }
-
- memset(&l_addr, 0, sizeof(l_addr));
- l_addr.nl_family = AF_NETLINK;
- if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
- {
- close(l_socket);
- return -1;
- }
-
- l_len = sizeof(l_addr);
- if(getsockname(l_socket, (struct sockaddr *)&l_addr, &l_len) < 0)
- {
- close(l_socket);
- return -1;
- }
- *p_pid = l_addr.nl_pid;
-
- return l_socket;
-}
-
-static int netlink_send(int p_socket, int p_request)
-{
- char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
-
- struct nlmsghdr *l_hdr;
- struct rtgenmsg *l_msg;
- struct sockaddr_nl l_addr;
-
- memset(l_buffer, 0, sizeof(l_buffer));
-
- l_hdr = (struct nlmsghdr *)l_buffer;
- l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
-
- l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
- l_hdr->nlmsg_type = p_request;
- l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
- l_hdr->nlmsg_pid = 0;
- l_hdr->nlmsg_seq = p_socket;
- l_msg->rtgen_family = AF_UNSPEC;
-
- memset(&l_addr, 0, sizeof(l_addr));
- l_addr.nl_family = AF_NETLINK;
- return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
-}
-
-static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
-{
- struct sockaddr_nl l_addr;
- struct msghdr l_msg;
-
- struct iovec l_iov;
- l_iov.iov_base = p_buffer;
- l_iov.iov_len = p_len;
-
- for(;;)
- {
- int l_result;
- l_msg.msg_name = (void *)&l_addr;
- l_msg.msg_namelen = sizeof(l_addr);
- l_msg.msg_iov = &l_iov;
- l_msg.msg_iovlen = 1;
- l_msg.msg_control = NULL;
- l_msg.msg_controllen = 0;
- l_msg.msg_flags = 0;
- l_result = recvmsg(p_socket, &l_msg, 0);
-
- if(l_result < 0)
- {
- if(errno == EINTR)
- {
- continue;
- }
- return -2;
- }
-
- /* Buffer was too small */
- if(l_msg.msg_flags & MSG_TRUNC)
- {
- return -1;
- }
- return l_result;
- }
-}
-
-static struct nlmsghdr *getNetlinkResponse(int p_socket, pid_t p_pid, int *p_size, int *p_done)
-{
- size_t l_size = 4096;
- void *l_buffer = NULL;
-
- for(;;)
- {
- int l_read;
-
- uv__free(l_buffer);
- l_buffer = uv__malloc(l_size);
- if (l_buffer == NULL)
- {
- return NULL;
- }
-
- l_read = netlink_recv(p_socket, l_buffer, l_size);
- *p_size = l_read;
- if(l_read == -2)
- {
- uv__free(l_buffer);
- return NULL;
- }
- if(l_read >= 0)
- {
- struct nlmsghdr *l_hdr;
- for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- *p_done = 1;
- break;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_ERROR)
- {
- uv__free(l_buffer);
- return NULL;
- }
- }
- return l_buffer;
- }
-
- l_size *= 2;
- }
-}
-
-static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
-{
- NetlinkList *l_item = (NetlinkList*)uv__malloc(sizeof(NetlinkList));
- if (l_item == NULL)
- {
- return NULL;
- }
-
- l_item->m_next = NULL;
- l_item->m_data = p_data;
- l_item->m_size = p_size;
- return l_item;
-}
-
-static void freeResultList(NetlinkList *p_list)
-{
- NetlinkList *l_cur;
- while(p_list)
- {
- l_cur = p_list;
- p_list = p_list->m_next;
- uv__free(l_cur->m_data);
- uv__free(l_cur);
- }
-}
-
-static NetlinkList *getResultList(int p_socket, int p_request, pid_t p_pid)
-{
- int l_size;
- int l_done;
- NetlinkList *l_list;
- NetlinkList *l_end;
-
- if(netlink_send(p_socket, p_request) < 0)
- {
- return NULL;
- }
-
- l_list = NULL;
- l_end = NULL;
-
- l_done = 0;
- while(!l_done)
- {
- NetlinkList *l_item;
-
- struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, p_pid, &l_size, &l_done);
- /* Error */
- if(!l_hdr)
- {
- freeResultList(l_list);
- return NULL;
- }
-
- l_item = newListItem(l_hdr, l_size);
- if (!l_item)
- {
- freeResultList(l_list);
- return NULL;
- }
- if(!l_list)
- {
- l_list = l_item;
- }
- else
- {
- l_end->m_next = l_item;
- }
- l_end = l_item;
- }
- return l_list;
-}
-
-static size_t maxSize(size_t a, size_t b)
-{
- return (a > b ? a : b);
-}
-
-static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
-{
- switch(p_family)
- {
- case AF_INET:
- return sizeof(struct sockaddr_in);
- case AF_INET6:
- return sizeof(struct sockaddr_in6);
- case AF_PACKET:
- return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
- default:
- return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
- }
-}
-
-static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
-{
- switch(p_family)
- {
- case AF_INET:
- memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
- break;
- case AF_INET6:
- memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
- break;
- case AF_PACKET:
- memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
- ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
- break;
- default:
- memcpy(p_dest->sa_data, p_data, p_size);
- break;
- }
- p_dest->sa_family = p_family;
-}
-
-static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
-{
- if(!*p_resultList)
- {
- *p_resultList = p_entry;
- }
- else
- {
- struct ifaddrs *l_cur = *p_resultList;
- while(l_cur->ifa_next)
- {
- l_cur = l_cur->ifa_next;
- }
- l_cur->ifa_next = p_entry;
- }
-}
-
-static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
-{
- struct ifaddrs *l_entry;
-
- char *l_index;
- char *l_name;
- char *l_addr;
- char *l_data;
-
- struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
-
- size_t l_nameSize = 0;
- size_t l_addrSize = 0;
- size_t l_dataSize = 0;
-
- size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
- struct rtattr *l_rta;
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFLA_ADDRESS:
- case IFLA_BROADCAST:
- l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
- break;
- case IFLA_IFNAME:
- l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
- break;
- case IFLA_STATS:
- l_dataSize += NLMSG_ALIGN(l_rtaSize);
- break;
- default:
- break;
- }
- }
-
- l_entry = (struct ifaddrs*)uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
- if (l_entry == NULL)
- {
- return -1;
- }
- memset(l_entry, 0, sizeof(struct ifaddrs));
- l_entry->ifa_name = "";
-
- l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
- l_name = l_index + sizeof(int);
- l_addr = l_name + l_nameSize;
- l_data = l_addr + l_addrSize;
-
- /* Save the interface index so we can look it up when handling the
- * addresses.
- */
- memcpy(l_index, &l_info->ifi_index, sizeof(int));
-
- l_entry->ifa_flags = l_info->ifi_flags;
-
- l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
- for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- void *l_rtaData = RTA_DATA(l_rta);
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFLA_ADDRESS:
- case IFLA_BROADCAST:
- {
- size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
- makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
- ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
- ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
- if(l_rta->rta_type == IFLA_ADDRESS)
- {
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
- }
- l_addr += NLMSG_ALIGN(l_addrLen);
- break;
- }
- case IFLA_IFNAME:
- strncpy(l_name, l_rtaData, l_rtaDataSize);
- l_name[l_rtaDataSize] = '\0';
- l_entry->ifa_name = l_name;
- break;
- case IFLA_STATS:
- memcpy(l_data, l_rtaData, l_rtaDataSize);
- l_entry->ifa_data = l_data;
- break;
- default:
- break;
- }
- }
-
- addToEnd(p_resultList, l_entry);
- return 0;
-}
-
-static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
-{
- int l_num = 0;
- struct ifaddrs *l_cur = *p_links;
- while(l_cur && l_num < p_numLinks)
- {
- char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
- int l_index;
- memcpy(&l_index, l_indexPtr, sizeof(int));
- if(l_index == p_index)
- {
- return l_cur;
- }
-
- l_cur = l_cur->ifa_next;
- ++l_num;
- }
- return NULL;
-}
-
-static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
-{
- struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
- struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
-
- size_t l_nameSize = 0;
- size_t l_addrSize = 0;
-
- int l_addedNetmask = 0;
-
- size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- struct rtattr *l_rta;
- struct ifaddrs *l_entry;
-
- char *l_name;
- char *l_addr;
-
- for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- if(l_info->ifa_family == AF_PACKET)
- {
- continue;
- }
-
- switch(l_rta->rta_type)
- {
- case IFA_ADDRESS:
- case IFA_LOCAL:
- if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
- {
- /* Make room for netmask */
- l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
- l_addedNetmask = 1;
- }
- case IFA_BROADCAST:
- l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
- break;
- case IFA_LABEL:
- l_nameSize += NLMSG_ALIGN(l_rtaDataSize + 1);
- break;
- default:
- break;
- }
- }
-
- l_entry = (struct ifaddrs*)uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
- if (l_entry == NULL)
- {
- return -1;
- }
- memset(l_entry, 0, sizeof(struct ifaddrs));
- l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
-
- l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
- l_addr = l_name + l_nameSize;
-
- l_entry->ifa_flags = l_info->ifa_flags;
- if(l_interface)
- {
- l_entry->ifa_flags |= l_interface->ifa_flags;
- }
-
- l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
- for(l_rta = IFA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
- {
- void *l_rtaData = RTA_DATA(l_rta);
- size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
- switch(l_rta->rta_type)
- {
- case IFA_ADDRESS:
- case IFA_BROADCAST:
- case IFA_LOCAL:
- {
- size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
- makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
- if(l_info->ifa_family == AF_INET6)
- {
- if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
- {
- ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
- }
- }
-
- /* Apparently in a point-to-point network IFA_ADDRESS contains
- * the dest address and IFA_LOCAL contains the local address
- */
- if(l_rta->rta_type == IFA_ADDRESS)
- {
- if(l_entry->ifa_addr)
- {
- l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- }
- else if(l_rta->rta_type == IFA_LOCAL)
- {
- if(l_entry->ifa_addr)
- {
- l_entry->ifa_dstaddr = l_entry->ifa_addr;
- }
- l_entry->ifa_addr = (struct sockaddr *)l_addr;
- }
- else
- {
- l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
- }
- l_addr += NLMSG_ALIGN(l_addrLen);
- break;
- }
- case IFA_LABEL:
- strncpy(l_name, l_rtaData, l_rtaDataSize);
- l_name[l_rtaDataSize] = '\0';
- l_entry->ifa_name = l_name;
- break;
- default:
- break;
- }
- }
-
- if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
- {
- unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
- unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
- unsigned char l_mask[16] = {0};
- unsigned i;
- for(i=0; i<(l_prefix/8); ++i)
- {
- l_mask[i] = 0xff;
- }
- if(l_prefix % 8)
- {
- l_mask[i] = 0xff << (8 - (l_prefix % 8));
- }
-
- makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
- l_entry->ifa_netmask = (struct sockaddr *)l_addr;
- }
-
- addToEnd(p_resultList, l_entry);
- return 0;
-}
-
-static int interpretLinks(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
-{
-
- int l_numLinks = 0;
- for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
- {
- unsigned int l_nlsize = p_netlinkList->m_size;
- struct nlmsghdr *l_hdr;
- for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- break;
- }
-
- if(l_hdr->nlmsg_type == RTM_NEWLINK)
- {
- if(interpretLink(l_hdr, p_resultList) == -1)
- {
- return -1;
- }
- ++l_numLinks;
- }
- }
- }
- return l_numLinks;
-}
-
-static int interpretAddrs(int p_socket, pid_t p_pid, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
-{
- for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
- {
- unsigned int l_nlsize = p_netlinkList->m_size;
- struct nlmsghdr *l_hdr;
- for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
- {
- if((pid_t)l_hdr->nlmsg_pid != p_pid || (int)l_hdr->nlmsg_seq != p_socket)
- {
- continue;
- }
-
- if(l_hdr->nlmsg_type == NLMSG_DONE)
- {
- break;
- }
-
- if(l_hdr->nlmsg_type == RTM_NEWADDR)
- {
- if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
- {
- return -1;
- }
- }
- }
- }
- return 0;
-}
-
-int getifaddrs(struct ifaddrs **ifap)
-{
- int l_socket;
- int l_result;
- int l_numLinks;
- pid_t l_pid;
- NetlinkList *l_linkResults;
- NetlinkList *l_addrResults;
-
- if(!ifap)
- {
- return -1;
- }
- *ifap = NULL;
-
- l_socket = netlink_socket(&l_pid);
- if(l_socket < 0)
- {
- return -1;
- }
-
- l_linkResults = getResultList(l_socket, RTM_GETLINK, l_pid);
- if(!l_linkResults)
- {
- close(l_socket);
- return -1;
- }
-
- l_addrResults = getResultList(l_socket, RTM_GETADDR, l_pid);
- if(!l_addrResults)
- {
- close(l_socket);
- freeResultList(l_linkResults);
- return -1;
- }
-
- l_result = 0;
- l_numLinks = interpretLinks(l_socket, l_pid, l_linkResults, ifap);
- if(l_numLinks == -1 || interpretAddrs(l_socket, l_pid, l_addrResults, ifap, l_numLinks) == -1)
- {
- l_result = -1;
- }
-
- freeResultList(l_linkResults);
- freeResultList(l_addrResults);
- close(l_socket);
- return l_result;
-}
-
-void freeifaddrs(struct ifaddrs *ifa)
-{
- struct ifaddrs *l_cur;
- while(ifa)
- {
- l_cur = ifa;
- ifa = ifa->ifa_next;
- uv__free(l_cur);
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/async.cpp b/wpiutil/src/main/native/libuv/src/unix/async.cpp
deleted file mode 100644
index a5c47bc..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/async.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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.
- */
-
-/* This file contains both the uv__async internal infrastructure and the
- * user-facing uv_async_t functions.
- */
-
-#include "uv.h"
-#include "internal.h"
-#include "atomic-ops.h"
-
-#include <errno.h>
-#include <stdio.h> /* snprintf() */
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-static void uv__async_send(uv_loop_t* loop);
-static int uv__async_start(uv_loop_t* loop);
-static int uv__async_eventfd(void);
-
-
-int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
- int err;
-
- err = uv__async_start(loop);
- if (err)
- return err;
-
- uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
- handle->async_cb = async_cb;
- handle->pending = 0;
-
- QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-int uv_async_send(uv_async_t* handle) {
- /* Do a cheap read first. */
- if (ACCESS_ONCE(int, handle->pending) != 0)
- return 0;
-
- /* Tell the other thread we're busy with the handle. */
- if (cmpxchgi(&handle->pending, 0, 1) != 0)
- return 0;
-
- /* Wake up the other thread's event loop. */
- uv__async_send(handle->loop);
-
- /* Tell the other thread we're done. */
- if (cmpxchgi(&handle->pending, 1, 2) != 1)
- abort();
-
- return 0;
-}
-
-
-/* Only call this from the event loop thread. */
-static int uv__async_spin(uv_async_t* handle) {
- int rc;
-
- for (;;) {
- /* rc=0 -- handle is not pending.
- * rc=1 -- handle is pending, other thread is still working with it.
- * rc=2 -- handle is pending, other thread is done.
- */
- rc = cmpxchgi(&handle->pending, 2, 0);
-
- if (rc != 1)
- return rc;
-
- /* Other thread is busy with this handle, spin until it's done. */
- cpu_relax();
- }
-}
-
-
-void uv__async_close(uv_async_t* handle) {
- uv__async_spin(handle);
- QUEUE_REMOVE(&handle->queue);
- uv__handle_stop(handle);
-}
-
-
-static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- char buf[1024];
- ssize_t r;
- QUEUE queue;
- QUEUE* q;
- uv_async_t* h;
-
- assert(w == &loop->async_io_watcher);
-
- for (;;) {
- r = read(w->fd, buf, sizeof(buf));
-
- if (r == sizeof(buf))
- continue;
-
- if (r != -1)
- break;
-
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- break;
-
- if (errno == EINTR)
- continue;
-
- abort();
- }
-
- QUEUE_MOVE(&loop->async_handles, &queue);
- while (!QUEUE_EMPTY(&queue)) {
- q = QUEUE_HEAD(&queue);
- h = QUEUE_DATA(q, uv_async_t, queue);
-
- QUEUE_REMOVE(q);
- QUEUE_INSERT_TAIL(&loop->async_handles, q);
-
- if (0 == uv__async_spin(h))
- continue; /* Not pending. */
-
- if (h->async_cb == NULL)
- continue;
-
- h->async_cb(h);
- }
-}
-
-
-static void uv__async_send(uv_loop_t* loop) {
- const void* buf;
- ssize_t len;
- int fd;
- int r;
-
- buf = "";
- len = 1;
- fd = loop->async_wfd;
-
-#if defined(__linux__)
- if (fd == -1) {
- static const uint64_t val = 1;
- buf = &val;
- len = sizeof(val);
- fd = loop->async_io_watcher.fd; /* eventfd */
- }
-#endif
-
- do
- r = write(fd, buf, len);
- while (r == -1 && errno == EINTR);
-
- if (r == len)
- return;
-
- if (r == -1)
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- return;
-
- abort();
-}
-
-
-static int uv__async_start(uv_loop_t* loop) {
- int pipefd[2];
- int err;
-
- if (loop->async_io_watcher.fd != -1)
- return 0;
-
- err = uv__async_eventfd();
- if (err >= 0) {
- pipefd[0] = err;
- pipefd[1] = -1;
- }
- else if (err == UV_ENOSYS) {
- err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
-#if defined(__linux__)
- /* Save a file descriptor by opening one of the pipe descriptors as
- * read/write through the procfs. That file descriptor can then
- * function as both ends of the pipe.
- */
- if (err == 0) {
- char buf[32];
- int fd;
-
- snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
- fd = uv__open_cloexec(buf, O_RDWR);
- if (fd >= 0) {
- uv__close(pipefd[0]);
- uv__close(pipefd[1]);
- pipefd[0] = fd;
- pipefd[1] = fd;
- }
- }
-#endif
- }
-
- if (err < 0)
- return err;
-
- uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
- uv__io_start(loop, &loop->async_io_watcher, POLLIN);
- loop->async_wfd = pipefd[1];
-
- return 0;
-}
-
-
-int uv__async_fork(uv_loop_t* loop) {
- if (loop->async_io_watcher.fd == -1) /* never started */
- return 0;
-
- uv__async_stop(loop);
-
- return uv__async_start(loop);
-}
-
-
-void uv__async_stop(uv_loop_t* loop) {
- if (loop->async_io_watcher.fd == -1)
- return;
-
- if (loop->async_wfd != -1) {
- if (loop->async_wfd != loop->async_io_watcher.fd)
- uv__close(loop->async_wfd);
- loop->async_wfd = -1;
- }
-
- uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
- uv__close(loop->async_io_watcher.fd);
- loop->async_io_watcher.fd = -1;
-}
-
-
-static int uv__async_eventfd(void) {
-#if defined(__linux__)
- static int no_eventfd2;
- static int no_eventfd;
- int fd;
-
- if (no_eventfd2)
- goto skip_eventfd2;
-
- fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
- if (fd != -1)
- return fd;
-
- if (errno != ENOSYS)
- return UV__ERR(errno);
-
- no_eventfd2 = 1;
-
-skip_eventfd2:
-
- if (no_eventfd)
- goto skip_eventfd;
-
- fd = uv__eventfd(0);
- if (fd != -1) {
- uv__cloexec(fd, 1);
- uv__nonblock(fd, 1);
- return fd;
- }
-
- if (errno != ENOSYS)
- return UV__ERR(errno);
-
- no_eventfd = 1;
-
-skip_eventfd:
-
-#endif
-
- return UV_ENOSYS;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/atomic-ops.h b/wpiutil/src/main/native/libuv/src/unix/atomic-ops.h
deleted file mode 100644
index 541a6c8..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/atomic-ops.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#ifndef UV_ATOMIC_OPS_H_
-#define UV_ATOMIC_OPS_H_
-
-#include "internal.h" /* UV_UNUSED */
-
-#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-#include <atomic.h>
-#endif
-
-UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
-UV_UNUSED(static void cpu_relax(void));
-
-/* Prefer hand-rolled assembly over the gcc builtins because the latter also
- * issue full memory barriers.
- */
-UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
-#if defined(__i386__) || defined(__x86_64__)
- int out;
- __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
- : "=a" (out), "+m" (*(volatile int*) ptr)
- : "r" (newval), "0" (oldval)
- : "memory");
- return out;
-#elif defined(_AIX) && defined(__xlC__)
- const int out = (*(volatile int*) ptr);
- __compare_and_swap(ptr, &oldval, newval);
- return out;
-#elif defined(__MVS__)
- unsigned int op4;
- if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
- (unsigned int*) ptr, *ptr, &op4))
- return oldval;
- else
- return op4;
-#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
- return atomic_cas_uint((uint_t *)ptr, (uint_t)oldval, (uint_t)newval);
-#else
- return __sync_val_compare_and_swap(ptr, oldval, newval);
-#endif
-}
-
-UV_UNUSED(static void cpu_relax(void)) {
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
-#endif
-}
-
-#endif /* UV_ATOMIC_OPS_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/unix/bsd-ifaddrs.cpp b/wpiutil/src/main/native/libuv/src/unix/bsd-ifaddrs.cpp
deleted file mode 100644
index a01aa8d..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/bsd-ifaddrs.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <errno.h>
-#include <stddef.h>
-
-#include <ifaddrs.h>
-#include <net/if.h>
-#if !defined(__CYGWIN__) && !defined(__MSYS__)
-#include <net/if_dl.h>
-#endif
-
-#if defined(__HAIKU__)
-#define IFF_RUNNING IFF_LINK
-#endif
-
-static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
- if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
- return 1;
- if (ent->ifa_addr == NULL)
- return 1;
-#if !defined(__CYGWIN__) && !defined(__MSYS__)
- /*
- * If `exclude_type` is `UV__EXCLUDE_IFPHYS`, just see whether `sa_family`
- * equals to `AF_LINK` or not. Otherwise, the result depends on the operation
- * system with `AF_LINK` or `PF_INET`.
- */
- if (exclude_type == UV__EXCLUDE_IFPHYS)
- return (ent->ifa_addr->sa_family != AF_LINK);
-#endif
-#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || \
- defined(__HAIKU__)
- /*
- * On BSD getifaddrs returns information related to the raw underlying
- * devices. We're not interested in this information.
- */
- if (ent->ifa_addr->sa_family == AF_LINK)
- return 1;
-#elif defined(__NetBSD__) || defined(__OpenBSD__)
- if (ent->ifa_addr->sa_family != PF_INET &&
- ent->ifa_addr->sa_family != PF_INET6)
- return 1;
-#endif
- return 0;
-}
-
-int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
- struct ifaddrs* addrs;
- struct ifaddrs* ent;
- uv_interface_address_t* address;
- int i;
-
- *count = 0;
- *addresses = NULL;
-
- if (getifaddrs(&addrs) != 0)
- return UV__ERR(errno);
-
- /* Count the number of interfaces */
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
- continue;
- (*count)++;
- }
-
- if (*count == 0) {
- freeifaddrs(addrs);
- return 0;
- }
-
- /* Make sure the memory is initiallized to zero using calloc() */
- *addresses = (uv_interface_address_t*)uv__calloc(*count, sizeof(**addresses));
-
- if (*addresses == NULL) {
- freeifaddrs(addrs);
- return UV_ENOMEM;
- }
-
- address = *addresses;
-
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
- continue;
-
- address->name = uv__strdup(ent->ifa_name);
-
- if (ent->ifa_addr->sa_family == AF_INET6) {
- address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
- } else {
- address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
- }
-
- if (ent->ifa_netmask->sa_family == AF_INET6) {
- address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
- } else {
- address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
- }
-
- address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
- address++;
- }
-
-#if !(defined(__CYGWIN__) || defined(__MSYS__))
- /* Fill in physical addresses for each interface */
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
- continue;
-
- address = *addresses;
-
- for (i = 0; i < *count; i++) {
- if (strcmp(address->name, ent->ifa_name) == 0) {
- struct sockaddr_dl* sa_addr;
- sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
- memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
- }
- address++;
- }
- }
-#endif
-
- freeifaddrs(addrs);
-
- return 0;
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(addresses[i].name);
- }
-
- uv__free(addresses);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/core.cpp b/wpiutil/src/main/native/libuv/src/unix/core.cpp
deleted file mode 100644
index 77bb337..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/core.cpp
+++ /dev/null
@@ -1,1509 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stddef.h> /* NULL */
-#include <stdio.h> /* printf */
-#include <stdlib.h>
-#include <string.h> /* strerror */
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
-#include <sys/uio.h> /* writev */
-#include <sys/resource.h> /* getrusage */
-#include <pwd.h>
-#include <sys/utsname.h>
-#include <sys/time.h>
-
-#ifdef __sun
-# include <sys/filio.h>
-# include <sys/types.h>
-# include <sys/wait.h>
-#endif
-
-#ifdef __APPLE__
-# include <mach-o/dyld.h> /* _NSGetExecutablePath */
-# include <sys/filio.h>
-# if defined(O_CLOEXEC)
-# define UV__O_CLOEXEC O_CLOEXEC
-# endif
-#endif
-
-#if defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || \
- defined(__NetBSD__)
-# include <sys/sysctl.h>
-# include <sys/filio.h>
-# include <sys/wait.h>
-# define UV__O_CLOEXEC O_CLOEXEC
-# if defined(__FreeBSD__) && __FreeBSD__ >= 10
-# define uv__accept4 accept4
-# endif
-# if defined(__NetBSD__)
-# define uv__accept4(a, b, c, d) paccept((a), (b), (c), NULL, (d))
-# endif
-# if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
-# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
-# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
-# endif
-# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
-# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
-# endif
-#endif
-
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
-# include <dlfcn.h> /* for dlsym */
-#endif
-
-#if defined(__MVS__)
-#include <sys/ioctl.h>
-#endif
-
-#if defined(__linux__)
-#include <sys/syscall.h>
-#endif
-
-static int uv__run_pending(uv_loop_t* loop);
-
-/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
-STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
-STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
- sizeof(((struct iovec*) 0)->iov_base));
-STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
- sizeof(((struct iovec*) 0)->iov_len));
-STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
-STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
-
-
-uint64_t uv_hrtime(void) {
- return uv__hrtime(UV_CLOCK_PRECISE);
-}
-
-
-void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
- assert(!uv__is_closing(handle));
-
- handle->flags |= UV_HANDLE_CLOSING;
- handle->close_cb = close_cb;
-
- switch (handle->type) {
- case UV_NAMED_PIPE:
- uv__pipe_close((uv_pipe_t*)handle);
- break;
-
- case UV_TTY:
- uv__stream_close((uv_stream_t*)handle);
- break;
-
- case UV_TCP:
- uv__tcp_close((uv_tcp_t*)handle);
- break;
-
- case UV_UDP:
- uv__udp_close((uv_udp_t*)handle);
- break;
-
- case UV_PREPARE:
- uv__prepare_close((uv_prepare_t*)handle);
- break;
-
- case UV_CHECK:
- uv__check_close((uv_check_t*)handle);
- break;
-
- case UV_IDLE:
- uv__idle_close((uv_idle_t*)handle);
- break;
-
- case UV_ASYNC:
- uv__async_close((uv_async_t*)handle);
- break;
-
- case UV_TIMER:
- uv__timer_close((uv_timer_t*)handle);
- break;
-
- case UV_PROCESS:
- uv__process_close((uv_process_t*)handle);
- break;
-
- case UV_FS_EVENT:
- uv__fs_event_close((uv_fs_event_t*)handle);
- break;
-
- case UV_POLL:
- uv__poll_close((uv_poll_t*)handle);
- break;
-
- case UV_FS_POLL:
- uv__fs_poll_close((uv_fs_poll_t*)handle);
- /* Poll handles use file system requests, and one of them may still be
- * running. The poll code will call uv__make_close_pending() for us. */
- return;
-
- case UV_SIGNAL:
- uv__signal_close((uv_signal_t*) handle);
- /* Signal handles may not be closed immediately. The signal code will
- * itself close uv__make_close_pending whenever appropriate. */
- return;
-
- default:
- assert(0);
- }
-
- uv__make_close_pending(handle);
-}
-
-int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
- int r;
- int fd;
- socklen_t len;
-
- if (handle == NULL || value == NULL)
- return UV_EINVAL;
-
- if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
- fd = uv__stream_fd((uv_stream_t*) handle);
- else if (handle->type == UV_UDP)
- fd = ((uv_udp_t *) handle)->io_watcher.fd;
- else
- return UV_ENOTSUP;
-
- len = sizeof(*value);
-
- if (*value == 0)
- r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
- else
- r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
-
- if (r < 0)
- return UV__ERR(errno);
-
- return 0;
-}
-
-void uv__make_close_pending(uv_handle_t* handle) {
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- handle->next_closing = handle->loop->closing_handles;
- handle->loop->closing_handles = handle;
-}
-
-int uv__getiovmax(void) {
-#if defined(IOV_MAX)
- return IOV_MAX;
-#elif defined(_SC_IOV_MAX)
- static int iovmax = -1;
- if (iovmax == -1) {
- iovmax = sysconf(_SC_IOV_MAX);
- /* On some embedded devices (arm-linux-uclibc based ip camera),
- * sysconf(_SC_IOV_MAX) can not get the correct value. The return
- * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
- */
- if (iovmax == -1) iovmax = 1;
- }
- return iovmax;
-#else
- return 1024;
-#endif
-}
-
-
-static void uv__finish_close(uv_handle_t* handle) {
- /* Note: while the handle is in the UV_HANDLE_CLOSING state now, it's still
- * possible for it to be active in the sense that uv__is_active() returns
- * true.
- *
- * A good example is when the user calls uv_shutdown(), immediately followed
- * by uv_close(). The handle is considered active at this point because the
- * completion of the shutdown req is still pending.
- */
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- handle->flags |= UV_HANDLE_CLOSED;
-
- switch (handle->type) {
- case UV_PREPARE:
- case UV_CHECK:
- case UV_IDLE:
- case UV_ASYNC:
- case UV_TIMER:
- case UV_PROCESS:
- case UV_FS_EVENT:
- case UV_FS_POLL:
- case UV_POLL:
- case UV_SIGNAL:
- break;
-
- case UV_NAMED_PIPE:
- case UV_TCP:
- case UV_TTY:
- uv__stream_destroy((uv_stream_t*)handle);
- break;
-
- case UV_UDP:
- uv__udp_finish_close((uv_udp_t*)handle);
- break;
-
- default:
- assert(0);
- break;
- }
-
- uv__handle_unref(handle);
- QUEUE_REMOVE(&handle->handle_queue);
-
- if (handle->close_cb) {
- handle->close_cb(handle);
- }
-}
-
-
-static void uv__run_closing_handles(uv_loop_t* loop) {
- uv_handle_t* p;
- uv_handle_t* q;
-
- p = loop->closing_handles;
- loop->closing_handles = NULL;
-
- while (p) {
- q = p->next_closing;
- uv__finish_close(p);
- p = q;
- }
-}
-
-
-int uv_is_closing(const uv_handle_t* handle) {
- return uv__is_closing(handle);
-}
-
-
-int uv_backend_fd(const uv_loop_t* loop) {
- return loop->backend_fd;
-}
-
-
-int uv_backend_timeout(const uv_loop_t* loop) {
- if (loop->stop_flag != 0)
- return 0;
-
- if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
- return 0;
-
- if (!QUEUE_EMPTY(&loop->idle_handles))
- return 0;
-
- if (!QUEUE_EMPTY(&loop->pending_queue))
- return 0;
-
- if (loop->closing_handles)
- return 0;
-
- return uv__next_timeout(loop);
-}
-
-
-static int uv__loop_alive(const uv_loop_t* loop) {
- return uv__has_active_handles(loop) ||
- uv__has_active_reqs(loop) ||
- loop->closing_handles != NULL;
-}
-
-
-int uv_loop_alive(const uv_loop_t* loop) {
- return uv__loop_alive(loop);
-}
-
-
-int uv_run(uv_loop_t* loop, uv_run_mode mode) {
- int timeout;
- int r;
- int ran_pending;
-
- r = uv__loop_alive(loop);
- if (!r)
- uv__update_time(loop);
-
- while (r != 0 && loop->stop_flag == 0) {
- uv__update_time(loop);
- uv__run_timers(loop);
- ran_pending = uv__run_pending(loop);
- uv__run_idle(loop);
- uv__run_prepare(loop);
-
- timeout = 0;
- if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
- timeout = uv_backend_timeout(loop);
-
- uv__io_poll(loop, timeout);
- uv__run_check(loop);
- uv__run_closing_handles(loop);
-
- if (mode == UV_RUN_ONCE) {
- /* UV_RUN_ONCE implies forward progress: at least one callback must have
- * been invoked when it returns. uv__io_poll() can return without doing
- * I/O (meaning: no callbacks) when its timeout expires - which means we
- * have pending timers that satisfy the forward progress constraint.
- *
- * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
- * the check.
- */
- uv__update_time(loop);
- uv__run_timers(loop);
- }
-
- r = uv__loop_alive(loop);
- if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
- break;
- }
-
- /* The if statement lets gcc compile it to a conditional store. Avoids
- * dirtying a cache line.
- */
- if (loop->stop_flag != 0)
- loop->stop_flag = 0;
-
- return r;
-}
-
-
-void uv_update_time(uv_loop_t* loop) {
- uv__update_time(loop);
-}
-
-
-int uv_is_active(const uv_handle_t* handle) {
- return uv__is_active(handle);
-}
-
-
-/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
-int uv__socket(int domain, int type, int protocol) {
- int sockfd;
- int err;
-
-#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
- sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
- if (sockfd != -1)
- return sockfd;
-
- if (errno != EINVAL)
- return UV__ERR(errno);
-#endif
-
- sockfd = socket(domain, type, protocol);
- if (sockfd == -1)
- return UV__ERR(errno);
-
- err = uv__nonblock(sockfd, 1);
- if (err == 0)
- err = uv__cloexec(sockfd, 1);
-
- if (err) {
- uv__close(sockfd);
- return err;
- }
-
-#if defined(SO_NOSIGPIPE)
- {
- int on = 1;
- setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
- }
-#endif
-
- return sockfd;
-}
-
-/* get a file pointer to a file in read-only and close-on-exec mode */
-FILE* uv__open_file(const char* path) {
- int fd;
- FILE* fp;
-
- fd = uv__open_cloexec(path, O_RDONLY);
- if (fd < 0)
- return NULL;
-
- fp = fdopen(fd, "r");
- if (fp == NULL)
- uv__close(fd);
-
- return fp;
-}
-
-
-int uv__accept(int sockfd) {
- int peerfd;
- int err;
-
- assert(sockfd >= 0);
-
- while (1) {
-#if defined(__linux__) || \
- (defined(__FreeBSD__) && __FreeBSD__ >= 10) || \
- defined(__NetBSD__)
- static int no_accept4;
-
- if (no_accept4)
- goto skip;
-
- peerfd = uv__accept4(sockfd,
- NULL,
- NULL,
- UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
- if (peerfd != -1)
- return peerfd;
-
- if (errno == EINTR)
- continue;
-
- if (errno != ENOSYS)
- return UV__ERR(errno);
-
- no_accept4 = 1;
-skip:
-#endif
-
- peerfd = accept(sockfd, NULL, NULL);
- if (peerfd == -1) {
- if (errno == EINTR)
- continue;
- return UV__ERR(errno);
- }
-
- err = uv__cloexec(peerfd, 1);
- if (err == 0)
- err = uv__nonblock(peerfd, 1);
-
- if (err) {
- uv__close(peerfd);
- return err;
- }
-
- return peerfd;
- }
-}
-
-
-#if defined(__APPLE__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
-#if defined(__LP64__)
- extern "C" int close$NOCANCEL(int);
-#else
- extern "C" int close$NOCANCEL$UNIX2003(int);
-#endif
-#pragma GCC diagnostic pop
-#endif
-
-/* close() on macos has the "interesting" quirk that it fails with EINTR
- * without closing the file descriptor when a thread is in the cancel state.
- * That's why libuv calls close$NOCANCEL() instead.
- *
- * glibc on linux has a similar issue: close() is a cancellation point and
- * will unwind the thread when it's in the cancel state. Work around that
- * by making the system call directly. Musl libc is unaffected.
- */
-int uv__close_nocancel(int fd) {
-#if defined(__APPLE__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdollar-in-identifier-extension"
-#if defined(__LP64__)
- return close$NOCANCEL(fd);
-#else
- return close$NOCANCEL$UNIX2003(fd);
-#endif
-#pragma GCC diagnostic pop
-#elif defined(__linux__)
- return syscall(SYS_close, fd);
-#else
- return close(fd);
-#endif
-}
-
-
-int uv__close_nocheckstdio(int fd) {
- int saved_errno;
- int rc;
-
- assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
-
- saved_errno = errno;
- rc = uv__close_nocancel(fd);
- if (rc == -1) {
- rc = UV__ERR(errno);
- if (rc == UV_EINTR || rc == UV__ERR(EINPROGRESS))
- rc = 0; /* The close is in progress, not an error. */
- errno = saved_errno;
- }
-
- return rc;
-}
-
-
-int uv__close(int fd) {
- assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
-#if defined(__MVS__)
- SAVE_ERRNO(epoll_file_close(fd));
-#endif
- return uv__close_nocheckstdio(fd);
-}
-
-
-int uv__nonblock_ioctl(int fd, int set) {
- int r;
-
- do
- r = ioctl(fd, FIONBIO, &set);
- while (r == -1 && errno == EINTR);
-
- if (r)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-#if !defined(__CYGWIN__) && !defined(__MSYS__) && !defined(__HAIKU__)
-int uv__cloexec_ioctl(int fd, int set) {
- int r;
-
- do
- r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
- while (r == -1 && errno == EINTR);
-
- if (r)
- return UV__ERR(errno);
-
- return 0;
-}
-#endif
-
-
-int uv__nonblock_fcntl(int fd, int set) {
- int flags;
- int r;
-
- do
- r = fcntl(fd, F_GETFL);
- while (r == -1 && errno == EINTR);
-
- if (r == -1)
- return UV__ERR(errno);
-
- /* Bail out now if already set/clear. */
- if (!!(r & O_NONBLOCK) == !!set)
- return 0;
-
- if (set)
- flags = r | O_NONBLOCK;
- else
- flags = r & ~O_NONBLOCK;
-
- do
- r = fcntl(fd, F_SETFL, flags);
- while (r == -1 && errno == EINTR);
-
- if (r)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-int uv__cloexec_fcntl(int fd, int set) {
- int flags;
- int r;
-
- do
- r = fcntl(fd, F_GETFD);
- while (r == -1 && errno == EINTR);
-
- if (r == -1)
- return UV__ERR(errno);
-
- /* Bail out now if already set/clear. */
- if (!!(r & FD_CLOEXEC) == !!set)
- return 0;
-
- if (set)
- flags = r | FD_CLOEXEC;
- else
- flags = r & ~FD_CLOEXEC;
-
- do
- r = fcntl(fd, F_SETFD, flags);
- while (r == -1 && errno == EINTR);
-
- if (r)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
- struct cmsghdr* cmsg;
- ssize_t rc;
- int* pfd;
- int* end;
-#if defined(__linux__)
- static int no_msg_cmsg_cloexec;
- if (no_msg_cmsg_cloexec == 0) {
- rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
- if (rc != -1)
- return rc;
- if (errno != EINVAL)
- return UV__ERR(errno);
- rc = recvmsg(fd, msg, flags);
- if (rc == -1)
- return UV__ERR(errno);
- no_msg_cmsg_cloexec = 1;
- } else {
- rc = recvmsg(fd, msg, flags);
- }
-#else
- rc = recvmsg(fd, msg, flags);
-#endif
- if (rc == -1)
- return UV__ERR(errno);
- if (msg->msg_controllen == 0)
- return rc;
- for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
- if (cmsg->cmsg_type == SCM_RIGHTS)
- for (pfd = (int*) CMSG_DATA(cmsg),
- end = (int*) ((char*) cmsg + cmsg->cmsg_len);
- pfd < end;
- pfd += 1)
- uv__cloexec(*pfd, 1);
- return rc;
-}
-
-
-int uv_cwd(char* buffer, size_t* size) {
- char scratch[1 + UV__PATH_MAX];
-
- if (buffer == NULL || size == NULL)
- return UV_EINVAL;
-
- /* Try to read directly into the user's buffer first... */
- if (getcwd(buffer, *size) != NULL)
- goto fixup;
-
- if (errno != ERANGE)
- return UV__ERR(errno);
-
- /* ...or into scratch space if the user's buffer is too small
- * so we can report how much space to provide on the next try.
- */
- if (getcwd(scratch, sizeof(scratch)) == NULL)
- return UV__ERR(errno);
-
- buffer = scratch;
-
-fixup:
-
- *size = strlen(buffer);
-
- if (*size > 1 && buffer[*size - 1] == '/') {
- *size -= 1;
- buffer[*size] = '\0';
- }
-
- if (buffer == scratch) {
- *size += 1;
- return UV_ENOBUFS;
- }
-
- return 0;
-}
-
-
-int uv_chdir(const char* dir) {
- if (chdir(dir))
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-void uv_disable_stdio_inheritance(void) {
- int fd;
-
- /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
- * first 16 file descriptors. After that, bail out after the first error.
- */
- for (fd = 0; ; fd++)
- if (uv__cloexec(fd, 1) && fd > 15)
- break;
-}
-
-
-int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
- int fd_out;
-
- switch (handle->type) {
- case UV_TCP:
- case UV_NAMED_PIPE:
- case UV_TTY:
- fd_out = uv__stream_fd((uv_stream_t*) handle);
- break;
-
- case UV_UDP:
- fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
- break;
-
- case UV_POLL:
- fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
- break;
-
- default:
- return UV_EINVAL;
- }
-
- if (uv__is_closing(handle) || fd_out == -1)
- return UV_EBADF;
-
- *fd = fd_out;
- return 0;
-}
-
-
-static int uv__run_pending(uv_loop_t* loop) {
- QUEUE* q;
- QUEUE pq;
- uv__io_t* w;
-
- if (QUEUE_EMPTY(&loop->pending_queue))
- return 0;
-
- QUEUE_MOVE(&loop->pending_queue, &pq);
-
- while (!QUEUE_EMPTY(&pq)) {
- q = QUEUE_HEAD(&pq);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
- w = QUEUE_DATA(q, uv__io_t, pending_queue);
- w->cb(loop, w, POLLOUT);
- }
-
- return 1;
-}
-
-
-static unsigned int next_power_of_two(unsigned int val) {
- val -= 1;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val += 1;
- return val;
-}
-
-static void maybe_resize(uv_loop_t* loop, unsigned int len) {
- void** watchers;
- void* fake_watcher_list;
- void* fake_watcher_count;
- unsigned int nwatchers;
- unsigned int i;
-
- if (len <= loop->nwatchers)
- return;
-
- /* Preserve fake watcher list and count at the end of the watchers */
- if (loop->watchers != NULL) {
- fake_watcher_list = loop->watchers[loop->nwatchers];
- fake_watcher_count = loop->watchers[loop->nwatchers + 1];
- } else {
- fake_watcher_list = NULL;
- fake_watcher_count = NULL;
- }
-
- nwatchers = next_power_of_two(len + 2) - 2;
- watchers = (void**)
- uv__realloc(loop->watchers, (nwatchers + 2) * sizeof(loop->watchers[0]));
-
- if (watchers == NULL)
- abort();
- for (i = loop->nwatchers; i < nwatchers; i++)
- watchers[i] = NULL;
- watchers[nwatchers] = fake_watcher_list;
- watchers[nwatchers + 1] = fake_watcher_count;
-
- loop->watchers = watchers;
- loop->nwatchers = nwatchers;
-}
-
-
-void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
- assert(cb != NULL);
- assert(fd >= -1);
- QUEUE_INIT(&w->pending_queue);
- QUEUE_INIT(&w->watcher_queue);
- w->cb = cb;
- w->fd = fd;
- w->events = 0;
- w->pevents = 0;
-
-#if defined(UV_HAVE_KQUEUE)
- w->rcount = 0;
- w->wcount = 0;
-#endif /* defined(UV_HAVE_KQUEUE) */
-}
-
-
-void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
- assert(0 != events);
- assert(w->fd >= 0);
- assert(w->fd < INT_MAX);
-
- w->pevents |= events;
- maybe_resize(loop, w->fd + 1);
-
-#if !defined(__sun)
- /* The event ports backend needs to rearm all file descriptors on each and
- * every tick of the event loop but the other backends allow us to
- * short-circuit here if the event mask is unchanged.
- */
- if (w->events == w->pevents)
- return;
-#endif
-
- if (QUEUE_EMPTY(&w->watcher_queue))
- QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
-
- if (loop->watchers[w->fd] == NULL) {
- loop->watchers[w->fd] = w;
- loop->nfds++;
- }
-}
-
-
-void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
- assert(0 != events);
-
- if (w->fd == -1)
- return;
-
- assert(w->fd >= 0);
-
- /* Happens when uv__io_stop() is called on a handle that was never started. */
- if ((unsigned) w->fd >= loop->nwatchers)
- return;
-
- w->pevents &= ~events;
-
- if (w->pevents == 0) {
- QUEUE_REMOVE(&w->watcher_queue);
- QUEUE_INIT(&w->watcher_queue);
-
- if (loop->watchers[w->fd] != NULL) {
- assert(loop->watchers[w->fd] == w);
- assert(loop->nfds > 0);
- loop->watchers[w->fd] = NULL;
- loop->nfds--;
- w->events = 0;
- }
- }
- else if (QUEUE_EMPTY(&w->watcher_queue))
- QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
-}
-
-
-void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
- QUEUE_REMOVE(&w->pending_queue);
-
- /* Remove stale events for this file descriptor */
- if (w->fd != -1)
- uv__platform_invalidate_fd(loop, w->fd);
-}
-
-
-void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
- if (QUEUE_EMPTY(&w->pending_queue))
- QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
-}
-
-
-int uv__io_active(const uv__io_t* w, unsigned int events) {
- assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI)));
- assert(0 != events);
- return 0 != (w->pevents & events);
-}
-
-
-int uv__fd_exists(uv_loop_t* loop, int fd) {
- return (unsigned) fd < loop->nwatchers && loop->watchers[fd] != NULL;
-}
-
-
-int uv_getrusage(uv_rusage_t* rusage) {
- struct rusage usage;
-
- if (getrusage(RUSAGE_SELF, &usage))
- return UV__ERR(errno);
-
- rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
- rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
-
- rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
- rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
-
-#if !defined(__MVS__) && !defined(__HAIKU__)
- rusage->ru_maxrss = usage.ru_maxrss;
- rusage->ru_ixrss = usage.ru_ixrss;
- rusage->ru_idrss = usage.ru_idrss;
- rusage->ru_isrss = usage.ru_isrss;
- rusage->ru_minflt = usage.ru_minflt;
- rusage->ru_majflt = usage.ru_majflt;
- rusage->ru_nswap = usage.ru_nswap;
- rusage->ru_inblock = usage.ru_inblock;
- rusage->ru_oublock = usage.ru_oublock;
- rusage->ru_msgsnd = usage.ru_msgsnd;
- rusage->ru_msgrcv = usage.ru_msgrcv;
- rusage->ru_nsignals = usage.ru_nsignals;
- rusage->ru_nvcsw = usage.ru_nvcsw;
- rusage->ru_nivcsw = usage.ru_nivcsw;
-#endif
-
- return 0;
-}
-
-
-int uv__open_cloexec(const char* path, int flags) {
- int err;
- int fd;
-
-#if defined(UV__O_CLOEXEC)
- static int no_cloexec;
-
- if (!no_cloexec) {
- fd = open(path, flags | UV__O_CLOEXEC);
- if (fd != -1)
- return fd;
-
- if (errno != EINVAL)
- return UV__ERR(errno);
-
- /* O_CLOEXEC not supported. */
- no_cloexec = 1;
- }
-#endif
-
- fd = open(path, flags);
- if (fd == -1)
- return UV__ERR(errno);
-
- err = uv__cloexec(fd, 1);
- if (err) {
- uv__close(fd);
- return err;
- }
-
- return fd;
-}
-
-
-int uv__dup2_cloexec(int oldfd, int newfd) {
- int r;
-#if (defined(__FreeBSD__) && __FreeBSD__ >= 10) || defined(__NetBSD__)
- r = dup3(oldfd, newfd, O_CLOEXEC);
- if (r == -1)
- return UV__ERR(errno);
- return r;
-#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
- r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
- if (r != -1)
- return r;
- if (errno != EINVAL)
- return UV__ERR(errno);
- /* Fall through. */
-#elif defined(__linux__)
- static int no_dup3;
- if (!no_dup3) {
- do
- r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
- while (r == -1 && errno == EBUSY);
- if (r != -1)
- return r;
- if (errno != ENOSYS)
- return UV__ERR(errno);
- /* Fall through. */
- no_dup3 = 1;
- }
-#endif
- {
- int err;
- do
- r = dup2(oldfd, newfd);
-#if defined(__linux__)
- while (r == -1 && errno == EBUSY);
-#else
- while (0); /* Never retry. */
-#endif
-
- if (r == -1)
- return UV__ERR(errno);
-
- err = uv__cloexec(newfd, 1);
- if (err) {
- uv__close(newfd);
- return err;
- }
-
- return r;
- }
-}
-
-
-int uv_os_homedir(char* buffer, size_t* size) {
- uv_passwd_t pwd;
- size_t len;
- int r;
-
- /* Check if the HOME environment variable is set first. The task of
- performing input validation on buffer and size is taken care of by
- uv_os_getenv(). */
- r = uv_os_getenv("HOME", buffer, size);
-
- if (r != UV_ENOENT)
- return r;
-
- /* HOME is not set, so call uv__getpwuid_r() */
- r = uv__getpwuid_r(&pwd);
-
- if (r != 0) {
- return r;
- }
-
- len = strlen(pwd.homedir);
-
- if (len >= *size) {
- *size = len + 1;
- uv_os_free_passwd(&pwd);
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, pwd.homedir, len + 1);
- *size = len;
- uv_os_free_passwd(&pwd);
-
- return 0;
-}
-
-
-int uv_os_tmpdir(char* buffer, size_t* size) {
- const char* buf;
- size_t len;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
-#define CHECK_ENV_VAR(name) \
- do { \
- buf = getenv(name); \
- if (buf != NULL) \
- goto return_buffer; \
- } \
- while (0)
-
- /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
- CHECK_ENV_VAR("TMPDIR");
- CHECK_ENV_VAR("TMP");
- CHECK_ENV_VAR("TEMP");
- CHECK_ENV_VAR("TEMPDIR");
-
-#undef CHECK_ENV_VAR
-
- /* No temp environment variables defined */
- #if defined(__ANDROID__)
- buf = "/data/local/tmp";
- #else
- buf = "/tmp";
- #endif
-
-return_buffer:
- len = strlen(buf);
-
- if (len >= *size) {
- *size = len + 1;
- return UV_ENOBUFS;
- }
-
- /* The returned directory should not have a trailing slash. */
- if (len > 1 && buf[len - 1] == '/') {
- len--;
- }
-
- memcpy(buffer, buf, len + 1);
- buffer[len] = '\0';
- *size = len;
-
- return 0;
-}
-
-
-int uv__getpwuid_r(uv_passwd_t* pwd) {
- struct passwd pw;
- struct passwd* result;
- char* buf;
- uid_t uid;
- size_t bufsize;
- size_t name_size;
- size_t homedir_size;
- size_t shell_size;
- long initsize;
- int r;
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
- int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
-
- getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
- if (getpwuid_r == NULL)
- return UV_ENOSYS;
-#endif
-
- if (pwd == NULL)
- return UV_EINVAL;
-
- initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
-
- if (initsize <= 0)
- bufsize = 4096;
- else
- bufsize = (size_t) initsize;
-
- uid = geteuid();
- buf = NULL;
-
- for (;;) {
- uv__free(buf);
- buf = (char*)uv__malloc(bufsize);
-
- if (buf == NULL)
- return UV_ENOMEM;
-
- r = getpwuid_r(uid, &pw, buf, bufsize, &result);
-
- if (r != ERANGE)
- break;
-
- bufsize *= 2;
- }
-
- if (r != 0) {
- uv__free(buf);
- return -r;
- }
-
- if (result == NULL) {
- uv__free(buf);
- return UV_ENOENT;
- }
-
- /* Allocate memory for the username, shell, and home directory */
- name_size = strlen(pw.pw_name) + 1;
- homedir_size = strlen(pw.pw_dir) + 1;
- shell_size = strlen(pw.pw_shell) + 1;
- pwd->username = (char*)uv__malloc(name_size + homedir_size + shell_size);
-
- if (pwd->username == NULL) {
- uv__free(buf);
- return UV_ENOMEM;
- }
-
- /* Copy the username */
- memcpy(pwd->username, pw.pw_name, name_size);
-
- /* Copy the home directory */
- pwd->homedir = pwd->username + name_size;
- memcpy(pwd->homedir, pw.pw_dir, homedir_size);
-
- /* Copy the shell */
- pwd->shell = pwd->homedir + homedir_size;
- memcpy(pwd->shell, pw.pw_shell, shell_size);
-
- /* Copy the uid and gid */
- pwd->uid = pw.pw_uid;
- pwd->gid = pw.pw_gid;
-
- uv__free(buf);
-
- return 0;
-}
-
-
-void uv_os_free_passwd(uv_passwd_t* pwd) {
- if (pwd == NULL)
- return;
-
- /*
- The memory for name, shell, and homedir are allocated in a single
- uv__malloc() call. The base of the pointer is stored in pwd->username, so
- that is the field that needs to be freed.
- */
- uv__free(pwd->username);
- pwd->username = NULL;
- pwd->shell = NULL;
- pwd->homedir = NULL;
-}
-
-
-int uv_os_get_passwd(uv_passwd_t* pwd) {
- return uv__getpwuid_r(pwd);
-}
-
-
-int uv_translate_sys_error(int sys_errno) {
- /* If < 0 then it's already a libuv error. */
- return sys_errno <= 0 ? sys_errno : -sys_errno;
-}
-
-
-int uv_os_getenv(const char* name, char* buffer, size_t* size) {
- char* var;
- size_t len;
-
- if (name == NULL || buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- var = getenv(name);
-
- if (var == NULL)
- return UV_ENOENT;
-
- len = strlen(var);
-
- if (len >= *size) {
- *size = len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, var, len + 1);
- *size = len;
-
- return 0;
-}
-
-
-int uv_os_setenv(const char* name, const char* value) {
- if (name == NULL || value == NULL)
- return UV_EINVAL;
-
- if (setenv(name, value, 1) != 0)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-int uv_os_unsetenv(const char* name) {
- if (name == NULL)
- return UV_EINVAL;
-
- if (unsetenv(name) != 0)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-int uv_os_gethostname(char* buffer, size_t* size) {
- /*
- On some platforms, if the input buffer is not large enough, gethostname()
- succeeds, but truncates the result. libuv can detect this and return ENOBUFS
- instead by creating a large enough buffer and comparing the hostname length
- to the size input.
- */
- char buf[UV_MAXHOSTNAMESIZE];
- size_t len;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- if (gethostname(buf, sizeof(buf)) != 0)
- return UV__ERR(errno);
-
- buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
- len = strlen(buf);
-
- if (len >= *size) {
- *size = len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, buf, len + 1);
- *size = len;
- return 0;
-}
-
-
-uv_os_fd_t uv_get_osfhandle(int fd) {
- return fd;
-}
-
-int uv_open_osfhandle(uv_os_fd_t os_fd) {
- return os_fd;
-}
-
-uv_pid_t uv_os_getpid(void) {
- return getpid();
-}
-
-
-uv_pid_t uv_os_getppid(void) {
- return getppid();
-}
-
-
-int uv_os_getpriority(uv_pid_t pid, int* priority) {
- int r;
-
- if (priority == NULL)
- return UV_EINVAL;
-
- errno = 0;
- r = getpriority(PRIO_PROCESS, (int) pid);
-
- if (r == -1 && errno != 0)
- return UV__ERR(errno);
-
- *priority = r;
- return 0;
-}
-
-
-int uv_os_setpriority(uv_pid_t pid, int priority) {
- if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
- return UV_EINVAL;
-
- if (setpriority(PRIO_PROCESS, (int) pid, priority) != 0)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-int uv_os_uname(uv_utsname_t* buffer) {
- struct utsname buf;
- int r;
-
- if (buffer == NULL)
- return UV_EINVAL;
-
- if (uname(&buf) == -1) {
- r = UV__ERR(errno);
- goto error;
- }
-
- r = uv__strscpy(buffer->sysname, buf.sysname, sizeof(buffer->sysname));
- if (r == UV_E2BIG)
- goto error;
-
-#ifdef _AIX
- r = snprintf(buffer->release,
- sizeof(buffer->release),
- "%s.%s",
- buf.version,
- buf.release);
- if (r >= sizeof(buffer->release)) {
- r = UV_E2BIG;
- goto error;
- }
-#else
- r = uv__strscpy(buffer->release, buf.release, sizeof(buffer->release));
- if (r == UV_E2BIG)
- goto error;
-#endif
-
- r = uv__strscpy(buffer->version, buf.version, sizeof(buffer->version));
- if (r == UV_E2BIG)
- goto error;
-
-#if defined(_AIX) || defined(__PASE__)
- r = uv__strscpy(buffer->machine, "ppc64", sizeof(buffer->machine));
-#else
- r = uv__strscpy(buffer->machine, buf.machine, sizeof(buffer->machine));
-#endif
-
- if (r == UV_E2BIG)
- goto error;
-
- return 0;
-
-error:
- buffer->sysname[0] = '\0';
- buffer->release[0] = '\0';
- buffer->version[0] = '\0';
- buffer->machine[0] = '\0';
- return r;
-}
-
-int uv__getsockpeername(const uv_handle_t* handle,
- uv__peersockfunc func,
- struct sockaddr* name,
- int* namelen) {
- socklen_t socklen;
- uv_os_fd_t fd;
- int r;
-
- r = uv_fileno(handle, &fd);
- if (r < 0)
- return r;
-
- /* sizeof(socklen_t) != sizeof(int) on some systems. */
- socklen = (socklen_t) *namelen;
-
- if (func(fd, name, &socklen))
- return UV__ERR(errno);
-
- *namelen = (int) socklen;
- return 0;
-}
-
-int uv_gettimeofday(uv_timeval64_t* tv) {
- struct timeval time;
-
- if (tv == NULL)
- return UV_EINVAL;
-
- if (gettimeofday(&time, NULL) != 0)
- return UV__ERR(errno);
-
- tv->tv_sec = (int64_t) time.tv_sec;
- tv->tv_usec = (int32_t) time.tv_usec;
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/cygwin.cpp b/wpiutil/src/main/native/libuv/src/unix/cygwin.cpp
deleted file mode 100644
index 6b5cfb7..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/cygwin.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <sys/sysinfo.h>
-#include <unistd.h>
-
-int uv_uptime(double* uptime) {
- struct sysinfo info;
-
- if (sysinfo(&info) < 0)
- return UV__ERR(errno);
-
- *uptime = info.uptime;
- return 0;
-}
-
-int uv_resident_set_memory(size_t* rss) {
- /* FIXME: read /proc/meminfo? */
- *rss = 0;
- return 0;
-}
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- /* FIXME: read /proc/stat? */
- *cpu_infos = NULL;
- *count = 0;
- return UV_ENOSYS;
-}
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- (void)cpu_infos;
- (void)count;
-}
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/darwin-proctitle.cpp b/wpiutil/src/main/native/libuv/src/unix/darwin-proctitle.cpp
deleted file mode 100644
index f05d9f9..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/darwin-proctitle.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <TargetConditionals.h>
-
-#if !TARGET_OS_IPHONE
-# include <CoreFoundation/CoreFoundation.h>
-# include <ApplicationServices/ApplicationServices.h>
-#endif
-
-#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
-
-
-static int (*dynamic_pthread_setname_np)(const char* name);
-#if !TARGET_OS_IPHONE
-static CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
- const char*,
- CFStringEncoding);
-static CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
-static void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
-static void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
-static CFTypeRef (*pLSGetCurrentApplicationASN)(void);
-static OSStatus (*pLSSetApplicationInformationItem)(int,
- CFTypeRef,
- CFStringRef,
- CFStringRef,
- CFDictionaryRef*);
-static void* application_services_handle;
-static void* core_foundation_handle;
-static CFBundleRef launch_services_bundle;
-static CFStringRef* display_name_key;
-static CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
-static CFBundleRef (*pCFBundleGetMainBundle)(void);
-static CFBundleRef hi_services_bundle;
-static OSStatus (*pSetApplicationIsDaemon)(int);
-static CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
-static void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
- void*);
-
-
-UV_DESTRUCTOR(static void uv__set_process_title_platform_fini(void)) {
- if (core_foundation_handle != NULL) {
- dlclose(core_foundation_handle);
- core_foundation_handle = NULL;
- }
-
- if (application_services_handle != NULL) {
- dlclose(application_services_handle);
- application_services_handle = NULL;
- }
-}
-#endif /* !TARGET_OS_IPHONE */
-
-
-void uv__set_process_title_platform_init(void) {
- /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
- *(void **)(&dynamic_pthread_setname_np) =
- dlsym(RTLD_DEFAULT, "pthread_setname_np");
-
-#if !TARGET_OS_IPHONE
- application_services_handle = dlopen("/System/Library/Frameworks/"
- "ApplicationServices.framework/"
- "Versions/A/ApplicationServices",
- RTLD_LAZY | RTLD_LOCAL);
- core_foundation_handle = dlopen("/System/Library/Frameworks/"
- "CoreFoundation.framework/"
- "Versions/A/CoreFoundation",
- RTLD_LAZY | RTLD_LOCAL);
-
- if (application_services_handle == NULL || core_foundation_handle == NULL)
- goto out;
-
- *(void **)(&pCFStringCreateWithCString) =
- dlsym(core_foundation_handle, "CFStringCreateWithCString");
- *(void **)(&pCFBundleGetBundleWithIdentifier) =
- dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
- *(void **)(&pCFBundleGetDataPointerForName) =
- dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
- *(void **)(&pCFBundleGetFunctionPointerForName) =
- dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
-
- if (pCFStringCreateWithCString == NULL ||
- pCFBundleGetBundleWithIdentifier == NULL ||
- pCFBundleGetDataPointerForName == NULL ||
- pCFBundleGetFunctionPointerForName == NULL) {
- goto out;
- }
-
- launch_services_bundle =
- pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
-
- if (launch_services_bundle == NULL)
- goto out;
-
- *(void **)(&pLSGetCurrentApplicationASN) =
- pCFBundleGetFunctionPointerForName(launch_services_bundle,
- S("_LSGetCurrentApplicationASN"));
-
- if (pLSGetCurrentApplicationASN == NULL)
- goto out;
-
- *(void **)(&pLSSetApplicationInformationItem) =
- pCFBundleGetFunctionPointerForName(launch_services_bundle,
- S("_LSSetApplicationInformationItem"));
-
- if (pLSSetApplicationInformationItem == NULL)
- goto out;
-
- display_name_key = (CFStringRef*)
- pCFBundleGetDataPointerForName(launch_services_bundle,
- S("_kLSDisplayNameKey"));
-
- if (display_name_key == NULL || *display_name_key == NULL)
- goto out;
-
- *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
- "CFBundleGetInfoDictionary");
- *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
- "CFBundleGetMainBundle");
-
- if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
- goto out;
-
- /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
- hi_services_bundle =
- pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
-
- if (hi_services_bundle == NULL)
- goto out;
-
- *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
- hi_services_bundle,
- S("SetApplicationIsDaemon"));
- *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
- launch_services_bundle,
- S("_LSApplicationCheckIn"));
- *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
- pCFBundleGetFunctionPointerForName(
- launch_services_bundle,
- S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
-
- if (pSetApplicationIsDaemon == NULL ||
- pLSApplicationCheckIn == NULL ||
- pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
- goto out;
- }
-
- return;
-
-out:
- uv__set_process_title_platform_fini();
-#endif /* !TARGET_OS_IPHONE */
-}
-
-
-void uv__set_process_title(const char* title) {
-#if !TARGET_OS_IPHONE
- if (core_foundation_handle != NULL && pSetApplicationIsDaemon(1) != noErr) {
- CFTypeRef asn;
- pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
- pLSApplicationCheckIn(/* Magic value */ -2,
- pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
- asn = pLSGetCurrentApplicationASN();
- pLSSetApplicationInformationItem(/* Magic value */ -2, asn,
- *display_name_key, S(title), NULL);
- }
-#endif /* !TARGET_OS_IPHONE */
-
- if (dynamic_pthread_setname_np != NULL) {
- char namebuf[64]; /* MAXTHREADNAMESIZE */
- uv__strscpy(namebuf, title, sizeof(namebuf));
- dynamic_pthread_setname_np(namebuf);
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/darwin.cpp b/wpiutil/src/main/native/libuv/src/unix/darwin.cpp
deleted file mode 100644
index 2282d91..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/darwin.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <stdint.h>
-#include <errno.h>
-
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-#include <mach-o/dyld.h> /* _NSGetExecutablePath */
-#include <sys/resource.h>
-#include <sys/sysctl.h>
-#include <unistd.h> /* sysconf */
-
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- loop->cf_state = NULL;
-
- if (uv__kqueue_init(loop))
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
- uv__fsevents_loop_delete(loop);
-}
-
-
-uint64_t uv__hrtime(uv_clocktype_t type) {
- static mach_timebase_info_data_t info;
-
- if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
- ACCESS_ONCE(uint32_t, info.denom) == 0) &&
- mach_timebase_info(&info) != KERN_SUCCESS)
- abort();
-
- return mach_absolute_time() * info.numer / info.denom;
-}
-
-
-int uv_exepath(char* buffer, size_t* size) {
- /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
- char abspath[PATH_MAX * 2 + 1];
- char exepath[PATH_MAX + 1];
- uint32_t exepath_size;
- size_t abspath_size;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- exepath_size = sizeof(exepath);
- if (_NSGetExecutablePath(exepath, &exepath_size))
- return UV_EIO;
-
- if (realpath(exepath, abspath) != abspath)
- return UV__ERR(errno);
-
- abspath_size = strlen(abspath);
- if (abspath_size == 0)
- return UV_EIO;
-
- *size -= 1;
- if (*size > abspath_size)
- *size = abspath_size;
-
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
-
- return 0;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- vm_statistics_data_t info;
- mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
-
- if (host_statistics(mach_host_self(), HOST_VM_INFO,
- (host_info_t)&info, &count) != KERN_SUCCESS) {
- return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
- }
-
- return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
-}
-
-
-uint64_t uv_get_total_memory(void) {
- uint64_t info;
- int which[] = {CTL_HW, HW_MEMSIZE};
- size_t size = sizeof(info);
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-void uv_loadavg(double avg[3]) {
- struct loadavg info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_LOADAVG};
-
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
-
- avg[0] = (double) info.ldavg[0] / info.fscale;
- avg[1] = (double) info.ldavg[1] / info.fscale;
- avg[2] = (double) info.ldavg[2] / info.fscale;
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- mach_msg_type_number_t count;
- task_basic_info_data_t info;
- kern_return_t err;
-
- count = TASK_BASIC_INFO_COUNT;
- err = task_info(mach_task_self(),
- TASK_BASIC_INFO,
- (task_info_t) &info,
- &count);
- (void) &err;
- /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
- * KERN_SUCCESS implies a libuv bug.
- */
- assert(err == KERN_SUCCESS);
- *rss = info.resident_size;
-
- return 0;
-}
-
-
-int uv_uptime(double* uptime) {
- time_t now;
- struct timeval info;
- size_t size = sizeof(info);
- static int which[] = {CTL_KERN, KERN_BOOTTIME};
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- now = time(NULL);
- *uptime = now - info.tv_sec;
-
- return 0;
-}
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
- multiplier = ((uint64_t)1000L / ticks);
- char model[512];
- uint64_t cpuspeed;
- size_t size;
- unsigned int i;
- natural_t numcpus;
- mach_msg_type_number_t msg_type;
- processor_cpu_load_info_data_t *info;
- uv_cpu_info_t* cpu_info;
-
- size = sizeof(model);
- if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
- sysctlbyname("hw.model", &model, &size, NULL, 0)) {
- return UV__ERR(errno);
- }
-
- size = sizeof(cpuspeed);
- if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
- return UV__ERR(errno);
-
- if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
- (processor_info_array_t*)&info,
- &msg_type) != KERN_SUCCESS) {
- return UV_EINVAL; /* FIXME(bnoordhuis) Translate error. */
- }
-
- *cpu_infos = (uv_cpu_info_t*)uv__malloc(numcpus * sizeof(**cpu_infos));
- if (!(*cpu_infos)) {
- vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
- return UV_ENOMEM;
- }
-
- *count = numcpus;
-
- for (i = 0; i < numcpus; i++) {
- cpu_info = &(*cpu_infos)[i];
-
- cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
- cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
- cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
- cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
- cpu_info->cpu_times.irq = 0;
-
- cpu_info->model = uv__strdup(model);
- cpu_info->speed = cpuspeed/1000000;
- }
- vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
-
- return 0;
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/dl.cpp b/wpiutil/src/main/native/libuv/src/unix/dl.cpp
deleted file mode 100644
index fc1c052..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/dl.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <dlfcn.h>
-#include <errno.h>
-#include <string.h>
-#include <locale.h>
-
-static int uv__dlerror(uv_lib_t* lib);
-
-
-int uv_dlopen(const char* filename, uv_lib_t* lib) {
- dlerror(); /* Reset error status. */
- lib->errmsg = NULL;
- lib->handle = dlopen(filename, RTLD_LAZY);
- return lib->handle ? 0 : uv__dlerror(lib);
-}
-
-
-void uv_dlclose(uv_lib_t* lib) {
- uv__free(lib->errmsg);
- lib->errmsg = NULL;
-
- if (lib->handle) {
- /* Ignore errors. No good way to signal them without leaking memory. */
- dlclose(lib->handle);
- lib->handle = NULL;
- }
-}
-
-
-int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
- dlerror(); /* Reset error status. */
- *ptr = dlsym(lib->handle, name);
- return uv__dlerror(lib);
-}
-
-
-const char* uv_dlerror(const uv_lib_t* lib) {
- return lib->errmsg ? lib->errmsg : "no error";
-}
-
-
-static int uv__dlerror(uv_lib_t* lib) {
- const char* errmsg;
-
- uv__free(lib->errmsg);
-
- errmsg = dlerror();
-
- if (errmsg) {
- lib->errmsg = uv__strdup(errmsg);
- return -1;
- }
- else {
- lib->errmsg = NULL;
- return 0;
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/freebsd.cpp b/wpiutil/src/main/native/libuv/src/unix/freebsd.cpp
deleted file mode 100644
index c401145..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/freebsd.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-
-#include <paths.h>
-#include <sys/user.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-#include <sys/sysctl.h>
-#include <vm/vm_param.h> /* VM_LOADAVG */
-#include <time.h>
-#include <stdlib.h>
-#include <unistd.h> /* sysconf */
-#include <fcntl.h>
-
-#ifndef CPUSTATES
-# define CPUSTATES 5U
-#endif
-#ifndef CP_USER
-# define CP_USER 0
-# define CP_NICE 1
-# define CP_SYS 2
-# define CP_IDLE 3
-# define CP_INTR 4
-#endif
-
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- return uv__kqueue_init(loop);
-}
-
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
-}
-
-
-#ifdef __DragonFly__
-int uv_exepath(char* buffer, size_t* size) {
- char abspath[PATH_MAX * 2 + 1];
- ssize_t abspath_size;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
- if (abspath_size < 0)
- return UV__ERR(errno);
-
- assert(abspath_size > 0);
- *size -= 1;
-
- if (*size > abspath_size)
- *size = abspath_size;
-
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
-
- return 0;
-}
-#else
-int uv_exepath(char* buffer, size_t* size) {
- char abspath[PATH_MAX * 2 + 1];
- int mib[4];
- size_t abspath_size;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PATHNAME;
- mib[3] = -1;
-
- abspath_size = sizeof abspath;
- if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
- return UV__ERR(errno);
-
- assert(abspath_size > 0);
- abspath_size -= 1;
- *size -= 1;
-
- if (*size > abspath_size)
- *size = abspath_size;
-
- memcpy(buffer, abspath, *size);
- buffer[*size] = '\0';
-
- return 0;
-}
-#endif
-
-uint64_t uv_get_free_memory(void) {
- int freecount;
- size_t size = sizeof(freecount);
-
- if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
-
-}
-
-
-uint64_t uv_get_total_memory(void) {
- unsigned long info;
- int which[] = {CTL_HW, HW_PHYSMEM};
-
- size_t size = sizeof(info);
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-void uv_loadavg(double avg[3]) {
- struct loadavg info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_LOADAVG};
-
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
-
- avg[0] = (double) info.ldavg[0] / info.fscale;
- avg[1] = (double) info.ldavg[1] / info.fscale;
- avg[2] = (double) info.ldavg[2] / info.fscale;
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- struct kinfo_proc kinfo;
- size_t page_size;
- size_t kinfo_size;
- int mib[4];
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
-
- kinfo_size = sizeof(kinfo);
-
- if (sysctl(mib, 4, &kinfo, &kinfo_size, NULL, 0))
- return UV__ERR(errno);
-
- page_size = getpagesize();
-
-#ifdef __DragonFly__
- *rss = kinfo.kp_vm_rssize * page_size;
-#else
- *rss = kinfo.ki_rssize * page_size;
-#endif
-
- return 0;
-}
-
-
-int uv_uptime(double* uptime) {
- int r;
- struct timespec sp;
- r = clock_gettime(CLOCK_MONOTONIC, &sp);
- if (r)
- return UV__ERR(errno);
-
- *uptime = sp.tv_sec;
- return 0;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
- multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
- cur = 0;
- uv_cpu_info_t* cpu_info;
- const char* maxcpus_key;
- const char* cptimes_key;
- const char* model_key;
- char model[512];
- long* cp_times;
- int numcpus;
- size_t size;
- int i;
-
-#if defined(__DragonFly__)
- /* This is not quite correct but DragonFlyBSD doesn't seem to have anything
- * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
- * not per CPU). At least this stops uv_cpu_info() from failing completely.
- */
- maxcpus_key = "hw.ncpu";
- cptimes_key = "kern.cp_time";
-#else
- maxcpus_key = "kern.smp.maxcpus";
- cptimes_key = "kern.cp_times";
-#endif
-
-#if defined(__arm__) || defined(__aarch64__)
- /* The key hw.model and hw.clockrate are not available on FreeBSD ARM. */
- model_key = "hw.machine";
- cpuspeed = 0;
-#else
- model_key = "hw.model";
-
- size = sizeof(cpuspeed);
- if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0))
- return -errno;
-#endif
-
- size = sizeof(model);
- if (sysctlbyname(model_key, &model, &size, NULL, 0))
- return UV__ERR(errno);
-
- size = sizeof(numcpus);
- if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
- return UV__ERR(errno);
-
- *cpu_infos = (uv_cpu_info_t*)uv__malloc(numcpus * sizeof(**cpu_infos));
- if (!(*cpu_infos))
- return UV_ENOMEM;
-
- *count = numcpus;
-
- /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
- * ncpu.
- */
- size = sizeof(maxcpus);
- if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
- uv__free(*cpu_infos);
- return UV__ERR(errno);
- }
-
- size = maxcpus * CPUSTATES * sizeof(long);
-
- cp_times = (long*)uv__malloc(size);
- if (cp_times == NULL) {
- uv__free(*cpu_infos);
- return UV_ENOMEM;
- }
-
- if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
- uv__free(cp_times);
- uv__free(*cpu_infos);
- return UV__ERR(errno);
- }
-
- for (i = 0; i < numcpus; i++) {
- cpu_info = &(*cpu_infos)[i];
-
- cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
- cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
- cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
- cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
- cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
-
- cpu_info->model = uv__strdup(model);
- cpu_info->speed = cpuspeed;
-
- cur+=CPUSTATES;
- }
-
- uv__free(cp_times);
- return 0;
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/fs.cpp b/wpiutil/src/main/native/libuv/src/unix/fs.cpp
deleted file mode 100644
index 36871ee..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/fs.cpp
+++ /dev/null
@@ -1,1860 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-/* Caveat emptor: this file deviates from the libuv convention of returning
- * negated errno codes. Most uv_fs_*() functions map directly to the system
- * call of the same name. For more complex wrappers, it's easier to just
- * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
- * getting the errno to the right place (req->result or as the return value.)
- */
-
-#include "uv.h"
-#include "internal.h"
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h> /* PATH_MAX */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <pthread.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <poll.h>
-
-#if defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || \
- defined(__OpenBSD__) || \
- defined(__NetBSD__)
-# define HAVE_PREADV 1
-#else
-# define HAVE_PREADV 0
-#endif
-
-#if defined(__linux__) || defined(__sun)
-# include <sys/sendfile.h>
-#endif
-
-#if defined(__APPLE__)
-# include <sys/sysctl.h>
-#elif defined(__linux__) && !defined(FICLONE)
-# include <sys/ioctl.h>
-# define FICLONE _IOW(0x94, 9, int)
-#endif
-
-#if defined(_AIX) && !defined(_AIX71)
-# include <utime.h>
-#endif
-
-#if defined(_AIX) && _XOPEN_SOURCE <= 600
-extern char *mkdtemp(char *template); /* See issue #740 on AIX < 7 */
-#endif
-
-#define INIT(subtype) \
- do { \
- if (req == NULL) \
- return UV_EINVAL; \
- UV_REQ_INIT(req, UV_FS); \
- req->fs_type = UV_FS_ ## subtype; \
- req->result = 0; \
- req->ptr = NULL; \
- req->loop = loop; \
- req->path = NULL; \
- req->new_path = NULL; \
- req->bufs = NULL; \
- req->cb = cb; \
- } \
- while (0)
-
-#define PATH \
- do { \
- assert(path != NULL); \
- if (cb == NULL) { \
- req->path = path; \
- } else { \
- req->path = uv__strdup(path); \
- if (req->path == NULL) \
- return UV_ENOMEM; \
- } \
- } \
- while (0)
-
-#define PATH2 \
- do { \
- if (cb == NULL) { \
- req->path = path; \
- req->new_path = new_path; \
- } else { \
- size_t path_len; \
- size_t new_path_len; \
- path_len = strlen(path) + 1; \
- new_path_len = strlen(new_path) + 1; \
- req->path = (char*)uv__malloc(path_len + new_path_len); \
- if (req->path == NULL) \
- return UV_ENOMEM; \
- req->new_path = req->path + path_len; \
- memcpy((void*) req->path, path, path_len); \
- memcpy((void*) req->new_path, new_path, new_path_len); \
- } \
- } \
- while (0)
-
-#define POST \
- do { \
- if (cb != NULL) { \
- uv__req_register(loop, req); \
- uv__work_submit(loop, \
- &req->work_req, \
- UV__WORK_FAST_IO, \
- uv__fs_work, \
- uv__fs_done); \
- return 0; \
- } \
- else { \
- uv__fs_work(&req->work_req); \
- return req->result; \
- } \
- } \
- while (0)
-
-
-static int uv__fs_close(int fd) {
- int rc;
-
- rc = uv__close_nocancel(fd);
- if (rc == -1)
- if (errno == EINTR || errno == EINPROGRESS)
- rc = 0; /* The close is in progress, not an error. */
-
- return rc;
-}
-
-
-static ssize_t uv__fs_fsync(uv_fs_t* req) {
-#if defined(__APPLE__)
- /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
- * to the drive platters. This is in contrast to Linux's fdatasync and fsync
- * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
- * for flushing buffered data to permanent storage. If F_FULLFSYNC is not
- * supported by the file system we fall back to F_BARRIERFSYNC or fsync().
- * This is the same approach taken by sqlite, except sqlite does not issue
- * an F_BARRIERFSYNC call.
- */
- int r;
-
- r = fcntl(req->file, F_FULLFSYNC);
- if (r != 0)
- r = fcntl(req->file, 85 /* F_BARRIERFSYNC */); /* fsync + barrier */
- if (r != 0)
- r = fsync(req->file);
- return r;
-#else
- return fsync(req->file);
-#endif
-}
-
-
-static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
-#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
- return fdatasync(req->file);
-#elif defined(__APPLE__)
- /* See the comment in uv__fs_fsync. */
- return uv__fs_fsync(req);
-#else
- return fsync(req->file);
-#endif
-}
-
-
-static ssize_t uv__fs_futime(uv_fs_t* req) {
-#if defined(__linux__) \
- || defined(_AIX71) \
- || defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
- struct timespec ts[2];
- ts[0].tv_sec = req->atime;
- ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
- ts[1].tv_sec = req->mtime;
- ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
- return futimens(req->file, ts);
-#elif defined(__APPLE__) \
- || defined(__DragonFly__) \
- || defined(__FreeBSD__) \
- || defined(__FreeBSD_kernel__) \
- || defined(__NetBSD__) \
- || defined(__OpenBSD__) \
- || defined(__sun)
- struct timeval tv[2];
- tv[0].tv_sec = req->atime;
- tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
- tv[1].tv_sec = req->mtime;
- tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
-# if defined(__sun)
- return futimesat(req->file, NULL, tv);
-# else
- return futimes(req->file, tv);
-# endif
-#elif defined(__MVS__)
- attrib_t atr;
- memset(&atr, 0, sizeof(atr));
- atr.att_mtimechg = 1;
- atr.att_atimechg = 1;
- atr.att_mtime = req->mtime;
- atr.att_atime = req->atime;
- return __fchattr(req->file, &atr, sizeof(atr));
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-
-static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
- return mkdtemp((char*) req->path) ? 0 : -1;
-}
-
-
-static ssize_t uv__fs_open(uv_fs_t* req) {
- static int no_cloexec_support;
- int r;
-
- /* Try O_CLOEXEC before entering locks */
- if (no_cloexec_support == 0) {
-#ifdef O_CLOEXEC
- r = open(req->path, req->flags | O_CLOEXEC, req->mode);
- if (r >= 0)
- return r;
- if (errno != EINVAL)
- return r;
- no_cloexec_support = 1;
-#endif /* O_CLOEXEC */
- }
-
- if (req->cb != NULL)
- uv_rwlock_rdlock(&req->loop->cloexec_lock);
-
- r = open(req->path, req->flags, req->mode);
-
- /* In case of failure `uv__cloexec` will leave error in `errno`,
- * so it is enough to just set `r` to `-1`.
- */
- if (r >= 0 && uv__cloexec(r, 1) != 0) {
- r = uv__close(r);
- if (r != 0)
- abort();
- r = -1;
- }
-
- if (req->cb != NULL)
- uv_rwlock_rdunlock(&req->loop->cloexec_lock);
-
- return r;
-}
-
-
-static ssize_t uv__fs_preadv(uv_file fd,
- uv_buf_t* bufs,
- unsigned int nbufs,
- off_t off) {
- uv_buf_t* buf;
- uv_buf_t* end;
- ssize_t result;
- ssize_t rc;
- size_t pos;
-
- assert(nbufs > 0);
-
- result = 0;
- pos = 0;
- buf = bufs + 0;
- end = bufs + nbufs;
-
- for (;;) {
- do
- rc = pread(fd, buf->base + pos, buf->len - pos, off + result);
- while (rc == -1 && errno == EINTR);
-
- if (rc == 0)
- break;
-
- if (rc == -1 && result == 0)
- return UV__ERR(errno);
-
- if (rc == -1)
- break; /* We read some data so return that, ignore the error. */
-
- pos += rc;
- result += rc;
-
- if (pos < buf->len)
- continue;
-
- pos = 0;
- buf += 1;
-
- if (buf == end)
- break;
- }
-
- return result;
-}
-
-
-static ssize_t uv__fs_read(uv_fs_t* req) {
-#if defined(__linux__)
- static int no_preadv;
-#endif
- unsigned int iovmax;
- ssize_t result;
-
- iovmax = uv__getiovmax();
- if (req->nbufs > iovmax)
- req->nbufs = iovmax;
-
- if (req->off < 0) {
- if (req->nbufs == 1)
- result = read(req->file, req->bufs[0].base, req->bufs[0].len);
- else
- result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
- } else {
- if (req->nbufs == 1) {
- result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
- goto done;
- }
-
-#if HAVE_PREADV
- result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
-#else
-# if defined(__linux__)
- if (no_preadv) retry:
-# endif
- {
- result = uv__fs_preadv(req->file, req->bufs, req->nbufs, req->off);
- }
-# if defined(__linux__)
- else {
- result = uv__preadv(req->file,
- (struct iovec*)req->bufs,
- req->nbufs,
- req->off);
- if (result == -1 && errno == ENOSYS) {
- no_preadv = 1;
- goto retry;
- }
- }
-# endif
-#endif
- }
-
-done:
- /* Early cleanup of bufs allocation, since we're done with it. */
- if (req->bufs != req->bufsml)
- uv__free(req->bufs);
-
- req->bufs = NULL;
- req->nbufs = 0;
-
-#ifdef __PASE__
- /* PASE returns EOPNOTSUPP when reading a directory, convert to EISDIR */
- if (result == -1 && errno == EOPNOTSUPP) {
- struct stat buf;
- ssize_t rc;
- rc = fstat(req->file, &buf);
- if (rc == 0 && S_ISDIR(buf.st_mode)) {
- errno = EISDIR;
- }
- }
-#endif
-
- return result;
-}
-
-
-#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)
-#define UV_CONST_DIRENT uv__dirent_t
-#else
-#define UV_CONST_DIRENT const uv__dirent_t
-#endif
-
-
-static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) {
- return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
-}
-
-
-static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
- return strcmp((*a)->d_name, (*b)->d_name);
-}
-
-
-static ssize_t uv__fs_scandir(uv_fs_t* req) {
- uv__dirent_t** dents;
- int n;
-
- dents = NULL;
- n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort);
-
- /* NOTE: We will use nbufs as an index field */
- req->nbufs = 0;
-
- if (n == 0) {
- /* OS X still needs to deallocate some memory.
- * Memory was allocated using the system allocator, so use free() here.
- */
- free(dents);
- dents = NULL;
- } else if (n == -1) {
- return n;
- }
-
- req->ptr = dents;
-
- return n;
-}
-
-static int uv__fs_opendir(uv_fs_t* req) {
- uv_dir_t* dir;
-
- dir = (uv_dir_t*)uv__malloc(sizeof(*dir));
- if (dir == NULL)
- goto error;
-
- dir->dir = opendir(req->path);
- if (dir->dir == NULL)
- goto error;
-
- req->ptr = dir;
- return 0;
-
-error:
- uv__free(dir);
- req->ptr = NULL;
- return -1;
-}
-
-static int uv__fs_readdir(uv_fs_t* req) {
- uv_dir_t* dir;
- uv_dirent_t* dirent;
- struct dirent* res;
- unsigned int dirent_idx;
- unsigned int i;
-
- dir = (uv_dir_t*)req->ptr;
- dirent_idx = 0;
-
- while (dirent_idx < dir->nentries) {
- /* readdir() returns NULL on end of directory, as well as on error. errno
- is used to differentiate between the two conditions. */
- errno = 0;
- res = readdir(dir->dir);
-
- if (res == NULL) {
- if (errno != 0)
- goto error;
- break;
- }
-
- if (strcmp(res->d_name, ".") == 0 || strcmp(res->d_name, "..") == 0)
- continue;
-
- dirent = &dir->dirents[dirent_idx];
- dirent->name = uv__strdup(res->d_name);
-
- if (dirent->name == NULL)
- goto error;
-
- dirent->type = uv__fs_get_dirent_type(res);
- ++dirent_idx;
- }
-
- return dirent_idx;
-
-error:
- for (i = 0; i < dirent_idx; ++i) {
- uv__free((char*) dir->dirents[i].name);
- dir->dirents[i].name = NULL;
- }
-
- return -1;
-}
-
-static int uv__fs_closedir(uv_fs_t* req) {
- uv_dir_t* dir;
-
- dir = (uv_dir_t*)req->ptr;
-
- if (dir->dir != NULL) {
- closedir(dir->dir);
- dir->dir = NULL;
- }
-
- uv__free(req->ptr);
- req->ptr = NULL;
- return 0;
-}
-
-static ssize_t uv__fs_pathmax_size(const char* path) {
- ssize_t pathmax;
-
- pathmax = pathconf(path, _PC_PATH_MAX);
-
- if (pathmax == -1)
- pathmax = UV__PATH_MAX;
-
- return pathmax;
-}
-
-static ssize_t uv__fs_readlink(uv_fs_t* req) {
- ssize_t maxlen;
- ssize_t len;
- char* buf;
- char* newbuf;
-
-#if defined(_POSIX_PATH_MAX) || defined(PATH_MAX)
- maxlen = uv__fs_pathmax_size(req->path);
-#else
- /* We may not have a real PATH_MAX. Read size of link. */
- struct stat st;
- int ret;
- ret = lstat(req->path, &st);
- if (ret != 0)
- return -1;
- if (!S_ISLNK(st.st_mode)) {
- errno = EINVAL;
- return -1;
- }
-
- maxlen = st.st_size;
-
- /* According to readlink(2) lstat can report st_size == 0
- for some symlinks, such as those in /proc or /sys. */
- if (maxlen == 0)
- maxlen = uv__fs_pathmax_size(req->path);
-#endif
-
- buf = (char*)uv__malloc(maxlen);
-
- if (buf == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
-#if defined(__MVS__)
- len = os390_readlink(req->path, buf, maxlen);
-#else
- len = readlink(req->path, buf, maxlen);
-#endif
-
- if (len == -1) {
- uv__free(buf);
- return -1;
- }
-
- /* Uncommon case: resize to make room for the trailing nul byte. */
- if (len == maxlen) {
- newbuf = (char*)uv__realloc(buf, len + 1);
-
- if (newbuf == NULL) {
- uv__free(buf);
- return -1;
- }
-
- buf = newbuf;
- }
-
- buf[len] = '\0';
- req->ptr = buf;
-
- return 0;
-}
-
-static ssize_t uv__fs_realpath(uv_fs_t* req) {
- char* buf;
-
-#if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
- buf = realpath(req->path, NULL);
- if (buf == NULL)
- return -1;
-#else
- ssize_t len;
-
- len = uv__fs_pathmax_size(req->path);
- buf = (char*)uv__malloc(len + 1);
-
- if (buf == NULL) {
- errno = ENOMEM;
- return -1;
- }
-
- if (realpath(req->path, buf) == NULL) {
- uv__free(buf);
- return -1;
- }
-#endif
-
- req->ptr = buf;
-
- return 0;
-}
-
-static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
- struct pollfd pfd;
- int use_pread;
- off_t offset;
- ssize_t nsent;
- ssize_t nread;
- ssize_t nwritten;
- size_t buflen;
- size_t len;
- ssize_t n;
- int in_fd;
- int out_fd;
- char buf[8192];
-
- len = req->bufsml[0].len;
- in_fd = req->flags;
- out_fd = req->file;
- offset = req->off;
- use_pread = 1;
-
- /* Here are the rules regarding errors:
- *
- * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
- * The user needs to know that some data has already been sent, to stop
- * them from sending it twice.
- *
- * 2. Write errors are always reported. Write errors are bad because they
- * mean data loss: we've read data but now we can't write it out.
- *
- * We try to use pread() and fall back to regular read() if the source fd
- * doesn't support positional reads, for example when it's a pipe fd.
- *
- * If we get EAGAIN when writing to the target fd, we poll() on it until
- * it becomes writable again.
- *
- * FIXME: If we get a write error when use_pread==1, it should be safe to
- * return the number of sent bytes instead of an error because pread()
- * is, in theory, idempotent. However, special files in /dev or /proc
- * may support pread() but not necessarily return the same data on
- * successive reads.
- *
- * FIXME: There is no way now to signal that we managed to send *some* data
- * before a write error.
- */
- for (nsent = 0; (size_t) nsent < len; ) {
- buflen = len - nsent;
-
- if (buflen > sizeof(buf))
- buflen = sizeof(buf);
-
- do
- if (use_pread)
- nread = pread(in_fd, buf, buflen, offset);
- else
- nread = read(in_fd, buf, buflen);
- while (nread == -1 && errno == EINTR);
-
- if (nread == 0)
- goto out;
-
- if (nread == -1) {
- if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
- use_pread = 0;
- continue;
- }
-
- if (nsent == 0)
- nsent = -1;
-
- goto out;
- }
-
- for (nwritten = 0; nwritten < nread; ) {
- do
- n = write(out_fd, buf + nwritten, nread - nwritten);
- while (n == -1 && errno == EINTR);
-
- if (n != -1) {
- nwritten += n;
- continue;
- }
-
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- nsent = -1;
- goto out;
- }
-
- pfd.fd = out_fd;
- pfd.events = POLLOUT;
- pfd.revents = 0;
-
- do
- n = poll(&pfd, 1, -1);
- while (n == -1 && errno == EINTR);
-
- if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
- errno = EIO;
- nsent = -1;
- goto out;
- }
- }
-
- offset += nread;
- nsent += nread;
- }
-
-out:
- if (nsent != -1)
- req->off = offset;
-
- return nsent;
-}
-
-
-static ssize_t uv__fs_sendfile(uv_fs_t* req) {
- int in_fd;
- int out_fd;
-
- in_fd = req->flags;
- out_fd = req->file;
-
-#if defined(__linux__) || defined(__sun)
- {
- off_t off;
- ssize_t r;
-
- off = req->off;
- r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
-
- /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
- * it still writes out data. Fortunately, we can detect it by checking if
- * the offset has been updated.
- */
- if (r != -1 || off > req->off) {
- r = off - req->off;
- req->off = off;
- return r;
- }
-
- if (errno == EINVAL ||
- errno == EIO ||
- errno == ENOTSOCK ||
- errno == EXDEV) {
- errno = 0;
- return uv__fs_sendfile_emul(req);
- }
-
- return -1;
- }
-#elif defined(__APPLE__) || \
- defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__)
- {
- off_t len;
- ssize_t r;
-
- /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
- * non-blocking mode and not all data could be written. If a non-zero
- * number of bytes have been sent, we don't consider it an error.
- */
-
-#if defined(__FreeBSD__) || defined(__DragonFly__)
- len = 0;
- r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
-#elif defined(__FreeBSD_kernel__)
- len = 0;
- r = bsd_sendfile(in_fd,
- out_fd,
- req->off,
- req->bufsml[0].len,
- NULL,
- &len,
- 0);
-#else
- /* The darwin sendfile takes len as an input for the length to send,
- * so make sure to initialize it with the caller's value. */
- len = req->bufsml[0].len;
- r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
-#endif
-
- /*
- * The man page for sendfile(2) on DragonFly states that `len` contains
- * a meaningful value ONLY in case of EAGAIN and EINTR.
- * Nothing is said about it's value in case of other errors, so better
- * not depend on the potential wrong assumption that is was not modified
- * by the syscall.
- */
- if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
- req->off += len;
- return (ssize_t) len;
- }
-
- if (errno == EINVAL ||
- errno == EIO ||
- errno == ENOTSOCK ||
- errno == EXDEV) {
- errno = 0;
- return uv__fs_sendfile_emul(req);
- }
-
- return -1;
- }
-#else
- /* Squelch compiler warnings. */
- (void) &in_fd;
- (void) &out_fd;
-
- return uv__fs_sendfile_emul(req);
-#endif
-}
-
-
-static ssize_t uv__fs_utime(uv_fs_t* req) {
-#if defined(__linux__) \
- || defined(_AIX71) \
- || defined(__sun) \
- || defined(__HAIKU__)
- /* utimesat() has nanosecond resolution but we stick to microseconds
- * for the sake of consistency with other platforms.
- */
- struct timespec ts[2];
- ts[0].tv_sec = req->atime;
- ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
- ts[1].tv_sec = req->mtime;
- ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
- return utimensat(AT_FDCWD, req->path, ts, 0);
-#elif defined(__APPLE__) \
- || defined(__DragonFly__) \
- || defined(__FreeBSD__) \
- || defined(__FreeBSD_kernel__) \
- || defined(__NetBSD__) \
- || defined(__OpenBSD__)
- struct timeval tv[2];
- tv[0].tv_sec = req->atime;
- tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
- tv[1].tv_sec = req->mtime;
- tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
- return utimes(req->path, tv);
-#elif defined(_AIX) \
- && !defined(_AIX71)
- struct utimbuf buf;
- buf.actime = req->atime;
- buf.modtime = req->mtime;
- return utime(req->path, &buf);
-#elif defined(__MVS__)
- attrib_t atr;
- memset(&atr, 0, sizeof(atr));
- atr.att_mtimechg = 1;
- atr.att_atimechg = 1;
- atr.att_mtime = req->mtime;
- atr.att_atime = req->atime;
- return __lchattr((char*) req->path, &atr, sizeof(atr));
-#else
- errno = ENOSYS;
- return -1;
-#endif
-}
-
-
-static ssize_t uv__fs_write(uv_fs_t* req) {
-#if defined(__linux__)
- static int no_pwritev;
-#endif
- ssize_t r;
-
- /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
- * data loss. We can't use a per-file descriptor lock, the descriptor may be
- * a dup().
- */
-#if defined(__APPLE__)
- static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
- if (pthread_mutex_lock(&lock))
- abort();
-#endif
-
- if (req->off < 0) {
- if (req->nbufs == 1)
- r = write(req->file, req->bufs[0].base, req->bufs[0].len);
- else
- r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
- } else {
- if (req->nbufs == 1) {
- r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
- goto done;
- }
-#if HAVE_PREADV
- r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
-#else
-# if defined(__linux__)
- if (no_pwritev) retry:
-# endif
- {
- r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
- }
-# if defined(__linux__)
- else {
- r = uv__pwritev(req->file,
- (struct iovec*) req->bufs,
- req->nbufs,
- req->off);
- if (r == -1 && errno == ENOSYS) {
- no_pwritev = 1;
- goto retry;
- }
- }
-# endif
-#endif
- }
-
-done:
-#if defined(__APPLE__)
- if (pthread_mutex_unlock(&lock))
- abort();
-#endif
-
- return r;
-}
-
-static ssize_t uv__fs_copyfile(uv_fs_t* req) {
- uv_fs_t fs_req;
- uv_file srcfd;
- uv_file dstfd;
- struct stat src_statsbuf;
- struct stat dst_statsbuf;
- int dst_flags;
- int result;
- int err;
- size_t bytes_to_send;
- int64_t in_offset;
-
- dstfd = -1;
- err = 0;
-
- /* Open the source file. */
- srcfd = uv_fs_open(NULL, &fs_req, req->path, O_RDONLY, 0, NULL);
- uv_fs_req_cleanup(&fs_req);
-
- if (srcfd < 0)
- return srcfd;
-
- /* Get the source file's mode. */
- if (fstat(srcfd, &src_statsbuf)) {
- err = UV__ERR(errno);
- goto out;
- }
-
- dst_flags = O_WRONLY | O_CREAT | O_TRUNC;
-
- if (req->flags & UV_FS_COPYFILE_EXCL)
- dst_flags |= O_EXCL;
-
- /* Open the destination file. */
- dstfd = uv_fs_open(NULL,
- &fs_req,
- req->new_path,
- dst_flags,
- src_statsbuf.st_mode,
- NULL);
- uv_fs_req_cleanup(&fs_req);
-
- if (dstfd < 0) {
- err = dstfd;
- goto out;
- }
-
- /* Get the destination file's mode. */
- if (fstat(dstfd, &dst_statsbuf)) {
- err = UV__ERR(errno);
- goto out;
- }
-
- /* Check if srcfd and dstfd refer to the same file */
- if (src_statsbuf.st_dev == dst_statsbuf.st_dev &&
- src_statsbuf.st_ino == dst_statsbuf.st_ino) {
- goto out;
- }
-
- if (fchmod(dstfd, src_statsbuf.st_mode) == -1) {
- err = UV__ERR(errno);
- goto out;
- }
-
-#ifdef FICLONE
- if (req->flags & UV_FS_COPYFILE_FICLONE ||
- req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
- if (ioctl(dstfd, FICLONE, srcfd) == -1) {
- /* If an error occurred that the sendfile fallback also won't handle, or
- this is a force clone then exit. Otherwise, fall through to try using
- sendfile(). */
- if (errno != ENOTTY && errno != EOPNOTSUPP && errno != EXDEV) {
- err = UV__ERR(errno);
- goto out;
- } else if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
- err = UV_ENOTSUP;
- goto out;
- }
- } else {
- goto out;
- }
- }
-#else
- if (req->flags & UV_FS_COPYFILE_FICLONE_FORCE) {
- err = UV_ENOSYS;
- goto out;
- }
-#endif
-
- bytes_to_send = src_statsbuf.st_size;
- in_offset = 0;
- while (bytes_to_send != 0) {
- err = uv_fs_sendfile(NULL,
- &fs_req,
- dstfd,
- srcfd,
- in_offset,
- bytes_to_send,
- NULL);
- uv_fs_req_cleanup(&fs_req);
- if (err < 0)
- break;
- bytes_to_send -= fs_req.result;
- in_offset += fs_req.result;
- }
-
-out:
- if (err < 0)
- result = err;
- else
- result = 0;
-
- /* Close the source file. */
- err = uv__close_nocheckstdio(srcfd);
-
- /* Don't overwrite any existing errors. */
- if (err != 0 && result == 0)
- result = err;
-
- /* Close the destination file if it is open. */
- if (dstfd >= 0) {
- err = uv__close_nocheckstdio(dstfd);
-
- /* Don't overwrite any existing errors. */
- if (err != 0 && result == 0)
- result = err;
-
- /* Remove the destination file if something went wrong. */
- if (result != 0) {
- uv_fs_unlink(NULL, &fs_req, req->new_path, NULL);
- /* Ignore the unlink return value, as an error already happened. */
- uv_fs_req_cleanup(&fs_req);
- }
- }
-
- if (result == 0)
- return 0;
-
- errno = UV__ERR(result);
- return -1;
-}
-
-static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
- dst->st_dev = src->st_dev;
- dst->st_mode = src->st_mode;
- dst->st_nlink = src->st_nlink;
- dst->st_uid = src->st_uid;
- dst->st_gid = src->st_gid;
- dst->st_rdev = src->st_rdev;
- dst->st_ino = src->st_ino;
- dst->st_size = src->st_size;
- dst->st_blksize = src->st_blksize;
- dst->st_blocks = src->st_blocks;
-
-#if defined(__APPLE__)
- dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
- dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
- dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
- dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
- dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
- dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
- dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
- dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
- dst->st_flags = src->st_flags;
- dst->st_gen = src->st_gen;
-#elif defined(__ANDROID__)
- dst->st_atim.tv_sec = src->st_atime;
- dst->st_atim.tv_nsec = src->st_atimensec;
- dst->st_mtim.tv_sec = src->st_mtime;
- dst->st_mtim.tv_nsec = src->st_mtimensec;
- dst->st_ctim.tv_sec = src->st_ctime;
- dst->st_ctim.tv_nsec = src->st_ctimensec;
- dst->st_birthtim.tv_sec = src->st_ctime;
- dst->st_birthtim.tv_nsec = src->st_ctimensec;
- dst->st_flags = 0;
- dst->st_gen = 0;
-#elif !defined(_AIX) && ( \
- defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__OpenBSD__) || \
- defined(__NetBSD__) || \
- defined(_GNU_SOURCE) || \
- defined(_BSD_SOURCE) || \
- defined(_SVID_SOURCE) || \
- defined(_XOPEN_SOURCE) || \
- defined(_DEFAULT_SOURCE))
- dst->st_atim.tv_sec = src->st_atim.tv_sec;
- dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
- dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
- dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
- dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
- dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
-# if defined(__FreeBSD__) || \
- defined(__NetBSD__)
- dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
- dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
- dst->st_flags = src->st_flags;
- dst->st_gen = src->st_gen;
-# else
- dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
- dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
- dst->st_flags = 0;
- dst->st_gen = 0;
-# endif
-#else
- dst->st_atim.tv_sec = src->st_atime;
- dst->st_atim.tv_nsec = 0;
- dst->st_mtim.tv_sec = src->st_mtime;
- dst->st_mtim.tv_nsec = 0;
- dst->st_ctim.tv_sec = src->st_ctime;
- dst->st_ctim.tv_nsec = 0;
- dst->st_birthtim.tv_sec = src->st_ctime;
- dst->st_birthtim.tv_nsec = 0;
- dst->st_flags = 0;
- dst->st_gen = 0;
-#endif
-}
-
-
-static int uv__fs_statx(int fd,
- const char* path,
- int is_fstat,
- int is_lstat,
- uv_stat_t* buf) {
- STATIC_ASSERT(UV_ENOSYS != -1);
-#ifdef __linux__
- static int no_statx;
- struct uv__statx statxbuf;
- int dirfd;
- int flags;
- int mode;
- int rc;
-
- if (no_statx)
- return UV_ENOSYS;
-
- dirfd = AT_FDCWD;
- flags = 0; /* AT_STATX_SYNC_AS_STAT */
- mode = 0xFFF; /* STATX_BASIC_STATS + STATX_BTIME */
-
- if (is_fstat) {
- dirfd = fd;
- flags |= 0x1000; /* AT_EMPTY_PATH */
- }
-
- if (is_lstat)
- flags |= AT_SYMLINK_NOFOLLOW;
-
- rc = uv__statx(dirfd, path, flags, mode, &statxbuf);
-
- if (rc == -1) {
- /* EPERM happens when a seccomp filter rejects the system call.
- * Has been observed with libseccomp < 2.3.3 and docker < 18.04.
- */
- if (errno != EINVAL && errno != EPERM && errno != ENOSYS)
- return -1;
-
- no_statx = 1;
- return UV_ENOSYS;
- }
-
- buf->st_dev = 256 * statxbuf.stx_dev_major + statxbuf.stx_dev_minor;
- buf->st_mode = statxbuf.stx_mode;
- buf->st_nlink = statxbuf.stx_nlink;
- buf->st_uid = statxbuf.stx_uid;
- buf->st_gid = statxbuf.stx_gid;
- buf->st_rdev = statxbuf.stx_rdev_major;
- buf->st_ino = statxbuf.stx_ino;
- buf->st_size = statxbuf.stx_size;
- buf->st_blksize = statxbuf.stx_blksize;
- buf->st_blocks = statxbuf.stx_blocks;
- buf->st_atim.tv_sec = statxbuf.stx_atime.tv_sec;
- buf->st_atim.tv_nsec = statxbuf.stx_atime.tv_nsec;
- buf->st_mtim.tv_sec = statxbuf.stx_mtime.tv_sec;
- buf->st_mtim.tv_nsec = statxbuf.stx_mtime.tv_nsec;
- buf->st_ctim.tv_sec = statxbuf.stx_ctime.tv_sec;
- buf->st_ctim.tv_nsec = statxbuf.stx_ctime.tv_nsec;
- buf->st_birthtim.tv_sec = statxbuf.stx_btime.tv_sec;
- buf->st_birthtim.tv_nsec = statxbuf.stx_btime.tv_nsec;
- buf->st_flags = 0;
- buf->st_gen = 0;
-
- return 0;
-#else
- return UV_ENOSYS;
-#endif /* __linux__ */
-}
-
-
-static int uv__fs_stat(const char *path, uv_stat_t *buf) {
- struct stat pbuf;
- int ret;
-
- ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 0, buf);
- if (ret != UV_ENOSYS)
- return ret;
-
- ret = stat(path, &pbuf);
- if (ret == 0)
- uv__to_stat(&pbuf, buf);
-
- return ret;
-}
-
-
-static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
- struct stat pbuf;
- int ret;
-
- ret = uv__fs_statx(-1, path, /* is_fstat */ 0, /* is_lstat */ 1, buf);
- if (ret != UV_ENOSYS)
- return ret;
-
- ret = lstat(path, &pbuf);
- if (ret == 0)
- uv__to_stat(&pbuf, buf);
-
- return ret;
-}
-
-
-static int uv__fs_fstat(int fd, uv_stat_t *buf) {
- struct stat pbuf;
- int ret;
-
- ret = uv__fs_statx(fd, "", /* is_fstat */ 1, /* is_lstat */ 0, buf);
- if (ret != UV_ENOSYS)
- return ret;
-
- ret = fstat(fd, &pbuf);
- if (ret == 0)
- uv__to_stat(&pbuf, buf);
-
- return ret;
-}
-
-static size_t uv__fs_buf_offset(uv_buf_t* bufs, size_t size) {
- size_t offset;
- /* Figure out which bufs are done */
- for (offset = 0; size > 0 && bufs[offset].len <= size; ++offset)
- size -= bufs[offset].len;
-
- /* Fix a partial read/write */
- if (size > 0) {
- bufs[offset].base += size;
- bufs[offset].len -= size;
- }
- return offset;
-}
-
-static ssize_t uv__fs_write_all(uv_fs_t* req) {
- unsigned int iovmax;
- unsigned int nbufs;
- uv_buf_t* bufs;
- ssize_t total;
- ssize_t result;
-
- iovmax = uv__getiovmax();
- nbufs = req->nbufs;
- bufs = req->bufs;
- total = 0;
-
- while (nbufs > 0) {
- req->nbufs = nbufs;
- if (req->nbufs > iovmax)
- req->nbufs = iovmax;
-
- do
- result = uv__fs_write(req);
- while (result < 0 && errno == EINTR);
-
- if (result <= 0) {
- if (total == 0)
- total = result;
- break;
- }
-
- if (req->off >= 0)
- req->off += result;
-
- req->nbufs = uv__fs_buf_offset(req->bufs, result);
- req->bufs += req->nbufs;
- nbufs -= req->nbufs;
- total += result;
- }
-
- if (bufs != req->bufsml)
- uv__free(bufs);
-
- req->bufs = NULL;
- req->nbufs = 0;
-
- return total;
-}
-
-
-static void uv__fs_work(struct uv__work* w) {
- int retry_on_eintr;
- uv_fs_t* req;
- ssize_t r;
-
- req = container_of(w, uv_fs_t, work_req);
- retry_on_eintr = !(req->fs_type == UV_FS_CLOSE ||
- req->fs_type == UV_FS_READ);
-
- do {
- errno = 0;
-
-#define X(type, action) \
- case UV_FS_ ## type: \
- r = action; \
- break;
-
- switch (req->fs_type) {
- X(ACCESS, access(req->path, req->flags));
- X(CHMOD, chmod(req->path, req->mode));
- X(CHOWN, chown(req->path, req->uid, req->gid));
- X(CLOSE, uv__fs_close(req->file));
- X(COPYFILE, uv__fs_copyfile(req));
- X(FCHMOD, fchmod(req->file, req->mode));
- X(FCHOWN, fchown(req->file, req->uid, req->gid));
- X(LCHOWN, lchown(req->path, req->uid, req->gid));
- X(FDATASYNC, uv__fs_fdatasync(req));
- X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
- X(FSYNC, uv__fs_fsync(req));
- X(FTRUNCATE, ftruncate(req->file, req->off));
- X(FUTIME, uv__fs_futime(req));
- X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
- X(LINK, link(req->path, req->new_path));
- X(MKDIR, mkdir(req->path, req->mode));
- X(MKDTEMP, uv__fs_mkdtemp(req));
- X(OPEN, uv__fs_open(req));
- X(READ, uv__fs_read(req));
- X(SCANDIR, uv__fs_scandir(req));
- X(OPENDIR, uv__fs_opendir(req));
- X(READDIR, uv__fs_readdir(req));
- X(CLOSEDIR, uv__fs_closedir(req));
- X(READLINK, uv__fs_readlink(req));
- X(REALPATH, uv__fs_realpath(req));
- X(RENAME, rename(req->path, req->new_path));
- X(RMDIR, rmdir(req->path));
- X(SENDFILE, uv__fs_sendfile(req));
- X(STAT, uv__fs_stat(req->path, &req->statbuf));
- X(SYMLINK, symlink(req->path, req->new_path));
- X(UNLINK, unlink(req->path));
- X(UTIME, uv__fs_utime(req));
- X(WRITE, uv__fs_write_all(req));
- default: abort();
- }
-#undef X
- } while (r == -1 && errno == EINTR && retry_on_eintr);
-
- if (r == -1)
- req->result = UV__ERR(errno);
- else
- req->result = r;
-
- if (r == 0 && (req->fs_type == UV_FS_STAT ||
- req->fs_type == UV_FS_FSTAT ||
- req->fs_type == UV_FS_LSTAT)) {
- req->ptr = &req->statbuf;
- }
-}
-
-
-static void uv__fs_done(struct uv__work* w, int status) {
- uv_fs_t* req;
-
- req = container_of(w, uv_fs_t, work_req);
- uv__req_unregister(req->loop, req);
-
- if (status == UV_ECANCELED) {
- assert(req->result == 0);
- req->result = UV_ECANCELED;
- }
-
- req->cb(req);
-}
-
-
-int uv_fs_access(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- uv_fs_cb cb) {
- INIT(ACCESS);
- PATH;
- req->flags = flags;
- POST;
-}
-
-
-int uv_fs_chmod(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int mode,
- uv_fs_cb cb) {
- INIT(CHMOD);
- PATH;
- req->mode = mode;
- POST;
-}
-
-
-int uv_fs_chown(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb) {
- INIT(CHOWN);
- PATH;
- req->uid = uid;
- req->gid = gid;
- POST;
-}
-
-
-int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
- INIT(CLOSE);
- req->file = file;
- POST;
-}
-
-
-int uv_fs_fchmod(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- int mode,
- uv_fs_cb cb) {
- INIT(FCHMOD);
- req->file = file;
- req->mode = mode;
- POST;
-}
-
-
-int uv_fs_fchown(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb) {
- INIT(FCHOWN);
- req->file = file;
- req->uid = uid;
- req->gid = gid;
- POST;
-}
-
-
-int uv_fs_lchown(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_uid_t uid,
- uv_gid_t gid,
- uv_fs_cb cb) {
- INIT(LCHOWN);
- PATH;
- req->uid = uid;
- req->gid = gid;
- POST;
-}
-
-
-int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
- INIT(FDATASYNC);
- req->file = file;
- POST;
-}
-
-
-int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
- INIT(FSTAT);
- req->file = file;
- POST;
-}
-
-
-int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
- INIT(FSYNC);
- req->file = file;
- POST;
-}
-
-
-int uv_fs_ftruncate(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- int64_t off,
- uv_fs_cb cb) {
- INIT(FTRUNCATE);
- req->file = file;
- req->off = off;
- POST;
-}
-
-
-int uv_fs_futime(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- double atime,
- double mtime,
- uv_fs_cb cb) {
- INIT(FUTIME);
- req->file = file;
- req->atime = atime;
- req->mtime = mtime;
- POST;
-}
-
-
-int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- INIT(LSTAT);
- PATH;
- POST;
-}
-
-
-int uv_fs_link(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- uv_fs_cb cb) {
- INIT(LINK);
- PATH2;
- POST;
-}
-
-
-int uv_fs_mkdir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int mode,
- uv_fs_cb cb) {
- INIT(MKDIR);
- PATH;
- req->mode = mode;
- POST;
-}
-
-
-int uv_fs_mkdtemp(uv_loop_t* loop,
- uv_fs_t* req,
- const char* tpl,
- uv_fs_cb cb) {
- INIT(MKDTEMP);
- req->path = uv__strdup(tpl);
- if (req->path == NULL)
- return UV_ENOMEM;
- POST;
-}
-
-
-int uv_fs_open(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- int mode,
- uv_fs_cb cb) {
- INIT(OPEN);
- PATH;
- req->flags = flags;
- req->mode = mode;
- POST;
-}
-
-
-int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
- uv_file file,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t off,
- uv_fs_cb cb) {
- INIT(READ);
-
- if (bufs == NULL || nbufs == 0)
- return UV_EINVAL;
-
- req->file = file;
-
- req->nbufs = nbufs;
- req->bufs = req->bufsml;
- if (nbufs > ARRAY_SIZE(req->bufsml))
- req->bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(*bufs));
-
- if (req->bufs == NULL)
- return UV_ENOMEM;
-
- memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
-
- req->off = off;
- POST;
-}
-
-
-int uv_fs_scandir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- uv_fs_cb cb) {
- INIT(SCANDIR);
- PATH;
- req->flags = flags;
- POST;
-}
-
-int uv_fs_opendir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb) {
- INIT(OPENDIR);
- PATH;
- POST;
-}
-
-int uv_fs_readdir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb) {
- INIT(READDIR);
-
- if (dir == NULL || dir->dir == NULL || dir->dirents == NULL)
- return UV_EINVAL;
-
- req->ptr = dir;
- POST;
-}
-
-int uv_fs_closedir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb) {
- INIT(CLOSEDIR);
-
- if (dir == NULL)
- return UV_EINVAL;
-
- req->ptr = dir;
- POST;
-}
-
-int uv_fs_readlink(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb) {
- INIT(READLINK);
- PATH;
- POST;
-}
-
-
-int uv_fs_realpath(uv_loop_t* loop,
- uv_fs_t* req,
- const char * path,
- uv_fs_cb cb) {
- INIT(REALPATH);
- PATH;
- POST;
-}
-
-
-int uv_fs_rename(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- uv_fs_cb cb) {
- INIT(RENAME);
- PATH2;
- POST;
-}
-
-
-int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- INIT(RMDIR);
- PATH;
- POST;
-}
-
-
-int uv_fs_sendfile(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file out_fd,
- uv_file in_fd,
- int64_t off,
- size_t len,
- uv_fs_cb cb) {
- INIT(SENDFILE);
- req->flags = in_fd; /* hack */
- req->file = out_fd;
- req->off = off;
- req->bufsml[0].len = len;
- POST;
-}
-
-
-int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- INIT(STAT);
- PATH;
- POST;
-}
-
-
-int uv_fs_symlink(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- int flags,
- uv_fs_cb cb) {
- INIT(SYMLINK);
- PATH2;
- req->flags = flags;
- POST;
-}
-
-
-int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- INIT(UNLINK);
- PATH;
- POST;
-}
-
-
-int uv_fs_utime(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- double atime,
- double mtime,
- uv_fs_cb cb) {
- INIT(UTIME);
- PATH;
- req->atime = atime;
- req->mtime = mtime;
- POST;
-}
-
-
-int uv_fs_write(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file file,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t off,
- uv_fs_cb cb) {
- INIT(WRITE);
-
- if (bufs == NULL || nbufs == 0)
- return UV_EINVAL;
-
- req->file = file;
-
- req->nbufs = nbufs;
- req->bufs = req->bufsml;
- if (nbufs > ARRAY_SIZE(req->bufsml))
- req->bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(*bufs));
-
- if (req->bufs == NULL)
- return UV_ENOMEM;
-
- memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
-
- req->off = off;
- POST;
-}
-
-
-void uv_fs_req_cleanup(uv_fs_t* req) {
- if (req == NULL)
- return;
-
- /* Only necessary for asychronous requests, i.e., requests with a callback.
- * Synchronous ones don't copy their arguments and have req->path and
- * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
- * exception to the rule, it always allocates memory.
- */
- if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
- uv__free((void*) req->path); /* Memory is shared with req->new_path. */
-
- req->path = NULL;
- req->new_path = NULL;
-
- if (req->fs_type == UV_FS_READDIR && req->ptr != NULL)
- uv__fs_readdir_cleanup(req);
-
- if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
- uv__fs_scandir_cleanup(req);
-
- if (req->bufs != req->bufsml)
- uv__free(req->bufs);
- req->bufs = NULL;
-
- if (req->fs_type != UV_FS_OPENDIR && req->ptr != &req->statbuf)
- uv__free(req->ptr);
- req->ptr = NULL;
-}
-
-
-int uv_fs_copyfile(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- int flags,
- uv_fs_cb cb) {
- INIT(COPYFILE);
-
- if (flags & ~(UV_FS_COPYFILE_EXCL |
- UV_FS_COPYFILE_FICLONE |
- UV_FS_COPYFILE_FICLONE_FORCE)) {
- return UV_EINVAL;
- }
-
- PATH2;
- req->flags = flags;
- POST;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/fsevents.cpp b/wpiutil/src/main/native/libuv/src/unix/fsevents.cpp
deleted file mode 100644
index 32d280f..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/fsevents.cpp
+++ /dev/null
@@ -1,922 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#if TARGET_OS_IPHONE || MAC_OS_X_VERSION_MAX_ALLOWED < 1070
-
-/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
-/* macOS prior to 10.7 doesn't provide the full FSEvents API so use kqueue */
-
-int uv__fsevents_init(uv_fs_event_t* handle) {
- return 0;
-}
-
-
-int uv__fsevents_close(uv_fs_event_t* handle) {
- return 0;
-}
-
-
-void uv__fsevents_loop_delete(uv_loop_t* loop) {
-}
-
-#else /* TARGET_OS_IPHONE */
-
-#include <dlfcn.h>
-#include <assert.h>
-#include <stdlib.h>
-#include <pthread.h>
-
-#include <CoreFoundation/CFRunLoop.h>
-#include <CoreServices/CoreServices.h>
-
-/* These are macros to avoid "initializer element is not constant" errors
- * with old versions of gcc.
- */
-#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
- kFSEventStreamEventFlagItemModified | \
- kFSEventStreamEventFlagItemInodeMetaMod | \
- kFSEventStreamEventFlagItemChangeOwner | \
- kFSEventStreamEventFlagItemXattrMod)
-
-#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
- kFSEventStreamEventFlagItemRemoved | \
- kFSEventStreamEventFlagItemRenamed)
-
-#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
- kFSEventStreamEventFlagKernelDropped | \
- kFSEventStreamEventFlagEventIdsWrapped | \
- kFSEventStreamEventFlagHistoryDone | \
- kFSEventStreamEventFlagMount | \
- kFSEventStreamEventFlagUnmount | \
- kFSEventStreamEventFlagRootChanged)
-
-typedef struct uv__fsevents_event_s uv__fsevents_event_t;
-typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
-typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
-
-enum uv__cf_loop_signal_type_e {
- kUVCFLoopSignalRegular,
- kUVCFLoopSignalClosing
-};
-typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
-
-struct uv__cf_loop_signal_s {
- QUEUE member;
- uv_fs_event_t* handle;
- uv__cf_loop_signal_type_t type;
-};
-
-struct uv__fsevents_event_s {
- QUEUE member;
- int events;
- char path[1];
-};
-
-struct uv__cf_loop_state_s {
- CFRunLoopRef loop;
- CFRunLoopSourceRef signal_source;
- int fsevent_need_reschedule;
- FSEventStreamRef fsevent_stream;
- uv_sem_t fsevent_sem;
- uv_mutex_t fsevent_mutex;
- void* fsevent_handles[2];
- unsigned int fsevent_handle_count;
-};
-
-/* Forward declarations */
-static void uv__cf_loop_cb(void* arg);
-static void* uv__cf_loop_runner(void* arg);
-static int uv__cf_loop_signal(uv_loop_t* loop,
- uv_fs_event_t* handle,
- uv__cf_loop_signal_type_t type);
-
-/* Lazy-loaded by uv__fsevents_global_init(). */
-static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
- const void**,
- CFIndex,
- const CFArrayCallBacks*);
-static void (*pCFRelease)(CFTypeRef);
-static void (*pCFRunLoopAddSource)(CFRunLoopRef,
- CFRunLoopSourceRef,
- CFStringRef);
-static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
-static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
- CFRunLoopSourceRef,
- CFStringRef);
-static void (*pCFRunLoopRun)(void);
-static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
- CFIndex,
- CFRunLoopSourceContext*);
-static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
-static void (*pCFRunLoopStop)(CFRunLoopRef);
-static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
-static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
- CFAllocatorRef,
- const char*);
-static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
-static CFStringRef (*pkCFRunLoopDefaultMode);
-static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
- FSEventStreamCallback,
- FSEventStreamContext*,
- CFArrayRef,
- FSEventStreamEventId,
- CFTimeInterval,
- FSEventStreamCreateFlags);
-static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
-static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
-static void (*pFSEventStreamRelease)(FSEventStreamRef);
-static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
- CFRunLoopRef,
- CFStringRef);
-static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
-static void (*pFSEventStreamStop)(FSEventStreamRef);
-
-#define UV__FSEVENTS_PROCESS(handle, block) \
- do { \
- QUEUE events; \
- QUEUE* q; \
- uv__fsevents_event_t* event; \
- int err; \
- uv_mutex_lock(&(handle)->cf_mutex); \
- /* Split-off all events and empty original queue */ \
- QUEUE_MOVE(&(handle)->cf_events, &events); \
- /* Get error (if any) and zero original one */ \
- err = (handle)->cf_error; \
- (handle)->cf_error = 0; \
- uv_mutex_unlock(&(handle)->cf_mutex); \
- /* Loop through events, deallocating each after processing */ \
- while (!QUEUE_EMPTY(&events)) { \
- q = QUEUE_HEAD(&events); \
- event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
- QUEUE_REMOVE(q); \
- /* NOTE: Checking uv__is_active() is required here, because handle \
- * callback may close handle and invoking it after it will lead to \
- * incorrect behaviour */ \
- if (!uv__is_closing((handle)) && uv__is_active((handle))) \
- block \
- /* Free allocated data */ \
- uv__free(event); \
- } \
- if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
- (handle)->cb((handle), NULL, 0, err); \
- } while (0)
-
-
-/* Runs in UV loop's thread, when there're events to report to handle */
-static void uv__fsevents_cb(uv_async_t* cb) {
- uv_fs_event_t* handle;
-
- handle = (uv_fs_event_t*)cb->data;
-
- UV__FSEVENTS_PROCESS(handle, {
- handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
- });
-}
-
-
-/* Runs in CF thread, pushed event into handle's event list */
-static void uv__fsevents_push_event(uv_fs_event_t* handle,
- QUEUE* events,
- int err) {
- assert(events != NULL || err != 0);
- uv_mutex_lock(&handle->cf_mutex);
-
- /* Concatenate two queues */
- if (events != NULL)
- QUEUE_ADD(&handle->cf_events, events);
-
- /* Propagate error */
- if (err != 0)
- handle->cf_error = err;
- uv_mutex_unlock(&handle->cf_mutex);
-
- uv_async_send(handle->cf_cb);
-}
-
-
-/* Runs in CF thread, when there're events in FSEventStream */
-static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
- void* info,
- size_t numEvents,
- void* eventPaths,
- const FSEventStreamEventFlags eventFlags[],
- const FSEventStreamEventId eventIds[]) {
- size_t i;
- int len;
- char** paths;
- char* path;
- char* pos;
- uv_fs_event_t* handle;
- QUEUE* q;
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
- uv__fsevents_event_t* event;
- FSEventStreamEventFlags flags;
- QUEUE head;
-
- loop = (uv_loop_t*)info;
- state = (uv__cf_loop_state_t*)loop->cf_state;
- assert(state != NULL);
- paths = (char**)eventPaths;
-
- /* For each handle */
- uv_mutex_lock(&state->fsevent_mutex);
- QUEUE_FOREACH(q, &state->fsevent_handles) {
- handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
- QUEUE_INIT(&head);
-
- /* Process and filter out events */
- for (i = 0; i < numEvents; i++) {
- flags = eventFlags[i];
-
- /* Ignore system events */
- if (flags & kFSEventsSystem)
- continue;
-
- path = paths[i];
- len = strlen(path);
-
- if (handle->realpath_len == 0)
- continue; /* This should be unreachable */
-
- /* Filter out paths that are outside handle's request */
- if (len < handle->realpath_len)
- continue;
-
- if (handle->realpath_len != len &&
- path[handle->realpath_len] != '/')
- /* Make sure that realpath actually named a directory,
- * or that we matched the whole string */
- continue;
-
- if (memcmp(path, handle->realpath, handle->realpath_len) != 0)
- continue;
-
- if (!(handle->realpath_len == 1 && handle->realpath[0] == '/')) {
- /* Remove common prefix, unless the watched folder is "/" */
- path += handle->realpath_len;
- len -= handle->realpath_len;
-
- /* Ignore events with path equal to directory itself */
- if (len <= 1 && (flags & kFSEventStreamEventFlagItemIsDir))
- continue;
-
- if (len == 0) {
- /* Since we're using fsevents to watch the file itself,
- * realpath == path, and we now need to get the basename of the file back
- * (for commonality with other codepaths and platforms). */
- while (len < handle->realpath_len && path[-1] != '/') {
- path--;
- len++;
- }
- /* Created and Removed seem to be always set, but don't make sense */
- flags &= ~kFSEventsRenamed;
- } else {
- /* Skip forward slash */
- path++;
- len--;
- }
- }
-
- /* Do not emit events from subdirectories (without option set) */
- if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != '\0') {
- pos = strchr(path + 1, '/');
- if (pos != NULL)
- continue;
- }
-
- event = (uv__fsevents_event_t*)uv__malloc(sizeof(*event) + len);
- if (event == NULL)
- break;
-
- memset(event, 0, sizeof(*event));
- memcpy(event->path, path, len + 1);
- event->events = UV_RENAME;
-
- if (0 == (flags & kFSEventsRenamed)) {
- if (0 != (flags & kFSEventsModified) ||
- 0 == (flags & kFSEventStreamEventFlagItemIsDir))
- event->events = UV_CHANGE;
- }
-
- QUEUE_INSERT_TAIL(&head, &event->member);
- }
-
- if (!QUEUE_EMPTY(&head))
- uv__fsevents_push_event(handle, &head, 0);
- }
- uv_mutex_unlock(&state->fsevent_mutex);
-}
-
-
-/* Runs in CF thread */
-static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
- uv__cf_loop_state_t* state;
- FSEventStreamContext ctx;
- FSEventStreamRef ref;
- CFAbsoluteTime latency;
- FSEventStreamCreateFlags flags;
-
- /* Initialize context */
- ctx.version = 0;
- ctx.info = loop;
- ctx.retain = NULL;
- ctx.release = NULL;
- ctx.copyDescription = NULL;
-
- latency = 0.05;
-
- /* Explanation of selected flags:
- * 1. NoDefer - without this flag, events that are happening continuously
- * (i.e. each event is happening after time interval less than `latency`,
- * counted from previous event), will be deferred and passed to callback
- * once they'll either fill whole OS buffer, or when this continuous stream
- * will stop (i.e. there'll be delay between events, bigger than
- * `latency`).
- * Specifying this flag will invoke callback after `latency` time passed
- * since event.
- * 2. FileEvents - fire callback for file changes too (by default it is firing
- * it only for directory changes).
- */
- flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
-
- /*
- * NOTE: It might sound like a good idea to remember last seen StreamEventId,
- * but in reality one dir might have last StreamEventId less than, the other,
- * that is being watched now. Which will cause FSEventStream API to report
- * changes to files from the past.
- */
- ref = pFSEventStreamCreate(NULL,
- &uv__fsevents_event_cb,
- &ctx,
- paths,
- kFSEventStreamEventIdSinceNow,
- latency,
- flags);
- assert(ref != NULL);
-
- state = (uv__cf_loop_state_t*)loop->cf_state;
- pFSEventStreamScheduleWithRunLoop(ref,
- state->loop,
- *pkCFRunLoopDefaultMode);
- if (!pFSEventStreamStart(ref)) {
- pFSEventStreamInvalidate(ref);
- pFSEventStreamRelease(ref);
- return UV_EMFILE;
- }
-
- state->fsevent_stream = ref;
- return 0;
-}
-
-
-/* Runs in CF thread */
-static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
- uv__cf_loop_state_t* state;
-
- state = (uv__cf_loop_state_t*)loop->cf_state;
-
- if (state->fsevent_stream == NULL)
- return;
-
- /* Stop emitting events */
- pFSEventStreamStop(state->fsevent_stream);
-
- /* Release stream */
- pFSEventStreamInvalidate(state->fsevent_stream);
- pFSEventStreamRelease(state->fsevent_stream);
- state->fsevent_stream = NULL;
-}
-
-
-/* Runs in CF thread, when there're new fsevent handles to add to stream */
-static void uv__fsevents_reschedule(uv_fs_event_t* handle,
- uv__cf_loop_signal_type_t type) {
- uv__cf_loop_state_t* state;
- QUEUE* q;
- uv_fs_event_t* curr;
- CFArrayRef cf_paths;
- CFStringRef* paths;
- unsigned int i;
- int err;
- unsigned int path_count;
-
- state = (uv__cf_loop_state_t*)handle->loop->cf_state;
- paths = NULL;
- cf_paths = NULL;
- err = 0;
- /* NOTE: `i` is used in deallocation loop below */
- i = 0;
-
- /* Optimization to prevent O(n^2) time spent when starting to watch
- * many files simultaneously
- */
- uv_mutex_lock(&state->fsevent_mutex);
- if (state->fsevent_need_reschedule == 0) {
- uv_mutex_unlock(&state->fsevent_mutex);
- goto final;
- }
- state->fsevent_need_reschedule = 0;
- uv_mutex_unlock(&state->fsevent_mutex);
-
- /* Destroy previous FSEventStream */
- uv__fsevents_destroy_stream(handle->loop);
-
- /* Any failure below will be a memory failure */
- err = UV_ENOMEM;
-
- /* Create list of all watched paths */
- uv_mutex_lock(&state->fsevent_mutex);
- path_count = state->fsevent_handle_count;
- if (path_count != 0) {
- paths = (CFStringRef*)uv__malloc(sizeof(*paths) * path_count);
- if (paths == NULL) {
- uv_mutex_unlock(&state->fsevent_mutex);
- goto final;
- }
-
- q = &state->fsevent_handles;
- for (; i < path_count; i++) {
- q = QUEUE_NEXT(q);
- assert(q != &state->fsevent_handles);
- curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
-
- assert(curr->realpath != NULL);
- paths[i] =
- pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
- if (paths[i] == NULL) {
- uv_mutex_unlock(&state->fsevent_mutex);
- goto final;
- }
- }
- }
- uv_mutex_unlock(&state->fsevent_mutex);
- err = 0;
-
- if (path_count != 0) {
- /* Create new FSEventStream */
- cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
- if (cf_paths == NULL) {
- err = UV_ENOMEM;
- goto final;
- }
- err = uv__fsevents_create_stream(handle->loop, cf_paths);
- }
-
-final:
- /* Deallocate all paths in case of failure */
- if (err != 0) {
- if (cf_paths == NULL) {
- while (i != 0)
- pCFRelease(paths[--i]);
- uv__free(paths);
- } else {
- /* CFArray takes ownership of both strings and original C-array */
- pCFRelease(cf_paths);
- }
-
- /* Broadcast error to all handles */
- uv_mutex_lock(&state->fsevent_mutex);
- QUEUE_FOREACH(q, &state->fsevent_handles) {
- curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
- uv__fsevents_push_event(curr, NULL, err);
- }
- uv_mutex_unlock(&state->fsevent_mutex);
- }
-
- /*
- * Main thread will block until the removal of handle from the list,
- * we must tell it when we're ready.
- *
- * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
- */
- if (type == kUVCFLoopSignalClosing)
- uv_sem_post(&state->fsevent_sem);
-}
-
-
-static int uv__fsevents_global_init(void) {
- static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
- static void* core_foundation_handle;
- static void* core_services_handle;
- int err;
-
- err = 0;
- pthread_mutex_lock(&global_init_mutex);
- if (core_foundation_handle != NULL)
- goto out;
-
- /* The libraries are never unloaded because we currently don't have a good
- * mechanism for keeping a reference count. It's unlikely to be an issue
- * but if it ever becomes one, we can turn the dynamic library handles into
- * per-event loop properties and have the dynamic linker keep track for us.
- */
- err = UV_ENOSYS;
- core_foundation_handle = dlopen("/System/Library/Frameworks/"
- "CoreFoundation.framework/"
- "Versions/A/CoreFoundation",
- RTLD_LAZY | RTLD_LOCAL);
- if (core_foundation_handle == NULL)
- goto out;
-
- core_services_handle = dlopen("/System/Library/Frameworks/"
- "CoreServices.framework/"
- "Versions/A/CoreServices",
- RTLD_LAZY | RTLD_LOCAL);
- if (core_services_handle == NULL)
- goto out;
-
- err = UV_ENOENT;
-#define V(handle, symbol) \
- do { \
- *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
- if (p ## symbol == NULL) \
- goto out; \
- } \
- while (0)
- V(core_foundation_handle, CFArrayCreate);
- V(core_foundation_handle, CFRelease);
- V(core_foundation_handle, CFRunLoopAddSource);
- V(core_foundation_handle, CFRunLoopGetCurrent);
- V(core_foundation_handle, CFRunLoopRemoveSource);
- V(core_foundation_handle, CFRunLoopRun);
- V(core_foundation_handle, CFRunLoopSourceCreate);
- V(core_foundation_handle, CFRunLoopSourceSignal);
- V(core_foundation_handle, CFRunLoopStop);
- V(core_foundation_handle, CFRunLoopWakeUp);
- V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
- V(core_foundation_handle, CFStringGetSystemEncoding);
- V(core_foundation_handle, kCFRunLoopDefaultMode);
- V(core_services_handle, FSEventStreamCreate);
- V(core_services_handle, FSEventStreamFlushSync);
- V(core_services_handle, FSEventStreamInvalidate);
- V(core_services_handle, FSEventStreamRelease);
- V(core_services_handle, FSEventStreamScheduleWithRunLoop);
- V(core_services_handle, FSEventStreamStart);
- V(core_services_handle, FSEventStreamStop);
-#undef V
- err = 0;
-
-out:
- if (err && core_services_handle != NULL) {
- dlclose(core_services_handle);
- core_services_handle = NULL;
- }
-
- if (err && core_foundation_handle != NULL) {
- dlclose(core_foundation_handle);
- core_foundation_handle = NULL;
- }
-
- pthread_mutex_unlock(&global_init_mutex);
- return err;
-}
-
-
-/* Runs in UV loop */
-static int uv__fsevents_loop_init(uv_loop_t* loop) {
- CFRunLoopSourceContext ctx;
- uv__cf_loop_state_t* state;
- pthread_attr_t attr_storage;
- pthread_attr_t* attr;
- int err;
-
- if (loop->cf_state != NULL)
- return 0;
-
- err = uv__fsevents_global_init();
- if (err)
- return err;
-
- state = (uv__cf_loop_state_t*)uv__calloc(1, sizeof(*state));
- if (state == NULL)
- return UV_ENOMEM;
-
- err = uv_mutex_init(&loop->cf_mutex);
- if (err)
- goto fail_mutex_init;
-
- err = uv_sem_init(&loop->cf_sem, 0);
- if (err)
- goto fail_sem_init;
-
- QUEUE_INIT(&loop->cf_signals);
-
- err = uv_sem_init(&state->fsevent_sem, 0);
- if (err)
- goto fail_fsevent_sem_init;
-
- err = uv_mutex_init(&state->fsevent_mutex);
- if (err)
- goto fail_fsevent_mutex_init;
-
- QUEUE_INIT(&state->fsevent_handles);
- state->fsevent_need_reschedule = 0;
- state->fsevent_handle_count = 0;
-
- memset(&ctx, 0, sizeof(ctx));
- ctx.info = loop;
- ctx.perform = uv__cf_loop_cb;
- state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
- if (state->signal_source == NULL) {
- err = UV_ENOMEM;
- goto fail_signal_source_create;
- }
-
- /* In the unlikely event that pthread_attr_init() fails, create the thread
- * with the default stack size. We'll use a little more address space but
- * that in itself is not a fatal error.
- */
- attr = &attr_storage;
- if (pthread_attr_init(attr))
- attr = NULL;
-
- if (attr != NULL)
- if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
- abort();
-
- loop->cf_state = state;
-
- /* uv_thread_t is an alias for pthread_t. */
- err = UV__ERR(pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop));
-
- if (attr != NULL)
- pthread_attr_destroy(attr);
-
- if (err)
- goto fail_thread_create;
-
- /* Synchronize threads */
- uv_sem_wait(&loop->cf_sem);
- return 0;
-
-fail_thread_create:
- loop->cf_state = NULL;
-
-fail_signal_source_create:
- uv_mutex_destroy(&state->fsevent_mutex);
-
-fail_fsevent_mutex_init:
- uv_sem_destroy(&state->fsevent_sem);
-
-fail_fsevent_sem_init:
- uv_sem_destroy(&loop->cf_sem);
-
-fail_sem_init:
- uv_mutex_destroy(&loop->cf_mutex);
-
-fail_mutex_init:
- uv__free(state);
- return err;
-}
-
-
-/* Runs in UV loop */
-void uv__fsevents_loop_delete(uv_loop_t* loop) {
- uv__cf_loop_signal_t* s;
- uv__cf_loop_state_t* state;
- QUEUE* q;
-
- if (loop->cf_state == NULL)
- return;
-
- if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
- abort();
-
- uv_thread_join(&loop->cf_thread);
- uv_sem_destroy(&loop->cf_sem);
- uv_mutex_destroy(&loop->cf_mutex);
-
- /* Free any remaining data */
- while (!QUEUE_EMPTY(&loop->cf_signals)) {
- q = QUEUE_HEAD(&loop->cf_signals);
- s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
- QUEUE_REMOVE(q);
- uv__free(s);
- }
-
- /* Destroy state */
- state = (uv__cf_loop_state_t*)loop->cf_state;
- uv_sem_destroy(&state->fsevent_sem);
- uv_mutex_destroy(&state->fsevent_mutex);
- pCFRelease(state->signal_source);
- uv__free(state);
- loop->cf_state = NULL;
-}
-
-
-/* Runs in CF thread. This is the CF loop's body */
-static void* uv__cf_loop_runner(void* arg) {
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
-
- loop = (uv_loop_t*)arg;
- state = (uv__cf_loop_state_t*)loop->cf_state;
- state->loop = pCFRunLoopGetCurrent();
-
- pCFRunLoopAddSource(state->loop,
- state->signal_source,
- *pkCFRunLoopDefaultMode);
-
- uv_sem_post(&loop->cf_sem);
-
- pCFRunLoopRun();
- pCFRunLoopRemoveSource(state->loop,
- state->signal_source,
- *pkCFRunLoopDefaultMode);
-
- return NULL;
-}
-
-
-/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
-static void uv__cf_loop_cb(void* arg) {
- uv_loop_t* loop;
- uv__cf_loop_state_t* state;
- QUEUE* item;
- QUEUE split_head;
- uv__cf_loop_signal_t* s;
-
- loop = (uv_loop_t*)arg;
- state = (uv__cf_loop_state_t*)loop->cf_state;
-
- uv_mutex_lock(&loop->cf_mutex);
- QUEUE_MOVE(&loop->cf_signals, &split_head);
- uv_mutex_unlock(&loop->cf_mutex);
-
- while (!QUEUE_EMPTY(&split_head)) {
- item = QUEUE_HEAD(&split_head);
- QUEUE_REMOVE(item);
-
- s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
-
- /* This was a termination signal */
- if (s->handle == NULL)
- pCFRunLoopStop(state->loop);
- else
- uv__fsevents_reschedule(s->handle, s->type);
-
- uv__free(s);
- }
-}
-
-
-/* Runs in UV loop to notify CF thread */
-int uv__cf_loop_signal(uv_loop_t* loop,
- uv_fs_event_t* handle,
- uv__cf_loop_signal_type_t type) {
- uv__cf_loop_signal_t* item;
- uv__cf_loop_state_t* state;
-
- item = (uv__cf_loop_signal_t*)uv__malloc(sizeof(*item));
- if (item == NULL)
- return UV_ENOMEM;
-
- item->handle = handle;
- item->type = type;
-
- uv_mutex_lock(&loop->cf_mutex);
- QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
- uv_mutex_unlock(&loop->cf_mutex);
-
- state = (uv__cf_loop_state_t*)loop->cf_state;
- assert(state != NULL);
- pCFRunLoopSourceSignal(state->signal_source);
- pCFRunLoopWakeUp(state->loop);
-
- return 0;
-}
-
-
-/* Runs in UV loop to initialize handle */
-int uv__fsevents_init(uv_fs_event_t* handle) {
- int err;
- uv__cf_loop_state_t* state;
-
- err = uv__fsevents_loop_init(handle->loop);
- if (err)
- return err;
-
- /* Get absolute path to file */
- handle->realpath = realpath(handle->path, NULL);
- if (handle->realpath == NULL)
- return UV__ERR(errno);
- handle->realpath_len = strlen(handle->realpath);
-
- /* Initialize event queue */
- QUEUE_INIT(&handle->cf_events);
- handle->cf_error = 0;
-
- /*
- * Events will occur in other thread.
- * Initialize callback for getting them back into event loop's thread
- */
- handle->cf_cb = (uv_async_t*)uv__malloc(sizeof(*handle->cf_cb));
- if (handle->cf_cb == NULL) {
- err = UV_ENOMEM;
- goto fail_cf_cb_malloc;
- }
-
- handle->cf_cb->data = handle;
- uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
- handle->cf_cb->flags |= UV_HANDLE_INTERNAL;
- uv_unref((uv_handle_t*) handle->cf_cb);
-
- err = uv_mutex_init(&handle->cf_mutex);
- if (err)
- goto fail_cf_mutex_init;
-
- /* Insert handle into the list */
- state = (uv__cf_loop_state_t*)handle->loop->cf_state;
- uv_mutex_lock(&state->fsevent_mutex);
- QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
- state->fsevent_handle_count++;
- state->fsevent_need_reschedule = 1;
- uv_mutex_unlock(&state->fsevent_mutex);
-
- /* Reschedule FSEventStream */
- assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
- if (err)
- goto fail_loop_signal;
-
- return 0;
-
-fail_loop_signal:
- uv_mutex_destroy(&handle->cf_mutex);
-
-fail_cf_mutex_init:
- uv__free(handle->cf_cb);
- handle->cf_cb = NULL;
-
-fail_cf_cb_malloc:
- uv__free(handle->realpath);
- handle->realpath = NULL;
- handle->realpath_len = 0;
-
- return err;
-}
-
-
-/* Runs in UV loop to de-initialize handle */
-int uv__fsevents_close(uv_fs_event_t* handle) {
- int err;
- uv__cf_loop_state_t* state;
-
- if (handle->cf_cb == NULL)
- return UV_EINVAL;
-
- /* Remove handle from the list */
- state = (uv__cf_loop_state_t*)handle->loop->cf_state;
- uv_mutex_lock(&state->fsevent_mutex);
- QUEUE_REMOVE(&handle->cf_member);
- state->fsevent_handle_count--;
- state->fsevent_need_reschedule = 1;
- uv_mutex_unlock(&state->fsevent_mutex);
-
- /* Reschedule FSEventStream */
- assert(handle != NULL);
- err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
- if (err)
- return UV__ERR(err);
-
- /* Wait for deinitialization */
- uv_sem_wait(&state->fsevent_sem);
-
- uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
- handle->cf_cb = NULL;
-
- /* Free data in queue */
- UV__FSEVENTS_PROCESS(handle, {
- /* NOP */
- });
-
- uv_mutex_destroy(&handle->cf_mutex);
- uv__free(handle->realpath);
- handle->realpath = NULL;
- handle->realpath_len = 0;
-
- return 0;
-}
-
-#endif /* TARGET_OS_IPHONE */
diff --git a/wpiutil/src/main/native/libuv/src/unix/getaddrinfo.cpp b/wpiutil/src/main/native/libuv/src/unix/getaddrinfo.cpp
deleted file mode 100644
index 9a26b45..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/getaddrinfo.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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.
- */
-
-/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
- * include any headers.
- */
-#ifndef _GNU_SOURCE
-# define _GNU_SOURCE
-#endif
-
-#include "uv.h"
-#include "internal.h"
-#include "idna.h"
-
-#include <errno.h>
-#include <stddef.h> /* NULL */
-#include <stdlib.h>
-#include <string.h>
-#include <net/if.h> /* if_indextoname() */
-
-/* EAI_* constants. */
-#include <netdb.h>
-
-
-int uv__getaddrinfo_translate_error(int sys_err) {
- switch (sys_err) {
- case 0: return 0;
-#if defined(EAI_ADDRFAMILY)
- case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
-#endif
-#if defined(EAI_AGAIN)
- case EAI_AGAIN: return UV_EAI_AGAIN;
-#endif
-#if defined(EAI_BADFLAGS)
- case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
-#endif
-#if defined(EAI_BADHINTS)
- case EAI_BADHINTS: return UV_EAI_BADHINTS;
-#endif
-#if defined(EAI_CANCELED)
- case EAI_CANCELED: return UV_EAI_CANCELED;
-#endif
-#if defined(EAI_FAIL)
- case EAI_FAIL: return UV_EAI_FAIL;
-#endif
-#if defined(EAI_FAMILY)
- case EAI_FAMILY: return UV_EAI_FAMILY;
-#endif
-#if defined(EAI_MEMORY)
- case EAI_MEMORY: return UV_EAI_MEMORY;
-#endif
-#if defined(EAI_NODATA)
- case EAI_NODATA: return UV_EAI_NODATA;
-#endif
-#if defined(EAI_NONAME)
-# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
- case EAI_NONAME: return UV_EAI_NONAME;
-# endif
-#endif
-#if defined(EAI_OVERFLOW)
- case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
-#endif
-#if defined(EAI_PROTOCOL)
- case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
-#endif
-#if defined(EAI_SERVICE)
- case EAI_SERVICE: return UV_EAI_SERVICE;
-#endif
-#if defined(EAI_SOCKTYPE)
- case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
-#endif
-#if defined(EAI_SYSTEM)
- case EAI_SYSTEM: return UV__ERR(errno);
-#endif
- }
- assert(!"unknown EAI_* error code");
- abort();
-#ifndef __SUNPRO_C
- return 0; /* Pacify compiler. */
-#endif
-}
-
-
-static void uv__getaddrinfo_work(struct uv__work* w) {
- uv_getaddrinfo_t* req;
- int err;
-
- req = container_of(w, uv_getaddrinfo_t, work_req);
- err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
- req->retcode = uv__getaddrinfo_translate_error(err);
-}
-
-
-static void uv__getaddrinfo_done(struct uv__work* w, int status) {
- uv_getaddrinfo_t* req;
-
- req = container_of(w, uv_getaddrinfo_t, work_req);
- uv__req_unregister(req->loop, req);
-
- /* See initialization in uv_getaddrinfo(). */
- if (req->hints)
- uv__free(req->hints);
- else if (req->service)
- uv__free(req->service);
- else if (req->hostname)
- uv__free(req->hostname);
- else
- assert(0);
-
- req->hints = NULL;
- req->service = NULL;
- req->hostname = NULL;
-
- if (status == UV_ECANCELED) {
- assert(req->retcode == 0);
- req->retcode = UV_EAI_CANCELED;
- }
-
- if (req->cb)
- req->cb(req, req->retcode, req->addrinfo);
-}
-
-
-int uv_getaddrinfo(uv_loop_t* loop,
- uv_getaddrinfo_t* req,
- uv_getaddrinfo_cb cb,
- const char* hostname,
- const char* service,
- const struct addrinfo* hints) {
- char hostname_ascii[256];
- size_t hostname_len;
- size_t service_len;
- size_t hints_len;
- size_t len;
- char* buf;
- long rc;
-
- if (req == NULL || (hostname == NULL && service == NULL))
- return UV_EINVAL;
-
- /* FIXME(bnoordhuis) IDNA does not seem to work z/OS,
- * probably because it uses EBCDIC rather than ASCII.
- */
-#ifdef __MVS__
- (void) &hostname_ascii;
-#else
- if (hostname != NULL) {
- rc = uv__idna_toascii(hostname,
- hostname + strlen(hostname),
- hostname_ascii,
- hostname_ascii + sizeof(hostname_ascii));
- if (rc < 0)
- return rc;
- hostname = hostname_ascii;
- }
-#endif
-
- hostname_len = hostname ? strlen(hostname) + 1 : 0;
- service_len = service ? strlen(service) + 1 : 0;
- hints_len = hints ? sizeof(*hints) : 0;
- buf = (char*)uv__malloc(hostname_len + service_len + hints_len);
-
- if (buf == NULL)
- return UV_ENOMEM;
-
- uv__req_init(loop, req, UV_GETADDRINFO);
- req->loop = loop;
- req->cb = cb;
- req->addrinfo = NULL;
- req->hints = NULL;
- req->service = NULL;
- req->hostname = NULL;
- req->retcode = 0;
-
- /* order matters, see uv_getaddrinfo_done() */
- len = 0;
-
- if (hints) {
- req->hints = (struct addrinfo*)memcpy(buf + len, hints, sizeof(*hints));
- len += sizeof(*hints);
- }
-
- if (service) {
- req->service = (char*)memcpy(buf + len, service, service_len);
- len += service_len;
- }
-
- if (hostname)
- req->hostname = (char*)memcpy(buf + len, hostname, hostname_len);
-
- if (cb) {
- uv__work_submit(loop,
- &req->work_req,
- UV__WORK_SLOW_IO,
- uv__getaddrinfo_work,
- uv__getaddrinfo_done);
- return 0;
- } else {
- uv__getaddrinfo_work(&req->work_req);
- uv__getaddrinfo_done(&req->work_req, 0);
- return req->retcode;
- }
-}
-
-
-void uv_freeaddrinfo(struct addrinfo* ai) {
- if (ai)
- freeaddrinfo(ai);
-}
-
-
-int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
- char ifname_buf[UV_IF_NAMESIZE];
- size_t len;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- if (if_indextoname(ifindex, ifname_buf) == NULL)
- return UV__ERR(errno);
-
- len = strnlen(ifname_buf, sizeof(ifname_buf));
-
- if (*size <= len) {
- *size = len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, ifname_buf, len);
- buffer[len] = '\0';
- *size = len;
-
- return 0;
-}
-
-int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
- return uv_if_indextoname(ifindex, buffer, size);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/getnameinfo.cpp b/wpiutil/src/main/native/libuv/src/unix/getnameinfo.cpp
deleted file mode 100644
index 991002a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/getnameinfo.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
-*
-* 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 <assert.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-static void uv__getnameinfo_work(struct uv__work* w) {
- uv_getnameinfo_t* req;
- int err;
- socklen_t salen;
-
- req = container_of(w, uv_getnameinfo_t, work_req);
-
- if (req->storage.ss_family == AF_INET)
- salen = sizeof(struct sockaddr_in);
- else if (req->storage.ss_family == AF_INET6)
- salen = sizeof(struct sockaddr_in6);
- else
- abort();
-
- err = getnameinfo((struct sockaddr*) &req->storage,
- salen,
- req->host,
- sizeof(req->host),
- req->service,
- sizeof(req->service),
- req->flags);
- req->retcode = uv__getaddrinfo_translate_error(err);
-}
-
-static void uv__getnameinfo_done(struct uv__work* w, int status) {
- uv_getnameinfo_t* req;
- char* host;
- char* service;
-
- req = container_of(w, uv_getnameinfo_t, work_req);
- uv__req_unregister(req->loop, req);
- host = service = NULL;
-
- if (status == UV_ECANCELED) {
- assert(req->retcode == 0);
- req->retcode = UV_EAI_CANCELED;
- } else if (req->retcode == 0) {
- host = req->host;
- service = req->service;
- }
-
- if (req->getnameinfo_cb)
- req->getnameinfo_cb(req, req->retcode, host, service);
-}
-
-/*
-* Entry point for getnameinfo
-* return 0 if a callback will be made
-* return error code if validation fails
-*/
-int uv_getnameinfo(uv_loop_t* loop,
- uv_getnameinfo_t* req,
- uv_getnameinfo_cb getnameinfo_cb,
- const struct sockaddr* addr,
- int flags) {
- if (req == NULL || addr == NULL)
- return UV_EINVAL;
-
- if (addr->sa_family == AF_INET) {
- memcpy(&req->storage,
- addr,
- sizeof(struct sockaddr_in));
- } else if (addr->sa_family == AF_INET6) {
- memcpy(&req->storage,
- addr,
- sizeof(struct sockaddr_in6));
- } else {
- return UV_EINVAL;
- }
-
- uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
-
- req->getnameinfo_cb = getnameinfo_cb;
- req->flags = flags;
- req->type = UV_GETNAMEINFO;
- req->loop = loop;
- req->retcode = 0;
-
- if (getnameinfo_cb) {
- uv__work_submit(loop,
- &req->work_req,
- UV__WORK_SLOW_IO,
- uv__getnameinfo_work,
- uv__getnameinfo_done);
- return 0;
- } else {
- uv__getnameinfo_work(&req->work_req);
- uv__getnameinfo_done(&req->work_req, 0);
- return req->retcode;
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/ibmi.cpp b/wpiutil/src/main/native/libuv/src/unix/ibmi.cpp
deleted file mode 100644
index 4b0be2d..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/ibmi.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <sys/time.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <utmp.h>
-#include <libgen.h>
-
-#include <sys/protosw.h>
-#include <procinfo.h>
-#include <sys/proc.h>
-#include <sys/procfs.h>
-
-#include <ctype.h>
-
-#include <sys/mntctl.h>
-#include <sys/vmount.h>
-#include <limits.h>
-#include <strings.h>
-#include <sys/vnode.h>
-
-#include <as400_protos.h>
-
-
-typedef struct {
- int bytes_available;
- int bytes_returned;
- char current_date_and_time[8];
- char system_name[8];
- char elapsed_time[6];
- char restricted_state_flag;
- char reserved;
- int percent_processing_unit_used;
- int jobs_in_system;
- int percent_permanent_addresses;
- int percent_temporary_addresses;
- int system_asp;
- int percent_system_asp_used;
- int total_auxiliary_storage;
- int current_unprotected_storage_used;
- int maximum_unprotected_storage_used;
- int percent_db_capability;
- int main_storage_size;
- int number_of_partitions;
- int partition_identifier;
- int reserved1;
- int current_processing_capacity;
- char processor_sharing_attribute;
- char reserved2[3];
- int number_of_processors;
- int active_jobs_in_system;
- int active_threads_in_system;
- int maximum_jobs_in_system;
- int percent_temporary_256mb_segments_used;
- int percent_temporary_4gb_segments_used;
- int percent_permanent_256mb_segments_used;
- int percent_permanent_4gb_segments_used;
- int percent_current_interactive_performance;
- int percent_uncapped_cpu_capacity_used;
- int percent_shared_processor_pool_used;
- long main_storage_size_long;
-} SSTS0200;
-
-
-static int get_ibmi_system_status(SSTS0200* rcvr) {
- /* rcvrlen is input parameter 2 to QWCRSSTS */
- unsigned int rcvrlen = sizeof(*rcvr);
-
- /* format is input parameter 3 to QWCRSSTS ("SSTS0200" in EBCDIC) */
- unsigned char format[] = {0xE2, 0xE2, 0xE3, 0xE2, 0xF0, 0xF2, 0xF0, 0xF0};
-
- /* reset_status is input parameter 4 to QWCRSSTS ("*NO " in EBCDIC) */
- unsigned char reset_status[] = {
- 0x5C, 0xD5, 0xD6, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
- };
-
- /* errcode is input parameter 5 to QWCRSSTS */
- struct _errcode {
- int bytes_provided;
- int bytes_available;
- char msgid[7];
- } errcode;
-
- /* qwcrssts_pointer is the 16-byte tagged system pointer to QWCRSSTS */
- ILEpointer __attribute__((aligned(16))) qwcrssts_pointer;
-
- /* qwcrssts_argv is the array of argument pointers to QWCRSSTS */
- void* qwcrssts_argv[6];
-
- /* Set the IBM i pointer to the QSYS/QWCRSSTS *PGM object */
- int rc = _RSLOBJ2(&qwcrssts_pointer, RSLOBJ_TS_PGM, "QWCRSSTS", "QSYS");
-
- if (rc != 0)
- return rc;
-
- /* initialize the QWCRSSTS returned info structure */
- memset(rcvr, 0, sizeof(*rcvr));
-
- /* initialize the QWCRSSTS error code structure */
- memset(&errcode, 0, sizeof(errcode));
- errcode.bytes_provided = sizeof(errcode);
-
- /* initialize the array of argument pointers for the QWCRSSTS API */
- qwcrssts_argv[0] = rcvr;
- qwcrssts_argv[1] = &rcvrlen;
- qwcrssts_argv[2] = &format;
- qwcrssts_argv[3] = &reset_status;
- qwcrssts_argv[4] = &errcode;
- qwcrssts_argv[5] = NULL;
-
- /* Call the IBM i QWCRSSTS API from PASE */
- rc = _PGMCALL(&qwcrssts_pointer, (void**)&qwcrssts_argv, 0);
-
- return rc;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- SSTS0200 rcvr;
-
- if (get_ibmi_system_status(&rcvr))
- return 0;
-
- /* The amount of main storage, in kilobytes, in the system. */
- uint64_t main_storage_size = rcvr.main_storage_size;
-
- /* The current amount of storage in use for temporary objects.
- * in millions (M) of bytes.
- */
- uint64_t current_unprotected_storage_used =
- rcvr.current_unprotected_storage_used * 1024ULL;
-
- uint64_t free_storage_size =
- (main_storage_size - current_unprotected_storage_used) * 1024ULL;
-
- return free_storage_size < 0 ? 0 : free_storage_size;
-}
-
-
-uint64_t uv_get_total_memory(void) {
- SSTS0200 rcvr;
-
- if (get_ibmi_system_status(&rcvr))
- return 0;
-
- return (uint64_t)rcvr.main_storage_size * 1024ULL;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-void uv_loadavg(double avg[3]) {
- SSTS0200 rcvr;
-
- if (get_ibmi_system_status(&rcvr)) {
- avg[0] = avg[1] = avg[2] = 0;
- return;
- }
-
- /* The average (in tenths) of the elapsed time during which the processing
- * units were in use. For example, a value of 411 in binary would be 41.1%.
- * This percentage could be greater than 100% for an uncapped partition.
- */
- double processing_unit_used_percent =
- rcvr.percent_processing_unit_used / 1000.0;
-
- avg[0] = avg[1] = avg[2] = processing_unit_used_percent;
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- *rss = 0;
- return 0;
-}
-
-
-int uv_uptime(double* uptime) {
- return UV_ENOSYS;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int numcpus, idx = 0;
- uv_cpu_info_t* cpu_info;
-
- *cpu_infos = NULL;
- *count = 0;
-
- numcpus = sysconf(_SC_NPROCESSORS_ONLN);
-
- *cpu_infos = (uv_cpu_info_t*)uv__malloc(numcpus * sizeof(uv_cpu_info_t));
- if (!*cpu_infos) {
- return UV_ENOMEM;
- }
-
- cpu_info = *cpu_infos;
- for (idx = 0; idx < numcpus; idx++) {
- cpu_info->speed = 0;
- cpu_info->model = uv__strdup("unknown");
- cpu_info->cpu_times.user = 0;
- cpu_info->cpu_times.sys = 0;
- cpu_info->cpu_times.idle = 0;
- cpu_info->cpu_times.irq = 0;
- cpu_info->cpu_times.nice = 0;
- cpu_info++;
- }
- *count = numcpus;
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/internal.h b/wpiutil/src/main/native/libuv/src/unix/internal.h
deleted file mode 100644
index 13ca2e6..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/internal.h
+++ /dev/null
@@ -1,329 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_UNIX_INTERNAL_H_
-#define UV_UNIX_INTERNAL_H_
-
-#include "uv-common.h"
-
-#include <assert.h>
-#include <limits.h> /* _POSIX_PATH_MAX, PATH_MAX */
-#include <stdlib.h> /* abort */
-#include <string.h> /* strrchr */
-#include <fcntl.h> /* O_CLOEXEC, may be */
-#include <stdio.h>
-#include <errno.h>
-
-#if defined(__STRICT_ANSI__)
-# define inline __inline
-#endif
-
-#if defined(__linux__)
-# include "linux-syscalls.h"
-#endif /* __linux__ */
-
-#if defined(__MVS__)
-# include "os390-syscalls.h"
-#endif /* __MVS__ */
-
-#if defined(__sun)
-# include <sys/port.h>
-# include <port.h>
-#endif /* __sun */
-
-#if defined(_AIX)
-# define reqevents events
-# define rtnevents revents
-# include <sys/poll.h>
-#else
-# include <poll.h>
-#endif /* _AIX */
-
-#if defined(__APPLE__) && !TARGET_OS_IPHONE
-# include <AvailabilityMacros.h>
-#endif
-
-#if defined(_POSIX_PATH_MAX)
-# define UV__PATH_MAX _POSIX_PATH_MAX
-#elif defined(PATH_MAX)
-# define UV__PATH_MAX PATH_MAX
-#else
-# define UV__PATH_MAX 8192
-#endif
-
-#if defined(__ANDROID__)
-int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
-# ifdef pthread_sigmask
-# undef pthread_sigmask
-# endif
-# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
-#endif
-
-#define ACCESS_ONCE(type, var) \
- (*(volatile type*) &(var))
-
-#define ROUND_UP(a, b) \
- ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
-
-#define UNREACHABLE() \
- do { \
- assert(0 && "unreachable code"); \
- abort(); \
- } \
- while (0)
-
-#define SAVE_ERRNO(block) \
- do { \
- int _saved_errno = errno; \
- do { block; } while (0); \
- errno = _saved_errno; \
- } \
- while (0)
-
-/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
- * define __GNUC__. They are here to convey to you, dear reader, that these
- * macros are enabled when compiling with clang or icc.
- */
-#if defined(__clang__) || \
- defined(__GNUC__) || \
- defined(__INTEL_COMPILER)
-# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
-# define UV_UNUSED(declaration) __attribute__((unused)) declaration
-#else
-# define UV_DESTRUCTOR(declaration) declaration
-# define UV_UNUSED(declaration) declaration
-#endif
-
-/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */
-#ifdef POLLRDHUP
-# define UV__POLLRDHUP POLLRDHUP
-#else
-# define UV__POLLRDHUP 0x2000
-#endif
-
-#ifdef POLLPRI
-# define UV__POLLPRI POLLPRI
-#else
-# define UV__POLLPRI 0
-#endif
-
-#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
-/*
- * It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
- * Try using fixed value const and give up, if it doesn't work
- */
-# define O_CLOEXEC 0x00100000
-#endif
-
-typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
-
-/* loop flags */
-enum {
- UV_LOOP_BLOCK_SIGPROF = 1
-};
-
-/* flags of excluding ifaddr */
-enum {
- UV__EXCLUDE_IFPHYS,
- UV__EXCLUDE_IFADDR
-};
-
-typedef enum {
- UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
- UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
-} uv_clocktype_t;
-
-struct uv__stream_queued_fds_s {
- unsigned int size;
- unsigned int offset;
- int fds[1];
-};
-
-
-#if defined(_AIX) || \
- defined(__APPLE__) || \
- defined(__DragonFly__) || \
- defined(__FreeBSD__) || \
- defined(__FreeBSD_kernel__) || \
- defined(__linux__) || \
- defined(__OpenBSD__) || \
- defined(__NetBSD__)
-#define uv__cloexec uv__cloexec_ioctl
-#define uv__nonblock uv__nonblock_ioctl
-#define UV__NONBLOCK_IS_IOCTL
-#else
-#define uv__cloexec uv__cloexec_fcntl
-#define uv__nonblock uv__nonblock_fcntl
-#define UV__NONBLOCK_IS_FCNTL
-#endif
-
-/* On Linux, uv__nonblock_fcntl() and uv__nonblock_ioctl() do not commute
- * when O_NDELAY is not equal to O_NONBLOCK. Case in point: linux/sparc32
- * and linux/sparc64, where O_NDELAY is O_NONBLOCK + another bit.
- *
- * Libuv uses uv__nonblock_fcntl() directly sometimes so ensure that it
- * commutes with uv__nonblock().
- */
-#if defined(__linux__) && O_NDELAY != O_NONBLOCK
-#undef uv__nonblock
-#define uv__nonblock uv__nonblock_fcntl
-#undef UV__NONBLOCK_IS_IOCTL
-#define UV__NONBLOCK_IS_FCNTL
-#endif
-
-/* core */
-int uv__cloexec_ioctl(int fd, int set);
-int uv__cloexec_fcntl(int fd, int set);
-int uv__nonblock_ioctl(int fd, int set);
-int uv__nonblock_fcntl(int fd, int set);
-int uv__close(int fd); /* preserves errno */
-int uv__close_nocheckstdio(int fd);
-int uv__close_nocancel(int fd);
-int uv__socket(int domain, int type, int protocol);
-ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
-void uv__make_close_pending(uv_handle_t* handle);
-int uv__getiovmax(void);
-
-void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
-void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
-void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
-void uv__io_close(uv_loop_t* loop, uv__io_t* w);
-void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
-int uv__io_active(const uv__io_t* w, unsigned int events);
-int uv__io_check_fd(uv_loop_t* loop, int fd);
-void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
-int uv__io_fork(uv_loop_t* loop);
-int uv__fd_exists(uv_loop_t* loop, int fd);
-
-/* async */
-void uv__async_stop(uv_loop_t* loop);
-int uv__async_fork(uv_loop_t* loop);
-
-
-/* loop */
-void uv__run_idle(uv_loop_t* loop);
-void uv__run_check(uv_loop_t* loop);
-void uv__run_prepare(uv_loop_t* loop);
-
-/* stream */
-void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
- uv_handle_type type);
-int uv__stream_open(uv_stream_t*, int fd, int flags);
-void uv__stream_destroy(uv_stream_t* stream);
-#if defined(__APPLE__)
-int uv__stream_try_select(uv_stream_t* stream, int* fd);
-#endif /* defined(__APPLE__) */
-void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
-int uv__accept(int sockfd);
-int uv__dup2_cloexec(int oldfd, int newfd);
-int uv__open_cloexec(const char* path, int flags);
-
-/* tcp */
-int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
-int uv__tcp_nodelay(int fd, int on);
-int uv__tcp_keepalive(int fd, int on, unsigned int delay);
-
-/* pipe */
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
-
-/* signal */
-void uv__signal_close(uv_signal_t* handle);
-void uv__signal_global_once_init(void);
-void uv__signal_loop_cleanup(uv_loop_t* loop);
-int uv__signal_loop_fork(uv_loop_t* loop);
-
-/* platform specific */
-uint64_t uv__hrtime(uv_clocktype_t type);
-int uv__kqueue_init(uv_loop_t* loop);
-int uv__platform_loop_init(uv_loop_t* loop);
-void uv__platform_loop_delete(uv_loop_t* loop);
-void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
-
-/* various */
-void uv__async_close(uv_async_t* handle);
-void uv__check_close(uv_check_t* handle);
-void uv__fs_event_close(uv_fs_event_t* handle);
-void uv__idle_close(uv_idle_t* handle);
-void uv__pipe_close(uv_pipe_t* handle);
-void uv__poll_close(uv_poll_t* handle);
-void uv__prepare_close(uv_prepare_t* handle);
-void uv__process_close(uv_process_t* handle);
-void uv__stream_close(uv_stream_t* handle);
-void uv__tcp_close(uv_tcp_t* handle);
-void uv__udp_close(uv_udp_t* handle);
-void uv__udp_finish_close(uv_udp_t* handle);
-uv_handle_type uv__handle_type(int fd);
-FILE* uv__open_file(const char* path);
-int uv__getpwuid_r(uv_passwd_t* pwd);
-
-
-#if defined(__APPLE__)
-int uv___stream_fd(const uv_stream_t* handle);
-#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
-#else
-#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
-#endif /* defined(__APPLE__) */
-
-#ifdef UV__O_NONBLOCK
-# define UV__F_NONBLOCK UV__O_NONBLOCK
-#else
-# define UV__F_NONBLOCK 1
-#endif
-
-int uv__make_socketpair(int fds[2], int flags);
-int uv__make_pipe(int fds[2], int flags);
-
-#if defined(__APPLE__)
-
-int uv__fsevents_init(uv_fs_event_t* handle);
-int uv__fsevents_close(uv_fs_event_t* handle);
-void uv__fsevents_loop_delete(uv_loop_t* loop);
-
-#endif /* defined(__APPLE__) */
-
-UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
- /* Use a fast time source if available. We only need millisecond precision.
- */
- loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
-}
-
-UV_UNUSED(static const char* uv__basename_r(const char* path)) {
- const char* s;
-
- s = strrchr(path, '/');
- if (s == NULL)
- return (char*) path;
-
- return s + 1;
-}
-
-#if defined(__linux__)
-int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
-#endif
-
-typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
-
-int uv__getsockpeername(const uv_handle_t* handle,
- uv__peersockfunc func,
- struct sockaddr* name,
- int* namelen);
-
-#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/unix/kqueue.cpp b/wpiutil/src/main/native/libuv/src/unix/kqueue.cpp
deleted file mode 100644
index 4c4268b..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/kqueue.cpp
+++ /dev/null
@@ -1,536 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#include <sys/sysctl.h>
-#include <sys/types.h>
-#include <sys/event.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-
-/*
- * Required on
- * - Until at least FreeBSD 11.0
- * - Older versions of Mac OS X
- *
- * http://www.boost.org/doc/libs/1_61_0/boost/asio/detail/kqueue_reactor.hpp
- */
-#ifndef EV_OOBAND
-#define EV_OOBAND EV_FLAG1
-#endif
-
-static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
-
-
-int uv__kqueue_init(uv_loop_t* loop) {
- loop->backend_fd = kqueue();
- if (loop->backend_fd == -1)
- return UV__ERR(errno);
-
- uv__cloexec(loop->backend_fd, 1);
-
- return 0;
-}
-
-
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
-static int uv__has_forked_with_cfrunloop;
-#endif
-
-int uv__io_fork(uv_loop_t* loop) {
- int err;
- loop->backend_fd = -1;
- err = uv__kqueue_init(loop);
- if (err)
- return err;
-
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
- if (loop->cf_state != NULL) {
- /* We cannot start another CFRunloop and/or thread in the child
- process; CF aborts if you try or if you try to touch the thread
- at all to kill it. So the best we can do is ignore it from now
- on. This means we can't watch directories in the same way
- anymore (like other BSDs). It also means we cannot properly
- clean up the allocated resources; calling
- uv__fsevents_loop_delete from uv_loop_close will crash the
- process. So we sidestep the issue by pretending like we never
- started it in the first place.
- */
- uv__has_forked_with_cfrunloop = 1;
- uv__free(loop->cf_state);
- loop->cf_state = NULL;
- }
-#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
- return err;
-}
-
-
-int uv__io_check_fd(uv_loop_t* loop, int fd) {
- struct kevent ev;
- int rc;
-
- rc = 0;
- EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
- if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
- rc = UV__ERR(errno);
-
- EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
- if (rc == 0)
- if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
- abort();
-
- return rc;
-}
-
-
-void uv__io_poll(uv_loop_t* loop, int timeout) {
- struct kevent events[1024];
- struct kevent* ev;
- struct timespec spec;
- unsigned int nevents;
- unsigned int revents;
- QUEUE* q;
- uv__io_t* w;
- sigset_t* pset;
- sigset_t set;
- uint64_t base;
- uint64_t diff;
- int have_signals;
- int filter;
- int fflags;
- int count;
- int nfds;
- int fd;
- int op;
- int i;
-
- if (loop->nfds == 0) {
- assert(QUEUE_EMPTY(&loop->watcher_queue));
- return;
- }
-
- nevents = 0;
-
- while (!QUEUE_EMPTY(&loop->watcher_queue)) {
- q = QUEUE_HEAD(&loop->watcher_queue);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
-
- w = QUEUE_DATA(q, uv__io_t, watcher_queue);
- assert(w->pevents != 0);
- assert(w->fd >= 0);
- assert(w->fd < (int) loop->nwatchers);
-
- if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
- filter = EVFILT_READ;
- fflags = 0;
- op = EV_ADD;
-
- if (w->cb == uv__fs_event) {
- filter = EVFILT_VNODE;
- fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
- | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
- op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
- }
-
- EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
-
- if (++nevents == ARRAY_SIZE(events)) {
- if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
- abort();
- nevents = 0;
- }
- }
-
- if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
- EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
-
- if (++nevents == ARRAY_SIZE(events)) {
- if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
- abort();
- nevents = 0;
- }
- }
-
- if ((w->events & UV__POLLPRI) == 0 && (w->pevents & UV__POLLPRI) != 0) {
- EV_SET(events + nevents, w->fd, EV_OOBAND, EV_ADD, 0, 0, 0);
-
- if (++nevents == ARRAY_SIZE(events)) {
- if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
- abort();
- nevents = 0;
- }
- }
-
- w->events = w->pevents;
- }
-
- pset = NULL;
- if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
- pset = &set;
- sigemptyset(pset);
- sigaddset(pset, SIGPROF);
- }
-
- assert(timeout >= -1);
- base = loop->time;
- count = 48; /* Benchmarks suggest this gives the best throughput. */
-
- for (;; nevents = 0) {
- if (timeout != -1) {
- spec.tv_sec = timeout / 1000;
- spec.tv_nsec = (timeout % 1000) * 1000000;
- }
-
- if (pset != NULL)
- pthread_sigmask(SIG_BLOCK, pset, NULL);
-
- nfds = kevent(loop->backend_fd,
- events,
- nevents,
- events,
- ARRAY_SIZE(events),
- timeout == -1 ? NULL : &spec);
-
- if (pset != NULL)
- pthread_sigmask(SIG_UNBLOCK, pset, NULL);
-
- /* Update loop->time unconditionally. It's tempting to skip the update when
- * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
- * operating system didn't reschedule our process while in the syscall.
- */
- SAVE_ERRNO(uv__update_time(loop));
-
- if (nfds == 0) {
- assert(timeout != -1);
- return;
- }
-
- if (nfds == -1) {
- if (errno != EINTR)
- abort();
-
- if (timeout == 0)
- return;
-
- if (timeout == -1)
- continue;
-
- /* Interrupted by a signal. Update timeout and poll again. */
- goto update_timeout;
- }
-
- have_signals = 0;
- nevents = 0;
-
- assert(loop->watchers != NULL);
- loop->watchers[loop->nwatchers] = (uv__io_t*) events;
- loop->watchers[loop->nwatchers + 1] = (uv__io_t*) (uintptr_t) nfds;
- for (i = 0; i < nfds; i++) {
- ev = events + i;
- fd = ev->ident;
- /* Skip invalidated events, see uv__platform_invalidate_fd */
- if (fd == -1)
- continue;
- w = (uv__io_t*)loop->watchers[fd];
-
- if (w == NULL) {
- /* File descriptor that we've stopped watching, disarm it.
- * TODO: batch up. */
- struct kevent events[1];
-
- EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
- if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
- if (errno != EBADF && errno != ENOENT)
- abort();
-
- continue;
- }
-
- if (ev->filter == EVFILT_VNODE) {
- assert(w->events == POLLIN);
- assert(w->pevents == POLLIN);
- w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
- nevents++;
- continue;
- }
-
- revents = 0;
-
- if (ev->filter == EVFILT_READ) {
- if (w->pevents & POLLIN) {
- revents |= POLLIN;
- w->rcount = ev->data;
- } else {
- /* TODO batch up */
- struct kevent events[1];
- EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
- if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
- if (errno != ENOENT)
- abort();
- }
- }
-
- if (ev->filter == EV_OOBAND) {
- if (w->pevents & UV__POLLPRI) {
- revents |= UV__POLLPRI;
- w->rcount = ev->data;
- } else {
- /* TODO batch up */
- struct kevent events[1];
- EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
- if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
- if (errno != ENOENT)
- abort();
- }
- }
-
- if (ev->filter == EVFILT_WRITE) {
- if (w->pevents & POLLOUT) {
- revents |= POLLOUT;
- w->wcount = ev->data;
- } else {
- /* TODO batch up */
- struct kevent events[1];
- EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
- if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
- if (errno != ENOENT)
- abort();
- }
- }
-
- if (ev->flags & EV_ERROR)
- revents |= POLLERR;
-
- if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
- revents |= UV__POLLRDHUP;
-
- if (revents == 0)
- continue;
-
- /* Run signal watchers last. This also affects child process watchers
- * because those are implemented in terms of signal watchers.
- */
- if (w == &loop->signal_io_watcher)
- have_signals = 1;
- else
- w->cb(loop, w, revents);
-
- nevents++;
- }
-
- if (have_signals != 0)
- loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
-
- loop->watchers[loop->nwatchers] = NULL;
- loop->watchers[loop->nwatchers + 1] = NULL;
-
- if (have_signals != 0)
- return; /* Event loop should cycle now so don't poll again. */
-
- if (nevents != 0) {
- if (nfds == ARRAY_SIZE(events) && --count != 0) {
- /* Poll for more events but don't block this time. */
- timeout = 0;
- continue;
- }
- return;
- }
-
- if (timeout == 0)
- return;
-
- if (timeout == -1)
- continue;
-
-update_timeout:
- assert(timeout > 0);
-
- diff = loop->time - base;
- if (diff >= (uint64_t) timeout)
- return;
-
- timeout -= diff;
- }
-}
-
-
-void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
- struct kevent* events;
- uintptr_t i;
- uintptr_t nfds;
-
- assert(loop->watchers != NULL);
- assert(fd >= 0);
-
- events = (struct kevent*) loop->watchers[loop->nwatchers];
- nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
- if (events == NULL)
- return;
-
- /* Invalidate events with same file descriptor */
- for (i = 0; i < nfds; i++)
- if ((int) events[i].ident == fd)
- events[i].ident = -1;
-}
-
-
-static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
- uv_fs_event_t* handle;
- struct kevent ev;
- int events;
- const char* path;
-#if defined(F_GETPATH)
- /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
- char pathbuf[MAXPATHLEN];
-#endif
-
- handle = container_of(w, uv_fs_event_t, event_watcher);
-
- if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
- events = UV_CHANGE;
- else
- events = UV_RENAME;
-
- path = NULL;
-#if defined(F_GETPATH)
- /* Also works when the file has been unlinked from the file system. Passing
- * in the path when the file has been deleted is arguably a little strange
- * but it's consistent with what the inotify backend does.
- */
- if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
- path = uv__basename_r(pathbuf);
-#endif
- handle->cb(handle, path, events, 0);
-
- if (handle->event_watcher.fd == -1)
- return;
-
- /* Watcher operates in one-shot mode, re-arm it. */
- fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
- | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
-
- EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
-
- if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
- abort();
-}
-
-
-int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
- uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
- return 0;
-}
-
-
-int uv_fs_event_start(uv_fs_event_t* handle,
- uv_fs_event_cb cb,
- const char* path,
- unsigned int flags) {
- int fd;
-
- if (uv__is_active(handle))
- return UV_EINVAL;
-
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
- /* Nullify field to perform checks later */
- handle->cf_cb = NULL;
- handle->realpath = NULL;
- handle->realpath_len = 0;
- handle->cf_flags = flags;
-
- if (!uv__has_forked_with_cfrunloop) {
- int r;
- /* The fallback fd is not used */
- handle->event_watcher.fd = -1;
- handle->path = uv__strdup(path);
- if (handle->path == NULL)
- return UV_ENOMEM;
- handle->cb = cb;
- r = uv__fsevents_init(handle);
- if (r == 0) {
- uv__handle_start(handle);
- } else {
- uv__free(handle->path);
- handle->path = NULL;
- }
- return r;
- }
-#endif /* #if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 */
-
- /* TODO open asynchronously - but how do we report back errors? */
- fd = open(path, O_RDONLY);
- if (fd == -1)
- return UV__ERR(errno);
-
- handle->path = uv__strdup(path);
- if (handle->path == NULL) {
- uv__close_nocheckstdio(fd);
- return UV_ENOMEM;
- }
-
- handle->cb = cb;
- uv__handle_start(handle);
- uv__io_init(&handle->event_watcher, uv__fs_event, fd);
- uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
-
- return 0;
-}
-
-
-int uv_fs_event_stop(uv_fs_event_t* handle) {
- int r;
- r = 0;
-
- if (!uv__is_active(handle))
- return 0;
-
- uv__handle_stop(handle);
-
-#if defined(__APPLE__) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
- if (!uv__has_forked_with_cfrunloop)
- r = uv__fsevents_close(handle);
-#endif
-
- if (handle->event_watcher.fd != -1) {
- uv__io_close(handle->loop, &handle->event_watcher);
- uv__close(handle->event_watcher.fd);
- handle->event_watcher.fd = -1;
- }
-
- uv__free(handle->path);
- handle->path = NULL;
-
- return r;
-}
-
-
-void uv__fs_event_close(uv_fs_event_t* handle) {
- uv_fs_event_stop(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/linux-core.cpp b/wpiutil/src/main/native/libuv/src/unix/linux-core.cpp
deleted file mode 100644
index 8a26782..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/linux-core.cpp
+++ /dev/null
@@ -1,1062 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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.
- */
-
-/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
- * EPOLL* counterparts. We use the POLL* variants in this file because that
- * is what libuv uses elsewhere.
- */
-
-#include "uv.h"
-#include "internal.h"
-
-#include <inttypes.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <net/if.h>
-#include <sys/epoll.h>
-#include <sys/param.h>
-#include <sys/prctl.h>
-#include <sys/sysinfo.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-
-#define HAVE_IFADDRS_H 1
-
-#ifdef __UCLIBC__
-# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
-# undef HAVE_IFADDRS_H
-# endif
-#endif
-
-#ifdef HAVE_IFADDRS_H
-# if defined(__ANDROID__)
-# include "uv/android-ifaddrs.h"
-# else
-# include <ifaddrs.h>
-# endif
-# include <sys/socket.h>
-# include <net/ethernet.h>
-# include <netpacket/packet.h>
-#endif /* HAVE_IFADDRS_H */
-
-/* Available from 2.6.32 onwards. */
-#ifndef CLOCK_MONOTONIC_COARSE
-# define CLOCK_MONOTONIC_COARSE 6
-#endif
-
-#ifdef __FRC_ROBORIO__
-#include "wpi/timestamp.h"
-#endif
-
-/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
- * include that file because it conflicts with <time.h>. We'll just have to
- * define it ourselves.
- */
-#ifndef CLOCK_BOOTTIME
-# define CLOCK_BOOTTIME 7
-#endif
-
-static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
-static int read_times(FILE* statfile_fp,
- unsigned int numcpus,
- uv_cpu_info_t* ci);
-static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
-static uint64_t read_cpufreq(unsigned int cpunum);
-
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- int fd;
-
- /* It was reported that EPOLL_CLOEXEC is not defined on Android API < 21,
- * a.k.a. Lollipop. Since EPOLL_CLOEXEC is an alias for O_CLOEXEC on all
- * architectures, we just use that instead.
- */
- fd = epoll_create1(O_CLOEXEC);
-
- /* epoll_create1() can fail either because it's not implemented (old kernel)
- * or because it doesn't understand the O_CLOEXEC flag.
- */
- if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
- fd = epoll_create(256);
-
- if (fd != -1)
- uv__cloexec(fd, 1);
- }
-
- loop->backend_fd = fd;
- loop->inotify_fd = -1;
- loop->inotify_watchers = NULL;
-
- if (fd == -1)
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-int uv__io_fork(uv_loop_t* loop) {
- int err;
- void* old_watchers;
-
- old_watchers = loop->inotify_watchers;
-
- uv__close(loop->backend_fd);
- loop->backend_fd = -1;
- uv__platform_loop_delete(loop);
-
- err = uv__platform_loop_init(loop);
- if (err)
- return err;
-
- return uv__inotify_fork(loop, old_watchers);
-}
-
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
- if (loop->inotify_fd == -1) return;
- uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
- uv__close(loop->inotify_fd);
- loop->inotify_fd = -1;
-}
-
-
-void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
- struct epoll_event* events;
- struct epoll_event dummy;
- uintptr_t i;
- uintptr_t nfds;
-
- assert(loop->watchers != NULL);
- assert(fd >= 0);
-
- events = (struct epoll_event*) loop->watchers[loop->nwatchers];
- nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
- if (events != NULL)
- /* Invalidate events with same file descriptor */
- for (i = 0; i < nfds; i++)
- if (events[i].data.fd == fd)
- events[i].data.fd = -1;
-
- /* Remove the file descriptor from the epoll.
- * This avoids a problem where the same file description remains open
- * in another process, causing repeated junk epoll events.
- *
- * We pass in a dummy epoll_event, to work around a bug in old kernels.
- */
- if (loop->backend_fd >= 0) {
- /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
- * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
- */
- memset(&dummy, 0, sizeof(dummy));
- epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &dummy);
- }
-}
-
-
-int uv__io_check_fd(uv_loop_t* loop, int fd) {
- struct epoll_event e;
- int rc;
-
- memset(&e, 0, sizeof(e));
- e.events = POLLIN;
- e.data.fd = -1;
-
- rc = 0;
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_ADD, fd, &e))
- if (errno != EEXIST)
- rc = UV__ERR(errno);
-
- if (rc == 0)
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, &e))
- abort();
-
- return rc;
-}
-
-
-void uv__io_poll(uv_loop_t* loop, int timeout) {
- /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
- * effectively infinite on 32 bits architectures. To avoid blocking
- * indefinitely, we cap the timeout and poll again if necessary.
- *
- * Note that "30 minutes" is a simplification because it depends on
- * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
- * that being the largest value I have seen in the wild (and only once.)
- */
- static const int max_safe_timeout = 1789569;
- struct epoll_event events[1024];
- struct epoll_event* pe;
- struct epoll_event e;
- int real_timeout;
- QUEUE* q;
- uv__io_t* w;
- sigset_t sigset;
- sigset_t* psigset;
- uint64_t base;
- int have_signals;
- int nevents;
- int count;
- int nfds;
- int fd;
- int op;
- int i;
-
- if (loop->nfds == 0) {
- assert(QUEUE_EMPTY(&loop->watcher_queue));
- return;
- }
-
- memset(&e, 0, sizeof(e));
-
- while (!QUEUE_EMPTY(&loop->watcher_queue)) {
- q = QUEUE_HEAD(&loop->watcher_queue);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
-
- w = QUEUE_DATA(q, uv__io_t, watcher_queue);
- assert(w->pevents != 0);
- assert(w->fd >= 0);
- assert(w->fd < (int) loop->nwatchers);
-
- e.events = w->pevents;
- e.data.fd = w->fd;
-
- if (w->events == 0)
- op = EPOLL_CTL_ADD;
- else
- op = EPOLL_CTL_MOD;
-
- /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
- * events, skip the syscall and squelch the events after epoll_wait().
- */
- if (epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
- if (errno != EEXIST)
- abort();
-
- assert(op == EPOLL_CTL_ADD);
-
- /* We've reactivated a file descriptor that's been watched before. */
- if (epoll_ctl(loop->backend_fd, EPOLL_CTL_MOD, w->fd, &e))
- abort();
- }
-
- w->events = w->pevents;
- }
-
- psigset = NULL;
- if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
- sigemptyset(&sigset);
- sigaddset(&sigset, SIGPROF);
- psigset = &sigset;
- }
-
- assert(timeout >= -1);
- base = loop->time;
- count = 48; /* Benchmarks suggest this gives the best throughput. */
- real_timeout = timeout;
-
- for (;;) {
- /* See the comment for max_safe_timeout for an explanation of why
- * this is necessary. Executive summary: kernel bug workaround.
- */
- if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
- timeout = max_safe_timeout;
-
- nfds = epoll_pwait(loop->backend_fd,
- events,
- ARRAY_SIZE(events),
- timeout,
- psigset);
-
- /* Update loop->time unconditionally. It's tempting to skip the update when
- * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
- * operating system didn't reschedule our process while in the syscall.
- */
- SAVE_ERRNO(uv__update_time(loop));
-
- if (nfds == 0) {
- assert(timeout != -1);
-
- if (timeout == 0)
- return;
-
- /* We may have been inside the system call for longer than |timeout|
- * milliseconds so we need to update the timestamp to avoid drift.
- */
- goto update_timeout;
- }
-
- if (nfds == -1) {
- if (errno != EINTR)
- abort();
-
- if (timeout == -1)
- continue;
-
- if (timeout == 0)
- return;
-
- /* Interrupted by a signal. Update timeout and poll again. */
- goto update_timeout;
- }
-
- have_signals = 0;
- nevents = 0;
-
- assert(loop->watchers != NULL);
- loop->watchers[loop->nwatchers] = events;
- loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
- for (i = 0; i < nfds; i++) {
- pe = events + i;
- fd = pe->data.fd;
-
- /* Skip invalidated events, see uv__platform_invalidate_fd */
- if (fd == -1)
- continue;
-
- assert(fd >= 0);
- assert((unsigned) fd < loop->nwatchers);
-
- w = (uv__io_t*)loop->watchers[fd];
-
- if (w == NULL) {
- /* File descriptor that we've stopped watching, disarm it.
- *
- * Ignore all errors because we may be racing with another thread
- * when the file descriptor is closed.
- */
- epoll_ctl(loop->backend_fd, EPOLL_CTL_DEL, fd, pe);
- continue;
- }
-
- /* Give users only events they're interested in. Prevents spurious
- * callbacks when previous callback invocation in this loop has stopped
- * the current watcher. Also, filters out events that users has not
- * requested us to watch.
- */
- pe->events &= w->pevents | POLLERR | POLLHUP;
-
- /* Work around an epoll quirk where it sometimes reports just the
- * EPOLLERR or EPOLLHUP event. In order to force the event loop to
- * move forward, we merge in the read/write events that the watcher
- * is interested in; uv__read() and uv__write() will then deal with
- * the error or hangup in the usual fashion.
- *
- * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
- * reads the available data, calls uv_read_stop(), then sometime later
- * calls uv_read_start() again. By then, libuv has forgotten about the
- * hangup and the kernel won't report EPOLLIN again because there's
- * nothing left to read. If anything, libuv is to blame here. The
- * current hack is just a quick bandaid; to properly fix it, libuv
- * needs to remember the error/hangup event. We should get that for
- * free when we switch over to edge-triggered I/O.
- */
- if (pe->events == POLLERR || pe->events == POLLHUP)
- pe->events |=
- w->pevents & (POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
-
- if (pe->events != 0) {
- /* Run signal watchers last. This also affects child process watchers
- * because those are implemented in terms of signal watchers.
- */
- if (w == &loop->signal_io_watcher)
- have_signals = 1;
- else
- w->cb(loop, w, pe->events);
-
- nevents++;
- }
- }
-
- if (have_signals != 0)
- loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
-
- loop->watchers[loop->nwatchers] = NULL;
- loop->watchers[loop->nwatchers + 1] = NULL;
-
- if (have_signals != 0)
- return; /* Event loop should cycle now so don't poll again. */
-
- if (nevents != 0) {
- if (nfds == ARRAY_SIZE(events) && --count != 0) {
- /* Poll for more events but don't block this time. */
- timeout = 0;
- continue;
- }
- return;
- }
-
- if (timeout == 0)
- return;
-
- if (timeout == -1)
- continue;
-
-update_timeout:
- assert(timeout > 0);
-
- real_timeout -= (loop->time - base);
- if (real_timeout <= 0)
- return;
-
- timeout = real_timeout;
- }
-}
-
-
-uint64_t uv__hrtime(uv_clocktype_t type) {
-#ifdef __FRC_ROBORIO__
- return wpi::Now() * 1000u;
-#else
- static clock_t fast_clock_id = -1;
- struct timespec t;
- clock_t clock_id;
-
- /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
- * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
- * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
- * decide to make a costly system call.
- */
- /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
- * when it has microsecond granularity or better (unlikely).
- */
- if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
- if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
- t.tv_nsec <= 1 * 1000 * 1000) {
- fast_clock_id = CLOCK_MONOTONIC_COARSE;
- } else {
- fast_clock_id = CLOCK_MONOTONIC;
- }
- }
-
- clock_id = CLOCK_MONOTONIC;
- if (type == UV_CLOCK_FAST)
- clock_id = fast_clock_id;
-
- if (clock_gettime(clock_id, &t))
- return 0; /* Not really possible. */
-
- return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
-#endif
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- char buf[1024];
- const char* s;
- ssize_t n;
- long val;
- int fd;
- int i;
-
- do
- fd = open("/proc/self/stat", O_RDONLY);
- while (fd == -1 && errno == EINTR);
-
- if (fd == -1)
- return UV__ERR(errno);
-
- do
- n = read(fd, buf, sizeof(buf) - 1);
- while (n == -1 && errno == EINTR);
-
- uv__close(fd);
- if (n == -1)
- return UV__ERR(errno);
- buf[n] = '\0';
-
- s = strchr(buf, ' ');
- if (s == NULL)
- goto err;
-
- s += 1;
- if (*s != '(')
- goto err;
-
- s = strchr(s, ')');
- if (s == NULL)
- goto err;
-
- for (i = 1; i <= 22; i++) {
- s = strchr(s + 1, ' ');
- if (s == NULL)
- goto err;
- }
-
- errno = 0;
- val = strtol(s, NULL, 10);
- if (errno != 0)
- goto err;
- if (val < 0)
- goto err;
-
- *rss = val * getpagesize();
- return 0;
-
-err:
- return UV_EINVAL;
-}
-
-
-int uv_uptime(double* uptime) {
- static volatile int no_clock_boottime;
- struct timespec now;
- int r;
-
- /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
- * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
- * is suspended.
- */
- if (no_clock_boottime) {
- retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
- }
- else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
- no_clock_boottime = 1;
- goto retry;
- }
-
- if (r)
- return UV__ERR(errno);
-
- *uptime = now.tv_sec;
- return 0;
-}
-
-
-static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
- unsigned int num;
- char buf[1024];
-
- if (!fgets(buf, sizeof(buf), statfile_fp))
- return UV_EIO;
-
- num = 0;
- while (fgets(buf, sizeof(buf), statfile_fp)) {
- if (strncmp(buf, "cpu", 3))
- break;
- num++;
- }
-
- if (num == 0)
- return UV_EIO;
-
- *numcpus = num;
- return 0;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int numcpus;
- uv_cpu_info_t* ci;
- int err;
- FILE* statfile_fp;
-
- *cpu_infos = NULL;
- *count = 0;
-
- statfile_fp = uv__open_file("/proc/stat");
- if (statfile_fp == NULL)
- return UV__ERR(errno);
-
- err = uv__cpu_num(statfile_fp, &numcpus);
- if (err < 0)
- goto out;
-
- err = UV_ENOMEM;
- ci = (uv_cpu_info_t*)uv__calloc(numcpus, sizeof(*ci));
- if (ci == NULL)
- goto out;
-
- err = read_models(numcpus, ci);
- if (err == 0)
- err = read_times(statfile_fp, numcpus, ci);
-
- if (err) {
- uv_free_cpu_info(ci, numcpus);
- goto out;
- }
-
- /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
- * We don't check for errors here. Worst case, the field is left zero.
- */
- if (ci[0].speed == 0)
- read_speeds(numcpus, ci);
-
- *cpu_infos = ci;
- *count = numcpus;
- err = 0;
-
-out:
-
- if (fclose(statfile_fp))
- if (errno != EINTR && errno != EINPROGRESS)
- abort();
-
- return err;
-}
-
-
-static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
- unsigned int num;
-
- for (num = 0; num < numcpus; num++)
- ci[num].speed = read_cpufreq(num) / 1000;
-}
-
-
-/* Also reads the CPU frequency on x86. The other architectures only have
- * a BogoMIPS field, which may not be very accurate.
- *
- * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
- */
-static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
- static const char model_marker[] = "model name\t: ";
- static const char speed_marker[] = "cpu MHz\t\t: ";
- const char* inferred_model;
- unsigned int model_idx;
- unsigned int speed_idx;
- char buf[1024];
- char* model;
- FILE* fp;
-
- /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
- (void) &model_marker;
- (void) &speed_marker;
- (void) &speed_idx;
- (void) &model;
- (void) &buf;
- (void) &fp;
-
- model_idx = 0;
- speed_idx = 0;
-
-#if defined(__arm__) || \
- defined(__i386__) || \
- defined(__mips__) || \
- defined(__x86_64__)
- fp = uv__open_file("/proc/cpuinfo");
- if (fp == NULL)
- return UV__ERR(errno);
-
- while (fgets(buf, sizeof(buf), fp)) {
- if (model_idx < numcpus) {
- if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
- model = buf + sizeof(model_marker) - 1;
- model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
- if (model == NULL) {
- fclose(fp);
- return UV_ENOMEM;
- }
- ci[model_idx++].model = model;
- continue;
- }
- }
-#if defined(__arm__) || defined(__mips__)
- if (model_idx < numcpus) {
-#if defined(__arm__)
- /* Fallback for pre-3.8 kernels. */
- static const char model_marker[] = "Processor\t: ";
-#else /* defined(__mips__) */
- static const char model_marker[] = "cpu model\t\t: ";
-#endif
- if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
- model = buf + sizeof(model_marker) - 1;
- model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
- if (model == NULL) {
- fclose(fp);
- return UV_ENOMEM;
- }
- ci[model_idx++].model = model;
- continue;
- }
- }
-#else /* !__arm__ && !__mips__ */
- if (speed_idx < numcpus) {
- if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
- ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
- continue;
- }
- }
-#endif /* __arm__ || __mips__ */
- }
-
- fclose(fp);
-#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
-
- /* Now we want to make sure that all the models contain *something* because
- * it's not safe to leave them as null. Copy the last entry unless there
- * isn't one, in that case we simply put "unknown" into everything.
- */
- inferred_model = "unknown";
- if (model_idx > 0)
- inferred_model = ci[model_idx - 1].model;
-
- while (model_idx < numcpus) {
- model = uv__strndup(inferred_model, strlen(inferred_model));
- if (model == NULL)
- return UV_ENOMEM;
- ci[model_idx++].model = model;
- }
-
- return 0;
-}
-
-
-static int read_times(FILE* statfile_fp,
- unsigned int numcpus,
- uv_cpu_info_t* ci) {
- struct uv_cpu_times_s ts;
- uint64_t clock_ticks;
- uint64_t user;
- uint64_t nice;
- uint64_t sys;
- uint64_t idle;
- uint64_t dummy;
- uint64_t irq;
- uint64_t num;
- uint64_t len;
- char buf[1024];
-
- clock_ticks = sysconf(_SC_CLK_TCK);
- assert(clock_ticks != (uint64_t) -1);
- assert(clock_ticks != 0);
-
- rewind(statfile_fp);
-
- if (!fgets(buf, sizeof(buf), statfile_fp))
- abort();
-
- num = 0;
-
- while (fgets(buf, sizeof(buf), statfile_fp)) {
- if (num >= numcpus)
- break;
-
- if (strncmp(buf, "cpu", 3))
- break;
-
- /* skip "cpu<num> " marker */
- {
- unsigned int n;
- int r = sscanf(buf, "cpu%u ", &n);
- assert(r == 1);
- (void) r; /* silence build warning */
- for (len = sizeof("cpu0"); n /= 10; len++);
- }
-
- /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
- * guest, guest_nice but we're only interested in the first four + irq.
- *
- * Don't use %*s to skip fields or %ll to read straight into the uint64_t
- * fields, they're not allowed in C89 mode.
- */
- if (6 != sscanf(buf + len,
- "%" PRIu64 " %" PRIu64 " %" PRIu64
- "%" PRIu64 " %" PRIu64 " %" PRIu64,
- &user,
- &nice,
- &sys,
- &idle,
- &dummy,
- &irq))
- abort();
-
- ts.user = clock_ticks * user;
- ts.nice = clock_ticks * nice;
- ts.sys = clock_ticks * sys;
- ts.idle = clock_ticks * idle;
- ts.irq = clock_ticks * irq;
- ci[num++].cpu_times = ts;
- }
- assert(num == numcpus);
-
- return 0;
-}
-
-
-static uint64_t read_cpufreq(unsigned int cpunum) {
- uint64_t val;
- char buf[1024];
- FILE* fp;
-
- snprintf(buf,
- sizeof(buf),
- "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
- cpunum);
-
- fp = uv__open_file(buf);
- if (fp == NULL)
- return 0;
-
- if (fscanf(fp, "%" PRIu64, &val) != 1)
- val = 0;
-
- fclose(fp);
-
- return val;
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
-
-static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
- if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
- return 1;
- if (ent->ifa_addr == NULL)
- return 1;
- /*
- * On Linux getifaddrs returns information related to the raw underlying
- * devices. We're not interested in this information yet.
- */
- if (ent->ifa_addr->sa_family == PF_PACKET)
- return exclude_type;
- return !exclude_type;
-}
-
-int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
-#ifndef HAVE_IFADDRS_H
- *count = 0;
- *addresses = NULL;
- return UV_ENOSYS;
-#else
- struct ifaddrs *addrs, *ent;
- uv_interface_address_t* address;
- int i;
- struct sockaddr_ll *sll;
-
- *count = 0;
- *addresses = NULL;
-
- if (getifaddrs(&addrs))
- return UV__ERR(errno);
-
- /* Count the number of interfaces */
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
- continue;
-
- (*count)++;
- }
-
- if (*count == 0) {
- freeifaddrs(addrs);
- return 0;
- }
-
- /* Make sure the memory is initiallized to zero using calloc() */
- *addresses = (uv_interface_address_t*)uv__calloc(*count, sizeof(**addresses));
- if (!(*addresses)) {
- freeifaddrs(addrs);
- return UV_ENOMEM;
- }
-
- address = *addresses;
-
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
- continue;
-
- address->name = uv__strdup(ent->ifa_name);
-
- if (ent->ifa_addr->sa_family == AF_INET6) {
- address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
- } else {
- address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
- }
-
- if (ent->ifa_netmask->sa_family == AF_INET6) {
- address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
- } else {
- address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
- }
-
- address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
-
- address++;
- }
-
- /* Fill in physical addresses for each interface */
- for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
- if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
- continue;
-
- address = *addresses;
-
- for (i = 0; i < (*count); i++) {
- size_t namelen = strlen(ent->ifa_name);
- /* Alias interface share the same physical address */
- if (strncmp(address->name, ent->ifa_name, namelen) == 0 &&
- (address->name[namelen] == 0 || address->name[namelen] == ':')) {
- sll = (struct sockaddr_ll*)ent->ifa_addr;
- memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
- }
- address++;
- }
- }
-
- freeifaddrs(addrs);
-
- return 0;
-#endif
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(addresses[i].name);
- }
-
- uv__free(addresses);
-}
-
-
-void uv__set_process_title(const char* title) {
-#if defined(PR_SET_NAME)
- prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
-#endif
-}
-
-
-static uint64_t uv__read_proc_meminfo(const char* what) {
- uint64_t rc;
- ssize_t n;
- char* p;
- int fd;
- char buf[4096]; /* Large enough to hold all of /proc/meminfo. */
-
- rc = 0;
- fd = uv__open_cloexec("/proc/meminfo", O_RDONLY);
-
- if (fd == -1)
- return 0;
-
- n = read(fd, buf, sizeof(buf) - 1);
-
- if (n <= 0)
- goto out;
-
- buf[n] = '\0';
- p = strstr(buf, what);
-
- if (p == NULL)
- goto out;
-
- p += strlen(what);
-
- if (1 != sscanf(p, "%" PRIu64 " kB", &rc))
- goto out;
-
- rc *= 1024;
-
-out:
-
- if (uv__close_nocheckstdio(fd))
- abort();
-
- return rc;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- struct sysinfo info;
- uint64_t rc;
-
- rc = uv__read_proc_meminfo("MemFree:");
-
- if (rc != 0)
- return rc;
-
- if (0 == sysinfo(&info))
- return (uint64_t) info.freeram * info.mem_unit;
-
- return 0;
-}
-
-
-uint64_t uv_get_total_memory(void) {
- struct sysinfo info;
- uint64_t rc;
-
- rc = uv__read_proc_meminfo("MemTotal:");
-
- if (rc != 0)
- return rc;
-
- if (0 == sysinfo(&info))
- return (uint64_t) info.totalram * info.mem_unit;
-
- return 0;
-}
-
-
-static uint64_t uv__read_cgroups_uint64(const char* cgroup, const char* param) {
- char filename[256];
- uint64_t rc;
- int fd;
- ssize_t n;
- char buf[32]; /* Large enough to hold an encoded uint64_t. */
-
- snprintf(filename, 256, "/sys/fs/cgroup/%s/%s", cgroup, param);
-
- rc = 0;
- fd = uv__open_cloexec(filename, O_RDONLY);
-
- if (fd < 0)
- return 0;
-
- n = read(fd, buf, sizeof(buf) - 1);
-
- if (n > 0) {
- buf[n] = '\0';
- sscanf(buf, "%" PRIu64, &rc);
- }
-
- if (uv__close_nocheckstdio(fd))
- abort();
-
- return rc;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- /*
- * This might return 0 if there was a problem getting the memory limit from
- * cgroups. This is OK because a return value of 0 signifies that the memory
- * limit is unknown.
- */
- return uv__read_cgroups_uint64("memory", "memory.limit_in_bytes");
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/linux-inotify.cpp b/wpiutil/src/main/native/libuv/src/unix/linux-inotify.cpp
deleted file mode 100644
index ed484cc..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/linux-inotify.cpp
+++ /dev/null
@@ -1,354 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "uv/tree.h"
-#include "internal.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <unistd.h>
-
-struct watcher_list {
- RB_ENTRY(watcher_list) entry;
- QUEUE watchers;
- int iterating;
- char* path;
- int wd;
-};
-
-struct watcher_root {
- struct watcher_list* rbh_root;
-};
-#define CAST(p) ((struct watcher_root*)(p))
-
-
-static int compare_watchers(const struct watcher_list* a,
- const struct watcher_list* b) {
- if (a->wd < b->wd) return -1;
- if (a->wd > b->wd) return 1;
- return 0;
-}
-
-
-RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
-
-
-static void uv__inotify_read(uv_loop_t* loop,
- uv__io_t* w,
- unsigned int revents);
-
-static void maybe_free_watcher_list(struct watcher_list* w,
- uv_loop_t* loop);
-
-static int new_inotify_fd(void) {
- int err;
- int fd;
-
- fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
- if (fd != -1)
- return fd;
-
- if (errno != ENOSYS)
- return UV__ERR(errno);
-
- fd = uv__inotify_init();
- if (fd == -1)
- return UV__ERR(errno);
-
- err = uv__cloexec(fd, 1);
- if (err == 0)
- err = uv__nonblock(fd, 1);
-
- if (err) {
- uv__close(fd);
- return err;
- }
-
- return fd;
-}
-
-
-static int init_inotify(uv_loop_t* loop) {
- int err;
-
- if (loop->inotify_fd != -1)
- return 0;
-
- err = new_inotify_fd();
- if (err < 0)
- return err;
-
- loop->inotify_fd = err;
- uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
- uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
-
- return 0;
-}
-
-
-int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) {
- /* Open the inotify_fd, and re-arm all the inotify watchers. */
- int err;
- struct watcher_list* tmp_watcher_list_iter;
- struct watcher_list* watcher_list;
- struct watcher_list tmp_watcher_list;
- QUEUE queue;
- QUEUE* q;
- uv_fs_event_t* handle;
- char* tmp_path;
-
- if (old_watchers != NULL) {
- /* We must restore the old watcher list to be able to close items
- * out of it.
- */
- loop->inotify_watchers = old_watchers;
-
- QUEUE_INIT(&tmp_watcher_list.watchers);
- /* Note that the queue we use is shared with the start and stop()
- * functions, making QUEUE_FOREACH unsafe to use. So we use the
- * QUEUE_MOVE trick to safely iterate. Also don't free the watcher
- * list until we're done iterating. c.f. uv__inotify_read.
- */
- RB_FOREACH_SAFE(watcher_list, watcher_root,
- CAST(&old_watchers), tmp_watcher_list_iter) {
- watcher_list->iterating = 1;
- QUEUE_MOVE(&watcher_list->watchers, &queue);
- while (!QUEUE_EMPTY(&queue)) {
- q = QUEUE_HEAD(&queue);
- handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
- /* It's critical to keep a copy of path here, because it
- * will be set to NULL by stop() and then deallocated by
- * maybe_free_watcher_list
- */
- tmp_path = uv__strdup(handle->path);
- assert(tmp_path != NULL);
- QUEUE_REMOVE(q);
- QUEUE_INSERT_TAIL(&watcher_list->watchers, q);
- uv_fs_event_stop(handle);
-
- QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers);
- handle->path = tmp_path;
- }
- watcher_list->iterating = 0;
- maybe_free_watcher_list(watcher_list, loop);
- }
-
- QUEUE_MOVE(&tmp_watcher_list.watchers, &queue);
- while (!QUEUE_EMPTY(&queue)) {
- q = QUEUE_HEAD(&queue);
- QUEUE_REMOVE(q);
- handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
- tmp_path = handle->path;
- handle->path = NULL;
- err = uv_fs_event_start(handle, handle->cb, tmp_path, 0);
- uv__free(tmp_path);
- if (err)
- return err;
- }
- }
-
- return 0;
-}
-
-
-static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
- struct watcher_list w;
- w.wd = wd;
- return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
-}
-
-static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
- /* if the watcher_list->watchers is being iterated over, we can't free it. */
- if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
- /* No watchers left for this path. Clean up. */
- RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
- uv__inotify_rm_watch(loop->inotify_fd, w->wd);
- uv__free(w);
- }
-}
-
-static void uv__inotify_read(uv_loop_t* loop,
- uv__io_t* dummy,
- unsigned int events) {
- const struct uv__inotify_event* e;
- struct watcher_list* w;
- uv_fs_event_t* h;
- QUEUE queue;
- QUEUE* q;
- const char* path;
- ssize_t size;
- const char *p;
- /* needs to be large enough for sizeof(inotify_event) + strlen(path) */
- char buf[4096];
-
- while (1) {
- do
- size = read(loop->inotify_fd, buf, sizeof(buf));
- while (size == -1 && errno == EINTR);
-
- if (size == -1) {
- assert(errno == EAGAIN || errno == EWOULDBLOCK);
- break;
- }
-
- assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
-
- /* Now we have one or more inotify_event structs. */
- for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
- e = (const struct uv__inotify_event*)p;
-
- events = 0;
- if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
- events |= UV_CHANGE;
- if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
- events |= UV_RENAME;
-
- w = find_watcher(loop, e->wd);
- if (w == NULL)
- continue; /* Stale event, no watchers left. */
-
- /* inotify does not return the filename when monitoring a single file
- * for modifications. Repurpose the filename for API compatibility.
- * I'm not convinced this is a good thing, maybe it should go.
- */
- path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
-
- /* We're about to iterate over the queue and call user's callbacks.
- * What can go wrong?
- * A callback could call uv_fs_event_stop()
- * and the queue can change under our feet.
- * So, we use QUEUE_MOVE() trick to safely iterate over the queue.
- * And we don't free the watcher_list until we're done iterating.
- *
- * First,
- * tell uv_fs_event_stop() (that could be called from a user's callback)
- * not to free watcher_list.
- */
- w->iterating = 1;
- QUEUE_MOVE(&w->watchers, &queue);
- while (!QUEUE_EMPTY(&queue)) {
- q = QUEUE_HEAD(&queue);
- h = QUEUE_DATA(q, uv_fs_event_t, watchers);
-
- QUEUE_REMOVE(q);
- QUEUE_INSERT_TAIL(&w->watchers, q);
-
- h->cb(h, path, events, 0);
- }
- /* done iterating, time to (maybe) free empty watcher_list */
- w->iterating = 0;
- maybe_free_watcher_list(w, loop);
- }
- }
-}
-
-
-int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
- uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
- return 0;
-}
-
-
-int uv_fs_event_start(uv_fs_event_t* handle,
- uv_fs_event_cb cb,
- const char* path,
- unsigned int flags) {
- struct watcher_list* w;
- size_t len;
- int events;
- int err;
- int wd;
-
- if (uv__is_active(handle))
- return UV_EINVAL;
-
- err = init_inotify(handle->loop);
- if (err)
- return err;
-
- events = UV__IN_ATTRIB
- | UV__IN_CREATE
- | UV__IN_MODIFY
- | UV__IN_DELETE
- | UV__IN_DELETE_SELF
- | UV__IN_MOVE_SELF
- | UV__IN_MOVED_FROM
- | UV__IN_MOVED_TO;
-
- wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
- if (wd == -1)
- return UV__ERR(errno);
-
- w = find_watcher(handle->loop, wd);
- if (w)
- goto no_insert;
-
- len = strlen(path) + 1;
- w = (watcher_list*)uv__malloc(sizeof(*w) + len);
- if (w == NULL)
- return UV_ENOMEM;
-
- w->wd = wd;
- w->path = (char*)memcpy(w + 1, path, len);
- QUEUE_INIT(&w->watchers);
- w->iterating = 0;
- RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
-
-no_insert:
- uv__handle_start(handle);
- QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
- handle->path = w->path;
- handle->cb = cb;
- handle->wd = wd;
-
- return 0;
-}
-
-
-int uv_fs_event_stop(uv_fs_event_t* handle) {
- struct watcher_list* w;
-
- if (!uv__is_active(handle))
- return 0;
-
- w = find_watcher(handle->loop, handle->wd);
- assert(w != NULL);
-
- handle->wd = -1;
- handle->path = NULL;
- uv__handle_stop(handle);
- QUEUE_REMOVE(&handle->watchers);
-
- maybe_free_watcher_list(w, handle->loop);
-
- return 0;
-}
-
-
-void uv__fs_event_close(uv_fs_event_t* handle) {
- uv_fs_event_stop(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.cpp b/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.cpp
deleted file mode 100644
index 5637cf9..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.cpp
+++ /dev/null
@@ -1,369 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "linux-syscalls.h"
-#include <unistd.h>
-#include <signal.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#if defined(__has_feature)
-# if __has_feature(memory_sanitizer)
-# define MSAN_ACTIVE 1
-# include <sanitizer/msan_interface.h>
-# endif
-#endif
-
-#if defined(__i386__)
-# ifndef __NR_socketcall
-# define __NR_socketcall 102
-# endif
-#endif
-
-#if defined(__arm__)
-# if defined(__thumb__) || defined(__ARM_EABI__)
-# define UV_SYSCALL_BASE 0
-# else
-# define UV_SYSCALL_BASE 0x900000
-# endif
-#endif /* __arm__ */
-
-#ifndef __NR_accept4
-# if defined(__x86_64__)
-# define __NR_accept4 288
-# elif defined(__i386__)
- /* Nothing. Handled through socketcall(). */
-# elif defined(__arm__)
-# define __NR_accept4 (UV_SYSCALL_BASE + 366)
-# endif
-#endif /* __NR_accept4 */
-
-#ifndef __NR_eventfd
-# if defined(__x86_64__)
-# define __NR_eventfd 284
-# elif defined(__i386__)
-# define __NR_eventfd 323
-# elif defined(__arm__)
-# define __NR_eventfd (UV_SYSCALL_BASE + 351)
-# endif
-#endif /* __NR_eventfd */
-
-#ifndef __NR_eventfd2
-# if defined(__x86_64__)
-# define __NR_eventfd2 290
-# elif defined(__i386__)
-# define __NR_eventfd2 328
-# elif defined(__arm__)
-# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
-# endif
-#endif /* __NR_eventfd2 */
-
-#ifndef __NR_inotify_init
-# if defined(__x86_64__)
-# define __NR_inotify_init 253
-# elif defined(__i386__)
-# define __NR_inotify_init 291
-# elif defined(__arm__)
-# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
-# endif
-#endif /* __NR_inotify_init */
-
-#ifndef __NR_inotify_init1
-# if defined(__x86_64__)
-# define __NR_inotify_init1 294
-# elif defined(__i386__)
-# define __NR_inotify_init1 332
-# elif defined(__arm__)
-# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
-# endif
-#endif /* __NR_inotify_init1 */
-
-#ifndef __NR_inotify_add_watch
-# if defined(__x86_64__)
-# define __NR_inotify_add_watch 254
-# elif defined(__i386__)
-# define __NR_inotify_add_watch 292
-# elif defined(__arm__)
-# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
-# endif
-#endif /* __NR_inotify_add_watch */
-
-#ifndef __NR_inotify_rm_watch
-# if defined(__x86_64__)
-# define __NR_inotify_rm_watch 255
-# elif defined(__i386__)
-# define __NR_inotify_rm_watch 293
-# elif defined(__arm__)
-# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
-# endif
-#endif /* __NR_inotify_rm_watch */
-
-#ifndef __NR_pipe2
-# if defined(__x86_64__)
-# define __NR_pipe2 293
-# elif defined(__i386__)
-# define __NR_pipe2 331
-# elif defined(__arm__)
-# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
-# endif
-#endif /* __NR_pipe2 */
-
-#ifndef __NR_recvmmsg
-# if defined(__x86_64__)
-# define __NR_recvmmsg 299
-# elif defined(__i386__)
-# define __NR_recvmmsg 337
-# elif defined(__arm__)
-# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
-# endif
-#endif /* __NR_recvmsg */
-
-#ifndef __NR_sendmmsg
-# if defined(__x86_64__)
-# define __NR_sendmmsg 307
-# elif defined(__i386__)
-# define __NR_sendmmsg 345
-# elif defined(__arm__)
-# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
-# endif
-#endif /* __NR_sendmmsg */
-
-#ifndef __NR_utimensat
-# if defined(__x86_64__)
-# define __NR_utimensat 280
-# elif defined(__i386__)
-# define __NR_utimensat 320
-# elif defined(__arm__)
-# define __NR_utimensat (UV_SYSCALL_BASE + 348)
-# endif
-#endif /* __NR_utimensat */
-
-#ifndef __NR_preadv
-# if defined(__x86_64__)
-# define __NR_preadv 295
-# elif defined(__i386__)
-# define __NR_preadv 333
-# elif defined(__arm__)
-# define __NR_preadv (UV_SYSCALL_BASE + 361)
-# endif
-#endif /* __NR_preadv */
-
-#ifndef __NR_pwritev
-# if defined(__x86_64__)
-# define __NR_pwritev 296
-# elif defined(__i386__)
-# define __NR_pwritev 334
-# elif defined(__arm__)
-# define __NR_pwritev (UV_SYSCALL_BASE + 362)
-# endif
-#endif /* __NR_pwritev */
-
-#ifndef __NR_dup3
-# if defined(__x86_64__)
-# define __NR_dup3 292
-# elif defined(__i386__)
-# define __NR_dup3 330
-# elif defined(__arm__)
-# define __NR_dup3 (UV_SYSCALL_BASE + 358)
-# endif
-#endif /* __NR_pwritev */
-
-#ifndef __NR_statx
-# if defined(__x86_64__)
-# define __NR_statx 332
-# elif defined(__i386__)
-# define __NR_statx 383
-# elif defined(__aarch64__)
-# define __NR_statx 397
-# elif defined(__arm__)
-# define __NR_statx (UV_SYSCALL_BASE + 397)
-# elif defined(__ppc__)
-# define __NR_statx 383
-# elif defined(__s390__)
-# define __NR_statx 379
-# endif
-#endif /* __NR_statx */
-
-int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
-#if defined(__i386__)
- unsigned long args[4];
- int r;
-
- args[0] = (unsigned long) fd;
- args[1] = (unsigned long) addr;
- args[2] = (unsigned long) addrlen;
- args[3] = (unsigned long) flags;
-
- r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
-
- /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
- * a bad flags argument. Try to distinguish between the two cases.
- */
- if (r == -1)
- if (errno == EINVAL)
- if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
- errno = ENOSYS;
-
- return r;
-#elif defined(__NR_accept4)
- return syscall(__NR_accept4, fd, addr, addrlen, flags);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__eventfd(unsigned int count) {
-#if defined(__NR_eventfd)
- return syscall(__NR_eventfd, count);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__eventfd2(unsigned int count, int flags) {
-#if defined(__NR_eventfd2)
- return syscall(__NR_eventfd2, count, flags);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__inotify_init(void) {
-#if defined(__NR_inotify_init)
- return syscall(__NR_inotify_init);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__inotify_init1(int flags) {
-#if defined(__NR_inotify_init1)
- return syscall(__NR_inotify_init1, flags);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
-#if defined(__NR_inotify_add_watch)
- return syscall(__NR_inotify_add_watch, fd, path, mask);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__inotify_rm_watch(int fd, int32_t wd) {
-#if defined(__NR_inotify_rm_watch)
- return syscall(__NR_inotify_rm_watch, fd, wd);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__pipe2(int pipefd[2], int flags) {
-#if defined(__NR_pipe2)
- int result;
- result = syscall(__NR_pipe2, pipefd, flags);
-#if MSAN_ACTIVE
- if (!result)
- __msan_unpoison(pipefd, sizeof(int[2]));
-#endif
- return result;
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__sendmmsg(int fd,
- struct uv__mmsghdr* mmsg,
- unsigned int vlen,
- unsigned int flags) {
-#if defined(__NR_sendmmsg)
- return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__recvmmsg(int fd,
- struct uv__mmsghdr* mmsg,
- unsigned int vlen,
- unsigned int flags,
- struct timespec* timeout) {
-#if defined(__NR_recvmmsg)
- return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_preadv)
- return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
-#if defined(__NR_pwritev)
- return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__dup3(int oldfd, int newfd, int flags) {
-#if defined(__NR_dup3)
- return syscall(__NR_dup3, oldfd, newfd, flags);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
-
-
-int uv__statx(int dirfd,
- const char* path,
- int flags,
- unsigned int mask,
- struct uv__statx* statxbuf) {
- /* __NR_statx make Android box killed by SIGSYS.
- * That looks like a seccomp2 sandbox filter rejecting the system call.
- */
-#if defined(__NR_statx) && !defined(__ANDROID__)
- return syscall(__NR_statx, dirfd, path, flags, mask, statxbuf);
-#else
- return errno = ENOSYS, -1;
-#endif
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.h b/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.h
deleted file mode 100644
index 7e58bfa..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/linux-syscalls.h
+++ /dev/null
@@ -1,152 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_LINUX_SYSCALL_H_
-#define UV_LINUX_SYSCALL_H_
-
-#undef _GNU_SOURCE
-#define _GNU_SOURCE
-
-#include <stdint.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-
-#if defined(__alpha__)
-# define UV__O_CLOEXEC 0x200000
-#elif defined(__hppa__)
-# define UV__O_CLOEXEC 0x200000
-#elif defined(__sparc__)
-# define UV__O_CLOEXEC 0x400000
-#else
-# define UV__O_CLOEXEC 0x80000
-#endif
-
-#if defined(__alpha__)
-# define UV__O_NONBLOCK 0x4
-#elif defined(__hppa__)
-# define UV__O_NONBLOCK O_NONBLOCK
-#elif defined(__mips__)
-# define UV__O_NONBLOCK 0x80
-#elif defined(__sparc__)
-# define UV__O_NONBLOCK 0x4000
-#else
-# define UV__O_NONBLOCK 0x800
-#endif
-
-#define UV__EFD_CLOEXEC UV__O_CLOEXEC
-#define UV__EFD_NONBLOCK UV__O_NONBLOCK
-
-#define UV__IN_CLOEXEC UV__O_CLOEXEC
-#define UV__IN_NONBLOCK UV__O_NONBLOCK
-
-#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
-#if defined(SOCK_NONBLOCK)
-# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
-#else
-# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
-#endif
-
-/* inotify flags */
-#define UV__IN_ACCESS 0x001
-#define UV__IN_MODIFY 0x002
-#define UV__IN_ATTRIB 0x004
-#define UV__IN_CLOSE_WRITE 0x008
-#define UV__IN_CLOSE_NOWRITE 0x010
-#define UV__IN_OPEN 0x020
-#define UV__IN_MOVED_FROM 0x040
-#define UV__IN_MOVED_TO 0x080
-#define UV__IN_CREATE 0x100
-#define UV__IN_DELETE 0x200
-#define UV__IN_DELETE_SELF 0x400
-#define UV__IN_MOVE_SELF 0x800
-
-struct uv__statx_timestamp {
- int64_t tv_sec;
- uint32_t tv_nsec;
- int32_t unused0;
-};
-
-struct uv__statx {
- uint32_t stx_mask;
- uint32_t stx_blksize;
- uint64_t stx_attributes;
- uint32_t stx_nlink;
- uint32_t stx_uid;
- uint32_t stx_gid;
- uint16_t stx_mode;
- uint16_t unused0;
- uint64_t stx_ino;
- uint64_t stx_size;
- uint64_t stx_blocks;
- uint64_t stx_attributes_mask;
- struct uv__statx_timestamp stx_atime;
- struct uv__statx_timestamp stx_btime;
- struct uv__statx_timestamp stx_ctime;
- struct uv__statx_timestamp stx_mtime;
- uint32_t stx_rdev_major;
- uint32_t stx_rdev_minor;
- uint32_t stx_dev_major;
- uint32_t stx_dev_minor;
- uint64_t unused1[14];
-};
-
-struct uv__inotify_event {
- int32_t wd;
- uint32_t mask;
- uint32_t cookie;
- uint32_t len;
- /* char name[0]; */
-};
-
-struct uv__mmsghdr {
- struct msghdr msg_hdr;
- unsigned int msg_len;
-};
-
-int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
-int uv__eventfd(unsigned int count);
-int uv__eventfd2(unsigned int count, int flags);
-int uv__inotify_init(void);
-int uv__inotify_init1(int flags);
-int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
-int uv__inotify_rm_watch(int fd, int32_t wd);
-int uv__pipe2(int pipefd[2], int flags);
-int uv__recvmmsg(int fd,
- struct uv__mmsghdr* mmsg,
- unsigned int vlen,
- unsigned int flags,
- struct timespec* timeout);
-int uv__sendmmsg(int fd,
- struct uv__mmsghdr* mmsg,
- unsigned int vlen,
- unsigned int flags);
-ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
-ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
-int uv__dup3(int oldfd, int newfd, int flags);
-int uv__statx(int dirfd,
- const char* path,
- int flags,
- unsigned int mask,
- struct uv__statx* statxbuf);
-
-#endif /* UV_LINUX_SYSCALL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/unix/loop-watcher.cpp b/wpiutil/src/main/native/libuv/src/unix/loop-watcher.cpp
deleted file mode 100644
index b8c1c2a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/loop-watcher.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#define UV_LOOP_WATCHER_DEFINE(name, type) \
- int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
- uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
- handle->name##_cb = NULL; \
- return 0; \
- } \
- \
- int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
- if (uv__is_active(handle)) return 0; \
- if (cb == NULL) return UV_EINVAL; \
- QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
- handle->name##_cb = cb; \
- uv__handle_start(handle); \
- return 0; \
- } \
- \
- int uv_##name##_stop(uv_##name##_t* handle) { \
- if (!uv__is_active(handle)) return 0; \
- QUEUE_REMOVE(&handle->queue); \
- uv__handle_stop(handle); \
- return 0; \
- } \
- \
- void uv__run_##name(uv_loop_t* loop) { \
- uv_##name##_t* h; \
- QUEUE queue; \
- QUEUE* q; \
- QUEUE_MOVE(&loop->name##_handles, &queue); \
- while (!QUEUE_EMPTY(&queue)) { \
- q = QUEUE_HEAD(&queue); \
- h = QUEUE_DATA(q, uv_##name##_t, queue); \
- QUEUE_REMOVE(q); \
- QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
- h->name##_cb(h); \
- } \
- } \
- \
- void uv__##name##_close(uv_##name##_t* handle) { \
- uv_##name##_stop(handle); \
- }
-
-UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
-UV_LOOP_WATCHER_DEFINE(check, CHECK)
-UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/wpiutil/src/main/native/libuv/src/unix/loop.cpp b/wpiutil/src/main/native/libuv/src/unix/loop.cpp
deleted file mode 100644
index 7a037d1..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/loop.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "uv/tree.h"
-#include "internal.h"
-#include "heap-inl.h"
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-int uv_loop_init(uv_loop_t* loop) {
- void* saved_data;
- int err;
-
-
- saved_data = loop->data;
- memset(loop, 0, sizeof(*loop));
- loop->data = saved_data;
-
- heap_init((struct heap*) &loop->timer_heap);
- QUEUE_INIT(&loop->wq);
- QUEUE_INIT(&loop->idle_handles);
- QUEUE_INIT(&loop->async_handles);
- QUEUE_INIT(&loop->check_handles);
- QUEUE_INIT(&loop->prepare_handles);
- QUEUE_INIT(&loop->handle_queue);
-
- loop->active_handles = 0;
- loop->active_reqs.count = 0;
- loop->nfds = 0;
- loop->watchers = NULL;
- loop->nwatchers = 0;
- QUEUE_INIT(&loop->pending_queue);
- QUEUE_INIT(&loop->watcher_queue);
-
- loop->closing_handles = NULL;
- uv__update_time(loop);
- loop->async_io_watcher.fd = -1;
- loop->async_wfd = -1;
- loop->signal_pipefd[0] = -1;
- loop->signal_pipefd[1] = -1;
- loop->backend_fd = -1;
- loop->emfile_fd = -1;
-
- loop->timer_counter = 0;
- loop->stop_flag = 0;
-
- err = uv__platform_loop_init(loop);
- if (err)
- return err;
-
- uv__signal_global_once_init();
- err = uv_signal_init(loop, &loop->child_watcher);
- if (err)
- goto fail_signal_init;
-
- uv__handle_unref(&loop->child_watcher);
- loop->child_watcher.flags |= UV_HANDLE_INTERNAL;
- QUEUE_INIT(&loop->process_handles);
-
- err = uv_rwlock_init(&loop->cloexec_lock);
- if (err)
- goto fail_rwlock_init;
-
- err = uv_mutex_init(&loop->wq_mutex);
- if (err)
- goto fail_mutex_init;
-
- err = uv_async_init(loop, &loop->wq_async, uv__work_done);
- if (err)
- goto fail_async_init;
-
- uv__handle_unref(&loop->wq_async);
- loop->wq_async.flags |= UV_HANDLE_INTERNAL;
-
- return 0;
-
-fail_async_init:
- uv_mutex_destroy(&loop->wq_mutex);
-
-fail_mutex_init:
- uv_rwlock_destroy(&loop->cloexec_lock);
-
-fail_rwlock_init:
- uv__signal_loop_cleanup(loop);
-
-fail_signal_init:
- uv__platform_loop_delete(loop);
-
- return err;
-}
-
-
-int uv_loop_fork(uv_loop_t* loop) {
- int err;
- unsigned int i;
- uv__io_t* w;
-
- err = uv__io_fork(loop);
- if (err)
- return err;
-
- err = uv__async_fork(loop);
- if (err)
- return err;
-
- err = uv__signal_loop_fork(loop);
- if (err)
- return err;
-
- /* Rearm all the watchers that aren't re-queued by the above. */
- for (i = 0; i < loop->nwatchers; i++) {
- w = (uv__io_t*)loop->watchers[i];
- if (w == NULL)
- continue;
-
- if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
- w->events = 0; /* Force re-registration in uv__io_poll. */
- QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
- }
- }
-
- return 0;
-}
-
-
-void uv__loop_close(uv_loop_t* loop) {
- uv__signal_loop_cleanup(loop);
- uv__platform_loop_delete(loop);
- uv__async_stop(loop);
-
- if (loop->emfile_fd != -1) {
- uv__close(loop->emfile_fd);
- loop->emfile_fd = -1;
- }
-
- if (loop->backend_fd != -1) {
- uv__close(loop->backend_fd);
- loop->backend_fd = -1;
- }
-
- uv_mutex_lock(&loop->wq_mutex);
- assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
- assert(!uv__has_active_reqs(loop));
- uv_mutex_unlock(&loop->wq_mutex);
- uv_mutex_destroy(&loop->wq_mutex);
-
- /*
- * Note that all thread pool stuff is finished at this point and
- * it is safe to just destroy rw lock
- */
- uv_rwlock_destroy(&loop->cloexec_lock);
-
-#if 0
- assert(QUEUE_EMPTY(&loop->pending_queue));
- assert(QUEUE_EMPTY(&loop->watcher_queue));
- assert(loop->nfds == 0);
-#endif
-
- uv__free(loop->watchers);
- loop->watchers = NULL;
- loop->nwatchers = 0;
-}
-
-
-int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
- if (option != UV_LOOP_BLOCK_SIGNAL)
- return UV_ENOSYS;
-
- if (va_arg(ap, int) != SIGPROF)
- return UV_EINVAL;
-
- loop->flags |= UV_LOOP_BLOCK_SIGPROF;
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/netbsd.cpp b/wpiutil/src/main/native/libuv/src/unix/netbsd.cpp
deleted file mode 100644
index fb89843..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/netbsd.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-
-#include <kvm.h>
-#include <paths.h>
-#include <unistd.h>
-#include <time.h>
-#include <stdlib.h>
-#include <fcntl.h>
-
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <uvm/uvm_extern.h>
-
-#include <unistd.h>
-#include <time.h>
-
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- return uv__kqueue_init(loop);
-}
-
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
-}
-
-
-void uv_loadavg(double avg[3]) {
- struct loadavg info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_LOADAVG};
-
- if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
-
- avg[0] = (double) info.ldavg[0] / info.fscale;
- avg[1] = (double) info.ldavg[1] / info.fscale;
- avg[2] = (double) info.ldavg[2] / info.fscale;
-}
-
-
-int uv_exepath(char* buffer, size_t* size) {
- /* Intermediate buffer, retrieving partial path name does not work
- * As of NetBSD-8(beta), vnode->path translator does not handle files
- * with longer names than 31 characters.
- */
- char int_buf[PATH_MAX];
- size_t int_size;
- int mib[4];
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC_ARGS;
- mib[2] = -1;
- mib[3] = KERN_PROC_PATHNAME;
- int_size = ARRAY_SIZE(int_buf);
-
- if (sysctl(mib, 4, int_buf, &int_size, NULL, 0))
- return UV__ERR(errno);
-
- /* Copy string from the intermediate buffer to outer one with appropriate
- * length.
- */
- /* TODO(bnoordhuis) Check uv__strscpy() return value. */
- uv__strscpy(buffer, int_buf, *size);
-
- /* Set new size. */
- *size = strlen(buffer);
-
- return 0;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- struct uvmexp info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_UVMEXP};
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
-}
-
-
-uint64_t uv_get_total_memory(void) {
-#if defined(HW_PHYSMEM64)
- uint64_t info;
- int which[] = {CTL_HW, HW_PHYSMEM64};
-#else
- unsigned int info;
- int which[] = {CTL_HW, HW_PHYSMEM};
-#endif
- size_t size = sizeof(info);
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- kvm_t *kd = NULL;
- struct kinfo_proc2 *kinfo = NULL;
- pid_t pid;
- int nprocs;
- int max_size = sizeof(struct kinfo_proc2);
- int page_size;
-
- page_size = getpagesize();
- pid = getpid();
-
- kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
-
- if (kd == NULL) goto error;
-
- kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
- if (kinfo == NULL) goto error;
-
- *rss = kinfo->p_vm_rssize * page_size;
-
- kvm_close(kd);
-
- return 0;
-
-error:
- if (kd) kvm_close(kd);
- return UV_EPERM;
-}
-
-
-int uv_uptime(double* uptime) {
- time_t now;
- struct timeval info;
- size_t size = sizeof(info);
- static int which[] = {CTL_KERN, KERN_BOOTTIME};
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- now = time(NULL);
-
- *uptime = (double)(now - info.tv_sec);
- return 0;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
- unsigned int multiplier = ((uint64_t)1000L / ticks);
- unsigned int cur = 0;
- uv_cpu_info_t* cpu_info;
- u_int64_t* cp_times;
- char model[512];
- u_int64_t cpuspeed;
- int numcpus;
- size_t size;
- int i;
-
- size = sizeof(model);
- if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
- sysctlbyname("hw.model", &model, &size, NULL, 0)) {
- return UV__ERR(errno);
- }
-
- size = sizeof(numcpus);
- if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
- return UV__ERR(errno);
- *count = numcpus;
-
- /* Only i386 and amd64 have machdep.tsc_freq */
- size = sizeof(cpuspeed);
- if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
- cpuspeed = 0;
-
- size = numcpus * CPUSTATES * sizeof(*cp_times);
- cp_times = (u_int64_t*)uv__malloc(size);
- if (cp_times == NULL)
- return UV_ENOMEM;
-
- if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
- return UV__ERR(errno);
-
- *cpu_infos = (uv_cpu_info_t*)uv__malloc(numcpus * sizeof(**cpu_infos));
- if (!(*cpu_infos)) {
- uv__free(cp_times);
- uv__free(*cpu_infos);
- return UV_ENOMEM;
- }
-
- for (i = 0; i < numcpus; i++) {
- cpu_info = &(*cpu_infos)[i];
- cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
- cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
- cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
- cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
- cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
- cpu_info->model = uv__strdup(model);
- cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
- cur += CPUSTATES;
- }
- uv__free(cp_times);
- return 0;
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/no-fsevents.cpp b/wpiutil/src/main/native/libuv/src/unix/no-fsevents.cpp
deleted file mode 100644
index 158643a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/no-fsevents.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <errno.h>
-
-int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
- return UV_ENOSYS;
-}
-
-int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
- const char* filename, unsigned int flags) {
- return UV_ENOSYS;
-}
-
-int uv_fs_event_stop(uv_fs_event_t* handle) {
- return UV_ENOSYS;
-}
-
-void uv__fs_event_close(uv_fs_event_t* handle) {
- UNREACHABLE();
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/no-proctitle.cpp b/wpiutil/src/main/native/libuv/src/unix/no-proctitle.cpp
deleted file mode 100644
index 165740c..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/no-proctitle.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <errno.h>
-#include <stddef.h>
-
-char** uv_setup_args(int argc, char** argv) {
- return argv;
-}
-
-int uv_set_process_title(const char* title) {
- return 0;
-}
-
-int uv_get_process_title(char* buffer, size_t size) {
- if (buffer == NULL || size == 0)
- return UV_EINVAL;
-
- buffer[0] = '\0';
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/openbsd.cpp b/wpiutil/src/main/native/libuv/src/unix/openbsd.cpp
deleted file mode 100644
index f13ad8c..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/openbsd.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/resource.h>
-#include <sys/sched.h>
-#include <sys/time.h>
-#include <sys/sysctl.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <paths.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- return uv__kqueue_init(loop);
-}
-
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
-}
-
-
-void uv_loadavg(double avg[3]) {
- struct loadavg info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_LOADAVG};
-
- if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
-
- avg[0] = (double) info.ldavg[0] / info.fscale;
- avg[1] = (double) info.ldavg[1] / info.fscale;
- avg[2] = (double) info.ldavg[2] / info.fscale;
-}
-
-
-int uv_exepath(char* buffer, size_t* size) {
- int mib[4];
- char **argsbuf = NULL;
- char **argsbuf_tmp;
- size_t argsbuf_size = 100U;
- size_t exepath_size;
- pid_t mypid;
- int err;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- mypid = getpid();
- for (;;) {
- err = UV_ENOMEM;
- argsbuf_tmp = (char**)uv__realloc(argsbuf, argsbuf_size);
- if (argsbuf_tmp == NULL)
- goto out;
- argsbuf = argsbuf_tmp;
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC_ARGS;
- mib[2] = mypid;
- mib[3] = KERN_PROC_ARGV;
- if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
- break;
- }
- if (errno != ENOMEM) {
- err = UV__ERR(errno);
- goto out;
- }
- argsbuf_size *= 2U;
- }
-
- if (argsbuf[0] == NULL) {
- err = UV_EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
- goto out;
- }
-
- *size -= 1;
- exepath_size = strlen(argsbuf[0]);
- if (*size > exepath_size)
- *size = exepath_size;
-
- memcpy(buffer, argsbuf[0], *size);
- buffer[*size] = '\0';
- err = 0;
-
-out:
- uv__free(argsbuf);
-
- return err;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- struct uvmexp info;
- size_t size = sizeof(info);
- int which[] = {CTL_VM, VM_UVMEXP};
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
-}
-
-
-uint64_t uv_get_total_memory(void) {
- uint64_t info;
- int which[] = {CTL_HW, HW_PHYSMEM64};
- size_t size = sizeof(info);
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- return (uint64_t) info;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- struct kinfo_proc kinfo;
- size_t page_size = getpagesize();
- size_t size = sizeof(struct kinfo_proc);
- int mib[6];
-
- mib[0] = CTL_KERN;
- mib[1] = KERN_PROC;
- mib[2] = KERN_PROC_PID;
- mib[3] = getpid();
- mib[4] = sizeof(struct kinfo_proc);
- mib[5] = 1;
-
- if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
- return UV__ERR(errno);
-
- *rss = kinfo.p_vm_rssize * page_size;
- return 0;
-}
-
-
-int uv_uptime(double* uptime) {
- time_t now;
- struct timeval info;
- size_t size = sizeof(info);
- static int which[] = {CTL_KERN, KERN_BOOTTIME};
-
- if (sysctl(which, 2, &info, &size, NULL, 0))
- return UV__ERR(errno);
-
- now = time(NULL);
-
- *uptime = (double)(now - info.tv_sec);
- return 0;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
- unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
- multiplier = ((uint64_t)1000L / ticks), cpuspeed;
- uint64_t info[CPUSTATES];
- char model[512];
- int numcpus = 1;
- int which[] = {CTL_HW,HW_MODEL,0};
- size_t size;
- int i;
- uv_cpu_info_t* cpu_info;
-
- size = sizeof(model);
- if (sysctl(which, 2, &model, &size, NULL, 0))
- return UV__ERR(errno);
-
- which[1] = HW_NCPU;
- size = sizeof(numcpus);
- if (sysctl(which, 2, &numcpus, &size, NULL, 0))
- return UV__ERR(errno);
-
- *cpu_infos = (uv_cpu_info_t*)uv__malloc(numcpus * sizeof(**cpu_infos));
- if (!(*cpu_infos))
- return UV_ENOMEM;
-
- *count = numcpus;
-
- which[1] = HW_CPUSPEED;
- size = sizeof(cpuspeed);
- if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
- uv__free(*cpu_infos);
- return UV__ERR(errno);
- }
-
- size = sizeof(info);
- which[0] = CTL_KERN;
- which[1] = KERN_CPTIME2;
- for (i = 0; i < numcpus; i++) {
- which[2] = i;
- size = sizeof(info);
- if (sysctl(which, 3, &info, &size, NULL, 0)) {
- uv__free(*cpu_infos);
- return UV__ERR(errno);
- }
-
- cpu_info = &(*cpu_infos)[i];
-
- cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
- cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
- cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
- cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
- cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
-
- cpu_info->model = uv__strdup(model);
- cpu_info->speed = cpuspeed;
- }
-
- return 0;
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/pipe.cpp b/wpiutil/src/main/native/libuv/src/unix/pipe.cpp
deleted file mode 100644
index c21033a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/pipe.cpp
+++ /dev/null
@@ -1,377 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-
-int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
- uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
- handle->shutdown_req = NULL;
- handle->connect_req = NULL;
- handle->pipe_fname = NULL;
- handle->ipc = ipc;
- return 0;
-}
-
-
-int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
- struct sockaddr_un saddr;
- const char* pipe_fname;
- int sockfd;
- int err;
-
- pipe_fname = NULL;
-
- /* Already bound? */
- if (uv__stream_fd(handle) >= 0)
- return UV_EINVAL;
-
- /* Make a copy of the file name, it outlives this function's scope. */
- pipe_fname = uv__strdup(name);
- if (pipe_fname == NULL)
- return UV_ENOMEM;
-
- /* We've got a copy, don't touch the original any more. */
- name = NULL;
-
- err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
- if (err < 0)
- goto err_socket;
- sockfd = err;
-
- memset(&saddr, 0, sizeof saddr);
- uv__strscpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path));
- saddr.sun_family = AF_UNIX;
-
- if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
- err = UV__ERR(errno);
- /* Convert ENOENT to EACCES for compatibility with Windows. */
- if (err == UV_ENOENT)
- err = UV_EACCES;
-
- uv__close(sockfd);
- goto err_socket;
- }
-
- /* Success. */
- handle->flags |= UV_HANDLE_BOUND;
- handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
- handle->io_watcher.fd = sockfd;
- return 0;
-
-err_socket:
- uv__free((void*)pipe_fname);
- return err;
-}
-
-
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
- if (uv__stream_fd(handle) == -1)
- return UV_EINVAL;
-
-#if defined(__MVS__)
- /* On zOS, backlog=0 has undefined behaviour */
- if (backlog == 0)
- backlog = 1;
- else if (backlog < 0)
- backlog = SOMAXCONN;
-#endif
-
- if (listen(uv__stream_fd(handle), backlog))
- return UV__ERR(errno);
-
- handle->connection_cb = cb;
- handle->io_watcher.cb = uv__server_io;
- uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
- return 0;
-}
-
-
-void uv__pipe_close(uv_pipe_t* handle) {
- if (handle->pipe_fname) {
- /*
- * Unlink the file system entity before closing the file descriptor.
- * Doing it the other way around introduces a race where our process
- * unlinks a socket with the same name that's just been created by
- * another thread or process.
- */
- unlink(handle->pipe_fname);
- uv__free((void*)handle->pipe_fname);
- handle->pipe_fname = NULL;
- }
-
- uv__stream_close((uv_stream_t*)handle);
-}
-
-
-int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
- int flags;
- int mode;
- int err;
- flags = 0;
-
- if (uv__fd_exists(handle->loop, fd))
- return UV_EEXIST;
-
- do
- mode = fcntl(fd, F_GETFL);
- while (mode == -1 && errno == EINTR);
-
- if (mode == -1)
- return UV__ERR(errno); /* according to docs, must be EBADF */
-
- err = uv__nonblock(fd, 1);
- if (err)
- return err;
-
-#if defined(__APPLE__)
- err = uv__stream_try_select((uv_stream_t*) handle, &fd);
- if (err)
- return err;
-#endif /* defined(__APPLE__) */
-
- mode &= O_ACCMODE;
- if (mode != O_WRONLY)
- flags |= UV_HANDLE_READABLE;
- if (mode != O_RDONLY)
- flags |= UV_HANDLE_WRITABLE;
-
- return uv__stream_open((uv_stream_t*)handle, fd, flags);
-}
-
-
-void uv_pipe_connect(uv_connect_t* req,
- uv_pipe_t* handle,
- const char* name,
- uv_connect_cb cb) {
- struct sockaddr_un saddr;
- int new_sock;
- int err;
- int r;
-
- new_sock = (uv__stream_fd(handle) == -1);
-
- if (new_sock) {
- err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
- if (err < 0)
- goto out;
- handle->io_watcher.fd = err;
- }
-
- memset(&saddr, 0, sizeof saddr);
- uv__strscpy(saddr.sun_path, name, sizeof(saddr.sun_path));
- saddr.sun_family = AF_UNIX;
-
- do {
- r = connect(uv__stream_fd(handle),
- (struct sockaddr*)&saddr, sizeof saddr);
- }
- while (r == -1 && errno == EINTR);
-
- if (r == -1 && errno != EINPROGRESS) {
- err = UV__ERR(errno);
-#if defined(__CYGWIN__) || defined(__MSYS__)
- /* EBADF is supposed to mean that the socket fd is bad, but
- Cygwin reports EBADF instead of ENOTSOCK when the file is
- not a socket. We do not expect to see a bad fd here
- (e.g. due to new_sock), so translate the error. */
- if (err == UV_EBADF)
- err = UV_ENOTSOCK;
-#endif
- goto out;
- }
-
- err = 0;
- if (new_sock) {
- err = uv__stream_open((uv_stream_t*)handle,
- uv__stream_fd(handle),
- UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- }
-
- if (err == 0)
- uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
-
-out:
- handle->delayed_error = err;
- handle->connect_req = req;
-
- uv__req_init(handle->loop, req, UV_CONNECT);
- req->handle = (uv_stream_t*)handle;
- req->cb = cb;
- QUEUE_INIT(&req->queue);
-
- /* Force callback to run on next tick in case of error. */
- if (err)
- uv__io_feed(handle->loop, &handle->io_watcher);
-
-}
-
-
-static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
- uv__peersockfunc func,
- char* buffer,
- size_t* size) {
- struct sockaddr_un sa;
- socklen_t addrlen;
- int err;
-
- addrlen = sizeof(sa);
- memset(&sa, 0, addrlen);
- err = uv__getsockpeername((const uv_handle_t*) handle,
- func,
- (struct sockaddr*) &sa,
- (int*) &addrlen);
- if (err < 0) {
- *size = 0;
- return err;
- }
-
-#if defined(__linux__)
- if (sa.sun_path[0] == 0)
- /* Linux abstract namespace */
- addrlen -= offsetof(struct sockaddr_un, sun_path);
- else
-#endif
- addrlen = strlen(sa.sun_path);
-
-
- if (addrlen >= *size) {
- *size = addrlen + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, sa.sun_path, addrlen);
- *size = addrlen;
-
- /* only null-terminate if it's not an abstract socket */
- if (buffer[0] != '\0')
- buffer[addrlen] = '\0';
-
- return 0;
-}
-
-
-int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
- return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
-}
-
-
-int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
- return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
-}
-
-
-void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
-}
-
-
-int uv_pipe_pending_count(uv_pipe_t* handle) {
- uv__stream_queued_fds_t* queued_fds;
-
- if (!handle->ipc)
- return 0;
-
- if (handle->accepted_fd == -1)
- return 0;
-
- if (handle->queued_fds == NULL)
- return 1;
-
- queued_fds = (uv__stream_queued_fds_t*)(handle->queued_fds);
- return queued_fds->offset + 1;
-}
-
-
-uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
- if (!handle->ipc)
- return UV_UNKNOWN_HANDLE;
-
- if (handle->accepted_fd == -1)
- return UV_UNKNOWN_HANDLE;
- else
- return uv__handle_type(handle->accepted_fd);
-}
-
-
-int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
- unsigned desired_mode;
- struct stat pipe_stat;
- char* name_buffer;
- size_t name_len;
- int r;
-
- if (handle == NULL || uv__stream_fd(handle) == -1)
- return UV_EBADF;
-
- if (mode != UV_READABLE &&
- mode != UV_WRITABLE &&
- mode != (UV_WRITABLE | UV_READABLE))
- return UV_EINVAL;
-
- /* Unfortunately fchmod does not work on all platforms, we will use chmod. */
- name_len = 0;
- r = uv_pipe_getsockname(handle, NULL, &name_len);
- if (r != UV_ENOBUFS)
- return r;
-
- name_buffer = (char*)uv__malloc(name_len);
- if (name_buffer == NULL)
- return UV_ENOMEM;
-
- r = uv_pipe_getsockname(handle, name_buffer, &name_len);
- if (r != 0) {
- uv__free(name_buffer);
- return r;
- }
-
- /* stat must be used as fstat has a bug on Darwin */
- if (stat(name_buffer, &pipe_stat) == -1) {
- uv__free(name_buffer);
- return -errno;
- }
-
- desired_mode = 0;
- if (mode & UV_READABLE)
- desired_mode |= S_IRUSR | S_IRGRP | S_IROTH;
- if (mode & UV_WRITABLE)
- desired_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
-
- /* Exit early if pipe already has desired mode. */
- if ((pipe_stat.st_mode & desired_mode) == desired_mode) {
- uv__free(name_buffer);
- return 0;
- }
-
- pipe_stat.st_mode |= desired_mode;
-
- r = chmod(name_buffer, pipe_stat.st_mode);
- uv__free(name_buffer);
-
- return r != -1 ? 0 : UV__ERR(errno);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/poll.cpp b/wpiutil/src/main/native/libuv/src/unix/poll.cpp
deleted file mode 100644
index d578611..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/poll.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-
-static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- uv_poll_t* handle;
- int pevents;
-
- handle = container_of(w, uv_poll_t, io_watcher);
-
- /*
- * As documented in the kernel source fs/kernfs/file.c #780
- * poll will return POLLERR|POLLPRI in case of sysfs
- * polling. This does not happen in case of out-of-band
- * TCP messages.
- *
- * The above is the case on (at least) FreeBSD and Linux.
- *
- * So to properly determine a POLLPRI or a POLLERR we need
- * to check for both.
- */
- if ((events & POLLERR) && !(events & UV__POLLPRI)) {
- uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
- uv__handle_stop(handle);
- handle->poll_cb(handle, UV_EBADF, 0);
- return;
- }
-
- pevents = 0;
- if (events & POLLIN)
- pevents |= UV_READABLE;
- if (events & UV__POLLPRI)
- pevents |= UV_PRIORITIZED;
- if (events & POLLOUT)
- pevents |= UV_WRITABLE;
- if (events & UV__POLLRDHUP)
- pevents |= UV_DISCONNECT;
-
- handle->poll_cb(handle, 0, pevents);
-}
-
-
-int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
- int err;
-
- if (uv__fd_exists(loop, fd))
- return UV_EEXIST;
-
- err = uv__io_check_fd(loop, fd);
- if (err)
- return err;
-
- /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
- * Workaround for e.g. kqueue fds not supporting ioctls.
- */
- err = uv__nonblock(fd, 1);
-#ifdef UV__NONBLOCK_IS_IOCTL
- if (err == UV_ENOTTY)
- err = uv__nonblock_fcntl(fd, 1);
-#endif
-
- if (err)
- return err;
-
- uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
- uv__io_init(&handle->io_watcher, uv__poll_io, fd);
- handle->poll_cb = NULL;
- return 0;
-}
-
-
-int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
- uv_os_sock_t socket) {
- return uv_poll_init(loop, handle, socket);
-}
-
-
-static void uv__poll_stop(uv_poll_t* handle) {
- uv__io_stop(handle->loop,
- &handle->io_watcher,
- POLLIN | POLLOUT | UV__POLLRDHUP | UV__POLLPRI);
- uv__handle_stop(handle);
- uv__platform_invalidate_fd(handle->loop, handle->io_watcher.fd);
-}
-
-
-int uv_poll_stop(uv_poll_t* handle) {
- assert(!uv__is_closing(handle));
- uv__poll_stop(handle);
- return 0;
-}
-
-
-int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
- int events;
-
- assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT |
- UV_PRIORITIZED)) == 0);
- assert(!uv__is_closing(handle));
-
- uv__poll_stop(handle);
-
- if (pevents == 0)
- return 0;
-
- events = 0;
- if (pevents & UV_READABLE)
- events |= POLLIN;
- if (pevents & UV_PRIORITIZED)
- events |= UV__POLLPRI;
- if (pevents & UV_WRITABLE)
- events |= POLLOUT;
- if (pevents & UV_DISCONNECT)
- events |= UV__POLLRDHUP;
-
- uv__io_start(handle->loop, &handle->io_watcher, events);
- uv__handle_start(handle);
- handle->poll_cb = poll_cb;
-
- return 0;
-}
-
-
-void uv__poll_close(uv_poll_t* handle) {
- uv__poll_stop(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/posix-hrtime.cpp b/wpiutil/src/main/native/libuv/src/unix/posix-hrtime.cpp
deleted file mode 100644
index 323dfc2..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/posix-hrtime.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdint.h>
-#include <time.h>
-
-#undef NANOSEC
-#define NANOSEC ((uint64_t) 1e9)
-
-uint64_t uv__hrtime(uv_clocktype_t type) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/posix-poll.cpp b/wpiutil/src/main/native/libuv/src/unix/posix-poll.cpp
deleted file mode 100644
index b932f91..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/posix-poll.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-/* POSIX defines poll() as a portable way to wait on file descriptors.
- * Here we maintain a dynamically sized array of file descriptors and
- * events to pass as the first argument to poll().
- */
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-
-int uv__platform_loop_init(uv_loop_t* loop) {
- loop->poll_fds = NULL;
- loop->poll_fds_used = 0;
- loop->poll_fds_size = 0;
- loop->poll_fds_iterating = 0;
- return 0;
-}
-
-void uv__platform_loop_delete(uv_loop_t* loop) {
- uv__free(loop->poll_fds);
- loop->poll_fds = NULL;
-}
-
-int uv__io_fork(uv_loop_t* loop) {
- uv__platform_loop_delete(loop);
- return uv__platform_loop_init(loop);
-}
-
-/* Allocate or dynamically resize our poll fds array. */
-static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
- size_t i;
- size_t n;
- struct pollfd* p;
-
- if (loop->poll_fds_used < loop->poll_fds_size)
- return;
-
- n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
- p = (struct pollfd*)uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds));
- if (p == NULL)
- abort();
-
- loop->poll_fds = p;
- for (i = loop->poll_fds_size; i < n; i++) {
- loop->poll_fds[i].fd = -1;
- loop->poll_fds[i].events = 0;
- loop->poll_fds[i].revents = 0;
- }
- loop->poll_fds_size = n;
-}
-
-/* Primitive swap operation on poll fds array elements. */
-static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
- struct pollfd pfd;
- pfd = loop->poll_fds[l];
- loop->poll_fds[l] = loop->poll_fds[r];
- loop->poll_fds[r] = pfd;
-}
-
-/* Add a watcher's fd to our poll fds array with its pending events. */
-static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {
- size_t i;
- struct pollfd* pe;
-
- /* If the fd is already in the set just update its events. */
- assert(!loop->poll_fds_iterating);
- for (i = 0; i < loop->poll_fds_used; ++i) {
- if (loop->poll_fds[i].fd == w->fd) {
- loop->poll_fds[i].events = w->pevents;
- return;
- }
- }
-
- /* Otherwise, allocate a new slot in the set for the fd. */
- uv__pollfds_maybe_resize(loop);
- pe = &loop->poll_fds[loop->poll_fds_used++];
- pe->fd = w->fd;
- pe->events = w->pevents;
-}
-
-/* Remove a watcher's fd from our poll fds array. */
-static void uv__pollfds_del(uv_loop_t* loop, int fd) {
- size_t i;
- assert(!loop->poll_fds_iterating);
- for (i = 0; i < loop->poll_fds_used;) {
- if (loop->poll_fds[i].fd == fd) {
- /* swap to last position and remove */
- --loop->poll_fds_used;
- uv__pollfds_swap(loop, i, loop->poll_fds_used);
- loop->poll_fds[loop->poll_fds_used].fd = -1;
- loop->poll_fds[loop->poll_fds_used].events = 0;
- loop->poll_fds[loop->poll_fds_used].revents = 0;
- /* This method is called with an fd of -1 to purge the invalidated fds,
- * so we may possibly have multiples to remove.
- */
- if (-1 != fd)
- return;
- } else {
- /* We must only increment the loop counter when the fds do not match.
- * Otherwise, when we are purging an invalidated fd, the value just
- * swapped here from the previous end of the array will be skipped.
- */
- ++i;
- }
- }
-}
-
-
-void uv__io_poll(uv_loop_t* loop, int timeout) {
- sigset_t* pset;
- sigset_t set;
- uint64_t time_base;
- uint64_t time_diff;
- QUEUE* q;
- uv__io_t* w;
- size_t i;
- unsigned int nevents;
- int nfds;
- int have_signals;
- struct pollfd* pe;
- int fd;
-
- if (loop->nfds == 0) {
- assert(QUEUE_EMPTY(&loop->watcher_queue));
- return;
- }
-
- /* Take queued watchers and add their fds to our poll fds array. */
- while (!QUEUE_EMPTY(&loop->watcher_queue)) {
- q = QUEUE_HEAD(&loop->watcher_queue);
- QUEUE_REMOVE(q);
- QUEUE_INIT(q);
-
- w = QUEUE_DATA(q, uv__io_t, watcher_queue);
- assert(w->pevents != 0);
- assert(w->fd >= 0);
- assert(w->fd < (int) loop->nwatchers);
-
- uv__pollfds_add(loop, w);
-
- w->events = w->pevents;
- }
-
- /* Prepare a set of signals to block around poll(), if any. */
- pset = NULL;
- if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
- pset = &set;
- sigemptyset(pset);
- sigaddset(pset, SIGPROF);
- }
-
- assert(timeout >= -1);
- time_base = loop->time;
-
- /* Loop calls to poll() and processing of results. If we get some
- * results from poll() but they turn out not to be interesting to
- * our caller then we need to loop around and poll() again.
- */
- for (;;) {
- if (pset != NULL)
- if (pthread_sigmask(SIG_BLOCK, pset, NULL))
- abort();
- nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
- if (pset != NULL)
- if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
- abort();
-
- /* Update loop->time unconditionally. It's tempting to skip the update when
- * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
- * operating system didn't reschedule our process while in the syscall.
- */
- SAVE_ERRNO(uv__update_time(loop));
-
- if (nfds == 0) {
- assert(timeout != -1);
- return;
- }
-
- if (nfds == -1) {
- if (errno != EINTR)
- abort();
-
- if (timeout == -1)
- continue;
-
- if (timeout == 0)
- return;
-
- /* Interrupted by a signal. Update timeout and poll again. */
- goto update_timeout;
- }
-
- /* Tell uv__platform_invalidate_fd not to manipulate our array
- * while we are iterating over it.
- */
- loop->poll_fds_iterating = 1;
-
- /* Initialize a count of events that we care about. */
- nevents = 0;
- have_signals = 0;
-
- /* Loop over the entire poll fds array looking for returned events. */
- for (i = 0; i < loop->poll_fds_used; i++) {
- pe = loop->poll_fds + i;
- fd = pe->fd;
-
- /* Skip invalidated events, see uv__platform_invalidate_fd. */
- if (fd == -1)
- continue;
-
- assert(fd >= 0);
- assert((unsigned) fd < loop->nwatchers);
-
- w = loop->watchers[fd];
-
- if (w == NULL) {
- /* File descriptor that we've stopped watching, ignore. */
- uv__platform_invalidate_fd(loop, fd);
- continue;
- }
-
- /* Filter out events that user has not requested us to watch
- * (e.g. POLLNVAL).
- */
- pe->revents &= w->pevents | POLLERR | POLLHUP;
-
- if (pe->revents != 0) {
- /* Run signal watchers last. */
- if (w == &loop->signal_io_watcher) {
- have_signals = 1;
- } else {
- w->cb(loop, w, pe->revents);
- }
-
- nevents++;
- }
- }
-
- if (have_signals != 0)
- loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
-
- loop->poll_fds_iterating = 0;
-
- /* Purge invalidated fds from our poll fds array. */
- uv__pollfds_del(loop, -1);
-
- if (have_signals != 0)
- return; /* Event loop should cycle now so don't poll again. */
-
- if (nevents != 0)
- return;
-
- if (timeout == 0)
- return;
-
- if (timeout == -1)
- continue;
-
-update_timeout:
- assert(timeout > 0);
-
- time_diff = loop->time - time_base;
- if (time_diff >= (uint64_t) timeout)
- return;
-
- timeout -= time_diff;
- }
-}
-
-/* Remove the given fd from our poll fds array because no one
- * is interested in its events anymore.
- */
-void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
- size_t i;
-
- assert(fd >= 0);
-
- if (loop->poll_fds_iterating) {
- /* uv__io_poll is currently iterating. Just invalidate fd. */
- for (i = 0; i < loop->poll_fds_used; i++)
- if (loop->poll_fds[i].fd == fd) {
- loop->poll_fds[i].fd = -1;
- loop->poll_fds[i].events = 0;
- loop->poll_fds[i].revents = 0;
- }
- } else {
- /* uv__io_poll is not iterating. Delete fd from the set. */
- uv__pollfds_del(loop, fd);
- }
-}
-
-/* Check whether the given fd is supported by poll(). */
-int uv__io_check_fd(uv_loop_t* loop, int fd) {
- struct pollfd p[1];
- int rv;
-
- p[0].fd = fd;
- p[0].events = POLLIN;
-
- do
- rv = poll(p, 1, 0);
- while (rv == -1 && (errno == EINTR || errno == EAGAIN));
-
- if (rv == -1)
- return UV__ERR(errno);
-
- if (p[0].revents & POLLNVAL)
- return UV_EINVAL;
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/process.cpp b/wpiutil/src/main/native/libuv/src/unix/process.cpp
deleted file mode 100644
index 87dac7f..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/process.cpp
+++ /dev/null
@@ -1,603 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <poll.h>
-
-#if defined(__APPLE__) && !TARGET_OS_IPHONE
-# include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#else
-extern char **environ;
-#endif
-
-#if defined(__linux__) || defined(__GLIBC__)
-# include <grp.h>
-#endif
-
-
-static void uv__chld(uv_signal_t* handle, int signum) {
- uv_process_t* process;
- uv_loop_t* loop;
- int exit_status;
- int term_signal;
- int status;
- pid_t pid;
- QUEUE pending;
- QUEUE* q;
- QUEUE* h;
-
- assert(signum == SIGCHLD);
-
- QUEUE_INIT(&pending);
- loop = handle->loop;
-
- h = &loop->process_handles;
- q = QUEUE_HEAD(h);
- while (q != h) {
- process = QUEUE_DATA(q, uv_process_t, queue);
- q = QUEUE_NEXT(q);
-
- do
- pid = waitpid(process->pid, &status, WNOHANG);
- while (pid == -1 && errno == EINTR);
-
- if (pid == 0)
- continue;
-
- if (pid == -1) {
- if (errno != ECHILD)
- abort();
- continue;
- }
-
- process->status = status;
- QUEUE_REMOVE(&process->queue);
- QUEUE_INSERT_TAIL(&pending, &process->queue);
- }
-
- h = &pending;
- q = QUEUE_HEAD(h);
- while (q != h) {
- process = QUEUE_DATA(q, uv_process_t, queue);
- q = QUEUE_NEXT(q);
-
- QUEUE_REMOVE(&process->queue);
- QUEUE_INIT(&process->queue);
- uv__handle_stop(process);
-
- if (process->exit_cb == NULL)
- continue;
-
- exit_status = 0;
- if (WIFEXITED(process->status))
- exit_status = WEXITSTATUS(process->status);
-
- term_signal = 0;
- if (WIFSIGNALED(process->status))
- term_signal = WTERMSIG(process->status);
-
- process->exit_cb(process, exit_status, term_signal);
- }
- assert(QUEUE_EMPTY(&pending));
-}
-
-
-int uv__make_socketpair(int fds[2], int flags) {
-#if defined(__linux__)
- static int no_cloexec;
-
- if (no_cloexec)
- goto skip;
-
- if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
- return 0;
-
- /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
- * Anything else is a genuine error.
- */
- if (errno != EINVAL)
- return UV__ERR(errno);
-
- no_cloexec = 1;
-
-skip:
-#endif
-
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
- return UV__ERR(errno);
-
- uv__cloexec(fds[0], 1);
- uv__cloexec(fds[1], 1);
-
- if (flags & UV__F_NONBLOCK) {
- uv__nonblock(fds[0], 1);
- uv__nonblock(fds[1], 1);
- }
-
- return 0;
-}
-
-
-int uv__make_pipe(int fds[2], int flags) {
-#if defined(__linux__)
- static int no_pipe2;
-
- if (no_pipe2)
- goto skip;
-
- if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
- return 0;
-
- if (errno != ENOSYS)
- return UV__ERR(errno);
-
- no_pipe2 = 1;
-
-skip:
-#endif
-
- if (pipe(fds))
- return UV__ERR(errno);
-
- uv__cloexec(fds[0], 1);
- uv__cloexec(fds[1], 1);
-
- if (flags & UV__F_NONBLOCK) {
- uv__nonblock(fds[0], 1);
- uv__nonblock(fds[1], 1);
- }
-
- return 0;
-}
-
-
-/*
- * Used for initializing stdio streams like options.stdin_stream. Returns
- * zero on success. See also the cleanup section in uv_spawn().
- */
-static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
- int mask;
- int fd;
-
- mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
-
- switch (container->flags & mask) {
- case UV_IGNORE:
- return 0;
-
- case UV_CREATE_PIPE:
- assert(container->data.stream != NULL);
- if (container->data.stream->type != UV_NAMED_PIPE)
- return UV_EINVAL;
- else
- return uv__make_socketpair(fds, 0);
-
- case UV_INHERIT_FD:
- case UV_INHERIT_STREAM:
- if (container->flags & UV_INHERIT_FD)
- fd = container->data.fd;
- else
- fd = uv__stream_fd(container->data.stream);
-
- if (fd == -1)
- return UV_EINVAL;
-
- fds[1] = fd;
- return 0;
-
- default:
- assert(0 && "Unexpected flags");
- return UV_EINVAL;
- }
-}
-
-
-static int uv__process_open_stream(uv_stdio_container_t* container,
- int pipefds[2]) {
- int flags;
- int err;
-
- if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
- return 0;
-
- err = uv__close(pipefds[1]);
- if (err != 0)
- abort();
-
- pipefds[1] = -1;
- uv__nonblock(pipefds[0], 1);
-
- flags = 0;
- if (container->flags & UV_WRITABLE_PIPE)
- flags |= UV_HANDLE_READABLE;
- if (container->flags & UV_READABLE_PIPE)
- flags |= UV_HANDLE_WRITABLE;
-
- return uv__stream_open(container->data.stream, pipefds[0], flags);
-}
-
-
-static void uv__process_close_stream(uv_stdio_container_t* container) {
- if (!(container->flags & UV_CREATE_PIPE)) return;
- uv__stream_close(container->data.stream);
-}
-
-
-static void uv__write_int(int fd, int val) {
- ssize_t n;
-
- do
- n = write(fd, &val, sizeof(val));
- while (n == -1 && errno == EINTR);
-
- if (n == -1 && errno == EPIPE)
- return; /* parent process has quit */
-
- assert(n == sizeof(val));
-}
-
-
-#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
-/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
- * avoided. Since this isn't called on those targets, the function
- * doesn't even need to be defined for them.
- */
-static void uv__process_child_init(const uv_process_options_t* options,
- int stdio_count,
- int (*pipes)[2],
- int error_fd) {
- sigset_t set;
- int close_fd;
- int use_fd;
- int err;
- int fd;
- int n;
-
- if (options->flags & UV_PROCESS_DETACHED)
- setsid();
-
- /* First duplicate low numbered fds, since it's not safe to duplicate them,
- * they could get replaced. Example: swapping stdout and stderr; without
- * this fd 2 (stderr) would be duplicated into fd 1, thus making both
- * stdout and stderr go to the same fd, which was not the intention. */
- for (fd = 0; fd < stdio_count; fd++) {
- use_fd = pipes[fd][1];
- if (use_fd < 0 || use_fd >= fd)
- continue;
- pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
- if (pipes[fd][1] == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
- }
-
- for (fd = 0; fd < stdio_count; fd++) {
- close_fd = pipes[fd][0];
- use_fd = pipes[fd][1];
-
- if (use_fd < 0) {
- if (fd >= 3)
- continue;
- else {
- /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
- * set
- */
- use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
- close_fd = use_fd;
-
- if (use_fd < 0) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
- }
- }
-
- if (fd == use_fd)
- uv__cloexec_fcntl(use_fd, 0);
- else
- fd = dup2(use_fd, fd);
-
- if (fd == -1) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- if (fd <= 2)
- uv__nonblock_fcntl(fd, 0);
-
- if (close_fd >= stdio_count)
- uv__close(close_fd);
- }
-
- for (fd = 0; fd < stdio_count; fd++) {
- use_fd = pipes[fd][1];
-
- if (use_fd >= stdio_count)
- uv__close(use_fd);
- }
-
- if (options->cwd != NULL && chdir(options->cwd)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
- /* When dropping privileges from root, the `setgroups` call will
- * remove any extraneous groups. If we don't call this, then
- * even though our uid has dropped, we may still have groups
- * that enable us to do super-user things. This will fail if we
- * aren't root, so don't bother checking the return value, this
- * is just done as an optimistic privilege dropping function.
- */
- SAVE_ERRNO(setgroups(0, NULL));
- }
-
- if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- if (options->env != NULL) {
- environ = options->env;
- }
-
- /* Reset signal disposition. Use a hard-coded limit because NSIG
- * is not fixed on Linux: it's either 32, 34 or 64, depending on
- * whether RT signals are enabled. We are not allowed to touch
- * RT signal handlers, glibc uses them internally.
- */
- for (n = 1; n < 32; n += 1) {
- if (n == SIGKILL || n == SIGSTOP)
- continue; /* Can't be changed. */
-
-#if defined(__HAIKU__)
- if (n == SIGKILLTHR)
- continue; /* Can't be changed. */
-#endif
-
- if (SIG_ERR != signal(n, SIG_DFL))
- continue;
-
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
- }
-
- /* Reset signal mask. */
- sigemptyset(&set);
- err = pthread_sigmask(SIG_SETMASK, &set, NULL);
-
- if (err != 0) {
- uv__write_int(error_fd, UV__ERR(err));
- _exit(127);
- }
-
- execvp(options->file, options->args);
- uv__write_int(error_fd, UV__ERR(errno));
- _exit(127);
-}
-#endif
-
-
-int uv_spawn(uv_loop_t* loop,
- uv_process_t* process,
- const uv_process_options_t* options) {
-#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
- /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
- return UV_ENOSYS;
-#else
- int signal_pipe[2] = { -1, -1 };
- int pipes_storage[8][2];
- int (*pipes)[2];
- int stdio_count;
- ssize_t r;
- pid_t pid;
- int err;
- int exec_errorno;
- int i;
- int status;
-
- assert(options->file != NULL);
- assert(!(options->flags & ~(UV_PROCESS_DETACHED |
- UV_PROCESS_SETGID |
- UV_PROCESS_SETUID |
- UV_PROCESS_WINDOWS_HIDE |
- UV_PROCESS_WINDOWS_HIDE_CONSOLE |
- UV_PROCESS_WINDOWS_HIDE_GUI |
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
-
- uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
- QUEUE_INIT(&process->queue);
-
- stdio_count = options->stdio_count;
- if (stdio_count < 3)
- stdio_count = 3;
-
- err = UV_ENOMEM;
- pipes = pipes_storage;
- if (stdio_count > (int) ARRAY_SIZE(pipes_storage))
- pipes = (int (*)[2])uv__malloc(stdio_count * sizeof(*pipes));
-
- if (pipes == NULL)
- goto error;
-
- for (i = 0; i < stdio_count; i++) {
- pipes[i][0] = -1;
- pipes[i][1] = -1;
- }
-
- for (i = 0; i < options->stdio_count; i++) {
- err = uv__process_init_stdio(options->stdio + i, pipes[i]);
- if (err)
- goto error;
- }
-
- /* This pipe is used by the parent to wait until
- * the child has called `execve()`. We need this
- * to avoid the following race condition:
- *
- * if ((pid = fork()) > 0) {
- * kill(pid, SIGTERM);
- * }
- * else if (pid == 0) {
- * execve("/bin/cat", argp, envp);
- * }
- *
- * The parent sends a signal immediately after forking.
- * Since the child may not have called `execve()` yet,
- * there is no telling what process receives the signal,
- * our fork or /bin/cat.
- *
- * To avoid ambiguity, we create a pipe with both ends
- * marked close-on-exec. Then, after the call to `fork()`,
- * the parent polls the read end until it EOFs or errors with EPIPE.
- */
- err = uv__make_pipe(signal_pipe, 0);
- if (err)
- goto error;
-
- uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
-
- /* Acquire write lock to prevent opening new fds in worker threads */
- uv_rwlock_wrlock(&loop->cloexec_lock);
- pid = fork();
-
- if (pid == -1) {
- err = UV__ERR(errno);
- uv_rwlock_wrunlock(&loop->cloexec_lock);
- uv__close(signal_pipe[0]);
- uv__close(signal_pipe[1]);
- goto error;
- }
-
- if (pid == 0) {
- uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
- abort();
- }
-
- /* Release lock in parent process */
- uv_rwlock_wrunlock(&loop->cloexec_lock);
- uv__close(signal_pipe[1]);
-
- process->status = 0;
- exec_errorno = 0;
- do
- r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
- while (r == -1 && errno == EINTR);
-
- if (r == 0)
- ; /* okay, EOF */
- else if (r == sizeof(exec_errorno)) {
- do
- err = waitpid(pid, &status, 0); /* okay, read errorno */
- while (err == -1 && errno == EINTR);
- assert(err == pid);
- } else if (r == -1 && errno == EPIPE) {
- do
- err = waitpid(pid, &status, 0); /* okay, got EPIPE */
- while (err == -1 && errno == EINTR);
- assert(err == pid);
- } else
- abort();
-
- uv__close_nocheckstdio(signal_pipe[0]);
-
- for (i = 0; i < options->stdio_count; i++) {
- err = uv__process_open_stream(options->stdio + i, pipes[i]);
- if (err == 0)
- continue;
-
- while (i--)
- uv__process_close_stream(options->stdio + i);
-
- goto error;
- }
-
- /* Only activate this handle if exec() happened successfully */
- if (exec_errorno == 0) {
- QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
- uv__handle_start(process);
- }
-
- process->pid = pid;
- process->exit_cb = options->exit_cb;
-
- if (pipes != pipes_storage)
- uv__free(pipes);
-
- return exec_errorno;
-
-error:
- if (pipes != NULL) {
- for (i = 0; i < stdio_count; i++) {
- if (i < options->stdio_count)
- if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
- continue;
- if (pipes[i][0] != -1)
- uv__close_nocheckstdio(pipes[i][0]);
- if (pipes[i][1] != -1)
- uv__close_nocheckstdio(pipes[i][1]);
- }
-
- if (pipes != pipes_storage)
- uv__free(pipes);
- }
-
- return err;
-#endif
-}
-
-
-int uv_process_kill(uv_process_t* process, int signum) {
- return uv_kill(process->pid, signum);
-}
-
-
-int uv_kill(int pid, int signum) {
- if (kill(pid, signum))
- return UV__ERR(errno);
- else
- return 0;
-}
-
-
-void uv__process_close(uv_process_t* handle) {
- QUEUE_REMOVE(&handle->queue);
- uv__handle_stop(handle);
- if (QUEUE_EMPTY(&handle->loop->process_handles))
- uv_signal_stop(&handle->loop->child_watcher);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/procfs-exepath.cpp b/wpiutil/src/main/native/libuv/src/unix/procfs-exepath.cpp
deleted file mode 100644
index 00dc021..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/procfs-exepath.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stddef.h>
-#include <unistd.h>
-
-int uv_exepath(char* buffer, size_t* size) {
- ssize_t n;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- n = *size - 1;
- if (n > 0)
- n = readlink("/proc/self/exe", buffer, n);
-
- if (n == -1)
- return UV__ERR(errno);
-
- buffer[n] = '\0';
- *size = n;
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/proctitle.cpp b/wpiutil/src/main/native/libuv/src/unix/proctitle.cpp
deleted file mode 100644
index b09808f..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/proctitle.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-extern void uv__set_process_title_platform_init(void);
-extern void uv__set_process_title(const char* title);
-
-static uv_mutex_t process_title_mutex;
-static uv_once_t process_title_mutex_once = UV_ONCE_INIT;
-static void* args_mem;
-
-static struct {
- char* str;
- size_t len;
-} process_title;
-
-
-static void init_process_title_mutex_once(void) {
- uv_mutex_init(&process_title_mutex);
-#ifdef __APPLE__
- uv__set_process_title_platform_init();
-#endif
-}
-
-
-char** uv_setup_args(int argc, char** argv) {
- char** new_argv;
- size_t size;
- char* s;
- int i;
-
- if (argc <= 0)
- return argv;
-
- /* Calculate how much memory we need for the argv strings. */
- size = 0;
- for (i = 0; i < argc; i++)
- size += strlen(argv[i]) + 1;
-
-#if defined(__MVS__)
- /* argv is not adjacent. So just use argv[0] */
- process_title.str = argv[0];
- process_title.len = strlen(argv[0]);
-#else
- process_title.str = argv[0];
- process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
- assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
-#endif
-
- /* Add space for the argv pointers. */
- size += (argc + 1) * sizeof(char*);
-
- new_argv = (char**)uv__malloc(size);
- if (new_argv == NULL)
- return argv;
- args_mem = new_argv;
-
- /* Copy over the strings and set up the pointer table. */
- s = (char*) &new_argv[argc + 1];
- for (i = 0; i < argc; i++) {
- size = strlen(argv[i]) + 1;
- memcpy(s, argv[i], size);
- new_argv[i] = s;
- s += size;
- }
- new_argv[i] = NULL;
-
- return new_argv;
-}
-
-
-int uv_set_process_title(const char* title) {
- uv_once(&process_title_mutex_once, init_process_title_mutex_once);
- uv_mutex_lock(&process_title_mutex);
-
- if (process_title.len != 0) {
- /* No need to terminate, byte after is always '\0'. */
- strncpy(process_title.str, title, process_title.len);
- uv__set_process_title(title);
- }
-
- uv_mutex_unlock(&process_title_mutex);
-
- return 0;
-}
-
-
-int uv_get_process_title(char* buffer, size_t size) {
- if (buffer == NULL || size == 0)
- return UV_EINVAL;
-
- uv_once(&process_title_mutex_once, init_process_title_mutex_once);
- uv_mutex_lock(&process_title_mutex);
-
- if (size <= process_title.len) {
- uv_mutex_unlock(&process_title_mutex);
- return UV_ENOBUFS;
- }
-
- if (process_title.len != 0)
- memcpy(buffer, process_title.str, process_title.len + 1);
-
- buffer[process_title.len] = '\0';
-
- uv_mutex_unlock(&process_title_mutex);
-
- return 0;
-}
-
-
-UV_DESTRUCTOR(static void free_args_mem(void)) {
- uv__free(args_mem); /* Keep valgrind happy. */
- args_mem = NULL;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/pthread-fixes.cpp b/wpiutil/src/main/native/libuv/src/unix/pthread-fixes.cpp
deleted file mode 100644
index fb17995..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/pthread-fixes.cpp
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Copyright (c) 2013, Sony Mobile Communications AB
- * Copyright (c) 2012, 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.
-*/
-
-/* Android versions < 4.1 have a broken pthread_sigmask. */
-#include <errno.h>
-#include <pthread.h>
-#include <signal.h>
-
-int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
- static int workaround;
- int err;
-
- if (workaround) {
- return sigprocmask(how, set, oset);
- } else {
- err = pthread_sigmask(how, set, oset);
- if (err) {
- if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
- workaround = 1;
- return 0;
- } else {
- return -1;
- }
- }
- }
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/signal.cpp b/wpiutil/src/main/native/libuv/src/unix/signal.cpp
deleted file mode 100644
index ec2639a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/signal.cpp
+++ /dev/null
@@ -1,574 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#ifndef SA_RESTART
-# define SA_RESTART 0
-#endif
-
-typedef struct {
- uv_signal_t* handle;
- int signum;
-} uv__signal_msg_t;
-
-RB_HEAD(uv__signal_tree_s, uv_signal_s);
-
-
-static int uv__signal_unlock(void);
-static int uv__signal_start(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum,
- int oneshot);
-static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
-static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
-static void uv__signal_stop(uv_signal_t* handle);
-static void uv__signal_unregister_handler(int signum);
-
-
-static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
-static struct uv__signal_tree_s uv__signal_tree =
- RB_INITIALIZER(uv__signal_tree);
-static int uv__signal_lock_pipefd[2] = { -1, -1 };
-
-RB_GENERATE_STATIC(uv__signal_tree_s,
- uv_signal_s, tree_entry,
- uv__signal_compare)
-
-static void uv__signal_global_reinit(void);
-
-static void uv__signal_global_init(void) {
- if (uv__signal_lock_pipefd[0] == -1)
- /* pthread_atfork can register before and after handlers, one
- * for each child. This only registers one for the child. That
- * state is both persistent and cumulative, so if we keep doing
- * it the handler functions will be called multiple times. Thus
- * we only want to do it once.
- */
- if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
- abort();
-
- uv__signal_global_reinit();
-}
-
-
-UV_DESTRUCTOR(static void uv__signal_global_fini(void)) {
- /* We can only use signal-safe functions here.
- * That includes read/write and close, fortunately.
- * We do all of this directly here instead of resetting
- * uv__signal_global_init_guard because
- * uv__signal_global_once_init is only called from uv_loop_init
- * and this needs to function in existing loops.
- */
- if (uv__signal_lock_pipefd[0] != -1) {
- uv__close(uv__signal_lock_pipefd[0]);
- uv__signal_lock_pipefd[0] = -1;
- }
-
- if (uv__signal_lock_pipefd[1] != -1) {
- uv__close(uv__signal_lock_pipefd[1]);
- uv__signal_lock_pipefd[1] = -1;
- }
-}
-
-
-static void uv__signal_global_reinit(void) {
- uv__signal_global_fini();
-
- if (uv__make_pipe(uv__signal_lock_pipefd, 0))
- abort();
-
- if (uv__signal_unlock())
- abort();
-}
-
-
-void uv__signal_global_once_init(void) {
- uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
-}
-
-
-static int uv__signal_lock(void) {
- int r;
- char data;
-
- do {
- r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
- } while (r < 0 && errno == EINTR);
-
- return (r < 0) ? -1 : 0;
-}
-
-
-static int uv__signal_unlock(void) {
- int r;
- char data = 42;
-
- do {
- r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
- } while (r < 0 && errno == EINTR);
-
- return (r < 0) ? -1 : 0;
-}
-
-
-static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
- sigset_t new_mask;
-
- if (sigfillset(&new_mask))
- abort();
-
- if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
- abort();
-
- if (uv__signal_lock())
- abort();
-}
-
-
-static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
- if (uv__signal_unlock())
- abort();
-
- if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
- abort();
-}
-
-
-static uv_signal_t* uv__signal_first_handle(int signum) {
- /* This function must be called with the signal lock held. */
- uv_signal_t lookup;
- uv_signal_t* handle;
-
- lookup.signum = signum;
- lookup.flags = 0;
- lookup.loop = NULL;
-
- handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
-
- if (handle != NULL && handle->signum == signum)
- return handle;
-
- return NULL;
-}
-
-
-static void uv__signal_handler(int signum) {
- uv__signal_msg_t msg;
- uv_signal_t* handle;
- int saved_errno;
-
- saved_errno = errno;
- memset(&msg, 0, sizeof msg);
-
- if (uv__signal_lock()) {
- errno = saved_errno;
- return;
- }
-
- for (handle = uv__signal_first_handle(signum);
- handle != NULL && handle->signum == signum;
- handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
- int r;
-
- msg.signum = signum;
- msg.handle = handle;
-
- /* write() should be atomic for small data chunks, so the entire message
- * should be written at once. In theory the pipe could become full, in
- * which case the user is out of luck.
- */
- do {
- r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
- } while (r == -1 && errno == EINTR);
-
- assert(r == sizeof msg ||
- (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
-
- if (r != -1)
- handle->caught_signals++;
- }
-
- uv__signal_unlock();
- errno = saved_errno;
-}
-
-
-static int uv__signal_register_handler(int signum, int oneshot) {
- /* When this function is called, the signal lock must be held. */
- struct sigaction sa;
-
- /* XXX use a separate signal stack? */
- memset(&sa, 0, sizeof(sa));
- if (sigfillset(&sa.sa_mask))
- abort();
- sa.sa_handler = uv__signal_handler;
- sa.sa_flags = SA_RESTART;
- if (oneshot)
- sa.sa_flags |= SA_RESETHAND;
-
- /* XXX save old action so we can restore it later on? */
- if (sigaction(signum, &sa, NULL))
- return UV__ERR(errno);
-
- return 0;
-}
-
-
-static void uv__signal_unregister_handler(int signum) {
- /* When this function is called, the signal lock must be held. */
- struct sigaction sa;
-
- memset(&sa, 0, sizeof(sa));
- sa.sa_handler = SIG_DFL;
-
- /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
- * signal implies that it was successfully registered earlier, so EINVAL
- * should never happen.
- */
- if (sigaction(signum, &sa, NULL))
- abort();
-}
-
-
-static int uv__signal_loop_once_init(uv_loop_t* loop) {
- int err;
-
- /* Return if already initialized. */
- if (loop->signal_pipefd[0] != -1)
- return 0;
-
- err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
- if (err)
- return err;
-
- uv__io_init(&loop->signal_io_watcher,
- uv__signal_event,
- loop->signal_pipefd[0]);
- uv__io_start(loop, &loop->signal_io_watcher, POLLIN);
-
- return 0;
-}
-
-
-int uv__signal_loop_fork(uv_loop_t* loop) {
- uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
- uv__close(loop->signal_pipefd[0]);
- uv__close(loop->signal_pipefd[1]);
- loop->signal_pipefd[0] = -1;
- loop->signal_pipefd[1] = -1;
- return uv__signal_loop_once_init(loop);
-}
-
-
-void uv__signal_loop_cleanup(uv_loop_t* loop) {
- QUEUE* q;
-
- /* Stop all the signal watchers that are still attached to this loop. This
- * ensures that the (shared) signal tree doesn't contain any invalid entries
- * entries, and that signal handlers are removed when appropriate.
- * It's safe to use QUEUE_FOREACH here because the handles and the handle
- * queue are not modified by uv__signal_stop().
- */
- QUEUE_FOREACH(q, &loop->handle_queue) {
- uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
-
- if (handle->type == UV_SIGNAL)
- uv__signal_stop((uv_signal_t*) handle);
- }
-
- if (loop->signal_pipefd[0] != -1) {
- uv__close(loop->signal_pipefd[0]);
- loop->signal_pipefd[0] = -1;
- }
-
- if (loop->signal_pipefd[1] != -1) {
- uv__close(loop->signal_pipefd[1]);
- loop->signal_pipefd[1] = -1;
- }
-}
-
-
-int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
- int err;
-
- err = uv__signal_loop_once_init(loop);
- if (err)
- return err;
-
- uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
- handle->signum = 0;
- handle->caught_signals = 0;
- handle->dispatched_signals = 0;
-
- return 0;
-}
-
-
-void uv__signal_close(uv_signal_t* handle) {
-
- uv__signal_stop(handle);
-
- /* If there are any caught signals "trapped" in the signal pipe, we can't
- * call the close callback yet. Otherwise, add the handle to the finish_close
- * queue.
- */
- if (handle->caught_signals == handle->dispatched_signals) {
- uv__make_close_pending((uv_handle_t*) handle);
- }
-}
-
-
-int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
- return uv__signal_start(handle, signal_cb, signum, 0);
-}
-
-
-int uv_signal_start_oneshot(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum) {
- return uv__signal_start(handle, signal_cb, signum, 1);
-}
-
-
-static int uv__signal_start(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum,
- int oneshot) {
- sigset_t saved_sigmask;
- int err;
- uv_signal_t* first_handle;
-
- assert(!uv__is_closing(handle));
-
- /* If the user supplies signum == 0, then return an error already. If the
- * signum is otherwise invalid then uv__signal_register will find out
- * eventually.
- */
- if (signum == 0)
- return UV_EINVAL;
-
- /* Short circuit: if the signal watcher is already watching {signum} don't
- * go through the process of deregistering and registering the handler.
- * Additionally, this avoids pending signals getting lost in the small
- * time frame that handle->signum == 0.
- */
- if (signum == handle->signum) {
- handle->signal_cb = signal_cb;
- return 0;
- }
-
- /* If the signal handler was already active, stop it first. */
- if (handle->signum != 0) {
- uv__signal_stop(handle);
- }
-
- uv__signal_block_and_lock(&saved_sigmask);
-
- /* If at this point there are no active signal watchers for this signum (in
- * any of the loops), it's time to try and register a handler for it here.
- * Also in case there's only one-shot handlers and a regular handler comes in.
- */
- first_handle = uv__signal_first_handle(signum);
- if (first_handle == NULL ||
- (!oneshot && (first_handle->flags & UV_SIGNAL_ONE_SHOT))) {
- err = uv__signal_register_handler(signum, oneshot);
- if (err) {
- /* Registering the signal handler failed. Must be an invalid signal. */
- uv__signal_unlock_and_unblock(&saved_sigmask);
- return err;
- }
- }
-
- handle->signum = signum;
- if (oneshot)
- handle->flags |= UV_SIGNAL_ONE_SHOT;
-
- RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
-
- uv__signal_unlock_and_unblock(&saved_sigmask);
-
- handle->signal_cb = signal_cb;
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-static void uv__signal_event(uv_loop_t* loop,
- uv__io_t* w,
- unsigned int events) {
- uv__signal_msg_t* msg;
- uv_signal_t* handle;
- char buf[sizeof(uv__signal_msg_t) * 32];
- size_t bytes, end, i;
- int r;
-
- bytes = 0;
- end = 0;
-
- do {
- r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
-
- if (r == -1 && errno == EINTR)
- continue;
-
- if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- /* If there are bytes in the buffer already (which really is extremely
- * unlikely if possible at all) we can't exit the function here. We'll
- * spin until more bytes are read instead.
- */
- if (bytes > 0)
- continue;
-
- /* Otherwise, there was nothing there. */
- return;
- }
-
- /* Other errors really should never happen. */
- if (r == -1)
- abort();
-
- bytes += r;
-
- /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
- end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
-
- for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
- msg = (uv__signal_msg_t*) (buf + i);
- handle = msg->handle;
-
- if (msg->signum == handle->signum) {
- assert(!(handle->flags & UV_HANDLE_CLOSING));
- handle->signal_cb(handle, handle->signum);
- }
-
- handle->dispatched_signals++;
-
- if (handle->flags & UV_SIGNAL_ONE_SHOT)
- uv__signal_stop(handle);
-
- /* If uv_close was called while there were caught signals that were not
- * yet dispatched, the uv__finish_close was deferred. Make close pending
- * now if this has happened.
- */
- if ((handle->flags & UV_HANDLE_CLOSING) &&
- (handle->caught_signals == handle->dispatched_signals)) {
- uv__make_close_pending((uv_handle_t*) handle);
- }
- }
-
- bytes -= end;
-
- /* If there are any "partial" messages left, move them to the start of the
- * the buffer, and spin. This should not happen.
- */
- if (bytes) {
- memmove(buf, buf + end, bytes);
- continue;
- }
- } while (end == sizeof buf);
-}
-
-
-static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
- int f1;
- int f2;
- /* Compare signums first so all watchers with the same signnum end up
- * adjacent.
- */
- if (w1->signum < w2->signum) return -1;
- if (w1->signum > w2->signum) return 1;
-
- /* Handlers without UV_SIGNAL_ONE_SHOT set will come first, so if the first
- * handler returned is a one-shot handler, the rest will be too.
- */
- f1 = w1->flags & UV_SIGNAL_ONE_SHOT;
- f2 = w2->flags & UV_SIGNAL_ONE_SHOT;
- if (f1 < f2) return -1;
- if (f1 > f2) return 1;
-
- /* Sort by loop pointer, so we can easily look up the first item after
- * { .signum = x, .loop = NULL }.
- */
- if (w1->loop < w2->loop) return -1;
- if (w1->loop > w2->loop) return 1;
-
- if (w1 < w2) return -1;
- if (w1 > w2) return 1;
-
- return 0;
-}
-
-
-int uv_signal_stop(uv_signal_t* handle) {
- assert(!uv__is_closing(handle));
- uv__signal_stop(handle);
- return 0;
-}
-
-
-static void uv__signal_stop(uv_signal_t* handle) {
- uv_signal_t* removed_handle;
- sigset_t saved_sigmask;
- uv_signal_t* first_handle;
- int rem_oneshot;
- int first_oneshot;
- int ret;
-
- /* If the watcher wasn't started, this is a no-op. */
- if (handle->signum == 0)
- return;
-
- uv__signal_block_and_lock(&saved_sigmask);
-
- removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
- assert(removed_handle == handle);
- (void) removed_handle;
-
- /* Check if there are other active signal watchers observing this signal. If
- * not, unregister the signal handler.
- */
- first_handle = uv__signal_first_handle(handle->signum);
- if (first_handle == NULL) {
- uv__signal_unregister_handler(handle->signum);
- } else {
- rem_oneshot = handle->flags & UV_SIGNAL_ONE_SHOT;
- first_oneshot = first_handle->flags & UV_SIGNAL_ONE_SHOT;
- if (first_oneshot && !rem_oneshot) {
- ret = uv__signal_register_handler(handle->signum, 1);
- assert(ret == 0);
- (void) ret;
- }
- }
-
- uv__signal_unlock_and_unblock(&saved_sigmask);
-
- handle->signum = 0;
- uv__handle_stop(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/spinlock.h b/wpiutil/src/main/native/libuv/src/unix/spinlock.h
deleted file mode 100644
index a20c83c..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/spinlock.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, 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 THIS SOFTWARE.
- */
-
-#ifndef UV_SPINLOCK_H_
-#define UV_SPINLOCK_H_
-
-#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
-#include "atomic-ops.h"
-
-#define UV_SPINLOCK_INITIALIZER { 0 }
-
-typedef struct {
- int lock;
-} uv_spinlock_t;
-
-UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
-UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
-UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
-UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
-
-UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
- ACCESS_ONCE(int, spinlock->lock) = 0;
-}
-
-UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
- while (!uv_spinlock_trylock(spinlock)) cpu_relax();
-}
-
-UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
- ACCESS_ONCE(int, spinlock->lock) = 0;
-}
-
-UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
- /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
- * Not really critical until we have locks that are (frequently) contended
- * for by several threads.
- */
- return 0 == cmpxchgi(&spinlock->lock, 0, 1);
-}
-
-#endif /* UV_SPINLOCK_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/unix/stream.cpp b/wpiutil/src/main/native/libuv/src/unix/stream.cpp
deleted file mode 100644
index f3a8e66..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/stream.cpp
+++ /dev/null
@@ -1,1689 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <limits.h> /* IOV_MAX */
-
-#if defined(__APPLE__)
-# include <sys/event.h>
-# include <sys/time.h>
-# include <sys/select.h>
-
-/* Forward declaration */
-typedef struct uv__stream_select_s uv__stream_select_t;
-
-struct uv__stream_select_s {
- uv_stream_t* stream;
- uv_thread_t thread;
- uv_sem_t close_sem;
- uv_sem_t async_sem;
- uv_async_t async;
- int events;
- int fake_fd;
- int int_fd;
- int fd;
- fd_set* sread;
- size_t sread_sz;
- fd_set* swrite;
- size_t swrite_sz;
-};
-
-/* Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
- * EPROTOTYPE can be returned while trying to write to a socket that is
- * shutting down. If we retry the write, we should get the expected EPIPE
- * instead.
- */
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR || errno == EPROTOTYPE)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS || \
- (errno == EMSGSIZE && send_handle != NULL))
-#else
-# define RETRY_ON_WRITE_ERROR(errno) (errno == EINTR)
-# define IS_TRANSIENT_WRITE_ERROR(errno, send_handle) \
- (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
-#endif /* defined(__APPLE__) */
-
-static void uv__stream_connect(uv_stream_t*);
-static void uv__write(uv_stream_t* stream);
-static void uv__read(uv_stream_t* stream);
-static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
-static void uv__write_callbacks(uv_stream_t* stream);
-static size_t uv__write_req_size(uv_write_t* req);
-
-
-void uv__stream_init(uv_loop_t* loop,
- uv_stream_t* stream,
- uv_handle_type type) {
- int err;
-
- uv__handle_init(loop, (uv_handle_t*)stream, type);
- stream->read_cb = NULL;
- stream->alloc_cb = NULL;
- stream->close_cb = NULL;
- stream->connection_cb = NULL;
- stream->connect_req = NULL;
- stream->shutdown_req = NULL;
- stream->accepted_fd = -1;
- stream->queued_fds = NULL;
- stream->delayed_error = 0;
- QUEUE_INIT(&stream->write_queue);
- QUEUE_INIT(&stream->write_completed_queue);
- stream->write_queue_size = 0;
-
- if (loop->emfile_fd == -1) {
- err = uv__open_cloexec("/dev/null", O_RDONLY);
- if (err < 0)
- /* In the rare case that "/dev/null" isn't mounted open "/"
- * instead.
- */
- err = uv__open_cloexec("/", O_RDONLY);
- if (err >= 0)
- loop->emfile_fd = err;
- }
-
-#if defined(__APPLE__)
- stream->select = NULL;
-#endif /* defined(__APPLE_) */
-
- uv__io_init(&stream->io_watcher, uv__stream_io, -1);
-}
-
-
-static void uv__stream_osx_interrupt_select(uv_stream_t* stream) {
-#if defined(__APPLE__)
- /* Notify select() thread about state change */
- uv__stream_select_t* s;
- int r;
-
- s = (uv__stream_select_t*)stream->select;
- if (s == NULL)
- return;
-
- /* Interrupt select() loop
- * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will
- * emit read event on other side
- */
- do
- r = write(s->fake_fd, "x", 1);
- while (r == -1 && errno == EINTR);
-
- assert(r == 1);
-#else /* !defined(__APPLE__) */
- /* No-op on any other platform */
-#endif /* !defined(__APPLE__) */
-}
-
-
-#if defined(__APPLE__)
-static void uv__stream_osx_select(void* arg) {
- uv_stream_t* stream;
- uv__stream_select_t* s;
- char buf[1024];
- int events;
- int fd;
- int r;
- int max_fd;
-
- stream = (uv_stream_t*)arg;
- s = (uv__stream_select_t*)stream->select;
- fd = s->fd;
-
- if (fd > s->int_fd)
- max_fd = fd;
- else
- max_fd = s->int_fd;
-
- while (1) {
- /* Terminate on semaphore */
- if (uv_sem_trywait(&s->close_sem) == 0)
- break;
-
- /* Watch fd using select(2) */
- memset(s->sread, 0, s->sread_sz);
- memset(s->swrite, 0, s->swrite_sz);
-
- if (uv__io_active(&stream->io_watcher, POLLIN))
- FD_SET(fd, s->sread);
- if (uv__io_active(&stream->io_watcher, POLLOUT))
- FD_SET(fd, s->swrite);
- FD_SET(s->int_fd, s->sread);
-
- /* Wait indefinitely for fd events */
- r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
- if (r == -1) {
- if (errno == EINTR)
- continue;
-
- /* XXX: Possible?! */
- abort();
- }
-
- /* Ignore timeouts */
- if (r == 0)
- continue;
-
- /* Empty socketpair's buffer in case of interruption */
- if (FD_ISSET(s->int_fd, s->sread))
- while (1) {
- r = read(s->int_fd, buf, sizeof(buf));
-
- if (r == sizeof(buf))
- continue;
-
- if (r != -1)
- break;
-
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- break;
-
- if (errno == EINTR)
- continue;
-
- abort();
- }
-
- /* Handle events */
- events = 0;
- if (FD_ISSET(fd, s->sread))
- events |= POLLIN;
- if (FD_ISSET(fd, s->swrite))
- events |= POLLOUT;
-
- assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
- if (events != 0) {
- ACCESS_ONCE(int, s->events) = events;
-
- uv_async_send(&s->async);
- uv_sem_wait(&s->async_sem);
-
- /* Should be processed at this stage */
- assert((s->events == 0) || (stream->flags & UV_HANDLE_CLOSING));
- }
- }
-}
-
-
-static void uv__stream_osx_select_cb(uv_async_t* handle) {
- uv__stream_select_t* s;
- uv_stream_t* stream;
- int events;
-
- s = container_of(handle, uv__stream_select_t, async);
- stream = s->stream;
-
- /* Get and reset stream's events */
- events = s->events;
- ACCESS_ONCE(int, s->events) = 0;
-
- assert(events != 0);
- assert(events == (events & (POLLIN | POLLOUT)));
-
- /* Invoke callback on event-loop */
- if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN))
- uv__stream_io(stream->loop, &stream->io_watcher, POLLIN);
-
- if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
- uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT);
-
- if (stream->flags & UV_HANDLE_CLOSING)
- return;
-
- /* NOTE: It is important to do it here, otherwise `select()` might be called
- * before the actual `uv__read()`, leading to the blocking syscall
- */
- uv_sem_post(&s->async_sem);
-}
-
-
-static void uv__stream_osx_cb_close(uv_handle_t* async) {
- uv__stream_select_t* s;
-
- s = container_of(async, uv__stream_select_t, async);
- uv__free(s);
-}
-
-
-int uv__stream_try_select(uv_stream_t* stream, int* fd) {
- /*
- * kqueue doesn't work with some files from /dev mount on osx.
- * select(2) in separate thread for those fds
- */
-
- struct kevent filter[1];
- struct kevent events[1];
- struct timespec timeout;
- uv__stream_select_t* s;
- int fds[2];
- int err;
- int ret;
- int kq;
- int old_fd;
- int max_fd;
- size_t sread_sz;
- size_t swrite_sz;
-
- kq = kqueue();
- if (kq == -1) {
- perror("(libuv) kqueue()");
- return UV__ERR(errno);
- }
-
- EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
-
- /* Use small timeout, because we only want to capture EINVALs */
- timeout.tv_sec = 0;
- timeout.tv_nsec = 1;
-
- do
- ret = kevent(kq, filter, 1, events, 1, &timeout);
- while (ret == -1 && errno == EINTR);
-
- uv__close(kq);
-
- if (ret == -1)
- return UV__ERR(errno);
-
- if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL)
- return 0;
-
- /* At this point we definitely know that this fd won't work with kqueue */
-
- /*
- * Create fds for io watcher and to interrupt the select() loop.
- * NOTE: do it ahead of malloc below to allocate enough space for fd_sets
- */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
- return UV__ERR(errno);
-
- max_fd = *fd;
- if (fds[1] > max_fd)
- max_fd = fds[1];
-
- sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY;
- swrite_sz = sread_sz;
-
- s = (uv__stream_select_t*)uv__malloc(sizeof(*s) + sread_sz + swrite_sz);
- if (s == NULL) {
- err = UV_ENOMEM;
- goto failed_malloc;
- }
-
- s->events = 0;
- s->fd = *fd;
- s->sread = (fd_set*) ((char*) s + sizeof(*s));
- s->sread_sz = sread_sz;
- s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
- s->swrite_sz = swrite_sz;
-
- err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
- if (err)
- goto failed_async_init;
-
- s->async.flags |= UV_HANDLE_INTERNAL;
- uv__handle_unref(&s->async);
-
- err = uv_sem_init(&s->close_sem, 0);
- if (err != 0)
- goto failed_close_sem_init;
-
- err = uv_sem_init(&s->async_sem, 0);
- if (err != 0)
- goto failed_async_sem_init;
-
- s->fake_fd = fds[0];
- s->int_fd = fds[1];
-
- old_fd = *fd;
- s->stream = stream;
- stream->select = s;
- *fd = s->fake_fd;
-
- err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
- if (err != 0)
- goto failed_thread_create;
-
- return 0;
-
-failed_thread_create:
- s->stream = NULL;
- stream->select = NULL;
- *fd = old_fd;
-
- uv_sem_destroy(&s->async_sem);
-
-failed_async_sem_init:
- uv_sem_destroy(&s->close_sem);
-
-failed_close_sem_init:
- uv__close(fds[0]);
- uv__close(fds[1]);
- uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
- return err;
-
-failed_async_init:
- uv__free(s);
-
-failed_malloc:
- uv__close(fds[0]);
- uv__close(fds[1]);
-
- return err;
-}
-#endif /* defined(__APPLE__) */
-
-
-int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
-#if defined(__APPLE__)
- int enable;
-#endif
-
- if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd))
- return UV_EBUSY;
-
- assert(fd >= 0);
- stream->flags |= flags;
-
- if (stream->type == UV_TCP) {
- if ((stream->flags & UV_HANDLE_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
- return UV__ERR(errno);
-
- /* TODO Use delay the user passed in. */
- if ((stream->flags & UV_HANDLE_TCP_KEEPALIVE) &&
- uv__tcp_keepalive(fd, 1, 60)) {
- return UV__ERR(errno);
- }
- }
-
-#if defined(__APPLE__)
- enable = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
- errno != ENOTSOCK &&
- errno != EINVAL) {
- return UV__ERR(errno);
- }
-#endif
-
- stream->io_watcher.fd = fd;
-
- return 0;
-}
-
-
-void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
- uv_write_t* req;
- QUEUE* q;
- while (!QUEUE_EMPTY(&stream->write_queue)) {
- q = QUEUE_HEAD(&stream->write_queue);
- QUEUE_REMOVE(q);
-
- req = QUEUE_DATA(q, uv_write_t, queue);
- req->error = error;
-
- QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
- }
-}
-
-
-void uv__stream_destroy(uv_stream_t* stream) {
- assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
- assert(stream->flags & UV_HANDLE_CLOSED);
-
- if (stream->connect_req) {
- uv__req_unregister(stream->loop, stream->connect_req);
- stream->connect_req->cb(stream->connect_req, UV_ECANCELED);
- stream->connect_req = NULL;
- }
-
- uv__stream_flush_write_queue(stream, UV_ECANCELED);
- uv__write_callbacks(stream);
-
- if (stream->shutdown_req) {
- /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
- * fait accompli at this point. Maybe we should revisit this in v0.11.
- * A possible reason for leaving it unchanged is that it informs the
- * callee that the handle has been destroyed.
- */
- uv__req_unregister(stream->loop, stream->shutdown_req);
- stream->shutdown_req->cb(stream->shutdown_req, UV_ECANCELED);
- stream->shutdown_req = NULL;
- }
-
- assert(stream->write_queue_size == 0);
-}
-
-
-/* Implements a best effort approach to mitigating accept() EMFILE errors.
- * We have a spare file descriptor stashed away that we close to get below
- * the EMFILE limit. Next, we accept all pending connections and close them
- * immediately to signal the clients that we're overloaded - and we are, but
- * we still keep on trucking.
- *
- * There is one caveat: it's not reliable in a multi-threaded environment.
- * The file descriptor limit is per process. Our party trick fails if another
- * thread opens a file or creates a socket in the time window between us
- * calling close() and accept().
- */
-static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
- int err;
- int emfile_fd;
-
- if (loop->emfile_fd == -1)
- return UV_EMFILE;
-
- uv__close(loop->emfile_fd);
- loop->emfile_fd = -1;
-
- do {
- err = uv__accept(accept_fd);
- if (err >= 0)
- uv__close(err);
- } while (err >= 0 || err == UV_EINTR);
-
- emfile_fd = uv__open_cloexec("/", O_RDONLY);
- if (emfile_fd >= 0)
- loop->emfile_fd = emfile_fd;
-
- return err;
-}
-
-
-#if defined(UV_HAVE_KQUEUE)
-# define UV_DEC_BACKLOG(w) w->rcount--;
-#else
-# define UV_DEC_BACKLOG(w) /* no-op */
-#endif /* defined(UV_HAVE_KQUEUE) */
-
-
-void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- uv_stream_t* stream;
- int err;
-
- stream = container_of(w, uv_stream_t, io_watcher);
- assert(events & POLLIN);
- assert(stream->accepted_fd == -1);
- assert(!(stream->flags & UV_HANDLE_CLOSING));
-
- uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
-
- /* connection_cb can close the server socket while we're
- * in the loop so check it on each iteration.
- */
- while (uv__stream_fd(stream) != -1) {
- assert(stream->accepted_fd == -1);
-
-#if defined(UV_HAVE_KQUEUE)
- if (w->rcount <= 0)
- return;
-#endif /* defined(UV_HAVE_KQUEUE) */
-
- err = uv__accept(uv__stream_fd(stream));
- if (err < 0) {
- if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
- return; /* Not an error. */
-
- if (err == UV_ECONNABORTED)
- continue; /* Ignore. Nothing we can do about that. */
-
- if (err == UV_EMFILE || err == UV_ENFILE) {
- err = uv__emfile_trick(loop, uv__stream_fd(stream));
- if (err == UV_EAGAIN || err == UV__ERR(EWOULDBLOCK))
- break;
- }
-
- stream->connection_cb(stream, err);
- continue;
- }
-
- UV_DEC_BACKLOG(w)
- stream->accepted_fd = err;
- stream->connection_cb(stream, 0);
-
- if (stream->accepted_fd != -1) {
- /* The user hasn't yet accepted called uv_accept() */
- uv__io_stop(loop, &stream->io_watcher, POLLIN);
- return;
- }
-
- if (stream->type == UV_TCP &&
- (stream->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
- /* Give other processes a chance to accept connections. */
- struct timespec timeout = { 0, 1 };
- nanosleep(&timeout, NULL);
- }
- }
-}
-
-
-#undef UV_DEC_BACKLOG
-
-
-int uv_accept(uv_stream_t* server, uv_stream_t* client) {
- int err;
-
- assert(server->loop == client->loop);
-
- if (server->accepted_fd == -1)
- return UV_EAGAIN;
-
- switch (client->type) {
- case UV_NAMED_PIPE:
- case UV_TCP:
- err = uv__stream_open(client,
- server->accepted_fd,
- UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- if (err) {
- /* TODO handle error */
- uv__close(server->accepted_fd);
- goto done;
- }
- break;
-
- case UV_UDP:
- err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
- if (err) {
- uv__close(server->accepted_fd);
- goto done;
- }
- break;
-
- default:
- return UV_EINVAL;
- }
-
- client->flags |= UV_HANDLE_BOUND;
-
-done:
- /* Process queued fds */
- if (server->queued_fds != NULL) {
- uv__stream_queued_fds_t* queued_fds;
-
- queued_fds = (uv__stream_queued_fds_t*)(server->queued_fds);
-
- /* Read first */
- server->accepted_fd = queued_fds->fds[0];
-
- /* All read, free */
- assert(queued_fds->offset > 0);
- if (--queued_fds->offset == 0) {
- uv__free(queued_fds);
- server->queued_fds = NULL;
- } else {
- /* Shift rest */
- memmove(queued_fds->fds,
- queued_fds->fds + 1,
- queued_fds->offset * sizeof(*queued_fds->fds));
- }
- } else {
- server->accepted_fd = -1;
- if (err == 0)
- uv__io_start(server->loop, &server->io_watcher, POLLIN);
- }
- return err;
-}
-
-
-int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
- int err;
-
- switch (stream->type) {
- case UV_TCP:
- err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
- break;
-
- case UV_NAMED_PIPE:
- err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
- break;
-
- default:
- err = UV_EINVAL;
- }
-
- if (err == 0)
- uv__handle_start(stream);
-
- return err;
-}
-
-
-static void uv__drain(uv_stream_t* stream) {
- uv_shutdown_t* req;
- int err;
-
- assert(QUEUE_EMPTY(&stream->write_queue));
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- uv__stream_osx_interrupt_select(stream);
-
- /* Shutdown? */
- if ((stream->flags & UV_HANDLE_SHUTTING) &&
- !(stream->flags & UV_HANDLE_CLOSING) &&
- !(stream->flags & UV_HANDLE_SHUT)) {
- assert(stream->shutdown_req);
-
- req = stream->shutdown_req;
- stream->shutdown_req = NULL;
- stream->flags &= ~UV_HANDLE_SHUTTING;
- uv__req_unregister(stream->loop, req);
-
- err = 0;
- if (shutdown(uv__stream_fd(stream), SHUT_WR))
- err = UV__ERR(errno);
-
- if (err == 0)
- stream->flags |= UV_HANDLE_SHUT;
-
- if (req->cb != NULL)
- req->cb(req, err);
- }
-}
-
-
-static ssize_t uv__writev(int fd, struct iovec* vec, size_t n) {
- if (n == 1)
- return write(fd, vec->iov_base, vec->iov_len);
- else
- return writev(fd, vec, n);
-}
-
-
-static size_t uv__write_req_size(uv_write_t* req) {
- size_t size;
-
- assert(req->bufs != NULL);
- size = uv__count_bufs(req->bufs + req->write_index,
- req->nbufs - req->write_index);
- assert(req->handle->write_queue_size >= size);
-
- return size;
-}
-
-
-/* Returns 1 if all write request data has been written, or 0 if there is still
- * more data to write.
- *
- * Note: the return value only says something about the *current* request.
- * There may still be other write requests sitting in the queue.
- */
-static int uv__write_req_update(uv_stream_t* stream,
- uv_write_t* req,
- size_t n) {
- uv_buf_t* buf;
- size_t len;
-
- assert(n <= stream->write_queue_size);
- stream->write_queue_size -= n;
-
- buf = req->bufs + req->write_index;
-
- do {
- len = n < buf->len ? n : buf->len;
- buf->base += len;
- buf->len -= len;
- buf += (buf->len == 0); /* Advance to next buffer if this one is empty. */
- n -= len;
- } while (n > 0);
-
- req->write_index = buf - req->bufs;
-
- return req->write_index == req->nbufs;
-}
-
-
-static void uv__write_req_finish(uv_write_t* req) {
- uv_stream_t* stream = req->handle;
-
- /* Pop the req off tcp->write_queue. */
- QUEUE_REMOVE(&req->queue);
-
- /* Only free when there was no error. On error, we touch up write_queue_size
- * right before making the callback. The reason we don't do that right away
- * is that a write_queue_size > 0 is our only way to signal to the user that
- * they should stop writing - which they should if we got an error. Something
- * to revisit in future revisions of the libuv API.
- */
- if (req->error == 0) {
- if (req->bufs != req->bufsml)
- uv__free(req->bufs);
- req->bufs = NULL;
- }
-
- /* Add it to the write_completed_queue where it will have its
- * callback called in the near future.
- */
- QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
- uv__io_feed(stream->loop, &stream->io_watcher);
-}
-
-
-static int uv__handle_fd(uv_handle_t* handle) {
- switch (handle->type) {
- case UV_NAMED_PIPE:
- case UV_TCP:
- return ((uv_stream_t*) handle)->io_watcher.fd;
-
- case UV_UDP:
- return ((uv_udp_t*) handle)->io_watcher.fd;
-
- default:
- return -1;
- }
-}
-
-static void uv__write(uv_stream_t* stream) {
- struct iovec* iov;
- QUEUE* q;
- uv_write_t* req;
- int iovmax;
- int iovcnt;
- ssize_t n;
- int err;
-
-start:
-
- assert(uv__stream_fd(stream) >= 0);
-
- if (QUEUE_EMPTY(&stream->write_queue))
- return;
-
- q = QUEUE_HEAD(&stream->write_queue);
- req = QUEUE_DATA(q, uv_write_t, queue);
- assert(req->handle == stream);
-
- /*
- * Cast to iovec. We had to have our own uv_buf_t instead of iovec
- * because Windows's WSABUF is not an iovec.
- */
- assert(sizeof(uv_buf_t) == sizeof(struct iovec));
- iov = (struct iovec*) &(req->bufs[req->write_index]);
- iovcnt = req->nbufs - req->write_index;
-
- iovmax = uv__getiovmax();
-
- /* Limit iov count to avoid EINVALs from writev() */
- if (iovcnt > iovmax)
- iovcnt = iovmax;
-
- /*
- * Now do the actual writev. Note that we've been updating the pointers
- * inside the iov each time we write. So there is no need to offset it.
- */
-
- if (req->send_handle) {
- int fd_to_send;
- struct msghdr msg;
- struct cmsghdr *cmsg;
- union {
- char data[64];
- struct cmsghdr alias;
- } scratch;
-
- if (uv__is_closing(req->send_handle)) {
- err = UV_EBADF;
- goto error;
- }
-
- fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
-
- memset(&scratch, 0, sizeof(scratch));
-
- assert(fd_to_send >= 0);
-
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- msg.msg_iov = iov;
- msg.msg_iovlen = iovcnt;
- msg.msg_flags = 0;
-
- msg.msg_control = &scratch.alias;
- msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
-
- /* silence aliasing warning */
- {
- void* pv = CMSG_DATA(cmsg);
- int* pi = (int*)pv;
- *pi = fd_to_send;
- }
-
- do
- n = sendmsg(uv__stream_fd(stream), &msg, 0);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
-
- /* Ensure the handle isn't sent again in case this is a partial write. */
- if (n >= 0)
- req->send_handle = NULL;
- } else {
- do
- n = uv__writev(uv__stream_fd(stream), iov, iovcnt);
- while (n == -1 && RETRY_ON_WRITE_ERROR(errno));
- }
-
- if (n == -1 && !IS_TRANSIENT_WRITE_ERROR(errno, req->send_handle)) {
- err = UV__ERR(errno);
- goto error;
- }
-
- if (n >= 0 && uv__write_req_update(stream, req, n)) {
- uv__write_req_finish(req);
- return; /* TODO(bnoordhuis) Start trying to write the next request. */
- }
-
- /* If this is a blocking stream, try again. */
- if (stream->flags & UV_HANDLE_BLOCKING_WRITES)
- goto start;
-
- /* We're not done. */
- uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
-
- /* Notify select() thread about state change */
- uv__stream_osx_interrupt_select(stream);
-
- return;
-
-error:
- req->error = err;
- uv__write_req_finish(req);
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- if (!uv__io_active(&stream->io_watcher, POLLIN))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
-}
-
-
-static void uv__write_callbacks(uv_stream_t* stream) {
- uv_write_t* req;
- QUEUE* q;
- QUEUE pq;
-
- if (QUEUE_EMPTY(&stream->write_completed_queue))
- return;
-
- QUEUE_MOVE(&stream->write_completed_queue, &pq);
-
- while (!QUEUE_EMPTY(&pq)) {
- /* Pop a req off write_completed_queue. */
- q = QUEUE_HEAD(&pq);
- req = QUEUE_DATA(q, uv_write_t, queue);
- QUEUE_REMOVE(q);
- uv__req_unregister(stream->loop, req);
-
- if (req->bufs != NULL) {
- stream->write_queue_size -= uv__write_req_size(req);
- if (req->bufs != req->bufsml)
- uv__free(req->bufs);
- req->bufs = NULL;
- }
-
- /* NOTE: call callback AFTER freeing the request data. */
- if (req->cb)
- req->cb(req, req->error);
- }
-}
-
-
-uv_handle_type uv__handle_type(int fd) {
- struct sockaddr_storage ss;
- socklen_t sslen;
- socklen_t len;
- int type;
-
- memset(&ss, 0, sizeof(ss));
- sslen = sizeof(ss);
-
- if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
- return UV_UNKNOWN_HANDLE;
-
- len = sizeof type;
-
- if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
- return UV_UNKNOWN_HANDLE;
-
- if (type == SOCK_STREAM) {
-#if defined(_AIX) || defined(__DragonFly__)
- /* on AIX/DragonFly the getsockname call returns an empty sa structure
- * for sockets of type AF_UNIX. For all other types it will
- * return a properly filled in structure.
- */
- if (sslen == 0)
- return UV_NAMED_PIPE;
-#endif
- switch (ss.ss_family) {
- case AF_UNIX:
- return UV_NAMED_PIPE;
- case AF_INET:
- case AF_INET6:
- return UV_TCP;
- }
- }
-
- if (type == SOCK_DGRAM &&
- (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
- return UV_UDP;
-
- return UV_UNKNOWN_HANDLE;
-}
-
-
-static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
- stream->flags |= UV_HANDLE_READ_EOF;
- uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
- stream->read_cb(stream, UV_EOF, buf);
- stream->flags &= ~UV_HANDLE_READING;
-}
-
-
-static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
- uv__stream_queued_fds_t* queued_fds;
- unsigned int queue_size;
-
- queued_fds = (uv__stream_queued_fds_t*)stream->queued_fds;
- if (queued_fds == NULL) {
- queue_size = 8;
- queued_fds = (uv__stream_queued_fds_t*)
- uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) +
- sizeof(*queued_fds));
- if (queued_fds == NULL)
- return UV_ENOMEM;
- queued_fds->size = queue_size;
- queued_fds->offset = 0;
- stream->queued_fds = queued_fds;
-
- /* Grow */
- } else if (queued_fds->size == queued_fds->offset) {
- queue_size = queued_fds->size + 8;
- queued_fds = (uv__stream_queued_fds_t*)
- uv__realloc(queued_fds, (queue_size - 1) * sizeof(*queued_fds->fds) +
- sizeof(*queued_fds));
-
- /*
- * Allocation failure, report back.
- * NOTE: if it is fatal - sockets will be closed in uv__stream_close
- */
- if (queued_fds == NULL)
- return UV_ENOMEM;
- queued_fds->size = queue_size;
- stream->queued_fds = queued_fds;
- }
-
- /* Put fd in a queue */
- queued_fds->fds[queued_fds->offset++] = fd;
-
- return 0;
-}
-
-
-#define UV__CMSG_FD_COUNT 64
-#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
-
-
-static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
- struct cmsghdr* cmsg;
-
- for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
- char* start;
- char* end;
- int err;
- void* pv;
- int* pi;
- unsigned int i;
- unsigned int count;
-
- if (cmsg->cmsg_type != SCM_RIGHTS) {
- fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
- cmsg->cmsg_type);
- continue;
- }
-
- /* silence aliasing warning */
- pv = CMSG_DATA(cmsg);
- pi = (int*)pv;
-
- /* Count available fds */
- start = (char*) cmsg;
- end = (char*) cmsg + cmsg->cmsg_len;
- count = 0;
- while (start + CMSG_LEN(count * sizeof(*pi)) < end)
- count++;
- assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
-
- for (i = 0; i < count; i++) {
- /* Already has accepted fd, queue now */
- if (stream->accepted_fd != -1) {
- err = uv__stream_queue_fd(stream, pi[i]);
- if (err != 0) {
- /* Close rest */
- for (; i < count; i++)
- uv__close(pi[i]);
- return err;
- }
- } else {
- stream->accepted_fd = pi[i];
- }
- }
- }
-
- return 0;
-}
-
-
-#ifdef __clang__
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wgnu-folding-constant"
-# pragma clang diagnostic ignored "-Wvla-extension"
-#endif
-
-static void uv__read(uv_stream_t* stream) {
- uv_buf_t buf;
- ssize_t nread;
- struct msghdr msg;
- char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
- int count;
- int err;
- int is_ipc;
-
- stream->flags &= ~UV_HANDLE_READ_PARTIAL;
-
- /* Prevent loop starvation when the data comes in as fast as (or faster than)
- * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
- */
- count = 32;
-
- is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
-
- /* XXX: Maybe instead of having UV_HANDLE_READING we just test if
- * tcp->read_cb is NULL or not?
- */
- while (stream->read_cb
- && (stream->flags & UV_HANDLE_READING)
- && (count-- > 0)) {
- assert(stream->alloc_cb != NULL);
-
- buf = uv_buf_init(NULL, 0);
- stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
- if (buf.base == NULL || buf.len == 0) {
- /* User indicates it can't or won't handle the read. */
- stream->read_cb(stream, UV_ENOBUFS, &buf);
- return;
- }
-
- assert(buf.base != NULL);
- assert(uv__stream_fd(stream) >= 0);
-
- if (!is_ipc) {
- do {
- nread = read(uv__stream_fd(stream), buf.base, buf.len);
- }
- while (nread < 0 && errno == EINTR);
- } else {
- /* ipc uses recvmsg */
- msg.msg_flags = 0;
- msg.msg_iov = (struct iovec*) &buf;
- msg.msg_iovlen = 1;
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- /* Set up to receive a descriptor even if one isn't in the message */
- msg.msg_controllen = sizeof(cmsg_space);
- msg.msg_control = cmsg_space;
-
- do {
- nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
- }
- while (nread < 0 && errno == EINTR);
- }
-
- if (nread < 0) {
- /* Error */
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- /* Wait for the next one. */
- if (stream->flags & UV_HANDLE_READING) {
- uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
- uv__stream_osx_interrupt_select(stream);
- }
- stream->read_cb(stream, 0, &buf);
-#if defined(__CYGWIN__) || defined(__MSYS__)
- } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) {
- uv__stream_eof(stream, &buf);
- return;
-#endif
- } else {
- /* Error. User should call uv_close(). */
- stream->read_cb(stream, UV__ERR(errno), &buf);
- if (stream->flags & UV_HANDLE_READING) {
- stream->flags &= ~UV_HANDLE_READING;
- uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
- }
- }
- return;
- } else if (nread == 0) {
- uv__stream_eof(stream, &buf);
- return;
- } else {
- /* Successful read */
- ssize_t buflen = buf.len;
-
- if (is_ipc) {
- err = uv__stream_recv_cmsg(stream, &msg);
- if (err != 0) {
- stream->read_cb(stream, err, &buf);
- return;
- }
- }
-
-#if defined(__MVS__)
- if (is_ipc && msg.msg_controllen > 0) {
- uv_buf_t blankbuf;
- int nread;
- struct iovec *old;
-
- blankbuf.base = 0;
- blankbuf.len = 0;
- old = msg.msg_iov;
- msg.msg_iov = (struct iovec*) &blankbuf;
- nread = 0;
- do {
- nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
- err = uv__stream_recv_cmsg(stream, &msg);
- if (err != 0) {
- stream->read_cb(stream, err, &buf);
- msg.msg_iov = old;
- return;
- }
- } while (nread == 0 && msg.msg_controllen > 0);
- msg.msg_iov = old;
- }
-#endif
- stream->read_cb(stream, nread, &buf);
-
- /* Return if we didn't fill the buffer, there is no more data to read. */
- if (nread < buflen) {
- stream->flags |= UV_HANDLE_READ_PARTIAL;
- return;
- }
- }
- }
-}
-
-
-#ifdef __clang__
-# pragma clang diagnostic pop
-#endif
-
-#undef UV__CMSG_FD_COUNT
-#undef UV__CMSG_FD_SIZE
-
-
-int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
- assert(stream->type == UV_TCP ||
- stream->type == UV_TTY ||
- stream->type == UV_NAMED_PIPE);
-
- if (!(stream->flags & UV_HANDLE_WRITABLE) ||
- stream->flags & UV_HANDLE_SHUT ||
- stream->flags & UV_HANDLE_SHUTTING ||
- uv__is_closing(stream)) {
- return UV_ENOTCONN;
- }
-
- assert(uv__stream_fd(stream) >= 0);
-
- /* Initialize request */
- uv__req_init(stream->loop, req, UV_SHUTDOWN);
- req->handle = stream;
- req->cb = cb;
- stream->shutdown_req = req;
- stream->flags |= UV_HANDLE_SHUTTING;
-
- uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
- uv__stream_osx_interrupt_select(stream);
-
- return 0;
-}
-
-
-static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
- uv_stream_t* stream;
-
- stream = container_of(w, uv_stream_t, io_watcher);
-
- assert(stream->type == UV_TCP ||
- stream->type == UV_NAMED_PIPE ||
- stream->type == UV_TTY);
- assert(!(stream->flags & UV_HANDLE_CLOSING));
-
- if (stream->connect_req) {
- uv__stream_connect(stream);
- return;
- }
-
- assert(uv__stream_fd(stream) >= 0);
-
- /* Ignore POLLHUP here. Even if it's set, there may still be data to read. */
- if (events & (POLLIN | POLLERR | POLLHUP))
- uv__read(stream);
-
- if (uv__stream_fd(stream) == -1)
- return; /* read_cb closed stream. */
-
- /* Short-circuit iff POLLHUP is set, the user is still interested in read
- * events and uv__read() reported a partial read but not EOF. If the EOF
- * flag is set, uv__read() called read_cb with err=UV_EOF and we don't
- * have to do anything. If the partial read flag is not set, we can't
- * report the EOF yet because there is still data to read.
- */
- if ((events & POLLHUP) &&
- (stream->flags & UV_HANDLE_READING) &&
- (stream->flags & UV_HANDLE_READ_PARTIAL) &&
- !(stream->flags & UV_HANDLE_READ_EOF)) {
- uv_buf_t buf = { NULL, 0 };
- uv__stream_eof(stream, &buf);
- }
-
- if (uv__stream_fd(stream) == -1)
- return; /* read_cb closed stream. */
-
- if (events & (POLLOUT | POLLERR | POLLHUP)) {
- uv__write(stream);
- uv__write_callbacks(stream);
-
- /* Write queue drained. */
- if (QUEUE_EMPTY(&stream->write_queue))
- uv__drain(stream);
- }
-}
-
-
-/**
- * We get called here from directly following a call to connect(2).
- * In order to determine if we've errored out or succeeded must call
- * getsockopt.
- */
-static void uv__stream_connect(uv_stream_t* stream) {
- int error;
- uv_connect_t* req = stream->connect_req;
- socklen_t errorsize = sizeof(int);
-
- assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE);
- assert(req);
-
- if (stream->delayed_error) {
- /* To smooth over the differences between unixes errors that
- * were reported synchronously on the first connect can be delayed
- * until the next tick--which is now.
- */
- error = stream->delayed_error;
- stream->delayed_error = 0;
- } else {
- /* Normal situation: we need to get the socket error from the kernel. */
- assert(uv__stream_fd(stream) >= 0);
- getsockopt(uv__stream_fd(stream),
- SOL_SOCKET,
- SO_ERROR,
- &error,
- &errorsize);
- error = UV__ERR(error);
- }
-
- if (error == UV__ERR(EINPROGRESS))
- return;
-
- stream->connect_req = NULL;
- uv__req_unregister(stream->loop, req);
-
- if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- }
-
- if (req->cb)
- req->cb(req, error);
-
- if (uv__stream_fd(stream) == -1)
- return;
-
- if (error < 0) {
- uv__stream_flush_write_queue(stream, UV_ECANCELED);
- uv__write_callbacks(stream);
- }
-}
-
-
-int uv_write2(uv_write_t* req,
- uv_stream_t* stream,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb) {
- int empty_queue;
-
- assert(nbufs > 0);
- assert((stream->type == UV_TCP ||
- stream->type == UV_NAMED_PIPE ||
- stream->type == UV_TTY) &&
- "uv_write (unix) does not yet support other types of streams");
-
- if (uv__stream_fd(stream) < 0)
- return UV_EBADF;
-
- if (!(stream->flags & UV_HANDLE_WRITABLE))
- return -EPIPE;
-
- if (send_handle) {
- if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
- return UV_EINVAL;
-
- /* XXX We abuse uv_write2() to send over UDP handles to child processes.
- * Don't call uv__stream_fd() on those handles, it's a macro that on OS X
- * evaluates to a function that operates on a uv_stream_t with a couple of
- * OS X specific fields. On other Unices it does (handle)->io_watcher.fd,
- * which works but only by accident.
- */
- if (uv__handle_fd((uv_handle_t*) send_handle) < 0)
- return UV_EBADF;
-
-#if defined(__CYGWIN__) || defined(__MSYS__)
- /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it.
- See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */
- return UV_ENOSYS;
-#endif
- }
-
- /* It's legal for write_queue_size > 0 even when the write_queue is empty;
- * it means there are error-state requests in the write_completed_queue that
- * will touch up write_queue_size later, see also uv__write_req_finish().
- * We could check that write_queue is empty instead but that implies making
- * a write() syscall when we know that the handle is in error mode.
- */
- empty_queue = (stream->write_queue_size == 0);
-
- /* Initialize the req */
- uv__req_init(stream->loop, req, UV_WRITE);
- req->cb = cb;
- req->handle = stream;
- req->error = 0;
- req->send_handle = send_handle;
- QUEUE_INIT(&req->queue);
-
- req->bufs = req->bufsml;
- if (nbufs > ARRAY_SIZE(req->bufsml))
- req->bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(bufs[0]));
-
- if (req->bufs == NULL)
- return UV_ENOMEM;
-
- memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
- req->nbufs = nbufs;
- req->write_index = 0;
- stream->write_queue_size += uv__count_bufs(bufs, nbufs);
-
- /* Append the request to write_queue. */
- QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
-
- /* If the queue was empty when this function began, we should attempt to
- * do the write immediately. Otherwise start the write_watcher and wait
- * for the fd to become writable.
- */
- if (stream->connect_req) {
- /* Still connecting, do nothing. */
- }
- else if (empty_queue) {
- uv__write(stream);
- }
- else {
- /*
- * blocking streams should never have anything in the queue.
- * if this assert fires then somehow the blocking stream isn't being
- * sufficiently flushed in uv__write.
- */
- assert(!(stream->flags & UV_HANDLE_BLOCKING_WRITES));
- uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
- uv__stream_osx_interrupt_select(stream);
- }
-
- return 0;
-}
-
-
-/* The buffers to be written must remain valid until the callback is called.
- * This is not required for the uv_buf_t array.
- */
-int uv_write(uv_write_t* req,
- uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_write_cb cb) {
- return uv_write2(req, handle, bufs, nbufs, NULL, cb);
-}
-
-
-void uv_try_write_cb(uv_write_t* req, int status) {
- /* Should not be called */
- abort();
-}
-
-
-int uv_try_write(uv_stream_t* stream,
- const uv_buf_t bufs[],
- unsigned int nbufs) {
- int r;
- int has_pollout;
- size_t written;
- size_t req_size;
- uv_write_t req;
-
- /* Connecting or already writing some data */
- if (stream->connect_req != NULL || stream->write_queue_size != 0)
- return UV_EAGAIN;
-
- has_pollout = uv__io_active(&stream->io_watcher, POLLOUT);
-
- r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
- if (r != 0)
- return r;
-
- /* Remove not written bytes from write queue size */
- written = uv__count_bufs(bufs, nbufs);
- if (req.bufs != NULL)
- req_size = uv__write_req_size(&req);
- else
- req_size = 0;
- written -= req_size;
- stream->write_queue_size -= req_size;
-
- /* Unqueue request, regardless of immediateness */
- QUEUE_REMOVE(&req.queue);
- uv__req_unregister(stream->loop, &req);
- if (req.bufs != req.bufsml)
- uv__free(req.bufs);
- req.bufs = NULL;
-
- /* Do not poll for writable, if we wasn't before calling this */
- if (!has_pollout) {
- uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
- uv__stream_osx_interrupt_select(stream);
- }
-
- if (written == 0 && req_size != 0)
- return req.error < 0 ? req.error : UV_EAGAIN;
- else
- return written;
-}
-
-
-int uv_read_start(uv_stream_t* stream,
- uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
- assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
- stream->type == UV_TTY);
-
- if (stream->flags & UV_HANDLE_CLOSING)
- return UV_EINVAL;
-
- if (!(stream->flags & UV_HANDLE_READABLE))
- return -ENOTCONN;
-
- /* The UV_HANDLE_READING flag is irrelevant of the state of the tcp - it just
- * expresses the desired state of the user.
- */
- stream->flags |= UV_HANDLE_READING;
-
- /* TODO: try to do the read inline? */
- /* TODO: keep track of tcp state. If we've gotten a EOF then we should
- * not start the IO watcher.
- */
- assert(uv__stream_fd(stream) >= 0);
- assert(alloc_cb);
-
- stream->read_cb = read_cb;
- stream->alloc_cb = alloc_cb;
-
- uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
- uv__handle_start(stream);
- uv__stream_osx_interrupt_select(stream);
-
- return 0;
-}
-
-
-int uv_read_stop(uv_stream_t* stream) {
- if (!(stream->flags & UV_HANDLE_READING))
- return 0;
-
- stream->flags &= ~UV_HANDLE_READING;
- uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
- if (!uv__io_active(&stream->io_watcher, POLLOUT))
- uv__handle_stop(stream);
- uv__stream_osx_interrupt_select(stream);
-
- stream->read_cb = NULL;
- stream->alloc_cb = NULL;
- return 0;
-}
-
-
-int uv_is_readable(const uv_stream_t* stream) {
- return !!(stream->flags & UV_HANDLE_READABLE);
-}
-
-
-int uv_is_writable(const uv_stream_t* stream) {
- return !!(stream->flags & UV_HANDLE_WRITABLE);
-}
-
-
-#if defined(__APPLE__)
-int uv___stream_fd(const uv_stream_t* handle) {
- const uv__stream_select_t* s;
-
- assert(handle->type == UV_TCP ||
- handle->type == UV_TTY ||
- handle->type == UV_NAMED_PIPE);
-
- s = (const uv__stream_select_t*)handle->select;
- if (s != NULL)
- return s->fd;
-
- return handle->io_watcher.fd;
-}
-#endif /* defined(__APPLE__) */
-
-
-void uv__stream_close(uv_stream_t* handle) {
- unsigned int i;
- uv__stream_queued_fds_t* queued_fds;
-
-#if defined(__APPLE__)
- /* Terminate select loop first */
- if (handle->select != NULL) {
- uv__stream_select_t* s;
-
- s = (uv__stream_select_t*)handle->select;
-
- uv_sem_post(&s->close_sem);
- uv_sem_post(&s->async_sem);
- uv__stream_osx_interrupt_select(handle);
- uv_thread_join(&s->thread);
- uv_sem_destroy(&s->close_sem);
- uv_sem_destroy(&s->async_sem);
- uv__close(s->fake_fd);
- uv__close(s->int_fd);
- uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
-
- handle->select = NULL;
- }
-#endif /* defined(__APPLE__) */
-
- uv__io_close(handle->loop, &handle->io_watcher);
- uv_read_stop(handle);
- uv__handle_stop(handle);
- handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
-
- if (handle->io_watcher.fd != -1) {
- /* Don't close stdio file descriptors. Nothing good comes from it. */
- if (handle->io_watcher.fd > STDERR_FILENO)
- uv__close(handle->io_watcher.fd);
- handle->io_watcher.fd = -1;
- }
-
- if (handle->accepted_fd != -1) {
- uv__close(handle->accepted_fd);
- handle->accepted_fd = -1;
- }
-
- /* Close all queued fds */
- if (handle->queued_fds != NULL) {
- queued_fds = (uv__stream_queued_fds_t*)(handle->queued_fds);
- for (i = 0; i < queued_fds->offset; i++)
- uv__close(queued_fds->fds[i]);
- uv__free(handle->queued_fds);
- handle->queued_fds = NULL;
- }
-
- assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
-}
-
-
-int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
- /* Don't need to check the file descriptor, uv__nonblock()
- * will fail with EBADF if it's not valid.
- */
- return uv__nonblock(uv__stream_fd(handle), !blocking);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/sysinfo-loadavg.cpp b/wpiutil/src/main/native/libuv/src/unix/sysinfo-loadavg.cpp
deleted file mode 100644
index ebad0e8..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/sysinfo-loadavg.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/* Copyright libuv project contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdint.h>
-#include <sys/sysinfo.h>
-
-void uv_loadavg(double avg[3]) {
- struct sysinfo info;
-
- if (sysinfo(&info) < 0) return;
-
- avg[0] = (double) info.loads[0] / 65536.0;
- avg[1] = (double) info.loads[1] / 65536.0;
- avg[2] = (double) info.loads[2] / 65536.0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/tcp.cpp b/wpiutil/src/main/native/libuv/src/unix/tcp.cpp
deleted file mode 100644
index 8cedcd6..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/tcp.cpp
+++ /dev/null
@@ -1,433 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-
-static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
- struct sockaddr_storage saddr;
- socklen_t slen;
- int sockfd;
- int err;
-
- err = uv__socket(domain, SOCK_STREAM, 0);
- if (err < 0)
- return err;
- sockfd = err;
-
- err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
- if (err) {
- uv__close(sockfd);
- return err;
- }
-
- if (flags & UV_HANDLE_BOUND) {
- /* Bind this new socket to an arbitrary port */
- slen = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
- uv__close(sockfd);
- return UV__ERR(errno);
- }
-
- if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
- uv__close(sockfd);
- return UV__ERR(errno);
- }
- }
-
- return 0;
-}
-
-
-static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
- struct sockaddr_storage saddr;
- socklen_t slen;
-
- if (domain == AF_UNSPEC) {
- handle->flags |= flags;
- return 0;
- }
-
- if (uv__stream_fd(handle) != -1) {
-
- if (flags & UV_HANDLE_BOUND) {
-
- if (handle->flags & UV_HANDLE_BOUND) {
- /* It is already bound to a port. */
- handle->flags |= flags;
- return 0;
- }
-
- /* Query to see if tcp socket is bound. */
- slen = sizeof(saddr);
- memset(&saddr, 0, sizeof(saddr));
- if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
- return UV__ERR(errno);
-
- if ((saddr.ss_family == AF_INET6 &&
- ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
- (saddr.ss_family == AF_INET &&
- ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
- /* Handle is already bound to a port. */
- handle->flags |= flags;
- return 0;
- }
-
- /* Bind to arbitrary port */
- if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
- return UV__ERR(errno);
- }
-
- handle->flags |= flags;
- return 0;
- }
-
- return new_socket(handle, domain, flags);
-}
-
-
-int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
- int domain;
-
- /* Use the lower 8 bits for the domain */
- domain = flags & 0xFF;
- if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
- return UV_EINVAL;
-
- if (flags & ~0xFF)
- return UV_EINVAL;
-
- uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
-
- /* If anything fails beyond this point we need to remove the handle from
- * the handle queue, since it was added by uv__handle_init in uv_stream_init.
- */
-
- if (domain != AF_UNSPEC) {
- int err = maybe_new_socket(tcp, domain, 0);
- if (err) {
- QUEUE_REMOVE(&tcp->handle_queue);
- return err;
- }
- }
-
- return 0;
-}
-
-
-int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
- return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
-}
-
-
-int uv__tcp_bind(uv_tcp_t* tcp,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- int err;
- int on;
-
- /* Cannot set IPv6-only mode on non-IPv6 socket. */
- if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
- return UV_EINVAL;
-
- err = maybe_new_socket(tcp, addr->sa_family, 0);
- if (err)
- return err;
-
- on = 1;
- if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
- return UV__ERR(errno);
-
-#ifndef __OpenBSD__
-#ifdef IPV6_V6ONLY
- if (addr->sa_family == AF_INET6) {
- on = (flags & UV_TCP_IPV6ONLY) != 0;
- if (setsockopt(tcp->io_watcher.fd,
- IPPROTO_IPV6,
- IPV6_V6ONLY,
- &on,
- sizeof on) == -1) {
-#if defined(__MVS__)
- if (errno == EOPNOTSUPP)
- return UV_EINVAL;
-#endif
- return UV__ERR(errno);
- }
- }
-#endif
-#endif
-
- errno = 0;
- if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
- if (errno == EAFNOSUPPORT)
- /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
- * socket created with AF_INET to an AF_INET6 address or vice versa. */
- return UV_EINVAL;
- return UV__ERR(errno);
- }
- tcp->delayed_error = UV__ERR(errno);
-
- tcp->flags |= UV_HANDLE_BOUND;
- if (addr->sa_family == AF_INET6)
- tcp->flags |= UV_HANDLE_IPV6;
-
- return 0;
-}
-
-
-int uv__tcp_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_connect_cb cb) {
- int err;
- int r;
-
- assert(handle->type == UV_TCP);
-
- if (handle->connect_req != NULL)
- return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
-
- err = maybe_new_socket(handle,
- addr->sa_family,
- UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- if (err)
- return err;
-
- handle->delayed_error = 0;
-
- do {
- errno = 0;
- r = connect(uv__stream_fd(handle), addr, addrlen);
- } while (r == -1 && errno == EINTR);
-
- /* We not only check the return value, but also check the errno != 0.
- * Because in rare cases connect() will return -1 but the errno
- * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
- * and actually the tcp three-way handshake is completed.
- */
- if (r == -1 && errno != 0) {
- if (errno == EINPROGRESS)
- ; /* not an error */
- else if (errno == ECONNREFUSED
-#if defined(__OpenBSD__)
- || errno == EINVAL
-#endif
- )
- /* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
- * next tick to report the error. Solaris and OpenBSD wants to report
- * immediately -- other unixes want to wait.
- */
- handle->delayed_error = UV__ERR(ECONNREFUSED);
- else
- return UV__ERR(errno);
- }
-
- uv__req_init(handle->loop, req, UV_CONNECT);
- req->cb = cb;
- req->handle = (uv_stream_t*) handle;
- QUEUE_INIT(&req->queue);
- handle->connect_req = req;
-
- uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
-
- if (handle->delayed_error)
- uv__io_feed(handle->loop, &handle->io_watcher);
-
- return 0;
-}
-
-
-int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
- int err;
-
- if (uv__fd_exists(handle->loop, sock))
- return UV_EEXIST;
-
- err = uv__nonblock(sock, 1);
- if (err)
- return err;
-
- return uv__stream_open((uv_stream_t*)handle,
- sock,
- UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
-}
-
-
-int uv_tcp_getsockname(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- if (handle->delayed_error)
- return handle->delayed_error;
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getsockname,
- name,
- namelen);
-}
-
-
-int uv_tcp_getpeername(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- if (handle->delayed_error)
- return handle->delayed_error;
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getpeername,
- name,
- namelen);
-}
-
-
-int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
- static int single_accept = -1;
- unsigned long flags;
- int err;
-
- if (tcp->delayed_error)
- return tcp->delayed_error;
-
- if (single_accept == -1) {
- const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
- single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
- }
-
- if (single_accept)
- tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
-
- flags = 0;
-#if defined(__MVS__)
- /* on zOS the listen call does not bind automatically
- if the socket is unbound. Hence the manual binding to
- an arbitrary port is required to be done manually
- */
- flags |= UV_HANDLE_BOUND;
-#endif
- err = maybe_new_socket(tcp, AF_INET, flags);
- if (err)
- return err;
-
- if (listen(tcp->io_watcher.fd, backlog))
- return UV__ERR(errno);
-
- tcp->connection_cb = cb;
- tcp->flags |= UV_HANDLE_BOUND;
-
- /* Start listening for connections. */
- tcp->io_watcher.cb = uv__server_io;
- uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
-
- return 0;
-}
-
-
-int uv__tcp_nodelay(int fd, int on) {
- if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
- return UV__ERR(errno);
- return 0;
-}
-
-
-int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
- return UV__ERR(errno);
-
-#ifdef TCP_KEEPIDLE
- if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
- return UV__ERR(errno);
-#endif
-
- /* Solaris/SmartOS, if you don't support keep-alive,
- * then don't advertise it in your system headers...
- */
- /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
-#if defined(TCP_KEEPALIVE) && !defined(__sun)
- if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
- return UV__ERR(errno);
-#endif
-
- return 0;
-}
-
-
-int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
- int err;
-
- if (uv__stream_fd(handle) != -1) {
- err = uv__tcp_nodelay(uv__stream_fd(handle), on);
- if (err)
- return err;
- }
-
- if (on)
- handle->flags |= UV_HANDLE_TCP_NODELAY;
- else
- handle->flags &= ~UV_HANDLE_TCP_NODELAY;
-
- return 0;
-}
-
-
-int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
- int err;
-
- if (uv__stream_fd(handle) != -1) {
- err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
- if (err)
- return err;
- }
-
- if (on)
- handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
- else
- handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
-
- /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
- * uv_tcp_t with an int that's almost never used...
- */
-
- return 0;
-}
-
-
-int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
- if (enable)
- handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
- else
- handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
- return 0;
-}
-
-
-void uv__tcp_close(uv_tcp_t* handle) {
- uv__stream_close((uv_stream_t*)handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/thread.cpp b/wpiutil/src/main/native/libuv/src/unix/thread.cpp
deleted file mode 100644
index 012cd6a..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/thread.cpp
+++ /dev/null
@@ -1,844 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <pthread.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/time.h>
-#include <sys/resource.h> /* getrlimit() */
-#include <unistd.h> /* getpagesize() */
-
-#include <limits.h>
-
-#ifdef __MVS__
-#include <sys/ipc.h>
-#include <sys/sem.h>
-#endif
-
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
-#include <gnu/libc-version.h> /* gnu_get_libc_version() */
-#endif
-
-#undef NANOSEC
-#define NANOSEC ((uint64_t) 1e9)
-
-#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
-STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
-#endif
-
-/* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
-#if defined(_AIX) || \
- defined(__OpenBSD__) || \
- !defined(PTHREAD_BARRIER_SERIAL_THREAD)
-int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
- struct _uv_barrier* b;
- int rc;
-
- if (barrier == NULL || count == 0)
- return UV_EINVAL;
-
- b = (_uv_barrier*)uv__malloc(sizeof(*b));
- if (b == NULL)
- return UV_ENOMEM;
-
- b->in = 0;
- b->out = 0;
- b->threshold = count;
-
- rc = uv_mutex_init(&b->mutex);
- if (rc != 0)
- goto error2;
-
- rc = uv_cond_init(&b->cond);
- if (rc != 0)
- goto error;
-
- barrier->b = b;
- return 0;
-
-error:
- uv_mutex_destroy(&b->mutex);
-error2:
- uv__free(b);
- return rc;
-}
-
-int uv_barrier_wait(uv_barrier_t* barrier) {
- struct _uv_barrier* b;
- int last;
-
- if (barrier == NULL || barrier->b == NULL)
- return UV_EINVAL;
-
- b = barrier->b;
- /* Lock the mutex*/
- uv_mutex_lock(&b->mutex);
-
- if (++b->in == b->threshold) {
- b->in = 0;
- b->out = b->threshold;
- uv_cond_signal(&b->cond);
- } else {
- do
- uv_cond_wait(&b->cond, &b->mutex);
- while (b->in != 0);
- }
-
- last = (--b->out == 0);
- if (!last)
- uv_cond_signal(&b->cond); /* Not needed for last thread. */
-
- uv_mutex_unlock(&b->mutex);
- return last;
-}
-
-void uv_barrier_destroy(uv_barrier_t* barrier) {
- struct _uv_barrier* b;
-
- b = barrier->b;
- uv_mutex_lock(&b->mutex);
-
- assert(b->in == 0);
- assert(b->out == 0);
-
- if (b->in != 0 || b->out != 0)
- abort();
-
- uv_mutex_unlock(&b->mutex);
- uv_mutex_destroy(&b->mutex);
- uv_cond_destroy(&b->cond);
-
- uv__free(barrier->b);
- barrier->b = NULL;
-}
-
-#else
-
-int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
- return UV__ERR(pthread_barrier_init(barrier, NULL, count));
-}
-
-
-int uv_barrier_wait(uv_barrier_t* barrier) {
- int rc;
-
- rc = pthread_barrier_wait(barrier);
- if (rc != 0)
- if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
- abort();
-
- return rc == PTHREAD_BARRIER_SERIAL_THREAD;
-}
-
-
-void uv_barrier_destroy(uv_barrier_t* barrier) {
- if (pthread_barrier_destroy(barrier))
- abort();
-}
-
-#endif
-
-
-/* On MacOS, threads other than the main thread are created with a reduced
- * stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
- *
- * On Linux, threads created by musl have a much smaller stack than threads
- * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
- */
-static size_t thread_stack_size(void) {
-#if defined(__APPLE__) || defined(__linux__)
- struct rlimit lim;
-
- if (getrlimit(RLIMIT_STACK, &lim))
- abort();
-
- if (lim.rlim_cur != RLIM_INFINITY) {
- /* pthread_attr_setstacksize() expects page-aligned values. */
- lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
-
- /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
- * too small to safely receive signals on.
- *
- * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
- * the largest MINSIGSTKSZ of the architectures that musl supports) so
- * let's use that as a lower bound.
- *
- * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
- * is between 28 and 133 KB when compiling against glibc, depending
- * on the architecture.
- */
- if (lim.rlim_cur >= 8192)
- if (lim.rlim_cur >= (rlim_t) PTHREAD_STACK_MIN)
- return lim.rlim_cur;
- }
-#endif
-
-#if !defined(__linux__)
- return 0;
-#elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
- return 4 << 20; /* glibc default. */
-#else
- return 2 << 20; /* glibc default. */
-#endif
-}
-
-
-int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
- uv_thread_options_t params;
- params.flags = UV_THREAD_NO_FLAGS;
- return uv_thread_create_ex(tid, ¶ms, entry, arg);
-}
-
-int uv_thread_create_ex(uv_thread_t* tid,
- const uv_thread_options_t* params,
- void (*entry)(void *arg),
- void *arg) {
- int err;
- pthread_attr_t* attr;
- pthread_attr_t attr_storage;
- size_t pagesize;
- size_t stack_size;
-
- stack_size =
- params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
-
- attr = NULL;
- if (stack_size == 0) {
- stack_size = thread_stack_size();
- } else {
- pagesize = (size_t)getpagesize();
- /* Round up to the nearest page boundary. */
- stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
-#ifdef PTHREAD_STACK_MIN
- if (stack_size < (size_t) PTHREAD_STACK_MIN)
- stack_size = PTHREAD_STACK_MIN;
-#endif
- }
-
- if (stack_size > 0) {
- attr = &attr_storage;
-
- if (pthread_attr_init(attr))
- abort();
-
- if (pthread_attr_setstacksize(attr, stack_size))
- abort();
- }
-
- err = pthread_create(tid, attr, (void*(*)(void*)) (void(*)(void)) entry, arg);
-
- if (attr != NULL)
- pthread_attr_destroy(attr);
-
- return UV__ERR(err);
-}
-
-
-uv_thread_t uv_thread_self(void) {
- return pthread_self();
-}
-
-int uv_thread_join(uv_thread_t *tid) {
- return UV__ERR(pthread_join(*tid, NULL));
-}
-
-
-int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
- return pthread_equal(*t1, *t2);
-}
-
-
-int uv_mutex_init(uv_mutex_t* mutex) {
-#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
- return UV__ERR(pthread_mutex_init(mutex, NULL));
-#else
- pthread_mutexattr_t attr;
- int err;
-
- if (pthread_mutexattr_init(&attr))
- abort();
-
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
- abort();
-
- err = pthread_mutex_init(mutex, &attr);
-
- if (pthread_mutexattr_destroy(&attr))
- abort();
-
- return UV__ERR(err);
-#endif
-}
-
-
-int uv_mutex_init_recursive(uv_mutex_t* mutex) {
- pthread_mutexattr_t attr;
- int err;
-
- if (pthread_mutexattr_init(&attr))
- abort();
-
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
- abort();
-
- err = pthread_mutex_init(mutex, &attr);
-
- if (pthread_mutexattr_destroy(&attr))
- abort();
-
- return UV__ERR(err);
-}
-
-
-void uv_mutex_destroy(uv_mutex_t* mutex) {
- if (pthread_mutex_destroy(mutex))
- abort();
-}
-
-
-void uv_mutex_lock(uv_mutex_t* mutex) {
- if (pthread_mutex_lock(mutex))
- abort();
-}
-
-
-int uv_mutex_trylock(uv_mutex_t* mutex) {
- int err;
-
- err = pthread_mutex_trylock(mutex);
- if (err) {
- if (err != EBUSY && err != EAGAIN)
- abort();
- return UV_EBUSY;
- }
-
- return 0;
-}
-
-
-void uv_mutex_unlock(uv_mutex_t* mutex) {
- if (pthread_mutex_unlock(mutex))
- abort();
-}
-
-
-int uv_rwlock_init(uv_rwlock_t* rwlock) {
- return UV__ERR(pthread_rwlock_init(rwlock, NULL));
-}
-
-
-void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
- if (pthread_rwlock_destroy(rwlock))
- abort();
-}
-
-
-void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
- if (pthread_rwlock_rdlock(rwlock))
- abort();
-}
-
-
-int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
- int err;
-
- err = pthread_rwlock_tryrdlock(rwlock);
- if (err) {
- if (err != EBUSY && err != EAGAIN)
- abort();
- return UV_EBUSY;
- }
-
- return 0;
-}
-
-
-void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
- if (pthread_rwlock_unlock(rwlock))
- abort();
-}
-
-
-void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
- if (pthread_rwlock_wrlock(rwlock))
- abort();
-}
-
-
-int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
- int err;
-
- err = pthread_rwlock_trywrlock(rwlock);
- if (err) {
- if (err != EBUSY && err != EAGAIN)
- abort();
- return UV_EBUSY;
- }
-
- return 0;
-}
-
-
-void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
- if (pthread_rwlock_unlock(rwlock))
- abort();
-}
-
-
-void uv_once(uv_once_t* guard, void (*callback)(void)) {
- if (pthread_once(guard, callback))
- abort();
-}
-
-#if defined(__APPLE__) && defined(__MACH__)
-
-int uv_sem_init(uv_sem_t* sem, unsigned int value) {
- kern_return_t err;
-
- err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
- if (err == KERN_SUCCESS)
- return 0;
- if (err == KERN_INVALID_ARGUMENT)
- return UV_EINVAL;
- if (err == KERN_RESOURCE_SHORTAGE)
- return UV_ENOMEM;
-
- abort();
- return UV_EINVAL; /* Satisfy the compiler. */
-}
-
-
-void uv_sem_destroy(uv_sem_t* sem) {
- if (semaphore_destroy(mach_task_self(), *sem))
- abort();
-}
-
-
-void uv_sem_post(uv_sem_t* sem) {
- if (semaphore_signal(*sem))
- abort();
-}
-
-
-void uv_sem_wait(uv_sem_t* sem) {
- int r;
-
- do
- r = semaphore_wait(*sem);
- while (r == KERN_ABORTED);
-
- if (r != KERN_SUCCESS)
- abort();
-}
-
-
-int uv_sem_trywait(uv_sem_t* sem) {
- mach_timespec_t interval;
- kern_return_t err;
-
- interval.tv_sec = 0;
- interval.tv_nsec = 0;
-
- err = semaphore_timedwait(*sem, interval);
- if (err == KERN_SUCCESS)
- return 0;
- if (err == KERN_OPERATION_TIMED_OUT)
- return UV_EAGAIN;
-
- abort();
- return UV_EINVAL; /* Satisfy the compiler. */
-}
-
-#else /* !(defined(__APPLE__) && defined(__MACH__)) */
-
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
-
-/* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674
- * by providing a custom implementation for glibc < 2.21 in terms of other
- * concurrency primitives.
- * Refs: https://github.com/nodejs/node/issues/19903 */
-
-/* To preserve ABI compatibility, we treat the uv_sem_t as storage for
- * a pointer to the actual struct we're using underneath. */
-
-static uv_once_t glibc_version_check_once = UV_ONCE_INIT;
-static int platform_needs_custom_semaphore = 0;
-
-static void glibc_version_check(void) {
- const char* version = gnu_get_libc_version();
- platform_needs_custom_semaphore =
- version[0] == '2' && version[1] == '.' &&
- atoi(version + 2) < 21;
-}
-
-#elif defined(__MVS__)
-
-#define platform_needs_custom_semaphore 1
-
-#else /* !defined(__GLIBC__) && !defined(__MVS__) */
-
-#define platform_needs_custom_semaphore 0
-
-#endif
-
-typedef struct uv_semaphore_s {
- uv_mutex_t mutex;
- uv_cond_t cond;
- unsigned int value;
-} uv_semaphore_t;
-
-#if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \
- platform_needs_custom_semaphore
-STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*));
-#endif
-
-static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) {
- int err;
- uv_semaphore_t* sem;
-
- sem = (uv_semaphore_t*)uv__malloc(sizeof(*sem));
- if (sem == NULL)
- return UV_ENOMEM;
-
- if ((err = uv_mutex_init(&sem->mutex)) != 0) {
- uv__free(sem);
- return err;
- }
-
- if ((err = uv_cond_init(&sem->cond)) != 0) {
- uv_mutex_destroy(&sem->mutex);
- uv__free(sem);
- return err;
- }
-
- sem->value = value;
- *(uv_semaphore_t**)sem_ = sem;
- return 0;
-}
-
-
-static void uv__custom_sem_destroy(uv_sem_t* sem_) {
- uv_semaphore_t* sem;
-
- sem = *(uv_semaphore_t**)sem_;
- uv_cond_destroy(&sem->cond);
- uv_mutex_destroy(&sem->mutex);
- uv__free(sem);
-}
-
-
-static void uv__custom_sem_post(uv_sem_t* sem_) {
- uv_semaphore_t* sem;
-
- sem = *(uv_semaphore_t**)sem_;
- uv_mutex_lock(&sem->mutex);
- sem->value++;
- if (sem->value == 1)
- uv_cond_signal(&sem->cond);
- uv_mutex_unlock(&sem->mutex);
-}
-
-
-static void uv__custom_sem_wait(uv_sem_t* sem_) {
- uv_semaphore_t* sem;
-
- sem = *(uv_semaphore_t**)sem_;
- uv_mutex_lock(&sem->mutex);
- while (sem->value == 0)
- uv_cond_wait(&sem->cond, &sem->mutex);
- sem->value--;
- uv_mutex_unlock(&sem->mutex);
-}
-
-
-static int uv__custom_sem_trywait(uv_sem_t* sem_) {
- uv_semaphore_t* sem;
-
- sem = *(uv_semaphore_t**)sem_;
- if (uv_mutex_trylock(&sem->mutex) != 0)
- return UV_EAGAIN;
-
- if (sem->value == 0) {
- uv_mutex_unlock(&sem->mutex);
- return UV_EAGAIN;
- }
-
- sem->value--;
- uv_mutex_unlock(&sem->mutex);
-
- return 0;
-}
-
-static int uv__sem_init(uv_sem_t* sem, unsigned int value) {
- if (sem_init(sem, 0, value))
- return UV__ERR(errno);
- return 0;
-}
-
-
-static void uv__sem_destroy(uv_sem_t* sem) {
- if (sem_destroy(sem))
- abort();
-}
-
-
-static void uv__sem_post(uv_sem_t* sem) {
- if (sem_post(sem))
- abort();
-}
-
-
-static void uv__sem_wait(uv_sem_t* sem) {
- int r;
-
- do
- r = sem_wait(sem);
- while (r == -1 && errno == EINTR);
-
- if (r)
- abort();
-}
-
-
-static int uv__sem_trywait(uv_sem_t* sem) {
- int r;
-
- do
- r = sem_trywait(sem);
- while (r == -1 && errno == EINTR);
-
- if (r) {
- if (errno == EAGAIN)
- return UV_EAGAIN;
- abort();
- }
-
- return 0;
-}
-
-int uv_sem_init(uv_sem_t* sem, unsigned int value) {
-#if defined(__GLIBC__) && !defined(__UCLIBC__)
- uv_once(&glibc_version_check_once, glibc_version_check);
-#endif
-
- if (platform_needs_custom_semaphore)
- return uv__custom_sem_init(sem, value);
- else
- return uv__sem_init(sem, value);
-}
-
-
-void uv_sem_destroy(uv_sem_t* sem) {
- if (platform_needs_custom_semaphore)
- uv__custom_sem_destroy(sem);
- else
- uv__sem_destroy(sem);
-}
-
-
-void uv_sem_post(uv_sem_t* sem) {
- if (platform_needs_custom_semaphore)
- uv__custom_sem_post(sem);
- else
- uv__sem_post(sem);
-}
-
-
-void uv_sem_wait(uv_sem_t* sem) {
- if (platform_needs_custom_semaphore)
- uv__custom_sem_wait(sem);
- else
- uv__sem_wait(sem);
-}
-
-
-int uv_sem_trywait(uv_sem_t* sem) {
- if (platform_needs_custom_semaphore)
- return uv__custom_sem_trywait(sem);
- else
- return uv__sem_trywait(sem);
-}
-
-#endif /* defined(__APPLE__) && defined(__MACH__) */
-
-
-#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
-
-int uv_cond_init(uv_cond_t* cond) {
- return UV__ERR(pthread_cond_init(cond, NULL));
-}
-
-#else /* !(defined(__APPLE__) && defined(__MACH__)) */
-
-int uv_cond_init(uv_cond_t* cond) {
- pthread_condattr_t attr;
- int err;
-
- err = pthread_condattr_init(&attr);
- if (err)
- return UV__ERR(err);
-
-#if !(defined(__ANDROID_API__) && __ANDROID_API__ < 21)
- err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
- if (err)
- goto error2;
-#endif
-
- err = pthread_cond_init(cond, &attr);
- if (err)
- goto error2;
-
- err = pthread_condattr_destroy(&attr);
- if (err)
- goto error;
-
- return 0;
-
-error:
- pthread_cond_destroy(cond);
-error2:
- pthread_condattr_destroy(&attr);
- return UV__ERR(err);
-}
-
-#endif /* defined(__APPLE__) && defined(__MACH__) */
-
-void uv_cond_destroy(uv_cond_t* cond) {
-#if defined(__APPLE__) && defined(__MACH__)
- /* It has been reported that destroying condition variables that have been
- * signalled but not waited on can sometimes result in application crashes.
- * See https://codereview.chromium.org/1323293005.
- */
- pthread_mutex_t mutex;
- struct timespec ts;
- int err;
-
- if (pthread_mutex_init(&mutex, NULL))
- abort();
-
- if (pthread_mutex_lock(&mutex))
- abort();
-
- ts.tv_sec = 0;
- ts.tv_nsec = 1;
-
- err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
- if (err != 0 && err != ETIMEDOUT)
- abort();
-
- if (pthread_mutex_unlock(&mutex))
- abort();
-
- if (pthread_mutex_destroy(&mutex))
- abort();
-#endif /* defined(__APPLE__) && defined(__MACH__) */
-
- if (pthread_cond_destroy(cond))
- abort();
-}
-
-void uv_cond_signal(uv_cond_t* cond) {
- if (pthread_cond_signal(cond))
- abort();
-}
-
-void uv_cond_broadcast(uv_cond_t* cond) {
- if (pthread_cond_broadcast(cond))
- abort();
-}
-
-void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
- if (pthread_cond_wait(cond, mutex))
- abort();
-}
-
-
-int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
- int r;
- struct timespec ts;
-#if defined(__MVS__)
- struct timeval tv;
-#endif
-
-#if defined(__APPLE__) && defined(__MACH__)
- ts.tv_sec = timeout / NANOSEC;
- ts.tv_nsec = timeout % NANOSEC;
- r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
-#else
-#if defined(__MVS__)
- if (gettimeofday(&tv, NULL))
- abort();
- timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3;
-#else
- timeout += uv__hrtime(UV_CLOCK_PRECISE);
-#endif
- ts.tv_sec = timeout / NANOSEC;
- ts.tv_nsec = timeout % NANOSEC;
-#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
-
- /*
- * The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
- * but has this alternative function instead.
- */
- r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
-#else
- r = pthread_cond_timedwait(cond, mutex, &ts);
-#endif /* __ANDROID_API__ */
-#endif
-
-
- if (r == 0)
- return 0;
-
- if (r == ETIMEDOUT)
- return UV_ETIMEDOUT;
-
- abort();
-#ifndef __SUNPRO_C
- return UV_EINVAL; /* Satisfy the compiler. */
-#endif
-}
-
-
-int uv_key_create(uv_key_t* key) {
- return UV__ERR(pthread_key_create(key, NULL));
-}
-
-
-void uv_key_delete(uv_key_t* key) {
- if (pthread_key_delete(*key))
- abort();
-}
-
-
-void* uv_key_get(uv_key_t* key) {
- return pthread_getspecific(*key);
-}
-
-
-void uv_key_set(uv_key_t* key, void* value) {
- if (pthread_setspecific(*key, value))
- abort();
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/tty.cpp b/wpiutil/src/main/native/libuv/src/unix/tty.cpp
deleted file mode 100644
index 5f68140..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/tty.cpp
+++ /dev/null
@@ -1,368 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-#include "spinlock.h"
-
-#include <stdlib.h>
-#include <assert.h>
-#include <unistd.h>
-#include <termios.h>
-#include <errno.h>
-#include <sys/ioctl.h>
-
-#if defined(__MVS__) && !defined(IMAXBEL)
-#define IMAXBEL 0
-#endif
-
-static int orig_termios_fd = -1;
-static struct termios orig_termios;
-static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
-
-static int uv__tty_is_peripheral(const int fd) {
- int result;
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
- int dummy;
-
- result = ioctl(fd, TIOCGPTN, &dummy) != 0;
-#elif defined(__APPLE__)
- char dummy[256];
-
- result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
-#elif defined(__NetBSD__)
- /*
- * NetBSD as an extension returns with ptsname(3) and ptsname_r(3) the
- * peripheral device name for both descriptors, the controller one and
- * peripheral one.
- *
- * Implement function to compare major device number with pts devices.
- *
- * The major numbers are machine-dependent, on NetBSD/amd64 they are
- * respectively:
- * - controller tty: ptc - major 6
- * - peripheral tty: pts - major 5
- */
-
- struct stat sb;
- /* Lookup device's major for the pts driver and cache it. */
- static devmajor_t pts = NODEVMAJOR;
-
- if (pts == NODEVMAJOR) {
- pts = getdevmajor("pts", S_IFCHR);
- if (pts == NODEVMAJOR)
- abort();
- }
-
- /* Lookup stat structure behind the file descriptor. */
- if (fstat(fd, &sb) != 0)
- abort();
-
- /* Assert character device. */
- if (!S_ISCHR(sb.st_mode))
- abort();
-
- /* Assert valid major. */
- if (major(sb.st_rdev) == NODEVMAJOR)
- abort();
-
- result = (pts == major(sb.st_rdev));
-#else
- /* Fallback to ptsname
- */
- result = ptsname(fd) == NULL;
-#endif
- return result;
-}
-
-int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int unused) {
- uv_handle_type type;
- int flags;
- int newfd;
- int r;
- int saved_flags;
- int mode;
- char path[256];
- (void)unused; /* deprecated parameter is no longer needed */
-
- /* File descriptors that refer to files cannot be monitored with epoll.
- * That restriction also applies to character devices like /dev/random
- * (but obviously not /dev/tty.)
- */
- type = uv_guess_handle(fd);
- if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
- return UV_EINVAL;
-
- flags = 0;
- newfd = -1;
-
- /* Save the fd flags in case we need to restore them due to an error. */
- do
- saved_flags = fcntl(fd, F_GETFL);
- while (saved_flags == -1 && errno == EINTR);
-
- if (saved_flags == -1)
- return UV__ERR(errno);
- mode = saved_flags & O_ACCMODE;
-
- /* Reopen the file descriptor when it refers to a tty. This lets us put the
- * tty in non-blocking mode without affecting other processes that share it
- * with us.
- *
- * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
- * affects fd 1 of `cat` because both file descriptors refer to the same
- * struct file in the kernel. When we reopen our fd 0, it points to a
- * different struct file, hence changing its properties doesn't affect
- * other processes.
- */
- if (type == UV_TTY) {
- /* Reopening a pty in controller mode won't work either because the reopened
- * pty will be in peripheral mode (*BSD) or reopening will allocate a new
- * controller/peripheral pair (Linux). Therefore check if the fd points to a
- * peripheral device.
- */
- if (uv__tty_is_peripheral(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
- r = uv__open_cloexec(path, mode);
- else
- r = -1;
-
- if (r < 0) {
- /* fallback to using blocking writes */
- if (mode != O_RDONLY)
- flags |= UV_HANDLE_BLOCKING_WRITES;
- goto skip;
- }
-
- newfd = r;
-
- r = uv__dup2_cloexec(newfd, fd);
- if (r < 0 && r != UV_EINVAL) {
- /* EINVAL means newfd == fd which could conceivably happen if another
- * thread called close(fd) between our calls to isatty() and open().
- * That's a rather unlikely event but let's handle it anyway.
- */
- uv__close(newfd);
- return r;
- }
-
- fd = newfd;
- }
-
-skip:
- uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
-
- /* If anything fails beyond this point we need to remove the handle from
- * the handle queue, since it was added by uv__handle_init in uv_stream_init.
- */
-
- if (!(flags & UV_HANDLE_BLOCKING_WRITES))
- uv__nonblock(fd, 1);
-
-#if defined(__APPLE__)
- r = uv__stream_try_select((uv_stream_t*) tty, &fd);
- if (r) {
- int rc = r;
- if (newfd != -1)
- uv__close(newfd);
- QUEUE_REMOVE(&tty->handle_queue);
- do
- r = fcntl(fd, F_SETFL, saved_flags);
- while (r == -1 && errno == EINTR);
- return rc;
- }
-#endif
-
- if (mode != O_WRONLY)
- flags |= UV_HANDLE_READABLE;
- if (mode != O_RDONLY)
- flags |= UV_HANDLE_WRITABLE;
-
- uv__stream_open((uv_stream_t*) tty, fd, flags);
- tty->mode = UV_TTY_MODE_NORMAL;
-
- return 0;
-}
-
-static void uv__tty_make_raw(struct termios* tio) {
- assert(tio != NULL);
-
-#if defined __sun || defined __MVS__
- /*
- * This implementation of cfmakeraw for Solaris and derivatives is taken from
- * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
- */
- tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
- IGNCR | ICRNL | IXON);
- tio->c_oflag &= ~OPOST;
- tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
- tio->c_cflag &= ~(CSIZE | PARENB);
- tio->c_cflag |= CS8;
-#else
- cfmakeraw(tio);
-#endif /* #ifdef __sun */
-}
-
-int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
- struct termios tmp;
- int fd;
-
- if (tty->mode == (int) mode)
- return 0;
-
- fd = uv__stream_fd(tty);
- if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
- if (tcgetattr(fd, &tty->orig_termios))
- return UV__ERR(errno);
-
- /* This is used for uv_tty_reset_mode() */
- uv_spinlock_lock(&termios_spinlock);
- if (orig_termios_fd == -1) {
- orig_termios = tty->orig_termios;
- orig_termios_fd = fd;
- }
- uv_spinlock_unlock(&termios_spinlock);
- }
-
- tmp = tty->orig_termios;
- switch (mode) {
- case UV_TTY_MODE_NORMAL:
- break;
- case UV_TTY_MODE_RAW:
- tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
- tmp.c_oflag |= (ONLCR);
- tmp.c_cflag |= (CS8);
- tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
- tmp.c_cc[VMIN] = 1;
- tmp.c_cc[VTIME] = 0;
- break;
- case UV_TTY_MODE_IO:
- uv__tty_make_raw(&tmp);
- break;
- }
-
- /* Apply changes after draining */
- if (tcsetattr(fd, TCSADRAIN, &tmp))
- return UV__ERR(errno);
-
- tty->mode = mode;
- return 0;
-}
-
-
-int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
- struct winsize ws;
- int err;
-
- do
- err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
- while (err == -1 && errno == EINTR);
-
- if (err == -1)
- return UV__ERR(errno);
-
- *width = ws.ws_col;
- *height = ws.ws_row;
-
- return 0;
-}
-
-
-uv_handle_type uv_guess_handle(uv_file file) {
- struct sockaddr sa;
- struct stat s;
- socklen_t len;
- int type;
-
- if (file < 0)
- return UV_UNKNOWN_HANDLE;
-
- if (isatty(file))
- return UV_TTY;
-
- if (fstat(file, &s))
- return UV_UNKNOWN_HANDLE;
-
- if (S_ISREG(s.st_mode))
- return UV_FILE;
-
- if (S_ISCHR(s.st_mode))
- return UV_FILE; /* XXX UV_NAMED_PIPE? */
-
- if (S_ISFIFO(s.st_mode))
- return UV_NAMED_PIPE;
-
- if (!S_ISSOCK(s.st_mode))
- return UV_UNKNOWN_HANDLE;
-
- len = sizeof(type);
- if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
- return UV_UNKNOWN_HANDLE;
-
- len = sizeof(sa);
- if (getsockname(file, &sa, &len))
- return UV_UNKNOWN_HANDLE;
-
- if (type == SOCK_DGRAM)
- if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
- return UV_UDP;
-
- if (type == SOCK_STREAM) {
-#if defined(_AIX) || defined(__DragonFly__)
- /* on AIX/DragonFly the getsockname call returns an empty sa structure
- * for sockets of type AF_UNIX. For all other types it will
- * return a properly filled in structure.
- */
- if (len == 0)
- return UV_NAMED_PIPE;
-#endif /* defined(_AIX) || defined(__DragonFly__) */
-
- if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
- return UV_TCP;
- if (sa.sa_family == AF_UNIX)
- return UV_NAMED_PIPE;
- }
-
- return UV_UNKNOWN_HANDLE;
-}
-
-
-/* This function is async signal-safe, meaning that it's safe to call from
- * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
- * critical section when the signal was raised.
- */
-int uv_tty_reset_mode(void) {
- int saved_errno;
- int err;
-
- saved_errno = errno;
- if (!uv_spinlock_trylock(&termios_spinlock))
- return UV_EBUSY; /* In uv_tty_set_mode(). */
-
- err = 0;
- if (orig_termios_fd != -1)
- if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
- err = UV__ERR(errno);
-
- uv_spinlock_unlock(&termios_spinlock);
- errno = saved_errno;
-
- return err;
-}
diff --git a/wpiutil/src/main/native/libuv/src/unix/udp.cpp b/wpiutil/src/main/native/libuv/src/unix/udp.cpp
deleted file mode 100644
index 5c03ae1..0000000
--- a/wpiutil/src/main/native/libuv/src/unix/udp.cpp
+++ /dev/null
@@ -1,999 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-#include <assert.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#if defined(__MVS__)
-#include <xti.h>
-#endif
-#include <sys/un.h>
-
-#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
-# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
-#endif
-
-#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
-# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
-#endif
-
-
-static void uv__udp_run_completed(uv_udp_t* handle);
-static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
-static void uv__udp_recvmsg(uv_udp_t* handle);
-static void uv__udp_sendmsg(uv_udp_t* handle);
-static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
- int domain,
- unsigned int flags);
-
-
-void uv__udp_close(uv_udp_t* handle) {
- uv__io_close(handle->loop, &handle->io_watcher);
- uv__handle_stop(handle);
-
- if (handle->io_watcher.fd != -1) {
- uv__close(handle->io_watcher.fd);
- handle->io_watcher.fd = -1;
- }
-}
-
-
-void uv__udp_finish_close(uv_udp_t* handle) {
- uv_udp_send_t* req;
- QUEUE* q;
-
- assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
- assert(handle->io_watcher.fd == -1);
-
- while (!QUEUE_EMPTY(&handle->write_queue)) {
- q = QUEUE_HEAD(&handle->write_queue);
- QUEUE_REMOVE(q);
-
- req = QUEUE_DATA(q, uv_udp_send_t, queue);
- req->status = UV_ECANCELED;
- QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
- }
-
- uv__udp_run_completed(handle);
-
- assert(handle->send_queue_size == 0);
- assert(handle->send_queue_count == 0);
-
- /* Now tear down the handle. */
- handle->recv_cb = NULL;
- handle->alloc_cb = NULL;
- /* but _do not_ touch close_cb */
-}
-
-
-static void uv__udp_run_completed(uv_udp_t* handle) {
- uv_udp_send_t* req;
- QUEUE* q;
-
- assert(!(handle->flags & UV_HANDLE_UDP_PROCESSING));
- handle->flags |= UV_HANDLE_UDP_PROCESSING;
-
- while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
- q = QUEUE_HEAD(&handle->write_completed_queue);
- QUEUE_REMOVE(q);
-
- req = QUEUE_DATA(q, uv_udp_send_t, queue);
- uv__req_unregister(handle->loop, req);
-
- handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
- handle->send_queue_count--;
-
- if (req->bufs != req->bufsml)
- uv__free(req->bufs);
- req->bufs = NULL;
-
- if (req->send_cb == NULL)
- continue;
-
- /* req->status >= 0 == bytes written
- * req->status < 0 == errno
- */
- if (req->status >= 0)
- req->send_cb(req, 0);
- else
- req->send_cb(req, req->status);
- }
-
- if (QUEUE_EMPTY(&handle->write_queue)) {
- /* Pending queue and completion queue empty, stop watcher. */
- uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
- if (!uv__io_active(&handle->io_watcher, POLLIN))
- uv__handle_stop(handle);
- }
-
- handle->flags &= ~UV_HANDLE_UDP_PROCESSING;
-}
-
-
-static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
- uv_udp_t* handle;
-
- handle = container_of(w, uv_udp_t, io_watcher);
- assert(handle->type == UV_UDP);
-
- if (revents & POLLIN)
- uv__udp_recvmsg(handle);
-
- if (revents & POLLOUT) {
- uv__udp_sendmsg(handle);
- uv__udp_run_completed(handle);
- }
-}
-
-
-static void uv__udp_recvmsg(uv_udp_t* handle) {
- struct sockaddr_storage peer;
- struct msghdr h;
- ssize_t nread;
- uv_buf_t buf;
- int flags;
- int count;
-
- assert(handle->recv_cb != NULL);
- assert(handle->alloc_cb != NULL);
-
- /* Prevent loop starvation when the data comes in as fast as (or faster than)
- * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
- */
- count = 32;
-
- memset(&h, 0, sizeof(h));
- h.msg_name = &peer;
-
- do {
- buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
- if (buf.base == NULL || buf.len == 0) {
- handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
- return;
- }
- assert(buf.base != NULL);
-
- h.msg_namelen = sizeof(peer);
- h.msg_iov = (iovec*) &buf;
- h.msg_iovlen = 1;
-
- do {
- nread = recvmsg(handle->io_watcher.fd, &h, 0);
- }
- while (nread == -1 && errno == EINTR);
-
- if (nread == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK)
- handle->recv_cb(handle, 0, &buf, NULL, 0);
- else
- handle->recv_cb(handle, UV__ERR(errno), &buf, NULL, 0);
- }
- else {
- const struct sockaddr *addr;
- if (h.msg_namelen == 0)
- addr = NULL;
- else
- addr = (const struct sockaddr*) &peer;
-
- flags = 0;
- if (h.msg_flags & MSG_TRUNC)
- flags |= UV_UDP_PARTIAL;
-
- handle->recv_cb(handle, nread, &buf, addr, flags);
- }
- }
- /* recv_cb callback may decide to pause or close the handle */
- while (nread != -1
- && count-- > 0
- && handle->io_watcher.fd != -1
- && handle->recv_cb != NULL);
-}
-
-
-static void uv__udp_sendmsg(uv_udp_t* handle) {
- uv_udp_send_t* req;
- QUEUE* q;
- struct msghdr h;
- ssize_t size;
-
- while (!QUEUE_EMPTY(&handle->write_queue)) {
- q = QUEUE_HEAD(&handle->write_queue);
- assert(q != NULL);
-
- req = QUEUE_DATA(q, uv_udp_send_t, queue);
- assert(req != NULL);
-
- memset(&h, 0, sizeof h);
- if (req->addr.ss_family == AF_UNSPEC) {
- h.msg_name = NULL;
- h.msg_namelen = 0;
- } else {
- h.msg_name = &req->addr;
- if (req->addr.ss_family == AF_INET6)
- h.msg_namelen = sizeof(struct sockaddr_in6);
- else if (req->addr.ss_family == AF_INET)
- h.msg_namelen = sizeof(struct sockaddr_in);
- else if (req->addr.ss_family == AF_UNIX)
- h.msg_namelen = sizeof(struct sockaddr_un);
- else {
- assert(0 && "unsupported address family");
- abort();
- }
- }
- h.msg_iov = (struct iovec*) req->bufs;
- h.msg_iovlen = req->nbufs;
-
- do {
- size = sendmsg(handle->io_watcher.fd, &h, 0);
- } while (size == -1 && errno == EINTR);
-
- if (size == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
- break;
- }
-
- req->status = (size == -1 ? UV__ERR(errno) : size);
-
- /* Sending a datagram is an atomic operation: either all data
- * is written or nothing is (and EMSGSIZE is raised). That is
- * why we don't handle partial writes. Just pop the request
- * off the write queue and onto the completed queue, done.
- */
- QUEUE_REMOVE(&req->queue);
- QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
- uv__io_feed(handle->loop, &handle->io_watcher);
- }
-}
-
-
-/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
- * refinements for programs that use multicast.
- *
- * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
- * are different from the BSDs: it _shares_ the port rather than steal it
- * from the current listener. While useful, it's not something we can emulate
- * on other platforms so we don't enable it.
- *
- * zOS does not support getsockname with SO_REUSEPORT option when using
- * AF_UNIX.
- */
-static int uv__set_reuse(int fd) {
- int yes;
- yes = 1;
-
-#if defined(SO_REUSEPORT) && defined(__MVS__)
- struct sockaddr_in sockfd;
- unsigned int sockfd_len = sizeof(sockfd);
- if (getsockname(fd, (struct sockaddr*) &sockfd, &sockfd_len) == -1)
- return UV__ERR(errno);
- if (sockfd.sin_family == AF_UNIX) {
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
- return UV__ERR(errno);
- } else {
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
- return UV__ERR(errno);
- }
-#elif defined(SO_REUSEPORT) && !defined(__linux__)
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
- return UV__ERR(errno);
-#else
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
- return UV__ERR(errno);
-#endif
-
- return 0;
-}
-
-
-int uv__udp_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- int err;
- int yes;
- int fd;
-
- /* Check for bad flags. */
- if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
- return UV_EINVAL;
-
- /* Cannot set IPv6-only mode on non-IPv6 socket. */
- if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
- return UV_EINVAL;
-
- fd = handle->io_watcher.fd;
- if (fd == -1) {
- err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
- if (err < 0)
- return err;
- fd = err;
- handle->io_watcher.fd = fd;
- }
-
- if (flags & UV_UDP_REUSEADDR) {
- err = uv__set_reuse(fd);
- if (err)
- return err;
- }
-
- if (flags & UV_UDP_IPV6ONLY) {
-#ifdef IPV6_V6ONLY
- yes = 1;
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
- err = UV__ERR(errno);
- return err;
- }
-#else
- err = UV_ENOTSUP;
- return err;
-#endif
- }
-
- if (bind(fd, addr, addrlen)) {
- err = UV__ERR(errno);
- if (errno == EAFNOSUPPORT)
- /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
- * socket created with AF_INET to an AF_INET6 address or vice versa. */
- err = UV_EINVAL;
- return err;
- }
-
- if (addr->sa_family == AF_INET6)
- handle->flags |= UV_HANDLE_IPV6;
-
- handle->flags |= UV_HANDLE_BOUND;
- return 0;
-}
-
-
-static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
- int domain,
- unsigned int flags) {
- union {
- struct sockaddr_in6 in6;
- struct sockaddr_in in;
- struct sockaddr addr;
- } taddr;
- socklen_t addrlen;
-
- if (handle->io_watcher.fd != -1)
- return 0;
-
- switch (domain) {
- case AF_INET:
- {
- struct sockaddr_in* addr = &taddr.in;
- memset(addr, 0, sizeof *addr);
- addr->sin_family = AF_INET;
- addr->sin_addr.s_addr = INADDR_ANY;
- addrlen = sizeof *addr;
- break;
- }
- case AF_INET6:
- {
- struct sockaddr_in6* addr = &taddr.in6;
- memset(addr, 0, sizeof *addr);
- addr->sin6_family = AF_INET6;
- addr->sin6_addr = in6addr_any;
- addrlen = sizeof *addr;
- break;
- }
- default:
- assert(0 && "unsupported address family");
- abort();
- }
-
- return uv__udp_bind(handle, &taddr.addr, addrlen, flags);
-}
-
-
-int uv__udp_connect(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen) {
- int err;
-
- err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
- if (err)
- return err;
-
- do {
- errno = 0;
- err = connect(handle->io_watcher.fd, addr, addrlen);
- } while (err == -1 && errno == EINTR);
-
- if (err)
- return UV__ERR(errno);
-
- handle->flags |= UV_HANDLE_UDP_CONNECTED;
-
- return 0;
-}
-
-
-int uv__udp_disconnect(uv_udp_t* handle) {
- int r;
- struct sockaddr addr;
-
- memset(&addr, 0, sizeof(addr));
-
- addr.sa_family = AF_UNSPEC;
-
- do {
- errno = 0;
- r = connect(handle->io_watcher.fd, &addr, sizeof(addr));
- } while (r == -1 && errno == EINTR);
-
- if (r == -1 && errno != EAFNOSUPPORT)
- return UV__ERR(errno);
-
- handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
- return 0;
-}
-
-
-int uv__udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_udp_send_cb send_cb) {
- int err;
- int empty_queue;
-
- assert(nbufs > 0);
-
- if (addr) {
- err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
- if (err)
- return err;
- }
-
- /* It's legal for send_queue_count > 0 even when the write_queue is empty;
- * it means there are error-state requests in the write_completed_queue that
- * will touch up send_queue_size/count later.
- */
- empty_queue = (handle->send_queue_count == 0);
-
- uv__req_init(handle->loop, req, UV_UDP_SEND);
- assert(addrlen <= sizeof(req->addr));
- if (addr == NULL)
- req->addr.ss_family = AF_UNSPEC;
- else
- memcpy(&req->addr, addr, addrlen);
- req->send_cb = send_cb;
- req->handle = handle;
- req->nbufs = nbufs;
-
- req->bufs = req->bufsml;
- if (nbufs > ARRAY_SIZE(req->bufsml))
- req->bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(bufs[0]));
-
- if (req->bufs == NULL) {
- uv__req_unregister(handle->loop, req);
- return UV_ENOMEM;
- }
-
- memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
- handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
- handle->send_queue_count++;
- QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
- uv__handle_start(handle);
-
- if (empty_queue && !(handle->flags & UV_HANDLE_UDP_PROCESSING)) {
- uv__udp_sendmsg(handle);
-
- /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
- * away. In such cases the `io_watcher` has to be queued for asynchronous
- * write.
- */
- if (!QUEUE_EMPTY(&handle->write_queue))
- uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
- } else {
- uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
- }
-
- return 0;
-}
-
-
-int uv__udp_try_send(uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen) {
- int err;
- struct msghdr h;
- ssize_t size;
-
- assert(nbufs > 0);
-
- /* already sending a message */
- if (handle->send_queue_count != 0)
- return UV_EAGAIN;
-
- if (addr) {
- err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
- if (err)
- return err;
- } else {
- assert(handle->flags & UV_HANDLE_UDP_CONNECTED);
- }
-
- memset(&h, 0, sizeof h);
- h.msg_name = (struct sockaddr*) addr;
- h.msg_namelen = addrlen;
- h.msg_iov = (struct iovec*) bufs;
- h.msg_iovlen = nbufs;
-
- do {
- size = sendmsg(handle->io_watcher.fd, &h, 0);
- } while (size == -1 && errno == EINTR);
-
- if (size == -1) {
- if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOBUFS)
- return UV_EAGAIN;
- else
- return UV__ERR(errno);
- }
-
- return size;
-}
-
-
-static int uv__udp_set_membership4(uv_udp_t* handle,
- const struct sockaddr_in* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- struct ip_mreq mreq;
- int optname;
- int err;
-
- memset(&mreq, 0, sizeof mreq);
-
- if (interface_addr) {
- err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
- if (err)
- return err;
- } else {
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- }
-
- mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
-
- switch (membership) {
- case UV_JOIN_GROUP:
- optname = IP_ADD_MEMBERSHIP;
- break;
- case UV_LEAVE_GROUP:
- optname = IP_DROP_MEMBERSHIP;
- break;
- default:
- return UV_EINVAL;
- }
-
- if (setsockopt(handle->io_watcher.fd,
- IPPROTO_IP,
- optname,
- &mreq,
- sizeof(mreq))) {
-#if defined(__MVS__)
- if (errno == ENXIO)
- return UV_ENODEV;
-#endif
- return UV__ERR(errno);
- }
-
- return 0;
-}
-
-
-static int uv__udp_set_membership6(uv_udp_t* handle,
- const struct sockaddr_in6* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- int optname;
- struct ipv6_mreq mreq;
- struct sockaddr_in6 addr6;
-
- memset(&mreq, 0, sizeof mreq);
-
- if (interface_addr) {
- if (uv_ip6_addr(interface_addr, 0, &addr6))
- return UV_EINVAL;
- mreq.ipv6mr_interface = addr6.sin6_scope_id;
- } else {
- mreq.ipv6mr_interface = 0;
- }
-
- mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
-
- switch (membership) {
- case UV_JOIN_GROUP:
- optname = IPV6_ADD_MEMBERSHIP;
- break;
- case UV_LEAVE_GROUP:
- optname = IPV6_DROP_MEMBERSHIP;
- break;
- default:
- return UV_EINVAL;
- }
-
- if (setsockopt(handle->io_watcher.fd,
- IPPROTO_IPV6,
- optname,
- &mreq,
- sizeof(mreq))) {
-#if defined(__MVS__)
- if (errno == ENXIO)
- return UV_ENODEV;
-#endif
- return UV__ERR(errno);
- }
-
- return 0;
-}
-
-
-int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
- int domain;
- int err;
- int fd;
-
- /* Use the lower 8 bits for the domain */
- domain = flags & 0xFF;
- if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
- return UV_EINVAL;
-
- if (flags & ~0xFF)
- return UV_EINVAL;
-
- if (domain != AF_UNSPEC) {
- err = uv__socket(domain, SOCK_DGRAM, 0);
- if (err < 0)
- return err;
- fd = err;
- } else {
- fd = -1;
- }
-
- uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
- handle->alloc_cb = NULL;
- handle->recv_cb = NULL;
- handle->send_queue_size = 0;
- handle->send_queue_count = 0;
- uv__io_init(&handle->io_watcher, uv__udp_io, fd);
- QUEUE_INIT(&handle->write_queue);
- QUEUE_INIT(&handle->write_completed_queue);
-
- return 0;
-}
-
-
-int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
- return uv_udp_init_ex(loop, handle, AF_UNSPEC);
-}
-
-
-int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
- int err;
-
- /* Check for already active socket. */
- if (handle->io_watcher.fd != -1)
- return UV_EBUSY;
-
- if (uv__fd_exists(handle->loop, sock))
- return UV_EEXIST;
-
- err = uv__nonblock(sock, 1);
- if (err)
- return err;
-
- err = uv__set_reuse(sock);
- if (err)
- return err;
-
- handle->io_watcher.fd = sock;
- if (uv__udp_is_connected(handle))
- handle->flags |= UV_HANDLE_UDP_CONNECTED;
-
- return 0;
-}
-
-
-int uv_udp_set_membership(uv_udp_t* handle,
- const char* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- int err;
- struct sockaddr_in addr4;
- struct sockaddr_in6 addr6;
-
- if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
- if (err)
- return err;
- return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
- } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
- err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
- if (err)
- return err;
- return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
- } else {
- return UV_EINVAL;
- }
-}
-
-static int uv__setsockopt(uv_udp_t* handle,
- int option4,
- int option6,
- const void* val,
- size_t size) {
- int r;
-
- if (handle->flags & UV_HANDLE_IPV6)
- r = setsockopt(handle->io_watcher.fd,
- IPPROTO_IPV6,
- option6,
- val,
- size);
- else
- r = setsockopt(handle->io_watcher.fd,
- IPPROTO_IP,
- option4,
- val,
- size);
- if (r)
- return UV__ERR(errno);
-
- return 0;
-}
-
-static int uv__setsockopt_maybe_char(uv_udp_t* handle,
- int option4,
- int option6,
- int val) {
-#if defined(__sun) || defined(_AIX) || defined(__MVS__)
- char arg = val;
-#elif defined(__OpenBSD__)
- unsigned char arg = val;
-#else
- int arg = val;
-#endif
-
- if (val < 0 || val > 255)
- return UV_EINVAL;
-
- return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
-}
-
-
-int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
- if (setsockopt(handle->io_watcher.fd,
- SOL_SOCKET,
- SO_BROADCAST,
- &on,
- sizeof(on))) {
- return UV__ERR(errno);
- }
-
- return 0;
-}
-
-
-int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
- if (ttl < 1 || ttl > 255)
- return UV_EINVAL;
-
-#if defined(__MVS__)
- if (!(handle->flags & UV_HANDLE_IPV6))
- return UV_ENOTSUP; /* zOS does not support setting ttl for IPv4 */
-#endif
-
-/*
- * On Solaris and derivatives such as SmartOS, the length of socket options
- * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
- * so hardcode the size of these options on this platform,
- * and use the general uv__setsockopt_maybe_char call on other platforms.
- */
-#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
- defined(__MVS__)
-
- return uv__setsockopt(handle,
- IP_TTL,
- IPV6_UNICAST_HOPS,
- &ttl,
- sizeof(ttl));
-
-#else /* !(defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
- defined(__MVS__)) */
-
- return uv__setsockopt_maybe_char(handle,
- IP_TTL,
- IPV6_UNICAST_HOPS,
- ttl);
-
-#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
- defined(__MVS__) */
-}
-
-
-int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
-/*
- * On Solaris and derivatives such as SmartOS, the length of socket options
- * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
- * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
- * and use the general uv__setsockopt_maybe_char call otherwise.
- */
-#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
- defined(__MVS__)
- if (handle->flags & UV_HANDLE_IPV6)
- return uv__setsockopt(handle,
- IP_MULTICAST_TTL,
- IPV6_MULTICAST_HOPS,
- &ttl,
- sizeof(ttl));
-#endif /* defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
- defined(__MVS__) */
-
- return uv__setsockopt_maybe_char(handle,
- IP_MULTICAST_TTL,
- IPV6_MULTICAST_HOPS,
- ttl);
-}
-
-
-int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
-/*
- * On Solaris and derivatives such as SmartOS, the length of socket options
- * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
- * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
- * and use the general uv__setsockopt_maybe_char call otherwise.
- */
-#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
- defined(__MVS__)
- if (handle->flags & UV_HANDLE_IPV6)
- return uv__setsockopt(handle,
- IP_MULTICAST_LOOP,
- IPV6_MULTICAST_LOOP,
- &on,
- sizeof(on));
-#endif /* defined(__sun) || defined(_AIX) ||defined(__OpenBSD__) ||
- defined(__MVS__) */
-
- return uv__setsockopt_maybe_char(handle,
- IP_MULTICAST_LOOP,
- IPV6_MULTICAST_LOOP,
- on);
-}
-
-int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- struct sockaddr_storage addr_st;
- struct sockaddr_in* addr4;
- struct sockaddr_in6* addr6;
-
- addr4 = (struct sockaddr_in*) &addr_st;
- addr6 = (struct sockaddr_in6*) &addr_st;
-
- if (!interface_addr) {
- memset(&addr_st, 0, sizeof addr_st);
- if (handle->flags & UV_HANDLE_IPV6) {
- addr_st.ss_family = AF_INET6;
- addr6->sin6_scope_id = 0;
- } else {
- addr_st.ss_family = AF_INET;
- addr4->sin_addr.s_addr = htonl(INADDR_ANY);
- }
- } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
- /* nothing, address was parsed */
- } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
- /* nothing, address was parsed */
- } else {
- return UV_EINVAL;
- }
-
- if (addr_st.ss_family == AF_INET) {
- if (setsockopt(handle->io_watcher.fd,
- IPPROTO_IP,
- IP_MULTICAST_IF,
- (void*) &addr4->sin_addr,
- sizeof(addr4->sin_addr)) == -1) {
- return UV__ERR(errno);
- }
- } else if (addr_st.ss_family == AF_INET6) {
- if (setsockopt(handle->io_watcher.fd,
- IPPROTO_IPV6,
- IPV6_MULTICAST_IF,
- &addr6->sin6_scope_id,
- sizeof(addr6->sin6_scope_id)) == -1) {
- return UV__ERR(errno);
- }
- } else {
- assert(0 && "unexpected address family");
- abort();
- }
-
- return 0;
-}
-
-int uv_udp_getpeername(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getpeername,
- name,
- namelen);
-}
-
-int uv_udp_getsockname(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getsockname,
- name,
- namelen);
-}
-
-
-int uv__udp_recv_start(uv_udp_t* handle,
- uv_alloc_cb alloc_cb,
- uv_udp_recv_cb recv_cb) {
- int err;
-
- if (alloc_cb == NULL || recv_cb == NULL)
- return UV_EINVAL;
-
- if (uv__io_active(&handle->io_watcher, POLLIN))
- return UV_EALREADY; /* FIXME(bnoordhuis) Should be UV_EBUSY. */
-
- err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
- if (err)
- return err;
-
- handle->alloc_cb = alloc_cb;
- handle->recv_cb = recv_cb;
-
- uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-int uv__udp_recv_stop(uv_udp_t* handle) {
- uv__io_stop(handle->loop, &handle->io_watcher, POLLIN);
-
- if (!uv__io_active(&handle->io_watcher, POLLOUT))
- uv__handle_stop(handle);
-
- handle->alloc_cb = NULL;
- handle->recv_cb = NULL;
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/uv-common.cpp b/wpiutil/src/main/native/libuv/src/uv-common.cpp
deleted file mode 100644
index 3c65476..0000000
--- a/wpiutil/src/main/native/libuv/src/uv-common.cpp
+++ /dev/null
@@ -1,797 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "uv-common.h"
-
-#include <assert.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <stddef.h> /* NULL */
-#include <stdio.h>
-#include <stdlib.h> /* malloc */
-#include <string.h> /* memset */
-
-#if defined(_WIN32)
-# include <malloc.h> /* malloc */
-#else
-# include <net/if.h> /* if_nametoindex */
-# include <sys/un.h> /* AF_UNIX, sockaddr_un */
-#endif
-
-
-typedef struct {
- uv_malloc_func local_malloc;
- uv_realloc_func local_realloc;
- uv_calloc_func local_calloc;
- uv_free_func local_free;
-} uv__allocator_t;
-
-static uv__allocator_t uv__allocator = {
- malloc,
- realloc,
- calloc,
- free,
-};
-
-char* uv__strdup(const char* s) {
- size_t len = strlen(s) + 1;
- char* m = (char*)uv__malloc(len);
- if (m == NULL)
- return NULL;
- return (char*)memcpy(m, s, len);
-}
-
-char* uv__strndup(const char* s, size_t n) {
- char* m;
- size_t len = strlen(s);
- if (n < len)
- len = n;
- m = (char*)uv__malloc(len + 1);
- if (m == NULL)
- return NULL;
- m[len] = '\0';
- return (char*)memcpy(m, s, len);
-}
-
-void* uv__malloc(size_t size) {
- if (size > 0)
- return uv__allocator.local_malloc(size);
- return NULL;
-}
-
-void uv__free(void* ptr) {
- int saved_errno;
-
- /* Libuv expects that free() does not clobber errno. The system allocator
- * honors that assumption but custom allocators may not be so careful.
- */
- saved_errno = errno;
- uv__allocator.local_free(ptr);
- errno = saved_errno;
-}
-
-void* uv__calloc(size_t count, size_t size) {
- return uv__allocator.local_calloc(count, size);
-}
-
-void* uv__realloc(void* ptr, size_t size) {
- if (size > 0)
- return uv__allocator.local_realloc(ptr, size);
- uv__free(ptr);
- return NULL;
-}
-
-int uv_replace_allocator(uv_malloc_func malloc_func,
- uv_realloc_func realloc_func,
- uv_calloc_func calloc_func,
- uv_free_func free_func) {
- if (malloc_func == NULL || realloc_func == NULL ||
- calloc_func == NULL || free_func == NULL) {
- return UV_EINVAL;
- }
-
- uv__allocator.local_malloc = malloc_func;
- uv__allocator.local_realloc = realloc_func;
- uv__allocator.local_calloc = calloc_func;
- uv__allocator.local_free = free_func;
-
- return 0;
-}
-
-#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
-
-size_t uv_handle_size(uv_handle_type type) {
- switch (type) {
- UV_HANDLE_TYPE_MAP(XX)
- default:
- return -1;
- }
-}
-
-size_t uv_req_size(uv_req_type type) {
- switch(type) {
- UV_REQ_TYPE_MAP(XX)
- default:
- return -1;
- }
-}
-
-#undef XX
-
-
-size_t uv_loop_size(void) {
- return sizeof(uv_loop_t);
-}
-
-
-uv_buf_t uv_buf_init(char* base, unsigned int len) {
- uv_buf_t buf;
- buf.base = base;
- buf.len = len;
- return buf;
-}
-
-
-static const char* uv__unknown_err_code(int err) {
- char buf[32];
- char* copy;
-
- snprintf(buf, sizeof(buf), "Unknown system error %d", err);
- copy = uv__strdup(buf);
-
- return copy != NULL ? copy : "Unknown system error";
-}
-
-#define UV_ERR_NAME_GEN_R(name, _) \
-case UV_## name: \
- uv__strscpy(buf, #name, buflen); break;
-char* uv_err_name_r(int err, char* buf, size_t buflen) {
- switch (err) {
- UV_ERRNO_MAP(UV_ERR_NAME_GEN_R)
- default: snprintf(buf, buflen, "Unknown system error %d", err);
- }
- return buf;
-}
-#undef UV_ERR_NAME_GEN_R
-
-
-#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
-const char* uv_err_name(int err) {
- switch (err) {
- UV_ERRNO_MAP(UV_ERR_NAME_GEN)
- }
- return uv__unknown_err_code(err);
-}
-#undef UV_ERR_NAME_GEN
-
-
-#define UV_STRERROR_GEN_R(name, msg) \
-case UV_ ## name: \
- snprintf(buf, buflen, "%s", msg); break;
-char* uv_strerror_r(int err, char* buf, size_t buflen) {
- switch (err) {
- UV_ERRNO_MAP(UV_STRERROR_GEN_R)
- default: snprintf(buf, buflen, "Unknown system error %d", err);
- }
- return buf;
-}
-#undef UV_STRERROR_GEN_R
-
-
-#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
-const char* uv_strerror(int err) {
- switch (err) {
- UV_ERRNO_MAP(UV_STRERROR_GEN)
- }
- return uv__unknown_err_code(err);
-}
-#undef UV_STRERROR_GEN
-
-
-int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
- memset(addr, 0, sizeof(*addr));
- addr->sin_family = AF_INET;
- addr->sin_port = htons(port);
- return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
-}
-
-
-int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
- char address_part[40];
- size_t address_part_size;
- const char* zone_index;
-
- memset(addr, 0, sizeof(*addr));
- addr->sin6_family = AF_INET6;
- addr->sin6_port = htons(port);
-#ifdef SIN6_LEN
- addr->sin6_len = sizeof(*addr);
-#endif
-
- zone_index = strchr(ip, '%');
- if (zone_index != NULL) {
- address_part_size = zone_index - ip;
- if (address_part_size >= sizeof(address_part))
- address_part_size = sizeof(address_part) - 1;
-
- memcpy(address_part, ip, address_part_size);
- address_part[address_part_size] = '\0';
- ip = address_part;
-
- zone_index++; /* skip '%' */
- /* NOTE: unknown interface (id=0) is silently ignored */
-#ifdef _WIN32
- addr->sin6_scope_id = atoi(zone_index);
-#else
- addr->sin6_scope_id = if_nametoindex(zone_index);
-#endif
- }
-
- return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
-}
-
-
-int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
- return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
-}
-
-
-int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
- return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
-}
-
-
-int uv_tcp_bind(uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int flags) {
- unsigned int addrlen;
-
- if (handle->type != UV_TCP)
- return UV_EINVAL;
-
- if (addr->sa_family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (addr->sa_family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
- else
- return UV_EINVAL;
-
- return uv__tcp_bind(handle, addr, addrlen, flags);
-}
-
-
-int uv_udp_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int flags) {
- unsigned int addrlen;
-
- if (handle->type != UV_UDP)
- return UV_EINVAL;
-
- if (addr->sa_family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (addr->sa_family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
- else
- return UV_EINVAL;
-
- return uv__udp_bind(handle, addr, addrlen, flags);
-}
-
-
-int uv_tcp_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- uv_connect_cb cb) {
- unsigned int addrlen;
-
- if (handle->type != UV_TCP)
- return UV_EINVAL;
-
- if (addr->sa_family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (addr->sa_family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
- else
- return UV_EINVAL;
-
- return uv__tcp_connect(req, handle, addr, addrlen, cb);
-}
-
-
-int uv_udp_connect(uv_udp_t* handle, const struct sockaddr* addr) {
- unsigned int addrlen;
-
- if (handle->type != UV_UDP)
- return UV_EINVAL;
-
- /* Disconnect the handle */
- if (addr == NULL) {
- if (!(handle->flags & UV_HANDLE_UDP_CONNECTED))
- return UV_ENOTCONN;
-
- return uv__udp_disconnect(handle);
- }
-
- if (addr->sa_family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (addr->sa_family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
- else
- return UV_EINVAL;
-
- if (handle->flags & UV_HANDLE_UDP_CONNECTED)
- return UV_EISCONN;
-
- return uv__udp_connect(handle, addr, addrlen);
-}
-
-
-int uv__udp_is_connected(uv_udp_t* handle) {
- struct sockaddr_storage addr;
- int addrlen;
- if (handle->type != UV_UDP)
- return 0;
-
- addrlen = sizeof(addr);
- if (uv_udp_getpeername(handle, (struct sockaddr*) &addr, &addrlen) != 0)
- return 0;
-
- return addrlen > 0;
-}
-
-
-int uv__udp_check_before_send(uv_udp_t* handle, const struct sockaddr* addr) {
- unsigned int addrlen;
-
- if (handle->type != UV_UDP)
- return UV_EINVAL;
-
- if (addr != NULL && (handle->flags & UV_HANDLE_UDP_CONNECTED))
- return UV_EISCONN;
-
- if (addr == NULL && !(handle->flags & UV_HANDLE_UDP_CONNECTED))
- return UV_EDESTADDRREQ;
-
- if (addr != NULL) {
- if (addr->sa_family == AF_INET)
- addrlen = sizeof(struct sockaddr_in);
- else if (addr->sa_family == AF_INET6)
- addrlen = sizeof(struct sockaddr_in6);
-#if defined(AF_UNIX) && !defined(_WIN32)
- else if (addr->sa_family == AF_UNIX)
- addrlen = sizeof(struct sockaddr_un);
-#endif
- else
- return UV_EINVAL;
- } else {
- addrlen = 0;
- }
-
- return addrlen;
-}
-
-
-int uv_udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- uv_udp_send_cb send_cb) {
- int addrlen;
-
- addrlen = uv__udp_check_before_send(handle, addr);
- if (addrlen < 0)
- return addrlen;
-
- return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
-}
-
-
-int uv_udp_try_send(uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr) {
- int addrlen;
-
- addrlen = uv__udp_check_before_send(handle, addr);
- if (addrlen < 0)
- return addrlen;
-
- return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
-}
-
-
-int uv_udp_recv_start(uv_udp_t* handle,
- uv_alloc_cb alloc_cb,
- uv_udp_recv_cb recv_cb) {
- if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
- return UV_EINVAL;
- else
- return uv__udp_recv_start(handle, alloc_cb, recv_cb);
-}
-
-
-int uv_udp_recv_stop(uv_udp_t* handle) {
- if (handle->type != UV_UDP)
- return UV_EINVAL;
- else
- return uv__udp_recv_stop(handle);
-}
-
-
-void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
- QUEUE queue;
- QUEUE* q;
- uv_handle_t* h;
-
- QUEUE_MOVE(&loop->handle_queue, &queue);
- while (!QUEUE_EMPTY(&queue)) {
- q = QUEUE_HEAD(&queue);
- h = QUEUE_DATA(q, uv_handle_t, handle_queue);
-
- QUEUE_REMOVE(q);
- QUEUE_INSERT_TAIL(&loop->handle_queue, q);
-
- if (h->flags & UV_HANDLE_INTERNAL) continue;
- walk_cb(h, arg);
- }
-}
-
-
-static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
- const char* type;
- QUEUE* q;
- uv_handle_t* h;
-
- if (loop == NULL)
- loop = uv_default_loop();
-
- QUEUE_FOREACH(q, &loop->handle_queue) {
- h = QUEUE_DATA(q, uv_handle_t, handle_queue);
-
- if (only_active && !uv__is_active(h))
- continue;
-
- switch (h->type) {
-#define X(uc, lc) case UV_##uc: type = #lc; break;
- UV_HANDLE_TYPE_MAP(X)
-#undef X
- default: type = "<unknown>";
- }
-
- fprintf(stream,
- "[%c%c%c] %-8s %p\n",
- "R-"[!(h->flags & UV_HANDLE_REF)],
- "A-"[!(h->flags & UV_HANDLE_ACTIVE)],
- "I-"[!(h->flags & UV_HANDLE_INTERNAL)],
- type,
- (void*)h);
- }
-}
-
-
-void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
- uv__print_handles(loop, 0, stream);
-}
-
-
-void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
- uv__print_handles(loop, 1, stream);
-}
-
-
-void uv_ref(uv_handle_t* handle) {
- uv__handle_ref(handle);
-}
-
-
-void uv_unref(uv_handle_t* handle) {
- uv__handle_unref(handle);
-}
-
-
-int uv_has_ref(const uv_handle_t* handle) {
- return uv__has_ref(handle);
-}
-
-
-void uv_stop(uv_loop_t* loop) {
- loop->stop_flag = 1;
-}
-
-
-uint64_t uv_now(const uv_loop_t* loop) {
- return loop->time;
-}
-
-
-
-size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
- unsigned int i;
- size_t bytes;
-
- bytes = 0;
- for (i = 0; i < nbufs; i++)
- bytes += (size_t) bufs[i].len;
-
- return bytes;
-}
-
-int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
- return uv__socket_sockopt(handle, SO_RCVBUF, value);
-}
-
-int uv_send_buffer_size(uv_handle_t* handle, int *value) {
- return uv__socket_sockopt(handle, SO_SNDBUF, value);
-}
-
-int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
- size_t required_len;
-
- if (!uv__is_active(handle)) {
- *size = 0;
- return UV_EINVAL;
- }
-
- required_len = strlen(handle->path);
- if (required_len >= *size) {
- *size = required_len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, handle->path, required_len);
- *size = required_len;
- buffer[required_len] = '\0';
-
- return 0;
-}
-
-/* The windows implementation does not have the same structure layout as
- * the unix implementation (nbufs is not directly inside req but is
- * contained in a nested union/struct) so this function locates it.
-*/
-static unsigned int* uv__get_nbufs(uv_fs_t* req) {
-#ifdef _WIN32
- return &req->fs.info.nbufs;
-#else
- return &req->nbufs;
-#endif
-}
-
-/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
- * systems. So, the memory should be released using free(). On Windows,
- * uv__malloc() is used, so use uv__free() to free memory.
-*/
-#ifdef _WIN32
-# define uv__fs_scandir_free uv__free
-#else
-# define uv__fs_scandir_free free
-#endif
-
-void uv__fs_scandir_cleanup(uv_fs_t* req) {
- uv__dirent_t** dents;
-
- unsigned int* nbufs = uv__get_nbufs(req);
-
- dents = (uv__dirent_t**)(req->ptr);
- if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
- (*nbufs)--;
- for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
- uv__fs_scandir_free(dents[*nbufs]);
-
- uv__fs_scandir_free(req->ptr);
- req->ptr = NULL;
-}
-
-
-int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
- uv__dirent_t** dents;
- uv__dirent_t* dent;
- unsigned int* nbufs;
-
- /* Check to see if req passed */
- if (req->result < 0)
- return req->result;
-
- /* Ptr will be null if req was canceled or no files found */
- if (!req->ptr)
- return UV_EOF;
-
- nbufs = uv__get_nbufs(req);
- assert(nbufs);
-
- dents = (uv__dirent_t**)(req->ptr);
-
- /* Free previous entity */
- if (*nbufs > 0)
- uv__fs_scandir_free(dents[*nbufs - 1]);
-
- /* End was already reached */
- if (*nbufs == (unsigned int) req->result) {
- uv__fs_scandir_free(dents);
- req->ptr = NULL;
- return UV_EOF;
- }
-
- dent = dents[(*nbufs)++];
-
- ent->name = dent->d_name;
- ent->type = uv__fs_get_dirent_type(dent);
-
- return 0;
-}
-
-uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent) {
- uv_dirent_type_t type;
-
-#ifdef HAVE_DIRENT_TYPES
- switch (dent->d_type) {
- case UV__DT_DIR:
- type = UV_DIRENT_DIR;
- break;
- case UV__DT_FILE:
- type = UV_DIRENT_FILE;
- break;
- case UV__DT_LINK:
- type = UV_DIRENT_LINK;
- break;
- case UV__DT_FIFO:
- type = UV_DIRENT_FIFO;
- break;
- case UV__DT_SOCKET:
- type = UV_DIRENT_SOCKET;
- break;
- case UV__DT_CHAR:
- type = UV_DIRENT_CHAR;
- break;
- case UV__DT_BLOCK:
- type = UV_DIRENT_BLOCK;
- break;
- default:
- type = UV_DIRENT_UNKNOWN;
- }
-#else
- type = UV_DIRENT_UNKNOWN;
-#endif
-
- return type;
-}
-
-void uv__fs_readdir_cleanup(uv_fs_t* req) {
- uv_dir_t* dir;
- uv_dirent_t* dirents;
- int i;
-
- if (req->ptr == NULL)
- return;
-
- dir = (uv_dir_t*)req->ptr;
- dirents = dir->dirents;
- req->ptr = NULL;
-
- if (dirents == NULL)
- return;
-
- for (i = 0; i < req->result; ++i) {
- uv__free((char*) dirents[i].name);
- dirents[i].name = NULL;
- }
-}
-
-
-#ifdef __clang__
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wvarargs"
-#endif
-
-int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
- va_list ap;
- int err;
-
- va_start(ap, option);
- /* Any platform-agnostic options should be handled here. */
- err = uv__loop_configure(loop, option, ap);
- va_end(ap);
-
- return err;
-}
-
-#ifdef __clang__
-# pragma clang diagnostic pop
-#endif
-
-
-static uv_loop_t default_loop_struct;
-static uv_loop_t* default_loop_ptr;
-
-
-uv_loop_t* uv_default_loop(void) {
- if (default_loop_ptr != NULL)
- return default_loop_ptr;
-
- if (uv_loop_init(&default_loop_struct))
- return NULL;
-
- default_loop_ptr = &default_loop_struct;
- return default_loop_ptr;
-}
-
-
-uv_loop_t* uv_loop_new(void) {
- uv_loop_t* loop;
-
- loop = (uv_loop_t*)uv__malloc(sizeof(*loop));
- if (loop == NULL)
- return NULL;
-
- if (uv_loop_init(loop)) {
- uv__free(loop);
- return NULL;
- }
-
- return loop;
-}
-
-
-int uv_loop_close(uv_loop_t* loop) {
- QUEUE* q;
- uv_handle_t* h;
-#ifndef NDEBUG
- void* saved_data;
-#endif
-
- if (uv__has_active_reqs(loop))
- return UV_EBUSY;
-
- QUEUE_FOREACH(q, &loop->handle_queue) {
- h = QUEUE_DATA(q, uv_handle_t, handle_queue);
- if (!(h->flags & UV_HANDLE_INTERNAL))
- return UV_EBUSY;
- }
-
- uv__loop_close(loop);
-
-#ifndef NDEBUG
- saved_data = loop->data;
- memset(loop, -1, sizeof(*loop));
- loop->data = saved_data;
-#endif
- if (loop == default_loop_ptr)
- default_loop_ptr = NULL;
-
- return 0;
-}
-
-
-void uv_loop_delete(uv_loop_t* loop) {
- uv_loop_t* default_loop;
- int err;
-
- default_loop = default_loop_ptr;
-
- err = uv_loop_close(loop);
- (void) err; /* Squelch compiler warnings. */
- assert(err == 0);
- if (loop != default_loop)
- uv__free(loop);
-}
diff --git a/wpiutil/src/main/native/libuv/src/uv-common.h b/wpiutil/src/main/native/libuv/src/uv-common.h
deleted file mode 100644
index f788161..0000000
--- a/wpiutil/src/main/native/libuv/src/uv-common.h
+++ /dev/null
@@ -1,326 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-/*
- * This file is private to libuv. It provides common functionality to both
- * Windows and Unix backends.
- */
-
-#ifndef UV_COMMON_H_
-#define UV_COMMON_H_
-
-#include <assert.h>
-#include <stdarg.h>
-#include <stddef.h>
-
-#if defined(_MSC_VER) && _MSC_VER < 1600
-# include "uv/stdint-msvc2008.h"
-#else
-# include <stdint.h>
-#endif
-
-#include "uv.h"
-#include "uv/tree.h"
-#include "queue.h"
-#include "strscpy.h"
-
-#if EDOM > 0
-# define UV__ERR(x) (-(x))
-#else
-# define UV__ERR(x) (x)
-#endif
-
-#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
-extern int snprintf(char*, size_t, const char*, ...);
-#endif
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-#define container_of(ptr, type, member) \
- ((type *) ((char *) (ptr) - offsetof(type, member)))
-
-#define STATIC_ASSERT(expr) \
- void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
-
-/* Handle flags. Some flags are specific to Windows or UNIX. */
-enum {
- /* Used by all handles. */
- UV_HANDLE_CLOSING = 0x00000001,
- UV_HANDLE_CLOSED = 0x00000002,
- UV_HANDLE_ACTIVE = 0x00000004,
- UV_HANDLE_REF = 0x00000008,
- UV_HANDLE_INTERNAL = 0x00000010,
- UV_HANDLE_ENDGAME_QUEUED = 0x00000020,
-
- /* Used by streams. */
- UV_HANDLE_LISTENING = 0x00000040,
- UV_HANDLE_CONNECTION = 0x00000080,
- UV_HANDLE_SHUTTING = 0x00000100,
- UV_HANDLE_SHUT = 0x00000200,
- UV_HANDLE_READ_PARTIAL = 0x00000400,
- UV_HANDLE_READ_EOF = 0x00000800,
-
- /* Used by streams and UDP handles. */
- UV_HANDLE_READING = 0x00001000,
- UV_HANDLE_BOUND = 0x00002000,
- UV_HANDLE_READABLE = 0x00004000,
- UV_HANDLE_WRITABLE = 0x00008000,
- UV_HANDLE_READ_PENDING = 0x00010000,
- UV_HANDLE_SYNC_BYPASS_IOCP = 0x00020000,
- UV_HANDLE_ZERO_READ = 0x00040000,
- UV_HANDLE_EMULATE_IOCP = 0x00080000,
- UV_HANDLE_BLOCKING_WRITES = 0x00100000,
- UV_HANDLE_CANCELLATION_PENDING = 0x00200000,
-
- /* Used by uv_tcp_t and uv_udp_t handles */
- UV_HANDLE_IPV6 = 0x00400000,
-
- /* Only used by uv_tcp_t handles. */
- UV_HANDLE_TCP_NODELAY = 0x01000000,
- UV_HANDLE_TCP_KEEPALIVE = 0x02000000,
- UV_HANDLE_TCP_SINGLE_ACCEPT = 0x04000000,
- UV_HANDLE_TCP_ACCEPT_STATE_CHANGING = 0x08000000,
- UV_HANDLE_TCP_SOCKET_CLOSED = 0x10000000,
- UV_HANDLE_SHARED_TCP_SOCKET = 0x20000000,
-
- /* Only used by uv_udp_t handles. */
- UV_HANDLE_UDP_PROCESSING = 0x01000000,
- UV_HANDLE_UDP_CONNECTED = 0x02000000,
-
- /* Only used by uv_pipe_t handles. */
- UV_HANDLE_NON_OVERLAPPED_PIPE = 0x01000000,
- UV_HANDLE_PIPESERVER = 0x02000000,
-
- /* Only used by uv_tty_t handles. */
- UV_HANDLE_TTY_READABLE = 0x01000000,
- UV_HANDLE_TTY_RAW = 0x02000000,
- UV_HANDLE_TTY_SAVED_POSITION = 0x04000000,
- UV_HANDLE_TTY_SAVED_ATTRIBUTES = 0x08000000,
-
- /* Only used by uv_signal_t handles. */
- UV_SIGNAL_ONE_SHOT_DISPATCHED = 0x01000000,
- UV_SIGNAL_ONE_SHOT = 0x02000000,
-
- /* Only used by uv_poll_t handles. */
- UV_HANDLE_POLL_SLOW = 0x01000000
-};
-
-int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
-
-void uv__loop_close(uv_loop_t* loop);
-
-int uv__tcp_bind(uv_tcp_t* tcp,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags);
-
-int uv__tcp_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_connect_cb cb);
-
-int uv__udp_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags);
-
-int uv__udp_connect(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen);
-
-int uv__udp_disconnect(uv_udp_t* handle);
-
-int uv__udp_is_connected(uv_udp_t* handle);
-
-int uv__udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_udp_send_cb send_cb);
-
-int uv__udp_try_send(uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen);
-
-int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
- uv_udp_recv_cb recv_cb);
-
-int uv__udp_recv_stop(uv_udp_t* handle);
-
-void uv__fs_poll_close(uv_fs_poll_t* handle);
-
-int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
-
-enum uv__work_kind {
- UV__WORK_CPU,
- UV__WORK_FAST_IO,
- UV__WORK_SLOW_IO
-};
-
-void uv__work_submit(uv_loop_t* loop,
- struct uv__work *w,
- enum uv__work_kind kind,
- void (*work)(struct uv__work *w),
- void (*done)(struct uv__work *w, int status));
-
-void uv__work_done(uv_async_t* handle);
-
-size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
-
-int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
-
-void uv__fs_scandir_cleanup(uv_fs_t* req);
-void uv__fs_readdir_cleanup(uv_fs_t* req);
-uv_dirent_type_t uv__fs_get_dirent_type(uv__dirent_t* dent);
-
-int uv__next_timeout(const uv_loop_t* loop);
-void uv__run_timers(uv_loop_t* loop);
-void uv__timer_close(uv_timer_t* handle);
-
-#define uv__has_active_reqs(loop) \
- ((loop)->active_reqs.count > 0)
-
-#define uv__req_register(loop, req) \
- do { \
- (loop)->active_reqs.count++; \
- } \
- while (0)
-
-#define uv__req_unregister(loop, req) \
- do { \
- assert(uv__has_active_reqs(loop)); \
- (loop)->active_reqs.count--; \
- } \
- while (0)
-
-#define uv__has_active_handles(loop) \
- ((loop)->active_handles > 0)
-
-#define uv__active_handle_add(h) \
- do { \
- (h)->loop->active_handles++; \
- } \
- while (0)
-
-#define uv__active_handle_rm(h) \
- do { \
- (h)->loop->active_handles--; \
- } \
- while (0)
-
-#define uv__is_active(h) \
- (((h)->flags & UV_HANDLE_ACTIVE) != 0)
-
-#define uv__is_closing(h) \
- (((h)->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED)) != 0)
-
-#define uv__handle_start(h) \
- do { \
- if (((h)->flags & UV_HANDLE_ACTIVE) != 0) break; \
- (h)->flags |= UV_HANDLE_ACTIVE; \
- if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_add(h); \
- } \
- while (0)
-
-#define uv__handle_stop(h) \
- do { \
- if (((h)->flags & UV_HANDLE_ACTIVE) == 0) break; \
- (h)->flags &= ~UV_HANDLE_ACTIVE; \
- if (((h)->flags & UV_HANDLE_REF) != 0) uv__active_handle_rm(h); \
- } \
- while (0)
-
-#define uv__handle_ref(h) \
- do { \
- if (((h)->flags & UV_HANDLE_REF) != 0) break; \
- (h)->flags |= UV_HANDLE_REF; \
- if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
- if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
- } \
- while (0)
-
-#define uv__handle_unref(h) \
- do { \
- if (((h)->flags & UV_HANDLE_REF) == 0) break; \
- (h)->flags &= ~UV_HANDLE_REF; \
- if (((h)->flags & UV_HANDLE_CLOSING) != 0) break; \
- if (((h)->flags & UV_HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
- } \
- while (0)
-
-#define uv__has_ref(h) \
- (((h)->flags & UV_HANDLE_REF) != 0)
-
-#if defined(_WIN32)
-# define uv__handle_platform_init(h) ((h)->u.fd = -1)
-#else
-# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
-#endif
-
-#define uv__handle_init(loop_, h, type_) \
- do { \
- (h)->loop = (loop_); \
- (h)->type = (type_); \
- (h)->flags = UV_HANDLE_REF; /* Ref the loop when active. */ \
- QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
- uv__handle_platform_init(h); \
- } \
- while (0)
-
-/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of
- * a circular dependency between src/uv-common.h and src/win/internal.h.
- */
-#if defined(_WIN32)
-# define UV_REQ_INIT(req, typ) \
- do { \
- (req)->type = (typ); \
- (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \
- } \
- while (0)
-#else
-# define UV_REQ_INIT(req, typ) \
- do { \
- (req)->type = (typ); \
- } \
- while (0)
-#endif
-
-#define uv__req_init(loop, req, typ) \
- do { \
- UV_REQ_INIT(req, typ); \
- uv__req_register(loop, req); \
- } \
- while (0)
-
-/* Allocator prototypes */
-void *uv__calloc(size_t count, size_t size);
-char *uv__strdup(const char* s);
-char *uv__strndup(const char* s, size_t n);
-void* uv__malloc(size_t size);
-void uv__free(void* ptr);
-void* uv__realloc(void* ptr, size_t size);
-
-#endif /* UV_COMMON_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/uv-data-getter-setters.cpp b/wpiutil/src/main/native/libuv/src/uv-data-getter-setters.cpp
deleted file mode 100644
index c302566..0000000
--- a/wpiutil/src/main/native/libuv/src/uv-data-getter-setters.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-#include "uv.h"
-
-const char* uv_handle_type_name(uv_handle_type type) {
- switch (type) {
-#define XX(uc,lc) case UV_##uc: return #lc;
- UV_HANDLE_TYPE_MAP(XX)
-#undef XX
- case UV_FILE: return "file";
- case UV_HANDLE_TYPE_MAX:
- case UV_UNKNOWN_HANDLE: return NULL;
- }
- return NULL;
-}
-
-uv_handle_type uv_handle_get_type(const uv_handle_t* handle) {
- return handle->type;
-}
-
-void* uv_handle_get_data(const uv_handle_t* handle) {
- return handle->data;
-}
-
-uv_loop_t* uv_handle_get_loop(const uv_handle_t* handle) {
- return handle->loop;
-}
-
-void uv_handle_set_data(uv_handle_t* handle, void* data) {
- handle->data = data;
-}
-
-const char* uv_req_type_name(uv_req_type type) {
- switch (type) {
-#define XX(uc,lc) case UV_##uc: return #lc;
- UV_REQ_TYPE_MAP(XX)
-#undef XX
- case UV_REQ_TYPE_MAX:
- case UV_UNKNOWN_REQ:
- default: /* UV_REQ_TYPE_PRIVATE */
- break;
- }
- return NULL;
-}
-
-uv_req_type uv_req_get_type(const uv_req_t* req) {
- return req->type;
-}
-
-void* uv_req_get_data(const uv_req_t* req) {
- return req->data;
-}
-
-void uv_req_set_data(uv_req_t* req, void* data) {
- req->data = data;
-}
-
-size_t uv_stream_get_write_queue_size(const uv_stream_t* stream) {
- return stream->write_queue_size;
-}
-
-size_t uv_udp_get_send_queue_size(const uv_udp_t* handle) {
- return handle->send_queue_size;
-}
-
-size_t uv_udp_get_send_queue_count(const uv_udp_t* handle) {
- return handle->send_queue_count;
-}
-
-uv_pid_t uv_process_get_pid(const uv_process_t* proc) {
- return proc->pid;
-}
-
-uv_fs_type uv_fs_get_type(const uv_fs_t* req) {
- return req->fs_type;
-}
-
-ssize_t uv_fs_get_result(const uv_fs_t* req) {
- return req->result;
-}
-
-void* uv_fs_get_ptr(const uv_fs_t* req) {
- return req->ptr;
-}
-
-const char* uv_fs_get_path(const uv_fs_t* req) {
- return req->path;
-}
-
-uv_stat_t* uv_fs_get_statbuf(uv_fs_t* req) {
- return &req->statbuf;
-}
-
-void* uv_loop_get_data(const uv_loop_t* loop) {
- return loop->data;
-}
-
-void uv_loop_set_data(uv_loop_t* loop, void* data) {
- loop->data = data;
-}
diff --git a/wpiutil/src/main/native/libuv/src/version.cpp b/wpiutil/src/main/native/libuv/src/version.cpp
deleted file mode 100644
index 686dedd..0000000
--- a/wpiutil/src/main/native/libuv/src/version.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-
-#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
-#define UV_STRINGIFY_HELPER(v) #v
-
-#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
- UV_STRINGIFY(UV_VERSION_MINOR) "." \
- UV_STRINGIFY(UV_VERSION_PATCH)
-
-#if UV_VERSION_IS_RELEASE
-# define UV_VERSION_STRING UV_VERSION_STRING_BASE
-#else
-# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
-#endif
-
-
-unsigned int uv_version(void) {
- return UV_VERSION_HEX;
-}
-
-
-const char* uv_version_string(void) {
- return UV_VERSION_STRING;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/async.cpp b/wpiutil/src/main/native/libuv/src/win/async.cpp
deleted file mode 100644
index d787f66..0000000
--- a/wpiutil/src/main/native/libuv/src/win/async.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "atomicops-inl.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
- if (handle->flags & UV_HANDLE_CLOSING &&
- !handle->async_sent) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- uv__handle_close(handle);
- }
-}
-
-
-int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
- uv_req_t* req;
-
- uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
- handle->async_sent = 0;
- handle->async_cb = async_cb;
-
- req = &handle->async_req;
- UV_REQ_INIT(req, UV_WAKEUP);
- req->data = handle;
-
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
- if (!((uv_async_t*)handle)->async_sent) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-
- uv__handle_closing(handle);
-}
-
-
-int uv_async_send(uv_async_t* handle) {
- uv_loop_t* loop = handle->loop;
-
- if (handle->type != UV_ASYNC) {
- /* Can't set errno because that's not thread-safe. */
- return -1;
- }
-
- /* The user should make sure never to call uv_async_send to a closing or
- * closed handle. */
- assert(!(handle->flags & UV_HANDLE_CLOSING));
-
- if (!uv__atomic_exchange_set(&handle->async_sent)) {
- POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
- }
-
- return 0;
-}
-
-
-void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
- uv_req_t* req) {
- assert(handle->type == UV_ASYNC);
- assert(req->type == UV_WAKEUP);
-
- handle->async_sent = 0;
-
- if (handle->flags & UV_HANDLE_CLOSING) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- } else if (handle->async_cb != NULL) {
- handle->async_cb(handle);
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/atomicops-inl.h b/wpiutil/src/main/native/libuv/src/win/atomicops-inl.h
deleted file mode 100644
index 52713cf..0000000
--- a/wpiutil/src/main/native/libuv/src/win/atomicops-inl.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_ATOMICOPS_INL_H_
-#define UV_WIN_ATOMICOPS_INL_H_
-
-#include "uv.h"
-#include "internal.h"
-
-
-/* Atomic set operation on char */
-#ifdef _MSC_VER /* MSVC */
-
-/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less
- * efficient than InterlockedExchange, but InterlockedExchange8 does not exist,
- * and interlocked operations on larger targets might require the target to be
- * aligned. */
-#pragma intrinsic(_InterlockedOr8)
-
-static char INLINE uv__atomic_exchange_set(char volatile* target) {
- return _InterlockedOr8(target, 1);
-}
-
-#else /* GCC */
-
-/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
-static inline char uv__atomic_exchange_set(char volatile* target) {
- const char one = 1;
- char old_value;
- __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
- : "=r"(old_value), "=m"(*target)
- : "0"(one), "m"(*target)
- : "memory");
- return old_value;
-}
-
-#endif
-
-#endif /* UV_WIN_ATOMICOPS_INL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/core.cpp b/wpiutil/src/main/native/libuv/src/win/core.cpp
deleted file mode 100644
index 1e162dd..0000000
--- a/wpiutil/src/main/native/libuv/src/win/core.cpp
+++ /dev/null
@@ -1,654 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
-#include <crtdbg.h>
-#endif
-
-#include "uv.h"
-#include "internal.h"
-#include "queue.h"
-#include "handle-inl.h"
-#include "heap-inl.h"
-#include "req-inl.h"
-
-/* uv_once initialization guards */
-static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
-
-
-#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
-/* Our crt debug report handler allows us to temporarily disable asserts
- * just for the current thread.
- */
-
-UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
-
-static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
- if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
- return FALSE;
-
- if (ret_val) {
- /* Set ret_val to 0 to continue with normal execution.
- * Set ret_val to 1 to trigger a breakpoint.
- */
-
- if(IsDebuggerPresent())
- *ret_val = 1;
- else
- *ret_val = 0;
- }
-
- /* Don't call _CrtDbgReport. */
- return TRUE;
-}
-#else
-UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
-#endif
-
-
-#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
-static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
- const wchar_t* function, const wchar_t * file, unsigned int line,
- uintptr_t reserved) {
- /* No-op. */
-}
-#endif
-
-static uv_loop_t** uv__loops;
-static int uv__loops_size;
-static int uv__loops_capacity;
-#define UV__LOOPS_CHUNK_SIZE 8
-static uv_mutex_t uv__loops_lock;
-
-static void uv__loops_init(void) {
- uv_mutex_init(&uv__loops_lock);
-}
-
-static int uv__loops_add(uv_loop_t* loop) {
- uv_loop_t** new_loops;
- int new_capacity, i;
-
- uv_mutex_lock(&uv__loops_lock);
-
- if (uv__loops_size == uv__loops_capacity) {
- new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
- new_loops = (uv_loop_t**)
- uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
- if (!new_loops)
- goto failed_loops_realloc;
- uv__loops = new_loops;
- for (i = uv__loops_capacity; i < new_capacity; ++i)
- uv__loops[i] = NULL;
- uv__loops_capacity = new_capacity;
- }
- uv__loops[uv__loops_size] = loop;
- ++uv__loops_size;
-
- uv_mutex_unlock(&uv__loops_lock);
- return 0;
-
-failed_loops_realloc:
- uv_mutex_unlock(&uv__loops_lock);
- return ERROR_OUTOFMEMORY;
-}
-
-static void uv__loops_remove(uv_loop_t* loop) {
- int loop_index;
- int smaller_capacity;
- uv_loop_t** new_loops;
-
- uv_mutex_lock(&uv__loops_lock);
-
- for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
- if (uv__loops[loop_index] == loop)
- break;
- }
- /* If loop was not found, ignore */
- if (loop_index == uv__loops_size)
- goto loop_removed;
-
- uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
- uv__loops[uv__loops_size - 1] = NULL;
- --uv__loops_size;
-
- if (uv__loops_size == 0) {
- uv__loops_capacity = 0;
- uv__free(uv__loops);
- uv__loops = NULL;
- goto loop_removed;
- }
-
- /* If we didn't grow to big skip downsizing */
- if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
- goto loop_removed;
-
- /* Downsize only if more than half of buffer is free */
- smaller_capacity = uv__loops_capacity / 2;
- if (uv__loops_size >= smaller_capacity)
- goto loop_removed;
- new_loops = (uv_loop_t**)
- uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
- if (!new_loops)
- goto loop_removed;
- uv__loops = new_loops;
- uv__loops_capacity = smaller_capacity;
-
-loop_removed:
- uv_mutex_unlock(&uv__loops_lock);
-}
-
-void uv__wake_all_loops(void) {
- int i;
- uv_loop_t* loop;
-
- uv_mutex_lock(&uv__loops_lock);
- for (i = 0; i < uv__loops_size; ++i) {
- loop = uv__loops[i];
- assert(loop);
- if (loop->iocp != INVALID_HANDLE_VALUE)
- PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
- }
- uv_mutex_unlock(&uv__loops_lock);
-}
-
-static void uv_init(void) {
- /* Tell Windows that we will handle critical errors. */
- SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
- SEM_NOOPENFILEERRORBOX);
-
- /* Tell the CRT to not exit the application when an invalid parameter is
- * passed. The main issue is that invalid FDs will trigger this behavior.
- */
-#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
- _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
-#endif
-
- /* We also need to setup our debug report handler because some CRT
- * functions (eg _get_osfhandle) raise an assert when called with invalid
- * FDs even though they return the proper error code in the release build.
- */
-#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
- _CrtSetReportHook(uv__crt_dbg_report_handler);
-#endif
-
- /* Initialize tracking of all uv loops */
- uv__loops_init();
-
- /* Fetch winapi function pointers. This must be done first because other
- * initialization code might need these function pointers to be loaded.
- */
- uv_winapi_init();
-
- /* Initialize winsock */
- uv_winsock_init();
-
- /* Initialize FS */
- uv_fs_init();
-
- /* Initialize signal stuff */
- uv_signals_init();
-
- /* Initialize console */
- uv_console_init();
-
- /* Initialize utilities */
- uv__util_init();
-
- /* Initialize system wakeup detection */
- uv__init_detect_system_wakeup();
-}
-
-
-int uv_loop_init(uv_loop_t* loop) {
- struct heap* timer_heap;
- int err;
-
- /* Initialize libuv itself first */
- uv__once_init();
-
- /* Create an I/O completion port */
- loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
- if (loop->iocp == NULL)
- return uv_translate_sys_error(GetLastError());
-
- /* To prevent uninitialized memory access, loop->time must be initialized
- * to zero before calling uv_update_time for the first time.
- */
- loop->time = 0;
- uv_update_time(loop);
-
- QUEUE_INIT(&loop->wq);
- QUEUE_INIT(&loop->handle_queue);
- loop->active_reqs.count = 0;
- loop->active_handles = 0;
-
- loop->pending_reqs_tail = NULL;
-
- loop->endgame_handles = NULL;
-
- loop->timer_heap = timer_heap = (heap*)uv__malloc(sizeof(*timer_heap));
- if (timer_heap == NULL) {
- err = UV_ENOMEM;
- goto fail_timers_alloc;
- }
-
- heap_init(timer_heap);
-
- loop->check_handles = NULL;
- loop->prepare_handles = NULL;
- loop->idle_handles = NULL;
-
- loop->next_prepare_handle = NULL;
- loop->next_check_handle = NULL;
- loop->next_idle_handle = NULL;
-
- memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
-
- loop->active_tcp_streams = 0;
- loop->active_udp_streams = 0;
-
- loop->timer_counter = 0;
- loop->stop_flag = 0;
-
- err = uv_mutex_init(&loop->wq_mutex);
- if (err)
- goto fail_mutex_init;
-
- err = uv_async_init(loop, &loop->wq_async, uv__work_done);
- if (err)
- goto fail_async_init;
-
- uv__handle_unref(&loop->wq_async);
- loop->wq_async.flags |= UV_HANDLE_INTERNAL;
-
- err = uv__loops_add(loop);
- if (err)
- goto fail_async_init;
-
- return 0;
-
-fail_async_init:
- uv_mutex_destroy(&loop->wq_mutex);
-
-fail_mutex_init:
- uv__free(timer_heap);
- loop->timer_heap = NULL;
-
-fail_timers_alloc:
- CloseHandle(loop->iocp);
- loop->iocp = INVALID_HANDLE_VALUE;
-
- return err;
-}
-
-
-void uv_update_time(uv_loop_t* loop) {
- uint64_t new_time = uv__hrtime(1000);
- assert(new_time >= loop->time);
- loop->time = new_time;
-}
-
-
-void uv__once_init(void) {
- uv_once(&uv_init_guard_, uv_init);
-}
-
-
-void uv__loop_close(uv_loop_t* loop) {
- size_t i;
-
- uv__loops_remove(loop);
-
- /* close the async handle without needing an extra loop iteration */
- assert(!loop->wq_async.async_sent);
- loop->wq_async.close_cb = NULL;
- uv__handle_closing(&loop->wq_async);
- uv__handle_close(&loop->wq_async);
-
- for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
- SOCKET sock = loop->poll_peer_sockets[i];
- if (sock != 0 && sock != INVALID_SOCKET)
- closesocket(sock);
- }
-
- uv_mutex_lock(&loop->wq_mutex);
- assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
- assert(!uv__has_active_reqs(loop));
- uv_mutex_unlock(&loop->wq_mutex);
- uv_mutex_destroy(&loop->wq_mutex);
-
- uv__free(loop->timer_heap);
- loop->timer_heap = NULL;
-
- CloseHandle(loop->iocp);
-}
-
-
-int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
- return UV_ENOSYS;
-}
-
-
-int uv_backend_fd(const uv_loop_t* loop) {
- return -1;
-}
-
-
-int uv_loop_fork(uv_loop_t* loop) {
- return UV_ENOSYS;
-}
-
-
-int uv_backend_timeout(const uv_loop_t* loop) {
- if (loop->stop_flag != 0)
- return 0;
-
- if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
- return 0;
-
- if (loop->pending_reqs_tail)
- return 0;
-
- if (loop->endgame_handles)
- return 0;
-
- if (loop->idle_handles)
- return 0;
-
- return uv__next_timeout(loop);
-}
-
-
-static void uv__poll_wine(uv_loop_t* loop, DWORD timeout) {
- DWORD bytes;
- ULONG_PTR key;
- OVERLAPPED* overlapped;
- uv_req_t* req;
- int repeat;
- uint64_t timeout_time;
-
- timeout_time = loop->time + timeout;
-
- for (repeat = 0; ; repeat++) {
- GetQueuedCompletionStatus(loop->iocp,
- &bytes,
- &key,
- &overlapped,
- timeout);
-
- if (overlapped) {
- /* Package was dequeued */
- req = uv_overlapped_to_req(overlapped);
- uv_insert_pending_req(loop, req);
-
- /* Some time might have passed waiting for I/O,
- * so update the loop time here.
- */
- uv_update_time(loop);
- } else if (GetLastError() != WAIT_TIMEOUT) {
- /* Serious error */
- uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
- } else if (timeout > 0) {
- /* GetQueuedCompletionStatus can occasionally return a little early.
- * Make sure that the desired timeout target time is reached.
- */
- uv_update_time(loop);
- if (timeout_time > loop->time) {
- timeout = (DWORD)(timeout_time - loop->time);
- /* The first call to GetQueuedCompletionStatus should return very
- * close to the target time and the second should reach it, but
- * this is not stated in the documentation. To make sure a busy
- * loop cannot happen, the timeout is increased exponentially
- * starting on the third round.
- */
- timeout += repeat ? (1 << (repeat - 1)) : 0;
- continue;
- }
- }
- break;
- }
-}
-
-
-static void uv__poll(uv_loop_t* loop, DWORD timeout) {
- BOOL success;
- uv_req_t* req;
- OVERLAPPED_ENTRY overlappeds[128];
- ULONG count;
- ULONG i;
- int repeat;
- uint64_t timeout_time;
-
- timeout_time = loop->time + timeout;
-
- for (repeat = 0; ; repeat++) {
- success = GetQueuedCompletionStatusEx(loop->iocp,
- overlappeds,
- ARRAY_SIZE(overlappeds),
- &count,
- timeout,
- FALSE);
-
- if (success) {
- for (i = 0; i < count; i++) {
- /* Package was dequeued, but see if it is not a empty package
- * meant only to wake us up.
- */
- if (overlappeds[i].lpOverlapped) {
- req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
- uv_insert_pending_req(loop, req);
- }
- }
-
- /* Some time might have passed waiting for I/O,
- * so update the loop time here.
- */
- uv_update_time(loop);
- } else if (GetLastError() != WAIT_TIMEOUT) {
- /* Serious error */
- uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
- } else if (timeout > 0) {
- /* GetQueuedCompletionStatus can occasionally return a little early.
- * Make sure that the desired timeout target time is reached.
- */
- uv_update_time(loop);
- if (timeout_time > loop->time) {
- timeout = (DWORD)(timeout_time - loop->time);
- /* The first call to GetQueuedCompletionStatus should return very
- * close to the target time and the second should reach it, but
- * this is not stated in the documentation. To make sure a busy
- * loop cannot happen, the timeout is increased exponentially
- * starting on the third round.
- */
- timeout += repeat ? (1 << (repeat - 1)) : 0;
- continue;
- }
- }
- break;
- }
-}
-
-
-static int uv__loop_alive(const uv_loop_t* loop) {
- return uv__has_active_handles(loop) ||
- uv__has_active_reqs(loop) ||
- loop->endgame_handles != NULL;
-}
-
-
-int uv_loop_alive(const uv_loop_t* loop) {
- return uv__loop_alive(loop);
-}
-
-
-int uv_run(uv_loop_t *loop, uv_run_mode mode) {
- DWORD timeout;
- int r;
- int ran_pending;
-
- r = uv__loop_alive(loop);
- if (!r)
- uv_update_time(loop);
-
- while (r != 0 && loop->stop_flag == 0) {
- uv_update_time(loop);
- uv__run_timers(loop);
-
- ran_pending = uv_process_reqs(loop);
- uv_idle_invoke(loop);
- uv_prepare_invoke(loop);
-
- timeout = 0;
- if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
- timeout = uv_backend_timeout(loop);
-
- if (pGetQueuedCompletionStatusEx)
- uv__poll(loop, timeout);
- else
- uv__poll_wine(loop, timeout);
-
-
- uv_check_invoke(loop);
- uv_process_endgames(loop);
-
- if (mode == UV_RUN_ONCE) {
- /* UV_RUN_ONCE implies forward progress: at least one callback must have
- * been invoked when it returns. uv__io_poll() can return without doing
- * I/O (meaning: no callbacks) when its timeout expires - which means we
- * have pending timers that satisfy the forward progress constraint.
- *
- * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
- * the check.
- */
- uv__run_timers(loop);
- }
-
- r = uv__loop_alive(loop);
- if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
- break;
- }
-
- /* The if statement lets the compiler compile it to a conditional store.
- * Avoids dirtying a cache line.
- */
- if (loop->stop_flag != 0)
- loop->stop_flag = 0;
-
- return r;
-}
-
-
-int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
- uv_os_fd_t fd_out;
-
- switch (handle->type) {
- case UV_TCP:
- fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
- break;
-
- case UV_NAMED_PIPE:
- fd_out = ((uv_pipe_t*) handle)->handle;
- break;
-
- case UV_TTY:
- fd_out = ((uv_tty_t*) handle)->handle;
- break;
-
- case UV_UDP:
- fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
- break;
-
- case UV_POLL:
- fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
- break;
-
- default:
- return UV_EINVAL;
- }
-
- if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
- return UV_EBADF;
-
- *fd = fd_out;
- return 0;
-}
-
-
-int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
- int r;
- int len;
- SOCKET socket;
-
- if (handle == NULL || value == NULL)
- return UV_EINVAL;
-
- if (handle->type == UV_TCP)
- socket = ((uv_tcp_t*) handle)->socket;
- else if (handle->type == UV_UDP)
- socket = ((uv_udp_t*) handle)->socket;
- else
- return UV_ENOTSUP;
-
- len = sizeof(*value);
-
- if (*value == 0)
- r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
- else
- r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
-
- if (r == SOCKET_ERROR)
- return uv_translate_sys_error(WSAGetLastError());
-
- return 0;
-}
-
-int uv_cpumask_size(void) {
- return (int)(sizeof(DWORD_PTR) * 8);
-}
-
-int uv__getsockpeername(const uv_handle_t* handle,
- uv__peersockfunc func,
- struct sockaddr* name,
- int* namelen,
- int delayed_error) {
-
- int result;
- uv_os_fd_t fd;
-
- result = uv_fileno(handle, &fd);
- if (result != 0)
- return result;
-
- if (delayed_error)
- return uv_translate_sys_error(delayed_error);
-
- result = func((SOCKET) fd, name, namelen);
- if (result != 0)
- return uv_translate_sys_error(WSAGetLastError());
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/detect-wakeup.cpp b/wpiutil/src/main/native/libuv/src/win/detect-wakeup.cpp
deleted file mode 100644
index 72dfb7a..0000000
--- a/wpiutil/src/main/native/libuv/src/win/detect-wakeup.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "uv.h"
-#include "internal.h"
-#include "winapi.h"
-
-static void uv__register_system_resume_callback(void);
-
-void uv__init_detect_system_wakeup(void) {
- /* Try registering system power event callback. This is the cleanest
- * method, but it will only work on Win8 and above.
- */
- uv__register_system_resume_callback();
-}
-
-static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
- ULONG Type,
- PVOID Setting) {
- if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
- uv__wake_all_loops();
-
- return 0;
-}
-
-static void uv__register_system_resume_callback(void) {
- _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
- _HPOWERNOTIFY registration_handle;
-
- if (pPowerRegisterSuspendResumeNotification == NULL)
- return;
-
- recipient.Callback = uv__system_resume_callback;
- recipient.Context = NULL;
- (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
- &recipient,
- ®istration_handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/dl.cpp b/wpiutil/src/main/native/libuv/src/win/dl.cpp
deleted file mode 100644
index 676be4d..0000000
--- a/wpiutil/src/main/native/libuv/src/win/dl.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 "uv.h"
-#include "internal.h"
-
-static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno);
-
-
-int uv_dlopen(const char* filename, uv_lib_t* lib) {
- WCHAR filename_w[32768];
-
- lib->handle = NULL;
- lib->errmsg = NULL;
-
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- filename,
- -1,
- filename_w,
- ARRAY_SIZE(filename_w))) {
- return uv__dlerror(lib, filename, GetLastError());
- }
-
- lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- if (lib->handle == NULL) {
- return uv__dlerror(lib, filename, GetLastError());
- }
-
- return 0;
-}
-
-
-void uv_dlclose(uv_lib_t* lib) {
- if (lib->errmsg) {
- LocalFree((void*)lib->errmsg);
- lib->errmsg = NULL;
- }
-
- if (lib->handle) {
- /* Ignore errors. No good way to signal them without leaking memory. */
- FreeLibrary(lib->handle);
- lib->handle = NULL;
- }
-}
-
-
-int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
- /* Cast though integer to suppress pedantic warning about forbidden cast. */
- *ptr = (void*)(uintptr_t) GetProcAddress(lib->handle, name);
- return uv__dlerror(lib, "", *ptr ? 0 : GetLastError());
-}
-
-
-const char* uv_dlerror(const uv_lib_t* lib) {
- return lib->errmsg ? lib->errmsg : "no error";
-}
-
-
-static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
- static const CHAR fallback_error[] = "error: %1!d!";
- DWORD_PTR args[1];
- args[0] = (DWORD_PTR) errorno;
-
- FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
- FORMAT_MESSAGE_ARGUMENT_ARRAY |
- FORMAT_MESSAGE_ALLOCATE_BUFFER,
- fallback_error, 0, 0,
- (LPSTR) &lib->errmsg,
- 0, (va_list*) args);
-}
-
-
-
-static int uv__dlerror(uv_lib_t* lib, const char* filename, DWORD errorno) {
- DWORD_PTR arg;
- DWORD res;
- char* msg;
-
- if (lib->errmsg) {
- LocalFree(lib->errmsg);
- lib->errmsg = NULL;
- }
-
- if (errorno == 0)
- return 0;
-
- res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
- (LPSTR) &lib->errmsg, 0, NULL);
-
- if (!res && (GetLastError() == ERROR_MUI_FILE_NOT_FOUND ||
- GetLastError() == ERROR_RESOURCE_TYPE_NOT_FOUND)) {
- res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- 0, (LPSTR) &lib->errmsg, 0, NULL);
- }
-
- if (res && errorno == ERROR_BAD_EXE_FORMAT && strstr(lib->errmsg, "%1")) {
- msg = lib->errmsg;
- lib->errmsg = NULL;
- arg = (DWORD_PTR) filename;
- res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_ARGUMENT_ARRAY |
- FORMAT_MESSAGE_FROM_STRING,
- msg,
- 0, 0, (LPSTR) &lib->errmsg, 0, (va_list*) &arg);
- LocalFree(msg);
- }
-
- if (!res)
- uv__format_fallback_error(lib, errorno);
-
- return -1;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/error.cpp b/wpiutil/src/main/native/libuv/src/win/error.cpp
deleted file mode 100644
index 24924ba..0000000
--- a/wpiutil/src/main/native/libuv/src/win/error.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-/*
- * Display an error message and abort the event loop.
- */
-void uv_fatal_error(const int errorno, const char* syscall) {
- char* buf = NULL;
- const char* errmsg;
-
- FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
-
- if (buf) {
- errmsg = buf;
- } else {
- errmsg = "Unknown error";
- }
-
- /* FormatMessage messages include a newline character already, so don't add
- * another. */
- if (syscall) {
- fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
- } else {
- fprintf(stderr, "(%d) %s", errorno, errmsg);
- }
-
- if (buf) {
- LocalFree(buf);
- }
-
- DebugBreak();
- abort();
-}
-
-
-int uv_translate_sys_error(int sys_errno) {
- if (sys_errno <= 0) {
- return sys_errno; /* If < 0 then it's already a libuv error. */
- }
-
- switch (sys_errno) {
- case ERROR_NOACCESS: return UV_EACCES;
- case WSAEACCES: return UV_EACCES;
- case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
- case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
- case WSAEADDRINUSE: return UV_EADDRINUSE;
- case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
- case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
- case WSAEWOULDBLOCK: return UV_EAGAIN;
- case WSAEALREADY: return UV_EALREADY;
- case ERROR_INVALID_FLAGS: return UV_EBADF;
- case ERROR_INVALID_HANDLE: return UV_EBADF;
- case ERROR_LOCK_VIOLATION: return UV_EBUSY;
- case ERROR_PIPE_BUSY: return UV_EBUSY;
- case ERROR_SHARING_VIOLATION: return UV_EBUSY;
- case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
- case WSAEINTR: return UV_ECANCELED;
- case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
- case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
- case WSAECONNABORTED: return UV_ECONNABORTED;
- case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
- case WSAECONNREFUSED: return UV_ECONNREFUSED;
- case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
- case WSAECONNRESET: return UV_ECONNRESET;
- case ERROR_ALREADY_EXISTS: return UV_EEXIST;
- case ERROR_FILE_EXISTS: return UV_EEXIST;
- case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
- case WSAEFAULT: return UV_EFAULT;
- case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
- case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
- case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
- case ERROR_INVALID_DATA: return UV_EINVAL;
- case ERROR_INVALID_PARAMETER: return UV_EINVAL;
- case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
- case WSAEINVAL: return UV_EINVAL;
- case WSAEPFNOSUPPORT: return UV_EINVAL;
- case WSAESOCKTNOSUPPORT: return UV_EINVAL;
- case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
- case ERROR_BUS_RESET: return UV_EIO;
- case ERROR_CRC: return UV_EIO;
- case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
- case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
- case ERROR_DISK_CORRUPT: return UV_EIO;
- case ERROR_EOM_OVERFLOW: return UV_EIO;
- case ERROR_FILEMARK_DETECTED: return UV_EIO;
- case ERROR_GEN_FAILURE: return UV_EIO;
- case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
- case ERROR_IO_DEVICE: return UV_EIO;
- case ERROR_NO_DATA_DETECTED: return UV_EIO;
- case ERROR_NO_SIGNAL_SENT: return UV_EIO;
- case ERROR_OPEN_FAILED: return UV_EIO;
- case ERROR_SETMARK_DETECTED: return UV_EIO;
- case ERROR_SIGNAL_REFUSED: return UV_EIO;
- case WSAEISCONN: return UV_EISCONN;
- case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
- case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
- case WSAEMFILE: return UV_EMFILE;
- case WSAEMSGSIZE: return UV_EMSGSIZE;
- case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
- case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
- case WSAENETUNREACH: return UV_ENETUNREACH;
- case WSAENOBUFS: return UV_ENOBUFS;
- case ERROR_BAD_PATHNAME: return UV_ENOENT;
- case ERROR_DIRECTORY: return UV_ENOENT;
- case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
- case ERROR_INVALID_NAME: return UV_ENOENT;
- case ERROR_INVALID_DRIVE: return UV_ENOENT;
- case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
- case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
- case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
- case WSAHOST_NOT_FOUND: return UV_ENOENT;
- case WSANO_DATA: return UV_ENOENT;
- case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
- case ERROR_OUTOFMEMORY: return UV_ENOMEM;
- case ERROR_CANNOT_MAKE: return UV_ENOSPC;
- case ERROR_DISK_FULL: return UV_ENOSPC;
- case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
- case ERROR_END_OF_MEDIA: return UV_ENOSPC;
- case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
- case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
- case WSAENOTCONN: return UV_ENOTCONN;
- case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
- case WSAENOTSOCK: return UV_ENOTSOCK;
- case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
- case ERROR_BROKEN_PIPE: return UV_EOF;
- case ERROR_ACCESS_DENIED: return UV_EPERM;
- case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
- case ERROR_BAD_PIPE: return UV_EPIPE;
- case ERROR_NO_DATA: return UV_EPIPE;
- case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
- case WSAESHUTDOWN: return UV_EPIPE;
- case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
- case ERROR_WRITE_PROTECT: return UV_EROFS;
- case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
- case WSAETIMEDOUT: return UV_ETIMEDOUT;
- case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
- case ERROR_INVALID_FUNCTION: return UV_EISDIR;
- case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
- default: return UV_UNKNOWN;
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/fs-event.cpp b/wpiutil/src/main/native/libuv/src/win/fs-event.cpp
deleted file mode 100644
index b9ec025..0000000
--- a/wpiutil/src/main/native/libuv/src/win/fs-event.cpp
+++ /dev/null
@@ -1,591 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 _CRT_NONSTDC_NO_WARNINGS
-
-#include <assert.h>
-#include <errno.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-const unsigned int uv_directory_watcher_buffer_size = 4096;
-
-
-static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
- uv_fs_event_t* handle) {
- assert(handle->dir_handle != INVALID_HANDLE_VALUE);
- assert(!handle->req_pending);
-
- memset(&(handle->req.u.io.overlapped), 0,
- sizeof(handle->req.u.io.overlapped));
- if (!ReadDirectoryChangesW(handle->dir_handle,
- handle->buffer,
- uv_directory_watcher_buffer_size,
- (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
- FILE_NOTIFY_CHANGE_FILE_NAME |
- FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_ATTRIBUTES |
- FILE_NOTIFY_CHANGE_SIZE |
- FILE_NOTIFY_CHANGE_LAST_WRITE |
- FILE_NOTIFY_CHANGE_LAST_ACCESS |
- FILE_NOTIFY_CHANGE_CREATION |
- FILE_NOTIFY_CHANGE_SECURITY,
- NULL,
- &handle->req.u.io.overlapped,
- NULL)) {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(&handle->req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
- }
-
- handle->req_pending = 1;
-}
-
-static void uv_relative_path(const WCHAR* filename,
- const WCHAR* dir,
- WCHAR** relpath) {
- size_t relpathlen;
- size_t filenamelen = wcslen(filename);
- size_t dirlen = wcslen(dir);
- assert(!_wcsnicmp(filename, dir, dirlen));
- if (dirlen > 0 && dir[dirlen - 1] == '\\')
- dirlen--;
- relpathlen = filenamelen - dirlen - 1;
- *relpath = (WCHAR*)uv__malloc((relpathlen + 1) * sizeof(WCHAR));
- if (!*relpath)
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
- (*relpath)[relpathlen] = L'\0';
-}
-
-static int uv_split_path(const WCHAR* filename, WCHAR** dir,
- WCHAR** file) {
- size_t len, i;
-
- if (filename == NULL) {
- if (dir != NULL)
- *dir = NULL;
- *file = NULL;
- return 0;
- }
-
- len = wcslen(filename);
- i = len;
- while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
-
- if (i == 0) {
- if (dir) {
- *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
- if (!*dir) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
- uv__free(*dir);
- *dir = NULL;
- return -1;
- }
- }
-
- *file = wcsdup(filename);
- } else {
- if (dir) {
- *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
- if (!*dir) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
- wcsncpy(*dir, filename, i + 1);
- (*dir)[i + 1] = L'\0';
- }
-
- *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
- if (!*file) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
- wcsncpy(*file, filename + i + 1, len - i - 1);
- (*file)[len - i - 1] = L'\0';
- }
-
- return 0;
-}
-
-
-int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
- uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
- handle->dir_handle = INVALID_HANDLE_VALUE;
- handle->buffer = NULL;
- handle->req_pending = 0;
- handle->filew = NULL;
- handle->short_filew = NULL;
- handle->dirw = NULL;
-
- UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
- handle->req.data = handle;
-
- return 0;
-}
-
-
-int uv_fs_event_start(uv_fs_event_t* handle,
- uv_fs_event_cb cb,
- const char* path,
- unsigned int flags) {
- int name_size, is_path_dir, size;
- DWORD attr, last_error;
- WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
- WCHAR short_path_buffer[MAX_PATH];
- WCHAR* short_path, *long_path;
-
- if (uv__is_active(handle))
- return UV_EINVAL;
-
- handle->cb = cb;
- handle->path = uv__strdup(path);
- if (!handle->path) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- uv__handle_start(handle);
-
- /* Convert name to UTF16. */
-
- name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
- sizeof(WCHAR);
- pathw = (WCHAR*)uv__malloc(name_size);
- if (!pathw) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- path,
- -1,
- pathw,
- name_size / sizeof(WCHAR))) {
- return uv_translate_sys_error(GetLastError());
- }
-
- /* Determine whether path is a file or a directory. */
- attr = GetFileAttributesW(pathw);
- if (attr == INVALID_FILE_ATTRIBUTES) {
- last_error = GetLastError();
- goto error;
- }
-
- is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
-
- if (is_path_dir) {
- /* path is a directory, so that's the directory that we will watch. */
-
- /* Convert to long path. */
- size = GetLongPathNameW(pathw, NULL, 0);
-
- if (size) {
- long_path = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
- if (!long_path) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- size = GetLongPathNameW(pathw, long_path, size);
- if (size) {
- long_path[size] = '\0';
- } else {
- uv__free(long_path);
- long_path = NULL;
- }
-
- if (long_path) {
- uv__free(pathw);
- pathw = long_path;
- }
- }
-
- dir_to_watch = pathw;
- } else {
- /*
- * path is a file. So we split path into dir & file parts, and
- * watch the dir directory.
- */
-
- /* Convert to short path. */
- if (GetShortPathNameW(pathw,
- short_path_buffer,
- ARRAY_SIZE(short_path_buffer))) {
- short_path = short_path_buffer;
- } else {
- short_path = NULL;
- }
-
- if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
- last_error = GetLastError();
- goto error;
- }
-
- if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
- last_error = GetLastError();
- goto error;
- }
-
- dir_to_watch = dir;
- uv__free(pathw);
- pathw = NULL;
- }
-
- handle->dir_handle = CreateFileW(dir_to_watch,
- FILE_LIST_DIRECTORY,
- FILE_SHARE_READ | FILE_SHARE_DELETE |
- FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (dir) {
- uv__free(dir);
- dir = NULL;
- }
-
- if (handle->dir_handle == INVALID_HANDLE_VALUE) {
- last_error = GetLastError();
- goto error;
- }
-
- if (CreateIoCompletionPort(handle->dir_handle,
- handle->loop->iocp,
- (ULONG_PTR)handle,
- 0) == NULL) {
- last_error = GetLastError();
- goto error;
- }
-
- if (!handle->buffer) {
- handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
- }
- if (!handle->buffer) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- memset(&(handle->req.u.io.overlapped), 0,
- sizeof(handle->req.u.io.overlapped));
-
- if (!ReadDirectoryChangesW(handle->dir_handle,
- handle->buffer,
- uv_directory_watcher_buffer_size,
- (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
- FILE_NOTIFY_CHANGE_FILE_NAME |
- FILE_NOTIFY_CHANGE_DIR_NAME |
- FILE_NOTIFY_CHANGE_ATTRIBUTES |
- FILE_NOTIFY_CHANGE_SIZE |
- FILE_NOTIFY_CHANGE_LAST_WRITE |
- FILE_NOTIFY_CHANGE_LAST_ACCESS |
- FILE_NOTIFY_CHANGE_CREATION |
- FILE_NOTIFY_CHANGE_SECURITY,
- NULL,
- &handle->req.u.io.overlapped,
- NULL)) {
- last_error = GetLastError();
- goto error;
- }
-
- assert(is_path_dir ? pathw != NULL : pathw == NULL);
- handle->dirw = pathw;
- handle->req_pending = 1;
- return 0;
-
-error:
- if (handle->path) {
- uv__free(handle->path);
- handle->path = NULL;
- }
-
- if (handle->filew) {
- uv__free(handle->filew);
- handle->filew = NULL;
- }
-
- if (handle->short_filew) {
- uv__free(handle->short_filew);
- handle->short_filew = NULL;
- }
-
- uv__free(pathw);
-
- if (handle->dir_handle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle->dir_handle);
- handle->dir_handle = INVALID_HANDLE_VALUE;
- }
-
- if (handle->buffer) {
- uv__free(handle->buffer);
- handle->buffer = NULL;
- }
-
- if (uv__is_active(handle))
- uv__handle_stop(handle);
-
- return uv_translate_sys_error(last_error);
-}
-
-
-int uv_fs_event_stop(uv_fs_event_t* handle) {
- if (!uv__is_active(handle))
- return 0;
-
- if (handle->dir_handle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle->dir_handle);
- handle->dir_handle = INVALID_HANDLE_VALUE;
- }
-
- uv__handle_stop(handle);
-
- if (handle->filew) {
- uv__free(handle->filew);
- handle->filew = NULL;
- }
-
- if (handle->short_filew) {
- uv__free(handle->short_filew);
- handle->short_filew = NULL;
- }
-
- if (handle->path) {
- uv__free(handle->path);
- handle->path = NULL;
- }
-
- if (handle->dirw) {
- uv__free(handle->dirw);
- handle->dirw = NULL;
- }
-
- return 0;
-}
-
-
-static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
- size_t str_len;
-
- if (str == NULL)
- return -1;
-
- str_len = wcslen(str);
-
- /*
- Since we only care about equality, return early if the strings
- aren't the same length
- */
- if (str_len != (file_name_len / sizeof(WCHAR)))
- return -1;
-
- return _wcsnicmp(str, file_name, str_len);
-}
-
-
-void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
- uv_fs_event_t* handle) {
- FILE_NOTIFY_INFORMATION* file_info;
- int err, sizew, size;
- char* filename = NULL;
- WCHAR* filenamew = NULL;
- WCHAR* long_filenamew = NULL;
- DWORD offset = 0;
-
- assert(req->type == UV_FS_EVENT_REQ);
- assert(handle->req_pending);
- handle->req_pending = 0;
-
- /* Don't report any callbacks if:
- * - We're closing, just push the handle onto the endgame queue
- * - We are not active, just ignore the callback
- */
- if (!uv__is_active(handle)) {
- if (handle->flags & UV_HANDLE_CLOSING) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
- return;
- }
-
- file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
-
- if (REQ_SUCCESS(req)) {
- if (req->u.io.overlapped.InternalHigh > 0) {
- do {
- file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
- assert(!filename);
- assert(!filenamew);
- assert(!long_filenamew);
-
- /*
- * Fire the event only if we were asked to watch a directory,
- * or if the filename filter matches.
- */
- if (handle->dirw ||
- file_info_cmp(handle->filew,
- file_info->FileName,
- file_info->FileNameLength) == 0 ||
- file_info_cmp(handle->short_filew,
- file_info->FileName,
- file_info->FileNameLength) == 0) {
-
- if (handle->dirw) {
- /*
- * We attempt to resolve the long form of the file name explicitly.
- * We only do this for file names that might still exist on disk.
- * If this fails, we use the name given by ReadDirectoryChangesW.
- * This may be the long form or the 8.3 short name in some cases.
- */
- if (file_info->Action != FILE_ACTION_REMOVED &&
- file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
- /* Construct a full path to the file. */
- size = wcslen(handle->dirw) +
- file_info->FileNameLength / sizeof(WCHAR) + 2;
-
- filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
- if (!filenamew) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
- file_info->FileNameLength / (DWORD)sizeof(WCHAR),
- file_info->FileName);
-
- filenamew[size - 1] = L'\0';
-
- /* Convert to long name. */
- size = GetLongPathNameW(filenamew, NULL, 0);
-
- if (size) {
- long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
- if (!long_filenamew) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- size = GetLongPathNameW(filenamew, long_filenamew, size);
- if (size) {
- long_filenamew[size] = '\0';
- } else {
- uv__free(long_filenamew);
- long_filenamew = NULL;
- }
- }
-
- uv__free(filenamew);
-
- if (long_filenamew) {
- /* Get the file name out of the long path. */
- uv_relative_path(long_filenamew,
- handle->dirw,
- &filenamew);
- uv__free(long_filenamew);
- long_filenamew = filenamew;
- sizew = -1;
- } else {
- /* We couldn't get the long filename, use the one reported. */
- filenamew = file_info->FileName;
- sizew = file_info->FileNameLength / sizeof(WCHAR);
- }
- } else {
- /*
- * Removed or renamed events cannot be resolved to the long form.
- * We therefore use the name given by ReadDirectoryChangesW.
- * This may be the long form or the 8.3 short name in some cases.
- */
- filenamew = file_info->FileName;
- sizew = file_info->FileNameLength / sizeof(WCHAR);
- }
- } else {
- /* We already have the long name of the file, so just use it. */
- filenamew = handle->filew;
- sizew = -1;
- }
-
- /* Convert the filename to utf8. */
- uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
-
- switch (file_info->Action) {
- case FILE_ACTION_ADDED:
- case FILE_ACTION_REMOVED:
- case FILE_ACTION_RENAMED_OLD_NAME:
- case FILE_ACTION_RENAMED_NEW_NAME:
- handle->cb(handle, filename, UV_RENAME, 0);
- break;
-
- case FILE_ACTION_MODIFIED:
- handle->cb(handle, filename, UV_CHANGE, 0);
- break;
- }
-
- uv__free(filename);
- filename = NULL;
- uv__free(long_filenamew);
- long_filenamew = NULL;
- filenamew = NULL;
- }
-
- offset = file_info->NextEntryOffset;
- } while (offset && !(handle->flags & UV_HANDLE_CLOSING));
- } else {
- handle->cb(handle, NULL, UV_CHANGE, 0);
- }
- } else {
- err = GET_REQ_ERROR(req);
- handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
- }
-
- if (!(handle->flags & UV_HANDLE_CLOSING)) {
- uv_fs_event_queue_readdirchanges(loop, handle);
- } else {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-}
-
-
-void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
- uv_fs_event_stop(handle);
-
- uv__handle_closing(handle);
-
- if (!handle->req_pending) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-
-}
-
-
-void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
- if ((handle->flags & UV_HANDLE_CLOSING) && !handle->req_pending) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- if (handle->buffer) {
- uv__free(handle->buffer);
- handle->buffer = NULL;
- }
-
- uv__handle_close(handle);
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/fs.cpp b/wpiutil/src/main/native/libuv/src/win/fs.cpp
deleted file mode 100644
index 6b9e37b..0000000
--- a/wpiutil/src/main/native/libuv/src/win/fs.cpp
+++ /dev/null
@@ -1,2721 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 _CRT_NONSTDC_NO_WARNINGS
-
-#include <assert.h>
-#include <stdlib.h>
-#include <direct.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <io.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/utime.h>
-#include <stdio.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "req-inl.h"
-#include "handle-inl.h"
-
-#include <wincrypt.h>
-
-#pragma comment(lib, "Advapi32.lib")
-
-#define UV_FS_FREE_PATHS 0x0002
-#define UV_FS_FREE_PTR 0x0008
-#define UV_FS_CLEANEDUP 0x0010
-
-
-#define INIT(subtype) \
- do { \
- if (req == NULL) \
- return UV_EINVAL; \
- uv_fs_req_init(loop, req, subtype, cb); \
- } \
- while (0)
-
-#define POST \
- do { \
- if (cb != NULL) { \
- uv__req_register(loop, req); \
- uv__work_submit(loop, \
- &req->work_req, \
- UV__WORK_FAST_IO, \
- uv__fs_work, \
- uv__fs_done); \
- return 0; \
- } else { \
- uv__fs_work(&req->work_req); \
- return req->result; \
- } \
- } \
- while (0)
-
-#define SET_REQ_RESULT(req, result_value) \
- do { \
- req->result = (result_value); \
- if (req->result == -1) { \
- req->sys_errno_ = _doserrno; \
- req->result = uv_translate_sys_error(req->sys_errno_); \
- } \
- } while (0)
-
-#define SET_REQ_WIN32_ERROR(req, sys_errno) \
- do { \
- req->sys_errno_ = (sys_errno); \
- req->result = uv_translate_sys_error(req->sys_errno_); \
- } while (0)
-
-#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
- do { \
- req->result = (uv_errno); \
- req->sys_errno_ = (sys_errno); \
- } while (0)
-
-#define VERIFY_FD(fd, req) \
- if (fd == -1) { \
- req->result = UV_EBADF; \
- req->sys_errno_ = ERROR_INVALID_HANDLE; \
- return; \
- }
-
-#define MILLIONu (1000U * 1000U)
-#define BILLIONu (1000U * 1000U * 1000U)
-
-#define FILETIME_TO_UINT(filetime) \
- (*((uint64_t*) &(filetime)) - (uint64_t) 116444736 * BILLIONu)
-
-#define FILETIME_TO_TIME_T(filetime) \
- (FILETIME_TO_UINT(filetime) / (10u * MILLIONu))
-
-#define FILETIME_TO_TIME_NS(filetime, secs) \
- ((FILETIME_TO_UINT(filetime) - (secs * (uint64_t) 10 * MILLIONu)) * 100U)
-
-#define FILETIME_TO_TIMESPEC(ts, filetime) \
- do { \
- (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
- (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
- } while(0)
-
-#define TIME_T_TO_FILETIME(time, filetime_ptr) \
- do { \
- uint64_t bigtime = ((uint64_t) ((time) * (uint64_t) 10 * MILLIONu)) + \
- (uint64_t) 116444736 * BILLIONu; \
- (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
- (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
- } while(0)
-
-#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
-#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
- ((c) >= L'A' && (c) <= L'Z'))
-
-const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
-const WCHAR JUNCTION_PREFIX_LEN = 4;
-
-const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
-const WCHAR LONG_PATH_PREFIX_LEN = 4;
-
-const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
-const WCHAR UNC_PATH_PREFIX_LEN = 8;
-
-static int uv__file_symlink_usermode_flag = SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE;
-
-void uv_fs_init(void) {
- _fmode = _O_BINARY;
-}
-
-
-INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
- const char* new_path, const int copy_path) {
- char* buf;
- char* pos;
- ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
-
- /* new_path can only be set if path is also set. */
- assert(new_path == NULL || path != NULL);
-
- if (path != NULL) {
- pathw_len = MultiByteToWideChar(CP_UTF8,
- 0,
- path,
- -1,
- NULL,
- 0);
- if (pathw_len == 0) {
- return GetLastError();
- }
-
- buf_sz += pathw_len * sizeof(WCHAR);
- }
-
- if (path != NULL && copy_path) {
- path_len = 1 + strlen(path);
- buf_sz += path_len;
- }
-
- if (new_path != NULL) {
- new_pathw_len = MultiByteToWideChar(CP_UTF8,
- 0,
- new_path,
- -1,
- NULL,
- 0);
- if (new_pathw_len == 0) {
- return GetLastError();
- }
-
- buf_sz += new_pathw_len * sizeof(WCHAR);
- }
-
-
- if (buf_sz == 0) {
- req->file.pathw = NULL;
- req->fs.info.new_pathw = NULL;
- req->path = NULL;
- return 0;
- }
-
- buf = (char*) uv__malloc(buf_sz);
- if (buf == NULL) {
- return ERROR_OUTOFMEMORY;
- }
-
- pos = buf;
-
- if (path != NULL) {
- DWORD r = MultiByteToWideChar(CP_UTF8,
- 0,
- path,
- -1,
- (WCHAR*) pos,
- pathw_len);
- assert(r == (DWORD) pathw_len);
- req->file.pathw = (WCHAR*) pos;
- pos += r * sizeof(WCHAR);
- } else {
- req->file.pathw = NULL;
- }
-
- if (new_path != NULL) {
- DWORD r = MultiByteToWideChar(CP_UTF8,
- 0,
- new_path,
- -1,
- (WCHAR*) pos,
- new_pathw_len);
- assert(r == (DWORD) new_pathw_len);
- req->fs.info.new_pathw = (WCHAR*) pos;
- pos += r * sizeof(WCHAR);
- } else {
- req->fs.info.new_pathw = NULL;
- }
-
- req->path = path;
- if (path != NULL && copy_path) {
- memcpy(pos, path, path_len);
- assert(path_len == buf_sz - (pos - buf));
- req->path = pos;
- }
-
- req->flags |= UV_FS_FREE_PATHS;
-
- return 0;
-}
-
-
-
-INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
- uv_fs_type fs_type, const uv_fs_cb cb) {
- uv__once_init();
- UV_REQ_INIT(req, UV_FS);
- req->loop = loop;
- req->flags = 0;
- req->fs_type = fs_type;
- req->result = 0;
- req->ptr = NULL;
- req->path = NULL;
- req->cb = cb;
- memset(&req->fs, 0, sizeof(req->fs));
-}
-
-
-static int fs__wide_to_utf8(WCHAR* w_source_ptr,
- DWORD w_source_len,
- char** target_ptr,
- uint64_t* target_len_ptr) {
- int r;
- int target_len;
- char* target;
- target_len = WideCharToMultiByte(CP_UTF8,
- 0,
- w_source_ptr,
- w_source_len,
- NULL,
- 0,
- NULL,
- NULL);
-
- if (target_len == 0) {
- return -1;
- }
-
- if (target_len_ptr != NULL) {
- *target_len_ptr = target_len;
- }
-
- if (target_ptr == NULL) {
- return 0;
- }
-
- target = (char*)uv__malloc(target_len + 1);
- if (target == NULL) {
- SetLastError(ERROR_OUTOFMEMORY);
- return -1;
- }
-
- r = WideCharToMultiByte(CP_UTF8,
- 0,
- w_source_ptr,
- w_source_len,
- target,
- target_len,
- NULL,
- NULL);
- assert(r == target_len);
- target[target_len] = '\0';
- *target_ptr = target;
- return 0;
-}
-
-
-INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
- uint64_t* target_len_ptr) {
- char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
- REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
- WCHAR* w_target;
- DWORD w_target_len;
- DWORD bytes;
-
- if (!DeviceIoControl(handle,
- FSCTL_GET_REPARSE_POINT,
- NULL,
- 0,
- buffer,
- sizeof buffer,
- &bytes,
- NULL)) {
- return -1;
- }
-
- if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
- /* Real symlink */
- w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
- (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
- sizeof(WCHAR));
- w_target_len =
- reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
- sizeof(WCHAR);
-
- /* Real symlinks can contain pretty much everything, but the only thing we
- * really care about is undoing the implicit conversion to an NT namespaced
- * path that CreateSymbolicLink will perform on absolute paths. If the path
- * is win32-namespaced then the user must have explicitly made it so, and
- * we better just return the unmodified reparse data. */
- if (w_target_len >= 4 &&
- w_target[0] == L'\\' &&
- w_target[1] == L'?' &&
- w_target[2] == L'?' &&
- w_target[3] == L'\\') {
- /* Starts with \??\ */
- if (w_target_len >= 6 &&
- ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
- (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
- w_target[5] == L':' &&
- (w_target_len == 6 || w_target[6] == L'\\')) {
- /* \??\<drive>:\ */
- w_target += 4;
- w_target_len -= 4;
-
- } else if (w_target_len >= 8 &&
- (w_target[4] == L'U' || w_target[4] == L'u') &&
- (w_target[5] == L'N' || w_target[5] == L'n') &&
- (w_target[6] == L'C' || w_target[6] == L'c') &&
- w_target[7] == L'\\') {
- /* \??\UNC\<server>\<share>\ - make sure the final path looks like
- * \\<server>\<share>\ */
- w_target += 6;
- w_target[0] = L'\\';
- w_target_len -= 6;
- }
- }
-
- } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
- /* Junction. */
- w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
- (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
- sizeof(WCHAR));
- w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
- sizeof(WCHAR);
-
- /* Only treat junctions that look like \??\<drive>:\ as symlink. Junctions
- * can also be used as mount points, like \??\Volume{<guid>}, but that's
- * confusing for programs since they wouldn't be able to actually
- * understand such a path when returned by uv_readlink(). UNC paths are
- * never valid for junctions so we don't care about them. */
- if (!(w_target_len >= 6 &&
- w_target[0] == L'\\' &&
- w_target[1] == L'?' &&
- w_target[2] == L'?' &&
- w_target[3] == L'\\' &&
- ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
- (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
- w_target[5] == L':' &&
- (w_target_len == 6 || w_target[6] == L'\\'))) {
- SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
- return -1;
- }
-
- /* Remove leading \??\ */
- w_target += 4;
- w_target_len -= 4;
-
- } else {
- /* Reparse tag does not indicate a symlink. */
- SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
- return -1;
- }
-
- return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
-}
-
-
-void fs__open(uv_fs_t* req) {
- DWORD access;
- DWORD share;
- DWORD disposition;
- DWORD attributes = 0;
- HANDLE file;
- int fd, current_umask;
- int flags = req->fs.info.file_flags;
-
- /* Obtain the active umask. umask() never fails and returns the previous
- * umask. */
- current_umask = umask(0);
- umask(current_umask);
-
- /* convert flags and mode to CreateFile parameters */
- switch (flags & (UV_FS_O_RDONLY | UV_FS_O_WRONLY | UV_FS_O_RDWR)) {
- case UV_FS_O_RDONLY:
- access = FILE_GENERIC_READ;
- break;
- case UV_FS_O_WRONLY:
- access = FILE_GENERIC_WRITE;
- break;
- case UV_FS_O_RDWR:
- access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
- break;
- default:
- goto einval;
- }
-
- if (flags & UV_FS_O_APPEND) {
- access &= ~FILE_WRITE_DATA;
- access |= FILE_APPEND_DATA;
- }
-
- /*
- * Here is where we deviate significantly from what CRT's _open()
- * does. We indiscriminately use all the sharing modes, to match
- * UNIX semantics. In particular, this ensures that the file can
- * be deleted even whilst it's open, fixing issue #1449.
- * We still support exclusive sharing mode, since it is necessary
- * for opening raw block devices, otherwise Windows will prevent
- * any attempt to write past the master boot record.
- */
- if (flags & UV_FS_O_EXLOCK) {
- share = 0;
- } else {
- share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
- }
-
- switch (flags & (UV_FS_O_CREAT | UV_FS_O_EXCL | UV_FS_O_TRUNC)) {
- case 0:
- case UV_FS_O_EXCL:
- disposition = OPEN_EXISTING;
- break;
- case UV_FS_O_CREAT:
- disposition = OPEN_ALWAYS;
- break;
- case UV_FS_O_CREAT | UV_FS_O_EXCL:
- case UV_FS_O_CREAT | UV_FS_O_TRUNC | UV_FS_O_EXCL:
- disposition = CREATE_NEW;
- break;
- case UV_FS_O_TRUNC:
- case UV_FS_O_TRUNC | UV_FS_O_EXCL:
- disposition = TRUNCATE_EXISTING;
- break;
- case UV_FS_O_CREAT | UV_FS_O_TRUNC:
- disposition = CREATE_ALWAYS;
- break;
- default:
- goto einval;
- }
-
- attributes |= FILE_ATTRIBUTE_NORMAL;
- if (flags & UV_FS_O_CREAT) {
- if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
- attributes |= FILE_ATTRIBUTE_READONLY;
- }
- }
-
- if (flags & UV_FS_O_TEMPORARY ) {
- attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
- access |= DELETE;
- }
-
- if (flags & UV_FS_O_SHORT_LIVED) {
- attributes |= FILE_ATTRIBUTE_TEMPORARY;
- }
-
- switch (flags & (UV_FS_O_SEQUENTIAL | UV_FS_O_RANDOM)) {
- case 0:
- break;
- case UV_FS_O_SEQUENTIAL:
- attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
- break;
- case UV_FS_O_RANDOM:
- attributes |= FILE_FLAG_RANDOM_ACCESS;
- break;
- default:
- goto einval;
- }
-
- if (flags & UV_FS_O_DIRECT) {
- /*
- * FILE_APPEND_DATA and FILE_FLAG_NO_BUFFERING are mutually exclusive.
- * Windows returns 87, ERROR_INVALID_PARAMETER if these are combined.
- *
- * FILE_APPEND_DATA is included in FILE_GENERIC_WRITE:
- *
- * FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE |
- * FILE_WRITE_DATA |
- * FILE_WRITE_ATTRIBUTES |
- * FILE_WRITE_EA |
- * FILE_APPEND_DATA |
- * SYNCHRONIZE
- *
- * Note: Appends are also permitted by FILE_WRITE_DATA.
- *
- * In order for direct writes and direct appends to succeed, we therefore
- * exclude FILE_APPEND_DATA if FILE_WRITE_DATA is specified, and otherwise
- * fail if the user's sole permission is a direct append, since this
- * particular combination is invalid.
- */
- if (access & FILE_APPEND_DATA) {
- if (access & FILE_WRITE_DATA) {
- access &= ~FILE_APPEND_DATA;
- } else {
- goto einval;
- }
- }
- attributes |= FILE_FLAG_NO_BUFFERING;
- }
-
- switch (flags & (UV_FS_O_DSYNC | UV_FS_O_SYNC)) {
- case 0:
- break;
- case UV_FS_O_DSYNC:
- case UV_FS_O_SYNC:
- attributes |= FILE_FLAG_WRITE_THROUGH;
- break;
- default:
- goto einval;
- }
-
- /* Setting this flag makes it possible to open a directory. */
- attributes |= FILE_FLAG_BACKUP_SEMANTICS;
-
- file = CreateFileW(req->file.pathw,
- access,
- share,
- NULL,
- disposition,
- attributes,
- NULL);
- if (file == INVALID_HANDLE_VALUE) {
- DWORD error = GetLastError();
- if (error == ERROR_FILE_EXISTS && (flags & UV_FS_O_CREAT) &&
- !(flags & UV_FS_O_EXCL)) {
- /* Special case: when ERROR_FILE_EXISTS happens and UV_FS_O_CREAT was
- * specified, it means the path referred to a directory. */
- SET_REQ_UV_ERROR(req, UV_EISDIR, error);
- } else {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- }
- return;
- }
-
- fd = _open_osfhandle((intptr_t) file, flags);
- if (fd < 0) {
- /* The only known failure mode for _open_osfhandle() is EMFILE, in which
- * case GetLastError() will return zero. However we'll try to handle other
- * errors as well, should they ever occur.
- */
- if (errno == EMFILE)
- SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
- else if (GetLastError() != ERROR_SUCCESS)
- SET_REQ_WIN32_ERROR(req, GetLastError());
- else
- SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
- CloseHandle(file);
- return;
- }
-
- SET_REQ_RESULT(req, fd);
- return;
-
- einval:
- SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
-}
-
-void fs__close(uv_fs_t* req) {
- int fd = req->file.fd;
- int result;
-
- VERIFY_FD(fd, req);
-
- if (fd > 2)
- result = _close(fd);
- else
- result = 0;
-
- /* _close doesn't set _doserrno on failure, but it does always set errno
- * to EBADF on failure.
- */
- if (result == -1) {
- assert(errno == EBADF);
- SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
- } else {
- req->result = 0;
- }
-}
-
-
-void fs__read(uv_fs_t* req) {
- int fd = req->file.fd;
- int64_t offset = req->fs.info.offset;
- HANDLE handle;
- OVERLAPPED overlapped, *overlapped_ptr;
- LARGE_INTEGER offset_;
- DWORD bytes;
- DWORD error;
- int result;
- unsigned int index;
- LARGE_INTEGER original_position;
- LARGE_INTEGER zero_offset;
- int restore_position;
-
- VERIFY_FD(fd, req);
-
- zero_offset.QuadPart = 0;
- restore_position = 0;
- handle = uv__get_osfhandle(fd);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
- return;
- }
-
- if (offset != -1) {
- memset(&overlapped, 0, sizeof overlapped);
- overlapped_ptr = &overlapped;
- if (SetFilePointerEx(handle, zero_offset, &original_position,
- FILE_CURRENT)) {
- restore_position = 1;
- }
- } else {
- overlapped_ptr = NULL;
- }
-
- index = 0;
- bytes = 0;
- do {
- DWORD incremental_bytes;
-
- if (offset != -1) {
- offset_.QuadPart = offset + bytes;
- overlapped.Offset = offset_.LowPart;
- overlapped.OffsetHigh = offset_.HighPart;
- }
-
- result = ReadFile(handle,
- req->fs.info.bufs[index].base,
- req->fs.info.bufs[index].len,
- &incremental_bytes,
- overlapped_ptr);
- bytes += incremental_bytes;
- ++index;
- } while (result && index < req->fs.info.nbufs);
-
- if (restore_position)
- SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
-
- if (result || bytes > 0) {
- SET_REQ_RESULT(req, bytes);
- } else {
- error = GetLastError();
- if (error == ERROR_HANDLE_EOF) {
- SET_REQ_RESULT(req, bytes);
- } else {
- SET_REQ_WIN32_ERROR(req, error);
- }
- }
-}
-
-
-void fs__write(uv_fs_t* req) {
- int fd = req->file.fd;
- int64_t offset = req->fs.info.offset;
- HANDLE handle;
- OVERLAPPED overlapped, *overlapped_ptr;
- LARGE_INTEGER offset_;
- DWORD bytes;
- int result;
- unsigned int index;
- LARGE_INTEGER original_position;
- LARGE_INTEGER zero_offset;
- int restore_position;
-
- VERIFY_FD(fd, req);
-
- zero_offset.QuadPart = 0;
- restore_position = 0;
- handle = uv__get_osfhandle(fd);
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
- return;
- }
-
- if (offset != -1) {
- memset(&overlapped, 0, sizeof overlapped);
- overlapped_ptr = &overlapped;
- if (SetFilePointerEx(handle, zero_offset, &original_position,
- FILE_CURRENT)) {
- restore_position = 1;
- }
- } else {
- overlapped_ptr = NULL;
- }
-
- index = 0;
- bytes = 0;
- do {
- DWORD incremental_bytes;
-
- if (offset != -1) {
- offset_.QuadPart = offset + bytes;
- overlapped.Offset = offset_.LowPart;
- overlapped.OffsetHigh = offset_.HighPart;
- }
-
- result = WriteFile(handle,
- req->fs.info.bufs[index].base,
- req->fs.info.bufs[index].len,
- &incremental_bytes,
- overlapped_ptr);
- bytes += incremental_bytes;
- ++index;
- } while (result && index < req->fs.info.nbufs);
-
- if (restore_position)
- SetFilePointerEx(handle, original_position, NULL, FILE_BEGIN);
-
- if (result || bytes > 0) {
- SET_REQ_RESULT(req, bytes);
- } else {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- }
-}
-
-
-void fs__rmdir(uv_fs_t* req) {
- int result = _wrmdir(req->file.pathw);
- SET_REQ_RESULT(req, result);
-}
-
-
-void fs__unlink(uv_fs_t* req) {
- const WCHAR* pathw = req->file.pathw;
- HANDLE handle;
- BY_HANDLE_FILE_INFORMATION info;
- FILE_DISPOSITION_INFORMATION disposition;
- IO_STATUS_BLOCK iosb;
- NTSTATUS status;
-
- handle = CreateFileW(pathw,
- FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- if (!GetFileInformationByHandle(handle, &info)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- CloseHandle(handle);
- return;
- }
-
- if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- /* Do not allow deletion of directories, unless it is a symlink. When the
- * path refers to a non-symlink directory, report EPERM as mandated by
- * POSIX.1. */
-
- /* Check if it is a reparse point. If it's not, it's a normal directory. */
- if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
- SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
- CloseHandle(handle);
- return;
- }
-
- /* Read the reparse point and check if it is a valid symlink. If not, don't
- * unlink. */
- if (fs__readlink_handle(handle, NULL, NULL) < 0) {
- DWORD error = GetLastError();
- if (error == ERROR_SYMLINK_NOT_SUPPORTED)
- error = ERROR_ACCESS_DENIED;
- SET_REQ_WIN32_ERROR(req, error);
- CloseHandle(handle);
- return;
- }
- }
-
- if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
- /* Remove read-only attribute */
- FILE_BASIC_INFORMATION basic = { 0 };
-
- basic.FileAttributes = (info.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) |
- FILE_ATTRIBUTE_ARCHIVE;
-
- status = pNtSetInformationFile(handle,
- &iosb,
- &basic,
- sizeof basic,
- FileBasicInformation);
- if (!NT_SUCCESS(status)) {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
- CloseHandle(handle);
- return;
- }
- }
-
- /* Try to set the delete flag. */
- disposition.DeleteFile = TRUE;
- status = pNtSetInformationFile(handle,
- &iosb,
- &disposition,
- sizeof disposition,
- FileDispositionInformation);
- if (NT_SUCCESS(status)) {
- SET_REQ_SUCCESS(req);
- } else {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
- }
-
- CloseHandle(handle);
-}
-
-
-void fs__mkdir(uv_fs_t* req) {
- /* TODO: use req->mode. */
- int result = _wmkdir(req->file.pathw);
- SET_REQ_RESULT(req, result);
-}
-
-
-/* OpenBSD original: lib/libc/stdio/mktemp.c */
-void fs__mkdtemp(uv_fs_t* req) {
- static const WCHAR *tempchars =
- L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
- static const size_t num_chars = 62;
- static const size_t num_x = 6;
- WCHAR *cp, *ep;
- unsigned int tries, i;
- size_t len;
- HCRYPTPROV h_crypt_prov;
- uint64_t v;
- BOOL released;
-
- len = wcslen(req->file.pathw);
- ep = req->file.pathw + len;
- if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
- SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
- return;
- }
-
- if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- tries = TMP_MAX;
- do {
- if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- break;
- }
-
- cp = ep - num_x;
- for (i = 0; i < num_x; i++) {
- *cp++ = tempchars[v % num_chars];
- v /= num_chars;
- }
-
- if (_wmkdir(req->file.pathw) == 0) {
- len = strlen(req->path);
- wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
- SET_REQ_RESULT(req, 0);
- break;
- } else if (errno != EEXIST) {
- SET_REQ_RESULT(req, -1);
- break;
- }
- } while (--tries);
-
- released = CryptReleaseContext(h_crypt_prov, 0);
- assert(released);
- if (tries == 0) {
- SET_REQ_RESULT(req, -1);
- }
-}
-
-
-void fs__scandir(uv_fs_t* req) {
- static const size_t dirents_initial_size = 32;
-
- HANDLE dir_handle = INVALID_HANDLE_VALUE;
-
- uv__dirent_t** dirents = NULL;
- size_t dirents_size = 0;
- size_t dirents_used = 0;
-
- IO_STATUS_BLOCK iosb;
- NTSTATUS status;
-
- /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
- * It's important that this buffer can hold at least one entry, regardless
- * of the length of the file names present in the enumerated directory.
- * A file name is at most 256 WCHARs long.
- * According to MSDN, the buffer must be aligned at an 8-byte boundary.
- */
-#if _MSC_VER
- __declspec(align(8)) char buffer[8192];
-#else
- __attribute__ ((aligned (8))) char buffer[8192];
-#endif
-
- STATIC_ASSERT(sizeof buffer >=
- sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
-
- /* Open the directory. */
- dir_handle =
- CreateFileW(req->file.pathw,
- FILE_LIST_DIRECTORY | SYNCHRONIZE,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
- if (dir_handle == INVALID_HANDLE_VALUE)
- goto win32_error;
-
- /* Read the first chunk. */
- status = pNtQueryDirectoryFile(dir_handle,
- NULL,
- NULL,
- NULL,
- &iosb,
- &buffer,
- sizeof buffer,
- FileDirectoryInformation,
- FALSE,
- NULL,
- TRUE);
-
- /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
- * This should be reported back as UV_ENOTDIR.
- */
- if (status == STATUS_INVALID_PARAMETER)
- goto not_a_directory_error;
-
- while (NT_SUCCESS(status)) {
- char* position = buffer;
- size_t next_entry_offset = 0;
-
- do {
- FILE_DIRECTORY_INFORMATION* info;
- uv__dirent_t* dirent;
-
- size_t wchar_len;
- size_t utf8_len;
-
- /* Obtain a pointer to the current directory entry. */
- position += next_entry_offset;
- info = (FILE_DIRECTORY_INFORMATION*) position;
-
- /* Fetch the offset to the next directory entry. */
- next_entry_offset = info->NextEntryOffset;
-
- /* Compute the length of the filename in WCHARs. */
- wchar_len = info->FileNameLength / sizeof info->FileName[0];
-
- /* Skip over '.' and '..' entries. It has been reported that
- * the SharePoint driver includes the terminating zero byte in
- * the filename length. Strip those first.
- */
- while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0')
- wchar_len -= 1;
-
- if (wchar_len == 0)
- continue;
- if (wchar_len == 1 && info->FileName[0] == L'.')
- continue;
- if (wchar_len == 2 && info->FileName[0] == L'.' &&
- info->FileName[1] == L'.')
- continue;
-
- /* Compute the space required to store the filename as UTF-8. */
- utf8_len = WideCharToMultiByte(
- CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
- if (utf8_len == 0)
- goto win32_error;
-
- /* Resize the dirent array if needed. */
- if (dirents_used >= dirents_size) {
- size_t new_dirents_size =
- dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
- uv__dirent_t** new_dirents = (uv__dirent_t**)
- uv__realloc(dirents, new_dirents_size * sizeof *dirents);
-
- if (new_dirents == NULL)
- goto out_of_memory_error;
-
- dirents_size = new_dirents_size;
- dirents = new_dirents;
- }
-
- /* Allocate space for the uv dirent structure. The dirent structure
- * includes room for the first character of the filename, but `utf8_len`
- * doesn't count the NULL terminator at this point.
- */
- dirent = (uv__dirent_t*)uv__malloc(sizeof *dirent + utf8_len);
- if (dirent == NULL)
- goto out_of_memory_error;
-
- dirents[dirents_used++] = dirent;
-
- /* Convert file name to UTF-8. */
- if (WideCharToMultiByte(CP_UTF8,
- 0,
- &info->FileName[0],
- wchar_len,
- &dirent->d_name[0],
- utf8_len,
- NULL,
- NULL) == 0)
- goto win32_error;
-
- /* Add a null terminator to the filename. */
- dirent->d_name[utf8_len] = '\0';
-
- /* Fill out the type field. */
- if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
- dirent->d_type = UV__DT_CHAR;
- else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
- dirent->d_type = UV__DT_LINK;
- else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- dirent->d_type = UV__DT_DIR;
- else
- dirent->d_type = UV__DT_FILE;
- } while (next_entry_offset != 0);
-
- /* Read the next chunk. */
- status = pNtQueryDirectoryFile(dir_handle,
- NULL,
- NULL,
- NULL,
- &iosb,
- &buffer,
- sizeof buffer,
- FileDirectoryInformation,
- FALSE,
- NULL,
- FALSE);
-
- /* After the first pNtQueryDirectoryFile call, the function may return
- * STATUS_SUCCESS even if the buffer was too small to hold at least one
- * directory entry.
- */
- if (status == STATUS_SUCCESS && iosb.Information == 0)
- status = STATUS_BUFFER_OVERFLOW;
- }
-
- if (status != STATUS_NO_MORE_FILES)
- goto nt_error;
-
- CloseHandle(dir_handle);
-
- /* Store the result in the request object. */
- req->ptr = dirents;
- if (dirents != NULL)
- req->flags |= UV_FS_FREE_PTR;
-
- SET_REQ_RESULT(req, dirents_used);
-
- /* `nbufs` will be used as index by uv_fs_scandir_next. */
- req->fs.info.nbufs = 0;
-
- return;
-
-nt_error:
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
- goto cleanup;
-
-win32_error:
- SET_REQ_WIN32_ERROR(req, GetLastError());
- goto cleanup;
-
-not_a_directory_error:
- SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
- goto cleanup;
-
-out_of_memory_error:
- SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
- goto cleanup;
-
-cleanup:
- if (dir_handle != INVALID_HANDLE_VALUE)
- CloseHandle(dir_handle);
- while (dirents_used > 0)
- uv__free(dirents[--dirents_used]);
- if (dirents != NULL)
- uv__free(dirents);
-}
-
-void fs__opendir(uv_fs_t* req) {
- WCHAR* pathw;
- size_t len;
- const WCHAR* fmt;
- WCHAR* find_path;
- uv_dir_t* dir;
-
- pathw = req->file.pathw;
- dir = NULL;
- find_path = NULL;
-
- /* Figure out whether path is a file or a directory. */
- if (!(GetFileAttributesW(pathw) & FILE_ATTRIBUTE_DIRECTORY)) {
- SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
- goto error;
- }
-
- dir = (uv_dir_t*)uv__malloc(sizeof(*dir));
- if (dir == NULL) {
- SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
- goto error;
- }
-
- len = wcslen(pathw);
-
- if (len == 0)
- fmt = L"./*";
- else if (IS_SLASH(pathw[len - 1]))
- fmt = L"%s*";
- else
- fmt = L"%s\\*";
-
- find_path = (WCHAR*)uv__malloc(sizeof(WCHAR) * (len + 4));
- if (find_path == NULL) {
- SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
- goto error;
- }
-
- _snwprintf(find_path, len + 3, fmt, pathw);
- dir->dir_handle = FindFirstFileW(find_path, &dir->find_data);
- uv__free(find_path);
- find_path = NULL;
- if (dir->dir_handle == INVALID_HANDLE_VALUE &&
- GetLastError() != ERROR_FILE_NOT_FOUND) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- goto error;
- }
-
- dir->need_find_call = FALSE;
- req->ptr = dir;
- SET_REQ_RESULT(req, 0);
- return;
-
-error:
- uv__free(dir);
- uv__free(find_path);
- req->ptr = NULL;
-}
-
-void fs__readdir(uv_fs_t* req) {
- uv_dir_t* dir;
- uv_dirent_t* dirents;
- uv__dirent_t dent;
- unsigned int dirent_idx;
- PWIN32_FIND_DATAW find_data;
- unsigned int i;
- int r;
-
- req->flags |= UV_FS_FREE_PTR;
- dir = (uv_dir_t*)req->ptr;
- dirents = dir->dirents;
- memset(dirents, 0, dir->nentries * sizeof(*dir->dirents));
- find_data = &dir->find_data;
- dirent_idx = 0;
-
- while (dirent_idx < dir->nentries) {
- if (dir->need_find_call && FindNextFileW(dir->dir_handle, find_data) == 0) {
- if (GetLastError() == ERROR_NO_MORE_FILES)
- break;
- goto error;
- }
-
- /* Skip "." and ".." entries. */
- if (find_data->cFileName[0] == L'.' &&
- (find_data->cFileName[1] == L'\0' ||
- (find_data->cFileName[1] == L'.' &&
- find_data->cFileName[2] == L'\0'))) {
- dir->need_find_call = TRUE;
- continue;
- }
-
- r = uv__convert_utf16_to_utf8((const WCHAR*) &find_data->cFileName,
- -1,
- (char**) &dirents[dirent_idx].name);
- if (r != 0)
- goto error;
-
- /* Copy file type. */
- if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
- dent.d_type = UV__DT_DIR;
- else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0)
- dent.d_type = UV__DT_LINK;
- else if ((find_data->dwFileAttributes & FILE_ATTRIBUTE_DEVICE) != 0)
- dent.d_type = UV__DT_CHAR;
- else
- dent.d_type = UV__DT_FILE;
-
- dirents[dirent_idx].type = uv__fs_get_dirent_type(&dent);
- dir->need_find_call = TRUE;
- ++dirent_idx;
- }
-
- SET_REQ_RESULT(req, dirent_idx);
- return;
-
-error:
- SET_REQ_WIN32_ERROR(req, GetLastError());
- for (i = 0; i < dirent_idx; ++i) {
- uv__free((char*) dirents[i].name);
- dirents[i].name = NULL;
- }
-}
-
-void fs__closedir(uv_fs_t* req) {
- uv_dir_t* dir;
-
- dir = (uv_dir_t*)req->ptr;
- FindClose(dir->dir_handle);
- uv__free(req->ptr);
- SET_REQ_RESULT(req, 0);
-}
-
-INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf,
- int do_lstat) {
- FILE_ALL_INFORMATION file_info;
- FILE_FS_VOLUME_INFORMATION volume_info;
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
-
- nt_status = pNtQueryInformationFile(handle,
- &io_status,
- &file_info,
- sizeof file_info,
- FileAllInformation);
-
- /* Buffer overflow (a warning status code) is expected here. */
- if (NT_ERROR(nt_status)) {
- SetLastError(pRtlNtStatusToDosError(nt_status));
- return -1;
- }
-
- nt_status = pNtQueryVolumeInformationFile(handle,
- &io_status,
- &volume_info,
- sizeof volume_info,
- FileFsVolumeInformation);
-
- /* Buffer overflow (a warning status code) is expected here. */
- if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
- statbuf->st_dev = 0;
- } else if (NT_ERROR(nt_status)) {
- SetLastError(pRtlNtStatusToDosError(nt_status));
- return -1;
- } else {
- statbuf->st_dev = volume_info.VolumeSerialNumber;
- }
-
- /* Todo: st_mode should probably always be 0666 for everyone. We might also
- * want to report 0777 if the file is a .exe or a directory.
- *
- * Currently it's based on whether the 'readonly' attribute is set, which
- * makes little sense because the semantics are so different: the 'read-only'
- * flag is just a way for a user to protect against accidental deletion, and
- * serves no security purpose. Windows uses ACLs for that.
- *
- * Also people now use uv_fs_chmod() to take away the writable bit for good
- * reasons. Windows however just makes the file read-only, which makes it
- * impossible to delete the file afterwards, since read-only files can't be
- * deleted.
- *
- * IOW it's all just a clusterfuck and we should think of something that
- * makes slightly more sense.
- *
- * And uv_fs_chmod should probably just fail on windows or be a total no-op.
- * There's nothing sensible it can do anyway.
- */
- statbuf->st_mode = 0;
-
- /*
- * On Windows, FILE_ATTRIBUTE_REPARSE_POINT is a general purpose mechanism
- * by which filesystem drivers can intercept and alter file system requests.
- *
- * The only reparse points we care about are symlinks and mount points, both
- * of which are treated as POSIX symlinks. Further, we only care when
- * invoked via lstat, which seeks information about the link instead of its
- * target. Otherwise, reparse points must be treated as regular files.
- */
- if (do_lstat &&
- (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
- /*
- * If reading the link fails, the reparse point is not a symlink and needs
- * to be treated as a regular file. The higher level lstat function will
- * detect this failure and retry without do_lstat if appropriate.
- */
- if (fs__readlink_handle(handle, NULL, &statbuf->st_size) != 0)
- return -1;
- statbuf->st_mode |= S_IFLNK;
- }
-
- if (statbuf->st_mode == 0) {
- if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- statbuf->st_mode |= _S_IFDIR;
- statbuf->st_size = 0;
- } else {
- statbuf->st_mode |= _S_IFREG;
- statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
- }
- }
-
- if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
- statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
- else
- statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
- ((_S_IREAD | _S_IWRITE) >> 6);
-
- FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
- FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
- FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
- FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
-
- statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
-
- /* st_blocks contains the on-disk allocation size in 512-byte units. */
- statbuf->st_blocks =
- (uint64_t) file_info.StandardInformation.AllocationSize.QuadPart >> 9;
-
- statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
-
- /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
- * and writing to the disk. That is, for any definition of 'optimal' - it's
- * supposed to at least avoid read-update-write behavior when writing to the
- * disk.
- *
- * However nobody knows this and even fewer people actually use this value,
- * and in order to fill it out we'd have to make another syscall to query the
- * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
- *
- * Therefore we'll just report a sensible value that's quite commonly okay
- * on modern hardware.
- *
- * 4096 is the minimum required to be compatible with newer Advanced Format
- * drives (which have 4096 bytes per physical sector), and to be backwards
- * compatible with older drives (which have 512 bytes per physical sector).
- */
- statbuf->st_blksize = 4096;
-
- /* Todo: set st_flags to something meaningful. Also provide a wrapper for
- * chattr(2).
- */
- statbuf->st_flags = 0;
-
- /* Windows has nothing sensible to say about these values, so they'll just
- * remain empty.
- */
- statbuf->st_gid = 0;
- statbuf->st_uid = 0;
- statbuf->st_rdev = 0;
- statbuf->st_gen = 0;
-
- return 0;
-}
-
-
-INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
- size_t len = wcslen(pathw);
-
- /* TODO: ignore namespaced paths. */
- if (len > 1 && pathw[len - 2] != L':' &&
- (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
- pathw[len - 1] = '\0';
- }
-}
-
-
-INLINE static DWORD fs__stat_impl_from_path(WCHAR* path,
- int do_lstat,
- uv_stat_t* statbuf) {
- HANDLE handle;
- DWORD flags;
- DWORD ret;
-
- flags = FILE_FLAG_BACKUP_SEMANTICS;
- if (do_lstat)
- flags |= FILE_FLAG_OPEN_REPARSE_POINT;
-
- handle = CreateFileW(path,
- FILE_READ_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- flags,
- NULL);
-
- if (handle == INVALID_HANDLE_VALUE)
- ret = GetLastError();
- else if (fs__stat_handle(handle, statbuf, do_lstat) != 0)
- ret = GetLastError();
- else
- ret = 0;
-
- CloseHandle(handle);
- return ret;
-}
-
-
-INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
- DWORD error;
-
- error = fs__stat_impl_from_path(req->file.pathw, do_lstat, &req->statbuf);
- if (error != 0) {
- if (do_lstat &&
- (error == ERROR_SYMLINK_NOT_SUPPORTED ||
- error == ERROR_NOT_A_REPARSE_POINT)) {
- /* We opened a reparse point but it was not a symlink. Try again. */
- fs__stat_impl(req, 0);
- } else {
- /* Stat failed. */
- SET_REQ_WIN32_ERROR(req, error);
- }
-
- return;
- }
-
- req->ptr = &req->statbuf;
- req->result = 0;
-}
-
-
-static void fs__stat(uv_fs_t* req) {
- fs__stat_prepare_path(req->file.pathw);
- fs__stat_impl(req, 0);
-}
-
-
-static void fs__lstat(uv_fs_t* req) {
- fs__stat_prepare_path(req->file.pathw);
- fs__stat_impl(req, 1);
-}
-
-
-static void fs__fstat(uv_fs_t* req) {
- int fd = req->file.fd;
- HANDLE handle;
-
- VERIFY_FD(fd, req);
-
- handle = uv__get_osfhandle(fd);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
- return;
- }
-
- if (fs__stat_handle(handle, &req->statbuf, 0) != 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- req->ptr = &req->statbuf;
- req->result = 0;
-}
-
-
-static void fs__rename(uv_fs_t* req) {
- if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- SET_REQ_RESULT(req, 0);
-}
-
-
-INLINE static void fs__sync_impl(uv_fs_t* req) {
- int fd = req->file.fd;
- int result;
-
- VERIFY_FD(fd, req);
-
- result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
- if (result == -1) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- } else {
- SET_REQ_RESULT(req, result);
- }
-}
-
-
-static void fs__fsync(uv_fs_t* req) {
- fs__sync_impl(req);
-}
-
-
-static void fs__fdatasync(uv_fs_t* req) {
- fs__sync_impl(req);
-}
-
-
-static void fs__ftruncate(uv_fs_t* req) {
- int fd = req->file.fd;
- HANDLE handle;
- NTSTATUS status;
- IO_STATUS_BLOCK io_status;
- FILE_END_OF_FILE_INFORMATION eof_info;
-
- VERIFY_FD(fd, req);
-
- handle = uv__get_osfhandle(fd);
-
- eof_info.EndOfFile.QuadPart = req->fs.info.offset;
-
- status = pNtSetInformationFile(handle,
- &io_status,
- &eof_info,
- sizeof eof_info,
- FileEndOfFileInformation);
-
- if (NT_SUCCESS(status)) {
- SET_REQ_RESULT(req, 0);
- } else {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
- }
-}
-
-
-static void fs__copyfile(uv_fs_t* req) {
- int flags;
- int overwrite;
- uv_stat_t statbuf;
- uv_stat_t new_statbuf;
-
- flags = req->fs.info.file_flags;
-
- if (flags & UV_FS_COPYFILE_FICLONE_FORCE) {
- SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
- return;
- }
-
- overwrite = flags & UV_FS_COPYFILE_EXCL;
-
- if (CopyFileW(req->file.pathw, req->fs.info.new_pathw, overwrite) != 0) {
- SET_REQ_RESULT(req, 0);
- return;
- }
-
- SET_REQ_WIN32_ERROR(req, GetLastError());
- if (req->result != UV_EBUSY)
- return;
-
- /* if error UV_EBUSY check if src and dst file are the same */
- if (fs__stat_impl_from_path(req->file.pathw, 0, &statbuf) != 0 ||
- fs__stat_impl_from_path(req->fs.info.new_pathw, 0, &new_statbuf) != 0) {
- return;
- }
-
- if (statbuf.st_dev == new_statbuf.st_dev &&
- statbuf.st_ino == new_statbuf.st_ino) {
- SET_REQ_RESULT(req, 0);
- }
-}
-
-
-static void fs__sendfile(uv_fs_t* req) {
- int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
- size_t length = req->fs.info.bufsml[0].len;
- int64_t offset = req->fs.info.offset;
- const size_t max_buf_size = 65536;
- size_t buf_size = length < max_buf_size ? length : max_buf_size;
- int n, result = 0;
- int64_t result_offset = 0;
- char* buf = (char*) uv__malloc(buf_size);
- if (!buf) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- if (offset != -1) {
- result_offset = _lseeki64(fd_in, offset, SEEK_SET);
- }
-
- if (result_offset == -1) {
- result = -1;
- } else {
- while (length > 0) {
- n = _read(fd_in, buf, length < buf_size ? length : buf_size);
- if (n == 0) {
- break;
- } else if (n == -1) {
- result = -1;
- break;
- }
-
- length -= n;
-
- n = _write(fd_out, buf, n);
- if (n == -1) {
- result = -1;
- break;
- }
-
- result += n;
- }
- }
-
- uv__free(buf);
-
- SET_REQ_RESULT(req, result);
-}
-
-
-static void fs__access(uv_fs_t* req) {
- DWORD attr = GetFileAttributesW(req->file.pathw);
-
- if (attr == INVALID_FILE_ATTRIBUTES) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- /*
- * Access is possible if
- * - write access wasn't requested,
- * - or the file isn't read-only,
- * - or it's a directory.
- * (Directories cannot be read-only on Windows.)
- */
- if (!(req->fs.info.mode & W_OK) ||
- !(attr & FILE_ATTRIBUTE_READONLY) ||
- (attr & FILE_ATTRIBUTE_DIRECTORY)) {
- SET_REQ_RESULT(req, 0);
- } else {
- SET_REQ_WIN32_ERROR(req, UV_EPERM);
- }
-
-}
-
-
-static void fs__chmod(uv_fs_t* req) {
- int result = _wchmod(req->file.pathw, req->fs.info.mode);
- SET_REQ_RESULT(req, result);
-}
-
-
-static void fs__fchmod(uv_fs_t* req) {
- int fd = req->file.fd;
- int clear_archive_flag;
- HANDLE handle;
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
- FILE_BASIC_INFORMATION file_info;
-
- VERIFY_FD(fd, req);
-
- handle = ReOpenFile(uv__get_osfhandle(fd), FILE_WRITE_ATTRIBUTES, 0, 0);
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- nt_status = pNtQueryInformationFile(handle,
- &io_status,
- &file_info,
- sizeof file_info,
- FileBasicInformation);
-
- if (!NT_SUCCESS(nt_status)) {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
- goto fchmod_cleanup;
- }
-
- /* Test if the Archive attribute is cleared */
- if ((file_info.FileAttributes & FILE_ATTRIBUTE_ARCHIVE) == 0) {
- /* Set Archive flag, otherwise setting or clearing the read-only
- flag will not work */
- file_info.FileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
- nt_status = pNtSetInformationFile(handle,
- &io_status,
- &file_info,
- sizeof file_info,
- FileBasicInformation);
- if (!NT_SUCCESS(nt_status)) {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
- goto fchmod_cleanup;
- }
- /* Remeber to clear the flag later on */
- clear_archive_flag = 1;
- } else {
- clear_archive_flag = 0;
- }
-
- if (req->fs.info.mode & _S_IWRITE) {
- file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
- } else {
- file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
- }
-
- nt_status = pNtSetInformationFile(handle,
- &io_status,
- &file_info,
- sizeof file_info,
- FileBasicInformation);
-
- if (!NT_SUCCESS(nt_status)) {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
- goto fchmod_cleanup;
- }
-
- if (clear_archive_flag) {
- file_info.FileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
- if (file_info.FileAttributes == 0) {
- file_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
- }
- nt_status = pNtSetInformationFile(handle,
- &io_status,
- &file_info,
- sizeof file_info,
- FileBasicInformation);
- if (!NT_SUCCESS(nt_status)) {
- SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
- goto fchmod_cleanup;
- }
- }
-
- SET_REQ_SUCCESS(req);
-fchmod_cleanup:
- CloseHandle(handle);
-}
-
-
-INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
- FILETIME filetime_a, filetime_m;
-
- TIME_T_TO_FILETIME(atime, &filetime_a);
- TIME_T_TO_FILETIME(mtime, &filetime_m);
-
- if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
- return -1;
- }
-
- return 0;
-}
-
-
-static void fs__utime(uv_fs_t* req) {
- HANDLE handle;
-
- handle = CreateFileW(req->file.pathw,
- FILE_WRITE_ATTRIBUTES,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- CloseHandle(handle);
- return;
- }
-
- CloseHandle(handle);
-
- req->result = 0;
-}
-
-
-static void fs__futime(uv_fs_t* req) {
- int fd = req->file.fd;
- HANDLE handle;
- VERIFY_FD(fd, req);
-
- handle = uv__get_osfhandle(fd);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
- return;
- }
-
- if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- req->result = 0;
-}
-
-
-static void fs__link(uv_fs_t* req) {
- DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
- if (r == 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- } else {
- req->result = 0;
- }
-}
-
-
-static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
- const WCHAR* new_path) {
- HANDLE handle = INVALID_HANDLE_VALUE;
- REPARSE_DATA_BUFFER *buffer = NULL;
- int created = 0;
- int target_len;
- int is_absolute, is_long_path;
- int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
- int start, len, i;
- int add_slash;
- DWORD bytes;
- WCHAR* path_buf;
-
- target_len = wcslen(path);
- is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
-
- if (is_long_path) {
- is_absolute = 1;
- } else {
- is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
- path[1] == L':' && IS_SLASH(path[2]);
- }
-
- if (!is_absolute) {
- /* Not supporting relative paths */
- SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
- return;
- }
-
- /* Do a pessimistic calculation of the required buffer size */
- needed_buf_size =
- FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
- JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
- 2 * (target_len + 2) * sizeof(WCHAR);
-
- /* Allocate the buffer */
- buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
- if (!buffer) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- /* Grab a pointer to the part of the buffer where filenames go */
- path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
- path_buf_len = 0;
-
- /* Copy the substitute (internal) target path */
- start = path_buf_len;
-
- wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
- JUNCTION_PREFIX_LEN);
- path_buf_len += JUNCTION_PREFIX_LEN;
-
- add_slash = 0;
- for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
- if (IS_SLASH(path[i])) {
- add_slash = 1;
- continue;
- }
-
- if (add_slash) {
- path_buf[path_buf_len++] = L'\\';
- add_slash = 0;
- }
-
- path_buf[path_buf_len++] = path[i];
- }
- path_buf[path_buf_len++] = L'\\';
- len = path_buf_len - start;
-
- /* Set the info about the substitute name */
- buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
- buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
-
- /* Insert null terminator */
- path_buf[path_buf_len++] = L'\0';
-
- /* Copy the print name of the target path */
- start = path_buf_len;
- add_slash = 0;
- for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
- if (IS_SLASH(path[i])) {
- add_slash = 1;
- continue;
- }
-
- if (add_slash) {
- path_buf[path_buf_len++] = L'\\';
- add_slash = 0;
- }
-
- path_buf[path_buf_len++] = path[i];
- }
- len = path_buf_len - start;
- if (len == 2) {
- path_buf[path_buf_len++] = L'\\';
- len++;
- }
-
- /* Set the info about the print name */
- buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
- buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
-
- /* Insert another null terminator */
- path_buf[path_buf_len++] = L'\0';
-
- /* Calculate how much buffer space was actually used */
- used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
- path_buf_len * sizeof(WCHAR);
- used_data_size = used_buf_size -
- FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
-
- /* Put general info in the data buffer */
- buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
- buffer->ReparseDataLength = used_data_size;
- buffer->Reserved = 0;
-
- /* Create a new directory */
- if (!CreateDirectoryW(new_path, NULL)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- goto error;
- }
- created = 1;
-
- /* Open the directory */
- handle = CreateFileW(new_path,
- GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS |
- FILE_FLAG_OPEN_REPARSE_POINT,
- NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- goto error;
- }
-
- /* Create the actual reparse point */
- if (!DeviceIoControl(handle,
- FSCTL_SET_REPARSE_POINT,
- buffer,
- used_buf_size,
- NULL,
- 0,
- &bytes,
- NULL)) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- goto error;
- }
-
- /* Clean up */
- CloseHandle(handle);
- uv__free(buffer);
-
- SET_REQ_RESULT(req, 0);
- return;
-
-error:
- uv__free(buffer);
-
- if (handle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle);
- }
-
- if (created) {
- RemoveDirectoryW(new_path);
- }
-}
-
-
-static void fs__symlink(uv_fs_t* req) {
- WCHAR* pathw;
- WCHAR* new_pathw;
- int flags;
- int err;
-
- pathw = req->file.pathw;
- new_pathw = req->fs.info.new_pathw;
-
- if (req->fs.info.file_flags & UV_FS_SYMLINK_JUNCTION) {
- fs__create_junction(req, pathw, new_pathw);
- return;
- }
-
- if (req->fs.info.file_flags & UV_FS_SYMLINK_DIR)
- flags = SYMBOLIC_LINK_FLAG_DIRECTORY | uv__file_symlink_usermode_flag;
- else
- flags = uv__file_symlink_usermode_flag;
-
- if (CreateSymbolicLinkW(new_pathw, pathw, flags)) {
- SET_REQ_RESULT(req, 0);
- return;
- }
-
- /* Something went wrong. We will test if it is because of user-mode
- * symlinks.
- */
- err = GetLastError();
- if (err == ERROR_INVALID_PARAMETER &&
- flags & SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE) {
- /* This system does not support user-mode symlinks. We will clear the
- * unsupported flag and retry.
- */
- uv__file_symlink_usermode_flag = 0;
- fs__symlink(req);
- } else {
- SET_REQ_WIN32_ERROR(req, err);
- }
-}
-
-
-static void fs__readlink(uv_fs_t* req) {
- HANDLE handle;
-
- handle = CreateFileW(req->file.pathw,
- 0,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
-
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- CloseHandle(handle);
- return;
- }
-
- req->flags |= UV_FS_FREE_PTR;
- SET_REQ_RESULT(req, 0);
-
- CloseHandle(handle);
-}
-
-
-static ssize_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
- int r;
- DWORD w_realpath_len;
- WCHAR* w_realpath_ptr = NULL;
- WCHAR* w_realpath_buf;
-
- w_realpath_len = GetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
- if (w_realpath_len == 0) {
- return -1;
- }
-
- w_realpath_buf = (WCHAR*)uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
- if (w_realpath_buf == NULL) {
- SetLastError(ERROR_OUTOFMEMORY);
- return -1;
- }
- w_realpath_ptr = w_realpath_buf;
-
- if (GetFinalPathNameByHandleW(
- handle, w_realpath_ptr, w_realpath_len, VOLUME_NAME_DOS) == 0) {
- uv__free(w_realpath_buf);
- SetLastError(ERROR_INVALID_HANDLE);
- return -1;
- }
-
- /* convert UNC path to long path */
- if (wcsncmp(w_realpath_ptr,
- UNC_PATH_PREFIX,
- UNC_PATH_PREFIX_LEN) == 0) {
- w_realpath_ptr += 6;
- *w_realpath_ptr = L'\\';
- w_realpath_len -= 6;
- } else if (wcsncmp(w_realpath_ptr,
- LONG_PATH_PREFIX,
- LONG_PATH_PREFIX_LEN) == 0) {
- w_realpath_ptr += 4;
- w_realpath_len -= 4;
- } else {
- uv__free(w_realpath_buf);
- SetLastError(ERROR_INVALID_HANDLE);
- return -1;
- }
-
- r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
- uv__free(w_realpath_buf);
- return r;
-}
-
-static void fs__realpath(uv_fs_t* req) {
- HANDLE handle;
-
- handle = CreateFileW(req->file.pathw,
- 0,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
- CloseHandle(handle);
- SET_REQ_WIN32_ERROR(req, GetLastError());
- return;
- }
-
- CloseHandle(handle);
- req->flags |= UV_FS_FREE_PTR;
- SET_REQ_RESULT(req, 0);
-}
-
-
-static void fs__chown(uv_fs_t* req) {
- req->result = 0;
-}
-
-
-static void fs__fchown(uv_fs_t* req) {
- req->result = 0;
-}
-
-
-static void fs__lchown(uv_fs_t* req) {
- req->result = 0;
-}
-
-static void uv__fs_work(struct uv__work* w) {
- uv_fs_t* req;
-
- req = container_of(w, uv_fs_t, work_req);
- assert(req->type == UV_FS);
-
-#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
- switch (req->fs_type) {
- XX(OPEN, open)
- XX(CLOSE, close)
- XX(READ, read)
- XX(WRITE, write)
- XX(COPYFILE, copyfile)
- XX(SENDFILE, sendfile)
- XX(STAT, stat)
- XX(LSTAT, lstat)
- XX(FSTAT, fstat)
- XX(FTRUNCATE, ftruncate)
- XX(UTIME, utime)
- XX(FUTIME, futime)
- XX(ACCESS, access)
- XX(CHMOD, chmod)
- XX(FCHMOD, fchmod)
- XX(FSYNC, fsync)
- XX(FDATASYNC, fdatasync)
- XX(UNLINK, unlink)
- XX(RMDIR, rmdir)
- XX(MKDIR, mkdir)
- XX(MKDTEMP, mkdtemp)
- XX(RENAME, rename)
- XX(SCANDIR, scandir)
- XX(READDIR, readdir)
- XX(OPENDIR, opendir)
- XX(CLOSEDIR, closedir)
- XX(LINK, link)
- XX(SYMLINK, symlink)
- XX(READLINK, readlink)
- XX(REALPATH, realpath)
- XX(CHOWN, chown)
- XX(FCHOWN, fchown);
- XX(LCHOWN, lchown);
- default:
- assert(!"bad uv_fs_type");
- }
-}
-
-
-static void uv__fs_done(struct uv__work* w, int status) {
- uv_fs_t* req;
-
- req = container_of(w, uv_fs_t, work_req);
- uv__req_unregister(req->loop, req);
-
- if (status == UV_ECANCELED) {
- assert(req->result == 0);
- req->result = UV_ECANCELED;
- }
-
- req->cb(req);
-}
-
-
-void uv_fs_req_cleanup(uv_fs_t* req) {
- if (req == NULL)
- return;
-
- if (req->flags & UV_FS_CLEANEDUP)
- return;
-
- if (req->flags & UV_FS_FREE_PATHS)
- uv__free(req->file.pathw);
-
- if (req->flags & UV_FS_FREE_PTR) {
- if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
- uv__fs_scandir_cleanup(req);
- else if (req->fs_type == UV_FS_READDIR)
- uv__fs_readdir_cleanup(req);
- else
- uv__free(req->ptr);
- }
-
- if (req->fs.info.bufs != req->fs.info.bufsml)
- uv__free(req->fs.info.bufs);
-
- req->path = NULL;
- req->file.pathw = NULL;
- req->fs.info.new_pathw = NULL;
- req->fs.info.bufs = NULL;
- req->ptr = NULL;
-
- req->flags |= UV_FS_CLEANEDUP;
-}
-
-
-int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
- int mode, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_OPEN);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.info.file_flags = flags;
- req->fs.info.mode = mode;
- POST;
-}
-
-
-int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- INIT(UV_FS_CLOSE);
- req->file.fd = fd;
- POST;
-}
-
-
-int uv_fs_read(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file fd,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t offset,
- uv_fs_cb cb) {
- INIT(UV_FS_READ);
-
- if (bufs == NULL || nbufs == 0)
- return UV_EINVAL;
-
- req->file.fd = fd;
-
- req->fs.info.nbufs = nbufs;
- req->fs.info.bufs = req->fs.info.bufsml;
- if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
- req->fs.info.bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(*bufs));
-
- if (req->fs.info.bufs == NULL)
- return UV_ENOMEM;
-
- memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
-
- req->fs.info.offset = offset;
- POST;
-}
-
-
-int uv_fs_write(uv_loop_t* loop,
- uv_fs_t* req,
- uv_file fd,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- int64_t offset,
- uv_fs_cb cb) {
- INIT(UV_FS_WRITE);
-
- if (bufs == NULL || nbufs == 0)
- return UV_EINVAL;
-
- req->file.fd = fd;
-
- req->fs.info.nbufs = nbufs;
- req->fs.info.bufs = req->fs.info.bufsml;
- if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
- req->fs.info.bufs = (uv_buf_t*)uv__malloc(nbufs * sizeof(*bufs));
-
- if (req->fs.info.bufs == NULL)
- return UV_ENOMEM;
-
- memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
-
- req->fs.info.offset = offset;
- POST;
-}
-
-
-int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_UNLINK);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_MKDIR);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.info.mode = mode;
- POST;
-}
-
-
-int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_MKDTEMP);
- err = fs__capture_path(req, tpl, NULL, TRUE);
- if (err)
- return uv_translate_sys_error(err);
-
- POST;
-}
-
-
-int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_RMDIR);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_SCANDIR);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.info.file_flags = flags;
- POST;
-}
-
-int uv_fs_opendir(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_OPENDIR);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err)
- return uv_translate_sys_error(err);
- POST;
-}
-
-int uv_fs_readdir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb) {
- INIT(UV_FS_READDIR);
-
- if (dir == NULL ||
- dir->dirents == NULL ||
- dir->dir_handle == INVALID_HANDLE_VALUE) {
- return UV_EINVAL;
- }
-
- req->ptr = dir;
- POST;
-}
-
-int uv_fs_closedir(uv_loop_t* loop,
- uv_fs_t* req,
- uv_dir_t* dir,
- uv_fs_cb cb) {
- INIT(UV_FS_CLOSEDIR);
- if (dir == NULL)
- return UV_EINVAL;
- req->ptr = dir;
- POST;
-}
-
-int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_LINK);
- err = fs__capture_path(req, path, new_path, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, int flags, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_SYMLINK);
- err = fs__capture_path(req, path, new_path, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.info.file_flags = flags;
- POST;
-}
-
-
-int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_READLINK);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_REALPATH);
-
- if (!path) {
- return UV_EINVAL;
- }
-
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
- uv_gid_t gid, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_CHOWN);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
- uv_gid_t gid, uv_fs_cb cb) {
- INIT(UV_FS_FCHOWN);
- POST;
-}
-
-
-int uv_fs_lchown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
- uv_gid_t gid, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_LCHOWN);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
- POST;
-}
-
-
-int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_STAT);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_LSTAT);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- INIT(UV_FS_FSTAT);
- req->file.fd = fd;
- POST;
-}
-
-
-int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
- const char* new_path, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_RENAME);
- err = fs__capture_path(req, path, new_path, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- POST;
-}
-
-
-int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- INIT(UV_FS_FSYNC);
- req->file.fd = fd;
- POST;
-}
-
-
-int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
- INIT(UV_FS_FDATASYNC);
- req->file.fd = fd;
- POST;
-}
-
-
-int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
- int64_t offset, uv_fs_cb cb) {
- INIT(UV_FS_FTRUNCATE);
- req->file.fd = fd;
- req->fs.info.offset = offset;
- POST;
-}
-
-
-int uv_fs_copyfile(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- const char* new_path,
- int flags,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_COPYFILE);
-
- if (flags & ~(UV_FS_COPYFILE_EXCL |
- UV_FS_COPYFILE_FICLONE |
- UV_FS_COPYFILE_FICLONE_FORCE)) {
- return UV_EINVAL;
- }
-
- err = fs__capture_path(req, path, new_path, cb != NULL);
-
- if (err)
- return uv_translate_sys_error(err);
-
- req->fs.info.file_flags = flags;
- POST;
-}
-
-
-int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
- uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
- INIT(UV_FS_SENDFILE);
- req->file.fd = fd_in;
- req->fs.info.fd_out = fd_out;
- req->fs.info.offset = in_offset;
- req->fs.info.bufsml[0].len = length;
- POST;
-}
-
-
-int uv_fs_access(uv_loop_t* loop,
- uv_fs_t* req,
- const char* path,
- int flags,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_ACCESS);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err)
- return uv_translate_sys_error(err);
-
- req->fs.info.mode = flags;
- POST;
-}
-
-
-int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
- uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_CHMOD);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.info.mode = mode;
- POST;
-}
-
-
-int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
- uv_fs_cb cb) {
- INIT(UV_FS_FCHMOD);
- req->file.fd = fd;
- req->fs.info.mode = mode;
- POST;
-}
-
-
-int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
- double mtime, uv_fs_cb cb) {
- int err;
-
- INIT(UV_FS_UTIME);
- err = fs__capture_path(req, path, NULL, cb != NULL);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- req->fs.time.atime = atime;
- req->fs.time.mtime = mtime;
- POST;
-}
-
-
-int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
- double mtime, uv_fs_cb cb) {
- INIT(UV_FS_FUTIME);
- req->file.fd = fd;
- req->fs.time.atime = atime;
- req->fs.time.mtime = mtime;
- POST;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/getaddrinfo.cpp b/wpiutil/src/main/native/libuv/src/win/getaddrinfo.cpp
deleted file mode 100644
index dfab860..0000000
--- a/wpiutil/src/main/native/libuv/src/win/getaddrinfo.cpp
+++ /dev/null
@@ -1,463 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "req-inl.h"
-#include "idna.h"
-
-/* EAI_* constants. */
-#include <winsock2.h>
-
-/* Needed for ConvertInterfaceIndexToLuid and ConvertInterfaceLuidToNameA */
-#include <iphlpapi.h>
-
-int uv__getaddrinfo_translate_error(int sys_err) {
- switch (sys_err) {
- case 0: return 0;
- case WSATRY_AGAIN: return UV_EAI_AGAIN;
- case WSAEINVAL: return UV_EAI_BADFLAGS;
- case WSANO_RECOVERY: return UV_EAI_FAIL;
- case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
- case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
- case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
- case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
- case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
- default: return uv_translate_sys_error(sys_err);
- }
-}
-
-
-/*
- * MinGW is missing this
- */
-#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
- typedef struct addrinfoW {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- size_t ai_addrlen;
- WCHAR* ai_canonname;
- struct sockaddr* ai_addr;
- struct addrinfoW* ai_next;
- } ADDRINFOW, *PADDRINFOW;
-
- DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
- const WCHAR* service,
- const ADDRINFOW* hints,
- PADDRINFOW* result);
-
- DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
-#endif
-
-
-/* Adjust size value to be multiple of 4. Use to keep pointer aligned.
- * Do we need different versions of this for different architectures? */
-#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
-
-#ifndef NDIS_IF_MAX_STRING_SIZE
-#define NDIS_IF_MAX_STRING_SIZE IF_MAX_STRING_SIZE
-#endif
-
-static void uv__getaddrinfo_work(struct uv__work* w) {
- uv_getaddrinfo_t* req;
- struct addrinfoW* hints;
- int err;
-
- req = container_of(w, uv_getaddrinfo_t, work_req);
- hints = req->addrinfow;
- req->addrinfow = NULL;
- err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
- req->retcode = uv__getaddrinfo_translate_error(err);
-}
-
-
-/*
- * Called from uv_run when complete. Call user specified callback
- * then free returned addrinfo
- * Returned addrinfo strings are converted from UTF-16 to UTF-8.
- *
- * To minimize allocation we calculate total size required,
- * and copy all structs and referenced strings into the one block.
- * Each size calculation is adjusted to avoid unaligned pointers.
- */
-static void uv__getaddrinfo_done(struct uv__work* w, int status) {
- uv_getaddrinfo_t* req;
- int addrinfo_len = 0;
- int name_len = 0;
- size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
- struct addrinfoW* addrinfow_ptr;
- struct addrinfo* addrinfo_ptr;
- char* alloc_ptr = NULL;
- char* cur_ptr = NULL;
-
- req = container_of(w, uv_getaddrinfo_t, work_req);
-
- /* release input parameter memory */
- uv__free(req->alloc);
- req->alloc = NULL;
-
- if (status == UV_ECANCELED) {
- assert(req->retcode == 0);
- req->retcode = UV_EAI_CANCELED;
- goto complete;
- }
-
- if (req->retcode == 0) {
- /* Convert addrinfoW to addrinfo. First calculate required length. */
- addrinfow_ptr = req->addrinfow;
- while (addrinfow_ptr != NULL) {
- addrinfo_len += addrinfo_struct_len +
- ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
- if (addrinfow_ptr->ai_canonname != NULL) {
- name_len = WideCharToMultiByte(CP_UTF8,
- 0,
- addrinfow_ptr->ai_canonname,
- -1,
- NULL,
- 0,
- NULL,
- NULL);
- if (name_len == 0) {
- req->retcode = uv_translate_sys_error(GetLastError());
- goto complete;
- }
- addrinfo_len += ALIGNED_SIZE(name_len);
- }
- addrinfow_ptr = addrinfow_ptr->ai_next;
- }
-
- /* allocate memory for addrinfo results */
- alloc_ptr = (char*)uv__malloc(addrinfo_len);
-
- /* do conversions */
- if (alloc_ptr != NULL) {
- cur_ptr = alloc_ptr;
- addrinfow_ptr = req->addrinfow;
-
- while (addrinfow_ptr != NULL) {
- /* copy addrinfo struct data */
- assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
- addrinfo_ptr = (struct addrinfo*)cur_ptr;
- addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
- addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
- addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
- addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
- addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
- addrinfo_ptr->ai_canonname = NULL;
- addrinfo_ptr->ai_addr = NULL;
- addrinfo_ptr->ai_next = NULL;
-
- cur_ptr += addrinfo_struct_len;
-
- /* copy sockaddr */
- if (addrinfo_ptr->ai_addrlen > 0) {
- assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
- alloc_ptr + addrinfo_len);
- memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
- addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
- cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
- }
-
- /* convert canonical name to UTF-8 */
- if (addrinfow_ptr->ai_canonname != NULL) {
- name_len = WideCharToMultiByte(CP_UTF8,
- 0,
- addrinfow_ptr->ai_canonname,
- -1,
- NULL,
- 0,
- NULL,
- NULL);
- assert(name_len > 0);
- assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
- name_len = WideCharToMultiByte(CP_UTF8,
- 0,
- addrinfow_ptr->ai_canonname,
- -1,
- cur_ptr,
- name_len,
- NULL,
- NULL);
- assert(name_len > 0);
- addrinfo_ptr->ai_canonname = cur_ptr;
- cur_ptr += ALIGNED_SIZE(name_len);
- }
- assert(cur_ptr <= alloc_ptr + addrinfo_len);
-
- /* set next ptr */
- addrinfow_ptr = addrinfow_ptr->ai_next;
- if (addrinfow_ptr != NULL) {
- addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
- }
- }
- req->addrinfo = (struct addrinfo*)alloc_ptr;
- } else {
- req->retcode = UV_EAI_MEMORY;
- }
- }
-
- /* return memory to system */
- if (req->addrinfow != NULL) {
- FreeAddrInfoW(req->addrinfow);
- req->addrinfow = NULL;
- }
-
-complete:
- uv__req_unregister(req->loop, req);
-
- /* finally do callback with converted result */
- if (req->getaddrinfo_cb)
- req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
-}
-
-
-void uv_freeaddrinfo(struct addrinfo* ai) {
- char* alloc_ptr = (char*)ai;
-
- /* release copied result memory */
- uv__free(alloc_ptr);
-}
-
-
-/*
- * Entry point for getaddrinfo
- * we convert the UTF-8 strings to UNICODE
- * and save the UNICODE string pointers in the req
- * We also copy hints so that caller does not need to keep memory until the
- * callback.
- * return 0 if a callback will be made
- * return error code if validation fails
- *
- * To minimize allocation we calculate total size required,
- * and copy all structs and referenced strings into the one block.
- * Each size calculation is adjusted to avoid unaligned pointers.
- */
-int uv_getaddrinfo(uv_loop_t* loop,
- uv_getaddrinfo_t* req,
- uv_getaddrinfo_cb getaddrinfo_cb,
- const char* node,
- const char* service,
- const struct addrinfo* hints) {
- char hostname_ascii[256];
- int nodesize = 0;
- int servicesize = 0;
- int hintssize = 0;
- char* alloc_ptr = NULL;
- int err;
- long rc;
-
- if (req == NULL || (node == NULL && service == NULL)) {
- return UV_EINVAL;
- }
-
- UV_REQ_INIT(req, UV_GETADDRINFO);
- req->getaddrinfo_cb = getaddrinfo_cb;
- req->addrinfo = NULL;
- req->loop = loop;
- req->retcode = 0;
-
- /* calculate required memory size for all input values */
- if (node != NULL) {
- rc = uv__idna_toascii(node,
- node + strlen(node),
- hostname_ascii,
- hostname_ascii + sizeof(hostname_ascii));
- if (rc < 0)
- return rc;
- nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, hostname_ascii,
- -1, NULL, 0) * sizeof(WCHAR));
- if (nodesize == 0) {
- err = GetLastError();
- goto error;
- }
- node = hostname_ascii;
- }
-
- if (service != NULL) {
- servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
- 0,
- service,
- -1,
- NULL,
- 0) *
- sizeof(WCHAR));
- if (servicesize == 0) {
- err = GetLastError();
- goto error;
- }
- }
- if (hints != NULL) {
- hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
- }
-
- /* allocate memory for inputs, and partition it as needed */
- alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
- if (!alloc_ptr) {
- err = WSAENOBUFS;
- goto error;
- }
-
- /* save alloc_ptr now so we can free if error */
- req->alloc = (void*)alloc_ptr;
-
- /* Convert node string to UTF16 into allocated memory and save pointer in the
- * request. */
- if (node != NULL) {
- req->node = (WCHAR*)alloc_ptr;
- if (MultiByteToWideChar(CP_UTF8,
- 0,
- node,
- -1,
- (WCHAR*) alloc_ptr,
- nodesize / sizeof(WCHAR)) == 0) {
- err = GetLastError();
- goto error;
- }
- alloc_ptr += nodesize;
- } else {
- req->node = NULL;
- }
-
- /* Convert service string to UTF16 into allocated memory and save pointer in
- * the req. */
- if (service != NULL) {
- req->service = (WCHAR*)alloc_ptr;
- if (MultiByteToWideChar(CP_UTF8,
- 0,
- service,
- -1,
- (WCHAR*) alloc_ptr,
- servicesize / sizeof(WCHAR)) == 0) {
- err = GetLastError();
- goto error;
- }
- alloc_ptr += servicesize;
- } else {
- req->service = NULL;
- }
-
- /* copy hints to allocated memory and save pointer in req */
- if (hints != NULL) {
- req->addrinfow = (struct addrinfoW*)alloc_ptr;
- req->addrinfow->ai_family = hints->ai_family;
- req->addrinfow->ai_socktype = hints->ai_socktype;
- req->addrinfow->ai_protocol = hints->ai_protocol;
- req->addrinfow->ai_flags = hints->ai_flags;
- req->addrinfow->ai_addrlen = 0;
- req->addrinfow->ai_canonname = NULL;
- req->addrinfow->ai_addr = NULL;
- req->addrinfow->ai_next = NULL;
- } else {
- req->addrinfow = NULL;
- }
-
- uv__req_register(loop, req);
-
- if (getaddrinfo_cb) {
- uv__work_submit(loop,
- &req->work_req,
- UV__WORK_SLOW_IO,
- uv__getaddrinfo_work,
- uv__getaddrinfo_done);
- return 0;
- } else {
- uv__getaddrinfo_work(&req->work_req);
- uv__getaddrinfo_done(&req->work_req, 0);
- return req->retcode;
- }
-
-error:
- if (req != NULL) {
- uv__free(req->alloc);
- req->alloc = NULL;
- }
- return uv_translate_sys_error(err);
-}
-
-int uv_if_indextoname(unsigned int ifindex, char* buffer, size_t* size) {
- NET_LUID luid;
- wchar_t wname[NDIS_IF_MAX_STRING_SIZE + 1]; /* Add one for the NUL. */
- DWORD bufsize;
- int r;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- r = ConvertInterfaceIndexToLuid(ifindex, &luid);
-
- if (r != 0)
- return uv_translate_sys_error(r);
-
- r = ConvertInterfaceLuidToNameW(&luid, wname, ARRAY_SIZE(wname));
-
- if (r != 0)
- return uv_translate_sys_error(r);
-
- /* Check how much space we need */
- bufsize = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL, 0, NULL, NULL);
-
- if (bufsize == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (bufsize > *size) {
- *size = bufsize;
- return UV_ENOBUFS;
- }
-
- /* Convert to UTF-8 */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- wname,
- -1,
- buffer,
- *size,
- NULL,
- NULL);
-
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
-
- *size = bufsize - 1;
- return 0;
-}
-
-int uv_if_indextoiid(unsigned int ifindex, char* buffer, size_t* size) {
- int r;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- r = snprintf(buffer, *size, "%d", ifindex);
-
- if (r < 0)
- return uv_translate_sys_error(r);
-
- if (r >= (int) *size) {
- *size = r + 1;
- return UV_ENOBUFS;
- }
-
- *size = r;
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/getnameinfo.cpp b/wpiutil/src/main/native/libuv/src/win/getnameinfo.cpp
deleted file mode 100644
index b377338..0000000
--- a/wpiutil/src/main/native/libuv/src/win/getnameinfo.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
-*
-* 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 <assert.h>
-#include <stdio.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "req-inl.h"
-
-#ifndef GetNameInfo
-int WSAAPI GetNameInfoW(
- const SOCKADDR *pSockaddr,
- socklen_t SockaddrLength,
- PWCHAR pNodeBuffer,
- DWORD NodeBufferSize,
- PWCHAR pServiceBuffer,
- DWORD ServiceBufferSize,
- INT Flags
-);
-#endif
-
-static void uv__getnameinfo_work(struct uv__work* w) {
- uv_getnameinfo_t* req;
- WCHAR host[NI_MAXHOST];
- WCHAR service[NI_MAXSERV];
- int ret;
-
- req = container_of(w, uv_getnameinfo_t, work_req);
- if (GetNameInfoW((struct sockaddr*)&req->storage,
- sizeof(req->storage),
- host,
- ARRAY_SIZE(host),
- service,
- ARRAY_SIZE(service),
- req->flags)) {
- ret = WSAGetLastError();
- req->retcode = uv__getaddrinfo_translate_error(ret);
- return;
- }
-
- ret = WideCharToMultiByte(CP_UTF8,
- 0,
- host,
- -1,
- req->host,
- sizeof(req->host),
- NULL,
- NULL);
- if (ret == 0) {
- req->retcode = uv_translate_sys_error(GetLastError());
- return;
- }
-
- ret = WideCharToMultiByte(CP_UTF8,
- 0,
- service,
- -1,
- req->service,
- sizeof(req->service),
- NULL,
- NULL);
- if (ret == 0) {
- req->retcode = uv_translate_sys_error(GetLastError());
- }
-}
-
-
-/*
-* Called from uv_run when complete.
-*/
-static void uv__getnameinfo_done(struct uv__work* w, int status) {
- uv_getnameinfo_t* req;
- char* host;
- char* service;
-
- req = container_of(w, uv_getnameinfo_t, work_req);
- uv__req_unregister(req->loop, req);
- host = service = NULL;
-
- if (status == UV_ECANCELED) {
- assert(req->retcode == 0);
- req->retcode = UV_EAI_CANCELED;
- } else if (req->retcode == 0) {
- host = req->host;
- service = req->service;
- }
-
- if (req->getnameinfo_cb)
- req->getnameinfo_cb(req, req->retcode, host, service);
-}
-
-
-/*
-* Entry point for getnameinfo
-* return 0 if a callback will be made
-* return error code if validation fails
-*/
-int uv_getnameinfo(uv_loop_t* loop,
- uv_getnameinfo_t* req,
- uv_getnameinfo_cb getnameinfo_cb,
- const struct sockaddr* addr,
- int flags) {
- if (req == NULL || addr == NULL)
- return UV_EINVAL;
-
- if (addr->sa_family == AF_INET) {
- memcpy(&req->storage,
- addr,
- sizeof(struct sockaddr_in));
- } else if (addr->sa_family == AF_INET6) {
- memcpy(&req->storage,
- addr,
- sizeof(struct sockaddr_in6));
- } else {
- return UV_EINVAL;
- }
-
- UV_REQ_INIT(req, UV_GETNAMEINFO);
- uv__req_register(loop, req);
-
- req->getnameinfo_cb = getnameinfo_cb;
- req->flags = flags;
- req->loop = loop;
- req->retcode = 0;
-
- if (getnameinfo_cb) {
- uv__work_submit(loop,
- &req->work_req,
- UV__WORK_SLOW_IO,
- uv__getnameinfo_work,
- uv__getnameinfo_done);
- return 0;
- } else {
- uv__getnameinfo_work(&req->work_req);
- uv__getnameinfo_done(&req->work_req, 0);
- return req->retcode;
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/handle-inl.h b/wpiutil/src/main/native/libuv/src/win/handle-inl.h
deleted file mode 100644
index 82c657d..0000000
--- a/wpiutil/src/main/native/libuv/src/win/handle-inl.h
+++ /dev/null
@@ -1,180 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_HANDLE_INL_H_
-#define UV_WIN_HANDLE_INL_H_
-
-#include <assert.h>
-#include <io.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-#define DECREASE_ACTIVE_COUNT(loop, handle) \
- do { \
- if (--(handle)->activecnt == 0 && \
- !((handle)->flags & UV_HANDLE_CLOSING)) { \
- uv__handle_stop((handle)); \
- } \
- assert((handle)->activecnt >= 0); \
- } while (0)
-
-
-#define INCREASE_ACTIVE_COUNT(loop, handle) \
- do { \
- if ((handle)->activecnt++ == 0) { \
- uv__handle_start((handle)); \
- } \
- assert((handle)->activecnt > 0); \
- } while (0)
-
-
-#define DECREASE_PENDING_REQ_COUNT(handle) \
- do { \
- assert(handle->reqs_pending > 0); \
- handle->reqs_pending--; \
- \
- if (handle->flags & UV_HANDLE_CLOSING && \
- handle->reqs_pending == 0) { \
- uv_want_endgame(loop, (uv_handle_t*)handle); \
- } \
- } while (0)
-
-
-#define uv__handle_closing(handle) \
- do { \
- assert(!((handle)->flags & UV_HANDLE_CLOSING)); \
- \
- if (!(((handle)->flags & UV_HANDLE_ACTIVE) && \
- ((handle)->flags & UV_HANDLE_REF))) \
- uv__active_handle_add((uv_handle_t*) (handle)); \
- \
- (handle)->flags |= UV_HANDLE_CLOSING; \
- (handle)->flags &= ~UV_HANDLE_ACTIVE; \
- } while (0)
-
-
-#define uv__handle_close(handle) \
- do { \
- QUEUE_REMOVE(&(handle)->handle_queue); \
- uv__active_handle_rm((uv_handle_t*) (handle)); \
- \
- (handle)->flags |= UV_HANDLE_CLOSED; \
- \
- if ((handle)->close_cb) \
- (handle)->close_cb((uv_handle_t*) (handle)); \
- } while (0)
-
-
-INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
- if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
- handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
-
- handle->endgame_next = loop->endgame_handles;
- loop->endgame_handles = handle;
- }
-}
-
-
-INLINE static void uv_process_endgames(uv_loop_t* loop) {
- uv_handle_t* handle;
-
- while (loop->endgame_handles) {
- handle = loop->endgame_handles;
- loop->endgame_handles = handle->endgame_next;
-
- handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
-
- switch (handle->type) {
- case UV_TCP:
- uv_tcp_endgame(loop, (uv_tcp_t*) handle);
- break;
-
- case UV_NAMED_PIPE:
- uv_pipe_endgame(loop, (uv_pipe_t*) handle);
- break;
-
- case UV_TTY:
- uv_tty_endgame(loop, (uv_tty_t*) handle);
- break;
-
- case UV_UDP:
- uv_udp_endgame(loop, (uv_udp_t*) handle);
- break;
-
- case UV_POLL:
- uv_poll_endgame(loop, (uv_poll_t*) handle);
- break;
-
- case UV_TIMER:
- uv__timer_close((uv_timer_t*) handle);
- uv__handle_close(handle);
- break;
-
- case UV_PREPARE:
- case UV_CHECK:
- case UV_IDLE:
- uv_loop_watcher_endgame(loop, handle);
- break;
-
- case UV_ASYNC:
- uv_async_endgame(loop, (uv_async_t*) handle);
- break;
-
- case UV_SIGNAL:
- uv_signal_endgame(loop, (uv_signal_t*) handle);
- break;
-
- case UV_PROCESS:
- uv_process_endgame(loop, (uv_process_t*) handle);
- break;
-
- case UV_FS_EVENT:
- uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
- break;
-
- case UV_FS_POLL:
- uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
- break;
-
- default:
- assert(0);
- break;
- }
- }
-}
-
-INLINE static HANDLE uv__get_osfhandle(int fd)
-{
- /* _get_osfhandle() raises an assert in debug builds if the FD is invalid.
- * But it also correctly checks the FD and returns INVALID_HANDLE_VALUE for
- * invalid FDs in release builds (or if you let the assert continue). So this
- * wrapper function disables asserts when calling _get_osfhandle. */
-
- HANDLE handle;
- UV_BEGIN_DISABLE_CRT_ASSERT();
- handle = (HANDLE) _get_osfhandle(fd);
- UV_END_DISABLE_CRT_ASSERT();
- return handle;
-}
-
-#endif /* UV_WIN_HANDLE_INL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/handle.cpp b/wpiutil/src/main/native/libuv/src/win/handle.cpp
deleted file mode 100644
index 61e4df6..0000000
--- a/wpiutil/src/main/native/libuv/src/win/handle.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <io.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-
-
-uv_handle_type uv_guess_handle(uv_file file) {
- HANDLE handle;
- DWORD mode;
-
- if (file < 0) {
- return UV_UNKNOWN_HANDLE;
- }
-
- handle = uv__get_osfhandle(file);
-
- switch (GetFileType(handle)) {
- case FILE_TYPE_CHAR:
- if (GetConsoleMode(handle, &mode)) {
- return UV_TTY;
- } else {
- return UV_FILE;
- }
-
- case FILE_TYPE_PIPE:
- return UV_NAMED_PIPE;
-
- case FILE_TYPE_DISK:
- return UV_FILE;
-
- default:
- return UV_UNKNOWN_HANDLE;
- }
-}
-
-
-int uv_is_active(const uv_handle_t* handle) {
- return (handle->flags & UV_HANDLE_ACTIVE) &&
- !(handle->flags & UV_HANDLE_CLOSING);
-}
-
-
-void uv_close(uv_handle_t* handle, uv_close_cb cb) {
- uv_loop_t* loop = handle->loop;
-
- if (handle->flags & UV_HANDLE_CLOSING) {
- assert(0);
- return;
- }
-
- handle->close_cb = cb;
-
- /* Handle-specific close actions */
- switch (handle->type) {
- case UV_TCP:
- uv_tcp_close(loop, (uv_tcp_t*)handle);
- return;
-
- case UV_NAMED_PIPE:
- uv_pipe_close(loop, (uv_pipe_t*) handle);
- return;
-
- case UV_TTY:
- uv_tty_close((uv_tty_t*) handle);
- return;
-
- case UV_UDP:
- uv_udp_close(loop, (uv_udp_t*) handle);
- return;
-
- case UV_POLL:
- uv_poll_close(loop, (uv_poll_t*) handle);
- return;
-
- case UV_TIMER:
- uv_timer_stop((uv_timer_t*)handle);
- uv__handle_closing(handle);
- uv_want_endgame(loop, handle);
- return;
-
- case UV_PREPARE:
- uv_prepare_stop((uv_prepare_t*)handle);
- uv__handle_closing(handle);
- uv_want_endgame(loop, handle);
- return;
-
- case UV_CHECK:
- uv_check_stop((uv_check_t*)handle);
- uv__handle_closing(handle);
- uv_want_endgame(loop, handle);
- return;
-
- case UV_IDLE:
- uv_idle_stop((uv_idle_t*)handle);
- uv__handle_closing(handle);
- uv_want_endgame(loop, handle);
- return;
-
- case UV_ASYNC:
- uv_async_close(loop, (uv_async_t*) handle);
- return;
-
- case UV_SIGNAL:
- uv_signal_close(loop, (uv_signal_t*) handle);
- return;
-
- case UV_PROCESS:
- uv_process_close(loop, (uv_process_t*) handle);
- return;
-
- case UV_FS_EVENT:
- uv_fs_event_close(loop, (uv_fs_event_t*) handle);
- return;
-
- case UV_FS_POLL:
- uv__fs_poll_close((uv_fs_poll_t*) handle);
- uv__handle_closing(handle);
- return;
-
- default:
- /* Not supported */
- abort();
- }
-}
-
-
-int uv_is_closing(const uv_handle_t* handle) {
- return !!(handle->flags & (UV_HANDLE_CLOSING | UV_HANDLE_CLOSED));
-}
-
-
-uv_os_fd_t uv_get_osfhandle(int fd) {
- return uv__get_osfhandle(fd);
-}
-
-int uv_open_osfhandle(uv_os_fd_t os_fd) {
- return _open_osfhandle((intptr_t) os_fd, 0);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/internal.h b/wpiutil/src/main/native/libuv/src/win/internal.h
deleted file mode 100644
index 70ddaa5..0000000
--- a/wpiutil/src/main/native/libuv/src/win/internal.h
+++ /dev/null
@@ -1,342 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_INTERNAL_H_
-#define UV_WIN_INTERNAL_H_
-
-#include "uv.h"
-#include "../uv-common.h"
-
-#include "uv/tree.h"
-#include "winapi.h"
-#include "winsock.h"
-
-#ifdef _MSC_VER
-# define INLINE __inline
-# define UV_THREAD_LOCAL __declspec( thread )
-#else
-# define INLINE inline
-# define UV_THREAD_LOCAL __thread
-#endif
-
-
-#ifdef _DEBUG
-
-extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
-
-#define UV_BEGIN_DISABLE_CRT_ASSERT() \
- { \
- int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
- uv__crt_assert_enabled = FALSE;
-
-
-#define UV_END_DISABLE_CRT_ASSERT() \
- uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
- }
-
-#else
-#define UV_BEGIN_DISABLE_CRT_ASSERT()
-#define UV_END_DISABLE_CRT_ASSERT()
-#endif
-
-/*
- * TCP
- */
-
-typedef enum {
- UV__IPC_SOCKET_XFER_NONE = 0,
- UV__IPC_SOCKET_XFER_TCP_CONNECTION,
- UV__IPC_SOCKET_XFER_TCP_SERVER
-} uv__ipc_socket_xfer_type_t;
-
-typedef struct {
- WSAPROTOCOL_INFOW socket_info;
- uint32_t delayed_error;
-} uv__ipc_socket_xfer_info_t;
-
-int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
-int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
-int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb);
-int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
- const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
-int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
- unsigned int nbufs);
-
-void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
-void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_write_t* req);
-void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_req_t* req);
-void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_connect_t* req);
-
-void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
-void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
-
-int uv__tcp_xfer_export(uv_tcp_t* handle,
- int pid,
- uv__ipc_socket_xfer_type_t* xfer_type,
- uv__ipc_socket_xfer_info_t* xfer_info);
-int uv__tcp_xfer_import(uv_tcp_t* tcp,
- uv__ipc_socket_xfer_type_t xfer_type,
- uv__ipc_socket_xfer_info_t* xfer_info);
-
-
-/*
- * UDP
- */
-void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
-void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
- uv_udp_send_t* req);
-
-void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
-void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
-
-
-/*
- * Pipes
- */
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize);
-
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
-int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
-int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb);
-void uv__pipe_read_stop(uv_pipe_t* handle);
-int uv__pipe_write(uv_loop_t* loop,
- uv_write_t* req,
- uv_pipe_t* handle,
- const uv_buf_t bufs[],
- size_t nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb);
-
-void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_req_t* req);
-void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_write_t* req);
-void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_req_t* raw_req);
-void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_connect_t* req);
-void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_shutdown_t* req);
-
-void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
-void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
-void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
-
-
-/*
- * TTY
- */
-void uv_console_init(void);
-
-int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb);
-int uv_tty_read_stop(uv_tty_t* handle);
-int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
- const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
-int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
- unsigned int nbufs);
-void uv_tty_close(uv_tty_t* handle);
-
-void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* req);
-void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_write_t* req);
-/*
- * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
- * TODO: find a way to remove it
- */
-void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* raw_req);
-/*
- * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
- * TODO: find a way to remove it
- */
-void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_connect_t* req);
-
-void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
-
-
-/*
- * Poll watchers
- */
-void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
- uv_req_t* req);
-
-int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
-void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
-
-
-/*
- * Loop watchers
- */
-void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
-
-void uv_prepare_invoke(uv_loop_t* loop);
-void uv_check_invoke(uv_loop_t* loop);
-void uv_idle_invoke(uv_loop_t* loop);
-
-void uv__once_init(void);
-
-
-/*
- * Async watcher
- */
-void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
-void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
-
-void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
- uv_req_t* req);
-
-
-/*
- * Signal watcher
- */
-void uv_signals_init(void);
-int uv__signal_dispatch(int signum);
-
-void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
-void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
-
-void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
- uv_req_t* req);
-
-
-/*
- * Spawn
- */
-void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
-void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
-void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
-
-
-/*
- * Error
- */
-int uv_translate_sys_error(int sys_errno);
-
-
-/*
- * FS
- */
-void uv_fs_init(void);
-
-
-/*
- * FS Event
- */
-void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
- uv_fs_event_t* handle);
-void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
-void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
-
-
-/*
- * Stat poller.
- */
-void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
-
-
-/*
- * Utilities.
- */
-void uv__util_init(void);
-
-uint64_t uv__hrtime(double scale);
-__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
-int uv__getpwuid_r(uv_passwd_t* pwd);
-int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
-int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
-
-typedef int (WINAPI *uv__peersockfunc)(SOCKET, struct sockaddr*, int*);
-
-int uv__getsockpeername(const uv_handle_t* handle,
- uv__peersockfunc func,
- struct sockaddr* name,
- int* namelen,
- int delayed_error);
-
-
-/*
- * Process stdio handles.
- */
-int uv__stdio_create(uv_loop_t* loop,
- const uv_process_options_t* options,
- BYTE** buffer_ptr);
-void uv__stdio_destroy(BYTE* buffer);
-void uv__stdio_noinherit(BYTE* buffer);
-int uv__stdio_verify(BYTE* buffer, WORD size);
-WORD uv__stdio_size(BYTE* buffer);
-HANDLE uv__stdio_handle(BYTE* buffer, int fd);
-
-
-/*
- * Winapi and ntapi utility functions
- */
-void uv_winapi_init(void);
-
-
-/*
- * Winsock utility functions
- */
-void uv_winsock_init(void);
-
-int uv_ntstatus_to_winsock_error(NTSTATUS status);
-
-BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
-BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
-
-int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
- DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
-int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
- DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
- int* addr_len, WSAOVERLAPPED *overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
-
-int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
- AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
-
-/* Whether there are any non-IFS LSPs stacked on TCP */
-extern int uv_tcp_non_ifs_lsp_ipv4;
-extern int uv_tcp_non_ifs_lsp_ipv6;
-
-/* Ip address used to bind to any port at any interface */
-extern struct sockaddr_in uv_addr_ip4_any_;
-extern struct sockaddr_in6 uv_addr_ip6_any_;
-
-/*
- * Wake all loops with fake message
- */
-void uv__wake_all_loops(void);
-
-/*
- * Init system wake-up detection
- */
-void uv__init_detect_system_wakeup(void);
-
-#endif /* UV_WIN_INTERNAL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/loop-watcher.cpp b/wpiutil/src/main/native/libuv/src/win/loop-watcher.cpp
deleted file mode 100644
index ad7fbea..0000000
--- a/wpiutil/src/main/native/libuv/src/win/loop-watcher.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-
-
-void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
- if (handle->flags & UV_HANDLE_CLOSING) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- handle->flags |= UV_HANDLE_CLOSED;
- uv__handle_close(handle);
- }
-}
-
-
-#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
- int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
- uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
- \
- return 0; \
- } \
- \
- \
- int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
- uv_loop_t* loop = handle->loop; \
- uv_##name##_t* old_head; \
- \
- assert(handle->type == UV_##NAME); \
- \
- if (uv__is_active(handle)) \
- return 0; \
- \
- if (cb == NULL) \
- return UV_EINVAL; \
- \
- old_head = loop->name##_handles; \
- \
- handle->name##_next = old_head; \
- handle->name##_prev = NULL; \
- \
- if (old_head) { \
- old_head->name##_prev = handle; \
- } \
- \
- loop->name##_handles = handle; \
- \
- handle->name##_cb = cb; \
- uv__handle_start(handle); \
- \
- return 0; \
- } \
- \
- \
- int uv_##name##_stop(uv_##name##_t* handle) { \
- uv_loop_t* loop = handle->loop; \
- \
- assert(handle->type == UV_##NAME); \
- \
- if (!uv__is_active(handle)) \
- return 0; \
- \
- /* Update loop head if needed */ \
- if (loop->name##_handles == handle) { \
- loop->name##_handles = handle->name##_next; \
- } \
- \
- /* Update the iterator-next pointer of needed */ \
- if (loop->next_##name##_handle == handle) { \
- loop->next_##name##_handle = handle->name##_next; \
- } \
- \
- if (handle->name##_prev) { \
- handle->name##_prev->name##_next = handle->name##_next; \
- } \
- if (handle->name##_next) { \
- handle->name##_next->name##_prev = handle->name##_prev; \
- } \
- \
- uv__handle_stop(handle); \
- \
- return 0; \
- } \
- \
- \
- void uv_##name##_invoke(uv_loop_t* loop) { \
- uv_##name##_t* handle; \
- \
- (loop)->next_##name##_handle = (loop)->name##_handles; \
- \
- while ((loop)->next_##name##_handle != NULL) { \
- handle = (loop)->next_##name##_handle; \
- (loop)->next_##name##_handle = handle->name##_next; \
- \
- handle->name##_cb(handle); \
- } \
- }
-
-UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
-UV_LOOP_WATCHER_DEFINE(check, CHECK)
-UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/wpiutil/src/main/native/libuv/src/win/pipe.cpp b/wpiutil/src/main/native/libuv/src/win/pipe.cpp
deleted file mode 100644
index 0c03a06..0000000
--- a/wpiutil/src/main/native/libuv/src/win/pipe.cpp
+++ /dev/null
@@ -1,2388 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 _CRT_NONSTDC_NO_WARNINGS
-
-#include <assert.h>
-#include <io.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "handle-inl.h"
-#include "internal.h"
-#include "req-inl.h"
-#include "stream-inl.h"
-#include "uv-common.h"
-#include "uv.h"
-
-#include <aclapi.h>
-#include <accctrl.h>
-
-/* A zero-size buffer for use by uv_pipe_read */
-static char uv_zero_[] = "";
-
-/* Null uv_buf_t */
-static const uv_buf_t uv_null_buf_ = { 0, NULL };
-
-/* The timeout that the pipe will wait for the remote end to write data when
- * the local ends wants to shut it down. */
-static const int64_t eof_timeout = 50; /* ms */
-
-static const int default_pending_pipe_instances = 4;
-
-/* Pipe prefix */
-static char pipe_prefix[] = "\\\\?\\pipe";
-static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
-
-/* IPC incoming xfer queue item. */
-typedef struct {
- uv__ipc_socket_xfer_type_t xfer_type;
- uv__ipc_socket_xfer_info_t xfer_info;
- QUEUE member;
-} uv__ipc_xfer_queue_item_t;
-
-/* IPC frame header flags. */
-/* clang-format off */
-enum {
- UV__IPC_FRAME_HAS_DATA = 0x01,
- UV__IPC_FRAME_HAS_SOCKET_XFER = 0x02,
- UV__IPC_FRAME_XFER_IS_TCP_CONNECTION = 0x04,
- /* These are combinations of the flags above. */
- UV__IPC_FRAME_XFER_FLAGS = 0x06,
- UV__IPC_FRAME_VALID_FLAGS = 0x07
-};
-/* clang-format on */
-
-/* IPC frame header. */
-typedef struct {
- uint32_t flags;
- uint32_t reserved1; /* Ignored. */
- uint32_t data_length; /* Must be zero if there is no data. */
- uint32_t reserved2; /* Must be zero. */
-} uv__ipc_frame_header_t;
-
-/* To implement the IPC protocol correctly, these structures must have exactly
- * the right size. */
-STATIC_ASSERT(sizeof(uv__ipc_frame_header_t) == 16);
-STATIC_ASSERT(sizeof(uv__ipc_socket_xfer_info_t) == 632);
-
-/* Coalesced write request. */
-typedef struct {
- uv_write_t req; /* Internal heap-allocated write request. */
- uv_write_t* user_req; /* Pointer to user-specified uv_write_t. */
-} uv__coalesced_write_t;
-
-
-static void eof_timer_init(uv_pipe_t* pipe);
-static void eof_timer_start(uv_pipe_t* pipe);
-static void eof_timer_stop(uv_pipe_t* pipe);
-static void eof_timer_cb(uv_timer_t* timer);
-static void eof_timer_destroy(uv_pipe_t* pipe);
-static void eof_timer_close_cb(uv_handle_t* handle);
-
-
-static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
- snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
-}
-
-
-int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
- uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
-
- handle->reqs_pending = 0;
- handle->handle = INVALID_HANDLE_VALUE;
- handle->name = NULL;
- handle->pipe.conn.ipc_remote_pid = 0;
- handle->pipe.conn.ipc_data_frame.payload_remaining = 0;
- QUEUE_INIT(&handle->pipe.conn.ipc_xfer_queue);
- handle->pipe.conn.ipc_xfer_queue_length = 0;
- handle->ipc = ipc;
- handle->pipe.conn.non_overlapped_writes_tail = NULL;
-
- return 0;
-}
-
-
-static void uv_pipe_connection_init(uv_pipe_t* handle) {
- uv_connection_init((uv_stream_t*) handle);
- handle->read_req.data = handle;
- handle->pipe.conn.eof_timer = NULL;
- assert(!(handle->flags & UV_HANDLE_PIPESERVER));
- if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
- handle->pipe.conn.readfile_thread_handle = NULL;
- InitializeCriticalSection(&handle->pipe.conn.readfile_thread_lock);
- }
-}
-
-
-static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
- HANDLE pipeHandle;
-
- /*
- * Assume that we have a duplex pipe first, so attempt to
- * connect with GENERIC_READ | GENERIC_WRITE.
- */
- pipeHandle = CreateFileW(name,
- GENERIC_READ | GENERIC_WRITE,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
- return pipeHandle;
- }
-
- /*
- * If the pipe is not duplex CreateFileW fails with
- * ERROR_ACCESS_DENIED. In that case try to connect
- * as a read-only or write-only.
- */
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- pipeHandle = CreateFileW(name,
- GENERIC_READ | FILE_WRITE_ATTRIBUTES,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = UV_HANDLE_READABLE;
- return pipeHandle;
- }
- }
-
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- pipeHandle = CreateFileW(name,
- GENERIC_WRITE | FILE_READ_ATTRIBUTES,
- 0,
- NULL,
- OPEN_EXISTING,
- FILE_FLAG_OVERLAPPED,
- NULL);
-
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- *duplex_flags = UV_HANDLE_WRITABLE;
- return pipeHandle;
- }
- }
-
- return INVALID_HANDLE_VALUE;
-}
-
-
-static void close_pipe(uv_pipe_t* pipe) {
- assert(pipe->u.fd == -1 || pipe->u.fd > 2);
- if (pipe->u.fd == -1)
- CloseHandle(pipe->handle);
- else
- close(pipe->u.fd);
-
- pipe->u.fd = -1;
- pipe->handle = INVALID_HANDLE_VALUE;
-}
-
-
-int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
- char* name, size_t nameSize) {
- HANDLE pipeHandle;
- int err;
- char* ptr = (char*)handle;
-
- for (;;) {
- uv_unique_pipe_name(ptr, name, nameSize);
-
- pipeHandle = CreateNamedPipeA(name,
- access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
- NULL);
-
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- /* No name collisions. We're done. */
- break;
- }
-
- err = GetLastError();
- if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
- goto error;
- }
-
- /* Pipe name collision. Increment the pointer and try again. */
- ptr++;
- }
-
- if (CreateIoCompletionPort(pipeHandle,
- loop->iocp,
- (ULONG_PTR)handle,
- 0) == NULL) {
- err = GetLastError();
- goto error;
- }
-
- uv_pipe_connection_init(handle);
- handle->handle = pipeHandle;
-
- return 0;
-
- error:
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(pipeHandle);
- }
-
- return err;
-}
-
-
-static int uv_set_pipe_handle(uv_loop_t* loop,
- uv_pipe_t* handle,
- HANDLE pipeHandle,
- int fd,
- DWORD duplex_flags) {
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
- FILE_MODE_INFORMATION mode_info;
- DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
- DWORD current_mode = 0;
- DWORD err = 0;
-
- if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
- handle->handle != INVALID_HANDLE_VALUE)
- return UV_EBUSY;
-
- if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
- err = GetLastError();
- if (err == ERROR_ACCESS_DENIED) {
- /*
- * SetNamedPipeHandleState can fail if the handle doesn't have either
- * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES.
- * But if the handle already has the desired wait and blocking modes
- * we can continue.
- */
- if (!GetNamedPipeHandleState(pipeHandle, ¤t_mode, NULL, NULL,
- NULL, NULL, 0)) {
- return -1;
- } else if (current_mode & PIPE_NOWAIT) {
- SetLastError(ERROR_ACCESS_DENIED);
- return -1;
- }
- } else {
- /* If this returns ERROR_INVALID_PARAMETER we probably opened
- * something that is not a pipe. */
- if (err == ERROR_INVALID_PARAMETER) {
- SetLastError(WSAENOTSOCK);
- }
- return -1;
- }
- }
-
- /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
- nt_status = pNtQueryInformationFile(pipeHandle,
- &io_status,
- &mode_info,
- sizeof(mode_info),
- FileModeInformation);
- if (nt_status != STATUS_SUCCESS) {
- return -1;
- }
-
- if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
- mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
- /* Non-overlapped pipe. */
- handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
- } else {
- /* Overlapped pipe. Try to associate with IOCP. */
- if (CreateIoCompletionPort(pipeHandle,
- loop->iocp,
- (ULONG_PTR)handle,
- 0) == NULL) {
- handle->flags |= UV_HANDLE_EMULATE_IOCP;
- }
- }
-
- handle->handle = pipeHandle;
- handle->u.fd = fd;
- handle->flags |= duplex_flags;
-
- return 0;
-}
-
-
-static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
- uv_loop_t* loop;
- uv_pipe_t* handle;
- uv_shutdown_t* req;
-
- req = (uv_shutdown_t*) parameter;
- assert(req);
- handle = (uv_pipe_t*) req->handle;
- assert(handle);
- loop = handle->loop;
- assert(loop);
-
- FlushFileBuffers(handle->handle);
-
- /* Post completed */
- POST_COMPLETION_FOR_REQ(loop, req);
-
- return 0;
-}
-
-
-void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
- int err;
- DWORD result;
- uv_shutdown_t* req;
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
- FILE_PIPE_LOCAL_INFORMATION pipe_info;
- uv__ipc_xfer_queue_item_t* xfer_queue_item;
-
- if ((handle->flags & UV_HANDLE_CONNECTION) &&
- handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- req = handle->stream.conn.shutdown_req;
-
- /* Clear the shutdown_req field so we don't go here again. */
- handle->stream.conn.shutdown_req = NULL;
-
- if (handle->flags & UV_HANDLE_CLOSING) {
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- /* Already closing. Cancel the shutdown. */
- if (req->cb) {
- req->cb(req, UV_ECANCELED);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
-
- /* Try to avoid flushing the pipe buffer in the thread pool. */
- nt_status = pNtQueryInformationFile(handle->handle,
- &io_status,
- &pipe_info,
- sizeof pipe_info,
- FilePipeLocalInformation);
-
- if (nt_status != STATUS_SUCCESS) {
- /* Failure */
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
- if (req->cb) {
- err = pRtlNtStatusToDosError(nt_status);
- req->cb(req, uv_translate_sys_error(err));
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
-
- if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
- /* Short-circuit, no need to call FlushFileBuffers. */
- uv_insert_pending_req(loop, (uv_req_t*) req);
- return;
- }
-
- /* Run FlushFileBuffers in the thread pool. */
- result = QueueUserWorkItem(pipe_shutdown_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION);
- if (result) {
- return;
-
- } else {
- /* Failure. */
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
- if (req->cb) {
- err = GetLastError();
- req->cb(req, uv_translate_sys_error(err));
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
- }
-
- if (handle->flags & UV_HANDLE_CLOSING &&
- handle->reqs_pending == 0) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- if (handle->flags & UV_HANDLE_CONNECTION) {
- /* Free pending sockets */
- while (!QUEUE_EMPTY(&handle->pipe.conn.ipc_xfer_queue)) {
- QUEUE* q;
- SOCKET socket;
-
- q = QUEUE_HEAD(&handle->pipe.conn.ipc_xfer_queue);
- QUEUE_REMOVE(q);
- xfer_queue_item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
-
- /* Materialize socket and close it */
- socket = WSASocketW(FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- &xfer_queue_item->xfer_info.socket_info,
- 0,
- WSA_FLAG_OVERLAPPED);
- uv__free(xfer_queue_item);
-
- if (socket != INVALID_SOCKET)
- closesocket(socket);
- }
- handle->pipe.conn.ipc_xfer_queue_length = 0;
-
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(handle->read_req.wait_handle);
- handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
- }
- if (handle->read_req.event_handle) {
- CloseHandle(handle->read_req.event_handle);
- handle->read_req.event_handle = NULL;
- }
- }
-
- if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)
- DeleteCriticalSection(&handle->pipe.conn.readfile_thread_lock);
- }
-
- if (handle->flags & UV_HANDLE_PIPESERVER) {
- assert(handle->pipe.serv.accept_reqs);
- uv__free(handle->pipe.serv.accept_reqs);
- handle->pipe.serv.accept_reqs = NULL;
- }
-
- uv__handle_close(handle);
- }
-}
-
-
-void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
- if (handle->flags & UV_HANDLE_BOUND)
- return;
- handle->pipe.serv.pending_instances = count;
- handle->flags |= UV_HANDLE_PIPESERVER;
-}
-
-
-/* Creates a pipe server. */
-int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
- uv_loop_t* loop = handle->loop;
- int i, err, nameSize;
- uv_pipe_accept_t* req;
-
- if (handle->flags & UV_HANDLE_BOUND) {
- return UV_EINVAL;
- }
-
- if (!name) {
- return UV_EINVAL;
- }
-
- if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
- handle->pipe.serv.pending_instances = default_pending_pipe_instances;
- }
-
- handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
- uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
- if (!handle->pipe.serv.accept_reqs) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
- req = &handle->pipe.serv.accept_reqs[i];
- UV_REQ_INIT(req, UV_ACCEPT);
- req->data = handle;
- req->pipeHandle = INVALID_HANDLE_VALUE;
- req->next_pending = NULL;
- }
-
- /* Convert name to UTF16. */
- nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
- handle->name = (WCHAR*)uv__malloc(nameSize);
- if (!handle->name) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- name,
- -1,
- handle->name,
- nameSize / sizeof(WCHAR))) {
- err = GetLastError();
- goto error;
- }
-
- /*
- * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
- * If this fails then there's already a pipe server for the given pipe name.
- */
- handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
- FILE_FLAG_FIRST_PIPE_INSTANCE | WRITE_DAC,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
-
- if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
- err = GetLastError();
- if (err == ERROR_ACCESS_DENIED) {
- err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
- } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
- err = WSAEACCES; /* Translates to UV_EACCES. */
- }
- goto error;
- }
-
- if (uv_set_pipe_handle(loop,
- handle,
- handle->pipe.serv.accept_reqs[0].pipeHandle,
- -1,
- 0)) {
- err = GetLastError();
- goto error;
- }
-
- handle->pipe.serv.pending_accepts = NULL;
- handle->flags |= UV_HANDLE_PIPESERVER;
- handle->flags |= UV_HANDLE_BOUND;
-
- return 0;
-
-error:
- if (handle->name) {
- uv__free(handle->name);
- handle->name = NULL;
- }
-
- if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
- handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
- uv_loop_t* loop;
- uv_pipe_t* handle;
- uv_connect_t* req;
- HANDLE pipeHandle = INVALID_HANDLE_VALUE;
- DWORD duplex_flags;
-
- req = (uv_connect_t*) parameter;
- assert(req);
- handle = (uv_pipe_t*) req->handle;
- assert(handle);
- loop = handle->loop;
- assert(loop);
-
- /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. We wait
- * for the pipe to become available with WaitNamedPipe. */
- while (WaitNamedPipeW(handle->name, 30000)) {
- /* The pipe is now available, try to connect. */
- pipeHandle = open_named_pipe(handle->name, &duplex_flags);
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- break;
- }
-
- SwitchToThread();
- }
-
- if (pipeHandle != INVALID_HANDLE_VALUE &&
- !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
- SET_REQ_SUCCESS(req);
- } else {
- SET_REQ_ERROR(req, GetLastError());
- }
-
- /* Post completed */
- POST_COMPLETION_FOR_REQ(loop, req);
-
- return 0;
-}
-
-
-void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
- const char* name, uv_connect_cb cb) {
- uv_loop_t* loop = handle->loop;
- int err, nameSize;
- HANDLE pipeHandle = INVALID_HANDLE_VALUE;
- DWORD duplex_flags;
-
- UV_REQ_INIT(req, UV_CONNECT);
- req->handle = (uv_stream_t*) handle;
- req->cb = cb;
-
- /* Convert name to UTF16. */
- nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
- handle->name = (WCHAR*)uv__malloc(nameSize);
- if (!handle->name) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- name,
- -1,
- handle->name,
- nameSize / sizeof(WCHAR))) {
- err = GetLastError();
- goto error;
- }
-
- pipeHandle = open_named_pipe(handle->name, &duplex_flags);
- if (pipeHandle == INVALID_HANDLE_VALUE) {
- if (GetLastError() == ERROR_PIPE_BUSY) {
- /* Wait for the server to make a pipe instance available. */
- if (!QueueUserWorkItem(&pipe_connect_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION)) {
- err = GetLastError();
- goto error;
- }
-
- REGISTER_HANDLE_REQ(loop, handle, req);
- handle->reqs_pending++;
-
- return;
- }
-
- err = GetLastError();
- goto error;
- }
-
- assert(pipeHandle != INVALID_HANDLE_VALUE);
-
- if (uv_set_pipe_handle(loop,
- (uv_pipe_t*) req->handle,
- pipeHandle,
- -1,
- duplex_flags)) {
- err = GetLastError();
- goto error;
- }
-
- SET_REQ_SUCCESS(req);
- uv_insert_pending_req(loop, (uv_req_t*) req);
- handle->reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- return;
-
-error:
- if (handle->name) {
- uv__free(handle->name);
- handle->name = NULL;
- }
-
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(pipeHandle);
- }
-
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, err);
- uv_insert_pending_req(loop, (uv_req_t*) req);
- handle->reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- return;
-}
-
-
-void uv__pipe_interrupt_read(uv_pipe_t* handle) {
- BOOL r;
-
- if (!(handle->flags & UV_HANDLE_READ_PENDING))
- return; /* No pending reads. */
- if (handle->flags & UV_HANDLE_CANCELLATION_PENDING)
- return; /* Already cancelled. */
- if (handle->handle == INVALID_HANDLE_VALUE)
- return; /* Pipe handle closed. */
-
- if (!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE)) {
- /* Cancel asynchronous read. */
- r = CancelIoEx(handle->handle, &handle->read_req.u.io.overlapped);
- assert(r || GetLastError() == ERROR_NOT_FOUND);
-
- } else {
- /* Cancel synchronous read (which is happening in the thread pool). */
- HANDLE thread;
- volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle;
-
- EnterCriticalSection(&handle->pipe.conn.readfile_thread_lock);
-
- thread = *thread_ptr;
- if (thread == NULL) {
- /* The thread pool thread has not yet reached the point of blocking, we
- * can pre-empt it by setting thread_handle to INVALID_HANDLE_VALUE. */
- *thread_ptr = INVALID_HANDLE_VALUE;
-
- } else {
- /* Spin until the thread has acknowledged (by setting the thread to
- * INVALID_HANDLE_VALUE) that it is past the point of blocking. */
- while (thread != INVALID_HANDLE_VALUE) {
- r = CancelSynchronousIo(thread);
- assert(r || GetLastError() == ERROR_NOT_FOUND);
- SwitchToThread(); /* Yield thread. */
- thread = *thread_ptr;
- }
- }
-
- LeaveCriticalSection(&handle->pipe.conn.readfile_thread_lock);
- }
-
- /* Set flag to indicate that read has been cancelled. */
- handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
-}
-
-
-void uv__pipe_read_stop(uv_pipe_t* handle) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(handle->loop, handle);
-
- uv__pipe_interrupt_read(handle);
-}
-
-
-/* Cleans up uv_pipe_t (server or connection) and all resources associated with
- * it. */
-void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
- int i;
- HANDLE pipeHandle;
-
- uv__pipe_interrupt_read(handle);
-
- if (handle->name) {
- uv__free(handle->name);
- handle->name = NULL;
- }
-
- if (handle->flags & UV_HANDLE_PIPESERVER) {
- for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
- pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
- if (pipeHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(pipeHandle);
- handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
- }
- }
- handle->handle = INVALID_HANDLE_VALUE;
- }
-
- if (handle->flags & UV_HANDLE_CONNECTION) {
- handle->flags &= ~UV_HANDLE_WRITABLE;
- eof_timer_destroy(handle);
- }
-
- if ((handle->flags & UV_HANDLE_CONNECTION)
- && handle->handle != INVALID_HANDLE_VALUE)
- close_pipe(handle);
-}
-
-
-void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
- if (handle->flags & UV_HANDLE_READING) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- }
-
- if (handle->flags & UV_HANDLE_LISTENING) {
- handle->flags &= ~UV_HANDLE_LISTENING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- }
-
- uv_pipe_cleanup(loop, handle);
-
- if (handle->reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-
- handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- uv__handle_closing(handle);
-}
-
-
-static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
- uv_pipe_accept_t* req, BOOL firstInstance) {
- assert(handle->flags & UV_HANDLE_LISTENING);
-
- if (!firstInstance) {
- assert(req->pipeHandle == INVALID_HANDLE_VALUE);
-
- req->pipeHandle = CreateNamedPipeW(handle->name,
- PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | WRITE_DAC,
- PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
- PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
-
- if (req->pipeHandle == INVALID_HANDLE_VALUE) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*) req);
- handle->reqs_pending++;
- return;
- }
-
- if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
- CloseHandle(req->pipeHandle);
- req->pipeHandle = INVALID_HANDLE_VALUE;
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*) req);
- handle->reqs_pending++;
- return;
- }
- }
-
- assert(req->pipeHandle != INVALID_HANDLE_VALUE);
-
- /* Prepare the overlapped structure. */
- memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
-
- if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
- GetLastError() != ERROR_IO_PENDING) {
- if (GetLastError() == ERROR_PIPE_CONNECTED) {
- SET_REQ_SUCCESS(req);
- } else {
- CloseHandle(req->pipeHandle);
- req->pipeHandle = INVALID_HANDLE_VALUE;
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, GetLastError());
- }
- uv_insert_pending_req(loop, (uv_req_t*) req);
- handle->reqs_pending++;
- return;
- }
-
- /* Wait for completion via IOCP */
- handle->reqs_pending++;
-}
-
-
-int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
- uv_loop_t* loop = server->loop;
- uv_pipe_t* pipe_client;
- uv_pipe_accept_t* req;
- QUEUE* q;
- uv__ipc_xfer_queue_item_t* item;
- int err;
-
- if (server->ipc) {
- if (QUEUE_EMPTY(&server->pipe.conn.ipc_xfer_queue)) {
- /* No valid pending sockets. */
- return WSAEWOULDBLOCK;
- }
-
- q = QUEUE_HEAD(&server->pipe.conn.ipc_xfer_queue);
- QUEUE_REMOVE(q);
- server->pipe.conn.ipc_xfer_queue_length--;
- item = QUEUE_DATA(q, uv__ipc_xfer_queue_item_t, member);
-
- err = uv__tcp_xfer_import(
- (uv_tcp_t*) client, item->xfer_type, &item->xfer_info);
- if (err != 0)
- return err;
-
- uv__free(item);
-
- } else {
- pipe_client = (uv_pipe_t*)client;
-
- /* Find a connection instance that has been connected, but not yet
- * accepted. */
- req = server->pipe.serv.pending_accepts;
-
- if (!req) {
- /* No valid connections found, so we error out. */
- return WSAEWOULDBLOCK;
- }
-
- /* Initialize the client handle and copy the pipeHandle to the client */
- uv_pipe_connection_init(pipe_client);
- pipe_client->handle = req->pipeHandle;
- pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
-
- /* Prepare the req to pick up a new connection */
- server->pipe.serv.pending_accepts = req->next_pending;
- req->next_pending = NULL;
- req->pipeHandle = INVALID_HANDLE_VALUE;
-
- if (!(server->flags & UV_HANDLE_CLOSING)) {
- uv_pipe_queue_accept(loop, server, req, FALSE);
- }
- }
-
- return 0;
-}
-
-
-/* Starts listening for connections for the given pipe. */
-int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
- uv_loop_t* loop = handle->loop;
- int i;
-
- if (handle->flags & UV_HANDLE_LISTENING) {
- handle->stream.serv.connection_cb = cb;
- }
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- return WSAEINVAL;
- }
-
- if (handle->flags & UV_HANDLE_READING) {
- return WSAEISCONN;
- }
-
- if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
- return ERROR_NOT_SUPPORTED;
- }
-
- handle->flags |= UV_HANDLE_LISTENING;
- INCREASE_ACTIVE_COUNT(loop, handle);
- handle->stream.serv.connection_cb = cb;
-
- /* First pipe handle should have already been created in uv_pipe_bind */
- assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
-
- for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
- uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
- }
-
- return 0;
-}
-
-
-static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* arg) {
- uv_read_t* req = (uv_read_t*) arg;
- uv_pipe_t* handle = (uv_pipe_t*) req->data;
- uv_loop_t* loop = handle->loop;
- volatile HANDLE* thread_ptr = &handle->pipe.conn.readfile_thread_handle;
- CRITICAL_SECTION* lock = &handle->pipe.conn.readfile_thread_lock;
- HANDLE thread;
- DWORD bytes;
- DWORD err;
-
- assert(req->type == UV_READ);
- assert(handle->type == UV_NAMED_PIPE);
-
- err = 0;
-
- /* Create a handle to the current thread. */
- if (!DuplicateHandle(GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
- &thread,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS)) {
- err = GetLastError();
- goto out1;
- }
-
- /* The lock needs to be held when thread handle is modified. */
- EnterCriticalSection(lock);
- if (*thread_ptr == INVALID_HANDLE_VALUE) {
- /* uv__pipe_interrupt_read() cancelled reading before we got here. */
- err = ERROR_OPERATION_ABORTED;
- } else {
- /* Let main thread know which worker thread is doing the blocking read. */
- assert(*thread_ptr == NULL);
- *thread_ptr = thread;
- }
- LeaveCriticalSection(lock);
-
- if (err)
- goto out2;
-
- /* Block the thread until data is available on the pipe, or the read is
- * cancelled. */
- if (!ReadFile(handle->handle, &uv_zero_, 0, &bytes, NULL))
- err = GetLastError();
-
- /* Let the main thread know the worker is past the point of blocking. */
- assert(thread == *thread_ptr);
- *thread_ptr = INVALID_HANDLE_VALUE;
-
- /* Briefly acquire the mutex. Since the main thread holds the lock while it
- * is spinning trying to cancel this thread's I/O, we will block here until
- * it stops doing that. */
- EnterCriticalSection(lock);
- LeaveCriticalSection(lock);
-
-out2:
- /* Close the handle to the current thread. */
- CloseHandle(thread);
-
-out1:
- /* Set request status and post a completion record to the IOCP. */
- if (err)
- SET_REQ_ERROR(req, err);
- else
- SET_REQ_SUCCESS(req);
- POST_COMPLETION_FOR_REQ(loop, req);
-
- return 0;
-}
-
-
-static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
- int result;
- DWORD bytes;
- uv_write_t* req = (uv_write_t*) parameter;
- uv_pipe_t* handle = (uv_pipe_t*) req->handle;
- uv_loop_t* loop = handle->loop;
-
- assert(req != NULL);
- assert(req->type == UV_WRITE);
- assert(handle->type == UV_NAMED_PIPE);
- assert(req->write_buffer.base);
-
- result = WriteFile(handle->handle,
- req->write_buffer.base,
- req->write_buffer.len,
- &bytes,
- NULL);
-
- if (!result) {
- SET_REQ_ERROR(req, GetLastError());
- }
-
- POST_COMPLETION_FOR_REQ(loop, req);
- return 0;
-}
-
-
-static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
- uv_read_t* req;
- uv_tcp_t* handle;
-
- req = (uv_read_t*) context;
- assert(req != NULL);
- handle = (uv_tcp_t*)req->data;
- assert(handle != NULL);
- assert(!timed_out);
-
- if (!PostQueuedCompletionStatus(handle->loop->iocp,
- req->u.io.overlapped.InternalHigh,
- 0,
- &req->u.io.overlapped)) {
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
- }
-}
-
-
-static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
- uv_write_t* req;
- uv_tcp_t* handle;
-
- req = (uv_write_t*) context;
- assert(req != NULL);
- handle = (uv_tcp_t*)req->handle;
- assert(handle != NULL);
- assert(!timed_out);
-
- if (!PostQueuedCompletionStatus(handle->loop->iocp,
- req->u.io.overlapped.InternalHigh,
- 0,
- &req->u.io.overlapped)) {
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
- }
-}
-
-
-static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
- uv_read_t* req;
- int result;
-
- assert(handle->flags & UV_HANDLE_READING);
- assert(!(handle->flags & UV_HANDLE_READ_PENDING));
-
- assert(handle->handle != INVALID_HANDLE_VALUE);
-
- req = &handle->read_req;
-
- if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
- handle->pipe.conn.readfile_thread_handle = NULL; /* Reset cancellation. */
- if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION)) {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, GetLastError());
- goto error;
- }
- } else {
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
- }
-
- /* Do 0-read */
- result = ReadFile(handle->handle,
- &uv_zero_,
- 0,
- NULL,
- &req->u.io.overlapped);
-
- if (!result && GetLastError() != ERROR_IO_PENDING) {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, GetLastError());
- goto error;
- }
-
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- if (!req->event_handle) {
- req->event_handle = CreateEvent(NULL, 0, 0, NULL);
- if (!req->event_handle) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
- }
- if (req->wait_handle == INVALID_HANDLE_VALUE) {
- if (!RegisterWaitForSingleObject(&req->wait_handle,
- req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
- INFINITE, WT_EXECUTEINWAITTHREAD)) {
- SET_REQ_ERROR(req, GetLastError());
- goto error;
- }
- }
- }
- }
-
- /* Start the eof timer if there is one */
- eof_timer_start(handle);
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
- return;
-
-error:
- uv_insert_pending_req(loop, (uv_req_t*)req);
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
-}
-
-
-int uv_pipe_read_start(uv_pipe_t* handle,
- uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
- uv_loop_t* loop = handle->loop;
-
- handle->flags |= UV_HANDLE_READING;
- INCREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb = read_cb;
- handle->alloc_cb = alloc_cb;
-
- /* If reading was stopped and then started again, there could still be a read
- * request pending. */
- if (!(handle->flags & UV_HANDLE_READ_PENDING))
- uv_pipe_queue_read(loop, handle);
-
- return 0;
-}
-
-
-static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
- uv_write_t* req) {
- req->next_req = NULL;
- if (handle->pipe.conn.non_overlapped_writes_tail) {
- req->next_req =
- handle->pipe.conn.non_overlapped_writes_tail->next_req;
- handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
- handle->pipe.conn.non_overlapped_writes_tail = req;
- } else {
- req->next_req = (uv_req_t*)req;
- handle->pipe.conn.non_overlapped_writes_tail = req;
- }
-}
-
-
-static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
- uv_write_t* req;
-
- if (handle->pipe.conn.non_overlapped_writes_tail) {
- req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
-
- if (req == handle->pipe.conn.non_overlapped_writes_tail) {
- handle->pipe.conn.non_overlapped_writes_tail = NULL;
- } else {
- handle->pipe.conn.non_overlapped_writes_tail->next_req =
- req->next_req;
- }
-
- return req;
- } else {
- /* queue empty */
- return NULL;
- }
-}
-
-
-static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
- uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
- if (req) {
- if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
- req,
- WT_EXECUTELONGFUNCTION)) {
- uv_fatal_error(GetLastError(), "QueueUserWorkItem");
- }
- }
-}
-
-
-static int uv__build_coalesced_write_req(uv_write_t* user_req,
- const uv_buf_t bufs[],
- size_t nbufs,
- uv_write_t** req_out,
- uv_buf_t* write_buf_out) {
- /* Pack into a single heap-allocated buffer:
- * (a) a uv_write_t structure where libuv stores the actual state.
- * (b) a pointer to the original uv_write_t.
- * (c) data from all `bufs` entries.
- */
- char* heap_buffer;
- size_t heap_buffer_length, heap_buffer_offset;
- uv__coalesced_write_t* coalesced_write_req; /* (a) + (b) */
- char* data_start; /* (c) */
- size_t data_length;
- unsigned int i;
-
- /* Compute combined size of all combined buffers from `bufs`. */
- data_length = 0;
- for (i = 0; i < nbufs; i++)
- data_length += bufs[i].len;
-
- /* The total combined size of data buffers should not exceed UINT32_MAX,
- * because WriteFile() won't accept buffers larger than that. */
- if (data_length > UINT32_MAX)
- return WSAENOBUFS; /* Maps to UV_ENOBUFS. */
-
- /* Compute heap buffer size. */
- heap_buffer_length = sizeof *coalesced_write_req + /* (a) + (b) */
- data_length; /* (c) */
-
- /* Allocate buffer. */
- heap_buffer = (char*)uv__malloc(heap_buffer_length);
- if (heap_buffer == NULL)
- return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */
-
- /* Copy uv_write_t information to the buffer. */
- coalesced_write_req = (uv__coalesced_write_t*) heap_buffer;
- coalesced_write_req->req = *user_req; /* copy (a) */
- coalesced_write_req->req.coalesced = 1;
- coalesced_write_req->user_req = user_req; /* copy (b) */
- heap_buffer_offset = sizeof *coalesced_write_req; /* offset (a) + (b) */
-
- /* Copy data buffers to the heap buffer. */
- data_start = &heap_buffer[heap_buffer_offset];
- for (i = 0; i < nbufs; i++) {
- memcpy(&heap_buffer[heap_buffer_offset],
- bufs[i].base,
- bufs[i].len); /* copy (c) */
- heap_buffer_offset += bufs[i].len; /* offset (c) */
- }
- assert(heap_buffer_offset == heap_buffer_length);
-
- /* Set out arguments and return. */
- *req_out = &coalesced_write_req->req;
- *write_buf_out = uv_buf_init(data_start, (unsigned int) data_length);
- return 0;
-}
-
-
-static int uv__pipe_write_data(uv_loop_t* loop,
- uv_write_t* req,
- uv_pipe_t* handle,
- const uv_buf_t bufs[],
- size_t nbufs,
- uv_write_cb cb,
- int copy_always) {
- int err;
- int result;
- uv_buf_t write_buf;
-
- assert(handle->handle != INVALID_HANDLE_VALUE);
-
- UV_REQ_INIT(req, UV_WRITE);
- req->handle = (uv_stream_t*) handle;
- req->send_handle = NULL;
- req->cb = cb;
- /* Private fields. */
- req->coalesced = 0;
- req->event_handle = NULL;
- req->wait_handle = INVALID_HANDLE_VALUE;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
- req->write_buffer = uv_null_buf_;
-
- if (nbufs == 0) {
- /* Write empty buffer. */
- write_buf = uv_null_buf_;
- } else if (nbufs == 1 && !copy_always) {
- /* Write directly from bufs[0]. */
- write_buf = bufs[0];
- } else {
- /* Coalesce all `bufs` into one big buffer. This also creates a new
- * write-request structure that replaces the old one. */
- err = uv__build_coalesced_write_req(req, bufs, nbufs, &req, &write_buf);
- if (err != 0)
- return err;
- }
-
- if ((handle->flags &
- (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) ==
- (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) {
- DWORD bytes;
- result =
- WriteFile(handle->handle, write_buf.base, write_buf.len, &bytes, NULL);
-
- if (!result) {
- err = GetLastError();
- return err;
- } else {
- /* Request completed immediately. */
- req->u.io.queued_bytes = 0;
- }
-
- REGISTER_HANDLE_REQ(loop, handle, req);
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- POST_COMPLETION_FOR_REQ(loop, req);
- return 0;
- } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
- req->write_buffer = write_buf;
- uv_insert_non_overlapped_write_req(handle, req);
- if (handle->stream.conn.write_reqs_pending == 0) {
- uv_queue_non_overlapped_write(handle);
- }
-
- /* Request queued by the kernel. */
- req->u.io.queued_bytes = write_buf.len;
- handle->write_queue_size += req->u.io.queued_bytes;
- } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
- /* Using overlapped IO, but wait for completion before returning */
- req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
- if (!req->u.io.overlapped.hEvent) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
-
- result = WriteFile(handle->handle,
- write_buf.base,
- write_buf.len,
- NULL,
- &req->u.io.overlapped);
-
- if (!result && GetLastError() != ERROR_IO_PENDING) {
- err = GetLastError();
- CloseHandle(req->u.io.overlapped.hEvent);
- return err;
- }
-
- if (result) {
- /* Request completed immediately. */
- req->u.io.queued_bytes = 0;
- } else {
- /* Request queued by the kernel. */
- req->u.io.queued_bytes = write_buf.len;
- handle->write_queue_size += req->u.io.queued_bytes;
- if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
- WAIT_OBJECT_0) {
- err = GetLastError();
- CloseHandle(req->u.io.overlapped.hEvent);
- return err;
- }
- }
- CloseHandle(req->u.io.overlapped.hEvent);
-
- REGISTER_HANDLE_REQ(loop, handle, req);
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- return 0;
- } else {
- result = WriteFile(handle->handle,
- write_buf.base,
- write_buf.len,
- NULL,
- &req->u.io.overlapped);
-
- if (!result && GetLastError() != ERROR_IO_PENDING) {
- return GetLastError();
- }
-
- if (result) {
- /* Request completed immediately. */
- req->u.io.queued_bytes = 0;
- } else {
- /* Request queued by the kernel. */
- req->u.io.queued_bytes = write_buf.len;
- handle->write_queue_size += req->u.io.queued_bytes;
- }
-
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- req->event_handle = CreateEvent(NULL, 0, 0, NULL);
- if (!req->event_handle) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
- if (!RegisterWaitForSingleObject(&req->wait_handle,
- req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
- INFINITE, WT_EXECUTEINWAITTHREAD)) {
- return GetLastError();
- }
- }
- }
-
- REGISTER_HANDLE_REQ(loop, handle, req);
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
-
- return 0;
-}
-
-
-static DWORD uv__pipe_get_ipc_remote_pid(uv_pipe_t* handle) {
- DWORD* pid = &handle->pipe.conn.ipc_remote_pid;
-
- /* If the both ends of the IPC pipe are owned by the same process,
- * the remote end pid may not yet be set. If so, do it here.
- * TODO: this is weird; it'd probably better to use a handshake. */
- if (*pid == 0)
- *pid = GetCurrentProcessId();
-
- return *pid;
-}
-
-
-int uv__pipe_write_ipc(uv_loop_t* loop,
- uv_write_t* req,
- uv_pipe_t* handle,
- const uv_buf_t data_bufs[],
- size_t data_buf_count,
- uv_stream_t* send_handle,
- uv_write_cb cb) {
- uv_buf_t stack_bufs[6];
- uv_buf_t* bufs;
- size_t buf_count, buf_index;
- uv__ipc_frame_header_t frame_header;
- uv__ipc_socket_xfer_type_t xfer_type = UV__IPC_SOCKET_XFER_NONE;
- uv__ipc_socket_xfer_info_t xfer_info;
- uint64_t data_length;
- size_t i;
- int err;
-
- /* Compute the combined size of data buffers. */
- data_length = 0;
- for (i = 0; i < data_buf_count; i++)
- data_length += data_bufs[i].len;
- if (data_length > UINT32_MAX)
- return WSAENOBUFS; /* Maps to UV_ENOBUFS. */
-
- /* Prepare the frame's socket xfer payload. */
- if (send_handle != NULL) {
- uv_tcp_t* send_tcp_handle = (uv_tcp_t*) send_handle;
-
- /* Verify that `send_handle` it is indeed a tcp handle. */
- if (send_tcp_handle->type != UV_TCP)
- return ERROR_NOT_SUPPORTED;
-
- /* Export the tcp handle. */
- err = uv__tcp_xfer_export(send_tcp_handle,
- uv__pipe_get_ipc_remote_pid(handle),
- &xfer_type,
- &xfer_info);
- if (err != 0)
- return err;
- }
-
- /* Compute the number of uv_buf_t's required. */
- buf_count = 1 + data_buf_count; /* Frame header and data buffers. */
- if (send_handle != NULL)
- buf_count += 1; /* One extra for the socket xfer information. */
-
- /* Use the on-stack buffer array if it is big enough; otherwise allocate
- * space for it on the heap. */
- if (buf_count < ARRAY_SIZE(stack_bufs)) {
- /* Use on-stack buffer array. */
- bufs = stack_bufs;
- } else {
- /* Use heap-allocated buffer array. */
- bufs = (uv_buf_t*)uv__calloc(buf_count, sizeof(uv_buf_t));
- if (bufs == NULL)
- return ERROR_NOT_ENOUGH_MEMORY; /* Maps to UV_ENOMEM. */
- }
- buf_index = 0;
-
- /* Initialize frame header and add it to the buffers list. */
- memset(&frame_header, 0, sizeof frame_header);
- bufs[buf_index++] = uv_buf_init((char*) &frame_header, sizeof frame_header);
-
- if (send_handle != NULL) {
- /* Add frame header flags. */
- switch (xfer_type) {
- case UV__IPC_SOCKET_XFER_TCP_CONNECTION:
- frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER |
- UV__IPC_FRAME_XFER_IS_TCP_CONNECTION;
- break;
- case UV__IPC_SOCKET_XFER_TCP_SERVER:
- frame_header.flags |= UV__IPC_FRAME_HAS_SOCKET_XFER;
- break;
- default:
- assert(0); /* Unreachable. */
- }
- /* Add xfer info buffer. */
- bufs[buf_index++] = uv_buf_init((char*) &xfer_info, sizeof xfer_info);
- }
-
- if (data_length > 0) {
- /* Update frame header. */
- frame_header.flags |= UV__IPC_FRAME_HAS_DATA;
- frame_header.data_length = (uint32_t) data_length;
- /* Add data buffers to buffers list. */
- for (i = 0; i < data_buf_count; i++)
- bufs[buf_index++] = data_bufs[i];
- }
-
- /* Write buffers. We set the `always_copy` flag, so it is not a problem that
- * some of the written data lives on the stack. */
- err = uv__pipe_write_data(loop, req, handle, bufs, buf_count, cb, 1);
-
- /* If we had to heap-allocate the bufs array, free it now. */
- if (bufs != stack_bufs) {
- uv__free(bufs);
- }
-
- return err;
-}
-
-
-int uv__pipe_write(uv_loop_t* loop,
- uv_write_t* req,
- uv_pipe_t* handle,
- const uv_buf_t bufs[],
- size_t nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb) {
- if (handle->ipc) {
- /* IPC pipe write: use framing protocol. */
- return uv__pipe_write_ipc(loop, req, handle, bufs, nbufs, send_handle, cb);
- } else {
- /* Non-IPC pipe write: put data on the wire directly. */
- assert(send_handle == NULL);
- return uv__pipe_write_data(loop, req, handle, bufs, nbufs, cb, 0);
- }
-}
-
-
-static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
- uv_buf_t buf) {
- /* If there is an eof timer running, we don't need it any more, so discard
- * it. */
- eof_timer_destroy(handle);
-
- handle->flags &= ~UV_HANDLE_READABLE;
- uv_read_stop((uv_stream_t*) handle);
-
- handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
-}
-
-
-static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
- uv_buf_t buf) {
- /* If there is an eof timer running, we don't need it any more, so discard
- * it. */
- eof_timer_destroy(handle);
-
- uv_read_stop((uv_stream_t*) handle);
-
- handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
-}
-
-
-static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
- int error, uv_buf_t buf) {
- if (error == ERROR_BROKEN_PIPE) {
- uv_pipe_read_eof(loop, handle, buf);
- } else {
- uv_pipe_read_error(loop, handle, error, buf);
- }
-}
-
-
-static void uv__pipe_queue_ipc_xfer_info(
- uv_pipe_t* handle,
- uv__ipc_socket_xfer_type_t xfer_type,
- uv__ipc_socket_xfer_info_t* xfer_info) {
- uv__ipc_xfer_queue_item_t* item;
-
- item = (uv__ipc_xfer_queue_item_t*) uv__malloc(sizeof(*item));
- if (item == NULL)
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
-
- item->xfer_type = xfer_type;
- item->xfer_info = *xfer_info;
-
- QUEUE_INSERT_TAIL(&handle->pipe.conn.ipc_xfer_queue, &item->member);
- handle->pipe.conn.ipc_xfer_queue_length++;
-}
-
-
-/* Read an exact number of bytes from a pipe. If an error or end-of-file is
- * encountered before the requested number of bytes are read, an error is
- * returned. */
-static int uv__pipe_read_exactly(HANDLE h, void* buffer, DWORD count) {
- DWORD bytes_read, bytes_read_now;
-
- bytes_read = 0;
- while (bytes_read < count) {
- if (!ReadFile(h,
- (char*) buffer + bytes_read,
- count - bytes_read,
- &bytes_read_now,
- NULL)) {
- return GetLastError();
- }
-
- bytes_read += bytes_read_now;
- }
-
- assert(bytes_read == count);
- return 0;
-}
-
-
-static DWORD uv__pipe_read_data(uv_loop_t* loop,
- uv_pipe_t* handle,
- DWORD suggested_bytes,
- DWORD max_bytes) {
- DWORD bytes_read;
- uv_buf_t buf;
-
- /* Ask the user for a buffer to read data into. */
- buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, suggested_bytes, &buf);
- if (buf.base == NULL || buf.len == 0) {
- handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
- return 0; /* Break out of read loop. */
- }
-
- /* Ensure we read at most the smaller of:
- * (a) the length of the user-allocated buffer.
- * (b) the maximum data length as specified by the `max_bytes` argument.
- */
- if (max_bytes > buf.len)
- max_bytes = buf.len;
-
- /* Read into the user buffer. */
- if (!ReadFile(handle->handle, buf.base, max_bytes, &bytes_read, NULL)) {
- uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
- return 0; /* Break out of read loop. */
- }
-
- /* Call the read callback. */
- handle->read_cb((uv_stream_t*) handle, bytes_read, &buf);
-
- return bytes_read;
-}
-
-
-static DWORD uv__pipe_read_ipc(uv_loop_t* loop, uv_pipe_t* handle) {
- uint32_t* data_remaining = &handle->pipe.conn.ipc_data_frame.payload_remaining;
- int err;
-
- if (*data_remaining > 0) {
- /* Read frame data payload. */
- DWORD bytes_read =
- uv__pipe_read_data(loop, handle, *data_remaining, *data_remaining);
- *data_remaining -= bytes_read;
- return bytes_read;
-
- } else {
- /* Start of a new IPC frame. */
- uv__ipc_frame_header_t frame_header;
- uint32_t xfer_flags;
- uv__ipc_socket_xfer_type_t xfer_type;
- uv__ipc_socket_xfer_info_t xfer_info;
-
- /* Read the IPC frame header. */
- err = uv__pipe_read_exactly(
- handle->handle, &frame_header, sizeof frame_header);
- if (err)
- goto error;
-
- /* Validate that flags are valid. */
- if ((frame_header.flags & ~UV__IPC_FRAME_VALID_FLAGS) != 0)
- goto invalid;
- /* Validate that reserved2 is zero. */
- if (frame_header.reserved2 != 0)
- goto invalid;
-
- /* Parse xfer flags. */
- xfer_flags = frame_header.flags & UV__IPC_FRAME_XFER_FLAGS;
- if (xfer_flags & UV__IPC_FRAME_HAS_SOCKET_XFER) {
- /* Socket coming -- determine the type. */
- xfer_type = xfer_flags & UV__IPC_FRAME_XFER_IS_TCP_CONNECTION
- ? UV__IPC_SOCKET_XFER_TCP_CONNECTION
- : UV__IPC_SOCKET_XFER_TCP_SERVER;
- } else if (xfer_flags == 0) {
- /* No socket. */
- xfer_type = UV__IPC_SOCKET_XFER_NONE;
- } else {
- /* Invalid flags. */
- goto invalid;
- }
-
- /* Parse data frame information. */
- if (frame_header.flags & UV__IPC_FRAME_HAS_DATA) {
- *data_remaining = frame_header.data_length;
- } else if (frame_header.data_length != 0) {
- /* Data length greater than zero but data flag not set -- invalid. */
- goto invalid;
- }
-
- /* If no socket xfer info follows, return here. Data will be read in a
- * subsequent invocation of uv__pipe_read_ipc(). */
- if (xfer_type == UV__IPC_SOCKET_XFER_NONE)
- return sizeof frame_header; /* Number of bytes read. */
-
- /* Read transferred socket information. */
- err = uv__pipe_read_exactly(handle->handle, &xfer_info, sizeof xfer_info);
- if (err)
- goto error;
-
- /* Store the pending socket info. */
- uv__pipe_queue_ipc_xfer_info(handle, xfer_type, &xfer_info);
-
- /* Return number of bytes read. */
- return sizeof frame_header + sizeof xfer_info;
- }
-
-invalid:
- /* Invalid frame. */
- err = WSAECONNABORTED; /* Maps to UV_ECONNABORTED. */
-
-error:
- uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
- return 0; /* Break out of read loop. */
-}
-
-
-void uv_process_pipe_read_req(uv_loop_t* loop,
- uv_pipe_t* handle,
- uv_req_t* req) {
- assert(handle->type == UV_NAMED_PIPE);
-
- handle->flags &= ~(UV_HANDLE_READ_PENDING | UV_HANDLE_CANCELLATION_PENDING);
- DECREASE_PENDING_REQ_COUNT(handle);
- eof_timer_stop(handle);
-
- /* At this point, we're done with bookkeeping. If the user has stopped
- * reading the pipe in the meantime, there is nothing left to do, since there
- * is no callback that we can call. */
- if (!(handle->flags & UV_HANDLE_READING))
- return;
-
- if (!REQ_SUCCESS(req)) {
- /* An error occurred doing the zero-read. */
- DWORD err = GET_REQ_ERROR(req);
-
- /* If the read was cancelled by uv__pipe_interrupt_read(), the request may
- * indicate an ERROR_OPERATION_ABORTED error. This error isn't relevant to
- * the user; we'll start a new zero-read at the end of this function. */
- if (err != ERROR_OPERATION_ABORTED)
- uv_pipe_read_error_or_eof(loop, handle, err, uv_null_buf_);
-
- } else {
- /* The zero-read completed without error, indicating there is data
- * available in the kernel buffer. */
- DWORD avail;
-
- /* Get the number of bytes available. */
- avail = 0;
- if (!PeekNamedPipe(handle->handle, NULL, 0, NULL, &avail, NULL))
- uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
-
- /* Read until we've either read all the bytes available, or the 'reading'
- * flag is cleared. */
- while (avail > 0 && handle->flags & UV_HANDLE_READING) {
- /* Depending on the type of pipe, read either IPC frames or raw data. */
- DWORD bytes_read =
- handle->ipc ? uv__pipe_read_ipc(loop, handle)
- : uv__pipe_read_data(loop, handle, avail, (DWORD) -1);
-
- /* If no bytes were read, treat this as an indication that an error
- * occurred, and break out of the read loop. */
- if (bytes_read == 0)
- break;
-
- /* It is possible that more bytes were read than we thought were
- * available. To prevent `avail` from underflowing, break out of the loop
- * if this is the case. */
- if (bytes_read > avail)
- break;
-
- /* Recompute the number of bytes available. */
- avail -= bytes_read;
- }
- }
-
- /* Start another zero-read request if necessary. */
- if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_READ_PENDING)) {
- uv_pipe_queue_read(loop, handle);
- }
-}
-
-
-void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_write_t* req) {
- int err;
-
- assert(handle->type == UV_NAMED_PIPE);
-
- assert(handle->write_queue_size >= req->u.io.queued_bytes);
- handle->write_queue_size -= req->u.io.queued_bytes;
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- if (req->wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(req->wait_handle);
- req->wait_handle = INVALID_HANDLE_VALUE;
- }
- if (req->event_handle) {
- CloseHandle(req->event_handle);
- req->event_handle = NULL;
- }
- }
-
- err = GET_REQ_ERROR(req);
-
- /* If this was a coalesced write, extract pointer to the user_provided
- * uv_write_t structure so we can pass the expected pointer to the callback,
- * then free the heap-allocated write req. */
- if (req->coalesced) {
- uv__coalesced_write_t* coalesced_write =
- container_of(req, uv__coalesced_write_t, req);
- req = coalesced_write->user_req;
- uv__free(coalesced_write);
- }
- if (req->cb) {
- req->cb(req, uv_translate_sys_error(err));
- }
-
- handle->stream.conn.write_reqs_pending--;
-
- if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
- handle->pipe.conn.non_overlapped_writes_tail) {
- assert(handle->stream.conn.write_reqs_pending > 0);
- uv_queue_non_overlapped_write(handle);
- }
-
- if (handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_req_t* raw_req) {
- uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
-
- assert(handle->type == UV_NAMED_PIPE);
-
- if (handle->flags & UV_HANDLE_CLOSING) {
- /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
- assert(req->pipeHandle == INVALID_HANDLE_VALUE);
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
-
- if (REQ_SUCCESS(req)) {
- assert(req->pipeHandle != INVALID_HANDLE_VALUE);
- req->next_pending = handle->pipe.serv.pending_accepts;
- handle->pipe.serv.pending_accepts = req;
-
- if (handle->stream.serv.connection_cb) {
- handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
- }
- } else {
- if (req->pipeHandle != INVALID_HANDLE_VALUE) {
- CloseHandle(req->pipeHandle);
- req->pipeHandle = INVALID_HANDLE_VALUE;
- }
- if (!(handle->flags & UV_HANDLE_CLOSING)) {
- uv_pipe_queue_accept(loop, handle, req, FALSE);
- }
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_connect_t* req) {
- int err;
-
- assert(handle->type == UV_NAMED_PIPE);
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (req->cb) {
- err = 0;
- if (REQ_SUCCESS(req)) {
- uv_pipe_connection_init(handle);
- } else {
- err = GET_REQ_ERROR(req);
- }
- req->cb(req, uv_translate_sys_error(err));
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
- uv_shutdown_t* req) {
- assert(handle->type == UV_NAMED_PIPE);
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (handle->flags & UV_HANDLE_READABLE) {
- /* Initialize and optionally start the eof timer. Only do this if the pipe
- * is readable and we haven't seen EOF come in ourselves. */
- eof_timer_init(handle);
-
- /* If reading start the timer right now. Otherwise uv_pipe_queue_read will
- * start it. */
- if (handle->flags & UV_HANDLE_READ_PENDING) {
- eof_timer_start(handle);
- }
-
- } else {
- /* This pipe is not readable. We can just close it to let the other end
- * know that we're done writing. */
- close_pipe(handle);
- }
-
- if (req->cb) {
- req->cb(req, 0);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-static void eof_timer_init(uv_pipe_t* pipe) {
- int r;
-
- assert(pipe->pipe.conn.eof_timer == NULL);
- assert(pipe->flags & UV_HANDLE_CONNECTION);
-
- pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
-
- r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
- assert(r == 0); /* timers can't fail */
- pipe->pipe.conn.eof_timer->data = pipe;
- uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
-}
-
-
-static void eof_timer_start(uv_pipe_t* pipe) {
- assert(pipe->flags & UV_HANDLE_CONNECTION);
-
- if (pipe->pipe.conn.eof_timer != NULL) {
- uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
- }
-}
-
-
-static void eof_timer_stop(uv_pipe_t* pipe) {
- assert(pipe->flags & UV_HANDLE_CONNECTION);
-
- if (pipe->pipe.conn.eof_timer != NULL) {
- uv_timer_stop(pipe->pipe.conn.eof_timer);
- }
-}
-
-
-static void eof_timer_cb(uv_timer_t* timer) {
- uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
- uv_loop_t* loop = timer->loop;
-
- assert(pipe->type == UV_NAMED_PIPE);
-
- /* This should always be true, since we start the timer only in
- * uv_pipe_queue_read after successfully calling ReadFile, or in
- * uv_process_pipe_shutdown_req if a read is pending, and we always
- * immediately stop the timer in uv_process_pipe_read_req. */
- assert(pipe->flags & UV_HANDLE_READ_PENDING);
-
- /* If there are many packets coming off the iocp then the timer callback may
- * be called before the read request is coming off the queue. Therefore we
- * check here if the read request has completed but will be processed later.
- */
- if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
- HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
- return;
- }
-
- /* Force both ends off the pipe. */
- close_pipe(pipe);
-
- /* Stop reading, so the pending read that is going to fail will not be
- * reported to the user. */
- uv_read_stop((uv_stream_t*) pipe);
-
- /* Report the eof and update flags. This will get reported even if the user
- * stopped reading in the meantime. TODO: is that okay? */
- uv_pipe_read_eof(loop, pipe, uv_null_buf_);
-}
-
-
-static void eof_timer_destroy(uv_pipe_t* pipe) {
- assert(pipe->flags & UV_HANDLE_CONNECTION);
-
- if (pipe->pipe.conn.eof_timer) {
- uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
- pipe->pipe.conn.eof_timer = NULL;
- }
-}
-
-
-static void eof_timer_close_cb(uv_handle_t* handle) {
- assert(handle->type == UV_TIMER);
- uv__free(handle);
-}
-
-
-int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
- HANDLE os_handle = uv__get_osfhandle(file);
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
- FILE_ACCESS_INFORMATION access;
- DWORD duplex_flags = 0;
-
- if (os_handle == INVALID_HANDLE_VALUE)
- return UV_EBADF;
-
- uv__once_init();
- /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
- * underlying OS handle and forget about the original fd.
- * We could also opt to use the original OS handle and just never close it,
- * but then there would be no reliable way to cancel pending read operations
- * upon close.
- */
- if (file <= 2) {
- if (!DuplicateHandle(INVALID_HANDLE_VALUE,
- os_handle,
- INVALID_HANDLE_VALUE,
- &os_handle,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS))
- return uv_translate_sys_error(GetLastError());
- file = -1;
- }
-
- /* Determine what kind of permissions we have on this handle.
- * Cygwin opens the pipe in message mode, but we can support it,
- * just query the access flags and set the stream flags accordingly.
- */
- nt_status = pNtQueryInformationFile(os_handle,
- &io_status,
- &access,
- sizeof(access),
- FileAccessInformation);
- if (nt_status != STATUS_SUCCESS)
- return UV_EINVAL;
-
- if (pipe->ipc) {
- if (!(access.AccessFlags & FILE_WRITE_DATA) ||
- !(access.AccessFlags & FILE_READ_DATA)) {
- return UV_EINVAL;
- }
- }
-
- if (access.AccessFlags & FILE_WRITE_DATA)
- duplex_flags |= UV_HANDLE_WRITABLE;
- if (access.AccessFlags & FILE_READ_DATA)
- duplex_flags |= UV_HANDLE_READABLE;
-
- if (os_handle == INVALID_HANDLE_VALUE ||
- uv_set_pipe_handle(pipe->loop,
- pipe,
- os_handle,
- file,
- duplex_flags) == -1) {
- return UV_EINVAL;
- }
-
- uv_pipe_connection_init(pipe);
-
- if (pipe->ipc) {
- assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
- pipe->pipe.conn.ipc_remote_pid = uv_os_getppid();
- assert(pipe->pipe.conn.ipc_remote_pid != (DWORD) -1);
- }
- return 0;
-}
-
-
-static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
- NTSTATUS nt_status;
- IO_STATUS_BLOCK io_status;
- FILE_NAME_INFORMATION tmp_name_info;
- FILE_NAME_INFORMATION* name_info;
- WCHAR* name_buf;
- unsigned int addrlen;
- unsigned int name_size;
- unsigned int name_len;
- int err;
-
- uv__once_init();
- name_info = NULL;
-
- if (handle->handle == INVALID_HANDLE_VALUE) {
- *size = 0;
- return UV_EINVAL;
- }
-
- /* NtQueryInformationFile will block if another thread is performing a
- * blocking operation on the queried handle. If the pipe handle is
- * synchronous, there may be a worker thread currently calling ReadFile() on
- * the pipe handle, which could cause a deadlock. To avoid this, interrupt
- * the read. */
- if (handle->flags & UV_HANDLE_CONNECTION &&
- handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
- uv__pipe_interrupt_read((uv_pipe_t*) handle); /* cast away const warning */
- }
-
- nt_status = pNtQueryInformationFile(handle->handle,
- &io_status,
- &tmp_name_info,
- sizeof tmp_name_info,
- FileNameInformation);
- if (nt_status == STATUS_BUFFER_OVERFLOW) {
- name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
- name_info = (FILE_NAME_INFORMATION*)uv__malloc(name_size);
- if (!name_info) {
- *size = 0;
- err = UV_ENOMEM;
- goto cleanup;
- }
-
- nt_status = pNtQueryInformationFile(handle->handle,
- &io_status,
- name_info,
- name_size,
- FileNameInformation);
- }
-
- if (nt_status != STATUS_SUCCESS) {
- *size = 0;
- err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
- goto error;
- }
-
- if (!name_info) {
- /* the struct on stack was used */
- name_buf = tmp_name_info.FileName;
- name_len = tmp_name_info.FileNameLength;
- } else {
- name_buf = name_info->FileName;
- name_len = name_info->FileNameLength;
- }
-
- if (name_len == 0) {
- *size = 0;
- err = 0;
- goto error;
- }
-
- name_len /= sizeof(WCHAR);
-
- /* check how much space we need */
- addrlen = WideCharToMultiByte(CP_UTF8,
- 0,
- name_buf,
- name_len,
- NULL,
- 0,
- NULL,
- NULL);
- if (!addrlen) {
- *size = 0;
- err = uv_translate_sys_error(GetLastError());
- goto error;
- } else if (pipe_prefix_len + addrlen >= *size) {
- /* "\\\\.\\pipe" + name */
- *size = pipe_prefix_len + addrlen + 1;
- err = UV_ENOBUFS;
- goto error;
- }
-
- memcpy(buffer, pipe_prefix, pipe_prefix_len);
- addrlen = WideCharToMultiByte(CP_UTF8,
- 0,
- name_buf,
- name_len,
- buffer+pipe_prefix_len,
- *size-pipe_prefix_len,
- NULL,
- NULL);
- if (!addrlen) {
- *size = 0;
- err = uv_translate_sys_error(GetLastError());
- goto error;
- }
-
- addrlen += pipe_prefix_len;
- *size = addrlen;
- buffer[addrlen] = '\0';
-
- err = 0;
-
-error:
- uv__free(name_info);
-
-cleanup:
- return err;
-}
-
-
-int uv_pipe_pending_count(uv_pipe_t* handle) {
- if (!handle->ipc)
- return 0;
- return handle->pipe.conn.ipc_xfer_queue_length;
-}
-
-
-int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
- if (handle->flags & UV_HANDLE_BOUND)
- return uv__pipe_getname(handle, buffer, size);
-
- if (handle->flags & UV_HANDLE_CONNECTION ||
- handle->handle != INVALID_HANDLE_VALUE) {
- *size = 0;
- return 0;
- }
-
- return UV_EBADF;
-}
-
-
-int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
- /* emulate unix behaviour */
- if (handle->flags & UV_HANDLE_BOUND)
- return UV_ENOTCONN;
-
- if (handle->handle != INVALID_HANDLE_VALUE)
- return uv__pipe_getname(handle, buffer, size);
-
- return UV_EBADF;
-}
-
-
-uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
- if (!handle->ipc)
- return UV_UNKNOWN_HANDLE;
- if (handle->pipe.conn.ipc_xfer_queue_length == 0)
- return UV_UNKNOWN_HANDLE;
- else
- return UV_TCP;
-}
-
-int uv_pipe_chmod(uv_pipe_t* handle, int mode) {
- SID_IDENTIFIER_AUTHORITY sid_world = { SECURITY_WORLD_SID_AUTHORITY };
- PACL old_dacl, new_dacl;
- PSECURITY_DESCRIPTOR sd;
- EXPLICIT_ACCESS ea;
- PSID everyone;
- int error;
-
- if (handle == NULL || handle->handle == INVALID_HANDLE_VALUE)
- return UV_EBADF;
-
- if (mode != UV_READABLE &&
- mode != UV_WRITABLE &&
- mode != (UV_WRITABLE | UV_READABLE))
- return UV_EINVAL;
-
- if (!AllocateAndInitializeSid(&sid_world,
- 1,
- SECURITY_WORLD_RID,
- 0, 0, 0, 0, 0, 0, 0,
- &everyone)) {
- error = GetLastError();
- goto done;
- }
-
- if (GetSecurityInfo(handle->handle,
- SE_KERNEL_OBJECT,
- DACL_SECURITY_INFORMATION,
- NULL,
- NULL,
- &old_dacl,
- NULL,
- &sd)) {
- error = GetLastError();
- goto clean_sid;
- }
-
- memset(&ea, 0, sizeof(EXPLICIT_ACCESS));
- if (mode & UV_READABLE)
- ea.grfAccessPermissions |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
- if (mode & UV_WRITABLE)
- ea.grfAccessPermissions |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
- ea.grfAccessPermissions |= SYNCHRONIZE;
- ea.grfAccessMode = SET_ACCESS;
- ea.grfInheritance = NO_INHERITANCE;
- ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
- ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
- ea.Trustee.ptstrName = (LPTSTR)everyone;
-
- if (SetEntriesInAcl(1, &ea, old_dacl, &new_dacl)) {
- error = GetLastError();
- goto clean_sd;
- }
-
- if (SetSecurityInfo(handle->handle,
- SE_KERNEL_OBJECT,
- DACL_SECURITY_INFORMATION,
- NULL,
- NULL,
- new_dacl,
- NULL)) {
- error = GetLastError();
- goto clean_dacl;
- }
-
- error = 0;
-
-clean_dacl:
- LocalFree((HLOCAL) new_dacl);
-clean_sd:
- LocalFree((HLOCAL) sd);
-clean_sid:
- FreeSid(everyone);
-done:
- return uv_translate_sys_error(error);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/poll.cpp b/wpiutil/src/main/native/libuv/src/win/poll.cpp
deleted file mode 100644
index 3c66786..0000000
--- a/wpiutil/src/main/native/libuv/src/win/poll.cpp
+++ /dev/null
@@ -1,643 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <io.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
- {0xe70f1aa0, 0xab8b, 0x11cf,
- {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
- {0xf9eab0c0, 0x26d4, 0x11d0,
- {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
- {0x9fc48064, 0x7298, 0x43e4,
- {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
-};
-
-typedef struct uv_single_fd_set_s {
- unsigned int fd_count;
- SOCKET fd_array[1];
-} uv_single_fd_set_t;
-
-
-static OVERLAPPED overlapped_dummy_;
-static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
-
-static AFD_POLL_INFO afd_poll_info_dummy_;
-
-
-static void uv__init_overlapped_dummy(void) {
- HANDLE event;
-
- event = CreateEvent(NULL, TRUE, TRUE, NULL);
- if (event == NULL)
- uv_fatal_error(GetLastError(), "CreateEvent");
-
- memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
- overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
-}
-
-
-static OVERLAPPED* uv__get_overlapped_dummy(void) {
- uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
- return &overlapped_dummy_;
-}
-
-
-static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
- return &afd_poll_info_dummy_;
-}
-
-
-static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
- uv_req_t* req;
- AFD_POLL_INFO* afd_poll_info;
- int result;
-
- /* Find a yet unsubmitted req to submit. */
- if (handle->submitted_events_1 == 0) {
- req = &handle->poll_req_1;
- afd_poll_info = &handle->afd_poll_info_1;
- handle->submitted_events_1 = handle->events;
- handle->mask_events_1 = 0;
- handle->mask_events_2 = handle->events;
- } else if (handle->submitted_events_2 == 0) {
- req = &handle->poll_req_2;
- afd_poll_info = &handle->afd_poll_info_2;
- handle->submitted_events_2 = handle->events;
- handle->mask_events_1 = handle->events;
- handle->mask_events_2 = 0;
- } else {
- /* Just wait until there's an unsubmitted req. This will happen almost
- * immediately as one of the 2 outstanding requests is about to return.
- * When this happens, uv__fast_poll_process_poll_req will be called, and
- * the pending events, if needed, will be processed in a subsequent
- * request. */
- return;
- }
-
- /* Setting Exclusive to TRUE makes the other poll request return if there is
- * any. */
- afd_poll_info->Exclusive = TRUE;
- afd_poll_info->NumberOfHandles = 1;
- afd_poll_info->Timeout.QuadPart = INT64_MAX;
- afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
- afd_poll_info->Handles[0].Status = 0;
- afd_poll_info->Handles[0].Events = 0;
-
- if (handle->events & UV_READABLE) {
- afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
- AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
- } else {
- if (handle->events & UV_DISCONNECT) {
- afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
- }
- }
- if (handle->events & UV_WRITABLE) {
- afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
- }
-
- memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
-
- result = uv_msafd_poll((SOCKET) handle->peer_socket,
- afd_poll_info,
- afd_poll_info,
- &req->u.io.overlapped);
- if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
- /* Queue this req, reporting an error. */
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, req);
- }
-}
-
-
-static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
- AFD_POLL_INFO afd_poll_info;
- int result;
-
- afd_poll_info.Exclusive = TRUE;
- afd_poll_info.NumberOfHandles = 1;
- afd_poll_info.Timeout.QuadPart = INT64_MAX;
- afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
- afd_poll_info.Handles[0].Status = 0;
- afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
-
- result = uv_msafd_poll(handle->socket,
- &afd_poll_info,
- uv__get_afd_poll_info_dummy(),
- uv__get_overlapped_dummy());
-
- if (result == SOCKET_ERROR) {
- DWORD error = WSAGetLastError();
- if (error != WSA_IO_PENDING)
- return error;
- }
-
- return 0;
-}
-
-
-static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
- uv_req_t* req) {
- unsigned char mask_events;
- AFD_POLL_INFO* afd_poll_info;
-
- if (req == &handle->poll_req_1) {
- afd_poll_info = &handle->afd_poll_info_1;
- handle->submitted_events_1 = 0;
- mask_events = handle->mask_events_1;
- } else if (req == &handle->poll_req_2) {
- afd_poll_info = &handle->afd_poll_info_2;
- handle->submitted_events_2 = 0;
- mask_events = handle->mask_events_2;
- } else {
- assert(0);
- return;
- }
-
- /* Report an error unless the select was just interrupted. */
- if (!REQ_SUCCESS(req)) {
- DWORD error = GET_REQ_SOCK_ERROR(req);
- if (error != WSAEINTR && handle->events != 0) {
- handle->events = 0; /* Stop the watcher */
- handle->poll_cb(handle, uv_translate_sys_error(error), 0);
- }
-
- } else if (afd_poll_info->NumberOfHandles >= 1) {
- unsigned char events = 0;
-
- if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
- AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
- events |= UV_READABLE;
- if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
- events |= UV_DISCONNECT;
- }
- }
- if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
- AFD_POLL_CONNECT_FAIL)) != 0) {
- events |= UV_WRITABLE;
- }
-
- events &= handle->events & ~mask_events;
-
- if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
- /* Stop polling. */
- handle->events = 0;
- if (uv__is_active(handle))
- uv__handle_stop(handle);
- }
-
- if (events != 0) {
- handle->poll_cb(handle, 0, events);
- }
- }
-
- if ((handle->events & ~(handle->submitted_events_1 |
- handle->submitted_events_2)) != 0) {
- uv__fast_poll_submit_poll_req(loop, handle);
- } else if ((handle->flags & UV_HANDLE_CLOSING) &&
- handle->submitted_events_1 == 0 &&
- handle->submitted_events_2 == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-}
-
-
-static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
- assert(handle->type == UV_POLL);
- assert(!(handle->flags & UV_HANDLE_CLOSING));
- assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
-
- handle->events = events;
-
- if (handle->events != 0) {
- uv__handle_start(handle);
- } else {
- uv__handle_stop(handle);
- }
-
- if ((handle->events & ~(handle->submitted_events_1 |
- handle->submitted_events_2)) != 0) {
- uv__fast_poll_submit_poll_req(handle->loop, handle);
- }
-
- return 0;
-}
-
-
-static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
- handle->events = 0;
- uv__handle_closing(handle);
-
- if (handle->submitted_events_1 == 0 &&
- handle->submitted_events_2 == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- return 0;
- } else {
- /* Cancel outstanding poll requests by executing another, unique poll
- * request that forces the outstanding ones to return. */
- return uv__fast_poll_cancel_poll_req(loop, handle);
- }
-}
-
-
-static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
- WSAPROTOCOL_INFOW* protocol_info) {
- SOCKET sock = 0;
-
- sock = WSASocketW(protocol_info->iAddressFamily,
- protocol_info->iSocketType,
- protocol_info->iProtocol,
- protocol_info,
- 0,
- WSA_FLAG_OVERLAPPED);
- if (sock == INVALID_SOCKET) {
- return INVALID_SOCKET;
- }
-
- if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
- goto error;
- };
-
- if (CreateIoCompletionPort((HANDLE) sock,
- iocp,
- (ULONG_PTR) sock,
- 0) == NULL) {
- goto error;
- }
-
- return sock;
-
- error:
- closesocket(sock);
- return INVALID_SOCKET;
-}
-
-
-static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
- WSAPROTOCOL_INFOW* protocol_info) {
- int index, i;
- SOCKET peer_socket;
-
- index = -1;
- for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
- if (memcmp((void*) &protocol_info->ProviderId,
- (void*) &uv_msafd_provider_ids[i],
- sizeof protocol_info->ProviderId) == 0) {
- index = i;
- }
- }
-
- /* Check if the protocol uses an msafd socket. */
- if (index < 0) {
- return INVALID_SOCKET;
- }
-
- /* If we didn't (try) to create a peer socket yet, try to make one. Don't try
- * again if the peer socket creation failed earlier for the same protocol. */
- peer_socket = loop->poll_peer_sockets[index];
- if (peer_socket == 0) {
- peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
- loop->poll_peer_sockets[index] = peer_socket;
- }
-
- return peer_socket;
-}
-
-
-static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
- uv_req_t* req = (uv_req_t*) arg;
- uv_poll_t* handle = (uv_poll_t*) req->data;
- unsigned char reported_events;
- int r;
- uv_single_fd_set_t rfds, wfds, efds;
- struct timeval timeout;
-
- assert(handle->type == UV_POLL);
- assert(req->type == UV_POLL_REQ);
-
- if (handle->events & UV_READABLE) {
- rfds.fd_count = 1;
- rfds.fd_array[0] = handle->socket;
- } else {
- rfds.fd_count = 0;
- }
-
- if (handle->events & UV_WRITABLE) {
- wfds.fd_count = 1;
- wfds.fd_array[0] = handle->socket;
- efds.fd_count = 1;
- efds.fd_array[0] = handle->socket;
- } else {
- wfds.fd_count = 0;
- efds.fd_count = 0;
- }
-
- /* Make the select() time out after 3 minutes. If select() hangs because the
- * user closed the socket, we will at least not hang indefinitely. */
- timeout.tv_sec = 3 * 60;
- timeout.tv_usec = 0;
-
- r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
- if (r == SOCKET_ERROR) {
- /* Queue this req, reporting an error. */
- SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
- POST_COMPLETION_FOR_REQ(handle->loop, req);
- return 0;
- }
-
- reported_events = 0;
-
- if (r > 0) {
- if (rfds.fd_count > 0) {
- assert(rfds.fd_count == 1);
- assert(rfds.fd_array[0] == handle->socket);
- reported_events |= UV_READABLE;
- }
-
- if (wfds.fd_count > 0) {
- assert(wfds.fd_count == 1);
- assert(wfds.fd_array[0] == handle->socket);
- reported_events |= UV_WRITABLE;
- } else if (efds.fd_count > 0) {
- assert(efds.fd_count == 1);
- assert(efds.fd_array[0] == handle->socket);
- reported_events |= UV_WRITABLE;
- }
- }
-
- SET_REQ_SUCCESS(req);
- req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
- POST_COMPLETION_FOR_REQ(handle->loop, req);
-
- return 0;
-}
-
-
-static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
- uv_req_t* req;
-
- /* Find a yet unsubmitted req to submit. */
- if (handle->submitted_events_1 == 0) {
- req = &handle->poll_req_1;
- handle->submitted_events_1 = handle->events;
- handle->mask_events_1 = 0;
- handle->mask_events_2 = handle->events;
- } else if (handle->submitted_events_2 == 0) {
- req = &handle->poll_req_2;
- handle->submitted_events_2 = handle->events;
- handle->mask_events_1 = handle->events;
- handle->mask_events_2 = 0;
- } else {
- assert(0);
- return;
- }
-
- if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
- (void*) req,
- WT_EXECUTELONGFUNCTION)) {
- /* Make this req pending, reporting an error. */
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, req);
- }
-}
-
-
-
-static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
- uv_req_t* req) {
- unsigned char mask_events;
- int err;
-
- if (req == &handle->poll_req_1) {
- handle->submitted_events_1 = 0;
- mask_events = handle->mask_events_1;
- } else if (req == &handle->poll_req_2) {
- handle->submitted_events_2 = 0;
- mask_events = handle->mask_events_2;
- } else {
- assert(0);
- return;
- }
-
- if (!REQ_SUCCESS(req)) {
- /* Error. */
- if (handle->events != 0) {
- err = GET_REQ_ERROR(req);
- handle->events = 0; /* Stop the watcher */
- handle->poll_cb(handle, uv_translate_sys_error(err), 0);
- }
- } else {
- /* Got some events. */
- int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
- if (events != 0) {
- handle->poll_cb(handle, 0, events);
- }
- }
-
- if ((handle->events & ~(handle->submitted_events_1 |
- handle->submitted_events_2)) != 0) {
- uv__slow_poll_submit_poll_req(loop, handle);
- } else if ((handle->flags & UV_HANDLE_CLOSING) &&
- handle->submitted_events_1 == 0 &&
- handle->submitted_events_2 == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-}
-
-
-static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
- assert(handle->type == UV_POLL);
- assert(!(handle->flags & UV_HANDLE_CLOSING));
- assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
-
- handle->events = events;
-
- if (handle->events != 0) {
- uv__handle_start(handle);
- } else {
- uv__handle_stop(handle);
- }
-
- if ((handle->events &
- ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
- uv__slow_poll_submit_poll_req(handle->loop, handle);
- }
-
- return 0;
-}
-
-
-static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
- handle->events = 0;
- uv__handle_closing(handle);
-
- if (handle->submitted_events_1 == 0 &&
- handle->submitted_events_2 == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-
- return 0;
-}
-
-
-int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
- return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
-}
-
-
-int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
- uv_os_sock_t socket) {
- WSAPROTOCOL_INFOW protocol_info;
- int len;
- SOCKET peer_socket, base_socket;
- DWORD bytes;
- DWORD yes = 1;
-
- /* Set the socket to nonblocking mode */
- if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
- return uv_translate_sys_error(WSAGetLastError());
-
-/* Try to obtain a base handle for the socket. This increases this chances that
- * we find an AFD handle and are able to use the fast poll mechanism. This will
- * always fail on windows XP/2k3, since they don't support the. SIO_BASE_HANDLE
- * ioctl. */
-#ifndef NDEBUG
- base_socket = INVALID_SOCKET;
-#endif
-
- if (WSAIoctl(socket,
- SIO_BASE_HANDLE,
- NULL,
- 0,
- &base_socket,
- sizeof base_socket,
- &bytes,
- NULL,
- NULL) == 0) {
- assert(base_socket != 0 && base_socket != INVALID_SOCKET);
- socket = base_socket;
- }
-
- uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
- handle->socket = socket;
- handle->events = 0;
-
- /* Obtain protocol information about the socket. */
- len = sizeof protocol_info;
- if (getsockopt(socket,
- SOL_SOCKET,
- SO_PROTOCOL_INFOW,
- (char*) &protocol_info,
- &len) != 0) {
- return uv_translate_sys_error(WSAGetLastError());
- }
-
- /* Get the peer socket that is needed to enable fast poll. If the returned
- * value is NULL, the protocol is not implemented by MSAFD and we'll have to
- * use slow mode. */
- peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
-
- if (peer_socket != INVALID_SOCKET) {
- /* Initialize fast poll specific fields. */
- handle->peer_socket = peer_socket;
- } else {
- /* Initialize slow poll specific fields. */
- handle->flags |= UV_HANDLE_POLL_SLOW;
- }
-
- /* Initialize 2 poll reqs. */
- handle->submitted_events_1 = 0;
- UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
- handle->poll_req_1.data = handle;
-
- handle->submitted_events_2 = 0;
- UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
- handle->poll_req_2.data = handle;
-
- return 0;
-}
-
-
-int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
- int err;
-
- if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
- err = uv__fast_poll_set(handle->loop, handle, events);
- } else {
- err = uv__slow_poll_set(handle->loop, handle, events);
- }
-
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- handle->poll_cb = cb;
-
- return 0;
-}
-
-
-int uv_poll_stop(uv_poll_t* handle) {
- int err;
-
- if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
- err = uv__fast_poll_set(handle->loop, handle, 0);
- } else {
- err = uv__slow_poll_set(handle->loop, handle, 0);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
- if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
- uv__fast_poll_process_poll_req(loop, handle, req);
- } else {
- uv__slow_poll_process_poll_req(loop, handle, req);
- }
-}
-
-
-int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
- if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
- return uv__fast_poll_close(loop, handle);
- } else {
- return uv__slow_poll_close(loop, handle);
- }
-}
-
-
-void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- assert(handle->submitted_events_1 == 0);
- assert(handle->submitted_events_2 == 0);
-
- uv__handle_close(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/process-stdio.cpp b/wpiutil/src/main/native/libuv/src/win/process-stdio.cpp
deleted file mode 100644
index 4701938..0000000
--- a/wpiutil/src/main/native/libuv/src/win/process-stdio.cpp
+++ /dev/null
@@ -1,512 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <io.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-
-
-/*
- * The `child_stdio_buffer` buffer has the following layout:
- * int number_of_fds
- * unsigned char crt_flags[number_of_fds]
- * HANDLE os_handle[number_of_fds]
- */
-#define CHILD_STDIO_SIZE(count) \
- (sizeof(int) + \
- sizeof(unsigned char) * (count) + \
- sizeof(uintptr_t) * (count))
-
-#define CHILD_STDIO_COUNT(buffer) \
- *((unsigned int*) (buffer))
-
-#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
- *((unsigned char*) (buffer) + sizeof(int) + fd)
-
-#define CHILD_STDIO_HANDLE(buffer, fd) \
- *((HANDLE*) ((unsigned char*) (buffer) + \
- sizeof(int) + \
- sizeof(unsigned char) * \
- CHILD_STDIO_COUNT((buffer)) + \
- sizeof(HANDLE) * (fd)))
-
-
-/* CRT file descriptor mode flags */
-#define FOPEN 0x01
-#define FEOFLAG 0x02
-#define FCRLF 0x04
-#define FPIPE 0x08
-#define FNOINHERIT 0x10
-#define FAPPEND 0x20
-#define FDEV 0x40
-#define FTEXT 0x80
-
-
-/*
- * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
- * the parent process. Don't check for errors - the stdio handles may not be
- * valid, or may be closed already. There is no guarantee that this function
- * does a perfect job.
- */
-void uv_disable_stdio_inheritance(void) {
- HANDLE handle;
- STARTUPINFOW si;
-
- /* Make the windows stdio handles non-inheritable. */
- handle = GetStdHandle(STD_INPUT_HANDLE);
- if (handle != NULL && handle != INVALID_HANDLE_VALUE)
- SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
-
- handle = GetStdHandle(STD_OUTPUT_HANDLE);
- if (handle != NULL && handle != INVALID_HANDLE_VALUE)
- SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
-
- handle = GetStdHandle(STD_ERROR_HANDLE);
- if (handle != NULL && handle != INVALID_HANDLE_VALUE)
- SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
-
- /* Make inherited CRT FDs non-inheritable. */
- GetStartupInfoW(&si);
- if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
- uv__stdio_noinherit(si.lpReserved2);
-}
-
-
-static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
- uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
- char pipe_name[64];
- SECURITY_ATTRIBUTES sa;
- DWORD server_access = 0;
- DWORD client_access = 0;
- HANDLE child_pipe = INVALID_HANDLE_VALUE;
- int err;
- BOOL overlap;
-
- if (flags & UV_READABLE_PIPE) {
- /* The server needs inbound access too, otherwise CreateNamedPipe() won't
- * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
- * state of the write buffer when we're trying to shutdown the pipe. */
- server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
- }
- if (flags & UV_WRITABLE_PIPE) {
- server_access |= PIPE_ACCESS_INBOUND;
- client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
- }
-
- /* Create server pipe handle. */
- err = uv_stdio_pipe_server(loop,
- server_pipe,
- server_access,
- pipe_name,
- sizeof(pipe_name));
- if (err)
- goto error;
-
- /* Create child pipe handle. */
- sa.nLength = sizeof sa;
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
- child_pipe = CreateFileA(pipe_name,
- client_access,
- 0,
- &sa,
- OPEN_EXISTING,
- overlap ? FILE_FLAG_OVERLAPPED : 0,
- NULL);
- if (child_pipe == INVALID_HANDLE_VALUE) {
- err = GetLastError();
- goto error;
- }
-
-#ifndef NDEBUG
- /* Validate that the pipe was opened in the right mode. */
- {
- DWORD mode;
- BOOL r = GetNamedPipeHandleState(child_pipe,
- &mode,
- NULL,
- NULL,
- NULL,
- NULL,
- 0);
- assert(r == TRUE);
- assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
- }
-#endif
-
- /* Do a blocking ConnectNamedPipe. This should not block because we have both
- * ends of the pipe created. */
- if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
- if (GetLastError() != ERROR_PIPE_CONNECTED) {
- err = GetLastError();
- goto error;
- }
- }
-
- /* The server end is now readable and/or writable. */
- if (flags & UV_READABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_WRITABLE;
- if (flags & UV_WRITABLE_PIPE)
- server_pipe->flags |= UV_HANDLE_READABLE;
-
- *child_pipe_ptr = child_pipe;
- return 0;
-
- error:
- if (server_pipe->handle != INVALID_HANDLE_VALUE) {
- uv_pipe_cleanup(loop, server_pipe);
- }
-
- if (child_pipe != INVALID_HANDLE_VALUE) {
- CloseHandle(child_pipe);
- }
-
- return err;
-}
-
-
-static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
- HANDLE current_process;
-
-
- /* _get_osfhandle will sometimes return -2 in case of an error. This seems to
- * happen when fd <= 2 and the process' corresponding stdio handle is set to
- * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
- * this situation goes unnoticed until someone tries to use the duplicate.
- * Therefore we filter out known-invalid handles here. */
- if (handle == INVALID_HANDLE_VALUE ||
- handle == NULL ||
- handle == (HANDLE) -2) {
- *dup = INVALID_HANDLE_VALUE;
- return ERROR_INVALID_HANDLE;
- }
-
- current_process = GetCurrentProcess();
-
- if (!DuplicateHandle(current_process,
- handle,
- current_process,
- dup,
- 0,
- TRUE,
- DUPLICATE_SAME_ACCESS)) {
- *dup = INVALID_HANDLE_VALUE;
- return GetLastError();
- }
-
- return 0;
-}
-
-
-static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
- HANDLE handle;
-
- if (fd == -1) {
- *dup = INVALID_HANDLE_VALUE;
- return ERROR_INVALID_HANDLE;
- }
-
- handle = uv__get_osfhandle(fd);
- return uv__duplicate_handle(loop, handle, dup);
-}
-
-
-int uv__create_nul_handle(HANDLE* handle_ptr,
- DWORD access) {
- HANDLE handle;
- SECURITY_ATTRIBUTES sa;
-
- sa.nLength = sizeof sa;
- sa.lpSecurityDescriptor = NULL;
- sa.bInheritHandle = TRUE;
-
- handle = CreateFileW(L"NUL",
- access,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- &sa,
- OPEN_EXISTING,
- 0,
- NULL);
- if (handle == INVALID_HANDLE_VALUE) {
- return GetLastError();
- }
-
- *handle_ptr = handle;
- return 0;
-}
-
-
-int uv__stdio_create(uv_loop_t* loop,
- const uv_process_options_t* options,
- BYTE** buffer_ptr) {
- BYTE* buffer;
- int count, i;
- int err;
-
- count = options->stdio_count;
-
- if (count < 0 || count > 255) {
- /* Only support FDs 0-255 */
- return ERROR_NOT_SUPPORTED;
- } else if (count < 3) {
- /* There should always be at least 3 stdio handles. */
- count = 3;
- }
-
- /* Allocate the child stdio buffer */
- buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
- if (buffer == NULL) {
- return ERROR_OUTOFMEMORY;
- }
-
- /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
- * up on failure. */
- CHILD_STDIO_COUNT(buffer) = count;
- for (i = 0; i < count; i++) {
- CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
- CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
- }
-
- for (i = 0; i < count; i++) {
- uv_stdio_container_t fdopt;
- if (i < options->stdio_count) {
- fdopt = options->stdio[i];
- } else {
- fdopt.flags = UV_IGNORE;
- }
-
- switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
- UV_INHERIT_STREAM)) {
- case UV_IGNORE:
- /* Starting a process with no stdin/stout/stderr can confuse it. So no
- * matter what the user specified, we make sure the first three FDs are
- * always open in their typical modes, e. g. stdin be readable and
- * stdout/err should be writable. For FDs > 2, don't do anything - all
- * handles in the stdio buffer are initialized with.
- * INVALID_HANDLE_VALUE, which should be okay. */
- if (i <= 2) {
- DWORD access = (i == 0) ? FILE_GENERIC_READ :
- FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
-
- err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
- access);
- if (err)
- goto error;
-
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
- }
- break;
-
- case UV_CREATE_PIPE: {
- /* Create a pair of two connected pipe ends; one end is turned into an
- * uv_pipe_t for use by the parent. The other one is given to the
- * child. */
- uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
- HANDLE child_pipe = INVALID_HANDLE_VALUE;
-
- /* Create a new, connected pipe pair. stdio[i]. stream should point to
- * an uninitialized, but not connected pipe handle. */
- assert(fdopt.data.stream->type == UV_NAMED_PIPE);
- assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
- assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
-
- err = uv__create_stdio_pipe_pair(loop,
- parent_pipe,
- &child_pipe,
- fdopt.flags);
- if (err)
- goto error;
-
- CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
- break;
- }
-
- case UV_INHERIT_FD: {
- /* Inherit a raw FD. */
- HANDLE child_handle;
-
- /* Make an inheritable duplicate of the handle. */
- err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
- if (err) {
- /* If fdopt. data. fd is not valid and fd <= 2, then ignore the
- * error. */
- if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
- CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
- CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
- break;
- }
- goto error;
- }
-
- /* Figure out what the type is. */
- switch (GetFileType(child_handle)) {
- case FILE_TYPE_DISK:
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
- break;
-
- case FILE_TYPE_PIPE:
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
- break;
-
- case FILE_TYPE_CHAR:
- case FILE_TYPE_REMOTE:
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
- break;
-
- case FILE_TYPE_UNKNOWN:
- if (GetLastError() != 0) {
- err = GetLastError();
- CloseHandle(child_handle);
- goto error;
- }
- CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
- break;
-
- default:
- assert(0);
- return -1;
- }
-
- CHILD_STDIO_HANDLE(buffer, i) = child_handle;
- break;
- }
-
- case UV_INHERIT_STREAM: {
- /* Use an existing stream as the stdio handle for the child. */
- HANDLE stream_handle, child_handle;
- unsigned char crt_flags;
- uv_stream_t* stream = fdopt.data.stream;
-
- /* Leech the handle out of the stream. */
- if (stream->type == UV_TTY) {
- stream_handle = ((uv_tty_t*) stream)->handle;
- crt_flags = FOPEN | FDEV;
- } else if (stream->type == UV_NAMED_PIPE &&
- stream->flags & UV_HANDLE_CONNECTION) {
- stream_handle = ((uv_pipe_t*) stream)->handle;
- crt_flags = FOPEN | FPIPE;
- } else {
- stream_handle = INVALID_HANDLE_VALUE;
- crt_flags = 0;
- }
-
- if (stream_handle == NULL ||
- stream_handle == INVALID_HANDLE_VALUE) {
- /* The handle is already closed, or not yet created, or the stream
- * type is not supported. */
- err = ERROR_NOT_SUPPORTED;
- goto error;
- }
-
- /* Make an inheritable copy of the handle. */
- err = uv__duplicate_handle(loop, stream_handle, &child_handle);
- if (err)
- goto error;
-
- CHILD_STDIO_HANDLE(buffer, i) = child_handle;
- CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
- break;
- }
-
- default:
- assert(0);
- return -1;
- }
- }
-
- *buffer_ptr = buffer;
- return 0;
-
- error:
- uv__stdio_destroy(buffer);
- return err;
-}
-
-
-void uv__stdio_destroy(BYTE* buffer) {
- int i, count;
-
- count = CHILD_STDIO_COUNT(buffer);
- for (i = 0; i < count; i++) {
- HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
- if (handle != INVALID_HANDLE_VALUE) {
- CloseHandle(handle);
- }
- }
-
- uv__free(buffer);
-}
-
-
-void uv__stdio_noinherit(BYTE* buffer) {
- int i, count;
-
- count = CHILD_STDIO_COUNT(buffer);
- for (i = 0; i < count; i++) {
- HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
- if (handle != INVALID_HANDLE_VALUE) {
- SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
- }
- }
-}
-
-
-int uv__stdio_verify(BYTE* buffer, WORD size) {
- unsigned int count;
-
- /* Check the buffer pointer. */
- if (buffer == NULL)
- return 0;
-
- /* Verify that the buffer is at least big enough to hold the count. */
- if (size < CHILD_STDIO_SIZE(0))
- return 0;
-
- /* Verify if the count is within range. */
- count = CHILD_STDIO_COUNT(buffer);
- if (count > 256)
- return 0;
-
- /* Verify that the buffer size is big enough to hold info for N FDs. */
- if (size < CHILD_STDIO_SIZE(count))
- return 0;
-
- return 1;
-}
-
-
-WORD uv__stdio_size(BYTE* buffer) {
- return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
-}
-
-
-HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
- return CHILD_STDIO_HANDLE(buffer, fd);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/process.cpp b/wpiutil/src/main/native/libuv/src/win/process.cpp
deleted file mode 100644
index 3b8675a..0000000
--- a/wpiutil/src/main/native/libuv/src/win/process.cpp
+++ /dev/null
@@ -1,1284 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 _CRT_NONSTDC_NO_WARNINGS
-
-#include <assert.h>
-#include <io.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <limits.h>
-#include <wchar.h>
-#include <malloc.h> /* alloca */
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-#define SIGKILL 9
-
-
-typedef struct env_var {
- const WCHAR* const wide;
- const WCHAR* const wide_eq;
- const size_t len; /* including null or '=' */
-} env_var_t;
-
-#define E_V(str) { L##str, L##str L"=", sizeof(str) }
-
-static const env_var_t required_vars[] = { /* keep me sorted */
- E_V("HOMEDRIVE"),
- E_V("HOMEPATH"),
- E_V("LOGONSERVER"),
- E_V("PATH"),
- E_V("SYSTEMDRIVE"),
- E_V("SYSTEMROOT"),
- E_V("TEMP"),
- E_V("USERDOMAIN"),
- E_V("USERNAME"),
- E_V("USERPROFILE"),
- E_V("WINDIR"),
-};
-static size_t n_required_vars = ARRAY_SIZE(required_vars);
-
-
-static HANDLE uv_global_job_handle_;
-static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
-
-
-static void uv__init_global_job_handle(void) {
- /* Create a job object and set it up to kill all contained processes when
- * it's closed. Since this handle is made non-inheritable and we're not
- * giving it to anyone, we're the only process holding a reference to it.
- * That means that if this process exits it is closed and all the processes
- * it contains are killed. All processes created with uv_spawn that are not
- * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
- *
- * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
- * processes that we explicitly add are affected, and *their* subprocesses
- * are not. This ensures that our child processes are not limited in their
- * ability to use job control on Windows versions that don't deal with
- * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
- * processes created detached processes without explicitly breaking away
- * from job control (which uv_spawn doesn't, either).
- */
- SECURITY_ATTRIBUTES attr;
- JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
-
- memset(&attr, 0, sizeof attr);
- attr.bInheritHandle = FALSE;
-
- memset(&info, 0, sizeof info);
- info.BasicLimitInformation.LimitFlags =
- JOB_OBJECT_LIMIT_BREAKAWAY_OK |
- JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
- JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
- JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
-
- uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
- if (uv_global_job_handle_ == NULL)
- uv_fatal_error(GetLastError(), "CreateJobObjectW");
-
- if (!SetInformationJobObject(uv_global_job_handle_,
- JobObjectExtendedLimitInformation,
- &info,
- sizeof info))
- uv_fatal_error(GetLastError(), "SetInformationJobObject");
-}
-
-
-static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
- int ws_len, r;
- WCHAR* ws;
-
- ws_len = MultiByteToWideChar(CP_UTF8,
- 0,
- s,
- -1,
- NULL,
- 0);
- if (ws_len <= 0) {
- return GetLastError();
- }
-
- ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
- if (ws == NULL) {
- return ERROR_OUTOFMEMORY;
- }
-
- r = MultiByteToWideChar(CP_UTF8,
- 0,
- s,
- -1,
- ws,
- ws_len);
- assert(r == ws_len);
-
- *ws_ptr = ws;
- return 0;
-}
-
-
-static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
- uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
- handle->exit_cb = NULL;
- handle->pid = 0;
- handle->exit_signal = 0;
- handle->wait_handle = INVALID_HANDLE_VALUE;
- handle->process_handle = INVALID_HANDLE_VALUE;
- handle->child_stdio_buffer = NULL;
- handle->exit_cb_pending = 0;
-
- UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
- handle->exit_req.data = handle;
-}
-
-
-/*
- * Path search functions
- */
-
-/*
- * Helper function for search_path
- */
-static WCHAR* search_path_join_test(const WCHAR* dir,
- size_t dir_len,
- const WCHAR* name,
- size_t name_len,
- const WCHAR* ext,
- size_t ext_len,
- const WCHAR* cwd,
- size_t cwd_len) {
- WCHAR *result, *result_pos;
- DWORD attrs;
- if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
- /* It's a UNC path so ignore cwd */
- cwd_len = 0;
- } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
- /* It's a full path without drive letter, use cwd's drive letter only */
- cwd_len = 2;
- } else if (dir_len >= 2 && dir[1] == L':' &&
- (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
- /* It's a relative path with drive letter (ext.g. D:../some/file)
- * Replace drive letter in dir by full cwd if it points to the same drive,
- * otherwise use the dir only.
- */
- if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
- cwd_len = 0;
- } else {
- dir += 2;
- dir_len -= 2;
- }
- } else if (dir_len > 2 && dir[1] == L':') {
- /* It's an absolute path with drive letter
- * Don't use the cwd at all
- */
- cwd_len = 0;
- }
-
- /* Allocate buffer for output */
- result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
- (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
-
- /* Copy cwd */
- wcsncpy(result_pos, cwd, cwd_len);
- result_pos += cwd_len;
-
- /* Add a path separator if cwd didn't end with one */
- if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
- result_pos[0] = L'\\';
- result_pos++;
- }
-
- /* Copy dir */
- wcsncpy(result_pos, dir, dir_len);
- result_pos += dir_len;
-
- /* Add a separator if the dir didn't end with one */
- if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
- result_pos[0] = L'\\';
- result_pos++;
- }
-
- /* Copy filename */
- wcsncpy(result_pos, name, name_len);
- result_pos += name_len;
-
- if (ext_len) {
- /* Add a dot if the filename didn't end with one */
- if (name_len && result_pos[-1] != '.') {
- result_pos[0] = L'.';
- result_pos++;
- }
-
- /* Copy extension */
- wcsncpy(result_pos, ext, ext_len);
- result_pos += ext_len;
- }
-
- /* Null terminator */
- result_pos[0] = L'\0';
-
- attrs = GetFileAttributesW(result);
-
- if (attrs != INVALID_FILE_ATTRIBUTES &&
- !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
- return result;
- }
-
- uv__free(result);
- return NULL;
-}
-
-
-/*
- * Helper function for search_path
- */
-static WCHAR* path_search_walk_ext(const WCHAR *dir,
- size_t dir_len,
- const WCHAR *name,
- size_t name_len,
- WCHAR *cwd,
- size_t cwd_len,
- int name_has_ext) {
- WCHAR* result;
-
- /* If the name itself has a nonempty extension, try this extension first */
- if (name_has_ext) {
- result = search_path_join_test(dir, dir_len,
- name, name_len,
- L"", 0,
- cwd, cwd_len);
- if (result != NULL) {
- return result;
- }
- }
-
- /* Try .com extension */
- result = search_path_join_test(dir, dir_len,
- name, name_len,
- L"com", 3,
- cwd, cwd_len);
- if (result != NULL) {
- return result;
- }
-
- /* Try .exe extension */
- result = search_path_join_test(dir, dir_len,
- name, name_len,
- L"exe", 3,
- cwd, cwd_len);
- if (result != NULL) {
- return result;
- }
-
- return NULL;
-}
-
-
-/*
- * search_path searches the system path for an executable filename -
- * the windows API doesn't provide this as a standalone function nor as an
- * option to CreateProcess.
- *
- * It tries to return an absolute filename.
- *
- * Furthermore, it tries to follow the semantics that cmd.exe, with this
- * exception that PATHEXT environment variable isn't used. Since CreateProcess
- * can start only .com and .exe files, only those extensions are tried. This
- * behavior equals that of msvcrt's spawn functions.
- *
- * - Do not search the path if the filename already contains a path (either
- * relative or absolute).
- *
- * - If there's really only a filename, check the current directory for file,
- * then search all path directories.
- *
- * - If filename specified has *any* extension, search for the file with the
- * specified extension first.
- *
- * - If the literal filename is not found in a directory, try *appending*
- * (not replacing) .com first and then .exe.
- *
- * - The path variable may contain relative paths; relative paths are relative
- * to the cwd.
- *
- * - Directories in path may or may not end with a trailing backslash.
- *
- * - CMD does not trim leading/trailing whitespace from path/pathex entries
- * nor from the environment variables as a whole.
- *
- * - When cmd.exe cannot read a directory, it will just skip it and go on
- * searching. However, unlike posix-y systems, it will happily try to run a
- * file that is not readable/executable; if the spawn fails it will not
- * continue searching.
- *
- * UNC path support: we are dealing with UNC paths in both the path and the
- * filename. This is a deviation from what cmd.exe does (it does not let you
- * start a program by specifying an UNC path on the command line) but this is
- * really a pointless restriction.
- *
- */
-static WCHAR* search_path(const WCHAR *file,
- WCHAR *cwd,
- const WCHAR *path) {
- int file_has_dir;
- WCHAR* result = NULL;
- WCHAR *file_name_start;
- WCHAR *dot;
- const WCHAR *dir_start, *dir_end, *dir_path;
- size_t dir_len;
- int name_has_ext;
-
- size_t file_len = wcslen(file);
- size_t cwd_len = wcslen(cwd);
-
- /* If the caller supplies an empty filename,
- * we're not gonna return c:\windows\.exe -- GFY!
- */
- if (file_len == 0
- || (file_len == 1 && file[0] == L'.')) {
- return NULL;
- }
-
- /* Find the start of the filename so we can split the directory from the
- * name. */
- for (file_name_start = (WCHAR*)file + file_len;
- file_name_start > file
- && file_name_start[-1] != L'\\'
- && file_name_start[-1] != L'/'
- && file_name_start[-1] != L':';
- file_name_start--);
-
- file_has_dir = file_name_start != file;
-
- /* Check if the filename includes an extension */
- dot = wcschr(file_name_start, L'.');
- name_has_ext = (dot != NULL && dot[1] != L'\0');
-
- if (file_has_dir) {
- /* The file has a path inside, don't use path */
- result = path_search_walk_ext(
- file, file_name_start - file,
- file_name_start, file_len - (file_name_start - file),
- cwd, cwd_len,
- name_has_ext);
-
- } else {
- dir_end = path;
-
- /* The file is really only a name; look in cwd first, then scan path */
- result = path_search_walk_ext(L"", 0,
- file, file_len,
- cwd, cwd_len,
- name_has_ext);
-
- while (result == NULL) {
- if (*dir_end == L'\0') {
- break;
- }
-
- /* Skip the separator that dir_end now points to */
- if (dir_end != path || *path == L';') {
- dir_end++;
- }
-
- /* Next slice starts just after where the previous one ended */
- dir_start = dir_end;
-
- /* If path is quoted, find quote end */
- if (*dir_start == L'"' || *dir_start == L'\'') {
- dir_end = wcschr(dir_start + 1, *dir_start);
- if (dir_end == NULL) {
- dir_end = wcschr(dir_start, L'\0');
- }
- }
- /* Slice until the next ; or \0 is found */
- dir_end = wcschr(dir_end, L';');
- if (dir_end == NULL) {
- dir_end = wcschr(dir_start, L'\0');
- }
-
- /* If the slice is zero-length, don't bother */
- if (dir_end - dir_start == 0) {
- continue;
- }
-
- dir_path = dir_start;
- dir_len = dir_end - dir_start;
-
- /* Adjust if the path is quoted. */
- if (dir_path[0] == '"' || dir_path[0] == '\'') {
- ++dir_path;
- --dir_len;
- }
-
- if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
- --dir_len;
- }
-
- result = path_search_walk_ext(dir_path, dir_len,
- file, file_len,
- cwd, cwd_len,
- name_has_ext);
- }
- }
-
- return result;
-}
-
-
-/*
- * Quotes command line arguments
- * Returns a pointer to the end (next char to be written) of the buffer
- */
-WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
- size_t len = wcslen(source);
- size_t i;
- int quote_hit;
- WCHAR* start;
-
- if (len == 0) {
- /* Need double quotation for empty argument */
- *(target++) = L'"';
- *(target++) = L'"';
- return target;
- }
-
- if (NULL == wcspbrk(source, L" \t\"")) {
- /* No quotation needed */
- wcsncpy(target, source, len);
- target += len;
- return target;
- }
-
- if (NULL == wcspbrk(source, L"\"\\")) {
- /*
- * No embedded double quotes or backlashes, so I can just wrap
- * quote marks around the whole thing.
- */
- *(target++) = L'"';
- wcsncpy(target, source, len);
- target += len;
- *(target++) = L'"';
- return target;
- }
-
- /*
- * Expected input/output:
- * input : hello"world
- * output: "hello\"world"
- * input : hello""world
- * output: "hello\"\"world"
- * input : hello\world
- * output: hello\world
- * input : hello\\world
- * output: hello\\world
- * input : hello\"world
- * output: "hello\\\"world"
- * input : hello\\"world
- * output: "hello\\\\\"world"
- * input : hello world\
- * output: "hello world\\"
- */
-
- *(target++) = L'"';
- start = target;
- quote_hit = 1;
-
- for (i = len; i > 0; --i) {
- *(target++) = source[i - 1];
-
- if (quote_hit && source[i - 1] == L'\\') {
- *(target++) = L'\\';
- } else if(source[i - 1] == L'"') {
- quote_hit = 1;
- *(target++) = L'\\';
- } else {
- quote_hit = 0;
- }
- }
- target[0] = L'\0';
- wcsrev(start);
- *(target++) = L'"';
- return target;
-}
-
-
-int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
- char** arg;
- WCHAR* dst = NULL;
- WCHAR* temp_buffer = NULL;
- size_t dst_len = 0;
- size_t temp_buffer_len = 0;
- WCHAR* pos;
- int arg_count = 0;
- int err = 0;
-
- /* Count the required size. */
- for (arg = args; *arg; arg++) {
- DWORD arg_len;
-
- arg_len = MultiByteToWideChar(CP_UTF8,
- 0,
- *arg,
- -1,
- NULL,
- 0);
- if (arg_len == 0) {
- return GetLastError();
- }
-
- dst_len += arg_len;
-
- if (arg_len > temp_buffer_len)
- temp_buffer_len = arg_len;
-
- arg_count++;
- }
-
- /* Adjust for potential quotes. Also assume the worst-case scenario that
- * every character needs escaping, so we need twice as much space. */
- dst_len = dst_len * 2 + arg_count * 2;
-
- /* Allocate buffer for the final command line. */
- dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
- if (dst == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
-
- /* Allocate temporary working buffer. */
- temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
- if (temp_buffer == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
-
- pos = dst;
- for (arg = args; *arg; arg++) {
- DWORD arg_len;
-
- /* Convert argument to wide char. */
- arg_len = MultiByteToWideChar(CP_UTF8,
- 0,
- *arg,
- -1,
- temp_buffer,
- (int) (dst + dst_len - pos));
- if (arg_len == 0) {
- err = GetLastError();
- goto error;
- }
-
- if (verbatim_arguments) {
- /* Copy verbatim. */
- wcscpy(pos, temp_buffer);
- pos += arg_len - 1;
- } else {
- /* Quote/escape, if needed. */
- pos = quote_cmd_arg(temp_buffer, pos);
- }
-
- *pos++ = *(arg + 1) ? L' ' : L'\0';
- }
-
- uv__free(temp_buffer);
-
- *dst_ptr = dst;
- return 0;
-
-error:
- uv__free(dst);
- uv__free(temp_buffer);
- return err;
-}
-
-
-int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
- const wchar_t* a_eq;
- const wchar_t* b_eq;
- wchar_t* A;
- wchar_t* B;
- int nb;
- int r;
-
- if (na < 0) {
- a_eq = wcschr(a, L'=');
- assert(a_eq);
- na = (int)(long)(a_eq - a);
- } else {
- na--;
- }
- b_eq = wcschr(b, L'=');
- assert(b_eq);
- nb = b_eq - b;
-
- A = (wchar_t*)alloca((na+1) * sizeof(wchar_t));
- B = (wchar_t*)alloca((nb+1) * sizeof(wchar_t));
-
- r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
- assert(r==na);
- A[na] = L'\0';
- r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
- assert(r==nb);
- B[nb] = L'\0';
-
- while (1) {
- wchar_t AA = *A++;
- wchar_t BB = *B++;
- if (AA < BB) {
- return -1;
- } else if (AA > BB) {
- return 1;
- } else if (!AA && !BB) {
- return 0;
- }
- }
-}
-
-
-static int qsort_wcscmp(const void *a, const void *b) {
- wchar_t* astr = *(wchar_t* const*)a;
- wchar_t* bstr = *(wchar_t* const*)b;
- return env_strncmp(astr, -1, bstr);
-}
-
-
-/*
- * The way windows takes environment variables is different than what C does;
- * Windows wants a contiguous block of null-terminated strings, terminated
- * with an additional null.
- *
- * Windows has a few "essential" environment variables. winsock will fail
- * to initialize if SYSTEMROOT is not defined; some APIs make reference to
- * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
- * these get defined if the input environment block does not contain any
- * values for them.
- *
- * Also add variables known to Cygwin to be required for correct
- * subprocess operation in many cases:
- * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
- *
- */
-int make_program_env(char* env_block[], WCHAR** dst_ptr) {
- WCHAR* dst;
- WCHAR* ptr;
- char** env;
- size_t env_len = 0;
- int len;
- size_t i;
- DWORD var_size;
- size_t env_block_count = 1; /* 1 for null-terminator */
- WCHAR* dst_copy;
- WCHAR** ptr_copy;
- WCHAR** env_copy;
- DWORD* required_vars_value_len =
- (DWORD*)alloca(n_required_vars * sizeof(DWORD*));
-
- /* first pass: determine size in UTF-16 */
- for (env = env_block; *env; env++) {
- int len;
- if (strchr(*env, '=')) {
- len = MultiByteToWideChar(CP_UTF8,
- 0,
- *env,
- -1,
- NULL,
- 0);
- if (len <= 0) {
- return GetLastError();
- }
- env_len += len;
- env_block_count++;
- }
- }
-
- /* second pass: copy to UTF-16 environment block */
- dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
- if (!dst_copy) {
- return ERROR_OUTOFMEMORY;
- }
- env_copy = (WCHAR**)alloca(env_block_count * sizeof(WCHAR*));
-
- ptr = dst_copy;
- ptr_copy = env_copy;
- for (env = env_block; *env; env++) {
- if (strchr(*env, '=')) {
- len = MultiByteToWideChar(CP_UTF8,
- 0,
- *env,
- -1,
- ptr,
- (int) (env_len - (ptr - dst_copy)));
- if (len <= 0) {
- DWORD err = GetLastError();
- uv__free(dst_copy);
- return err;
- }
- *ptr_copy++ = ptr;
- ptr += len;
- }
- }
- *ptr_copy = NULL;
- assert(env_len == (size_t) (ptr - dst_copy));
-
- /* sort our (UTF-16) copy */
- qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
-
- /* third pass: check for required variables */
- for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
- int cmp;
- if (!*ptr_copy) {
- cmp = -1;
- } else {
- cmp = env_strncmp(required_vars[i].wide_eq,
- required_vars[i].len,
- *ptr_copy);
- }
- if (cmp < 0) {
- /* missing required var */
- var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
- required_vars_value_len[i] = var_size;
- if (var_size != 0) {
- env_len += required_vars[i].len;
- env_len += var_size;
- }
- i++;
- } else {
- ptr_copy++;
- if (cmp == 0)
- i++;
- }
- }
-
- /* final pass: copy, in sort order, and inserting required variables */
- dst = (WCHAR*)uv__malloc((1+env_len) * sizeof(WCHAR));
- if (!dst) {
- uv__free(dst_copy);
- return ERROR_OUTOFMEMORY;
- }
-
- for (ptr = dst, ptr_copy = env_copy, i = 0;
- *ptr_copy || i < n_required_vars;
- ptr += len) {
- int cmp;
- if (i >= n_required_vars) {
- cmp = 1;
- } else if (!*ptr_copy) {
- cmp = -1;
- } else {
- cmp = env_strncmp(required_vars[i].wide_eq,
- required_vars[i].len,
- *ptr_copy);
- }
- if (cmp < 0) {
- /* missing required var */
- len = required_vars_value_len[i];
- if (len) {
- wcscpy(ptr, required_vars[i].wide_eq);
- ptr += required_vars[i].len;
- var_size = GetEnvironmentVariableW(required_vars[i].wide,
- ptr,
- (int) (env_len - (ptr - dst)));
- if (var_size != (DWORD) (len - 1)) { /* TODO: handle race condition? */
- uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
- }
- }
- i++;
- } else {
- /* copy var from env_block */
- len = wcslen(*ptr_copy) + 1;
- wmemcpy(ptr, *ptr_copy, len);
- ptr_copy++;
- if (cmp == 0)
- i++;
- }
- }
-
- /* Terminate with an extra NULL. */
- assert(env_len == (size_t) (ptr - dst));
- *ptr = L'\0';
-
- uv__free(dst_copy);
- *dst_ptr = dst;
- return 0;
-}
-
-/*
- * Attempt to find the value of the PATH environment variable in the child's
- * preprocessed environment.
- *
- * If found, a pointer into `env` is returned. If not found, NULL is returned.
- */
-static WCHAR* find_path(WCHAR *env) {
- for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
- if ((env[0] == L'P' || env[0] == L'p') &&
- (env[1] == L'A' || env[1] == L'a') &&
- (env[2] == L'T' || env[2] == L't') &&
- (env[3] == L'H' || env[3] == L'h') &&
- (env[4] == L'=')) {
- return &env[5];
- }
- }
-
- return NULL;
-}
-
-/*
- * Called on Windows thread-pool thread to indicate that
- * a child process has exited.
- */
-static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
- uv_process_t* process = (uv_process_t*) data;
- uv_loop_t* loop = process->loop;
-
- assert(didTimeout == FALSE);
- assert(process);
- assert(!process->exit_cb_pending);
-
- process->exit_cb_pending = 1;
-
- /* Post completed */
- POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
-}
-
-
-/* Called on main thread after a child process has exited. */
-void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
- int64_t exit_code;
- DWORD status;
-
- assert(handle->exit_cb_pending);
- handle->exit_cb_pending = 0;
-
- /* If we're closing, don't call the exit callback. Just schedule a close
- * callback now. */
- if (handle->flags & UV_HANDLE_CLOSING) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- return;
- }
-
- /* Unregister from process notification. */
- if (handle->wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(handle->wait_handle);
- handle->wait_handle = INVALID_HANDLE_VALUE;
- }
-
- /* Set the handle to inactive: no callbacks will be made after the exit
- * callback. */
- uv__handle_stop(handle);
-
- if (GetExitCodeProcess(handle->process_handle, &status)) {
- exit_code = status;
- } else {
- /* Unable to obtain the exit code. This should never happen. */
- exit_code = uv_translate_sys_error(GetLastError());
- }
-
- /* Fire the exit callback. */
- if (handle->exit_cb) {
- handle->exit_cb(handle, exit_code, handle->exit_signal);
- }
-}
-
-
-void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
- uv__handle_closing(handle);
-
- if (handle->wait_handle != INVALID_HANDLE_VALUE) {
- /* This blocks until either the wait was cancelled, or the callback has
- * completed. */
- BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
- if (!r) {
- /* This should never happen, and if it happens, we can't recover... */
- uv_fatal_error(GetLastError(), "UnregisterWaitEx");
- }
-
- handle->wait_handle = INVALID_HANDLE_VALUE;
- }
-
- if (!handle->exit_cb_pending) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-}
-
-
-void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
- assert(!handle->exit_cb_pending);
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- /* Clean-up the process handle. */
- CloseHandle(handle->process_handle);
-
- uv__handle_close(handle);
-}
-
-
-int uv_spawn(uv_loop_t* loop,
- uv_process_t* process,
- const uv_process_options_t* options) {
- int i;
- int err = 0;
- WCHAR* path = NULL, *alloc_path = NULL;
- BOOL result;
- WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
- *env = NULL, *cwd = NULL;
- STARTUPINFOW startup;
- PROCESS_INFORMATION info;
- DWORD process_flags;
-
- uv_process_init(loop, process);
- process->exit_cb = options->exit_cb;
-
- if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
- return UV_ENOTSUP;
- }
-
- if (options->file == NULL ||
- options->args == NULL) {
- return UV_EINVAL;
- }
-
- assert(options->file != NULL);
- assert(!(options->flags & ~(UV_PROCESS_DETACHED |
- UV_PROCESS_SETGID |
- UV_PROCESS_SETUID |
- UV_PROCESS_WINDOWS_HIDE |
- UV_PROCESS_WINDOWS_HIDE_CONSOLE |
- UV_PROCESS_WINDOWS_HIDE_GUI |
- UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
-
- err = uv_utf8_to_utf16_alloc(options->file, &application);
- if (err)
- goto done;
-
- err = make_program_args(
- options->args,
- options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
- &arguments);
- if (err)
- goto done;
-
- if (options->env) {
- err = make_program_env(options->env, &env);
- if (err)
- goto done;
- }
-
- if (options->cwd) {
- /* Explicit cwd */
- err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
- if (err)
- goto done;
-
- } else {
- /* Inherit cwd */
- DWORD cwd_len, r;
-
- cwd_len = GetCurrentDirectoryW(0, NULL);
- if (!cwd_len) {
- err = GetLastError();
- goto done;
- }
-
- cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
- if (cwd == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto done;
- }
-
- r = GetCurrentDirectoryW(cwd_len, cwd);
- if (r == 0 || r >= cwd_len) {
- err = GetLastError();
- goto done;
- }
- }
-
- /* Get PATH environment variable. */
- path = find_path(env);
- if (path == NULL) {
- DWORD path_len, r;
-
- path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
- if (path_len == 0) {
- err = GetLastError();
- goto done;
- }
-
- alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
- if (alloc_path == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto done;
- }
- path = alloc_path;
-
- r = GetEnvironmentVariableW(L"PATH", path, path_len);
- if (r == 0 || r >= path_len) {
- err = GetLastError();
- goto done;
- }
- }
-
- err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
- if (err)
- goto done;
-
- application_path = search_path(application,
- cwd,
- path);
- if (application_path == NULL) {
- /* Not found. */
- err = ERROR_FILE_NOT_FOUND;
- goto done;
- }
-
- startup.cb = sizeof(startup);
- startup.lpReserved = NULL;
- startup.lpDesktop = NULL;
- startup.lpTitle = NULL;
- startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-
- startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
- startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
-
- startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
- startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
- startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
-
- process_flags = CREATE_UNICODE_ENVIRONMENT;
-
- if ((options->flags & UV_PROCESS_WINDOWS_HIDE_CONSOLE) ||
- (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
- /* Avoid creating console window if stdio is not inherited. */
- for (i = 0; i < options->stdio_count; i++) {
- if (options->stdio[i].flags & UV_INHERIT_FD)
- break;
- if (i == options->stdio_count - 1)
- process_flags |= CREATE_NO_WINDOW;
- }
- }
- if ((options->flags & UV_PROCESS_WINDOWS_HIDE_GUI) ||
- (options->flags & UV_PROCESS_WINDOWS_HIDE)) {
- /* Use SW_HIDE to avoid any potential process window. */
- startup.wShowWindow = SW_HIDE;
- } else {
- startup.wShowWindow = SW_SHOWDEFAULT;
- }
-
- if (options->flags & UV_PROCESS_DETACHED) {
- /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
- * means that libuv might not let you create a fully daemonized process
- * when run under job control. However the type of job control that libuv
- * itself creates doesn't trickle down to subprocesses so they can still
- * daemonize.
- *
- * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
- * CreateProcess call fail if we're under job control that doesn't allow
- * breakaway.
- */
- process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
- }
-
- if (!CreateProcessW(application_path,
- arguments,
- NULL,
- NULL,
- 1,
- process_flags,
- env,
- cwd,
- &startup,
- &info)) {
- /* CreateProcessW failed. */
- err = GetLastError();
- goto done;
- }
-
- /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
-
- process->process_handle = info.hProcess;
- process->pid = info.dwProcessId;
-
- /* If the process isn't spawned as detached, assign to the global job object
- * so windows will kill it when the parent process dies. */
- if (!(options->flags & UV_PROCESS_DETACHED)) {
- uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
-
- if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
- /* AssignProcessToJobObject might fail if this process is under job
- * control and the job doesn't have the
- * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
- * that doesn't support nested jobs.
- *
- * When that happens we just swallow the error and continue without
- * establishing a kill-child-on-parent-exit relationship, otherwise
- * there would be no way for libuv applications run under job control
- * to spawn processes at all.
- */
- DWORD err = GetLastError();
- if (err != ERROR_ACCESS_DENIED)
- uv_fatal_error(err, "AssignProcessToJobObject");
- }
- }
-
- /* Set IPC pid to all IPC pipes. */
- for (i = 0; i < options->stdio_count; i++) {
- const uv_stdio_container_t* fdopt = &options->stdio[i];
- if (fdopt->flags & UV_CREATE_PIPE &&
- fdopt->data.stream->type == UV_NAMED_PIPE &&
- ((uv_pipe_t*) fdopt->data.stream)->ipc) {
- ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_remote_pid =
- info.dwProcessId;
- }
- }
-
- /* Setup notifications for when the child process exits. */
- result = RegisterWaitForSingleObject(&process->wait_handle,
- process->process_handle, exit_wait_callback, (void*)process, INFINITE,
- WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
- if (!result) {
- uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
- }
-
- CloseHandle(info.hThread);
-
- assert(!err);
-
- /* Make the handle active. It will remain active until the exit callback is
- * made or the handle is closed, whichever happens first. */
- uv__handle_start(process);
-
- /* Cleanup, whether we succeeded or failed. */
- done:
- uv__free(application);
- uv__free(application_path);
- uv__free(arguments);
- uv__free(cwd);
- uv__free(env);
- uv__free(alloc_path);
-
- if (process->child_stdio_buffer != NULL) {
- /* Clean up child stdio handles. */
- uv__stdio_destroy(process->child_stdio_buffer);
- process->child_stdio_buffer = NULL;
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-static int uv__kill(HANDLE process_handle, int signum) {
- if (signum < 0 || signum >= NSIG) {
- return UV_EINVAL;
- }
-
- switch (signum) {
- case SIGTERM:
- case SIGKILL:
- case SIGINT: {
- /* Unconditionally terminate the process. On Windows, killed processes
- * normally return 1. */
- DWORD status;
- int err;
-
- if (TerminateProcess(process_handle, 1))
- return 0;
-
- /* If the process already exited before TerminateProcess was called,.
- * TerminateProcess will fail with ERROR_ACCESS_DENIED. */
- err = GetLastError();
- if (err == ERROR_ACCESS_DENIED &&
- GetExitCodeProcess(process_handle, &status) &&
- status != STILL_ACTIVE) {
- return UV_ESRCH;
- }
-
- return uv_translate_sys_error(err);
- }
-
- case 0: {
- /* Health check: is the process still alive? */
- DWORD status;
-
- if (!GetExitCodeProcess(process_handle, &status))
- return uv_translate_sys_error(GetLastError());
-
- if (status != STILL_ACTIVE)
- return UV_ESRCH;
-
- return 0;
- }
-
- default:
- /* Unsupported signal. */
- return UV_ENOSYS;
- }
-}
-
-
-int uv_process_kill(uv_process_t* process, int signum) {
- int err;
-
- if (process->process_handle == INVALID_HANDLE_VALUE) {
- return UV_EINVAL;
- }
-
- err = uv__kill(process->process_handle, signum);
- if (err) {
- return err; /* err is already translated. */
- }
-
- process->exit_signal = signum;
-
- return 0;
-}
-
-
-int uv_kill(int pid, int signum) {
- int err;
- HANDLE process_handle;
-
- if (pid == 0) {
- process_handle = GetCurrentProcess();
- } else {
- process_handle = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION,
- FALSE,
- pid);
- }
-
- if (process_handle == NULL) {
- err = GetLastError();
- if (err == ERROR_INVALID_PARAMETER) {
- return UV_ESRCH;
- } else {
- return uv_translate_sys_error(err);
- }
- }
-
- err = uv__kill(process_handle, signum);
- CloseHandle(process_handle);
-
- return err; /* err is already translated. */
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/req-inl.h b/wpiutil/src/main/native/libuv/src/win/req-inl.h
deleted file mode 100644
index f2513b7..0000000
--- a/wpiutil/src/main/native/libuv/src/win/req-inl.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_REQ_INL_H_
-#define UV_WIN_REQ_INL_H_
-
-#include <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-#define SET_REQ_STATUS(req, status) \
- (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
-
-#define SET_REQ_ERROR(req, error) \
- SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
-
-/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency
- * between src/uv-common.h and src/win/internal.h.
- */
-#define SET_REQ_SUCCESS(req) \
- SET_REQ_STATUS((req), STATUS_SUCCESS)
-
-#define GET_REQ_STATUS(req) \
- ((NTSTATUS) (req)->u.io.overlapped.Internal)
-
-#define REQ_SUCCESS(req) \
- (NT_SUCCESS(GET_REQ_STATUS((req))))
-
-#define GET_REQ_ERROR(req) \
- (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
-
-#define GET_REQ_SOCK_ERROR(req) \
- (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
-
-
-#define REGISTER_HANDLE_REQ(loop, handle, req) \
- do { \
- INCREASE_ACTIVE_COUNT((loop), (handle)); \
- uv__req_register((loop), (req)); \
- } while (0)
-
-#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
- do { \
- DECREASE_ACTIVE_COUNT((loop), (handle)); \
- uv__req_unregister((loop), (req)); \
- } while (0)
-
-
-#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
- ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
-
-#define UV_SUCCEEDED_WITH_IOCP(result) \
- ((result) || (GetLastError() == ERROR_IO_PENDING))
-
-
-#define POST_COMPLETION_FOR_REQ(loop, req) \
- if (!PostQueuedCompletionStatus((loop)->iocp, \
- 0, \
- 0, \
- &((req)->u.io.overlapped))) { \
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
- }
-
-
-INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
- return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
-}
-
-
-INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
- req->next_req = NULL;
- if (loop->pending_reqs_tail) {
-#ifdef _DEBUG
- /* Ensure the request is not already in the queue, or the queue
- * will get corrupted.
- */
- uv_req_t* current = loop->pending_reqs_tail;
- do {
- assert(req != current);
- current = current->next_req;
- } while(current != loop->pending_reqs_tail);
-#endif
-
- req->next_req = loop->pending_reqs_tail->next_req;
- loop->pending_reqs_tail->next_req = req;
- loop->pending_reqs_tail = req;
- } else {
- req->next_req = req;
- loop->pending_reqs_tail = req;
- }
-}
-
-
-#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
- do { \
- switch (((uv_handle_t*) (req)->handle_at)->type) { \
- case UV_TCP: \
- uv_process_tcp_##method##_req(loop, \
- (uv_tcp_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- case UV_NAMED_PIPE: \
- uv_process_pipe_##method##_req(loop, \
- (uv_pipe_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- case UV_TTY: \
- uv_process_tty_##method##_req(loop, \
- (uv_tty_t*) ((req)->handle_at), \
- req); \
- break; \
- \
- default: \
- assert(0); \
- } \
- } while (0)
-
-
-INLINE static int uv_process_reqs(uv_loop_t* loop) {
- uv_req_t* req;
- uv_req_t* first;
- uv_req_t* next;
-
- if (loop->pending_reqs_tail == NULL)
- return 0;
-
- first = loop->pending_reqs_tail->next_req;
- next = first;
- loop->pending_reqs_tail = NULL;
-
- while (next != NULL) {
- req = next;
- next = req->next_req != first ? req->next_req : NULL;
-
- switch (req->type) {
- case UV_READ:
- DELEGATE_STREAM_REQ(loop, req, read, data);
- break;
-
- case UV_WRITE:
- DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
- break;
-
- case UV_ACCEPT:
- DELEGATE_STREAM_REQ(loop, req, accept, data);
- break;
-
- case UV_CONNECT:
- DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
- break;
-
- case UV_SHUTDOWN:
- /* Tcp shutdown requests don't come here. */
- assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
- uv_process_pipe_shutdown_req(
- loop,
- (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
- (uv_shutdown_t*) req);
- break;
-
- case UV_UDP_RECV:
- uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
- break;
-
- case UV_UDP_SEND:
- uv_process_udp_send_req(loop,
- ((uv_udp_send_t*) req)->handle,
- (uv_udp_send_t*) req);
- break;
-
- case UV_WAKEUP:
- uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
- break;
-
- case UV_SIGNAL_REQ:
- uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
- break;
-
- case UV_POLL_REQ:
- uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
- break;
-
- case UV_PROCESS_EXIT:
- uv_process_proc_exit(loop, (uv_process_t*) req->data);
- break;
-
- case UV_FS_EVENT_REQ:
- uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
- break;
-
- default:
- assert(0);
- }
- }
-
- return 1;
-}
-
-#endif /* UV_WIN_REQ_INL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/signal.cpp b/wpiutil/src/main/native/libuv/src/win/signal.cpp
deleted file mode 100644
index 276dc60..0000000
--- a/wpiutil/src/main/native/libuv/src/win/signal.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- * 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 <assert.h>
-#include <signal.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-RB_HEAD(uv_signal_tree_s, uv_signal_s);
-
-static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
-static CRITICAL_SECTION uv__signal_lock;
-
-static BOOL WINAPI uv__signal_control_handler(DWORD type);
-
-int uv__signal_start(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum,
- int oneshot);
-
-void uv_signals_init(void) {
- InitializeCriticalSection(&uv__signal_lock);
- if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
- abort();
-}
-
-
-static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
- /* Compare signums first so all watchers with the same signnum end up
- * adjacent. */
- if (w1->signum < w2->signum) return -1;
- if (w1->signum > w2->signum) return 1;
-
- /* Sort by loop pointer, so we can easily look up the first item after
- * { .signum = x, .loop = NULL }. */
- if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
- if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
-
- if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
- if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
-
- return 0;
-}
-
-
-RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare)
-
-
-/*
- * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
- * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
- * no active signal watchers observing this signal.
- */
-int uv__signal_dispatch(int signum) {
- uv_signal_t lookup;
- uv_signal_t* handle;
- int dispatched;
-
- dispatched = 0;
-
- EnterCriticalSection(&uv__signal_lock);
-
- lookup.signum = signum;
- lookup.loop = NULL;
-
- for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
- handle != NULL && handle->signum == signum;
- handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
- unsigned long previous = InterlockedExchange(
- (volatile LONG*) &handle->pending_signum, signum);
-
- if (handle->flags & UV_SIGNAL_ONE_SHOT_DISPATCHED)
- continue;
-
- if (!previous) {
- POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
- }
-
- dispatched = 1;
- if (handle->flags & UV_SIGNAL_ONE_SHOT)
- handle->flags |= UV_SIGNAL_ONE_SHOT_DISPATCHED;
- }
-
- LeaveCriticalSection(&uv__signal_lock);
-
- return dispatched;
-}
-
-
-static BOOL WINAPI uv__signal_control_handler(DWORD type) {
- switch (type) {
- case CTRL_C_EVENT:
- return uv__signal_dispatch(SIGINT);
-
- case CTRL_BREAK_EVENT:
- return uv__signal_dispatch(SIGBREAK);
-
- case CTRL_CLOSE_EVENT:
- if (uv__signal_dispatch(SIGHUP)) {
- /* Windows will terminate the process after the control handler
- * returns. After that it will just terminate our process. Therefore
- * block the signal handler so the main loop has some time to pick up
- * the signal and do something for a few seconds. */
- Sleep(INFINITE);
- return TRUE;
- }
- return FALSE;
-
- case CTRL_LOGOFF_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- /* These signals are only sent to services. Services have their own
- * notification mechanism, so there's no point in handling these. */
-
- default:
- /* We don't handle these. */
- return FALSE;
- }
-}
-
-
-int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
- uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
- handle->pending_signum = 0;
- handle->signum = 0;
- handle->signal_cb = NULL;
-
- UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
- handle->signal_req.data = handle;
-
- return 0;
-}
-
-
-int uv_signal_stop(uv_signal_t* handle) {
- uv_signal_t* removed_handle;
-
- /* If the watcher wasn't started, this is a no-op. */
- if (handle->signum == 0)
- return 0;
-
- EnterCriticalSection(&uv__signal_lock);
-
- removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
- assert(removed_handle == handle);
-
- LeaveCriticalSection(&uv__signal_lock);
-
- handle->signum = 0;
- uv__handle_stop(handle);
-
- return 0;
-}
-
-
-int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
- return uv__signal_start(handle, signal_cb, signum, 0);
-}
-
-
-int uv_signal_start_oneshot(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum) {
- return uv__signal_start(handle, signal_cb, signum, 1);
-}
-
-
-int uv__signal_start(uv_signal_t* handle,
- uv_signal_cb signal_cb,
- int signum,
- int oneshot) {
- /* Test for invalid signal values. */
- if (signum <= 0 || signum >= NSIG)
- return UV_EINVAL;
-
- /* Short circuit: if the signal watcher is already watching {signum} don't go
- * through the process of deregistering and registering the handler.
- * Additionally, this avoids pending signals getting lost in the (small) time
- * frame that handle->signum == 0. */
- if (signum == handle->signum) {
- handle->signal_cb = signal_cb;
- return 0;
- }
-
- /* If the signal handler was already active, stop it first. */
- if (handle->signum != 0) {
- int r = uv_signal_stop(handle);
- /* uv_signal_stop is infallible. */
- assert(r == 0);
- }
-
- EnterCriticalSection(&uv__signal_lock);
-
- handle->signum = signum;
- if (oneshot)
- handle->flags |= UV_SIGNAL_ONE_SHOT;
-
- RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
-
- LeaveCriticalSection(&uv__signal_lock);
-
- handle->signal_cb = signal_cb;
- uv__handle_start(handle);
-
- return 0;
-}
-
-
-void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
- uv_req_t* req) {
- long dispatched_signum;
-
- assert(handle->type == UV_SIGNAL);
- assert(req->type == UV_SIGNAL_REQ);
-
- dispatched_signum = InterlockedExchange(
- (volatile LONG*) &handle->pending_signum, 0);
- assert(dispatched_signum != 0);
-
- /* Check if the pending signal equals the signum that we are watching for.
- * These can get out of sync when the handler is stopped and restarted while
- * the signal_req is pending. */
- if (dispatched_signum == handle->signum)
- handle->signal_cb(handle, dispatched_signum);
-
- if (handle->flags & UV_SIGNAL_ONE_SHOT)
- uv_signal_stop(handle);
-
- if (handle->flags & UV_HANDLE_CLOSING) {
- /* When it is closing, it must be stopped at this point. */
- assert(handle->signum == 0);
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-}
-
-
-void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
- uv_signal_stop(handle);
- uv__handle_closing(handle);
-
- if (handle->pending_signum == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-}
-
-
-void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
- assert(handle->flags & UV_HANDLE_CLOSING);
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- assert(handle->signum == 0);
- assert(handle->pending_signum == 0);
-
- handle->flags |= UV_HANDLE_CLOSED;
-
- uv__handle_close(handle);
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/snprintf.cpp b/wpiutil/src/main/native/libuv/src/win/snprintf.cpp
deleted file mode 100644
index 776c0e3..0000000
--- a/wpiutil/src/main/native/libuv/src/win/snprintf.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright the libuv project contributors. All rights reserved.
- *
- * 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.
- */
-
-#if defined(_MSC_VER) && _MSC_VER < 1900
-
-#include <stdio.h>
-#include <stdarg.h>
-
-/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
- * on overflow...
- */
-int snprintf(char* buf, size_t len, const char* fmt, ...) {
- int n;
- va_list ap;
- va_start(ap, fmt);
-
- n = _vscprintf(fmt, ap);
- vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
-
- va_end(ap);
- return n;
-}
-
-#endif
diff --git a/wpiutil/src/main/native/libuv/src/win/stream-inl.h b/wpiutil/src/main/native/libuv/src/win/stream-inl.h
deleted file mode 100644
index 40f5ddd..0000000
--- a/wpiutil/src/main/native/libuv/src/win/stream-inl.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_STREAM_INL_H_
-#define UV_WIN_STREAM_INL_H_
-
-#include <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-INLINE static void uv_stream_init(uv_loop_t* loop,
- uv_stream_t* handle,
- uv_handle_type type) {
- uv__handle_init(loop, (uv_handle_t*) handle, type);
- handle->write_queue_size = 0;
- handle->activecnt = 0;
- handle->stream.conn.shutdown_req = NULL;
- handle->stream.conn.write_reqs_pending = 0;
-
- UV_REQ_INIT(&handle->read_req, UV_READ);
- handle->read_req.event_handle = NULL;
- handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
- handle->read_req.data = handle;
-}
-
-
-INLINE static void uv_connection_init(uv_stream_t* handle) {
- handle->flags |= UV_HANDLE_CONNECTION;
-}
-
-
-#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/stream.cpp b/wpiutil/src/main/native/libuv/src/win/stream.cpp
deleted file mode 100644
index 7656627..0000000
--- a/wpiutil/src/main/native/libuv/src/win/stream.cpp
+++ /dev/null
@@ -1,240 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "req-inl.h"
-
-
-int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
- int err;
-
- err = ERROR_INVALID_PARAMETER;
- switch (stream->type) {
- case UV_TCP:
- err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
- break;
- case UV_NAMED_PIPE:
- err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
- break;
- default:
- assert(0);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-int uv_accept(uv_stream_t* server, uv_stream_t* client) {
- int err;
-
- err = ERROR_INVALID_PARAMETER;
- switch (server->type) {
- case UV_TCP:
- err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
- break;
- case UV_NAMED_PIPE:
- err = uv_pipe_accept((uv_pipe_t*)server, client);
- break;
- default:
- assert(0);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
- int err;
-
- if (handle->flags & UV_HANDLE_READING) {
- return UV_EALREADY;
- }
-
- if (!(handle->flags & UV_HANDLE_READABLE)) {
- return UV_ENOTCONN;
- }
-
- err = ERROR_INVALID_PARAMETER;
- switch (handle->type) {
- case UV_TCP:
- err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
- break;
- case UV_NAMED_PIPE:
- err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
- break;
- case UV_TTY:
- err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
- break;
- default:
- assert(0);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-int uv_read_stop(uv_stream_t* handle) {
- int err;
-
- if (!(handle->flags & UV_HANDLE_READING))
- return 0;
-
- err = 0;
- if (handle->type == UV_TTY) {
- err = uv_tty_read_stop((uv_tty_t*) handle);
- } else if (handle->type == UV_NAMED_PIPE) {
- uv__pipe_read_stop((uv_pipe_t*) handle);
- } else {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(handle->loop, handle);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-int uv_write(uv_write_t* req,
- uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_write_cb cb) {
- uv_loop_t* loop = handle->loop;
- int err;
-
- if (!(handle->flags & UV_HANDLE_WRITABLE)) {
- return UV_EPIPE;
- }
-
- err = ERROR_INVALID_PARAMETER;
- switch (handle->type) {
- case UV_TCP:
- err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
- break;
- case UV_NAMED_PIPE:
- err = uv__pipe_write(
- loop, req, (uv_pipe_t*) handle, bufs, nbufs, NULL, cb);
- break;
- case UV_TTY:
- err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
- break;
- default:
- assert(0);
- }
-
- return uv_translate_sys_error(err);
-}
-
-
-int uv_write2(uv_write_t* req,
- uv_stream_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_stream_t* send_handle,
- uv_write_cb cb) {
- uv_loop_t* loop = handle->loop;
- int err;
-
- if (send_handle == NULL) {
- return uv_write(req, handle, bufs, nbufs, cb);
- }
-
- if (handle->type != UV_NAMED_PIPE || !((uv_pipe_t*) handle)->ipc) {
- return UV_EINVAL;
- } else if (!(handle->flags & UV_HANDLE_WRITABLE)) {
- return UV_EPIPE;
- }
-
- err = uv__pipe_write(
- loop, req, (uv_pipe_t*) handle, bufs, nbufs, send_handle, cb);
- return uv_translate_sys_error(err);
-}
-
-
-int uv_try_write(uv_stream_t* stream,
- const uv_buf_t bufs[],
- unsigned int nbufs) {
- if (stream->flags & UV_HANDLE_CLOSING)
- return UV_EBADF;
- if (!(stream->flags & UV_HANDLE_WRITABLE))
- return UV_EPIPE;
-
- switch (stream->type) {
- case UV_TCP:
- return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
- case UV_TTY:
- return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
- case UV_NAMED_PIPE:
- return UV_EAGAIN;
- default:
- assert(0);
- return UV_ENOSYS;
- }
-}
-
-
-int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
- uv_loop_t* loop = handle->loop;
-
- if (!(handle->flags & UV_HANDLE_WRITABLE)) {
- return UV_EPIPE;
- }
-
- UV_REQ_INIT(req, UV_SHUTDOWN);
- req->handle = handle;
- req->cb = cb;
-
- handle->flags &= ~UV_HANDLE_WRITABLE;
- handle->stream.conn.shutdown_req = req;
- handle->reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
-
- uv_want_endgame(loop, (uv_handle_t*)handle);
-
- return 0;
-}
-
-
-int uv_is_readable(const uv_stream_t* handle) {
- return !!(handle->flags & UV_HANDLE_READABLE);
-}
-
-
-int uv_is_writable(const uv_stream_t* handle) {
- return !!(handle->flags & UV_HANDLE_WRITABLE);
-}
-
-
-int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
- if (handle->type != UV_NAMED_PIPE)
- return UV_EINVAL;
-
- if (blocking != 0)
- handle->flags |= UV_HANDLE_BLOCKING_WRITES;
- else
- handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/tcp.cpp b/wpiutil/src/main/native/libuv/src/win/tcp.cpp
deleted file mode 100644
index f2cb527..0000000
--- a/wpiutil/src/main/native/libuv/src/win/tcp.cpp
+++ /dev/null
@@ -1,1505 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "stream-inl.h"
-#include "req-inl.h"
-
-
-/*
- * Threshold of active tcp streams for which to preallocate tcp read buffers.
- * (Due to node slab allocator performing poorly under this pattern,
- * the optimization is temporarily disabled (threshold=0). This will be
- * revisited once node allocator is improved.)
- */
-const unsigned int uv_active_tcp_streams_threshold = 0;
-
-/*
- * Number of simultaneous pending AcceptEx calls.
- */
-const unsigned int uv_simultaneous_server_accepts = 32;
-
-/* A zero-size buffer for use by uv_tcp_read */
-static char uv_zero_[] = "";
-
-static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
- if (setsockopt(socket,
- IPPROTO_TCP,
- TCP_NODELAY,
- (const char*)&enable,
- sizeof enable) == -1) {
- return WSAGetLastError();
- }
- return 0;
-}
-
-
-static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
- if (setsockopt(socket,
- SOL_SOCKET,
- SO_KEEPALIVE,
- (const char*)&enable,
- sizeof enable) == -1) {
- return WSAGetLastError();
- }
-
- if (enable && setsockopt(socket,
- IPPROTO_TCP,
- TCP_KEEPALIVE,
- (const char*)&delay,
- sizeof delay) == -1) {
- return WSAGetLastError();
- }
-
- return 0;
-}
-
-
-static int uv_tcp_set_socket(uv_loop_t* loop,
- uv_tcp_t* handle,
- SOCKET socket,
- int family,
- int imported) {
- DWORD yes = 1;
- int non_ifs_lsp;
- int err;
-
- if (handle->socket != INVALID_SOCKET)
- return UV_EBUSY;
-
- /* Set the socket to nonblocking mode */
- if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
- return WSAGetLastError();
- }
-
- /* Make the socket non-inheritable */
- if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
- return GetLastError();
-
- /* Associate it with the I/O completion port. Use uv_handle_t pointer as
- * completion key. */
- if (CreateIoCompletionPort((HANDLE)socket,
- loop->iocp,
- (ULONG_PTR)socket,
- 0) == NULL) {
- if (imported) {
- handle->flags |= UV_HANDLE_EMULATE_IOCP;
- } else {
- return GetLastError();
- }
- }
-
- if (family == AF_INET6) {
- non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6;
- } else {
- non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
- }
-
- if (!(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
- UCHAR sfcnm_flags =
- FILE_SKIP_SET_EVENT_ON_HANDLE | FILE_SKIP_COMPLETION_PORT_ON_SUCCESS;
- if (!SetFileCompletionNotificationModes((HANDLE) socket, sfcnm_flags))
- return GetLastError();
- handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
- }
-
- if (handle->flags & UV_HANDLE_TCP_NODELAY) {
- err = uv__tcp_nodelay(handle, socket, 1);
- if (err)
- return err;
- }
-
- /* TODO: Use stored delay. */
- if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) {
- err = uv__tcp_keepalive(handle, socket, 1, 60);
- if (err)
- return err;
- }
-
- handle->socket = socket;
-
- if (family == AF_INET6) {
- handle->flags |= UV_HANDLE_IPV6;
- } else {
- assert(!(handle->flags & UV_HANDLE_IPV6));
- }
-
- return 0;
-}
-
-
-int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
- int domain;
-
- /* Use the lower 8 bits for the domain */
- domain = flags & 0xFF;
- if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
- return UV_EINVAL;
-
- if (flags & ~0xFF)
- return UV_EINVAL;
-
- uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
- handle->tcp.serv.accept_reqs = NULL;
- handle->tcp.serv.pending_accepts = NULL;
- handle->socket = INVALID_SOCKET;
- handle->reqs_pending = 0;
- handle->tcp.serv.func_acceptex = NULL;
- handle->tcp.conn.func_connectex = NULL;
- handle->tcp.serv.processed_accepts = 0;
- handle->delayed_error = 0;
-
- /* If anything fails beyond this point we need to remove the handle from
- * the handle queue, since it was added by uv__handle_init in uv_stream_init.
- */
-
- if (domain != AF_UNSPEC) {
- SOCKET sock;
- DWORD err;
-
- sock = socket(domain, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- err = WSAGetLastError();
- QUEUE_REMOVE(&handle->handle_queue);
- return uv_translate_sys_error(err);
- }
-
- err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
- if (err) {
- closesocket(sock);
- QUEUE_REMOVE(&handle->handle_queue);
- return uv_translate_sys_error(err);
- }
-
- }
-
- return 0;
-}
-
-
-int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
- return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
-}
-
-
-void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
- int err;
- unsigned int i;
- uv_tcp_accept_t* req;
-
- if (handle->flags & UV_HANDLE_CONNECTION &&
- handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
-
- UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
-
- err = 0;
- if (handle->flags & UV_HANDLE_CLOSING) {
- err = ERROR_OPERATION_ABORTED;
- } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
- err = WSAGetLastError();
- }
-
- if (handle->stream.conn.shutdown_req->cb) {
- handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
- uv_translate_sys_error(err));
- }
-
- handle->stream.conn.shutdown_req = NULL;
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
-
- if (handle->flags & UV_HANDLE_CLOSING &&
- handle->reqs_pending == 0) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
-
- if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
- closesocket(handle->socket);
- handle->socket = INVALID_SOCKET;
- handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
- }
-
- if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- for (i = 0; i < uv_simultaneous_server_accepts; i++) {
- req = &handle->tcp.serv.accept_reqs[i];
- if (req->wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(req->wait_handle);
- req->wait_handle = INVALID_HANDLE_VALUE;
- }
- if (req->event_handle) {
- CloseHandle(req->event_handle);
- req->event_handle = NULL;
- }
- }
- }
-
- uv__free(handle->tcp.serv.accept_reqs);
- handle->tcp.serv.accept_reqs = NULL;
- }
-
- if (handle->flags & UV_HANDLE_CONNECTION &&
- handle->flags & UV_HANDLE_EMULATE_IOCP) {
- if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(handle->read_req.wait_handle);
- handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
- }
- if (handle->read_req.event_handle) {
- CloseHandle(handle->read_req.event_handle);
- handle->read_req.event_handle = NULL;
- }
- }
-
- uv__handle_close(handle);
- loop->active_tcp_streams--;
- }
-}
-
-
-/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
- * allow binding to addresses that are in use by sockets in TIME_WAIT, it
- * effectively allows 'stealing' a port which is in use by another application.
- *
- * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets,
- * regardless of state, so we'd get an error even if the port is in use by a
- * socket in TIME_WAIT state.
- *
- * See issue #1360.
- *
- */
-static int uv_tcp_try_bind(uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- DWORD err;
- int r;
-
- if (handle->socket == INVALID_SOCKET) {
- SOCKET sock;
-
- /* Cannot set IPv6-only mode on non-IPv6 socket. */
- if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
- return ERROR_INVALID_PARAMETER;
-
- sock = socket(addr->sa_family, SOCK_STREAM, 0);
- if (sock == INVALID_SOCKET) {
- return WSAGetLastError();
- }
-
- err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
- if (err) {
- closesocket(sock);
- return err;
- }
- }
-
-#ifdef IPV6_V6ONLY
- if (addr->sa_family == AF_INET6) {
- int on;
-
- on = (flags & UV_TCP_IPV6ONLY) != 0;
-
- /* TODO: how to handle errors? This may fail if there is no ipv4 stack
- * available, or when run on XP/2003 which have no support for dualstack
- * sockets. For now we're silently ignoring the error. */
- setsockopt(handle->socket,
- IPPROTO_IPV6,
- IPV6_V6ONLY,
- (const char*)&on,
- sizeof on);
- }
-#endif
-
- r = bind(handle->socket, addr, addrlen);
-
- if (r == SOCKET_ERROR) {
- err = WSAGetLastError();
- if (err == WSAEADDRINUSE) {
- /* Some errors are not to be reported until connect() or listen() */
- handle->delayed_error = err;
- } else {
- return err;
- }
- }
-
- handle->flags |= UV_HANDLE_BOUND;
-
- return 0;
-}
-
-
-static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
- uv_req_t* req;
- uv_tcp_t* handle;
-
- req = (uv_req_t*) context;
- assert(req != NULL);
- handle = (uv_tcp_t*)req->data;
- assert(handle != NULL);
- assert(!timed_out);
-
- if (!PostQueuedCompletionStatus(handle->loop->iocp,
- req->u.io.overlapped.InternalHigh,
- 0,
- &req->u.io.overlapped)) {
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
- }
-}
-
-
-static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
- uv_write_t* req;
- uv_tcp_t* handle;
-
- req = (uv_write_t*) context;
- assert(req != NULL);
- handle = (uv_tcp_t*)req->handle;
- assert(handle != NULL);
- assert(!timed_out);
-
- if (!PostQueuedCompletionStatus(handle->loop->iocp,
- req->u.io.overlapped.InternalHigh,
- 0,
- &req->u.io.overlapped)) {
- uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
- }
-}
-
-
-static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
- uv_loop_t* loop = handle->loop;
- BOOL success;
- DWORD bytes;
- SOCKET accept_socket;
- short family;
-
- assert(handle->flags & UV_HANDLE_LISTENING);
- assert(req->accept_socket == INVALID_SOCKET);
-
- /* choose family and extension function */
- if (handle->flags & UV_HANDLE_IPV6) {
- family = AF_INET6;
- } else {
- family = AF_INET;
- }
-
- /* Open a socket for the accepted connection. */
- accept_socket = socket(family, SOCK_STREAM, 0);
- if (accept_socket == INVALID_SOCKET) {
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- handle->reqs_pending++;
- return;
- }
-
- /* Make the socket non-inheritable */
- if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- handle->reqs_pending++;
- closesocket(accept_socket);
- return;
- }
-
- /* Prepare the overlapped structure. */
- memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
- }
-
- success = handle->tcp.serv.func_acceptex(handle->socket,
- accept_socket,
- (void*)req->accept_buffer,
- 0,
- sizeof(struct sockaddr_storage),
- sizeof(struct sockaddr_storage),
- &bytes,
- &req->u.io.overlapped);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
- /* Process the req without IOCP. */
- req->accept_socket = accept_socket;
- handle->reqs_pending++;
- uv_insert_pending_req(loop, (uv_req_t*)req);
- } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
- /* The req will be processed with IOCP. */
- req->accept_socket = accept_socket;
- handle->reqs_pending++;
- if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
- req->wait_handle == INVALID_HANDLE_VALUE &&
- !RegisterWaitForSingleObject(&req->wait_handle,
- req->event_handle, post_completion, (void*) req,
- INFINITE, WT_EXECUTEINWAITTHREAD)) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- }
- } else {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- handle->reqs_pending++;
- /* Destroy the preallocated client socket. */
- closesocket(accept_socket);
- /* Destroy the event handle */
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- CloseHandle(req->u.io.overlapped.hEvent);
- req->event_handle = NULL;
- }
- }
-}
-
-
-static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
- uv_read_t* req;
- uv_buf_t buf;
- int result;
- DWORD bytes, flags;
-
- assert(handle->flags & UV_HANDLE_READING);
- assert(!(handle->flags & UV_HANDLE_READ_PENDING));
-
- req = &handle->read_req;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- /*
- * Preallocate a read buffer if the number of active streams is below
- * the threshold.
- */
- if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
- handle->flags &= ~UV_HANDLE_ZERO_READ;
- handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
- if (handle->tcp.conn.read_buffer.base == NULL ||
- handle->tcp.conn.read_buffer.len == 0) {
- handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
- return;
- }
- assert(handle->tcp.conn.read_buffer.base != NULL);
- buf = handle->tcp.conn.read_buffer;
- } else {
- handle->flags |= UV_HANDLE_ZERO_READ;
- buf.base = (char*) &uv_zero_;
- buf.len = 0;
- }
-
- /* Prepare the overlapped structure. */
- memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- assert(req->event_handle);
- req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
- }
-
- flags = 0;
- result = WSARecv(handle->socket,
- (WSABUF*)&buf,
- 1,
- &bytes,
- &flags,
- &req->u.io.overlapped,
- NULL);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
- /* Process the req without IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- req->u.io.overlapped.InternalHigh = bytes;
- handle->reqs_pending++;
- uv_insert_pending_req(loop, (uv_req_t*)req);
- } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
- /* The req will be processed with IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
- if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
- req->wait_handle == INVALID_HANDLE_VALUE &&
- !RegisterWaitForSingleObject(&req->wait_handle,
- req->event_handle, post_completion, (void*) req,
- INFINITE, WT_EXECUTEINWAITTHREAD)) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- }
- } else {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- handle->reqs_pending++;
- }
-}
-
-
-int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
- unsigned int i, simultaneous_accepts;
- uv_tcp_accept_t* req;
- int err;
-
- assert(backlog > 0);
-
- if (handle->flags & UV_HANDLE_LISTENING) {
- handle->stream.serv.connection_cb = cb;
- }
-
- if (handle->flags & UV_HANDLE_READING) {
- return WSAEISCONN;
- }
-
- if (handle->delayed_error) {
- return handle->delayed_error;
- }
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- err = uv_tcp_try_bind(handle,
- (const struct sockaddr*) &uv_addr_ip4_any_,
- sizeof(uv_addr_ip4_any_),
- 0);
- if (err)
- return err;
- if (handle->delayed_error)
- return handle->delayed_error;
- }
-
- if (!handle->tcp.serv.func_acceptex) {
- if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
- return WSAEAFNOSUPPORT;
- }
- }
-
- if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
- listen(handle->socket, backlog) == SOCKET_ERROR) {
- return WSAGetLastError();
- }
-
- handle->flags |= UV_HANDLE_LISTENING;
- handle->stream.serv.connection_cb = cb;
- INCREASE_ACTIVE_COUNT(loop, handle);
-
- simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
- : uv_simultaneous_server_accepts;
-
- if(!handle->tcp.serv.accept_reqs) {
- handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
- uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
- if (!handle->tcp.serv.accept_reqs) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- for (i = 0; i < simultaneous_accepts; i++) {
- req = &handle->tcp.serv.accept_reqs[i];
- UV_REQ_INIT(req, UV_ACCEPT);
- req->accept_socket = INVALID_SOCKET;
- req->data = handle;
-
- req->wait_handle = INVALID_HANDLE_VALUE;
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- req->event_handle = CreateEvent(NULL, 0, 0, NULL);
- if (!req->event_handle) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
- } else {
- req->event_handle = NULL;
- }
-
- uv_tcp_queue_accept(handle, req);
- }
-
- /* Initialize other unused requests too, because uv_tcp_endgame doesn't
- * know how many requests were initialized, so it will try to clean up
- * {uv_simultaneous_server_accepts} requests. */
- for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
- req = &handle->tcp.serv.accept_reqs[i];
- UV_REQ_INIT(req, UV_ACCEPT);
- req->accept_socket = INVALID_SOCKET;
- req->data = handle;
- req->wait_handle = INVALID_HANDLE_VALUE;
- req->event_handle = NULL;
- }
- }
-
- return 0;
-}
-
-
-int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
- uv_loop_t* loop = server->loop;
- int err = 0;
- int family;
-
- uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
-
- if (!req) {
- /* No valid connections found, so we error out. */
- return WSAEWOULDBLOCK;
- }
-
- if (req->accept_socket == INVALID_SOCKET) {
- return WSAENOTCONN;
- }
-
- if (server->flags & UV_HANDLE_IPV6) {
- family = AF_INET6;
- } else {
- family = AF_INET;
- }
-
- err = uv_tcp_set_socket(client->loop,
- client,
- req->accept_socket,
- family,
- 0);
- if (err) {
- closesocket(req->accept_socket);
- } else {
- uv_connection_init((uv_stream_t*) client);
- /* AcceptEx() implicitly binds the accepted socket. */
- client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
- }
-
- /* Prepare the req to pick up a new connection */
- server->tcp.serv.pending_accepts = req->next_pending;
- req->next_pending = NULL;
- req->accept_socket = INVALID_SOCKET;
-
- if (!(server->flags & UV_HANDLE_CLOSING)) {
- /* Check if we're in a middle of changing the number of pending accepts. */
- if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
- uv_tcp_queue_accept(server, req);
- } else {
- /* We better be switching to a single pending accept. */
- assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
-
- server->tcp.serv.processed_accepts++;
-
- if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
- server->tcp.serv.processed_accepts = 0;
- /*
- * All previously queued accept requests are now processed.
- * We now switch to queueing just a single accept.
- */
- uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
- server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
- server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
- }
- }
- }
-
- loop->active_tcp_streams++;
-
- return err;
-}
-
-
-int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
- uv_loop_t* loop = handle->loop;
-
- handle->flags |= UV_HANDLE_READING;
- handle->read_cb = read_cb;
- handle->alloc_cb = alloc_cb;
- INCREASE_ACTIVE_COUNT(loop, handle);
-
- /* If reading was stopped and then started again, there could still be a read
- * request pending. */
- if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
- if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
- !handle->read_req.event_handle) {
- handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
- if (!handle->read_req.event_handle) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
- }
- uv_tcp_queue_read(loop, handle);
- }
-
- return 0;
-}
-
-
-static int uv_tcp_try_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_connect_cb cb) {
- uv_loop_t* loop = handle->loop;
- const struct sockaddr* bind_addr;
- struct sockaddr_storage converted;
- BOOL success;
- DWORD bytes;
- int err;
-
- err = uv__convert_to_localhost_if_unspecified(addr, &converted);
- if (err)
- return err;
-
- if (handle->delayed_error) {
- return handle->delayed_error;
- }
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_)) {
- bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
- bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- } else {
- abort();
- }
- err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
- if (err)
- return err;
- if (handle->delayed_error)
- return handle->delayed_error;
- }
-
- if (!handle->tcp.conn.func_connectex) {
- if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
- return WSAEAFNOSUPPORT;
- }
- }
-
- UV_REQ_INIT(req, UV_CONNECT);
- req->handle = (uv_stream_t*) handle;
- req->cb = cb;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- success = handle->tcp.conn.func_connectex(handle->socket,
- (const struct sockaddr*) &converted,
- addrlen,
- NULL,
- 0,
- &bytes,
- &req->u.io.overlapped);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
- /* Process the req without IOCP. */
- handle->reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- uv_insert_pending_req(loop, (uv_req_t*)req);
- } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
- /* The req will be processed with IOCP. */
- handle->reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- } else {
- return WSAGetLastError();
- }
-
- return 0;
-}
-
-
-int uv_tcp_getsockname(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getsockname,
- name,
- namelen,
- handle->delayed_error);
-}
-
-
-int uv_tcp_getpeername(const uv_tcp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getpeername,
- name,
- namelen,
- handle->delayed_error);
-}
-
-
-int uv_tcp_write(uv_loop_t* loop,
- uv_write_t* req,
- uv_tcp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_write_cb cb) {
- int result;
- DWORD bytes;
-
- UV_REQ_INIT(req, UV_WRITE);
- req->handle = (uv_stream_t*) handle;
- req->cb = cb;
-
- /* Prepare the overlapped structure. */
- memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- req->event_handle = CreateEvent(NULL, 0, 0, NULL);
- if (!req->event_handle) {
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
- req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
- req->wait_handle = INVALID_HANDLE_VALUE;
- }
-
- result = WSASend(handle->socket,
- (WSABUF*) bufs,
- nbufs,
- &bytes,
- 0,
- &req->u.io.overlapped,
- NULL);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
- /* Request completed immediately. */
- req->u.io.queued_bytes = 0;
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- uv_insert_pending_req(loop, (uv_req_t*) req);
- } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
- /* Request queued by the kernel. */
- req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- handle->write_queue_size += req->u.io.queued_bytes;
- if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
- !RegisterWaitForSingleObject(&req->wait_handle,
- req->event_handle, post_write_completion, (void*) req,
- INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- }
- } else {
- /* Send failed due to an error, report it later */
- req->u.io.queued_bytes = 0;
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, (uv_req_t*) req);
- }
-
- return 0;
-}
-
-
-int uv__tcp_try_write(uv_tcp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs) {
- int result;
- DWORD bytes;
-
- if (handle->stream.conn.write_reqs_pending > 0)
- return UV_EAGAIN;
-
- result = WSASend(handle->socket,
- (WSABUF*) bufs,
- nbufs,
- &bytes,
- 0,
- NULL,
- NULL);
-
- if (result == SOCKET_ERROR)
- return uv_translate_sys_error(WSAGetLastError());
- else
- return bytes;
-}
-
-
-void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_req_t* req) {
- DWORD bytes, flags, err;
- uv_buf_t buf;
- int count;
-
- assert(handle->type == UV_TCP);
-
- handle->flags &= ~UV_HANDLE_READ_PENDING;
-
- if (!REQ_SUCCESS(req)) {
- /* An error occurred doing the read. */
- if ((handle->flags & UV_HANDLE_READING) ||
- !(handle->flags & UV_HANDLE_ZERO_READ)) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
- uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
-
- err = GET_REQ_SOCK_ERROR(req);
-
- if (err == WSAECONNABORTED) {
- /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
- */
- err = WSAECONNRESET;
- }
-
- handle->read_cb((uv_stream_t*)handle,
- uv_translate_sys_error(err),
- &buf);
- }
- } else {
- if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
- /* The read was done with a non-zero buffer length. */
- if (req->u.io.overlapped.InternalHigh > 0) {
- /* Successful read */
- handle->read_cb((uv_stream_t*)handle,
- req->u.io.overlapped.InternalHigh,
- &handle->tcp.conn.read_buffer);
- /* Read again only if bytes == buf.len */
- if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
- goto done;
- }
- } else {
- /* Connection closed */
- if (handle->flags & UV_HANDLE_READING) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- }
- handle->flags &= ~UV_HANDLE_READABLE;
-
- buf.base = 0;
- buf.len = 0;
- handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
- goto done;
- }
- }
-
- /* Do nonblocking reads until the buffer is empty */
- count = 32;
- while ((handle->flags & UV_HANDLE_READING) && (count-- > 0)) {
- buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
- if (buf.base == NULL || buf.len == 0) {
- handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
- break;
- }
- assert(buf.base != NULL);
-
- flags = 0;
- if (WSARecv(handle->socket,
- (WSABUF*)&buf,
- 1,
- &bytes,
- &flags,
- NULL,
- NULL) != SOCKET_ERROR) {
- if (bytes > 0) {
- /* Successful read */
- handle->read_cb((uv_stream_t*)handle, bytes, &buf);
- /* Read again only if bytes == buf.len */
- if (bytes < buf.len) {
- break;
- }
- } else {
- /* Connection closed */
- handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
- DECREASE_ACTIVE_COUNT(loop, handle);
-
- handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
- break;
- }
- } else {
- err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
- /* Read buffer was completely empty, report a 0-byte read. */
- handle->read_cb((uv_stream_t*)handle, 0, &buf);
- } else {
- /* Ouch! serious error. */
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
-
- if (err == WSAECONNABORTED) {
- /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with
- * Unix. */
- err = WSAECONNRESET;
- }
-
- handle->read_cb((uv_stream_t*)handle,
- uv_translate_sys_error(err),
- &buf);
- }
- break;
- }
- }
-
-done:
- /* Post another read if still reading and not closing. */
- if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_READ_PENDING)) {
- uv_tcp_queue_read(loop, handle);
- }
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_write_t* req) {
- int err;
-
- assert(handle->type == UV_TCP);
-
- assert(handle->write_queue_size >= req->u.io.queued_bytes);
- handle->write_queue_size -= req->u.io.queued_bytes;
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
- if (req->wait_handle != INVALID_HANDLE_VALUE) {
- UnregisterWait(req->wait_handle);
- req->wait_handle = INVALID_HANDLE_VALUE;
- }
- if (req->event_handle) {
- CloseHandle(req->event_handle);
- req->event_handle = NULL;
- }
- }
-
- if (req->cb) {
- err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
- if (err == UV_ECONNABORTED) {
- /* use UV_ECANCELED for consistency with Unix */
- err = UV_ECANCELED;
- }
- req->cb(req, err);
- }
-
- handle->stream.conn.write_reqs_pending--;
- if (handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_req_t* raw_req) {
- uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
- int err;
-
- assert(handle->type == UV_TCP);
-
- /* If handle->accepted_socket is not a valid socket, then uv_queue_accept
- * must have failed. This is a serious error. We stop accepting connections
- * and report this error to the connection callback. */
- if (req->accept_socket == INVALID_SOCKET) {
- if (handle->flags & UV_HANDLE_LISTENING) {
- handle->flags &= ~UV_HANDLE_LISTENING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- if (handle->stream.serv.connection_cb) {
- err = GET_REQ_SOCK_ERROR(req);
- handle->stream.serv.connection_cb((uv_stream_t*)handle,
- uv_translate_sys_error(err));
- }
- }
- } else if (REQ_SUCCESS(req) &&
- setsockopt(req->accept_socket,
- SOL_SOCKET,
- SO_UPDATE_ACCEPT_CONTEXT,
- (char*)&handle->socket,
- sizeof(handle->socket)) == 0) {
- req->next_pending = handle->tcp.serv.pending_accepts;
- handle->tcp.serv.pending_accepts = req;
-
- /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
- if (handle->stream.serv.connection_cb) {
- handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
- }
- } else {
- /* Error related to accepted socket is ignored because the server socket
- * may still be healthy. If the server socket is broken uv_queue_accept
- * will detect it. */
- closesocket(req->accept_socket);
- req->accept_socket = INVALID_SOCKET;
- if (handle->flags & UV_HANDLE_LISTENING) {
- uv_tcp_queue_accept(handle, req);
- }
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
- uv_connect_t* req) {
- int err;
-
- assert(handle->type == UV_TCP);
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- err = 0;
- if (REQ_SUCCESS(req)) {
- if (handle->flags & UV_HANDLE_CLOSING) {
- /* use UV_ECANCELED for consistency with Unix */
- err = ERROR_OPERATION_ABORTED;
- } else if (setsockopt(handle->socket,
- SOL_SOCKET,
- SO_UPDATE_CONNECT_CONTEXT,
- NULL,
- 0) == 0) {
- uv_connection_init((uv_stream_t*)handle);
- handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
- loop->active_tcp_streams++;
- } else {
- err = WSAGetLastError();
- }
- } else {
- err = GET_REQ_SOCK_ERROR(req);
- }
- req->cb(req, uv_translate_sys_error(err));
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-int uv__tcp_xfer_export(uv_tcp_t* handle,
- int target_pid,
- uv__ipc_socket_xfer_type_t* xfer_type,
- uv__ipc_socket_xfer_info_t* xfer_info) {
- if (handle->flags & UV_HANDLE_CONNECTION) {
- *xfer_type = UV__IPC_SOCKET_XFER_TCP_CONNECTION;
- } else {
- *xfer_type = UV__IPC_SOCKET_XFER_TCP_SERVER;
- /* We're about to share the socket with another process. Because this is a
- * listening socket, we assume that the other process will be accepting
- * connections on it. Thus, before sharing the socket with another process,
- * we call listen here in the parent process. */
- if (!(handle->flags & UV_HANDLE_LISTENING)) {
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- return ERROR_NOT_SUPPORTED;
- }
- if (handle->delayed_error == 0 &&
- listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
- handle->delayed_error = WSAGetLastError();
- }
- }
- }
-
- if (WSADuplicateSocketW(handle->socket, target_pid, &xfer_info->socket_info))
- return WSAGetLastError();
- xfer_info->delayed_error = handle->delayed_error;
-
- /* Mark the local copy of the handle as 'shared' so we behave in a way that's
- * friendly to the process(es) that we share the socket with. */
- handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
-
- return 0;
-}
-
-
-int uv__tcp_xfer_import(uv_tcp_t* tcp,
- uv__ipc_socket_xfer_type_t xfer_type,
- uv__ipc_socket_xfer_info_t* xfer_info) {
- int err;
- SOCKET socket;
-
- assert(xfer_type == UV__IPC_SOCKET_XFER_TCP_SERVER ||
- xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION);
-
- socket = WSASocketW(FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- FROM_PROTOCOL_INFO,
- &xfer_info->socket_info,
- 0,
- WSA_FLAG_OVERLAPPED);
-
- if (socket == INVALID_SOCKET) {
- return WSAGetLastError();
- }
-
- err = uv_tcp_set_socket(
- tcp->loop, tcp, socket, xfer_info->socket_info.iAddressFamily, 1);
- if (err) {
- closesocket(socket);
- return err;
- }
-
- tcp->delayed_error = xfer_info->delayed_error;
- tcp->flags |= UV_HANDLE_BOUND | UV_HANDLE_SHARED_TCP_SOCKET;
-
- if (xfer_type == UV__IPC_SOCKET_XFER_TCP_CONNECTION) {
- uv_connection_init((uv_stream_t*)tcp);
- tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
- }
-
- tcp->loop->active_tcp_streams++;
- return 0;
-}
-
-
-int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
- int err;
-
- if (handle->socket != INVALID_SOCKET) {
- err = uv__tcp_nodelay(handle, handle->socket, enable);
- if (err)
- return err;
- }
-
- if (enable) {
- handle->flags |= UV_HANDLE_TCP_NODELAY;
- } else {
- handle->flags &= ~UV_HANDLE_TCP_NODELAY;
- }
-
- return 0;
-}
-
-
-int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
- int err;
-
- if (handle->socket != INVALID_SOCKET) {
- err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
- if (err)
- return err;
- }
-
- if (enable) {
- handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
- } else {
- handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
- }
-
- /* TODO: Store delay if handle->socket isn't created yet. */
-
- return 0;
-}
-
-
-int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
- if (handle->flags & UV_HANDLE_CONNECTION) {
- return UV_EINVAL;
- }
-
- /* Check if we're already in the desired mode. */
- if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
- (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
- return 0;
- }
-
- /* Don't allow switching from single pending accept to many. */
- if (enable) {
- return UV_ENOTSUP;
- }
-
- /* Check if we're in a middle of changing the number of pending accepts. */
- if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
- return 0;
- }
-
- handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
-
- /* Flip the changing flag if we have already queued multiple accepts. */
- if (handle->flags & UV_HANDLE_LISTENING) {
- handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
- }
-
- return 0;
-}
-
-
-static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
- SOCKET socket = tcp->socket;
- int non_ifs_lsp;
-
- /* Check if we have any non-IFS LSPs stacked on top of TCP */
- non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
- uv_tcp_non_ifs_lsp_ipv4;
-
- /* If there are non-ifs LSPs then try to obtain a base handle for the socket.
- * This will always fail on Windows XP/3k. */
- if (non_ifs_lsp) {
- DWORD bytes;
- if (WSAIoctl(socket,
- SIO_BASE_HANDLE,
- NULL,
- 0,
- &socket,
- sizeof socket,
- &bytes,
- NULL,
- NULL) != 0) {
- /* Failed. We can't do CancelIo. */
- return -1;
- }
- }
-
- assert(socket != 0 && socket != INVALID_SOCKET);
-
- if (!CancelIo((HANDLE) socket)) {
- return GetLastError();
- }
-
- /* It worked. */
- return 0;
-}
-
-
-void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
- int close_socket = 1;
-
- if (tcp->flags & UV_HANDLE_READ_PENDING) {
- /* In order for winsock to do a graceful close there must not be any any
- * pending reads, or the socket must be shut down for writing */
- if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
- /* Just do shutdown on non-shared sockets, which ensures graceful close. */
- shutdown(tcp->socket, SD_SEND);
-
- } else if (uv_tcp_try_cancel_io(tcp) == 0) {
- /* In case of a shared socket, we try to cancel all outstanding I/O,. If
- * that works, don't close the socket yet - wait for the read req to
- * return and close the socket in uv_tcp_endgame. */
- close_socket = 0;
-
- } else {
- /* When cancelling isn't possible - which could happen when an LSP is
- * present on an old Windows version, we will have to close the socket
- * with a read pending. That is not nice because trailing sent bytes may
- * not make it to the other side. */
- }
-
- } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
- tcp->tcp.serv.accept_reqs != NULL) {
- /* Under normal circumstances closesocket() will ensure that all pending
- * accept reqs are canceled. However, when the socket is shared the
- * presence of another reference to the socket in another process will keep
- * the accept reqs going, so we have to ensure that these are canceled. */
- if (uv_tcp_try_cancel_io(tcp) != 0) {
- /* When cancellation is not possible, there is another option: we can
- * close the incoming sockets, which will also cancel the accept
- * operations. However this is not cool because we might inadvertently
- * close a socket that just accepted a new connection, which will cause
- * the connection to be aborted. */
- unsigned int i;
- for (i = 0; i < uv_simultaneous_server_accepts; i++) {
- uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
- if (req->accept_socket != INVALID_SOCKET &&
- !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
- closesocket(req->accept_socket);
- req->accept_socket = INVALID_SOCKET;
- }
- }
- }
- }
-
- if (tcp->flags & UV_HANDLE_READING) {
- tcp->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, tcp);
- }
-
- if (tcp->flags & UV_HANDLE_LISTENING) {
- tcp->flags &= ~UV_HANDLE_LISTENING;
- DECREASE_ACTIVE_COUNT(loop, tcp);
- }
-
- if (close_socket) {
- closesocket(tcp->socket);
- tcp->socket = INVALID_SOCKET;
- tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
- }
-
- tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- uv__handle_closing(tcp);
-
- if (tcp->reqs_pending == 0) {
- uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
- }
-}
-
-
-int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
- WSAPROTOCOL_INFOW protocol_info;
- int opt_len;
- int err;
- struct sockaddr_storage saddr;
- int saddr_len;
-
- /* Detect the address family of the socket. */
- opt_len = (int) sizeof protocol_info;
- if (getsockopt(sock,
- SOL_SOCKET,
- SO_PROTOCOL_INFOW,
- (char*) &protocol_info,
- &opt_len) == SOCKET_ERROR) {
- return uv_translate_sys_error(GetLastError());
- }
-
- err = uv_tcp_set_socket(handle->loop,
- handle,
- sock,
- protocol_info.iAddressFamily,
- 1);
- if (err) {
- return uv_translate_sys_error(err);
- }
-
- /* Support already active socket. */
- saddr_len = sizeof(saddr);
- if (!uv_tcp_getsockname(handle, (struct sockaddr*) &saddr, &saddr_len)) {
- /* Socket is already bound. */
- handle->flags |= UV_HANDLE_BOUND;
- saddr_len = sizeof(saddr);
- if (!uv_tcp_getpeername(handle, (struct sockaddr*) &saddr, &saddr_len)) {
- /* Socket is already connected. */
- uv_connection_init((uv_stream_t*) handle);
- handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
- }
- }
-
- return 0;
-}
-
-
-/* This function is an egress point, i.e. it returns libuv errors rather than
- * system errors.
- */
-int uv__tcp_bind(uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- int err;
-
- err = uv_tcp_try_bind(handle, addr, addrlen, flags);
- if (err)
- return uv_translate_sys_error(err);
-
- return 0;
-}
-
-
-/* This function is an egress point, i.e. it returns libuv errors rather than
- * system errors.
- */
-int uv__tcp_connect(uv_connect_t* req,
- uv_tcp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_connect_cb cb) {
- int err;
-
- err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
- if (err)
- return uv_translate_sys_error(err);
-
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/thread.cpp b/wpiutil/src/main/native/libuv/src/win/thread.cpp
deleted file mode 100644
index 72af03c..0000000
--- a/wpiutil/src/main/native/libuv/src/win/thread.cpp
+++ /dev/null
@@ -1,520 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <limits.h>
-#include <stdlib.h>
-
-#if defined(__MINGW64_VERSION_MAJOR)
-/* MemoryBarrier expands to __mm_mfence in some cases (x86+sse2), which may
- * require this header in some versions of mingw64. */
-#include <intrin.h>
-#endif
-
-#include "uv.h"
-#include "internal.h"
-
-static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
- DWORD result;
- HANDLE existing_event, created_event;
-
- created_event = CreateEvent(NULL, 1, 0, NULL);
- if (created_event == 0) {
- /* Could fail in a low-memory situation? */
- uv_fatal_error(GetLastError(), "CreateEvent");
- }
-
- existing_event = InterlockedCompareExchangePointer(&guard->event,
- created_event,
- NULL);
-
- if (existing_event == NULL) {
- /* We won the race */
- callback();
-
- result = SetEvent(created_event);
- assert(result);
- guard->ran = 1;
-
- } else {
- /* We lost the race. Destroy the event we created and wait for the existing
- * one to become signaled. */
- CloseHandle(created_event);
- result = WaitForSingleObject(existing_event, INFINITE);
- assert(result == WAIT_OBJECT_0);
- }
-}
-
-
-void uv_once(uv_once_t* guard, void (*callback)(void)) {
- /* Fast case - avoid WaitForSingleObject. */
- if (guard->ran) {
- return;
- }
-
- uv__once_inner(guard, callback);
-}
-
-
-/* Verify that uv_thread_t can be stored in a TLS slot. */
-STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
-
-static uv_key_t uv__current_thread_key;
-static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
-
-
-static void uv__init_current_thread_key(void) {
- if (uv_key_create(&uv__current_thread_key))
- abort();
-}
-
-
-struct thread_ctx {
- void (*entry)(void* arg);
- void* arg;
- uv_thread_t self;
-};
-
-
-static UINT __stdcall uv__thread_start(void* arg) {
- struct thread_ctx *ctx_p;
- struct thread_ctx ctx;
-
- ctx_p = (struct thread_ctx*)arg;
- ctx = *ctx_p;
- uv__free(ctx_p);
-
- uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
- uv_key_set(&uv__current_thread_key, (void*) ctx.self);
-
- ctx.entry(ctx.arg);
-
- return 0;
-}
-
-
-int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
- uv_thread_options_t params;
- params.flags = UV_THREAD_NO_FLAGS;
- return uv_thread_create_ex(tid, ¶ms, entry, arg);
-}
-
-int uv_thread_create_ex(uv_thread_t* tid,
- const uv_thread_options_t* params,
- void (*entry)(void *arg),
- void *arg) {
- struct thread_ctx* ctx;
- int err;
- HANDLE thread;
- SYSTEM_INFO sysinfo;
- size_t stack_size;
- size_t pagesize;
-
- stack_size =
- params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
-
- if (stack_size != 0) {
- GetNativeSystemInfo(&sysinfo);
- pagesize = (size_t)sysinfo.dwPageSize;
- /* Round up to the nearest page boundary. */
- stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
-
- if ((unsigned)stack_size != stack_size)
- return UV_EINVAL;
- }
-
- ctx = (struct thread_ctx*)uv__malloc(sizeof(*ctx));
- if (ctx == NULL)
- return UV_ENOMEM;
-
- ctx->entry = entry;
- ctx->arg = arg;
-
- /* Create the thread in suspended state so we have a chance to pass
- * its own creation handle to it */
- thread = (HANDLE) _beginthreadex(NULL,
- (unsigned)stack_size,
- uv__thread_start,
- ctx,
- CREATE_SUSPENDED,
- NULL);
- if (thread == NULL) {
- err = errno;
- uv__free(ctx);
- } else {
- err = 0;
- *tid = thread;
- ctx->self = thread;
- ResumeThread(thread);
- }
-
- switch (err) {
- case 0:
- return 0;
- case EACCES:
- return UV_EACCES;
- case EAGAIN:
- return UV_EAGAIN;
- case EINVAL:
- return UV_EINVAL;
- }
-
- return UV_EIO;
-}
-
-
-uv_thread_t uv_thread_self(void) {
- uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
- return (uv_thread_t) uv_key_get(&uv__current_thread_key);
-}
-
-
-int uv_thread_join(uv_thread_t *tid) {
- if (WaitForSingleObject(*tid, INFINITE))
- return uv_translate_sys_error(GetLastError());
- else {
- CloseHandle(*tid);
- *tid = 0;
- MemoryBarrier(); /* For feature parity with pthread_join(). */
- return 0;
- }
-}
-
-
-int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
- return *t1 == *t2;
-}
-
-
-int uv_mutex_init(uv_mutex_t* mutex) {
- InitializeCriticalSection(mutex);
- return 0;
-}
-
-
-int uv_mutex_init_recursive(uv_mutex_t* mutex) {
- return uv_mutex_init(mutex);
-}
-
-
-void uv_mutex_destroy(uv_mutex_t* mutex) {
- DeleteCriticalSection(mutex);
-}
-
-
-void uv_mutex_lock(uv_mutex_t* mutex) {
- EnterCriticalSection(mutex);
-}
-
-
-int uv_mutex_trylock(uv_mutex_t* mutex) {
- if (TryEnterCriticalSection(mutex))
- return 0;
- else
- return UV_EBUSY;
-}
-
-
-void uv_mutex_unlock(uv_mutex_t* mutex) {
- LeaveCriticalSection(mutex);
-}
-
-
-int uv_rwlock_init(uv_rwlock_t* rwlock) {
- /* Initialize the semaphore that acts as the write lock. */
- HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
- if (handle == NULL)
- return uv_translate_sys_error(GetLastError());
- rwlock->state_.write_semaphore_ = handle;
-
- /* Initialize the critical section protecting the reader count. */
- InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
-
- /* Initialize the reader count. */
- rwlock->state_.num_readers_ = 0;
-
- return 0;
-}
-
-
-void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
- DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
- CloseHandle(rwlock->state_.write_semaphore_);
-}
-
-
-void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
- /* Acquire the lock that protects the reader count. */
- EnterCriticalSection(&rwlock->state_.num_readers_lock_);
-
- /* Increase the reader count, and lock for write if this is the first
- * reader.
- */
- if (++rwlock->state_.num_readers_ == 1) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
- if (r != WAIT_OBJECT_0)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
- }
-
- /* Release the lock that protects the reader count. */
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
-}
-
-
-int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
- int err;
-
- if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
- return UV_EBUSY;
-
- err = 0;
-
- if (rwlock->state_.num_readers_ == 0) {
- /* Currently there are no other readers, which means that the write lock
- * needs to be acquired.
- */
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
- if (r == WAIT_OBJECT_0)
- rwlock->state_.num_readers_++;
- else if (r == WAIT_TIMEOUT)
- err = UV_EBUSY;
- else if (r == WAIT_FAILED)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
-
- } else {
- /* The write lock has already been acquired because there are other
- * active readers.
- */
- rwlock->state_.num_readers_++;
- }
-
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
- return err;
-}
-
-
-void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
- EnterCriticalSection(&rwlock->state_.num_readers_lock_);
-
- if (--rwlock->state_.num_readers_ == 0) {
- if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
- uv_fatal_error(GetLastError(), "ReleaseSemaphore");
- }
-
- LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
-}
-
-
-void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
- if (r != WAIT_OBJECT_0)
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
-}
-
-
-int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
- DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
- if (r == WAIT_OBJECT_0)
- return 0;
- else if (r == WAIT_TIMEOUT)
- return UV_EBUSY;
- else
- uv_fatal_error(GetLastError(), "WaitForSingleObject");
-}
-
-
-void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
- if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
- uv_fatal_error(GetLastError(), "ReleaseSemaphore");
-}
-
-
-int uv_sem_init(uv_sem_t* sem, unsigned int value) {
- *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
- if (*sem == NULL)
- return uv_translate_sys_error(GetLastError());
- else
- return 0;
-}
-
-
-void uv_sem_destroy(uv_sem_t* sem) {
- if (!CloseHandle(*sem))
- abort();
-}
-
-
-void uv_sem_post(uv_sem_t* sem) {
- if (!ReleaseSemaphore(*sem, 1, NULL))
- abort();
-}
-
-
-void uv_sem_wait(uv_sem_t* sem) {
- if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
- abort();
-}
-
-
-int uv_sem_trywait(uv_sem_t* sem) {
- DWORD r = WaitForSingleObject(*sem, 0);
-
- if (r == WAIT_OBJECT_0)
- return 0;
-
- if (r == WAIT_TIMEOUT)
- return UV_EAGAIN;
-
- abort();
- return -1; /* Satisfy the compiler. */
-}
-
-
-int uv_cond_init(uv_cond_t* cond) {
- InitializeConditionVariable(&cond->cond_var);
- return 0;
-}
-
-
-void uv_cond_destroy(uv_cond_t* cond) {
- /* nothing to do */
- (void) &cond;
-}
-
-
-void uv_cond_signal(uv_cond_t* cond) {
- WakeConditionVariable(&cond->cond_var);
-}
-
-
-void uv_cond_broadcast(uv_cond_t* cond) {
- WakeAllConditionVariable(&cond->cond_var);
-}
-
-
-void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
- if (!SleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
- abort();
-}
-
-int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
- if (SleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
- return 0;
- if (GetLastError() != ERROR_TIMEOUT)
- abort();
- return UV_ETIMEDOUT;
-}
-
-
-int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
- int err;
-
- barrier->n = count;
- barrier->count = 0;
-
- err = uv_mutex_init(&barrier->mutex);
- if (err)
- return err;
-
- err = uv_sem_init(&barrier->turnstile1, 0);
- if (err)
- goto error2;
-
- err = uv_sem_init(&barrier->turnstile2, 1);
- if (err)
- goto error;
-
- return 0;
-
-error:
- uv_sem_destroy(&barrier->turnstile1);
-error2:
- uv_mutex_destroy(&barrier->mutex);
- return err;
-
-}
-
-
-void uv_barrier_destroy(uv_barrier_t* barrier) {
- uv_sem_destroy(&barrier->turnstile2);
- uv_sem_destroy(&barrier->turnstile1);
- uv_mutex_destroy(&barrier->mutex);
-}
-
-
-int uv_barrier_wait(uv_barrier_t* barrier) {
- int serial_thread;
-
- uv_mutex_lock(&barrier->mutex);
- if (++barrier->count == barrier->n) {
- uv_sem_wait(&barrier->turnstile2);
- uv_sem_post(&barrier->turnstile1);
- }
- uv_mutex_unlock(&barrier->mutex);
-
- uv_sem_wait(&barrier->turnstile1);
- uv_sem_post(&barrier->turnstile1);
-
- uv_mutex_lock(&barrier->mutex);
- serial_thread = (--barrier->count == 0);
- if (serial_thread) {
- uv_sem_wait(&barrier->turnstile1);
- uv_sem_post(&barrier->turnstile2);
- }
- uv_mutex_unlock(&barrier->mutex);
-
- uv_sem_wait(&barrier->turnstile2);
- uv_sem_post(&barrier->turnstile2);
- return serial_thread;
-}
-
-
-int uv_key_create(uv_key_t* key) {
- key->tls_index = TlsAlloc();
- if (key->tls_index == TLS_OUT_OF_INDEXES)
- return UV_ENOMEM;
- return 0;
-}
-
-
-void uv_key_delete(uv_key_t* key) {
- if (TlsFree(key->tls_index) == FALSE)
- abort();
- key->tls_index = TLS_OUT_OF_INDEXES;
-}
-
-
-void* uv_key_get(uv_key_t* key) {
- void* value;
-
- value = TlsGetValue(key->tls_index);
- if (value == NULL)
- if (GetLastError() != ERROR_SUCCESS)
- abort();
-
- return value;
-}
-
-
-void uv_key_set(uv_key_t* key, void* value) {
- if (TlsSetValue(key->tls_index, value) == FALSE)
- abort();
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/tty.cpp b/wpiutil/src/main/native/libuv/src/win/tty.cpp
deleted file mode 100644
index e4d7ac9..0000000
--- a/wpiutil/src/main/native/libuv/src/win/tty.cpp
+++ /dev/null
@@ -1,2335 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 _CRT_NONSTDC_NO_WARNINGS
-
-#include <assert.h>
-#include <io.h>
-#include <string.h>
-#include <stdlib.h>
-
-#if defined(_MSC_VER) && _MSC_VER < 1600
-# include "uv/stdint-msvc2008.h"
-#else
-# include <stdint.h>
-#endif
-
-#ifndef COMMON_LVB_REVERSE_VIDEO
-# define COMMON_LVB_REVERSE_VIDEO 0x4000
-#endif
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "stream-inl.h"
-#include "req-inl.h"
-
-#pragma comment(lib, "User32.lib")
-
-#ifndef InterlockedOr
-# define InterlockedOr _InterlockedOr
-#endif
-
-#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
-
-#define ANSI_NORMAL 0x00
-#define ANSI_ESCAPE_SEEN 0x02
-#define ANSI_CSI 0x04
-#define ANSI_ST_CONTROL 0x08
-#define ANSI_IGNORE 0x10
-#define ANSI_IN_ARG 0x20
-#define ANSI_IN_STRING 0x40
-#define ANSI_BACKSLASH_SEEN 0x80
-
-#define MAX_INPUT_BUFFER_LENGTH 8192
-#define MAX_CONSOLE_CHAR 8192
-
-#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
-#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
-#endif
-
-static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
-static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
-static int uv__cancel_read_console(uv_tty_t* handle);
-
-
-/* Null uv_buf_t */
-static const uv_buf_t uv_null_buf_ = { 0, NULL };
-
-enum uv__read_console_status_e {
- NOT_STARTED,
- IN_PROGRESS,
- TRAP_REQUESTED,
- COMPLETED
-};
-
-static volatile LONG uv__read_console_status = NOT_STARTED;
-static volatile LONG uv__restore_screen_state;
-static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
-
-
-/*
- * The console virtual window.
- *
- * Normally cursor movement in windows is relative to the console screen buffer,
- * e.g. the application is allowed to overwrite the 'history'. This is very
- * inconvenient, it makes absolute cursor movement pretty useless. There is
- * also the concept of 'client rect' which is defined by the actual size of
- * the console window and the scroll position of the screen buffer, but it's
- * very volatile because it changes when the user scrolls.
- *
- * To make cursor movement behave sensibly we define a virtual window to which
- * cursor movement is confined. The virtual window is always as wide as the
- * console screen buffer, but it's height is defined by the size of the
- * console window. The top of the virtual window aligns with the position
- * of the caret when the first stdout/err handle is created, unless that would
- * mean that it would extend beyond the bottom of the screen buffer - in that
- * that case it's located as far down as possible.
- *
- * When the user writes a long text or many newlines, such that the output
- * reaches beyond the bottom of the virtual window, the virtual window is
- * shifted downwards, but not resized.
- *
- * Since all tty i/o happens on the same console, this window is shared
- * between all stdout/stderr handles.
- */
-
-static int uv_tty_virtual_offset = -1;
-static int uv_tty_virtual_height = -1;
-static int uv_tty_virtual_width = -1;
-
-/* The console window size
- * We keep this separate from uv_tty_virtual_*. We use those values to only
- * handle signalling SIGWINCH
- */
-
-static HANDLE uv__tty_console_handle = INVALID_HANDLE_VALUE;
-static int uv__tty_console_height = -1;
-static int uv__tty_console_width = -1;
-
-static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param);
-static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
- DWORD event,
- HWND hwnd,
- LONG idObject,
- LONG idChild,
- DWORD dwEventThread,
- DWORD dwmsEventTime);
-
-/* We use a semaphore rather than a mutex or critical section because in some
- cases (uv__cancel_read_console) we need take the lock in the main thread and
- release it in another thread. Using a semaphore ensures that in such
- scenario the main thread will still block when trying to acquire the lock. */
-static uv_sem_t uv_tty_output_lock;
-
-static WORD uv_tty_default_text_attributes =
- FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
-
-static char uv_tty_default_fg_color = 7;
-static char uv_tty_default_bg_color = 0;
-static char uv_tty_default_fg_bright = 0;
-static char uv_tty_default_bg_bright = 0;
-static char uv_tty_default_inverse = 0;
-
-typedef enum {
- UV_SUPPORTED,
- UV_UNCHECKED,
- UV_UNSUPPORTED
-} uv_vtermstate_t;
-/* Determine whether or not ANSI support is enabled. */
-static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
-static void uv__determine_vterm_state(HANDLE handle);
-
-void uv_console_init(void) {
- if (uv_sem_init(&uv_tty_output_lock, 1))
- abort();
- uv__tty_console_handle = CreateFileW(L"CONOUT$",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_WRITE,
- 0,
- OPEN_EXISTING,
- 0,
- 0);
- if (uv__tty_console_handle != INVALID_HANDLE_VALUE) {
- QueueUserWorkItem(uv__tty_console_resize_message_loop_thread,
- NULL,
- WT_EXECUTELONGFUNCTION);
- }
-}
-
-
-int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int unused) {
- BOOL readable;
- DWORD NumberOfEvents;
- HANDLE handle;
- CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
- (void)unused;
-
- uv__once_init();
- handle = (HANDLE) uv__get_osfhandle(fd);
- if (handle == INVALID_HANDLE_VALUE)
- return UV_EBADF;
-
- if (fd <= 2) {
- /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
- * underlying OS handle and forget about the original fd.
- * We could also opt to use the original OS handle and just never close it,
- * but then there would be no reliable way to cancel pending read operations
- * upon close.
- */
- if (!DuplicateHandle(INVALID_HANDLE_VALUE,
- handle,
- INVALID_HANDLE_VALUE,
- &handle,
- 0,
- FALSE,
- DUPLICATE_SAME_ACCESS))
- return uv_translate_sys_error(GetLastError());
- fd = -1;
- }
-
- readable = GetNumberOfConsoleInputEvents(handle, &NumberOfEvents);
- if (!readable) {
- /* Obtain the screen buffer info with the output handle. */
- if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
- return uv_translate_sys_error(GetLastError());
- }
-
- /* Obtain the tty_output_lock because the virtual window state is shared
- * between all uv_tty_t handles. */
- uv_sem_wait(&uv_tty_output_lock);
-
- if (uv__vterm_state == UV_UNCHECKED)
- uv__determine_vterm_state(handle);
-
- /* Remember the original console text attributes. */
- uv_tty_capture_initial_style(&screen_buffer_info);
-
- uv_tty_update_virtual_window(&screen_buffer_info);
-
- uv_sem_post(&uv_tty_output_lock);
- }
-
-
- uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
- uv_connection_init((uv_stream_t*) tty);
-
- tty->handle = handle;
- tty->u.fd = fd;
- tty->reqs_pending = 0;
- tty->flags |= UV_HANDLE_BOUND;
-
- if (readable) {
- /* Initialize TTY input specific fields. */
- tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
- /* TODO: remove me in v2.x. */
- tty->tty.rd.unused_ = NULL;
- tty->tty.rd.read_line_buffer = uv_null_buf_;
- tty->tty.rd.read_raw_wait = NULL;
-
- /* Init keycode-to-vt100 mapper state. */
- tty->tty.rd.last_key_len = 0;
- tty->tty.rd.last_key_offset = 0;
- tty->tty.rd.last_utf16_high_surrogate = 0;
- memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
- } else {
- /* TTY output specific fields. */
- tty->flags |= UV_HANDLE_WRITABLE;
-
- /* Init utf8-to-utf16 conversion state. */
- tty->tty.wr.utf8_bytes_left = 0;
- tty->tty.wr.utf8_codepoint = 0;
-
- /* Initialize eol conversion state */
- tty->tty.wr.previous_eol = 0;
-
- /* Init ANSI parser state. */
- tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
- }
-
- return 0;
-}
-
-
-/* Set the default console text attributes based on how the console was
- * configured when libuv started.
- */
-static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
- static int style_captured = 0;
-
- /* Only do this once.
- Assumption: Caller has acquired uv_tty_output_lock. */
- if (style_captured)
- return;
-
- /* Save raw win32 attributes. */
- uv_tty_default_text_attributes = info->wAttributes;
-
- /* Convert black text on black background to use white text. */
- if (uv_tty_default_text_attributes == 0)
- uv_tty_default_text_attributes = 7;
-
- /* Convert Win32 attributes to ANSI colors. */
- uv_tty_default_fg_color = 0;
- uv_tty_default_bg_color = 0;
- uv_tty_default_fg_bright = 0;
- uv_tty_default_bg_bright = 0;
- uv_tty_default_inverse = 0;
-
- if (uv_tty_default_text_attributes & FOREGROUND_RED)
- uv_tty_default_fg_color |= 1;
-
- if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
- uv_tty_default_fg_color |= 2;
-
- if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
- uv_tty_default_fg_color |= 4;
-
- if (uv_tty_default_text_attributes & BACKGROUND_RED)
- uv_tty_default_bg_color |= 1;
-
- if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
- uv_tty_default_bg_color |= 2;
-
- if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
- uv_tty_default_bg_color |= 4;
-
- if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
- uv_tty_default_fg_bright = 1;
-
- if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
- uv_tty_default_bg_bright = 1;
-
- if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
- uv_tty_default_inverse = 1;
-
- style_captured = 1;
-}
-
-
-int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
- DWORD flags;
- unsigned char was_reading;
- uv_alloc_cb alloc_cb;
- uv_read_cb read_cb;
- int err;
-
- if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
- return UV_EINVAL;
- }
-
- if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
- return 0;
- }
-
- switch (mode) {
- case UV_TTY_MODE_NORMAL:
- flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
- break;
- case UV_TTY_MODE_RAW:
- flags = ENABLE_WINDOW_INPUT;
- break;
- case UV_TTY_MODE_IO:
- return UV_ENOTSUP;
- default:
- return UV_EINVAL;
- }
-
- /* If currently reading, stop, and restart reading. */
- if (tty->flags & UV_HANDLE_READING) {
- was_reading = 1;
- alloc_cb = tty->alloc_cb;
- read_cb = tty->read_cb;
- err = uv_tty_read_stop(tty);
- if (err) {
- return uv_translate_sys_error(err);
- }
- } else {
- was_reading = 0;
- alloc_cb = NULL;
- read_cb = NULL;
- }
-
- uv_sem_wait(&uv_tty_output_lock);
- if (!SetConsoleMode(tty->handle, flags)) {
- err = uv_translate_sys_error(GetLastError());
- uv_sem_post(&uv_tty_output_lock);
- return err;
- }
- uv_sem_post(&uv_tty_output_lock);
-
- /* Update flag. */
- tty->flags &= ~UV_HANDLE_TTY_RAW;
- tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
-
- /* If we just stopped reading, restart. */
- if (was_reading) {
- err = uv_tty_read_start(tty, alloc_cb, read_cb);
- if (err) {
- return uv_translate_sys_error(err);
- }
- }
-
- return 0;
-}
-
-
-int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
- return uv_translate_sys_error(GetLastError());
- }
-
- uv_sem_wait(&uv_tty_output_lock);
- uv_tty_update_virtual_window(&info);
- uv_sem_post(&uv_tty_output_lock);
-
- *width = uv_tty_virtual_width;
- *height = uv_tty_virtual_height;
-
- return 0;
-}
-
-
-static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
- uv_loop_t* loop;
- uv_tty_t* handle;
- uv_req_t* req;
-
- assert(data);
- assert(!didTimeout);
-
- req = (uv_req_t*) data;
- handle = (uv_tty_t*) req->data;
- loop = handle->loop;
-
- UnregisterWait(handle->tty.rd.read_raw_wait);
- handle->tty.rd.read_raw_wait = NULL;
-
- SET_REQ_SUCCESS(req);
- POST_COMPLETION_FOR_REQ(loop, req);
-}
-
-
-static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
- uv_read_t* req;
- BOOL r;
-
- assert(handle->flags & UV_HANDLE_READING);
- assert(!(handle->flags & UV_HANDLE_READ_PENDING));
-
- assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
-
- handle->tty.rd.read_line_buffer = uv_null_buf_;
-
- req = &handle->read_req;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
- handle->handle,
- uv_tty_post_raw_read,
- (void*) req,
- INFINITE,
- WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
- if (!r) {
- handle->tty.rd.read_raw_wait = NULL;
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- }
-
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
-}
-
-
-static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
- uv_loop_t* loop;
- uv_tty_t* handle;
- uv_req_t* req;
- DWORD bytes, read_bytes;
- WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
- DWORD chars, read_chars;
- LONG status;
- COORD pos;
- BOOL read_console_success;
-
- assert(data);
-
- req = (uv_req_t*) data;
- handle = (uv_tty_t*) req->data;
- loop = handle->loop;
-
- assert(handle->tty.rd.read_line_buffer.base != NULL);
- assert(handle->tty.rd.read_line_buffer.len > 0);
-
- /* ReadConsole can't handle big buffers. */
- if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
- bytes = handle->tty.rd.read_line_buffer.len;
- } else {
- bytes = MAX_INPUT_BUFFER_LENGTH;
- }
-
- /* At last, unicode! One utf-16 codeunit never takes more than 3 utf-8
- * codeunits to encode. */
- chars = bytes / 3;
-
- status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
- if (status == TRAP_REQUESTED) {
- SET_REQ_SUCCESS(req);
- req->u.io.overlapped.InternalHigh = 0;
- POST_COMPLETION_FOR_REQ(loop, req);
- return 0;
- }
-
- read_console_success = ReadConsoleW(handle->handle,
- (void*) utf16,
- chars,
- &read_chars,
- NULL);
-
- if (read_console_success) {
- read_bytes = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16,
- read_chars,
- handle->tty.rd.read_line_buffer.base,
- bytes,
- NULL,
- NULL);
- SET_REQ_SUCCESS(req);
- req->u.io.overlapped.InternalHigh = read_bytes;
- } else {
- SET_REQ_ERROR(req, GetLastError());
- }
-
- status = InterlockedExchange(&uv__read_console_status, COMPLETED);
-
- if (status == TRAP_REQUESTED) {
- /* If we canceled the read by sending a VK_RETURN event, restore the
- screen state to undo the visual effect of the VK_RETURN */
- if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
- HANDLE active_screen_buffer;
- active_screen_buffer = CreateFileA("conout$",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
- if (active_screen_buffer != INVALID_HANDLE_VALUE) {
- pos = uv__saved_screen_state.dwCursorPosition;
-
- /* If the cursor was at the bottom line of the screen buffer, the
- VK_RETURN would have caused the buffer contents to scroll up by one
- line. The right position to reset the cursor to is therefore one line
- higher */
- if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
- pos.Y--;
-
- SetConsoleCursorPosition(active_screen_buffer, pos);
- CloseHandle(active_screen_buffer);
- }
- }
- uv_sem_post(&uv_tty_output_lock);
- }
- POST_COMPLETION_FOR_REQ(loop, req);
- return 0;
-}
-
-
-static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
- uv_read_t* req;
- BOOL r;
-
- assert(handle->flags & UV_HANDLE_READING);
- assert(!(handle->flags & UV_HANDLE_READ_PENDING));
- assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
-
- req = &handle->read_req;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
- if (handle->tty.rd.read_line_buffer.base == NULL ||
- handle->tty.rd.read_line_buffer.len == 0) {
- handle->read_cb((uv_stream_t*) handle,
- UV_ENOBUFS,
- &handle->tty.rd.read_line_buffer);
- return;
- }
- assert(handle->tty.rd.read_line_buffer.base != NULL);
-
- /* Reset flags No locking is required since there cannot be a line read
- in progress. We are also relying on the memory barrier provided by
- QueueUserWorkItem*/
- uv__restore_screen_state = FALSE;
- uv__read_console_status = NOT_STARTED;
- r = QueueUserWorkItem(uv_tty_line_read_thread,
- (void*) req,
- WT_EXECUTELONGFUNCTION);
- if (!r) {
- SET_REQ_ERROR(req, GetLastError());
- uv_insert_pending_req(loop, (uv_req_t*)req);
- }
-
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
-}
-
-
-static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
- if (handle->flags & UV_HANDLE_TTY_RAW) {
- uv_tty_queue_read_raw(loop, handle);
- } else {
- uv_tty_queue_read_line(loop, handle);
- }
-}
-
-
-static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
- size_t* len) {
-#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
- case (vk): \
- if (shift && ctrl) { \
- *len = sizeof shift_ctrl_str; \
- return "\033" shift_ctrl_str; \
- } else if (shift) { \
- *len = sizeof shift_str ; \
- return "\033" shift_str; \
- } else if (ctrl) { \
- *len = sizeof ctrl_str; \
- return "\033" ctrl_str; \
- } else { \
- *len = sizeof normal_str; \
- return "\033" normal_str; \
- }
-
- switch (code) {
- /* These mappings are the same as Cygwin's. Unmodified and alt-modified
- * keypad keys comply with linux console, modifiers comply with xterm
- * modifier usage. F1. f12 and shift-f1. f10 comply with linux console, f6.
- * f12 with and without modifiers comply with rxvt. */
- VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
- VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
- VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
- VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
- VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
- VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
- VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
- VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
- VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
- VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
- VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
- VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
- VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
- VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
- VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
- VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
- VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
- VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
- VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
- VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
- VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
- VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
- VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
- VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
- VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
- VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
- VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
- VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
- VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
- VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
- VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
- VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
- VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
- VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
-
- default:
- *len = 0;
- return NULL;
- }
-#undef VK_CASE
-}
-
-
-void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* req) {
- /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
-#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
-
- DWORD records_left, records_read;
- uv_buf_t buf;
- off_t buf_used;
-
- assert(handle->type == UV_TTY);
- assert(handle->flags & UV_HANDLE_TTY_READABLE);
- handle->flags &= ~UV_HANDLE_READ_PENDING;
-
- if (!(handle->flags & UV_HANDLE_READING) ||
- !(handle->flags & UV_HANDLE_TTY_RAW)) {
- goto out;
- }
-
- if (!REQ_SUCCESS(req)) {
- /* An error occurred while waiting for the event. */
- if ((handle->flags & UV_HANDLE_READING)) {
- handle->flags &= ~UV_HANDLE_READING;
- handle->read_cb((uv_stream_t*)handle,
- uv_translate_sys_error(GET_REQ_ERROR(req)),
- &uv_null_buf_);
- }
- goto out;
- }
-
- /* Fetch the number of events */
- if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb((uv_stream_t*)handle,
- uv_translate_sys_error(GetLastError()),
- &uv_null_buf_);
- goto out;
- }
-
- /* Windows sends a lot of events that we're not interested in, so buf will be
- * allocated on demand, when there's actually something to emit. */
- buf = uv_null_buf_;
- buf_used = 0;
-
- while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
- (handle->flags & UV_HANDLE_READING)) {
- if (handle->tty.rd.last_key_len == 0) {
- /* Read the next input record */
- if (!ReadConsoleInputW(handle->handle,
- &handle->tty.rd.last_input_record,
- 1,
- &records_read)) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb((uv_stream_t*) handle,
- uv_translate_sys_error(GetLastError()),
- &buf);
- goto out;
- }
- records_left--;
-
- /* Ignore other events that are not key events. */
- if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
- continue;
- }
-
- /* Ignore keyup events, unless the left alt key was held and a valid
- * unicode character was emitted. */
- if (!KEV.bKeyDown &&
- (KEV.wVirtualKeyCode != VK_MENU ||
- KEV.uChar.UnicodeChar == 0)) {
- continue;
- }
-
- /* Ignore keypresses to numpad number keys if the left alt is held
- * because the user is composing a character, or windows simulating this.
- */
- if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
- !(KEV.dwControlKeyState & ENHANCED_KEY) &&
- (KEV.wVirtualKeyCode == VK_INSERT ||
- KEV.wVirtualKeyCode == VK_END ||
- KEV.wVirtualKeyCode == VK_DOWN ||
- KEV.wVirtualKeyCode == VK_NEXT ||
- KEV.wVirtualKeyCode == VK_LEFT ||
- KEV.wVirtualKeyCode == VK_CLEAR ||
- KEV.wVirtualKeyCode == VK_RIGHT ||
- KEV.wVirtualKeyCode == VK_HOME ||
- KEV.wVirtualKeyCode == VK_UP ||
- KEV.wVirtualKeyCode == VK_PRIOR ||
- KEV.wVirtualKeyCode == VK_NUMPAD0 ||
- KEV.wVirtualKeyCode == VK_NUMPAD1 ||
- KEV.wVirtualKeyCode == VK_NUMPAD2 ||
- KEV.wVirtualKeyCode == VK_NUMPAD3 ||
- KEV.wVirtualKeyCode == VK_NUMPAD4 ||
- KEV.wVirtualKeyCode == VK_NUMPAD5 ||
- KEV.wVirtualKeyCode == VK_NUMPAD6 ||
- KEV.wVirtualKeyCode == VK_NUMPAD7 ||
- KEV.wVirtualKeyCode == VK_NUMPAD8 ||
- KEV.wVirtualKeyCode == VK_NUMPAD9)) {
- continue;
- }
-
- if (KEV.uChar.UnicodeChar != 0) {
- int prefix_len, char_len;
-
- /* Character key pressed */
- if (KEV.uChar.UnicodeChar >= 0xD800 &&
- KEV.uChar.UnicodeChar < 0xDC00) {
- /* UTF-16 high surrogate */
- handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
- continue;
- }
-
- /* Prefix with \u033 if alt was held, but alt was not used as part a
- * compose sequence. */
- if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
- && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
- RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
- handle->tty.rd.last_key[0] = '\033';
- prefix_len = 1;
- } else {
- prefix_len = 0;
- }
-
- if (KEV.uChar.UnicodeChar >= 0xDC00 &&
- KEV.uChar.UnicodeChar < 0xE000) {
- /* UTF-16 surrogate pair */
- WCHAR utf16_buffer[2];
- utf16_buffer[0] = handle->tty.rd.last_utf16_high_surrogate;
- utf16_buffer[1] = KEV.uChar.UnicodeChar;
- char_len = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16_buffer,
- 2,
- &handle->tty.rd.last_key[prefix_len],
- sizeof handle->tty.rd.last_key,
- NULL,
- NULL);
- } else {
- /* Single UTF-16 character */
- char_len = WideCharToMultiByte(CP_UTF8,
- 0,
- &KEV.uChar.UnicodeChar,
- 1,
- &handle->tty.rd.last_key[prefix_len],
- sizeof handle->tty.rd.last_key,
- NULL,
- NULL);
- }
-
- /* Whatever happened, the last character wasn't a high surrogate. */
- handle->tty.rd.last_utf16_high_surrogate = 0;
-
- /* If the utf16 character(s) couldn't be converted something must be
- * wrong. */
- if (!char_len) {
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb((uv_stream_t*) handle,
- uv_translate_sys_error(GetLastError()),
- &buf);
- goto out;
- }
-
- handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
- handle->tty.rd.last_key_offset = 0;
- continue;
-
- } else {
- /* Function key pressed */
- const char* vt100;
- size_t prefix_len, vt100_len;
-
- vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
- !!(KEV.dwControlKeyState & SHIFT_PRESSED),
- !!(KEV.dwControlKeyState & (
- LEFT_CTRL_PRESSED |
- RIGHT_CTRL_PRESSED)),
- &vt100_len);
-
- /* If we were unable to map to a vt100 sequence, just ignore. */
- if (!vt100) {
- continue;
- }
-
- /* Prefix with \x033 when the alt key was held. */
- if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
- handle->tty.rd.last_key[0] = '\033';
- prefix_len = 1;
- } else {
- prefix_len = 0;
- }
-
- /* Copy the vt100 sequence to the handle buffer. */
- assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
- memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
-
- handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
- handle->tty.rd.last_key_offset = 0;
- continue;
- }
- } else {
- /* Copy any bytes left from the last keypress to the user buffer. */
- if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
- /* Allocate a buffer if needed */
- if (buf_used == 0) {
- buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
- if (buf.base == NULL || buf.len == 0) {
- handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
- goto out;
- }
- assert(buf.base != NULL);
- }
-
- buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
-
- /* If the buffer is full, emit it */
- if ((size_t) buf_used == buf.len) {
- handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
- buf = uv_null_buf_;
- buf_used = 0;
- }
-
- continue;
- }
-
- /* Apply dwRepeat from the last input record. */
- if (--KEV.wRepeatCount > 0) {
- handle->tty.rd.last_key_offset = 0;
- continue;
- }
-
- handle->tty.rd.last_key_len = 0;
- continue;
- }
- }
-
- /* Send the buffer back to the user */
- if (buf_used > 0) {
- handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
- }
-
- out:
- /* Wait for more input events. */
- if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_READ_PENDING)) {
- uv_tty_queue_read(loop, handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-
-#undef KEV
-}
-
-
-
-void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* req) {
- uv_buf_t buf;
-
- assert(handle->type == UV_TTY);
- assert(handle->flags & UV_HANDLE_TTY_READABLE);
-
- buf = handle->tty.rd.read_line_buffer;
-
- handle->flags &= ~UV_HANDLE_READ_PENDING;
- handle->tty.rd.read_line_buffer = uv_null_buf_;
-
- if (!REQ_SUCCESS(req)) {
- /* Read was not successful */
- if (handle->flags & UV_HANDLE_READING) {
- /* Real error */
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb((uv_stream_t*) handle,
- uv_translate_sys_error(GET_REQ_ERROR(req)),
- &buf);
- }
- } else {
- if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING) &&
- req->u.io.overlapped.InternalHigh != 0) {
- /* Read successful. TODO: read unicode, convert to utf-8 */
- DWORD bytes = req->u.io.overlapped.InternalHigh;
- handle->read_cb((uv_stream_t*) handle, bytes, &buf);
- }
- handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
- }
-
- /* Wait for more input events. */
- if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_READ_PENDING)) {
- uv_tty_queue_read(loop, handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* req) {
- assert(handle->type == UV_TTY);
- assert(handle->flags & UV_HANDLE_TTY_READABLE);
-
- /* If the read_line_buffer member is zero, it must have been an raw read.
- * Otherwise it was a line-buffered read. FIXME: This is quite obscure. Use a
- * flag or something. */
- if (handle->tty.rd.read_line_buffer.len == 0) {
- uv_process_tty_read_raw_req(loop, handle, req);
- } else {
- uv_process_tty_read_line_req(loop, handle, req);
- }
-}
-
-
-int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
- uv_read_cb read_cb) {
- uv_loop_t* loop = handle->loop;
-
- if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
- return ERROR_INVALID_PARAMETER;
- }
-
- handle->flags |= UV_HANDLE_READING;
- INCREASE_ACTIVE_COUNT(loop, handle);
- handle->read_cb = read_cb;
- handle->alloc_cb = alloc_cb;
-
- /* If reading was stopped and then started again, there could still be a read
- * request pending. */
- if (handle->flags & UV_HANDLE_READ_PENDING) {
- return 0;
- }
-
- /* Maybe the user stopped reading half-way while processing key events.
- * Short-circuit if this could be the case. */
- if (handle->tty.rd.last_key_len > 0) {
- SET_REQ_SUCCESS(&handle->read_req);
- uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
- /* Make sure no attempt is made to insert it again until it's handled. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
- return 0;
- }
-
- uv_tty_queue_read(loop, handle);
-
- return 0;
-}
-
-
-int uv_tty_read_stop(uv_tty_t* handle) {
- INPUT_RECORD record;
- DWORD written, err;
-
- handle->flags &= ~UV_HANDLE_READING;
- DECREASE_ACTIVE_COUNT(handle->loop, handle);
-
- if (!(handle->flags & UV_HANDLE_READ_PENDING))
- return 0;
-
- if (handle->flags & UV_HANDLE_TTY_RAW) {
- /* Cancel raw read. Write some bullshit event to force the console wait to
- * return. */
- memset(&record, 0, sizeof record);
- record.EventType = FOCUS_EVENT;
- if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
- return GetLastError();
- }
- } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
- /* Cancel line-buffered read if not already pending */
- err = uv__cancel_read_console(handle);
- if (err)
- return err;
-
- handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
- }
-
- return 0;
-}
-
-static int uv__cancel_read_console(uv_tty_t* handle) {
- HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
- INPUT_RECORD record;
- DWORD written;
- DWORD err = 0;
- LONG status;
-
- assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
-
- /* Hold the output lock during the cancellation, to ensure that further
- writes don't interfere with the screen state. It will be the ReadConsole
- thread's responsibility to release the lock. */
- uv_sem_wait(&uv_tty_output_lock);
- status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
- if (status != IN_PROGRESS) {
- /* Either we have managed to set a trap for the other thread before
- ReadConsole is called, or ReadConsole has returned because the user
- has pressed ENTER. In either case, there is nothing else to do. */
- uv_sem_post(&uv_tty_output_lock);
- return 0;
- }
-
- /* Save screen state before sending the VK_RETURN event */
- active_screen_buffer = CreateFileA("conout$",
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- if (active_screen_buffer != INVALID_HANDLE_VALUE &&
- GetConsoleScreenBufferInfo(active_screen_buffer,
- &uv__saved_screen_state)) {
- InterlockedOr(&uv__restore_screen_state, 1);
- }
-
- /* Write enter key event to force the console wait to return. */
- record.EventType = KEY_EVENT;
- record.Event.KeyEvent.bKeyDown = TRUE;
- record.Event.KeyEvent.wRepeatCount = 1;
- record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
- record.Event.KeyEvent.wVirtualScanCode =
- MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
- record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
- record.Event.KeyEvent.dwControlKeyState = 0;
- if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
- err = GetLastError();
-
- if (active_screen_buffer != INVALID_HANDLE_VALUE)
- CloseHandle(active_screen_buffer);
-
- return err;
-}
-
-
-static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
- uv_tty_virtual_width = info->dwSize.X;
- uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
-
- /* Recompute virtual window offset row. */
- if (uv_tty_virtual_offset == -1) {
- uv_tty_virtual_offset = info->dwCursorPosition.Y;
- } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
- uv_tty_virtual_height + 1) {
- /* If suddenly find the cursor outside of the virtual window, it must have
- * somehow scrolled. Update the virtual window offset. */
- uv_tty_virtual_offset = info->dwCursorPosition.Y -
- uv_tty_virtual_height + 1;
- }
- if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
- uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
- }
- if (uv_tty_virtual_offset < 0) {
- uv_tty_virtual_offset = 0;
- }
-}
-
-
-static COORD uv_tty_make_real_coord(uv_tty_t* handle,
- CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
- unsigned char y_relative) {
- COORD result;
-
- uv_tty_update_virtual_window(info);
-
- /* Adjust y position */
- if (y_relative) {
- y = info->dwCursorPosition.Y + y;
- } else {
- y = uv_tty_virtual_offset + y;
- }
- /* Clip y to virtual client rectangle */
- if (y < uv_tty_virtual_offset) {
- y = uv_tty_virtual_offset;
- } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
- y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
- }
-
- /* Adjust x */
- if (x_relative) {
- x = info->dwCursorPosition.X + x;
- }
- /* Clip x */
- if (x < 0) {
- x = 0;
- } else if (x >= uv_tty_virtual_width) {
- x = uv_tty_virtual_width - 1;
- }
-
- result.X = (unsigned short) x;
- result.Y = (unsigned short) y;
- return result;
-}
-
-
-static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
- DWORD* error) {
- DWORD written;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- if (!WriteConsoleW(handle->handle,
- (void*) buffer,
- length,
- &written,
- NULL)) {
- *error = GetLastError();
- return -1;
- }
-
- return 0;
-}
-
-
-static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
- int y, unsigned char y_relative, DWORD* error) {
- CONSOLE_SCREEN_BUFFER_INFO info;
- COORD pos;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- retry:
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- }
-
- pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
-
- if (!SetConsoleCursorPosition(handle->handle, pos)) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- /* The console may be resized - retry */
- goto retry;
- } else {
- *error = GetLastError();
- return -1;
- }
- }
-
- return 0;
-}
-
-
-static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
- const COORD origin = {0, 0};
- const WORD char_attrs = uv_tty_default_text_attributes;
- CONSOLE_SCREEN_BUFFER_INFO info;
- DWORD count, written;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- /* Reset original text attributes. */
- if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
- *error = GetLastError();
- return -1;
- }
-
- /* Move the cursor position to (0, 0). */
- if (!SetConsoleCursorPosition(handle->handle, origin)) {
- *error = GetLastError();
- return -1;
- }
-
- /* Clear the screen buffer. */
- retry:
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
- }
-
- count = info.dwSize.X * info.dwSize.Y;
-
- if (!(FillConsoleOutputCharacterW(handle->handle,
- L'\x20',
- count,
- origin,
- &written) &&
- FillConsoleOutputAttribute(handle->handle,
- char_attrs,
- written,
- origin,
- &written))) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- /* The console may be resized - retry */
- goto retry;
- } else {
- *error = GetLastError();
- return -1;
- }
- }
-
- /* Move the virtual window up to the top. */
- uv_tty_virtual_offset = 0;
- uv_tty_update_virtual_window(&info);
-
- return 0;
-}
-
-
-static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
- DWORD* error) {
- CONSOLE_SCREEN_BUFFER_INFO info;
- COORD start, end;
- DWORD count, written;
-
- int x1, x2, y1, y2;
- int x1r, x2r, y1r, y2r;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- if (dir == 0) {
- /* Clear from current position */
- x1 = 0;
- x1r = 1;
- } else {
- /* Clear from column 0 */
- x1 = 0;
- x1r = 0;
- }
-
- if (dir == 1) {
- /* Clear to current position */
- x2 = 0;
- x2r = 1;
- } else {
- /* Clear to end of row. We pretend the console is 65536 characters wide,
- * uv_tty_make_real_coord will clip it to the actual console width. */
- x2 = 0xffff;
- x2r = 0;
- }
-
- if (!entire_screen) {
- /* Stay on our own row */
- y1 = y2 = 0;
- y1r = y2r = 1;
- } else {
- /* Apply columns direction to row */
- y1 = x1;
- y1r = x1r;
- y2 = x2;
- y2r = x2r;
- }
-
- retry:
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
- }
-
- start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
- end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
- count = (end.Y * info.dwSize.X + end.X) -
- (start.Y * info.dwSize.X + start.X) + 1;
-
- if (!(FillConsoleOutputCharacterW(handle->handle,
- L'\x20',
- count,
- start,
- &written) &&
- FillConsoleOutputAttribute(handle->handle,
- info.wAttributes,
- written,
- start,
- &written))) {
- if (GetLastError() == ERROR_INVALID_PARAMETER) {
- /* The console may be resized - retry */
- goto retry;
- } else {
- *error = GetLastError();
- return -1;
- }
- }
-
- return 0;
-}
-
-#define FLIP_FGBG \
- do { \
- WORD fg = info.wAttributes & 0xF; \
- WORD bg = info.wAttributes & 0xF0; \
- info.wAttributes &= 0xFF00; \
- info.wAttributes |= fg << 4; \
- info.wAttributes |= bg >> 4; \
- } while (0)
-
-static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
- unsigned short argc = handle->tty.wr.ansi_csi_argc;
- unsigned short* argv = handle->tty.wr.ansi_csi_argv;
- int i;
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- char fg_color = -1, bg_color = -1;
- char fg_bright = -1, bg_bright = -1;
- char inverse = -1;
-
- if (argc == 0) {
- /* Reset mode */
- fg_color = uv_tty_default_fg_color;
- bg_color = uv_tty_default_bg_color;
- fg_bright = uv_tty_default_fg_bright;
- bg_bright = uv_tty_default_bg_bright;
- inverse = uv_tty_default_inverse;
- }
-
- for (i = 0; i < argc; i++) {
- short arg = argv[i];
-
- if (arg == 0) {
- /* Reset mode */
- fg_color = uv_tty_default_fg_color;
- bg_color = uv_tty_default_bg_color;
- fg_bright = uv_tty_default_fg_bright;
- bg_bright = uv_tty_default_bg_bright;
- inverse = uv_tty_default_inverse;
-
- } else if (arg == 1) {
- /* Foreground bright on */
- fg_bright = 1;
-
- } else if (arg == 2) {
- /* Both bright off */
- fg_bright = 0;
- bg_bright = 0;
-
- } else if (arg == 5) {
- /* Background bright on */
- bg_bright = 1;
-
- } else if (arg == 7) {
- /* Inverse: on */
- inverse = 1;
-
- } else if (arg == 21 || arg == 22) {
- /* Foreground bright off */
- fg_bright = 0;
-
- } else if (arg == 25) {
- /* Background bright off */
- bg_bright = 0;
-
- } else if (arg == 27) {
- /* Inverse: off */
- inverse = 0;
-
- } else if (arg >= 30 && arg <= 37) {
- /* Set foreground color */
- fg_color = arg - 30;
-
- } else if (arg == 39) {
- /* Default text color */
- fg_color = uv_tty_default_fg_color;
- fg_bright = uv_tty_default_fg_bright;
-
- } else if (arg >= 40 && arg <= 47) {
- /* Set background color */
- bg_color = arg - 40;
-
- } else if (arg == 49) {
- /* Default background color */
- bg_color = uv_tty_default_bg_color;
- bg_bright = uv_tty_default_bg_bright;
-
- } else if (arg >= 90 && arg <= 97) {
- /* Set bold foreground color */
- fg_bright = 1;
- fg_color = arg - 90;
-
- } else if (arg >= 100 && arg <= 107) {
- /* Set bold background color */
- bg_bright = 1;
- bg_color = arg - 100;
-
- }
- }
-
- if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
- bg_bright == -1 && inverse == -1) {
- /* Nothing changed */
- return 0;
- }
-
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
- }
-
- if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
- FLIP_FGBG;
- }
-
- if (fg_color != -1) {
- info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
- if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
- if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
- if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
- }
-
- if (fg_bright != -1) {
- if (fg_bright) {
- info.wAttributes |= FOREGROUND_INTENSITY;
- } else {
- info.wAttributes &= ~FOREGROUND_INTENSITY;
- }
- }
-
- if (bg_color != -1) {
- info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
- if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
- if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
- if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
- }
-
- if (bg_bright != -1) {
- if (bg_bright) {
- info.wAttributes |= BACKGROUND_INTENSITY;
- } else {
- info.wAttributes &= ~BACKGROUND_INTENSITY;
- }
- }
-
- if (inverse != -1) {
- if (inverse) {
- info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
- } else {
- info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
- }
- }
-
- if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
- FLIP_FGBG;
- }
-
- if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
- *error = GetLastError();
- return -1;
- }
-
- return 0;
-}
-
-
-static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
- DWORD* error) {
- CONSOLE_SCREEN_BUFFER_INFO info;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
- }
-
- uv_tty_update_virtual_window(&info);
-
- handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
- handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
- handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
-
- if (save_attributes) {
- handle->tty.wr.saved_attributes = info.wAttributes &
- (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
- handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
- }
-
- return 0;
-}
-
-
-static int uv_tty_restore_state(uv_tty_t* handle,
- unsigned char restore_attributes, DWORD* error) {
- CONSOLE_SCREEN_BUFFER_INFO info;
- WORD new_attributes;
-
- if (*error != ERROR_SUCCESS) {
- return -1;
- }
-
- if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
- if (uv_tty_move_caret(handle,
- handle->tty.wr.saved_position.X,
- 0,
- handle->tty.wr.saved_position.Y,
- 0,
- error) != 0) {
- return -1;
- }
- }
-
- if (restore_attributes &&
- (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
- if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
- *error = GetLastError();
- return -1;
- }
-
- new_attributes = info.wAttributes;
- new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
- new_attributes |= handle->tty.wr.saved_attributes;
-
- if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
- *error = GetLastError();
- return -1;
- }
- }
-
- return 0;
-}
-
-static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
- BOOL visible,
- DWORD* error) {
- CONSOLE_CURSOR_INFO cursor_info;
-
- if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
- *error = GetLastError();
- return -1;
- }
-
- cursor_info.bVisible = visible;
-
- if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
- *error = GetLastError();
- return -1;
- }
-
- return 0;
-}
-
-static int uv_tty_write_bufs(uv_tty_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- DWORD* error) {
- /* We can only write 8k characters at a time. Windows can't handle much more
- * characters in a single console write anyway. */
- WCHAR utf16_buf[MAX_CONSOLE_CHAR];
- WCHAR* utf16_buffer;
- DWORD utf16_buf_used = 0;
- unsigned int i, len, max_len, pos;
- int allocate = 0;
-
-#define FLUSH_TEXT() \
- do { \
- pos = 0; \
- do { \
- len = utf16_buf_used - pos; \
- if (len > MAX_CONSOLE_CHAR) \
- len = MAX_CONSOLE_CHAR; \
- uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
- pos += len; \
- } while (pos < utf16_buf_used); \
- if (allocate) { \
- uv__free(utf16_buffer); \
- allocate = 0; \
- utf16_buffer = utf16_buf; \
- } \
- utf16_buf_used = 0; \
- } while (0)
-
-#define ENSURE_BUFFER_SPACE(wchars_needed) \
- if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
- FLUSH_TEXT(); \
- }
-
- /* Cache for fast access */
- unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
- unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
- unsigned char previous_eol = handle->tty.wr.previous_eol;
- unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
-
- /* Store the error here. If we encounter an error, stop trying to do i/o but
- * keep parsing the buffer so we leave the parser in a consistent state. */
- *error = ERROR_SUCCESS;
-
- utf16_buffer = utf16_buf;
-
- uv_sem_wait(&uv_tty_output_lock);
-
- for (i = 0; i < nbufs; i++) {
- uv_buf_t buf = bufs[i];
- unsigned int j;
-
- if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
- utf16_buf_used = MultiByteToWideChar(CP_UTF8,
- 0,
- buf.base,
- buf.len,
- NULL,
- 0);
-
- if (utf16_buf_used == 0) {
- *error = GetLastError();
- break;
- }
-
- max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
- allocate = max_len > MAX_CONSOLE_CHAR;
- if (allocate)
- utf16_buffer = (WCHAR*)uv__malloc(max_len);
- if (!MultiByteToWideChar(CP_UTF8,
- 0,
- buf.base,
- buf.len,
- utf16_buffer,
- utf16_buf_used)) {
- if (allocate)
- uv__free(utf16_buffer);
- *error = GetLastError();
- break;
- }
-
- FLUSH_TEXT();
-
- continue;
- }
-
- for (j = 0; j < buf.len; j++) {
- unsigned char c = buf.base[j];
-
- /* Run the character through the utf8 decoder We happily accept non
- * shortest form encodings and invalid code points - there's no real harm
- * that can be done. */
- if (utf8_bytes_left == 0) {
- /* Read utf-8 start byte */
- DWORD first_zero_bit;
- unsigned char not_c = ~c;
-#ifdef _MSC_VER /* msvc */
- if (_BitScanReverse(&first_zero_bit, not_c)) {
-#else /* assume gcc */
- if (c != 0) {
- first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
-#endif
- if (first_zero_bit == 7) {
- /* Ascii - pass right through */
- utf8_codepoint = (unsigned int) c;
-
- } else if (first_zero_bit <= 5) {
- /* Multibyte sequence */
- utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
- utf8_bytes_left = (char) (6 - first_zero_bit);
-
- } else {
- /* Invalid continuation */
- utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
- }
-
- } else {
- /* 0xff -- invalid */
- utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
- }
-
- } else if ((c & 0xc0) == 0x80) {
- /* Valid continuation of utf-8 multibyte sequence */
- utf8_bytes_left--;
- utf8_codepoint <<= 6;
- utf8_codepoint |= ((unsigned int) c & 0x3f);
-
- } else {
- /* Start byte where continuation was expected. */
- utf8_bytes_left = 0;
- utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
- /* Patch buf offset so this character will be parsed again as a start
- * byte. */
- j--;
- }
-
- /* Maybe we need to parse more bytes to find a character. */
- if (utf8_bytes_left != 0) {
- continue;
- }
-
- /* Parse vt100/ansi escape codes */
- if (ansi_parser_state == ANSI_NORMAL) {
- switch (utf8_codepoint) {
- case '\033':
- ansi_parser_state = ANSI_ESCAPE_SEEN;
- continue;
-
- case 0233:
- ansi_parser_state = ANSI_CSI;
- handle->tty.wr.ansi_csi_argc = 0;
- continue;
- }
-
- } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
- switch (utf8_codepoint) {
- case '[':
- ansi_parser_state = ANSI_CSI;
- handle->tty.wr.ansi_csi_argc = 0;
- continue;
-
- case '^':
- case '_':
- case 'P':
- case ']':
- /* Not supported, but we'll have to parse until we see a stop code,
- * e. g. ESC \ or BEL. */
- ansi_parser_state = ANSI_ST_CONTROL;
- continue;
-
- case '\033':
- /* Ignore double escape. */
- continue;
-
- case 'c':
- /* Full console reset. */
- FLUSH_TEXT();
- uv_tty_reset(handle, error);
- ansi_parser_state = ANSI_NORMAL;
- continue;
-
- case '7':
- /* Save the cursor position and text attributes. */
- FLUSH_TEXT();
- uv_tty_save_state(handle, 1, error);
- ansi_parser_state = ANSI_NORMAL;
- continue;
-
- case '8':
- /* Restore the cursor position and text attributes */
- FLUSH_TEXT();
- uv_tty_restore_state(handle, 1, error);
- ansi_parser_state = ANSI_NORMAL;
- continue;
-
- default:
- if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
- /* Single-char control. */
- ansi_parser_state = ANSI_NORMAL;
- continue;
- } else {
- /* Invalid - proceed as normal, */
- ansi_parser_state = ANSI_NORMAL;
- }
- }
-
- } else if (ansi_parser_state & ANSI_CSI) {
- if (!(ansi_parser_state & ANSI_IGNORE)) {
- if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
- /* Parsing a numerical argument */
-
- if (!(ansi_parser_state & ANSI_IN_ARG)) {
- /* We were not currently parsing a number */
-
- /* Check for too many arguments */
- if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
-
- ansi_parser_state |= ANSI_IN_ARG;
- handle->tty.wr.ansi_csi_argc++;
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
- (unsigned short) utf8_codepoint - '0';
- continue;
- } else {
- /* We were already parsing a number. Parse next digit. */
- uint32_t value = 10 *
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
-
- /* Check for overflow. */
- if (value > UINT16_MAX) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
-
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
- (unsigned short) value + (utf8_codepoint - '0');
- continue;
- }
-
- } else if (utf8_codepoint == ';') {
- /* Denotes the end of an argument. */
- if (ansi_parser_state & ANSI_IN_ARG) {
- ansi_parser_state &= ~ANSI_IN_ARG;
- continue;
-
- } else {
- /* If ANSI_IN_ARG is not set, add another argument and default it
- * to 0. */
-
- /* Check for too many arguments */
- if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
-
- handle->tty.wr.ansi_csi_argc++;
- handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
- continue;
- }
-
- } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
- handle->tty.wr.ansi_csi_argc == 0) {
- /* Ignores '?' if it is the first character after CSI[. This is an
- * extension character from the VT100 codeset that is supported and
- * used by most ANSI terminals today. */
- continue;
-
- } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
- (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
- int x, y, d;
-
- /* Command byte */
- switch (utf8_codepoint) {
- case 'A':
- /* cursor up */
- FLUSH_TEXT();
- y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
- uv_tty_move_caret(handle, 0, 1, y, 1, error);
- break;
-
- case 'B':
- /* cursor down */
- FLUSH_TEXT();
- y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
- uv_tty_move_caret(handle, 0, 1, y, 1, error);
- break;
-
- case 'C':
- /* cursor forward */
- FLUSH_TEXT();
- x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
- uv_tty_move_caret(handle, x, 1, 0, 1, error);
- break;
-
- case 'D':
- /* cursor back */
- FLUSH_TEXT();
- x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
- uv_tty_move_caret(handle, x, 1, 0, 1, error);
- break;
-
- case 'E':
- /* cursor next line */
- FLUSH_TEXT();
- y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
- uv_tty_move_caret(handle, 0, 0, y, 1, error);
- break;
-
- case 'F':
- /* cursor previous line */
- FLUSH_TEXT();
- y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
- uv_tty_move_caret(handle, 0, 0, y, 1, error);
- break;
-
- case 'G':
- /* cursor horizontal move absolute */
- FLUSH_TEXT();
- x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
- ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
- uv_tty_move_caret(handle, x, 0, 0, 1, error);
- break;
-
- case 'H':
- case 'f':
- /* cursor move absolute */
- FLUSH_TEXT();
- y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
- ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
- x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
- ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
- uv_tty_move_caret(handle, x, 0, y, 0, error);
- break;
-
- case 'J':
- /* Erase screen */
- FLUSH_TEXT();
- d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
- if (d >= 0 && d <= 2) {
- uv_tty_clear(handle, d, 1, error);
- }
- break;
-
- case 'K':
- /* Erase line */
- FLUSH_TEXT();
- d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
- if (d >= 0 && d <= 2) {
- uv_tty_clear(handle, d, 0, error);
- }
- break;
-
- case 'm':
- /* Set style */
- FLUSH_TEXT();
- uv_tty_set_style(handle, error);
- break;
-
- case 's':
- /* Save the cursor position. */
- FLUSH_TEXT();
- uv_tty_save_state(handle, 0, error);
- break;
-
- case 'u':
- /* Restore the cursor position */
- FLUSH_TEXT();
- uv_tty_restore_state(handle, 0, error);
- break;
-
- case 'l':
- /* Hide the cursor */
- if (handle->tty.wr.ansi_csi_argc == 1 &&
- handle->tty.wr.ansi_csi_argv[0] == 25) {
- FLUSH_TEXT();
- uv_tty_set_cursor_visibility(handle, 0, error);
- }
- break;
-
- case 'h':
- /* Show the cursor */
- if (handle->tty.wr.ansi_csi_argc == 1 &&
- handle->tty.wr.ansi_csi_argv[0] == 25) {
- FLUSH_TEXT();
- uv_tty_set_cursor_visibility(handle, 1, error);
- }
- break;
- }
-
- /* Sequence ended - go back to normal state. */
- ansi_parser_state = ANSI_NORMAL;
- continue;
-
- } else {
- /* We don't support commands that use private mode characters or
- * intermediaries. Ignore the rest of the sequence. */
- ansi_parser_state |= ANSI_IGNORE;
- continue;
- }
- } else {
- /* We're ignoring this command. Stop only on command character. */
- if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
- ansi_parser_state = ANSI_NORMAL;
- }
- continue;
- }
-
- } else if (ansi_parser_state & ANSI_ST_CONTROL) {
- /* Unsupported control code.
- * Ignore everything until we see `BEL` or `ESC \`. */
- if (ansi_parser_state & ANSI_IN_STRING) {
- if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
- if (utf8_codepoint == '"') {
- ansi_parser_state &= ~ANSI_IN_STRING;
- } else if (utf8_codepoint == '\\') {
- ansi_parser_state |= ANSI_BACKSLASH_SEEN;
- }
- } else {
- ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
- }
- } else {
- if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
- (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
- /* End of sequence */
- ansi_parser_state = ANSI_NORMAL;
- } else if (utf8_codepoint == '\033') {
- /* Escape character */
- ansi_parser_state |= ANSI_ESCAPE_SEEN;
- } else if (utf8_codepoint == '"') {
- /* String starting */
- ansi_parser_state |= ANSI_IN_STRING;
- ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
- ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
- } else {
- ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
- }
- }
- continue;
- } else {
- /* Inconsistent state */
- abort();
- }
-
- /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the windows
- * console doesn't really support UTF-16, so just emit the replacement
- * character. */
- if (utf8_codepoint > 0xffff) {
- utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
- }
-
- if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
- /* EOL conversion - emit \r\n when we see \n. */
-
- if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
- /* \n was not preceded by \r; print \r\n. */
- ENSURE_BUFFER_SPACE(2);
- utf16_buf[utf16_buf_used++] = L'\r';
- utf16_buf[utf16_buf_used++] = L'\n';
- } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
- /* \n was followed by \r; do not print the \r, since the source was
- * either \r\n\r (so the second \r is redundant) or was \n\r (so the
- * \n was processed by the last case and an \r automatically
- * inserted). */
- } else {
- /* \r without \n; print \r as-is. */
- ENSURE_BUFFER_SPACE(1);
- utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
- }
-
- previous_eol = (char) utf8_codepoint;
-
- } else if (utf8_codepoint <= 0xffff) {
- /* Encode character into utf-16 buffer. */
- ENSURE_BUFFER_SPACE(1);
- utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
- previous_eol = 0;
- }
- }
- }
-
- /* Flush remaining characters */
- FLUSH_TEXT();
-
- /* Copy cached values back to struct. */
- handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
- handle->tty.wr.utf8_codepoint = utf8_codepoint;
- handle->tty.wr.previous_eol = previous_eol;
- handle->tty.wr.ansi_parser_state = ansi_parser_state;
-
- uv_sem_post(&uv_tty_output_lock);
-
- if (*error == STATUS_SUCCESS) {
- return 0;
- } else {
- return -1;
- }
-
-#undef FLUSH_TEXT
-}
-
-
-int uv_tty_write(uv_loop_t* loop,
- uv_write_t* req,
- uv_tty_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- uv_write_cb cb) {
- DWORD error;
-
- UV_REQ_INIT(req, UV_WRITE);
- req->handle = (uv_stream_t*) handle;
- req->cb = cb;
-
- handle->reqs_pending++;
- handle->stream.conn.write_reqs_pending++;
- REGISTER_HANDLE_REQ(loop, handle, req);
-
- req->u.io.queued_bytes = 0;
-
- if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
- SET_REQ_SUCCESS(req);
- } else {
- SET_REQ_ERROR(req, error);
- }
-
- uv_insert_pending_req(loop, (uv_req_t*) req);
-
- return 0;
-}
-
-
-int uv__tty_try_write(uv_tty_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs) {
- DWORD error;
-
- if (handle->stream.conn.write_reqs_pending > 0)
- return UV_EAGAIN;
-
- if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
- return uv_translate_sys_error(error);
-
- return uv__count_bufs(bufs, nbufs);
-}
-
-
-void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_write_t* req) {
- int err;
-
- handle->write_queue_size -= req->u.io.queued_bytes;
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (req->cb) {
- err = GET_REQ_ERROR(req);
- req->cb(req, uv_translate_sys_error(err));
- }
-
- handle->stream.conn.write_reqs_pending--;
- if (handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*)handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_tty_close(uv_tty_t* handle) {
- assert(handle->u.fd == -1 || handle->u.fd > 2);
- if (handle->flags & UV_HANDLE_READING)
- uv_tty_read_stop(handle);
-
- if (handle->u.fd == -1)
- CloseHandle(handle->handle);
- else
- close(handle->u.fd);
-
- handle->u.fd = -1;
- handle->handle = INVALID_HANDLE_VALUE;
- handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
- uv__handle_closing(handle);
-
- if (handle->reqs_pending == 0) {
- uv_want_endgame(handle->loop, (uv_handle_t*) handle);
- }
-}
-
-
-void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
- if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
- handle->stream.conn.shutdown_req != NULL &&
- handle->stream.conn.write_reqs_pending == 0) {
- UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
-
- /* TTY shutdown is really just a no-op */
- if (handle->stream.conn.shutdown_req->cb) {
- if (handle->flags & UV_HANDLE_CLOSING) {
- handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
- } else {
- handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
- }
- }
-
- handle->stream.conn.shutdown_req = NULL;
-
- DECREASE_PENDING_REQ_COUNT(handle);
- return;
- }
-
- if (handle->flags & UV_HANDLE_CLOSING &&
- handle->reqs_pending == 0) {
- /* The wait handle used for raw reading should be unregistered when the
- * wait callback runs. */
- assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
- handle->tty.rd.read_raw_wait == NULL);
-
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- uv__handle_close(handle);
- }
-}
-
-
-/*
- * uv_process_tty_accept_req() is a stub to keep DELEGATE_STREAM_REQ working
- * TODO: find a way to remove it
- */
-void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_req_t* raw_req) {
- abort();
-}
-
-
-/*
- * uv_process_tty_connect_req() is a stub to keep DELEGATE_STREAM_REQ working
- * TODO: find a way to remove it
- */
-void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
- uv_connect_t* req) {
- abort();
-}
-
-
-int uv_tty_reset_mode(void) {
- /* Not necessary to do anything. */
- return 0;
-}
-
-/* Determine whether or not this version of windows supports
- * proper ANSI color codes. Should be supported as of windows
- * 10 version 1511, build number 10.0.10586.
- */
-static void uv__determine_vterm_state(HANDLE handle) {
- DWORD dwMode = 0;
-
- if (!GetConsoleMode(handle, &dwMode)) {
- uv__vterm_state = UV_UNSUPPORTED;
- return;
- }
-
- dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
- if (!SetConsoleMode(handle, dwMode)) {
- uv__vterm_state = UV_UNSUPPORTED;
- return;
- }
-
- uv__vterm_state = UV_SUPPORTED;
-}
-
-static DWORD WINAPI uv__tty_console_resize_message_loop_thread(void* param) {
- CONSOLE_SCREEN_BUFFER_INFO sb_info;
- MSG msg;
-
- if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
- return 0;
-
- uv__tty_console_width = sb_info.dwSize.X;
- uv__tty_console_height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
-
- if (pSetWinEventHook == NULL)
- return 0;
-
- if (!pSetWinEventHook(EVENT_CONSOLE_LAYOUT,
- EVENT_CONSOLE_LAYOUT,
- NULL,
- uv__tty_console_resize_event,
- 0,
- 0,
- WINEVENT_OUTOFCONTEXT))
- return 0;
-
- while (GetMessage(&msg, NULL, 0, 0)) {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return 0;
-}
-
-static void CALLBACK uv__tty_console_resize_event(HWINEVENTHOOK hWinEventHook,
- DWORD event,
- HWND hwnd,
- LONG idObject,
- LONG idChild,
- DWORD dwEventThread,
- DWORD dwmsEventTime) {
- CONSOLE_SCREEN_BUFFER_INFO sb_info;
- int width, height;
-
- if (!GetConsoleScreenBufferInfo(uv__tty_console_handle, &sb_info))
- return;
-
- width = sb_info.dwSize.X;
- height = sb_info.srWindow.Bottom - sb_info.srWindow.Top + 1;
-
- if (width != uv__tty_console_width || height != uv__tty_console_height) {
- uv__tty_console_width = width;
- uv__tty_console_height = height;
- uv__signal_dispatch(SIGWINCH);
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/udp.cpp b/wpiutil/src/main/native/libuv/src/win/udp.cpp
deleted file mode 100644
index 8aeeab3..0000000
--- a/wpiutil/src/main/native/libuv/src/win/udp.cpp
+++ /dev/null
@@ -1,1035 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-#include "handle-inl.h"
-#include "stream-inl.h"
-#include "req-inl.h"
-
-
-/*
- * Threshold of active udp streams for which to preallocate udp read buffers.
- */
-const unsigned int uv_active_udp_streams_threshold = 0;
-
-/* A zero-size buffer for use by uv_udp_read */
-static char uv_zero_[] = "";
-int uv_udp_getpeername(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getpeername,
- name,
- namelen,
- 0);
-}
-
-
-int uv_udp_getsockname(const uv_udp_t* handle,
- struct sockaddr* name,
- int* namelen) {
-
- return uv__getsockpeername((const uv_handle_t*) handle,
- getsockname,
- name,
- namelen,
- 0);
-}
-
-
-static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
- int family) {
- DWORD yes = 1;
- WSAPROTOCOL_INFOW info;
- int opt_len;
-
- if (handle->socket != INVALID_SOCKET)
- return UV_EBUSY;
-
- /* Set the socket to nonblocking mode */
- if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
- return WSAGetLastError();
- }
-
- /* Make the socket non-inheritable */
- if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
- return GetLastError();
- }
-
- /* Associate it with the I/O completion port. Use uv_handle_t pointer as
- * completion key. */
- if (CreateIoCompletionPort((HANDLE)socket,
- loop->iocp,
- (ULONG_PTR)socket,
- 0) == NULL) {
- return GetLastError();
- }
-
- /* All known Windows that support SetFileCompletionNotificationModes have a
- * bug that makes it impossible to use this function in conjunction with
- * datagram sockets. We can work around that but only if the user is using
- * the default UDP driver (AFD) and has no other. LSPs stacked on top. Here
- * we check whether that is the case. */
- opt_len = (int) sizeof info;
- if (getsockopt(
- socket, SOL_SOCKET, SO_PROTOCOL_INFOW, (char*) &info, &opt_len) ==
- SOCKET_ERROR) {
- return GetLastError();
- }
-
- if (info.ProtocolChain.ChainLen == 1) {
- if (SetFileCompletionNotificationModes(
- (HANDLE) socket,
- FILE_SKIP_SET_EVENT_ON_HANDLE |
- FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
- handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
- handle->func_wsarecv = uv_wsarecv_workaround;
- handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
- } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
- return GetLastError();
- }
- }
-
- handle->socket = socket;
-
- if (family == AF_INET6) {
- handle->flags |= UV_HANDLE_IPV6;
- } else {
- assert(!(handle->flags & UV_HANDLE_IPV6));
- }
-
- return 0;
-}
-
-
-int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
- int domain;
-
- /* Use the lower 8 bits for the domain */
- domain = flags & 0xFF;
- if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
- return UV_EINVAL;
-
- if (flags & ~0xFF)
- return UV_EINVAL;
-
- uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
- handle->socket = INVALID_SOCKET;
- handle->reqs_pending = 0;
- handle->activecnt = 0;
- handle->func_wsarecv = WSARecv;
- handle->func_wsarecvfrom = WSARecvFrom;
- handle->send_queue_size = 0;
- handle->send_queue_count = 0;
- UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV);
- handle->recv_req.data = handle;
-
- /* If anything fails beyond this point we need to remove the handle from
- * the handle queue, since it was added by uv__handle_init.
- */
-
- if (domain != AF_UNSPEC) {
- SOCKET sock;
- DWORD err;
-
- sock = socket(domain, SOCK_DGRAM, 0);
- if (sock == INVALID_SOCKET) {
- err = WSAGetLastError();
- QUEUE_REMOVE(&handle->handle_queue);
- return uv_translate_sys_error(err);
- }
-
- err = uv_udp_set_socket(handle->loop, handle, sock, domain);
- if (err) {
- closesocket(sock);
- QUEUE_REMOVE(&handle->handle_queue);
- return uv_translate_sys_error(err);
- }
- }
-
- return 0;
-}
-
-
-int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
- return uv_udp_init_ex(loop, handle, AF_UNSPEC);
-}
-
-
-void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
- uv_udp_recv_stop(handle);
- closesocket(handle->socket);
- handle->socket = INVALID_SOCKET;
-
- uv__handle_closing(handle);
-
- if (handle->reqs_pending == 0) {
- uv_want_endgame(loop, (uv_handle_t*) handle);
- }
-}
-
-
-void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
- if (handle->flags & UV_HANDLE_CLOSING &&
- handle->reqs_pending == 0) {
- assert(!(handle->flags & UV_HANDLE_CLOSED));
- uv__handle_close(handle);
- }
-}
-
-
-static int uv_udp_maybe_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- int r;
- int err;
- DWORD no = 0;
-
- if (handle->flags & UV_HANDLE_BOUND)
- return 0;
-
- if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
- /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
- return ERROR_INVALID_PARAMETER;
- }
-
- if (handle->socket == INVALID_SOCKET) {
- SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
- if (sock == INVALID_SOCKET) {
- return WSAGetLastError();
- }
-
- err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
- if (err) {
- closesocket(sock);
- return err;
- }
- }
-
- if (flags & UV_UDP_REUSEADDR) {
- DWORD yes = 1;
- /* Set SO_REUSEADDR on the socket. */
- if (setsockopt(handle->socket,
- SOL_SOCKET,
- SO_REUSEADDR,
- (char*) &yes,
- sizeof yes) == SOCKET_ERROR) {
- err = WSAGetLastError();
- return err;
- }
- }
-
- if (addr->sa_family == AF_INET6)
- handle->flags |= UV_HANDLE_IPV6;
-
- if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
- /* On windows IPV6ONLY is on by default. If the user doesn't specify it
- * libuv turns it off. */
-
- /* TODO: how to handle errors? This may fail if there is no ipv4 stack
- * available, or when run on XP/2003 which have no support for dualstack
- * sockets. For now we're silently ignoring the error. */
- setsockopt(handle->socket,
- IPPROTO_IPV6,
- IPV6_V6ONLY,
- (char*) &no,
- sizeof no);
- }
-
- r = bind(handle->socket, addr, addrlen);
- if (r == SOCKET_ERROR) {
- return WSAGetLastError();
- }
-
- handle->flags |= UV_HANDLE_BOUND;
-
- return 0;
-}
-
-
-static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
- uv_req_t* req;
- uv_buf_t buf;
- DWORD bytes, flags;
- int result;
-
- assert(handle->flags & UV_HANDLE_READING);
- assert(!(handle->flags & UV_HANDLE_READ_PENDING));
-
- req = &handle->recv_req;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- /*
- * Preallocate a read buffer if the number of active streams is below
- * the threshold.
- */
- if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
- handle->flags &= ~UV_HANDLE_ZERO_READ;
-
- handle->recv_buffer = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
- if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
- handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
- return;
- }
- assert(handle->recv_buffer.base != NULL);
-
- buf = handle->recv_buffer;
- memset(&handle->recv_from, 0, sizeof handle->recv_from);
- handle->recv_from_len = sizeof handle->recv_from;
- flags = 0;
-
- result = handle->func_wsarecvfrom(handle->socket,
- (WSABUF*) &buf,
- 1,
- &bytes,
- &flags,
- (struct sockaddr*) &handle->recv_from,
- &handle->recv_from_len,
- &req->u.io.overlapped,
- NULL);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
- /* Process the req without IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- req->u.io.overlapped.InternalHigh = bytes;
- handle->reqs_pending++;
- uv_insert_pending_req(loop, req);
- } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
- /* The req will be processed with IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
- } else {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, req);
- handle->reqs_pending++;
- }
-
- } else {
- handle->flags |= UV_HANDLE_ZERO_READ;
-
- buf.base = (char*) uv_zero_;
- buf.len = 0;
- flags = MSG_PEEK;
-
- result = handle->func_wsarecv(handle->socket,
- (WSABUF*) &buf,
- 1,
- &bytes,
- &flags,
- &req->u.io.overlapped,
- NULL);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
- /* Process the req without IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- req->u.io.overlapped.InternalHigh = bytes;
- handle->reqs_pending++;
- uv_insert_pending_req(loop, req);
- } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
- /* The req will be processed with IOCP. */
- handle->flags |= UV_HANDLE_READ_PENDING;
- handle->reqs_pending++;
- } else {
- /* Make this req pending reporting an error. */
- SET_REQ_ERROR(req, WSAGetLastError());
- uv_insert_pending_req(loop, req);
- handle->reqs_pending++;
- }
- }
-}
-
-
-int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
- uv_udp_recv_cb recv_cb) {
- uv_loop_t* loop = handle->loop;
- int err;
-
- if (handle->flags & UV_HANDLE_READING) {
- return UV_EALREADY;
- }
-
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip4_any_,
- sizeof(uv_addr_ip4_any_),
- 0);
- if (err)
- return uv_translate_sys_error(err);
-
- handle->flags |= UV_HANDLE_READING;
- INCREASE_ACTIVE_COUNT(loop, handle);
- loop->active_udp_streams++;
-
- handle->recv_cb = recv_cb;
- handle->alloc_cb = alloc_cb;
-
- /* If reading was stopped and then started again, there could still be a recv
- * request pending. */
- if (!(handle->flags & UV_HANDLE_READ_PENDING))
- uv_udp_queue_recv(loop, handle);
-
- return 0;
-}
-
-
-int uv__udp_recv_stop(uv_udp_t* handle) {
- if (handle->flags & UV_HANDLE_READING) {
- handle->flags &= ~UV_HANDLE_READING;
- handle->loop->active_udp_streams--;
- DECREASE_ACTIVE_COUNT(loop, handle);
- }
-
- return 0;
-}
-
-
-static int uv__send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_udp_send_cb cb) {
- uv_loop_t* loop = handle->loop;
- DWORD result, bytes;
-
- UV_REQ_INIT(req, UV_UDP_SEND);
- req->handle = handle;
- req->cb = cb;
- memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
-
- result = WSASendTo(handle->socket,
- (WSABUF*)bufs,
- nbufs,
- &bytes,
- 0,
- addr,
- addrlen,
- &req->u.io.overlapped,
- NULL);
-
- if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
- /* Request completed immediately. */
- req->u.io.queued_bytes = 0;
- handle->reqs_pending++;
- handle->send_queue_size += req->u.io.queued_bytes;
- handle->send_queue_count++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- uv_insert_pending_req(loop, (uv_req_t*)req);
- } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
- /* Request queued by the kernel. */
- req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
- handle->reqs_pending++;
- handle->send_queue_size += req->u.io.queued_bytes;
- handle->send_queue_count++;
- REGISTER_HANDLE_REQ(loop, handle, req);
- } else {
- /* Send failed due to an error. */
- return WSAGetLastError();
- }
-
- return 0;
-}
-
-
-void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
- uv_req_t* req) {
- uv_buf_t buf;
- int partial;
-
- assert(handle->type == UV_UDP);
-
- handle->flags &= ~UV_HANDLE_READ_PENDING;
-
- if (!REQ_SUCCESS(req)) {
- DWORD err = GET_REQ_SOCK_ERROR(req);
- if (err == WSAEMSGSIZE) {
- /* Not a real error, it just indicates that the received packet was
- * bigger than the receive buffer. */
- } else if (err == WSAECONNRESET || err == WSAENETRESET) {
- /* A previous sendto operation failed; ignore this error. If zero-reading
- * we need to call WSARecv/WSARecvFrom _without_ the. MSG_PEEK flag to
- * clear out the error queue. For nonzero reads, immediately queue a new
- * receive. */
- if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
- goto done;
- }
- } else {
- /* A real error occurred. Report the error to the user only if we're
- * currently reading. */
- if (handle->flags & UV_HANDLE_READING) {
- uv_udp_recv_stop(handle);
- buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
- uv_buf_init(NULL, 0) : handle->recv_buffer;
- handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
- }
- goto done;
- }
- }
-
- if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
- /* Successful read */
- partial = !REQ_SUCCESS(req);
- handle->recv_cb(handle,
- req->u.io.overlapped.InternalHigh,
- &handle->recv_buffer,
- (const struct sockaddr*) &handle->recv_from,
- partial ? UV_UDP_PARTIAL : 0);
- } else if (handle->flags & UV_HANDLE_READING) {
- DWORD bytes, err, flags;
- struct sockaddr_storage from;
- int from_len;
-
- /* Do a nonblocking receive.
- * TODO: try to read multiple datagrams at once. FIONREAD maybe? */
- buf = uv_buf_init(NULL, 0);
- handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
- if (buf.base == NULL || buf.len == 0) {
- handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
- goto done;
- }
- assert(buf.base != NULL);
-
- memset(&from, 0, sizeof from);
- from_len = sizeof from;
-
- flags = 0;
-
- if (WSARecvFrom(handle->socket,
- (WSABUF*)&buf,
- 1,
- &bytes,
- &flags,
- (struct sockaddr*) &from,
- &from_len,
- NULL,
- NULL) != SOCKET_ERROR) {
-
- /* Message received */
- handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
- } else {
- err = WSAGetLastError();
- if (err == WSAEMSGSIZE) {
- /* Message truncated */
- handle->recv_cb(handle,
- bytes,
- &buf,
- (const struct sockaddr*) &from,
- UV_UDP_PARTIAL);
- } else if (err == WSAEWOULDBLOCK) {
- /* Kernel buffer empty */
- handle->recv_cb(handle, 0, &buf, NULL, 0);
- } else if (err == WSAECONNRESET || err == WSAENETRESET) {
- /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
- * that a previous sendto operation failed.
- */
- handle->recv_cb(handle, 0, &buf, NULL, 0);
- } else {
- /* Any other error that we want to report back to the user. */
- uv_udp_recv_stop(handle);
- handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
- }
- }
- }
-
-done:
- /* Post another read if still reading and not closing. */
- if ((handle->flags & UV_HANDLE_READING) &&
- !(handle->flags & UV_HANDLE_READ_PENDING)) {
- uv_udp_queue_recv(loop, handle);
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
- uv_udp_send_t* req) {
- int err;
-
- assert(handle->type == UV_UDP);
-
- assert(handle->send_queue_size >= req->u.io.queued_bytes);
- assert(handle->send_queue_count >= 1);
- handle->send_queue_size -= req->u.io.queued_bytes;
- handle->send_queue_count--;
-
- UNREGISTER_HANDLE_REQ(loop, handle, req);
-
- if (req->cb) {
- err = 0;
- if (!REQ_SUCCESS(req)) {
- err = GET_REQ_SOCK_ERROR(req);
- }
- req->cb(req, uv_translate_sys_error(err));
- }
-
- DECREASE_PENDING_REQ_COUNT(handle);
-}
-
-
-static int uv__udp_set_membership4(uv_udp_t* handle,
- const struct sockaddr_in* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- int err;
- int optname;
- struct ip_mreq mreq;
-
- if (handle->flags & UV_HANDLE_IPV6)
- return UV_EINVAL;
-
- /* If the socket is unbound, bind to inaddr_any. */
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip4_any_,
- sizeof(uv_addr_ip4_any_),
- UV_UDP_REUSEADDR);
- if (err)
- return uv_translate_sys_error(err);
-
- memset(&mreq, 0, sizeof mreq);
-
- if (interface_addr) {
- err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
- if (err)
- return err;
- } else {
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- }
-
- mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
-
- switch (membership) {
- case UV_JOIN_GROUP:
- optname = IP_ADD_MEMBERSHIP;
- break;
- case UV_LEAVE_GROUP:
- optname = IP_DROP_MEMBERSHIP;
- break;
- default:
- return UV_EINVAL;
- }
-
- if (setsockopt(handle->socket,
- IPPROTO_IP,
- optname,
- (char*) &mreq,
- sizeof mreq) == SOCKET_ERROR) {
- return uv_translate_sys_error(WSAGetLastError());
- }
-
- return 0;
-}
-
-
-int uv__udp_set_membership6(uv_udp_t* handle,
- const struct sockaddr_in6* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- int optname;
- int err;
- struct ipv6_mreq mreq;
- struct sockaddr_in6 addr6;
-
- if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
- return UV_EINVAL;
-
- err = uv_udp_maybe_bind(handle,
- (const struct sockaddr*) &uv_addr_ip6_any_,
- sizeof(uv_addr_ip6_any_),
- UV_UDP_REUSEADDR);
-
- if (err)
- return uv_translate_sys_error(err);
-
- memset(&mreq, 0, sizeof(mreq));
-
- if (interface_addr) {
- if (uv_ip6_addr(interface_addr, 0, &addr6))
- return UV_EINVAL;
- mreq.ipv6mr_interface = addr6.sin6_scope_id;
- } else {
- mreq.ipv6mr_interface = 0;
- }
-
- mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
-
- switch (membership) {
- case UV_JOIN_GROUP:
- optname = IPV6_ADD_MEMBERSHIP;
- break;
- case UV_LEAVE_GROUP:
- optname = IPV6_DROP_MEMBERSHIP;
- break;
- default:
- return UV_EINVAL;
- }
-
- if (setsockopt(handle->socket,
- IPPROTO_IPV6,
- optname,
- (char*) &mreq,
- sizeof mreq) == SOCKET_ERROR) {
- return uv_translate_sys_error(WSAGetLastError());
- }
-
- return 0;
-}
-
-
-int uv_udp_set_membership(uv_udp_t* handle,
- const char* multicast_addr,
- const char* interface_addr,
- uv_membership membership) {
- struct sockaddr_in addr4;
- struct sockaddr_in6 addr6;
-
- if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
- return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
- else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
- return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
- else
- return UV_EINVAL;
-}
-
-
-int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
- struct sockaddr_storage addr_st;
- struct sockaddr_in* addr4;
- struct sockaddr_in6* addr6;
-
- addr4 = (struct sockaddr_in*) &addr_st;
- addr6 = (struct sockaddr_in6*) &addr_st;
-
- if (!interface_addr) {
- memset(&addr_st, 0, sizeof addr_st);
- if (handle->flags & UV_HANDLE_IPV6) {
- addr_st.ss_family = AF_INET6;
- addr6->sin6_scope_id = 0;
- } else {
- addr_st.ss_family = AF_INET;
- addr4->sin_addr.s_addr = htonl(INADDR_ANY);
- }
- } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
- /* nothing, address was parsed */
- } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
- /* nothing, address was parsed */
- } else {
- return UV_EINVAL;
- }
-
- if (handle->socket == INVALID_SOCKET)
- return UV_EBADF;
-
- if (addr_st.ss_family == AF_INET) {
- if (setsockopt(handle->socket,
- IPPROTO_IP,
- IP_MULTICAST_IF,
- (char*) &addr4->sin_addr,
- sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
- return uv_translate_sys_error(WSAGetLastError());
- }
- } else if (addr_st.ss_family == AF_INET6) {
- if (setsockopt(handle->socket,
- IPPROTO_IPV6,
- IPV6_MULTICAST_IF,
- (char*) &addr6->sin6_scope_id,
- sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
- return uv_translate_sys_error(WSAGetLastError());
- }
- } else {
- assert(0 && "unexpected address family");
- abort();
- }
-
- return 0;
-}
-
-
-int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
- BOOL optval = (BOOL) value;
-
- if (handle->socket == INVALID_SOCKET)
- return UV_EBADF;
-
- if (setsockopt(handle->socket,
- SOL_SOCKET,
- SO_BROADCAST,
- (char*) &optval,
- sizeof optval)) {
- return uv_translate_sys_error(WSAGetLastError());
- }
-
- return 0;
-}
-
-
-int uv__udp_is_bound(uv_udp_t* handle) {
- struct sockaddr_storage addr;
- int addrlen;
-
- addrlen = sizeof(addr);
- if (uv_udp_getsockname(handle, (struct sockaddr*) &addr, &addrlen) != 0)
- return 0;
-
- return addrlen > 0;
-}
-
-
-int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
- WSAPROTOCOL_INFOW protocol_info;
- int opt_len;
- int err;
-
- /* Detect the address family of the socket. */
- opt_len = (int) sizeof protocol_info;
- if (getsockopt(sock,
- SOL_SOCKET,
- SO_PROTOCOL_INFOW,
- (char*) &protocol_info,
- &opt_len) == SOCKET_ERROR) {
- return uv_translate_sys_error(GetLastError());
- }
-
- err = uv_udp_set_socket(handle->loop,
- handle,
- sock,
- protocol_info.iAddressFamily);
- if (err)
- return uv_translate_sys_error(err);
-
- if (uv__udp_is_bound(handle))
- handle->flags |= UV_HANDLE_BOUND;
-
- if (uv__udp_is_connected(handle))
- handle->flags |= UV_HANDLE_UDP_CONNECTED;
-
- return 0;
-}
-
-
-#define SOCKOPT_SETTER(name, option4, option6, validate) \
- int uv_udp_set_##name(uv_udp_t* handle, int value) { \
- DWORD optval = (DWORD) value; \
- \
- if (!(validate(value))) { \
- return UV_EINVAL; \
- } \
- \
- if (handle->socket == INVALID_SOCKET) \
- return UV_EBADF; \
- \
- if (!(handle->flags & UV_HANDLE_IPV6)) { \
- /* Set IPv4 socket option */ \
- if (setsockopt(handle->socket, \
- IPPROTO_IP, \
- option4, \
- (char*) &optval, \
- sizeof optval)) { \
- return uv_translate_sys_error(WSAGetLastError()); \
- } \
- } else { \
- /* Set IPv6 socket option */ \
- if (setsockopt(handle->socket, \
- IPPROTO_IPV6, \
- option6, \
- (char*) &optval, \
- sizeof optval)) { \
- return uv_translate_sys_error(WSAGetLastError()); \
- } \
- } \
- return 0; \
- }
-
-#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
-#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
-#define VALIDATE_MULTICAST_LOOP(value) (1)
-
-SOCKOPT_SETTER(ttl,
- IP_TTL,
- IPV6_HOPLIMIT,
- VALIDATE_TTL)
-SOCKOPT_SETTER(multicast_ttl,
- IP_MULTICAST_TTL,
- IPV6_MULTICAST_HOPS,
- VALIDATE_MULTICAST_TTL)
-SOCKOPT_SETTER(multicast_loop,
- IP_MULTICAST_LOOP,
- IPV6_MULTICAST_LOOP,
- VALIDATE_MULTICAST_LOOP)
-
-#undef SOCKOPT_SETTER
-#undef VALIDATE_TTL
-#undef VALIDATE_MULTICAST_TTL
-#undef VALIDATE_MULTICAST_LOOP
-
-
-/* This function is an egress point, i.e. it returns libuv errors rather than
- * system errors.
- */
-int uv__udp_bind(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen,
- unsigned int flags) {
- int err;
-
- err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
- if (err)
- return uv_translate_sys_error(err);
-
- return 0;
-}
-
-
-int uv__udp_connect(uv_udp_t* handle,
- const struct sockaddr* addr,
- unsigned int addrlen) {
- const struct sockaddr* bind_addr;
- int err;
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- else if (addrlen == sizeof(uv_addr_ip6_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- else
- return UV_EINVAL;
-
- err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
- if (err)
- return uv_translate_sys_error(err);
- }
-
- err = connect(handle->socket, addr, addrlen);
- if (err)
- return uv_translate_sys_error(err);
-
- handle->flags |= UV_HANDLE_UDP_CONNECTED;
-
- return 0;
-}
-
-
-int uv__udp_disconnect(uv_udp_t* handle) {
- int err;
- struct sockaddr addr;
-
- memset(&addr, 0, sizeof(addr));
-
- err = connect(handle->socket, &addr, sizeof(addr));
- if (err)
- return uv_translate_sys_error(err);
-
- handle->flags &= ~UV_HANDLE_UDP_CONNECTED;
- return 0;
-}
-
-
-/* This function is an egress point, i.e. it returns libuv errors rather than
- * system errors.
- */
-int uv__udp_send(uv_udp_send_t* req,
- uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen,
- uv_udp_send_cb send_cb) {
- const struct sockaddr* bind_addr;
- int err;
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- else if (addrlen == sizeof(uv_addr_ip6_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- else
- return UV_EINVAL;
-
- err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
- if (err)
- return uv_translate_sys_error(err);
- }
-
- err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
- if (err)
- return uv_translate_sys_error(err);
-
- return 0;
-}
-
-
-int uv__udp_try_send(uv_udp_t* handle,
- const uv_buf_t bufs[],
- unsigned int nbufs,
- const struct sockaddr* addr,
- unsigned int addrlen) {
- DWORD bytes;
- const struct sockaddr* bind_addr;
- struct sockaddr_storage converted;
- int err;
-
- assert(nbufs > 0);
-
- if (addr != NULL) {
- err = uv__convert_to_localhost_if_unspecified(addr, &converted);
- if (err)
- return err;
- }
-
- /* Already sending a message.*/
- if (handle->send_queue_count != 0)
- return UV_EAGAIN;
-
- if (!(handle->flags & UV_HANDLE_BOUND)) {
- if (addrlen == sizeof(uv_addr_ip4_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
- else if (addrlen == sizeof(uv_addr_ip6_any_))
- bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
- else
- return UV_EINVAL;
- err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
- if (err)
- return uv_translate_sys_error(err);
- }
-
- err = WSASendTo(handle->socket,
- (WSABUF*)bufs,
- nbufs,
- &bytes,
- 0,
- (const struct sockaddr*) &converted,
- addrlen,
- NULL,
- NULL);
-
- if (err)
- return uv_translate_sys_error(WSAGetLastError());
-
- return bytes;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/util.cpp b/wpiutil/src/main/native/libuv/src/win/util.cpp
deleted file mode 100644
index b5afb1d..0000000
--- a/wpiutil/src/main/native/libuv/src/win/util.cpp
+++ /dev/null
@@ -1,1811 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <direct.h>
-#include <limits.h>
-#include <stdio.h>
-#include <string.h>
-#include <time.h>
-#include <wchar.h>
-
-#include "uv.h"
-#include "internal.h"
-
-#include <winsock2.h>
-#include <winperf.h>
-#include <iphlpapi.h>
-#include <psapi.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <userenv.h>
-#include <math.h>
-
-/*
- * Max title length; the only thing MSDN tells us about the maximum length
- * of the console title is that it is smaller than 64K. However in practice
- * it is much smaller, and there is no way to figure out what the exact length
- * of the title is or can be, at least not on XP. To make it even more
- * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
- * than the actual maximum length. So we make a conservative guess here;
- * just don't put the novel you're writing in the title, unless the plot
- * survives truncation.
- */
-#define MAX_TITLE_LENGTH 8192
-
-/* The number of nanoseconds in one second. */
-#define UV__NANOSEC 1000000000
-
-/* Max user name length, from iphlpapi.h */
-#ifndef UNLEN
-# define UNLEN 256
-#endif
-
-
-/* Maximum environment variable size, including the terminating null */
-#define MAX_ENV_VAR_LENGTH 32767
-
-/* Cached copy of the process title, plus a mutex guarding it. */
-static char *process_title;
-static CRITICAL_SECTION process_title_lock;
-
-#pragma comment(lib, "Advapi32.lib")
-#pragma comment(lib, "IPHLPAPI.lib")
-#pragma comment(lib, "Psapi.lib")
-#pragma comment(lib, "Userenv.lib")
-#pragma comment(lib, "kernel32.lib")
-
-/* Interval (in seconds) of the high-resolution clock. */
-static double hrtime_interval_ = 0;
-
-
-/*
- * One-time initialization code for functionality defined in util.c.
- */
-void uv__util_init(void) {
- LARGE_INTEGER perf_frequency;
-
- /* Initialize process title access mutex. */
- InitializeCriticalSection(&process_title_lock);
-
- /* Retrieve high-resolution timer frequency
- * and precompute its reciprocal.
- */
- if (QueryPerformanceFrequency(&perf_frequency)) {
- hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
- } else {
- hrtime_interval_= 0;
- }
-}
-
-
-int uv_exepath(char* buffer, size_t* size_ptr) {
- int utf8_len, utf16_buffer_len, utf16_len;
- WCHAR* utf16_buffer;
- int err;
-
- if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
- return UV_EINVAL;
- }
-
- if (*size_ptr > 32768) {
- /* Windows paths can never be longer than this. */
- utf16_buffer_len = 32768;
- } else {
- utf16_buffer_len = (int) *size_ptr;
- }
-
- utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
- if (!utf16_buffer) {
- return UV_ENOMEM;
- }
-
- /* Get the path as UTF-16. */
- utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
- if (utf16_len <= 0) {
- err = GetLastError();
- goto error;
- }
-
- /* utf16_len contains the length, *not* including the terminating null. */
- utf16_buffer[utf16_len] = L'\0';
-
- /* Convert to UTF-8 */
- utf8_len = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16_buffer,
- -1,
- buffer,
- (int) *size_ptr,
- NULL,
- NULL);
- if (utf8_len == 0) {
- err = GetLastError();
- goto error;
- }
-
- uv__free(utf16_buffer);
-
- /* utf8_len *does* include the terminating null at this point, but the
- * returned size shouldn't. */
- *size_ptr = utf8_len - 1;
- return 0;
-
- error:
- uv__free(utf16_buffer);
- return uv_translate_sys_error(err);
-}
-
-
-int uv_cwd(char* buffer, size_t* size) {
- DWORD utf16_len;
- WCHAR utf16_buffer[MAX_PATH];
- int r;
-
- if (buffer == NULL || size == NULL) {
- return UV_EINVAL;
- }
-
- utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
- if (utf16_len == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (utf16_len > MAX_PATH) {
- /* This should be impossible; however the CRT has a code path to deal with
- * this scenario, so I added a check anyway. */
- return UV_EIO;
- }
-
- /* utf16_len contains the length, *not* including the terminating null. */
- utf16_buffer[utf16_len] = L'\0';
-
- /* The returned directory should not have a trailing slash, unless it points
- * at a drive root, like c:\. Remove it if needed. */
- if (utf16_buffer[utf16_len - 1] == L'\\' &&
- !(utf16_len == 3 && utf16_buffer[1] == L':')) {
- utf16_len--;
- utf16_buffer[utf16_len] = L'\0';
- }
-
- /* Check how much space we need */
- r = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16_buffer,
- -1,
- NULL,
- 0,
- NULL,
- NULL);
- if (r == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (r > (int) *size) {
- *size = r;
- return UV_ENOBUFS;
- }
-
- /* Convert to UTF-8 */
- r = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16_buffer,
- -1,
- buffer,
- *size > INT_MAX ? INT_MAX : (int) *size,
- NULL,
- NULL);
- if (r == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- *size = r - 1;
- return 0;
-}
-
-
-int uv_chdir(const char* dir) {
- WCHAR utf16_buffer[MAX_PATH];
- size_t utf16_len;
- WCHAR drive_letter, env_var[4];
-
- if (dir == NULL) {
- return UV_EINVAL;
- }
-
- if (MultiByteToWideChar(CP_UTF8,
- 0,
- dir,
- -1,
- utf16_buffer,
- MAX_PATH) == 0) {
- DWORD error = GetLastError();
- /* The maximum length of the current working directory is 260 chars,
- * including terminating null. If it doesn't fit, the path name must be too
- * long. */
- if (error == ERROR_INSUFFICIENT_BUFFER) {
- return UV_ENAMETOOLONG;
- } else {
- return uv_translate_sys_error(error);
- }
- }
-
- if (!SetCurrentDirectoryW(utf16_buffer)) {
- return uv_translate_sys_error(GetLastError());
- }
-
- /* Windows stores the drive-local path in an "hidden" environment variable,
- * which has the form "=C:=C:\Windows". SetCurrentDirectory does not update
- * this, so we'll have to do it. */
- utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
- if (utf16_len == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (utf16_len > MAX_PATH) {
- return UV_EIO;
- }
-
- /* The returned directory should not have a trailing slash, unless it points
- * at a drive root, like c:\. Remove it if needed. */
- if (utf16_buffer[utf16_len - 1] == L'\\' &&
- !(utf16_len == 3 && utf16_buffer[1] == L':')) {
- utf16_len--;
- utf16_buffer[utf16_len] = L'\0';
- }
-
- if (utf16_len < 2 || utf16_buffer[1] != L':') {
- /* Doesn't look like a drive letter could be there - probably an UNC path.
- * TODO: Need to handle win32 namespaces like \\?\C:\ ? */
- drive_letter = 0;
- } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
- drive_letter = utf16_buffer[0];
- } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
- /* Convert to uppercase. */
- drive_letter = utf16_buffer[0] - L'a' + L'A';
- } else {
- /* Not valid. */
- drive_letter = 0;
- }
-
- if (drive_letter != 0) {
- /* Construct the environment variable name and set it. */
- env_var[0] = L'=';
- env_var[1] = drive_letter;
- env_var[2] = L':';
- env_var[3] = L'\0';
-
- if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
- return uv_translate_sys_error(GetLastError());
- }
- }
-
- return 0;
-}
-
-
-void uv_loadavg(double avg[3]) {
- /* Can't be implemented */
- avg[0] = avg[1] = avg[2] = 0;
-}
-
-
-uint64_t uv_get_free_memory(void) {
- MEMORYSTATUSEX memory_status;
- memory_status.dwLength = sizeof(memory_status);
-
- if (!GlobalMemoryStatusEx(&memory_status)) {
- return -1;
- }
-
- return (uint64_t)memory_status.ullAvailPhys;
-}
-
-
-uint64_t uv_get_total_memory(void) {
- MEMORYSTATUSEX memory_status;
- memory_status.dwLength = sizeof(memory_status);
-
- if (!GlobalMemoryStatusEx(&memory_status)) {
- return -1;
- }
-
- return (uint64_t)memory_status.ullTotalPhys;
-}
-
-
-uint64_t uv_get_constrained_memory(void) {
- return 0; /* Memory constraints are unknown. */
-}
-
-
-uv_pid_t uv_os_getpid(void) {
- return GetCurrentProcessId();
-}
-
-
-uv_pid_t uv_os_getppid(void) {
- int parent_pid = -1;
- HANDLE handle;
- PROCESSENTRY32 pe;
- DWORD current_pid = GetCurrentProcessId();
-
- pe.dwSize = sizeof(PROCESSENTRY32);
- handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-
- if (Process32First(handle, &pe)) {
- do {
- if (pe.th32ProcessID == current_pid) {
- parent_pid = pe.th32ParentProcessID;
- break;
- }
- } while( Process32Next(handle, &pe));
- }
-
- CloseHandle(handle);
- return parent_pid;
-}
-
-
-char** uv_setup_args(int argc, char** argv) {
- return argv;
-}
-
-
-int uv_set_process_title(const char* title) {
- int err;
- int length;
- WCHAR* title_w = NULL;
-
- uv__once_init();
-
- /* Find out how big the buffer for the wide-char title must be */
- length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
- if (!length) {
- err = GetLastError();
- goto done;
- }
-
- /* Convert to wide-char string */
- title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
- if (!title_w) {
- uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
- }
-
- length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
- if (!length) {
- err = GetLastError();
- goto done;
- }
-
- /* If the title must be truncated insert a \0 terminator there */
- if (length > MAX_TITLE_LENGTH) {
- title_w[MAX_TITLE_LENGTH - 1] = L'\0';
- }
-
- if (!SetConsoleTitleW(title_w)) {
- err = GetLastError();
- goto done;
- }
-
- EnterCriticalSection(&process_title_lock);
- uv__free(process_title);
- process_title = uv__strdup(title);
- LeaveCriticalSection(&process_title_lock);
-
- err = 0;
-
-done:
- uv__free(title_w);
- return uv_translate_sys_error(err);
-}
-
-
-static int uv__get_process_title(void) {
- WCHAR title_w[MAX_TITLE_LENGTH];
-
- if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
- return -1;
- }
-
- if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
- return -1;
-
- return 0;
-}
-
-
-int uv_get_process_title(char* buffer, size_t size) {
- size_t len;
-
- if (buffer == NULL || size == 0)
- return UV_EINVAL;
-
- uv__once_init();
-
- EnterCriticalSection(&process_title_lock);
- /*
- * If the process_title was never read before nor explicitly set,
- * we must query it with getConsoleTitleW
- */
- if (!process_title && uv__get_process_title() == -1) {
- LeaveCriticalSection(&process_title_lock);
- return uv_translate_sys_error(GetLastError());
- }
-
- assert(process_title);
- len = strlen(process_title) + 1;
-
- if (size < len) {
- LeaveCriticalSection(&process_title_lock);
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, process_title, len);
- LeaveCriticalSection(&process_title_lock);
-
- return 0;
-}
-
-
-uint64_t uv_hrtime(void) {
- uv__once_init();
- return uv__hrtime(UV__NANOSEC);
-}
-
-uint64_t uv__hrtime(double scale) {
- LARGE_INTEGER counter;
-
- /* If the performance interval is zero, there's no support. */
- if (hrtime_interval_ == 0) {
- return 0;
- }
-
- if (!QueryPerformanceCounter(&counter)) {
- return 0;
- }
-
- /* Because we have no guarantee about the order of magnitude of the
- * performance counter interval, integer math could cause this computation
- * to overflow. Therefore we resort to floating point math.
- */
- return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
-}
-
-
-int uv_resident_set_memory(size_t* rss) {
- HANDLE current_process;
- PROCESS_MEMORY_COUNTERS pmc;
-
- current_process = GetCurrentProcess();
-
- if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
- return uv_translate_sys_error(GetLastError());
- }
-
- *rss = pmc.WorkingSetSize;
-
- return 0;
-}
-
-
-int uv_uptime(double* uptime) {
- BYTE stack_buffer[4096];
- BYTE* malloced_buffer = NULL;
- BYTE* buffer = (BYTE*) stack_buffer;
- size_t buffer_size = sizeof(stack_buffer);
- DWORD data_size;
-
- PERF_DATA_BLOCK* data_block;
- PERF_OBJECT_TYPE* object_type;
- PERF_COUNTER_DEFINITION* counter_definition;
-
- DWORD i;
-
- for (;;) {
- LONG result;
-
- data_size = (DWORD) buffer_size;
- result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
- L"2",
- NULL,
- NULL,
- buffer,
- &data_size);
- if (result == ERROR_SUCCESS) {
- break;
- } else if (result != ERROR_MORE_DATA) {
- *uptime = 0;
- return uv_translate_sys_error(result);
- }
-
- buffer_size *= 2;
- /* Don't let the buffer grow infinitely. */
- if (buffer_size > 1 << 20) {
- goto internalError;
- }
-
- uv__free(malloced_buffer);
-
- buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
- if (malloced_buffer == NULL) {
- *uptime = 0;
- return UV_ENOMEM;
- }
- }
-
- if (data_size < sizeof(*data_block))
- goto internalError;
-
- data_block = (PERF_DATA_BLOCK*) buffer;
-
- if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
- goto internalError;
-
- if (data_size < data_block->HeaderLength + sizeof(*object_type))
- goto internalError;
-
- object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
-
- if (object_type->NumInstances != PERF_NO_INSTANCES)
- goto internalError;
-
- counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
- data_block->HeaderLength + object_type->HeaderLength);
- for (i = 0; i < object_type->NumCounters; i++) {
- if ((BYTE*) counter_definition + sizeof(*counter_definition) >
- buffer + data_size) {
- break;
- }
-
- if (counter_definition->CounterNameTitleIndex == 674 &&
- counter_definition->CounterSize == sizeof(uint64_t)) {
- if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
- !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
- goto internalError;
- } else {
- BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
- counter_definition->CounterOffset;
- uint64_t value = *((uint64_t*) address);
- *uptime = floor((double) (object_type->PerfTime.QuadPart - value) /
- (double) object_type->PerfFreq.QuadPart);
- uv__free(malloced_buffer);
- return 0;
- }
- }
-
- counter_definition = (PERF_COUNTER_DEFINITION*)
- ((BYTE*) counter_definition + counter_definition->ByteLength);
- }
-
- /* If we get here, the uptime value was not found. */
- uv__free(malloced_buffer);
- *uptime = 0;
- return UV_ENOSYS;
-
- internalError:
- uv__free(malloced_buffer);
- *uptime = 0;
- return UV_EIO;
-}
-
-
-int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
- uv_cpu_info_t* cpu_infos;
- SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
- DWORD sppi_size;
- SYSTEM_INFO system_info;
- DWORD cpu_count, i;
- NTSTATUS status;
- ULONG result_size;
- int err;
- uv_cpu_info_t* cpu_info;
-
- cpu_infos = NULL;
- cpu_count = 0;
- sppi = NULL;
-
- uv__once_init();
-
- GetSystemInfo(&system_info);
- cpu_count = system_info.dwNumberOfProcessors;
-
- cpu_infos = (uv_cpu_info_t*)uv__calloc(cpu_count, sizeof *cpu_infos);
- if (cpu_infos == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
-
- sppi_size = cpu_count * sizeof(*sppi);
- sppi = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION*)uv__malloc(sppi_size);
- if (sppi == NULL) {
- err = ERROR_OUTOFMEMORY;
- goto error;
- }
-
- status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
- sppi,
- sppi_size,
- &result_size);
- if (!NT_SUCCESS(status)) {
- err = pRtlNtStatusToDosError(status);
- goto error;
- }
-
- assert(result_size == sppi_size);
-
- for (i = 0; i < cpu_count; i++) {
- WCHAR key_name[128];
- HKEY processor_key;
- DWORD cpu_speed;
- DWORD cpu_speed_size = sizeof(cpu_speed);
- WCHAR cpu_brand[256];
- DWORD cpu_brand_size = sizeof(cpu_brand);
- size_t len;
-
- len = _snwprintf(key_name,
- ARRAY_SIZE(key_name),
- L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
- i);
-
- assert(len > 0 && len < ARRAY_SIZE(key_name));
-
- err = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- key_name,
- 0,
- KEY_QUERY_VALUE,
- &processor_key);
- if (err != ERROR_SUCCESS) {
- goto error;
- }
-
- err = RegQueryValueExW(processor_key,
- L"~MHz",
- NULL,
- NULL,
- (BYTE*)&cpu_speed,
- &cpu_speed_size);
- if (err != ERROR_SUCCESS) {
- RegCloseKey(processor_key);
- goto error;
- }
-
- err = RegQueryValueExW(processor_key,
- L"ProcessorNameString",
- NULL,
- NULL,
- (BYTE*)&cpu_brand,
- &cpu_brand_size);
- RegCloseKey(processor_key);
- if (err != ERROR_SUCCESS)
- goto error;
-
- cpu_info = &cpu_infos[i];
- cpu_info->speed = cpu_speed;
- cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
- cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
- sppi[i].IdleTime.QuadPart) / 10000;
- cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
- cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
- cpu_info->cpu_times.nice = 0;
-
- uv__convert_utf16_to_utf8(cpu_brand,
- cpu_brand_size / sizeof(WCHAR),
- &(cpu_info->model));
- }
-
- uv__free(sppi);
-
- *cpu_count_ptr = cpu_count;
- *cpu_infos_ptr = cpu_infos;
-
- return 0;
-
- error:
- if (cpu_infos != NULL) {
- /* This is safe because the cpu_infos array is zeroed on allocation. */
- for (i = 0; i < cpu_count; i++)
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
- uv__free(sppi);
-
- return uv_translate_sys_error(err);
-}
-
-
-void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
- int i;
-
- for (i = 0; i < count; i++) {
- uv__free(cpu_infos[i].model);
- }
-
- uv__free(cpu_infos);
-}
-
-
-static int is_windows_version_or_greater(DWORD os_major,
- DWORD os_minor,
- WORD service_pack_major,
- WORD service_pack_minor) {
- OSVERSIONINFOEX osvi;
- DWORDLONG condition_mask = 0;
- int op = VER_GREATER_EQUAL;
-
- /* Initialize the OSVERSIONINFOEX structure. */
- ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
- osvi.dwMajorVersion = os_major;
- osvi.dwMinorVersion = os_minor;
- osvi.wServicePackMajor = service_pack_major;
- osvi.wServicePackMinor = service_pack_minor;
-
- /* Initialize the condition mask. */
- VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
- VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
- VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
- VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
-
- /* Perform the test. */
- return (int) VerifyVersionInfo(
- &osvi,
- VER_MAJORVERSION | VER_MINORVERSION |
- VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
- condition_mask);
-}
-
-
-static int address_prefix_match(int family,
- struct sockaddr* address,
- struct sockaddr* prefix_address,
- int prefix_len) {
- uint8_t* address_data;
- uint8_t* prefix_address_data;
- int i;
-
- assert(address->sa_family == family);
- assert(prefix_address->sa_family == family);
-
- if (family == AF_INET6) {
- address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
- prefix_address_data =
- (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
- } else {
- address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
- prefix_address_data =
- (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
- }
-
- for (i = 0; i < prefix_len >> 3; i++) {
- if (address_data[i] != prefix_address_data[i])
- return 0;
- }
-
- if (prefix_len % 8)
- return prefix_address_data[i] ==
- (address_data[i] & (0xff << (8 - prefix_len % 8)));
-
- return 1;
-}
-
-
-int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
- int* count_ptr) {
- IP_ADAPTER_ADDRESSES* win_address_buf;
- ULONG win_address_buf_size;
- IP_ADAPTER_ADDRESSES* adapter;
-
- uv_interface_address_t* uv_address_buf;
- char* name_buf;
- size_t uv_address_buf_size;
- uv_interface_address_t* uv_address;
-
- int count;
-
- int is_vista_or_greater;
- ULONG flags;
-
- *addresses_ptr = NULL;
- *count_ptr = 0;
-
- is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
- if (is_vista_or_greater) {
- flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
- GAA_FLAG_SKIP_DNS_SERVER;
- } else {
- /* We need at least XP SP1. */
- if (!is_windows_version_or_greater(5, 1, 1, 0))
- return UV_ENOTSUP;
-
- flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
- GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
- }
-
-
- /* Fetch the size of the adapters reported by windows, and then get the list
- * itself. */
- win_address_buf_size = 0;
- win_address_buf = NULL;
-
- for (;;) {
- ULONG r;
-
- /* If win_address_buf is 0, then GetAdaptersAddresses will fail with.
- * ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in
- * win_address_buf_size. */
- r = GetAdaptersAddresses(AF_UNSPEC,
- flags,
- NULL,
- win_address_buf,
- &win_address_buf_size);
-
- if (r == ERROR_SUCCESS)
- break;
-
- uv__free(win_address_buf);
-
- switch (r) {
- case ERROR_BUFFER_OVERFLOW:
- /* This happens when win_address_buf is NULL or too small to hold all
- * adapters. */
- win_address_buf =
- (IP_ADAPTER_ADDRESSES*)uv__malloc(win_address_buf_size);
- if (win_address_buf == NULL)
- return UV_ENOMEM;
-
- continue;
-
- case ERROR_NO_DATA: {
- /* No adapters were found. */
- uv_address_buf = (uv_interface_address_t*)uv__malloc(1);
- if (uv_address_buf == NULL)
- return UV_ENOMEM;
-
- *count_ptr = 0;
- *addresses_ptr = uv_address_buf;
-
- return 0;
- }
-
- case ERROR_ADDRESS_NOT_ASSOCIATED:
- return UV_EAGAIN;
-
- case ERROR_INVALID_PARAMETER:
- /* MSDN says:
- * "This error is returned for any of the following conditions: the
- * SizePointer parameter is NULL, the Address parameter is not
- * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
- * the parameters requested is greater than ULONG_MAX."
- * Since the first two conditions are not met, it must be that the
- * adapter data is too big.
- */
- return UV_ENOBUFS;
-
- default:
- /* Other (unspecified) errors can happen, but we don't have any special
- * meaning for them. */
- assert(r != ERROR_SUCCESS);
- return uv_translate_sys_error(r);
- }
- }
-
- /* Count the number of enabled interfaces and compute how much space is
- * needed to store their info. */
- count = 0;
- uv_address_buf_size = 0;
-
- for (adapter = win_address_buf;
- adapter != NULL;
- adapter = adapter->Next) {
- IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
- int name_size;
-
- /* Interfaces that are not 'up' should not be reported. Also skip
- * interfaces that have no associated unicast address, as to avoid
- * allocating space for the name for this interface. */
- if (adapter->OperStatus != IfOperStatusUp ||
- adapter->FirstUnicastAddress == NULL)
- continue;
-
- /* Compute the size of the interface name. */
- name_size = WideCharToMultiByte(CP_UTF8,
- 0,
- adapter->FriendlyName,
- -1,
- NULL,
- 0,
- NULL,
- FALSE);
- if (name_size <= 0) {
- uv__free(win_address_buf);
- return uv_translate_sys_error(GetLastError());
- }
- uv_address_buf_size += name_size;
-
- /* Count the number of addresses associated with this interface, and
- * compute the size. */
- for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
- adapter->FirstUnicastAddress;
- unicast_address != NULL;
- unicast_address = unicast_address->Next) {
- count++;
- uv_address_buf_size += sizeof(uv_interface_address_t);
- }
- }
-
- /* Allocate space to store interface data plus adapter names. */
- uv_address_buf = (uv_interface_address_t*)uv__malloc(uv_address_buf_size);
- if (uv_address_buf == NULL) {
- uv__free(win_address_buf);
- return UV_ENOMEM;
- }
-
- /* Compute the start of the uv_interface_address_t array, and the place in
- * the buffer where the interface names will be stored. */
- uv_address = uv_address_buf;
- name_buf = (char*) (uv_address_buf + count);
-
- /* Fill out the output buffer. */
- for (adapter = win_address_buf;
- adapter != NULL;
- adapter = adapter->Next) {
- IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
- int name_size;
- size_t max_name_size;
-
- if (adapter->OperStatus != IfOperStatusUp ||
- adapter->FirstUnicastAddress == NULL)
- continue;
-
- /* Convert the interface name to UTF8. */
- max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
- if (max_name_size > (size_t) INT_MAX)
- max_name_size = INT_MAX;
- name_size = WideCharToMultiByte(CP_UTF8,
- 0,
- adapter->FriendlyName,
- -1,
- name_buf,
- (int) max_name_size,
- NULL,
- FALSE);
- if (name_size <= 0) {
- uv__free(win_address_buf);
- uv__free(uv_address_buf);
- return uv_translate_sys_error(GetLastError());
- }
-
- /* Add an uv_interface_address_t element for every unicast address. */
- for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
- adapter->FirstUnicastAddress;
- unicast_address != NULL;
- unicast_address = unicast_address->Next) {
- struct sockaddr* sa;
- ULONG prefix_len;
-
- sa = unicast_address->Address.lpSockaddr;
-
- /* XP has no OnLinkPrefixLength field. */
- if (is_vista_or_greater) {
- prefix_len =
- ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
- } else {
- /* Prior to Windows Vista the FirstPrefix pointed to the list with
- * single prefix for each IP address assigned to the adapter.
- * Order of FirstPrefix does not match order of FirstUnicastAddress,
- * so we need to find corresponding prefix.
- */
- IP_ADAPTER_PREFIX* prefix;
- prefix_len = 0;
-
- for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
- /* We want the longest matching prefix. */
- if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
- prefix->PrefixLength <= prefix_len)
- continue;
-
- if (address_prefix_match(sa->sa_family, sa,
- prefix->Address.lpSockaddr, prefix->PrefixLength)) {
- prefix_len = prefix->PrefixLength;
- }
- }
-
- /* If there is no matching prefix information, return a single-host
- * subnet mask (e.g. 255.255.255.255 for IPv4).
- */
- if (!prefix_len)
- prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
- }
-
- memset(uv_address, 0, sizeof *uv_address);
-
- uv_address->name = name_buf;
-
- if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
- memcpy(uv_address->phys_addr,
- adapter->PhysicalAddress,
- sizeof(uv_address->phys_addr));
- }
-
- uv_address->is_internal =
- (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
-
- if (sa->sa_family == AF_INET6) {
- uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
-
- uv_address->netmask.netmask6.sin6_family = AF_INET6;
- memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
- /* This check ensures that we don't write past the size of the data. */
- if (prefix_len % 8) {
- uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
- 0xff << (8 - prefix_len % 8);
- }
-
- } else {
- uv_address->address.address4 = *((struct sockaddr_in *) sa);
-
- uv_address->netmask.netmask4.sin_family = AF_INET;
- uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
- htonl(0xffffffff << (32 - prefix_len)) : 0;
- }
-
- uv_address++;
- }
-
- name_buf += name_size;
- }
-
- uv__free(win_address_buf);
-
- *addresses_ptr = uv_address_buf;
- *count_ptr = count;
-
- return 0;
-}
-
-
-void uv_free_interface_addresses(uv_interface_address_t* addresses,
- int count) {
- uv__free(addresses);
-}
-
-
-int uv_getrusage(uv_rusage_t *uv_rusage) {
- FILETIME createTime, exitTime, kernelTime, userTime;
- SYSTEMTIME kernelSystemTime, userSystemTime;
- PROCESS_MEMORY_COUNTERS memCounters;
- IO_COUNTERS ioCounters;
- int ret;
-
- ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
- if (ret == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
- if (ret == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- ret = FileTimeToSystemTime(&userTime, &userSystemTime);
- if (ret == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- ret = GetProcessMemoryInfo(GetCurrentProcess(),
- &memCounters,
- sizeof(memCounters));
- if (ret == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
- if (ret == 0) {
- return uv_translate_sys_error(GetLastError());
- }
-
- memset(uv_rusage, 0, sizeof(*uv_rusage));
-
- uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
- userSystemTime.wMinute * 60 +
- userSystemTime.wSecond;
- uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
-
- uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
- kernelSystemTime.wMinute * 60 +
- kernelSystemTime.wSecond;
- uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
-
- uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
- uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
-
- uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
- uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
-
- return 0;
-}
-
-
-int uv_os_homedir(char* buffer, size_t* size) {
- uv_passwd_t pwd;
- size_t len;
- int r;
-
- /* Check if the USERPROFILE environment variable is set first. The task of
- performing input validation on buffer and size is taken care of by
- uv_os_getenv(). */
- r = uv_os_getenv("USERPROFILE", buffer, size);
-
- /* Don't return an error if USERPROFILE was not found. */
- if (r != UV_ENOENT)
- return r;
-
- /* USERPROFILE is not set, so call uv__getpwuid_r() */
- r = uv__getpwuid_r(&pwd);
-
- if (r != 0) {
- return r;
- }
-
- len = strlen(pwd.homedir);
-
- if (len >= *size) {
- *size = len + 1;
- uv_os_free_passwd(&pwd);
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, pwd.homedir, len + 1);
- *size = len;
- uv_os_free_passwd(&pwd);
-
- return 0;
-}
-
-
-int uv_os_tmpdir(char* buffer, size_t* size) {
- wchar_t path[MAX_PATH + 1];
- DWORD bufsize;
- size_t len;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- len = GetTempPathW(MAX_PATH + 1, path);
-
- if (len == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (len > MAX_PATH + 1) {
- /* This should not be possible */
- return UV_EIO;
- }
-
- /* The returned directory should not have a trailing slash, unless it points
- * at a drive root, like c:\. Remove it if needed. */
- if (path[len - 1] == L'\\' &&
- !(len == 3 && path[1] == L':')) {
- len--;
- path[len] = L'\0';
- }
-
- /* Check how much space we need */
- bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
-
- if (bufsize == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (bufsize > *size) {
- *size = bufsize;
- return UV_ENOBUFS;
- }
-
- /* Convert to UTF-8 */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- path,
- -1,
- buffer,
- *size,
- NULL,
- NULL);
-
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
-
- *size = bufsize - 1;
- return 0;
-}
-
-
-void uv_os_free_passwd(uv_passwd_t* pwd) {
- if (pwd == NULL)
- return;
-
- uv__free(pwd->username);
- uv__free(pwd->homedir);
- pwd->username = NULL;
- pwd->homedir = NULL;
-}
-
-
-/*
- * Converts a UTF-16 string into a UTF-8 one. The resulting string is
- * null-terminated.
- *
- * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
- * be specified.
- */
-int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
- DWORD bufsize;
-
- if (utf16 == NULL)
- return UV_EINVAL;
-
- /* Check how much space we need */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16,
- utf16len,
- NULL,
- 0,
- NULL,
- NULL);
-
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
-
- /* Allocate the destination buffer adding an extra byte for the terminating
- * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
- * we do it ourselves always, just in case. */
- *utf8 = (char*)uv__malloc(bufsize + 1);
-
- if (*utf8 == NULL)
- return UV_ENOMEM;
-
- /* Convert to UTF-8 */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- utf16,
- utf16len,
- *utf8,
- bufsize,
- NULL,
- NULL);
-
- if (bufsize == 0) {
- uv__free(*utf8);
- *utf8 = NULL;
- return uv_translate_sys_error(GetLastError());
- }
-
- (*utf8)[bufsize] = '\0';
- return 0;
-}
-
-
-/*
- * Converts a UTF-8 string into a UTF-16 one. The resulting string is
- * null-terminated.
- *
- * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
- * be specified.
- */
-int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
- int bufsize;
-
- if (utf8 == NULL)
- return UV_EINVAL;
-
- /* Check how much space we need */
- bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
-
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
-
- /* Allocate the destination buffer adding an extra byte for the terminating
- * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
- * we do it ourselves always, just in case. */
- *utf16 = (WCHAR*)uv__malloc(sizeof(WCHAR) * (bufsize + 1));
-
- if (*utf16 == NULL)
- return UV_ENOMEM;
-
- /* Convert to UTF-16 */
- bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
-
- if (bufsize == 0) {
- uv__free(*utf16);
- *utf16 = NULL;
- return uv_translate_sys_error(GetLastError());
- }
-
- (*utf16)[bufsize] = '\0';
- return 0;
-}
-
-
-int uv__getpwuid_r(uv_passwd_t* pwd) {
- HANDLE token;
- wchar_t username[UNLEN + 1];
- wchar_t path[MAX_PATH];
- DWORD bufsize;
- int r;
-
- if (pwd == NULL)
- return UV_EINVAL;
-
- /* Get the home directory using GetUserProfileDirectoryW() */
- if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
- return uv_translate_sys_error(GetLastError());
-
- bufsize = ARRAY_SIZE(path);
- if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
- r = GetLastError();
- CloseHandle(token);
-
- /* This should not be possible */
- if (r == ERROR_INSUFFICIENT_BUFFER)
- return UV_ENOMEM;
-
- return uv_translate_sys_error(r);
- }
-
- CloseHandle(token);
-
- /* Get the username using GetUserNameW() */
- bufsize = ARRAY_SIZE(username);
- if (!GetUserNameW(username, &bufsize)) {
- r = GetLastError();
-
- /* This should not be possible */
- if (r == ERROR_INSUFFICIENT_BUFFER)
- return UV_ENOMEM;
-
- return uv_translate_sys_error(r);
- }
-
- pwd->homedir = NULL;
- r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
-
- if (r != 0)
- return r;
-
- pwd->username = NULL;
- r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
-
- if (r != 0) {
- uv__free(pwd->homedir);
- return r;
- }
-
- pwd->shell = NULL;
- pwd->uid = -1;
- pwd->gid = -1;
-
- return 0;
-}
-
-
-int uv_os_get_passwd(uv_passwd_t* pwd) {
- return uv__getpwuid_r(pwd);
-}
-
-
-int uv_os_getenv(const char* name, char* buffer, size_t* size) {
- wchar_t var[MAX_ENV_VAR_LENGTH];
- wchar_t* name_w;
- DWORD bufsize;
- size_t len;
- int r;
-
- if (name == NULL || buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- r = uv__convert_utf8_to_utf16(name, -1, &name_w);
-
- if (r != 0)
- return r;
-
- len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
- uv__free(name_w);
- assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
-
- if (len == 0) {
- r = GetLastError();
-
- if (r == ERROR_ENVVAR_NOT_FOUND)
- return UV_ENOENT;
-
- return uv_translate_sys_error(r);
- }
-
- /* Check how much space we need */
- bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
-
- if (bufsize == 0) {
- return uv_translate_sys_error(GetLastError());
- } else if (bufsize > *size) {
- *size = bufsize;
- return UV_ENOBUFS;
- }
-
- /* Convert to UTF-8 */
- bufsize = WideCharToMultiByte(CP_UTF8,
- 0,
- var,
- -1,
- buffer,
- *size,
- NULL,
- NULL);
-
- if (bufsize == 0)
- return uv_translate_sys_error(GetLastError());
-
- *size = bufsize - 1;
- return 0;
-}
-
-
-int uv_os_setenv(const char* name, const char* value) {
- wchar_t* name_w;
- wchar_t* value_w;
- int r;
-
- if (name == NULL || value == NULL)
- return UV_EINVAL;
-
- r = uv__convert_utf8_to_utf16(name, -1, &name_w);
-
- if (r != 0)
- return r;
-
- r = uv__convert_utf8_to_utf16(value, -1, &value_w);
-
- if (r != 0) {
- uv__free(name_w);
- return r;
- }
-
- r = SetEnvironmentVariableW(name_w, value_w);
- uv__free(name_w);
- uv__free(value_w);
-
- if (r == 0)
- return uv_translate_sys_error(GetLastError());
-
- return 0;
-}
-
-
-int uv_os_unsetenv(const char* name) {
- wchar_t* name_w;
- int r;
-
- if (name == NULL)
- return UV_EINVAL;
-
- r = uv__convert_utf8_to_utf16(name, -1, &name_w);
-
- if (r != 0)
- return r;
-
- r = SetEnvironmentVariableW(name_w, NULL);
- uv__free(name_w);
-
- if (r == 0)
- return uv_translate_sys_error(GetLastError());
-
- return 0;
-}
-
-
-int uv_os_gethostname(char* buffer, size_t* size) {
- char buf[UV_MAXHOSTNAMESIZE];
- size_t len;
-
- if (buffer == NULL || size == NULL || *size == 0)
- return UV_EINVAL;
-
- uv__once_init(); /* Initialize winsock */
-
- if (gethostname(buf, sizeof(buf)) != 0)
- return uv_translate_sys_error(WSAGetLastError());
-
- buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
- len = strlen(buf);
-
- if (len >= *size) {
- *size = len + 1;
- return UV_ENOBUFS;
- }
-
- memcpy(buffer, buf, len + 1);
- *size = len;
- return 0;
-}
-
-
-static int uv__get_handle(uv_pid_t pid, int access, HANDLE* handle) {
- int r;
-
- if (pid == 0)
- *handle = GetCurrentProcess();
- else
- *handle = OpenProcess(access, FALSE, pid);
-
- if (*handle == NULL) {
- r = GetLastError();
-
- if (r == ERROR_INVALID_PARAMETER)
- return UV_ESRCH;
- else
- return uv_translate_sys_error(r);
- }
-
- return 0;
-}
-
-
-int uv_os_getpriority(uv_pid_t pid, int* priority) {
- HANDLE handle;
- int r;
-
- if (priority == NULL)
- return UV_EINVAL;
-
- r = uv__get_handle(pid, PROCESS_QUERY_LIMITED_INFORMATION, &handle);
-
- if (r != 0)
- return r;
-
- r = GetPriorityClass(handle);
-
- if (r == 0) {
- r = uv_translate_sys_error(GetLastError());
- } else {
- /* Map Windows priority classes to Unix nice values. */
- if (r == REALTIME_PRIORITY_CLASS)
- *priority = UV_PRIORITY_HIGHEST;
- else if (r == HIGH_PRIORITY_CLASS)
- *priority = UV_PRIORITY_HIGH;
- else if (r == ABOVE_NORMAL_PRIORITY_CLASS)
- *priority = UV_PRIORITY_ABOVE_NORMAL;
- else if (r == NORMAL_PRIORITY_CLASS)
- *priority = UV_PRIORITY_NORMAL;
- else if (r == BELOW_NORMAL_PRIORITY_CLASS)
- *priority = UV_PRIORITY_BELOW_NORMAL;
- else /* IDLE_PRIORITY_CLASS */
- *priority = UV_PRIORITY_LOW;
-
- r = 0;
- }
-
- CloseHandle(handle);
- return r;
-}
-
-
-int uv_os_setpriority(uv_pid_t pid, int priority) {
- HANDLE handle;
- int priority_class;
- int r;
-
- /* Map Unix nice values to Windows priority classes. */
- if (priority < UV_PRIORITY_HIGHEST || priority > UV_PRIORITY_LOW)
- return UV_EINVAL;
- else if (priority < UV_PRIORITY_HIGH)
- priority_class = REALTIME_PRIORITY_CLASS;
- else if (priority < UV_PRIORITY_ABOVE_NORMAL)
- priority_class = HIGH_PRIORITY_CLASS;
- else if (priority < UV_PRIORITY_NORMAL)
- priority_class = ABOVE_NORMAL_PRIORITY_CLASS;
- else if (priority < UV_PRIORITY_BELOW_NORMAL)
- priority_class = NORMAL_PRIORITY_CLASS;
- else if (priority < UV_PRIORITY_LOW)
- priority_class = BELOW_NORMAL_PRIORITY_CLASS;
- else
- priority_class = IDLE_PRIORITY_CLASS;
-
- r = uv__get_handle(pid, PROCESS_SET_INFORMATION, &handle);
-
- if (r != 0)
- return r;
-
- if (SetPriorityClass(handle, priority_class) == 0)
- r = uv_translate_sys_error(GetLastError());
-
- CloseHandle(handle);
- return r;
-}
-
-
-int uv_os_uname(uv_utsname_t* buffer) {
- /* Implementation loosely based on
- https://github.com/gagern/gnulib/blob/master/lib/uname.c */
- OSVERSIONINFOW os_info;
- SYSTEM_INFO system_info;
- HKEY registry_key;
- WCHAR product_name_w[256];
- DWORD product_name_w_size;
- int version_size;
- int processor_level;
- int r;
-
- if (buffer == NULL)
- return UV_EINVAL;
-
- uv__once_init();
- os_info.dwOSVersionInfoSize = sizeof(os_info);
- os_info.szCSDVersion[0] = L'\0';
-
- /* Try calling RtlGetVersion(), and fall back to the deprecated GetVersionEx()
- if RtlGetVersion() is not available. */
- if (pRtlGetVersion) {
- pRtlGetVersion(&os_info);
- } else {
- /* Silence GetVersionEx() deprecation warning. */
- #pragma warning(suppress : 4996)
- if (GetVersionExW(&os_info) == 0) {
- r = uv_translate_sys_error(GetLastError());
- goto error;
- }
- }
-
- /* Populate the version field. */
- version_size = 0;
- r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
- L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
- 0,
- KEY_QUERY_VALUE,
- ®istry_key);
-
- if (r == ERROR_SUCCESS) {
- product_name_w_size = sizeof(product_name_w);
- r = RegGetValueW(registry_key,
- NULL,
- L"ProductName",
- RRF_RT_REG_SZ,
- NULL,
- (PVOID) product_name_w,
- &product_name_w_size);
- RegCloseKey(registry_key);
-
- if (r == ERROR_SUCCESS) {
- version_size = WideCharToMultiByte(CP_UTF8,
- 0,
- product_name_w,
- -1,
- buffer->version,
- sizeof(buffer->version),
- NULL,
- NULL);
- if (version_size == 0) {
- r = uv_translate_sys_error(GetLastError());
- goto error;
- }
- }
- }
-
- /* Append service pack information to the version if present. */
- if (os_info.szCSDVersion[0] != L'\0') {
- if (version_size > 0)
- buffer->version[version_size - 1] = ' ';
-
- if (WideCharToMultiByte(CP_UTF8,
- 0,
- os_info.szCSDVersion,
- -1,
- buffer->version + version_size,
- sizeof(buffer->version) - version_size,
- NULL,
- NULL) == 0) {
- r = uv_translate_sys_error(GetLastError());
- goto error;
- }
- }
-
- /* Populate the sysname field. */
-#ifdef __MINGW32__
- r = snprintf(buffer->sysname,
- sizeof(buffer->sysname),
- "MINGW32_NT-%u.%u",
- (unsigned int) os_info.dwMajorVersion,
- (unsigned int) os_info.dwMinorVersion);
- assert(r < sizeof(buffer->sysname));
-#else
- uv__strscpy(buffer->sysname, "Windows_NT", sizeof(buffer->sysname));
-#endif
-
- /* Populate the release field. */
- r = snprintf(buffer->release,
- sizeof(buffer->release),
- "%d.%d.%d",
- (unsigned int) os_info.dwMajorVersion,
- (unsigned int) os_info.dwMinorVersion,
- (unsigned int) os_info.dwBuildNumber);
- assert(r < sizeof(buffer->release));
-
- /* Populate the machine field. */
- GetSystemInfo(&system_info);
-
- switch (system_info.wProcessorArchitecture) {
- case PROCESSOR_ARCHITECTURE_AMD64:
- uv__strscpy(buffer->machine, "x86_64", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_IA64:
- uv__strscpy(buffer->machine, "ia64", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_INTEL:
- uv__strscpy(buffer->machine, "i386", sizeof(buffer->machine));
-
- if (system_info.wProcessorLevel > 3) {
- processor_level = system_info.wProcessorLevel < 6 ?
- system_info.wProcessorLevel : 6;
- buffer->machine[1] = '0' + processor_level;
- }
-
- break;
- case PROCESSOR_ARCHITECTURE_IA32_ON_WIN64:
- uv__strscpy(buffer->machine, "i686", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_MIPS:
- uv__strscpy(buffer->machine, "mips", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_ALPHA:
- case PROCESSOR_ARCHITECTURE_ALPHA64:
- uv__strscpy(buffer->machine, "alpha", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_PPC:
- uv__strscpy(buffer->machine, "powerpc", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_SHX:
- uv__strscpy(buffer->machine, "sh", sizeof(buffer->machine));
- break;
- case PROCESSOR_ARCHITECTURE_ARM:
- uv__strscpy(buffer->machine, "arm", sizeof(buffer->machine));
- break;
- default:
- uv__strscpy(buffer->machine, "unknown", sizeof(buffer->machine));
- break;
- }
-
- return 0;
-
-error:
- buffer->sysname[0] = '\0';
- buffer->release[0] = '\0';
- buffer->version[0] = '\0';
- buffer->machine[0] = '\0';
- return r;
-}
-
-int uv_gettimeofday(uv_timeval64_t* tv) {
- /* Based on https://doxygen.postgresql.org/gettimeofday_8c_source.html */
- const uint64_t epoch = (uint64_t) 116444736000000000ULL;
- FILETIME file_time;
- ULARGE_INTEGER ularge;
-
- if (tv == NULL)
- return UV_EINVAL;
-
- GetSystemTimeAsFileTime(&file_time);
- ularge.LowPart = file_time.dwLowDateTime;
- ularge.HighPart = file_time.dwHighDateTime;
- tv->tv_sec = (int64_t) ((ularge.QuadPart - epoch) / 10000000L);
- tv->tv_usec = (int32_t) (((ularge.QuadPart - epoch) % 10000000L) / 10);
- return 0;
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/winapi.cpp b/wpiutil/src/main/native/libuv/src/win/winapi.cpp
deleted file mode 100644
index fbbbcee..0000000
--- a/wpiutil/src/main/native/libuv/src/win/winapi.cpp
+++ /dev/null
@@ -1,130 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-/* Ntdll function pointers */
-sRtlGetVersion pRtlGetVersion;
-sRtlNtStatusToDosError pRtlNtStatusToDosError;
-sNtDeviceIoControlFile pNtDeviceIoControlFile;
-sNtQueryInformationFile pNtQueryInformationFile;
-sNtSetInformationFile pNtSetInformationFile;
-sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
-sNtQueryDirectoryFile pNtQueryDirectoryFile;
-sNtQuerySystemInformation pNtQuerySystemInformation;
-
-/* Kernel32 function pointers */
-sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
-
-/* Powrprof.dll function pointer */
-sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
-
-/* User32.dll function pointer */
-sSetWinEventHook pSetWinEventHook;
-
-
-void uv_winapi_init(void) {
- HMODULE ntdll_module;
- HMODULE powrprof_module;
- HMODULE user32_module;
- HMODULE kernel32_module;
-
- ntdll_module = GetModuleHandleA("ntdll.dll");
- if (ntdll_module == NULL) {
- uv_fatal_error(GetLastError(), "GetModuleHandleA");
- }
-
- pRtlGetVersion = (sRtlGetVersion) GetProcAddress(ntdll_module,
- "RtlGetVersion");
-
- pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
- ntdll_module,
- "RtlNtStatusToDosError");
- if (pRtlNtStatusToDosError == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
- ntdll_module,
- "NtDeviceIoControlFile");
- if (pNtDeviceIoControlFile == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
- ntdll_module,
- "NtQueryInformationFile");
- if (pNtQueryInformationFile == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
- ntdll_module,
- "NtSetInformationFile");
- if (pNtSetInformationFile == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
- GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
- if (pNtQueryVolumeInformationFile == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
- GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
- if (pNtQueryVolumeInformationFile == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
- ntdll_module,
- "NtQuerySystemInformation");
- if (pNtQuerySystemInformation == NULL) {
- uv_fatal_error(GetLastError(), "GetProcAddress");
- }
-
- kernel32_module = GetModuleHandleA("kernel32.dll");
- if (kernel32_module == NULL) {
- uv_fatal_error(GetLastError(), "GetModuleHandleA");
- }
-
- pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
- kernel32_module,
- "GetQueuedCompletionStatusEx");
-
- powrprof_module = LoadLibraryA("powrprof.dll");
- if (powrprof_module != NULL) {
- pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
- GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
- }
-
- user32_module = LoadLibraryA("user32.dll");
- if (user32_module != NULL) {
- pSetWinEventHook = (sSetWinEventHook)
- GetProcAddress(user32_module, "SetWinEventHook");
- }
-
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/winapi.h b/wpiutil/src/main/native/libuv/src/win/winapi.h
deleted file mode 100644
index 82c5ed4..0000000
--- a/wpiutil/src/main/native/libuv/src/win/winapi.h
+++ /dev/null
@@ -1,4731 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_WINAPI_H_
-#define UV_WIN_WINAPI_H_
-
-#include <windows.h>
-
-
-/*
- * Ntdll headers
- */
-#ifndef STATUS_SEVERITY_SUCCESS
-# define STATUS_SEVERITY_SUCCESS 0x0
-#endif
-
-#ifndef STATUS_SEVERITY_INFORMATIONAL
-# define STATUS_SEVERITY_INFORMATIONAL 0x1
-#endif
-
-#ifndef STATUS_SEVERITY_WARNING
-# define STATUS_SEVERITY_WARNING 0x2
-#endif
-
-#ifndef STATUS_SEVERITY_ERROR
-# define STATUS_SEVERITY_ERROR 0x3
-#endif
-
-#ifndef FACILITY_NTWIN32
-# define FACILITY_NTWIN32 0x7
-#endif
-
-#ifndef NT_SUCCESS
-# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0)
-#endif
-
-#ifndef NT_INFORMATION
-# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1)
-#endif
-
-#ifndef NT_WARNING
-# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2)
-#endif
-
-#ifndef NT_ERROR
-# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3)
-#endif
-
-#ifndef STATUS_SUCCESS
-# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
-#endif
-
-#ifndef STATUS_WAIT_0
-# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L)
-#endif
-
-#ifndef STATUS_WAIT_1
-# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L)
-#endif
-
-#ifndef STATUS_WAIT_2
-# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L)
-#endif
-
-#ifndef STATUS_WAIT_3
-# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L)
-#endif
-
-#ifndef STATUS_WAIT_63
-# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL)
-#endif
-
-#ifndef STATUS_ABANDONED
-# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L)
-#endif
-
-#ifndef STATUS_ABANDONED_WAIT_0
-# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L)
-#endif
-
-#ifndef STATUS_ABANDONED_WAIT_63
-# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL)
-#endif
-
-#ifndef STATUS_USER_APC
-# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L)
-#endif
-
-#ifndef STATUS_KERNEL_APC
-# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L)
-#endif
-
-#ifndef STATUS_ALERTED
-# define STATUS_ALERTED ((NTSTATUS) 0x00000101L)
-#endif
-
-#ifndef STATUS_TIMEOUT
-# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L)
-#endif
-
-#ifndef STATUS_PENDING
-# define STATUS_PENDING ((NTSTATUS) 0x00000103L)
-#endif
-
-#ifndef STATUS_REPARSE
-# define STATUS_REPARSE ((NTSTATUS) 0x00000104L)
-#endif
-
-#ifndef STATUS_MORE_ENTRIES
-# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L)
-#endif
-
-#ifndef STATUS_NOT_ALL_ASSIGNED
-# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L)
-#endif
-
-#ifndef STATUS_SOME_NOT_MAPPED
-# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L)
-#endif
-
-#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS
-# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L)
-#endif
-
-#ifndef STATUS_VOLUME_MOUNTED
-# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L)
-#endif
-
-#ifndef STATUS_RXACT_COMMITTED
-# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL)
-#endif
-
-#ifndef STATUS_NOTIFY_CLEANUP
-# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL)
-#endif
-
-#ifndef STATUS_NOTIFY_ENUM_DIR
-# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL)
-#endif
-
-#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT
-# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL)
-#endif
-
-#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
-# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL)
-#endif
-
-#ifndef STATUS_PAGE_FAULT_TRANSITION
-# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L)
-#endif
-
-#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO
-# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L)
-#endif
-
-#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE
-# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L)
-#endif
-
-#ifndef STATUS_PAGE_FAULT_GUARD_PAGE
-# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L)
-#endif
-
-#ifndef STATUS_PAGE_FAULT_PAGING_FILE
-# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L)
-#endif
-
-#ifndef STATUS_CACHE_PAGE_LOCKED
-# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L)
-#endif
-
-#ifndef STATUS_CRASH_DUMP
-# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L)
-#endif
-
-#ifndef STATUS_BUFFER_ALL_ZEROS
-# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L)
-#endif
-
-#ifndef STATUS_REPARSE_OBJECT
-# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L)
-#endif
-
-#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED
-# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L)
-#endif
-
-#ifndef STATUS_TRANSLATION_COMPLETE
-# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L)
-#endif
-
-#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
-# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L)
-#endif
-
-#ifndef STATUS_NOTHING_TO_TERMINATE
-# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L)
-#endif
-
-#ifndef STATUS_PROCESS_NOT_IN_JOB
-# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L)
-#endif
-
-#ifndef STATUS_PROCESS_IN_JOB
-# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L)
-#endif
-
-#ifndef STATUS_VOLSNAP_HIBERNATE_READY
-# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L)
-#endif
-
-#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
-# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L)
-#endif
-
-#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
-# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L)
-#endif
-
-#ifndef STATUS_INTERRUPT_STILL_CONNECTED
-# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L)
-#endif
-
-#ifndef STATUS_PROCESS_CLONED
-# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L)
-#endif
-
-#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS
-# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL)
-#endif
-
-#ifndef STATUS_FILE_LOCKED_WITH_WRITERS
-# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL)
-#endif
-
-#ifndef STATUS_RESOURCEMANAGER_READ_ONLY
-# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L)
-#endif
-
-#ifndef STATUS_RING_PREVIOUSLY_EMPTY
-# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L)
-#endif
-
-#ifndef STATUS_RING_PREVIOUSLY_FULL
-# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L)
-#endif
-
-#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA
-# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L)
-#endif
-
-#ifndef STATUS_RING_NEWLY_EMPTY
-# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L)
-#endif
-
-#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT
-# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L)
-#endif
-
-#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE
-# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L)
-#endif
-
-#ifndef STATUS_OPLOCK_HANDLE_CLOSED
-# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L)
-#endif
-
-#ifndef STATUS_WAIT_FOR_OPLOCK
-# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L)
-#endif
-
-#ifndef STATUS_OBJECT_NAME_EXISTS
-# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L)
-#endif
-
-#ifndef STATUS_THREAD_WAS_SUSPENDED
-# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L)
-#endif
-
-#ifndef STATUS_WORKING_SET_LIMIT_RANGE
-# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L)
-#endif
-
-#ifndef STATUS_IMAGE_NOT_AT_BASE
-# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L)
-#endif
-
-#ifndef STATUS_RXACT_STATE_CREATED
-# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L)
-#endif
-
-#ifndef STATUS_SEGMENT_NOTIFICATION
-# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L)
-#endif
-
-#ifndef STATUS_LOCAL_USER_SESSION_KEY
-# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L)
-#endif
-
-#ifndef STATUS_BAD_CURRENT_DIRECTORY
-# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L)
-#endif
-
-#ifndef STATUS_SERIAL_MORE_WRITES
-# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L)
-#endif
-
-#ifndef STATUS_REGISTRY_RECOVERED
-# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L)
-#endif
-
-#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP
-# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL)
-#endif
-
-#ifndef STATUS_FT_WRITE_RECOVERY
-# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL)
-#endif
-
-#ifndef STATUS_SERIAL_COUNTER_TIMEOUT
-# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL)
-#endif
-
-#ifndef STATUS_NULL_LM_PASSWORD
-# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL)
-#endif
-
-#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH
-# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL)
-#endif
-
-#ifndef STATUS_RECEIVE_PARTIAL
-# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL)
-#endif
-
-#ifndef STATUS_RECEIVE_EXPEDITED
-# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L)
-#endif
-
-#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED
-# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L)
-#endif
-
-#ifndef STATUS_EVENT_DONE
-# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L)
-#endif
-
-#ifndef STATUS_EVENT_PENDING
-# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L)
-#endif
-
-#ifndef STATUS_CHECKING_FILE_SYSTEM
-# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L)
-#endif
-
-#ifndef STATUS_FATAL_APP_EXIT
-# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L)
-#endif
-
-#ifndef STATUS_PREDEFINED_HANDLE
-# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L)
-#endif
-
-#ifndef STATUS_WAS_UNLOCKED
-# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L)
-#endif
-
-#ifndef STATUS_SERVICE_NOTIFICATION
-# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L)
-#endif
-
-#ifndef STATUS_WAS_LOCKED
-# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L)
-#endif
-
-#ifndef STATUS_LOG_HARD_ERROR
-# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL)
-#endif
-
-#ifndef STATUS_ALREADY_WIN32
-# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL)
-#endif
-
-#ifndef STATUS_WX86_UNSIMULATE
-# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL)
-#endif
-
-#ifndef STATUS_WX86_CONTINUE
-# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL)
-#endif
-
-#ifndef STATUS_WX86_SINGLE_STEP
-# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL)
-#endif
-
-#ifndef STATUS_WX86_BREAKPOINT
-# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL)
-#endif
-
-#ifndef STATUS_WX86_EXCEPTION_CONTINUE
-# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L)
-#endif
-
-#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE
-# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L)
-#endif
-
-#ifndef STATUS_WX86_EXCEPTION_CHAIN
-# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L)
-#endif
-
-#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
-# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L)
-#endif
-
-#ifndef STATUS_NO_YIELD_PERFORMED
-# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L)
-#endif
-
-#ifndef STATUS_TIMER_RESUME_IGNORED
-# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L)
-#endif
-
-#ifndef STATUS_ARBITRATION_UNHANDLED
-# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L)
-#endif
-
-#ifndef STATUS_CARDBUS_NOT_SUPPORTED
-# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L)
-#endif
-
-#ifndef STATUS_WX86_CREATEWX86TIB
-# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L)
-#endif
-
-#ifndef STATUS_MP_PROCESSOR_MISMATCH
-# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L)
-#endif
-
-#ifndef STATUS_HIBERNATED
-# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL)
-#endif
-
-#ifndef STATUS_RESUME_HIBERNATION
-# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL)
-#endif
-
-#ifndef STATUS_FIRMWARE_UPDATED
-# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL)
-#endif
-
-#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES
-# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL)
-#endif
-
-#ifndef STATUS_MESSAGE_RETRIEVED
-# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL)
-#endif
-
-#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION
-# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL)
-#endif
-
-#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST
-# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L)
-#endif
-
-#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
-# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L)
-#endif
-
-#ifndef STATUS_ACCESS_AUDIT_BY_POLICY
-# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L)
-#endif
-
-#ifndef STATUS_ABANDON_HIBERFILE
-# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L)
-#endif
-
-#ifndef STATUS_BIZRULES_NOT_ENABLED
-# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L)
-#endif
-
-#ifndef STATUS_GUARD_PAGE_VIOLATION
-# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L)
-#endif
-
-#ifndef STATUS_DATATYPE_MISALIGNMENT
-# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L)
-#endif
-
-#ifndef STATUS_BREAKPOINT
-# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L)
-#endif
-
-#ifndef STATUS_SINGLE_STEP
-# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L)
-#endif
-
-#ifndef STATUS_BUFFER_OVERFLOW
-# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L)
-#endif
-
-#ifndef STATUS_NO_MORE_FILES
-# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L)
-#endif
-
-#ifndef STATUS_WAKE_SYSTEM_DEBUGGER
-# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L)
-#endif
-
-#ifndef STATUS_HANDLES_CLOSED
-# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL)
-#endif
-
-#ifndef STATUS_NO_INHERITANCE
-# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL)
-#endif
-
-#ifndef STATUS_GUID_SUBSTITUTION_MADE
-# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL)
-#endif
-
-#ifndef STATUS_PARTIAL_COPY
-# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL)
-#endif
-
-#ifndef STATUS_DEVICE_PAPER_EMPTY
-# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL)
-#endif
-
-#ifndef STATUS_DEVICE_POWERED_OFF
-# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL)
-#endif
-
-#ifndef STATUS_DEVICE_OFF_LINE
-# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L)
-#endif
-
-#ifndef STATUS_DEVICE_BUSY
-# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L)
-#endif
-
-#ifndef STATUS_NO_MORE_EAS
-# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L)
-#endif
-
-#ifndef STATUS_INVALID_EA_NAME
-# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L)
-#endif
-
-#ifndef STATUS_EA_LIST_INCONSISTENT
-# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L)
-#endif
-
-#ifndef STATUS_INVALID_EA_FLAG
-# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L)
-#endif
-
-#ifndef STATUS_VERIFY_REQUIRED
-# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L)
-#endif
-
-#ifndef STATUS_EXTRANEOUS_INFORMATION
-# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L)
-#endif
-
-#ifndef STATUS_RXACT_COMMIT_NECESSARY
-# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L)
-#endif
-
-#ifndef STATUS_NO_MORE_ENTRIES
-# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL)
-#endif
-
-#ifndef STATUS_FILEMARK_DETECTED
-# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL)
-#endif
-
-#ifndef STATUS_MEDIA_CHANGED
-# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL)
-#endif
-
-#ifndef STATUS_BUS_RESET
-# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL)
-#endif
-
-#ifndef STATUS_END_OF_MEDIA
-# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL)
-#endif
-
-#ifndef STATUS_BEGINNING_OF_MEDIA
-# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL)
-#endif
-
-#ifndef STATUS_MEDIA_CHECK
-# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L)
-#endif
-
-#ifndef STATUS_SETMARK_DETECTED
-# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L)
-#endif
-
-#ifndef STATUS_NO_DATA_DETECTED
-# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L)
-#endif
-
-#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES
-# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L)
-#endif
-
-#ifndef STATUS_SERVER_HAS_OPEN_HANDLES
-# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L)
-#endif
-
-#ifndef STATUS_ALREADY_DISCONNECTED
-# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L)
-#endif
-
-#ifndef STATUS_LONGJUMP
-# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L)
-#endif
-
-#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED
-# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L)
-#endif
-
-#ifndef STATUS_PLUGPLAY_QUERY_VETOED
-# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L)
-#endif
-
-#ifndef STATUS_UNWIND_CONSOLIDATE
-# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L)
-#endif
-
-#ifndef STATUS_REGISTRY_HIVE_RECOVERED
-# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL)
-#endif
-
-#ifndef STATUS_DLL_MIGHT_BE_INSECURE
-# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL)
-#endif
-
-#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE
-# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL)
-#endif
-
-#ifndef STATUS_STOPPED_ON_SYMLINK
-# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL)
-#endif
-
-#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK
-# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL)
-#endif
-
-#ifndef STATUS_NO_ACE_CONDITION
-# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL)
-#endif
-
-#ifndef STATUS_UNSUCCESSFUL
-# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
-#endif
-
-#ifndef STATUS_NOT_IMPLEMENTED
-# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L)
-#endif
-
-#ifndef STATUS_INVALID_INFO_CLASS
-# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L)
-#endif
-
-#ifndef STATUS_INFO_LENGTH_MISMATCH
-# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)
-#endif
-
-#ifndef STATUS_ACCESS_VIOLATION
-# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L)
-#endif
-
-#ifndef STATUS_IN_PAGE_ERROR
-# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L)
-#endif
-
-#ifndef STATUS_PAGEFILE_QUOTA
-# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L)
-#endif
-
-#ifndef STATUS_INVALID_HANDLE
-# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L)
-#endif
-
-#ifndef STATUS_BAD_INITIAL_STACK
-# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L)
-#endif
-
-#ifndef STATUS_BAD_INITIAL_PC
-# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL)
-#endif
-
-#ifndef STATUS_INVALID_CID
-# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL)
-#endif
-
-#ifndef STATUS_TIMER_NOT_CANCELED
-# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER
-# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL)
-#endif
-
-#ifndef STATUS_NO_SUCH_DEVICE
-# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL)
-#endif
-
-#ifndef STATUS_NO_SUCH_FILE
-# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL)
-#endif
-
-#ifndef STATUS_INVALID_DEVICE_REQUEST
-# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L)
-#endif
-
-#ifndef STATUS_END_OF_FILE
-# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L)
-#endif
-
-#ifndef STATUS_WRONG_VOLUME
-# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L)
-#endif
-
-#ifndef STATUS_NO_MEDIA_IN_DEVICE
-# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L)
-#endif
-
-#ifndef STATUS_UNRECOGNIZED_MEDIA
-# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L)
-#endif
-
-#ifndef STATUS_NONEXISTENT_SECTOR
-# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L)
-#endif
-
-#ifndef STATUS_MORE_PROCESSING_REQUIRED
-# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L)
-#endif
-
-#ifndef STATUS_NO_MEMORY
-# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L)
-#endif
-
-#ifndef STATUS_CONFLICTING_ADDRESSES
-# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L)
-#endif
-
-#ifndef STATUS_NOT_MAPPED_VIEW
-# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L)
-#endif
-
-#ifndef STATUS_UNABLE_TO_FREE_VM
-# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL)
-#endif
-
-#ifndef STATUS_UNABLE_TO_DELETE_SECTION
-# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL)
-#endif
-
-#ifndef STATUS_INVALID_SYSTEM_SERVICE
-# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL)
-#endif
-
-#ifndef STATUS_ILLEGAL_INSTRUCTION
-# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL)
-#endif
-
-#ifndef STATUS_INVALID_LOCK_SEQUENCE
-# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL)
-#endif
-
-#ifndef STATUS_INVALID_VIEW_SIZE
-# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL)
-#endif
-
-#ifndef STATUS_INVALID_FILE_FOR_SECTION
-# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L)
-#endif
-
-#ifndef STATUS_ALREADY_COMMITTED
-# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L)
-#endif
-
-#ifndef STATUS_ACCESS_DENIED
-# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L)
-#endif
-
-#ifndef STATUS_BUFFER_TOO_SMALL
-# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L)
-#endif
-
-#ifndef STATUS_OBJECT_TYPE_MISMATCH
-# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L)
-#endif
-
-#ifndef STATUS_NONCONTINUABLE_EXCEPTION
-# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L)
-#endif
-
-#ifndef STATUS_INVALID_DISPOSITION
-# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L)
-#endif
-
-#ifndef STATUS_UNWIND
-# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L)
-#endif
-
-#ifndef STATUS_BAD_STACK
-# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L)
-#endif
-
-#ifndef STATUS_INVALID_UNWIND_TARGET
-# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L)
-#endif
-
-#ifndef STATUS_NOT_LOCKED
-# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL)
-#endif
-
-#ifndef STATUS_PARITY_ERROR
-# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL)
-#endif
-
-#ifndef STATUS_UNABLE_TO_DECOMMIT_VM
-# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL)
-#endif
-
-#ifndef STATUS_NOT_COMMITTED
-# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL)
-#endif
-
-#ifndef STATUS_INVALID_PORT_ATTRIBUTES
-# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL)
-#endif
-
-#ifndef STATUS_PORT_MESSAGE_TOO_LONG
-# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_MIX
-# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L)
-#endif
-
-#ifndef STATUS_INVALID_QUOTA_LOWER
-# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L)
-#endif
-
-#ifndef STATUS_DISK_CORRUPT_ERROR
-# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L)
-#endif
-
-#ifndef STATUS_OBJECT_NAME_INVALID
-# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L)
-#endif
-
-#ifndef STATUS_OBJECT_NAME_NOT_FOUND
-# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L)
-#endif
-
-#ifndef STATUS_OBJECT_NAME_COLLISION
-# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L)
-#endif
-
-#ifndef STATUS_PORT_DISCONNECTED
-# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L)
-#endif
-
-#ifndef STATUS_DEVICE_ALREADY_ATTACHED
-# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L)
-#endif
-
-#ifndef STATUS_OBJECT_PATH_INVALID
-# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L)
-#endif
-
-#ifndef STATUS_OBJECT_PATH_NOT_FOUND
-# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL)
-#endif
-
-#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD
-# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL)
-#endif
-
-#ifndef STATUS_DATA_OVERRUN
-# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL)
-#endif
-
-#ifndef STATUS_DATA_LATE_ERROR
-# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL)
-#endif
-
-#ifndef STATUS_DATA_ERROR
-# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL)
-#endif
-
-#ifndef STATUS_CRC_ERROR
-# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL)
-#endif
-
-#ifndef STATUS_SECTION_TOO_BIG
-# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L)
-#endif
-
-#ifndef STATUS_PORT_CONNECTION_REFUSED
-# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L)
-#endif
-
-#ifndef STATUS_INVALID_PORT_HANDLE
-# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L)
-#endif
-
-#ifndef STATUS_SHARING_VIOLATION
-# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L)
-#endif
-
-#ifndef STATUS_QUOTA_EXCEEDED
-# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L)
-#endif
-
-#ifndef STATUS_INVALID_PAGE_PROTECTION
-# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L)
-#endif
-
-#ifndef STATUS_MUTANT_NOT_OWNED
-# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L)
-#endif
-
-#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED
-# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L)
-#endif
-
-#ifndef STATUS_PORT_ALREADY_SET
-# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L)
-#endif
-
-#ifndef STATUS_SECTION_NOT_IMAGE
-# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L)
-#endif
-
-#ifndef STATUS_SUSPEND_COUNT_EXCEEDED
-# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL)
-#endif
-
-#ifndef STATUS_THREAD_IS_TERMINATING
-# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL)
-#endif
-
-#ifndef STATUS_BAD_WORKING_SET_LIMIT
-# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL)
-#endif
-
-#ifndef STATUS_INCOMPATIBLE_FILE_MAP
-# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL)
-#endif
-
-#ifndef STATUS_SECTION_PROTECTION
-# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL)
-#endif
-
-#ifndef STATUS_EAS_NOT_SUPPORTED
-# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL)
-#endif
-
-#ifndef STATUS_EA_TOO_LARGE
-# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L)
-#endif
-
-#ifndef STATUS_NONEXISTENT_EA_ENTRY
-# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L)
-#endif
-
-#ifndef STATUS_NO_EAS_ON_FILE
-# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L)
-#endif
-
-#ifndef STATUS_EA_CORRUPT_ERROR
-# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L)
-#endif
-
-#ifndef STATUS_FILE_LOCK_CONFLICT
-# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L)
-#endif
-
-#ifndef STATUS_LOCK_NOT_GRANTED
-# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L)
-#endif
-
-#ifndef STATUS_DELETE_PENDING
-# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L)
-#endif
-
-#ifndef STATUS_CTL_FILE_NOT_SUPPORTED
-# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L)
-#endif
-
-#ifndef STATUS_UNKNOWN_REVISION
-# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L)
-#endif
-
-#ifndef STATUS_REVISION_MISMATCH
-# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L)
-#endif
-
-#ifndef STATUS_INVALID_OWNER
-# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL)
-#endif
-
-#ifndef STATUS_INVALID_PRIMARY_GROUP
-# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL)
-#endif
-
-#ifndef STATUS_NO_IMPERSONATION_TOKEN
-# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL)
-#endif
-
-#ifndef STATUS_CANT_DISABLE_MANDATORY
-# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL)
-#endif
-
-#ifndef STATUS_NO_LOGON_SERVERS
-# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL)
-#endif
-
-#ifndef STATUS_NO_SUCH_LOGON_SESSION
-# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL)
-#endif
-
-#ifndef STATUS_NO_SUCH_PRIVILEGE
-# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L)
-#endif
-
-#ifndef STATUS_PRIVILEGE_NOT_HELD
-# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L)
-#endif
-
-#ifndef STATUS_INVALID_ACCOUNT_NAME
-# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L)
-#endif
-
-#ifndef STATUS_USER_EXISTS
-# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L)
-#endif
-
-#ifndef STATUS_NO_SUCH_USER
-# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L)
-#endif
-
-#ifndef STATUS_GROUP_EXISTS
-# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L)
-#endif
-
-#ifndef STATUS_NO_SUCH_GROUP
-# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L)
-#endif
-
-#ifndef STATUS_MEMBER_IN_GROUP
-# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L)
-#endif
-
-#ifndef STATUS_MEMBER_NOT_IN_GROUP
-# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L)
-#endif
-
-#ifndef STATUS_LAST_ADMIN
-# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L)
-#endif
-
-#ifndef STATUS_WRONG_PASSWORD
-# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL)
-#endif
-
-#ifndef STATUS_ILL_FORMED_PASSWORD
-# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL)
-#endif
-
-#ifndef STATUS_PASSWORD_RESTRICTION
-# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL)
-#endif
-
-#ifndef STATUS_LOGON_FAILURE
-# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL)
-#endif
-
-#ifndef STATUS_ACCOUNT_RESTRICTION
-# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL)
-#endif
-
-#ifndef STATUS_INVALID_LOGON_HOURS
-# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL)
-#endif
-
-#ifndef STATUS_INVALID_WORKSTATION
-# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L)
-#endif
-
-#ifndef STATUS_PASSWORD_EXPIRED
-# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L)
-#endif
-
-#ifndef STATUS_ACCOUNT_DISABLED
-# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L)
-#endif
-
-#ifndef STATUS_NONE_MAPPED
-# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L)
-#endif
-
-#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED
-# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L)
-#endif
-
-#ifndef STATUS_LUIDS_EXHAUSTED
-# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L)
-#endif
-
-#ifndef STATUS_INVALID_SUB_AUTHORITY
-# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L)
-#endif
-
-#ifndef STATUS_INVALID_ACL
-# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L)
-#endif
-
-#ifndef STATUS_INVALID_SID
-# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L)
-#endif
-
-#ifndef STATUS_INVALID_SECURITY_DESCR
-# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L)
-#endif
-
-#ifndef STATUS_PROCEDURE_NOT_FOUND
-# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_FORMAT
-# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL)
-#endif
-
-#ifndef STATUS_NO_TOKEN
-# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL)
-#endif
-
-#ifndef STATUS_BAD_INHERITANCE_ACL
-# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL)
-#endif
-
-#ifndef STATUS_RANGE_NOT_LOCKED
-# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL)
-#endif
-
-#ifndef STATUS_DISK_FULL
-# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL)
-#endif
-
-#ifndef STATUS_SERVER_DISABLED
-# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L)
-#endif
-
-#ifndef STATUS_SERVER_NOT_DISABLED
-# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L)
-#endif
-
-#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED
-# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L)
-#endif
-
-#ifndef STATUS_GUIDS_EXHAUSTED
-# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L)
-#endif
-
-#ifndef STATUS_INVALID_ID_AUTHORITY
-# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L)
-#endif
-
-#ifndef STATUS_AGENTS_EXHAUSTED
-# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L)
-#endif
-
-#ifndef STATUS_INVALID_VOLUME_LABEL
-# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L)
-#endif
-
-#ifndef STATUS_SECTION_NOT_EXTENDED
-# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L)
-#endif
-
-#ifndef STATUS_NOT_MAPPED_DATA
-# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L)
-#endif
-
-#ifndef STATUS_RESOURCE_DATA_NOT_FOUND
-# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L)
-#endif
-
-#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND
-# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL)
-#endif
-
-#ifndef STATUS_RESOURCE_NAME_NOT_FOUND
-# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL)
-#endif
-
-#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED
-# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL)
-#endif
-
-#ifndef STATUS_FLOAT_DENORMAL_OPERAND
-# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL)
-#endif
-
-#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO
-# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL)
-#endif
-
-#ifndef STATUS_FLOAT_INEXACT_RESULT
-# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL)
-#endif
-
-#ifndef STATUS_FLOAT_INVALID_OPERATION
-# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L)
-#endif
-
-#ifndef STATUS_FLOAT_OVERFLOW
-# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L)
-#endif
-
-#ifndef STATUS_FLOAT_STACK_CHECK
-# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L)
-#endif
-
-#ifndef STATUS_FLOAT_UNDERFLOW
-# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L)
-#endif
-
-#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO
-# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L)
-#endif
-
-#ifndef STATUS_INTEGER_OVERFLOW
-# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L)
-#endif
-
-#ifndef STATUS_PRIVILEGED_INSTRUCTION
-# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L)
-#endif
-
-#ifndef STATUS_TOO_MANY_PAGING_FILES
-# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L)
-#endif
-
-#ifndef STATUS_FILE_INVALID
-# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L)
-#endif
-
-#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED
-# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L)
-#endif
-
-#ifndef STATUS_INSUFFICIENT_RESOURCES
-# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL)
-#endif
-
-#ifndef STATUS_DFS_EXIT_PATH_FOUND
-# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL)
-#endif
-
-#ifndef STATUS_DEVICE_DATA_ERROR
-# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL)
-#endif
-
-#ifndef STATUS_DEVICE_NOT_CONNECTED
-# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL)
-#endif
-
-#ifndef STATUS_DEVICE_POWER_FAILURE
-# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL)
-#endif
-
-#ifndef STATUS_FREE_VM_NOT_AT_BASE
-# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL)
-#endif
-
-#ifndef STATUS_MEMORY_NOT_ALLOCATED
-# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L)
-#endif
-
-#ifndef STATUS_WORKING_SET_QUOTA
-# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L)
-#endif
-
-#ifndef STATUS_MEDIA_WRITE_PROTECTED
-# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L)
-#endif
-
-#ifndef STATUS_DEVICE_NOT_READY
-# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)
-#endif
-
-#ifndef STATUS_INVALID_GROUP_ATTRIBUTES
-# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L)
-#endif
-
-#ifndef STATUS_BAD_IMPERSONATION_LEVEL
-# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L)
-#endif
-
-#ifndef STATUS_CANT_OPEN_ANONYMOUS
-# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L)
-#endif
-
-#ifndef STATUS_BAD_VALIDATION_CLASS
-# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L)
-#endif
-
-#ifndef STATUS_BAD_TOKEN_TYPE
-# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L)
-#endif
-
-#ifndef STATUS_BAD_MASTER_BOOT_RECORD
-# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L)
-#endif
-
-#ifndef STATUS_INSTRUCTION_MISALIGNMENT
-# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL)
-#endif
-
-#ifndef STATUS_INSTANCE_NOT_AVAILABLE
-# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL)
-#endif
-
-#ifndef STATUS_PIPE_NOT_AVAILABLE
-# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL)
-#endif
-
-#ifndef STATUS_INVALID_PIPE_STATE
-# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL)
-#endif
-
-#ifndef STATUS_PIPE_BUSY
-# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL)
-#endif
-
-#ifndef STATUS_ILLEGAL_FUNCTION
-# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL)
-#endif
-
-#ifndef STATUS_PIPE_DISCONNECTED
-# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L)
-#endif
-
-#ifndef STATUS_PIPE_CLOSING
-# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L)
-#endif
-
-#ifndef STATUS_PIPE_CONNECTED
-# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L)
-#endif
-
-#ifndef STATUS_PIPE_LISTENING
-# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L)
-#endif
-
-#ifndef STATUS_INVALID_READ_MODE
-# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L)
-#endif
-
-#ifndef STATUS_IO_TIMEOUT
-# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L)
-#endif
-
-#ifndef STATUS_FILE_FORCED_CLOSED
-# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L)
-#endif
-
-#ifndef STATUS_PROFILING_NOT_STARTED
-# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L)
-#endif
-
-#ifndef STATUS_PROFILING_NOT_STOPPED
-# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L)
-#endif
-
-#ifndef STATUS_COULD_NOT_INTERPRET
-# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L)
-#endif
-
-#ifndef STATUS_FILE_IS_A_DIRECTORY
-# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL)
-#endif
-
-#ifndef STATUS_NOT_SUPPORTED
-# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL)
-#endif
-
-#ifndef STATUS_REMOTE_NOT_LISTENING
-# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL)
-#endif
-
-#ifndef STATUS_DUPLICATE_NAME
-# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL)
-#endif
-
-#ifndef STATUS_BAD_NETWORK_PATH
-# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL)
-#endif
-
-#ifndef STATUS_NETWORK_BUSY
-# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL)
-#endif
-
-#ifndef STATUS_DEVICE_DOES_NOT_EXIST
-# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L)
-#endif
-
-#ifndef STATUS_TOO_MANY_COMMANDS
-# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L)
-#endif
-
-#ifndef STATUS_ADAPTER_HARDWARE_ERROR
-# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L)
-#endif
-
-#ifndef STATUS_INVALID_NETWORK_RESPONSE
-# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L)
-#endif
-
-#ifndef STATUS_UNEXPECTED_NETWORK_ERROR
-# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L)
-#endif
-
-#ifndef STATUS_BAD_REMOTE_ADAPTER
-# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L)
-#endif
-
-#ifndef STATUS_PRINT_QUEUE_FULL
-# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L)
-#endif
-
-#ifndef STATUS_NO_SPOOL_SPACE
-# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L)
-#endif
-
-#ifndef STATUS_PRINT_CANCELLED
-# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L)
-#endif
-
-#ifndef STATUS_NETWORK_NAME_DELETED
-# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L)
-#endif
-
-#ifndef STATUS_NETWORK_ACCESS_DENIED
-# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL)
-#endif
-
-#ifndef STATUS_BAD_DEVICE_TYPE
-# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL)
-#endif
-
-#ifndef STATUS_BAD_NETWORK_NAME
-# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL)
-#endif
-
-#ifndef STATUS_TOO_MANY_NAMES
-# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL)
-#endif
-
-#ifndef STATUS_TOO_MANY_SESSIONS
-# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL)
-#endif
-
-#ifndef STATUS_SHARING_PAUSED
-# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL)
-#endif
-
-#ifndef STATUS_REQUEST_NOT_ACCEPTED
-# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L)
-#endif
-
-#ifndef STATUS_REDIRECTOR_PAUSED
-# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L)
-#endif
-
-#ifndef STATUS_NET_WRITE_FAULT
-# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L)
-#endif
-
-#ifndef STATUS_PROFILING_AT_LIMIT
-# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L)
-#endif
-
-#ifndef STATUS_NOT_SAME_DEVICE
-# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L)
-#endif
-
-#ifndef STATUS_FILE_RENAMED
-# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L)
-#endif
-
-#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED
-# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L)
-#endif
-
-#ifndef STATUS_NO_SECURITY_ON_OBJECT
-# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L)
-#endif
-
-#ifndef STATUS_CANT_WAIT
-# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L)
-#endif
-
-#ifndef STATUS_PIPE_EMPTY
-# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L)
-#endif
-
-#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO
-# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL)
-#endif
-
-#ifndef STATUS_CANT_TERMINATE_SELF
-# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL)
-#endif
-
-#ifndef STATUS_INVALID_SERVER_STATE
-# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL)
-#endif
-
-#ifndef STATUS_INVALID_DOMAIN_STATE
-# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL)
-#endif
-
-#ifndef STATUS_INVALID_DOMAIN_ROLE
-# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL)
-#endif
-
-#ifndef STATUS_NO_SUCH_DOMAIN
-# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL)
-#endif
-
-#ifndef STATUS_DOMAIN_EXISTS
-# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L)
-#endif
-
-#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED
-# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L)
-#endif
-
-#ifndef STATUS_OPLOCK_NOT_GRANTED
-# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L)
-#endif
-
-#ifndef STATUS_INVALID_OPLOCK_PROTOCOL
-# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L)
-#endif
-
-#ifndef STATUS_INTERNAL_DB_CORRUPTION
-# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L)
-#endif
-
-#ifndef STATUS_INTERNAL_ERROR
-# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L)
-#endif
-
-#ifndef STATUS_GENERIC_NOT_MAPPED
-# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L)
-#endif
-
-#ifndef STATUS_BAD_DESCRIPTOR_FORMAT
-# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L)
-#endif
-
-#ifndef STATUS_INVALID_USER_BUFFER
-# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L)
-#endif
-
-#ifndef STATUS_UNEXPECTED_IO_ERROR
-# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L)
-#endif
-
-#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR
-# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL)
-#endif
-
-#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR
-# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL)
-#endif
-
-#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR
-# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL)
-#endif
-
-#ifndef STATUS_NOT_LOGON_PROCESS
-# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL)
-#endif
-
-#ifndef STATUS_LOGON_SESSION_EXISTS
-# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_1
-# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_2
-# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_3
-# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_4
-# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_5
-# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_6
-# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_7
-# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_8
-# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_9
-# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_10
-# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_11
-# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L)
-#endif
-
-#ifndef STATUS_INVALID_PARAMETER_12
-# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL)
-#endif
-
-#ifndef STATUS_REDIRECTOR_NOT_STARTED
-# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL)
-#endif
-
-#ifndef STATUS_REDIRECTOR_STARTED
-# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL)
-#endif
-
-#ifndef STATUS_STACK_OVERFLOW
-# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL)
-#endif
-
-#ifndef STATUS_NO_SUCH_PACKAGE
-# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL)
-#endif
-
-#ifndef STATUS_BAD_FUNCTION_TABLE
-# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL)
-#endif
-
-#ifndef STATUS_VARIABLE_NOT_FOUND
-# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L)
-#endif
-
-#ifndef STATUS_DIRECTORY_NOT_EMPTY
-# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L)
-#endif
-
-#ifndef STATUS_FILE_CORRUPT_ERROR
-# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L)
-#endif
-
-#ifndef STATUS_NOT_A_DIRECTORY
-# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L)
-#endif
-
-#ifndef STATUS_BAD_LOGON_SESSION_STATE
-# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L)
-#endif
-
-#ifndef STATUS_LOGON_SESSION_COLLISION
-# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L)
-#endif
-
-#ifndef STATUS_NAME_TOO_LONG
-# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L)
-#endif
-
-#ifndef STATUS_FILES_OPEN
-# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L)
-#endif
-
-#ifndef STATUS_CONNECTION_IN_USE
-# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L)
-#endif
-
-#ifndef STATUS_MESSAGE_NOT_FOUND
-# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L)
-#endif
-
-#ifndef STATUS_PROCESS_IS_TERMINATING
-# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL)
-#endif
-
-#ifndef STATUS_INVALID_LOGON_TYPE
-# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL)
-#endif
-
-#ifndef STATUS_NO_GUID_TRANSLATION
-# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL)
-#endif
-
-#ifndef STATUS_CANNOT_IMPERSONATE
-# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL)
-#endif
-
-#ifndef STATUS_IMAGE_ALREADY_LOADED
-# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL)
-#endif
-
-#ifndef STATUS_ABIOS_NOT_PRESENT
-# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL)
-#endif
-
-#ifndef STATUS_ABIOS_LID_NOT_EXIST
-# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L)
-#endif
-
-#ifndef STATUS_ABIOS_LID_ALREADY_OWNED
-# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L)
-#endif
-
-#ifndef STATUS_ABIOS_NOT_LID_OWNER
-# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L)
-#endif
-
-#ifndef STATUS_ABIOS_INVALID_COMMAND
-# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L)
-#endif
-
-#ifndef STATUS_ABIOS_INVALID_LID
-# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L)
-#endif
-
-#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
-# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L)
-#endif
-
-#ifndef STATUS_ABIOS_INVALID_SELECTOR
-# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L)
-#endif
-
-#ifndef STATUS_NO_LDT
-# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L)
-#endif
-
-#ifndef STATUS_INVALID_LDT_SIZE
-# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L)
-#endif
-
-#ifndef STATUS_INVALID_LDT_OFFSET
-# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L)
-#endif
-
-#ifndef STATUS_INVALID_LDT_DESCRIPTOR
-# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_NE_FORMAT
-# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL)
-#endif
-
-#ifndef STATUS_RXACT_INVALID_STATE
-# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL)
-#endif
-
-#ifndef STATUS_RXACT_COMMIT_FAILURE
-# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL)
-#endif
-
-#ifndef STATUS_MAPPED_FILE_SIZE_ZERO
-# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL)
-#endif
-
-#ifndef STATUS_TOO_MANY_OPENED_FILES
-# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL)
-#endif
-
-#ifndef STATUS_CANCELLED
-# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
-#endif
-
-#ifndef STATUS_CANNOT_DELETE
-# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L)
-#endif
-
-#ifndef STATUS_INVALID_COMPUTER_NAME
-# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L)
-#endif
-
-#ifndef STATUS_FILE_DELETED
-# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L)
-#endif
-
-#ifndef STATUS_SPECIAL_ACCOUNT
-# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L)
-#endif
-
-#ifndef STATUS_SPECIAL_GROUP
-# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L)
-#endif
-
-#ifndef STATUS_SPECIAL_USER
-# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L)
-#endif
-
-#ifndef STATUS_MEMBERS_PRIMARY_GROUP
-# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L)
-#endif
-
-#ifndef STATUS_FILE_CLOSED
-# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L)
-#endif
-
-#ifndef STATUS_TOO_MANY_THREADS
-# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L)
-#endif
-
-#ifndef STATUS_THREAD_NOT_IN_PROCESS
-# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL)
-#endif
-
-#ifndef STATUS_TOKEN_ALREADY_IN_USE
-# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL)
-#endif
-
-#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED
-# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL)
-#endif
-
-#ifndef STATUS_COMMITMENT_LIMIT
-# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_LE_FORMAT
-# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_NOT_MZ
-# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_PROTECT
-# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_WIN_16
-# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L)
-#endif
-
-#ifndef STATUS_LOGON_SERVER_CONFLICT
-# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L)
-#endif
-
-#ifndef STATUS_TIME_DIFFERENCE_AT_DC
-# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L)
-#endif
-
-#ifndef STATUS_SYNCHRONIZATION_REQUIRED
-# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L)
-#endif
-
-#ifndef STATUS_DLL_NOT_FOUND
-# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L)
-#endif
-
-#ifndef STATUS_OPEN_FAILED
-# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L)
-#endif
-
-#ifndef STATUS_IO_PRIVILEGE_FAILED
-# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L)
-#endif
-
-#ifndef STATUS_ORDINAL_NOT_FOUND
-# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L)
-#endif
-
-#ifndef STATUS_ENTRYPOINT_NOT_FOUND
-# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L)
-#endif
-
-#ifndef STATUS_CONTROL_C_EXIT
-# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL)
-#endif
-
-#ifndef STATUS_LOCAL_DISCONNECT
-# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL)
-#endif
-
-#ifndef STATUS_REMOTE_DISCONNECT
-# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL)
-#endif
-
-#ifndef STATUS_REMOTE_RESOURCES
-# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL)
-#endif
-
-#ifndef STATUS_LINK_FAILED
-# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL)
-#endif
-
-#ifndef STATUS_LINK_TIMEOUT
-# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL)
-#endif
-
-#ifndef STATUS_INVALID_CONNECTION
-# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L)
-#endif
-
-#ifndef STATUS_INVALID_ADDRESS
-# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L)
-#endif
-
-#ifndef STATUS_DLL_INIT_FAILED
-# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L)
-#endif
-
-#ifndef STATUS_MISSING_SYSTEMFILE
-# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L)
-#endif
-
-#ifndef STATUS_UNHANDLED_EXCEPTION
-# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L)
-#endif
-
-#ifndef STATUS_APP_INIT_FAILURE
-# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L)
-#endif
-
-#ifndef STATUS_PAGEFILE_CREATE_FAILED
-# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L)
-#endif
-
-#ifndef STATUS_NO_PAGEFILE
-# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L)
-#endif
-
-#ifndef STATUS_INVALID_LEVEL
-# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L)
-#endif
-
-#ifndef STATUS_WRONG_PASSWORD_CORE
-# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L)
-#endif
-
-#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT
-# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL)
-#endif
-
-#ifndef STATUS_PIPE_BROKEN
-# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL)
-#endif
-
-#ifndef STATUS_REGISTRY_CORRUPT
-# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL)
-#endif
-
-#ifndef STATUS_REGISTRY_IO_FAILED
-# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL)
-#endif
-
-#ifndef STATUS_NO_EVENT_PAIR
-# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL)
-#endif
-
-#ifndef STATUS_UNRECOGNIZED_VOLUME
-# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL)
-#endif
-
-#ifndef STATUS_SERIAL_NO_DEVICE_INITED
-# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L)
-#endif
-
-#ifndef STATUS_NO_SUCH_ALIAS
-# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L)
-#endif
-
-#ifndef STATUS_MEMBER_NOT_IN_ALIAS
-# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L)
-#endif
-
-#ifndef STATUS_MEMBER_IN_ALIAS
-# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L)
-#endif
-
-#ifndef STATUS_ALIAS_EXISTS
-# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L)
-#endif
-
-#ifndef STATUS_LOGON_NOT_GRANTED
-# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L)
-#endif
-
-#ifndef STATUS_TOO_MANY_SECRETS
-# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L)
-#endif
-
-#ifndef STATUS_SECRET_TOO_LONG
-# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L)
-#endif
-
-#ifndef STATUS_INTERNAL_DB_ERROR
-# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L)
-#endif
-
-#ifndef STATUS_FULLSCREEN_MODE
-# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L)
-#endif
-
-#ifndef STATUS_TOO_MANY_CONTEXT_IDS
-# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL)
-#endif
-
-#ifndef STATUS_LOGON_TYPE_NOT_GRANTED
-# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL)
-#endif
-
-#ifndef STATUS_NOT_REGISTRY_FILE
-# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL)
-#endif
-
-#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED
-# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL)
-#endif
-
-#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR
-# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL)
-#endif
-
-#ifndef STATUS_FT_MISSING_MEMBER
-# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL)
-#endif
-
-#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY
-# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L)
-#endif
-
-#ifndef STATUS_ILLEGAL_CHARACTER
-# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L)
-#endif
-
-#ifndef STATUS_UNMAPPABLE_CHARACTER
-# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L)
-#endif
-
-#ifndef STATUS_UNDEFINED_CHARACTER
-# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L)
-#endif
-
-#ifndef STATUS_FLOPPY_VOLUME
-# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L)
-#endif
-
-#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND
-# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L)
-#endif
-
-#ifndef STATUS_FLOPPY_WRONG_CYLINDER
-# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L)
-#endif
-
-#ifndef STATUS_FLOPPY_UNKNOWN_ERROR
-# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L)
-#endif
-
-#ifndef STATUS_FLOPPY_BAD_REGISTERS
-# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L)
-#endif
-
-#ifndef STATUS_DISK_RECALIBRATE_FAILED
-# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L)
-#endif
-
-#ifndef STATUS_DISK_OPERATION_FAILED
-# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL)
-#endif
-
-#ifndef STATUS_DISK_RESET_FAILED
-# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL)
-#endif
-
-#ifndef STATUS_SHARED_IRQ_BUSY
-# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL)
-#endif
-
-#ifndef STATUS_FT_ORPHANING
-# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL)
-#endif
-
-#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
-# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL)
-#endif
-
-#ifndef STATUS_PARTITION_FAILURE
-# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L)
-#endif
-
-#ifndef STATUS_INVALID_BLOCK_LENGTH
-# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L)
-#endif
-
-#ifndef STATUS_DEVICE_NOT_PARTITIONED
-# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L)
-#endif
-
-#ifndef STATUS_UNABLE_TO_LOCK_MEDIA
-# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L)
-#endif
-
-#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA
-# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L)
-#endif
-
-#ifndef STATUS_EOM_OVERFLOW
-# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L)
-#endif
-
-#ifndef STATUS_NO_MEDIA
-# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L)
-#endif
-
-#ifndef STATUS_NO_SUCH_MEMBER
-# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL)
-#endif
-
-#ifndef STATUS_INVALID_MEMBER
-# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL)
-#endif
-
-#ifndef STATUS_KEY_DELETED
-# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL)
-#endif
-
-#ifndef STATUS_NO_LOG_SPACE
-# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL)
-#endif
-
-#ifndef STATUS_TOO_MANY_SIDS
-# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL)
-#endif
-
-#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED
-# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL)
-#endif
-
-#ifndef STATUS_KEY_HAS_CHILDREN
-# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L)
-#endif
-
-#ifndef STATUS_CHILD_MUST_BE_VOLATILE
-# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L)
-#endif
-
-#ifndef STATUS_DEVICE_CONFIGURATION_ERROR
-# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L)
-#endif
-
-#ifndef STATUS_DRIVER_INTERNAL_ERROR
-# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L)
-#endif
-
-#ifndef STATUS_INVALID_DEVICE_STATE
-# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L)
-#endif
-
-#ifndef STATUS_IO_DEVICE_ERROR
-# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L)
-#endif
-
-#ifndef STATUS_DEVICE_PROTOCOL_ERROR
-# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L)
-#endif
-
-#ifndef STATUS_BACKUP_CONTROLLER
-# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L)
-#endif
-
-#ifndef STATUS_LOG_FILE_FULL
-# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L)
-#endif
-
-#ifndef STATUS_TOO_LATE
-# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L)
-#endif
-
-#ifndef STATUS_NO_TRUST_LSA_SECRET
-# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL)
-#endif
-
-#ifndef STATUS_NO_TRUST_SAM_ACCOUNT
-# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL)
-#endif
-
-#ifndef STATUS_TRUSTED_DOMAIN_FAILURE
-# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL)
-#endif
-
-#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE
-# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL)
-#endif
-
-#ifndef STATUS_EVENTLOG_FILE_CORRUPT
-# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL)
-#endif
-
-#ifndef STATUS_EVENTLOG_CANT_START
-# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL)
-#endif
-
-#ifndef STATUS_TRUST_FAILURE
-# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L)
-#endif
-
-#ifndef STATUS_MUTANT_LIMIT_EXCEEDED
-# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L)
-#endif
-
-#ifndef STATUS_NETLOGON_NOT_STARTED
-# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L)
-#endif
-
-#ifndef STATUS_ACCOUNT_EXPIRED
-# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L)
-#endif
-
-#ifndef STATUS_POSSIBLE_DEADLOCK
-# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L)
-#endif
-
-#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT
-# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L)
-#endif
-
-#ifndef STATUS_REMOTE_SESSION_LIMIT
-# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L)
-#endif
-
-#ifndef STATUS_EVENTLOG_FILE_CHANGED
-# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L)
-#endif
-
-#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
-# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L)
-#endif
-
-#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
-# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L)
-#endif
-
-#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
-# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL)
-#endif
-
-#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT
-# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL)
-#endif
-
-#ifndef STATUS_FS_DRIVER_REQUIRED
-# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL)
-#endif
-
-#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL
-# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL)
-#endif
-
-#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
-# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL)
-#endif
-
-#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
-# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL)
-#endif
-
-#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT
-# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L)
-#endif
-
-#ifndef STATUS_INVALID_LOCK_RANGE
-# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L)
-#endif
-
-#ifndef STATUS_INVALID_ACE_CONDITION
-# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L)
-#endif
-
-#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
-# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L)
-#endif
-
-#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
-# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L)
-#endif
-
-#ifndef STATUS_NETWORK_OPEN_RESTRICTION
-# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L)
-#endif
-
-#ifndef STATUS_NO_USER_SESSION_KEY
-# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L)
-#endif
-
-#ifndef STATUS_USER_SESSION_DELETED
-# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L)
-#endif
-
-#ifndef STATUS_RESOURCE_LANG_NOT_FOUND
-# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L)
-#endif
-
-#ifndef STATUS_INSUFF_SERVER_RESOURCES
-# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L)
-#endif
-
-#ifndef STATUS_INVALID_BUFFER_SIZE
-# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L)
-#endif
-
-#ifndef STATUS_INVALID_ADDRESS_COMPONENT
-# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L)
-#endif
-
-#ifndef STATUS_INVALID_ADDRESS_WILDCARD
-# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L)
-#endif
-
-#ifndef STATUS_TOO_MANY_ADDRESSES
-# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L)
-#endif
-
-#ifndef STATUS_ADDRESS_ALREADY_EXISTS
-# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL)
-#endif
-
-#ifndef STATUS_ADDRESS_CLOSED
-# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL)
-#endif
-
-#ifndef STATUS_CONNECTION_DISCONNECTED
-# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL)
-#endif
-
-#ifndef STATUS_CONNECTION_RESET
-# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL)
-#endif
-
-#ifndef STATUS_TOO_MANY_NODES
-# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL)
-#endif
-
-#ifndef STATUS_TRANSACTION_ABORTED
-# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL)
-#endif
-
-#ifndef STATUS_TRANSACTION_TIMED_OUT
-# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L)
-#endif
-
-#ifndef STATUS_TRANSACTION_NO_RELEASE
-# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L)
-#endif
-
-#ifndef STATUS_TRANSACTION_NO_MATCH
-# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L)
-#endif
-
-#ifndef STATUS_TRANSACTION_RESPONDED
-# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L)
-#endif
-
-#ifndef STATUS_TRANSACTION_INVALID_ID
-# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L)
-#endif
-
-#ifndef STATUS_TRANSACTION_INVALID_TYPE
-# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L)
-#endif
-
-#ifndef STATUS_NOT_SERVER_SESSION
-# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L)
-#endif
-
-#ifndef STATUS_NOT_CLIENT_SESSION
-# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L)
-#endif
-
-#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE
-# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L)
-#endif
-
-#ifndef STATUS_DEBUG_ATTACH_FAILED
-# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L)
-#endif
-
-#ifndef STATUS_SYSTEM_PROCESS_TERMINATED
-# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL)
-#endif
-
-#ifndef STATUS_DATA_NOT_ACCEPTED
-# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL)
-#endif
-
-#ifndef STATUS_NO_BROWSER_SERVERS_FOUND
-# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL)
-#endif
-
-#ifndef STATUS_VDM_HARD_ERROR
-# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL)
-#endif
-
-#ifndef STATUS_DRIVER_CANCEL_TIMEOUT
-# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL)
-#endif
-
-#ifndef STATUS_REPLY_MESSAGE_MISMATCH
-# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL)
-#endif
-
-#ifndef STATUS_MAPPED_ALIGNMENT
-# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L)
-#endif
-
-#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH
-# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L)
-#endif
-
-#ifndef STATUS_LOST_WRITEBEHIND_DATA
-# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L)
-#endif
-
-#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID
-# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L)
-#endif
-
-#ifndef STATUS_PASSWORD_MUST_CHANGE
-# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L)
-#endif
-
-#ifndef STATUS_NOT_FOUND
-# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
-#endif
-
-#ifndef STATUS_NOT_TINY_STREAM
-# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L)
-#endif
-
-#ifndef STATUS_RECOVERY_FAILURE
-# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L)
-#endif
-
-#ifndef STATUS_STACK_OVERFLOW_READ
-# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L)
-#endif
-
-#ifndef STATUS_FAIL_CHECK
-# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L)
-#endif
-
-#ifndef STATUS_DUPLICATE_OBJECTID
-# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL)
-#endif
-
-#ifndef STATUS_OBJECTID_EXISTS
-# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL)
-#endif
-
-#ifndef STATUS_CONVERT_TO_LARGE
-# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL)
-#endif
-
-#ifndef STATUS_RETRY
-# define STATUS_RETRY ((NTSTATUS) 0xC000022DL)
-#endif
-
-#ifndef STATUS_FOUND_OUT_OF_SCOPE
-# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL)
-#endif
-
-#ifndef STATUS_ALLOCATE_BUCKET
-# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL)
-#endif
-
-#ifndef STATUS_PROPSET_NOT_FOUND
-# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L)
-#endif
-
-#ifndef STATUS_MARSHALL_OVERFLOW
-# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L)
-#endif
-
-#ifndef STATUS_INVALID_VARIANT
-# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L)
-#endif
-
-#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND
-# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L)
-#endif
-
-#ifndef STATUS_ACCOUNT_LOCKED_OUT
-# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L)
-#endif
-
-#ifndef STATUS_HANDLE_NOT_CLOSABLE
-# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L)
-#endif
-
-#ifndef STATUS_CONNECTION_REFUSED
-# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L)
-#endif
-
-#ifndef STATUS_GRACEFUL_DISCONNECT
-# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L)
-#endif
-
-#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED
-# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L)
-#endif
-
-#ifndef STATUS_ADDRESS_NOT_ASSOCIATED
-# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L)
-#endif
-
-#ifndef STATUS_CONNECTION_INVALID
-# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL)
-#endif
-
-#ifndef STATUS_CONNECTION_ACTIVE
-# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL)
-#endif
-
-#ifndef STATUS_NETWORK_UNREACHABLE
-# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL)
-#endif
-
-#ifndef STATUS_HOST_UNREACHABLE
-# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL)
-#endif
-
-#ifndef STATUS_PROTOCOL_UNREACHABLE
-# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL)
-#endif
-
-#ifndef STATUS_PORT_UNREACHABLE
-# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL)
-#endif
-
-#ifndef STATUS_REQUEST_ABORTED
-# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L)
-#endif
-
-#ifndef STATUS_CONNECTION_ABORTED
-# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L)
-#endif
-
-#ifndef STATUS_BAD_COMPRESSION_BUFFER
-# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L)
-#endif
-
-#ifndef STATUS_USER_MAPPED_FILE
-# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L)
-#endif
-
-#ifndef STATUS_AUDIT_FAILED
-# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L)
-#endif
-
-#ifndef STATUS_TIMER_RESOLUTION_NOT_SET
-# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L)
-#endif
-
-#ifndef STATUS_CONNECTION_COUNT_LIMIT
-# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L)
-#endif
-
-#ifndef STATUS_LOGIN_TIME_RESTRICTION
-# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L)
-#endif
-
-#ifndef STATUS_LOGIN_WKSTA_RESTRICTION
-# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L)
-#endif
-
-#ifndef STATUS_IMAGE_MP_UP_MISMATCH
-# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L)
-#endif
-
-#ifndef STATUS_INSUFFICIENT_LOGON_INFO
-# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L)
-#endif
-
-#ifndef STATUS_BAD_DLL_ENTRYPOINT
-# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L)
-#endif
-
-#ifndef STATUS_BAD_SERVICE_ENTRYPOINT
-# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L)
-#endif
-
-#ifndef STATUS_LPC_REPLY_LOST
-# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L)
-#endif
-
-#ifndef STATUS_IP_ADDRESS_CONFLICT1
-# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L)
-#endif
-
-#ifndef STATUS_IP_ADDRESS_CONFLICT2
-# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L)
-#endif
-
-#ifndef STATUS_REGISTRY_QUOTA_LIMIT
-# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L)
-#endif
-
-#ifndef STATUS_PATH_NOT_COVERED
-# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L)
-#endif
-
-#ifndef STATUS_NO_CALLBACK_ACTIVE
-# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L)
-#endif
-
-#ifndef STATUS_LICENSE_QUOTA_EXCEEDED
-# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L)
-#endif
-
-#ifndef STATUS_PWD_TOO_SHORT
-# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL)
-#endif
-
-#ifndef STATUS_PWD_TOO_RECENT
-# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL)
-#endif
-
-#ifndef STATUS_PWD_HISTORY_CONFLICT
-# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL)
-#endif
-
-#ifndef STATUS_PLUGPLAY_NO_DEVICE
-# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL)
-#endif
-
-#ifndef STATUS_UNSUPPORTED_COMPRESSION
-# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL)
-#endif
-
-#ifndef STATUS_INVALID_HW_PROFILE
-# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L)
-#endif
-
-#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH
-# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L)
-#endif
-
-#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND
-# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L)
-#endif
-
-#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
-# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L)
-#endif
-
-#ifndef STATUS_RESOURCE_NOT_OWNED
-# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L)
-#endif
-
-#ifndef STATUS_TOO_MANY_LINKS
-# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L)
-#endif
-
-#ifndef STATUS_QUOTA_LIST_INCONSISTENT
-# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L)
-#endif
-
-#ifndef STATUS_FILE_IS_OFFLINE
-# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L)
-#endif
-
-#ifndef STATUS_EVALUATION_EXPIRATION
-# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L)
-#endif
-
-#ifndef STATUS_ILLEGAL_DLL_RELOCATION
-# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L)
-#endif
-
-#ifndef STATUS_LICENSE_VIOLATION
-# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL)
-#endif
-
-#ifndef STATUS_DLL_INIT_FAILED_LOGOFF
-# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL)
-#endif
-
-#ifndef STATUS_DRIVER_UNABLE_TO_LOAD
-# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL)
-#endif
-
-#ifndef STATUS_DFS_UNAVAILABLE
-# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL)
-#endif
-
-#ifndef STATUS_VOLUME_DISMOUNTED
-# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL)
-#endif
-
-#ifndef STATUS_WX86_INTERNAL_ERROR
-# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL)
-#endif
-
-#ifndef STATUS_WX86_FLOAT_STACK_CHECK
-# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L)
-#endif
-
-#ifndef STATUS_VALIDATE_CONTINUE
-# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L)
-#endif
-
-#ifndef STATUS_NO_MATCH
-# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L)
-#endif
-
-#ifndef STATUS_NO_MORE_MATCHES
-# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L)
-#endif
-
-#ifndef STATUS_NOT_A_REPARSE_POINT
-# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L)
-#endif
-
-#ifndef STATUS_IO_REPARSE_TAG_INVALID
-# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L)
-#endif
-
-#ifndef STATUS_IO_REPARSE_TAG_MISMATCH
-# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L)
-#endif
-
-#ifndef STATUS_IO_REPARSE_DATA_INVALID
-# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L)
-#endif
-
-#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED
-# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L)
-#endif
-
-#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED
-# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L)
-#endif
-
-#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT
-# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L)
-#endif
-
-#ifndef STATUS_RANGE_LIST_CONFLICT
-# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L)
-#endif
-
-#ifndef STATUS_SOURCE_ELEMENT_EMPTY
-# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L)
-#endif
-
-#ifndef STATUS_DESTINATION_ELEMENT_FULL
-# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L)
-#endif
-
-#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS
-# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L)
-#endif
-
-#ifndef STATUS_MAGAZINE_NOT_PRESENT
-# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L)
-#endif
-
-#ifndef STATUS_REINITIALIZATION_NEEDED
-# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L)
-#endif
-
-#ifndef STATUS_DEVICE_REQUIRES_CLEANING
-# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L)
-#endif
-
-#ifndef STATUS_DEVICE_DOOR_OPEN
-# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L)
-#endif
-
-#ifndef STATUS_ENCRYPTION_FAILED
-# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL)
-#endif
-
-#ifndef STATUS_DECRYPTION_FAILED
-# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL)
-#endif
-
-#ifndef STATUS_RANGE_NOT_FOUND
-# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL)
-#endif
-
-#ifndef STATUS_NO_RECOVERY_POLICY
-# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL)
-#endif
-
-#ifndef STATUS_NO_EFS
-# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL)
-#endif
-
-#ifndef STATUS_WRONG_EFS
-# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL)
-#endif
-
-#ifndef STATUS_NO_USER_KEYS
-# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L)
-#endif
-
-#ifndef STATUS_FILE_NOT_ENCRYPTED
-# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L)
-#endif
-
-#ifndef STATUS_NOT_EXPORT_FORMAT
-# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L)
-#endif
-
-#ifndef STATUS_FILE_ENCRYPTED
-# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L)
-#endif
-
-#ifndef STATUS_WAKE_SYSTEM
-# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L)
-#endif
-
-#ifndef STATUS_WMI_GUID_NOT_FOUND
-# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L)
-#endif
-
-#ifndef STATUS_WMI_INSTANCE_NOT_FOUND
-# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L)
-#endif
-
-#ifndef STATUS_WMI_ITEMID_NOT_FOUND
-# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L)
-#endif
-
-#ifndef STATUS_WMI_TRY_AGAIN
-# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L)
-#endif
-
-#ifndef STATUS_SHARED_POLICY
-# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L)
-#endif
-
-#ifndef STATUS_POLICY_OBJECT_NOT_FOUND
-# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL)
-#endif
-
-#ifndef STATUS_POLICY_ONLY_IN_DS
-# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL)
-#endif
-
-#ifndef STATUS_VOLUME_NOT_UPGRADED
-# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL)
-#endif
-
-#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE
-# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL)
-#endif
-
-#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR
-# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL)
-#endif
-
-#ifndef STATUS_NO_TRACKING_SERVICE
-# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL)
-#endif
-
-#ifndef STATUS_SERVER_SID_MISMATCH
-# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L)
-#endif
-
-#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE
-# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L)
-#endif
-
-#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
-# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L)
-#endif
-
-#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
-# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L)
-#endif
-
-#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
-# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L)
-#endif
-
-#ifndef STATUS_DS_BUSY
-# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L)
-#endif
-
-#ifndef STATUS_DS_UNAVAILABLE
-# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L)
-#endif
-
-#ifndef STATUS_DS_NO_RIDS_ALLOCATED
-# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L)
-#endif
-
-#ifndef STATUS_DS_NO_MORE_RIDS
-# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L)
-#endif
-
-#ifndef STATUS_DS_INCORRECT_ROLE_OWNER
-# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L)
-#endif
-
-#ifndef STATUS_DS_RIDMGR_INIT_ERROR
-# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL)
-#endif
-
-#ifndef STATUS_DS_OBJ_CLASS_VIOLATION
-# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL)
-#endif
-
-#ifndef STATUS_DS_CANT_ON_NON_LEAF
-# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL)
-#endif
-
-#ifndef STATUS_DS_CANT_ON_RDN
-# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL)
-#endif
-
-#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS
-# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL)
-#endif
-
-#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED
-# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL)
-#endif
-
-#ifndef STATUS_DS_GC_NOT_AVAILABLE
-# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L)
-#endif
-
-#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED
-# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L)
-#endif
-
-#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT
-# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L)
-#endif
-
-#ifndef STATUS_CANT_ENABLE_DENY_ONLY
-# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L)
-#endif
-
-#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
-# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L)
-#endif
-
-#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
-# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L)
-#endif
-
-#ifndef STATUS_DEVICE_REMOVED
-# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L)
-#endif
-
-#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS
-# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L)
-#endif
-
-#ifndef STATUS_JOURNAL_NOT_ACTIVE
-# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L)
-#endif
-
-#ifndef STATUS_NOINTERFACE
-# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L)
-#endif
-
-#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED
-# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L)
-#endif
-
-#ifndef STATUS_DRIVER_FAILED_SLEEP
-# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L)
-#endif
-
-#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED
-# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L)
-#endif
-
-#ifndef STATUS_CORRUPT_SYSTEM_FILE
-# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L)
-#endif
-
-#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR
-# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L)
-#endif
-
-#ifndef STATUS_WMI_READ_ONLY
-# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L)
-#endif
-
-#ifndef STATUS_WMI_SET_FAILURE
-# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L)
-#endif
-
-#ifndef STATUS_COMMITMENT_MINIMUM
-# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L)
-#endif
-
-#ifndef STATUS_REG_NAT_CONSUMPTION
-# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L)
-#endif
-
-#ifndef STATUS_TRANSPORT_FULL
-# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL)
-#endif
-
-#ifndef STATUS_DS_SAM_INIT_FAILURE
-# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL)
-#endif
-
-#ifndef STATUS_ONLY_IF_CONNECTED
-# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL)
-#endif
-
-#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION
-# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL)
-#endif
-
-#ifndef STATUS_PNP_RESTART_ENUMERATION
-# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL)
-#endif
-
-#ifndef STATUS_JOURNAL_ENTRY_DELETED
-# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL)
-#endif
-
-#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID
-# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L)
-#endif
-
-#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
-# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L)
-#endif
-
-#ifndef STATUS_PNP_REBOOT_REQUIRED
-# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L)
-#endif
-
-#ifndef STATUS_POWER_STATE_INVALID
-# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L)
-#endif
-
-#ifndef STATUS_DS_INVALID_GROUP_TYPE
-# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L)
-#endif
-
-#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
-# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L)
-#endif
-
-#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
-# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L)
-#endif
-
-#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
-# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L)
-#endif
-
-#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
-# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L)
-#endif
-
-#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
-# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L)
-#endif
-
-#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
-# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL)
-#endif
-
-#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
-# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL)
-#endif
-
-#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS
-# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL)
-#endif
-
-#ifndef STATUS_WMI_NOT_SUPPORTED
-# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL)
-#endif
-
-#ifndef STATUS_INSUFFICIENT_POWER
-# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL)
-#endif
-
-#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD
-# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL)
-#endif
-
-#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY
-# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L)
-#endif
-
-#ifndef STATUS_DS_CANT_START
-# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L)
-#endif
-
-#ifndef STATUS_DS_INIT_FAILURE
-# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L)
-#endif
-
-#ifndef STATUS_SAM_INIT_FAILURE
-# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L)
-#endif
-
-#ifndef STATUS_DS_GC_REQUIRED
-# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L)
-#endif
-
-#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
-# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L)
-#endif
-
-#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
-# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L)
-#endif
-
-#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
-# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L)
-#endif
-
-#ifndef STATUS_MULTIPLE_FAULT_VIOLATION
-# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L)
-#endif
-
-#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED
-# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L)
-#endif
-
-#ifndef STATUS_CANNOT_MAKE
-# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL)
-#endif
-
-#ifndef STATUS_SYSTEM_SHUTDOWN
-# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL)
-#endif
-
-#ifndef STATUS_DS_INIT_FAILURE_CONSOLE
-# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL)
-#endif
-
-#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE
-# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL)
-#endif
-
-#ifndef STATUS_UNFINISHED_CONTEXT_DELETED
-# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL)
-#endif
-
-#ifndef STATUS_NO_TGT_REPLY
-# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL)
-#endif
-
-#ifndef STATUS_OBJECTID_NOT_FOUND
-# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L)
-#endif
-
-#ifndef STATUS_NO_IP_ADDRESSES
-# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L)
-#endif
-
-#ifndef STATUS_WRONG_CREDENTIAL_HANDLE
-# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L)
-#endif
-
-#ifndef STATUS_CRYPTO_SYSTEM_INVALID
-# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L)
-#endif
-
-#ifndef STATUS_MAX_REFERRALS_EXCEEDED
-# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L)
-#endif
-
-#ifndef STATUS_MUST_BE_KDC
-# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L)
-#endif
-
-#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED
-# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L)
-#endif
-
-#ifndef STATUS_TOO_MANY_PRINCIPALS
-# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L)
-#endif
-
-#ifndef STATUS_NO_PA_DATA
-# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L)
-#endif
-
-#ifndef STATUS_PKINIT_NAME_MISMATCH
-# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L)
-#endif
-
-#ifndef STATUS_SMARTCARD_LOGON_REQUIRED
-# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL)
-#endif
-
-#ifndef STATUS_KDC_INVALID_REQUEST
-# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL)
-#endif
-
-#ifndef STATUS_KDC_UNABLE_TO_REFER
-# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL)
-#endif
-
-#ifndef STATUS_KDC_UNKNOWN_ETYPE
-# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL)
-#endif
-
-#ifndef STATUS_SHUTDOWN_IN_PROGRESS
-# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL)
-#endif
-
-#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS
-# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL)
-#endif
-
-#ifndef STATUS_NOT_SUPPORTED_ON_SBS
-# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L)
-#endif
-
-#ifndef STATUS_WMI_GUID_DISCONNECTED
-# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L)
-#endif
-
-#ifndef STATUS_WMI_ALREADY_DISABLED
-# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L)
-#endif
-
-#ifndef STATUS_WMI_ALREADY_ENABLED
-# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L)
-#endif
-
-#ifndef STATUS_MFT_TOO_FRAGMENTED
-# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L)
-#endif
-
-#ifndef STATUS_COPY_PROTECTION_FAILURE
-# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L)
-#endif
-
-#ifndef STATUS_CSS_AUTHENTICATION_FAILURE
-# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L)
-#endif
-
-#ifndef STATUS_CSS_KEY_NOT_PRESENT
-# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L)
-#endif
-
-#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED
-# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L)
-#endif
-
-#ifndef STATUS_CSS_SCRAMBLED_SECTOR
-# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L)
-#endif
-
-#ifndef STATUS_CSS_REGION_MISMATCH
-# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL)
-#endif
-
-#ifndef STATUS_CSS_RESETS_EXHAUSTED
-# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL)
-#endif
-
-#ifndef STATUS_PKINIT_FAILURE
-# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L)
-#endif
-
-#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE
-# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L)
-#endif
-
-#ifndef STATUS_NO_KERB_KEY
-# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L)
-#endif
-
-#ifndef STATUS_HOST_DOWN
-# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L)
-#endif
-
-#ifndef STATUS_UNSUPPORTED_PREAUTH
-# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L)
-#endif
-
-#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG
-# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L)
-#endif
-
-#ifndef STATUS_PORT_NOT_SET
-# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L)
-#endif
-
-#ifndef STATUS_DEBUGGER_INACTIVE
-# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L)
-#endif
-
-#ifndef STATUS_DS_VERSION_CHECK_FAILURE
-# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L)
-#endif
-
-#ifndef STATUS_AUDITING_DISABLED
-# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L)
-#endif
-
-#ifndef STATUS_PRENT4_MACHINE_ACCOUNT
-# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L)
-#endif
-
-#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
-# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_WIN_32
-# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_WIN_64
-# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL)
-#endif
-
-#ifndef STATUS_BAD_BINDINGS
-# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL)
-#endif
-
-#ifndef STATUS_NETWORK_SESSION_EXPIRED
-# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL)
-#endif
-
-#ifndef STATUS_APPHELP_BLOCK
-# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL)
-#endif
-
-#ifndef STATUS_ALL_SIDS_FILTERED
-# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL)
-#endif
-
-#ifndef STATUS_NOT_SAFE_MODE_DRIVER
-# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL)
-#endif
-
-#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
-# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L)
-#endif
-
-#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH
-# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L)
-#endif
-
-#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
-# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L)
-#endif
-
-#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
-# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L)
-#endif
-
-#ifndef STATUS_FAILED_DRIVER_ENTRY
-# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L)
-#endif
-
-#ifndef STATUS_DEVICE_ENUMERATION_ERROR
-# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L)
-#endif
-
-#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED
-# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L)
-#endif
-
-#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
-# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L)
-#endif
-
-#ifndef STATUS_MCA_OCCURED
-# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL)
-#endif
-
-#ifndef STATUS_DRIVER_BLOCKED_CRITICAL
-# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL)
-#endif
-
-#ifndef STATUS_DRIVER_BLOCKED
-# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL)
-#endif
-
-#ifndef STATUS_DRIVER_DATABASE_ERROR
-# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL)
-#endif
-
-#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE
-# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL)
-#endif
-
-#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL
-# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL)
-#endif
-
-#ifndef STATUS_DS_SHUTTING_DOWN
-# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L)
-#endif
-
-#ifndef STATUS_NO_SECRETS
-# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L)
-#endif
-
-#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
-# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L)
-#endif
-
-#ifndef STATUS_FAILED_STACK_SWITCH
-# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L)
-#endif
-
-#ifndef STATUS_HEAP_CORRUPTION
-# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L)
-#endif
-
-#ifndef STATUS_SMARTCARD_WRONG_PIN
-# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L)
-#endif
-
-#ifndef STATUS_SMARTCARD_CARD_BLOCKED
-# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L)
-#endif
-
-#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
-# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L)
-#endif
-
-#ifndef STATUS_SMARTCARD_NO_CARD
-# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L)
-#endif
-
-#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER
-# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L)
-#endif
-
-#ifndef STATUS_SMARTCARD_NO_CERTIFICATE
-# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L)
-#endif
-
-#ifndef STATUS_SMARTCARD_NO_KEYSET
-# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L)
-#endif
-
-#ifndef STATUS_SMARTCARD_IO_ERROR
-# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L)
-#endif
-
-#ifndef STATUS_DOWNGRADE_DETECTED
-# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L)
-#endif
-
-#ifndef STATUS_SMARTCARD_CERT_REVOKED
-# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L)
-#endif
-
-#ifndef STATUS_ISSUING_CA_UNTRUSTED
-# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL)
-#endif
-
-#ifndef STATUS_REVOCATION_OFFLINE_C
-# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL)
-#endif
-
-#ifndef STATUS_PKINIT_CLIENT_FAILURE
-# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL)
-#endif
-
-#ifndef STATUS_SMARTCARD_CERT_EXPIRED
-# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL)
-#endif
-
-#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD
-# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL)
-#endif
-
-#ifndef STATUS_SMARTCARD_SILENT_CONTEXT
-# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL)
-#endif
-
-#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
-# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L)
-#endif
-
-#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
-# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L)
-#endif
-
-#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
-# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L)
-#endif
-
-#ifndef STATUS_DS_NAME_NOT_UNIQUE
-# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L)
-#endif
-
-#ifndef STATUS_DS_DUPLICATE_ID_FOUND
-# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L)
-#endif
-
-#ifndef STATUS_DS_GROUP_CONVERSION_ERROR
-# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L)
-#endif
-
-#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE
-# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L)
-#endif
-
-#ifndef STATUS_USER2USER_REQUIRED
-# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L)
-#endif
-
-#ifndef STATUS_STACK_BUFFER_OVERRUN
-# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L)
-#endif
-
-#ifndef STATUS_NO_S4U_PROT_SUPPORT
-# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL)
-#endif
-
-#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE
-# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL)
-#endif
-
-#ifndef STATUS_REVOCATION_OFFLINE_KDC
-# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL)
-#endif
-
-#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC
-# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL)
-#endif
-
-#ifndef STATUS_KDC_CERT_EXPIRED
-# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL)
-#endif
-
-#ifndef STATUS_KDC_CERT_REVOKED
-# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL)
-#endif
-
-#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED
-# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L)
-#endif
-
-#ifndef STATUS_HIBERNATION_FAILURE
-# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L)
-#endif
-
-#ifndef STATUS_DELAY_LOAD_FAILED
-# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L)
-#endif
-
-#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED
-# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L)
-#endif
-
-#ifndef STATUS_VDM_DISALLOWED
-# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L)
-#endif
-
-#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD
-# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L)
-#endif
-
-#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
-# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L)
-#endif
-
-#ifndef STATUS_INVALID_CRUNTIME_PARAMETER
-# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L)
-#endif
-
-#ifndef STATUS_NTLM_BLOCKED
-# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L)
-#endif
-
-#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST
-# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L)
-#endif
-
-#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
-# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL)
-#endif
-
-#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
-# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL)
-#endif
-
-#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME
-# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL)
-#endif
-
-#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
-# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL)
-#endif
-
-#ifndef STATUS_ASSERTION_FAILURE
-# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L)
-#endif
-
-#ifndef STATUS_VERIFIER_STOP
-# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L)
-#endif
-
-#ifndef STATUS_CALLBACK_POP_STACK
-# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L)
-#endif
-
-#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED
-# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L)
-#endif
-
-#ifndef STATUS_HIVE_UNLOADED
-# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L)
-#endif
-
-#ifndef STATUS_COMPRESSION_DISABLED
-# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L)
-#endif
-
-#ifndef STATUS_FILE_SYSTEM_LIMITATION
-# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L)
-#endif
-
-#ifndef STATUS_INVALID_IMAGE_HASH
-# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L)
-#endif
-
-#ifndef STATUS_NOT_CAPABLE
-# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L)
-#endif
-
-#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE
-# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL)
-#endif
-
-#ifndef STATUS_IMPLEMENTATION_LIMIT
-# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL)
-#endif
-
-#ifndef STATUS_ELEVATION_REQUIRED
-# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL)
-#endif
-
-#ifndef STATUS_NO_SECURITY_CONTEXT
-# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL)
-#endif
-
-#ifndef STATUS_PKU2U_CERT_FAILURE
-# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL)
-#endif
-
-#ifndef STATUS_BEYOND_VDL
-# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L)
-#endif
-
-#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
-# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L)
-#endif
-
-#ifndef STATUS_PTE_CHANGED
-# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L)
-#endif
-
-#ifndef STATUS_PURGE_FAILED
-# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L)
-#endif
-
-#ifndef STATUS_CRED_REQUIRES_CONFIRMATION
-# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L)
-#endif
-
-#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
-# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L)
-#endif
-
-#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
-# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L)
-#endif
-
-#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
-# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L)
-#endif
-
-#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
-# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L)
-#endif
-
-#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE
-# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L)
-#endif
-
-#ifndef STATUS_INVALID_LABEL
-# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L)
-#endif
-
-#ifndef STATUS_DRIVER_PROCESS_TERMINATED
-# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L)
-#endif
-
-#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE
-# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L)
-#endif
-
-#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND
-# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L)
-#endif
-
-#ifndef STATUS_RESTART_BOOT_APPLICATION
-# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L)
-#endif
-
-#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES
-# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L)
-#endif
-
-#ifndef STATUS_INVALID_TASK_NAME
-# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L)
-#endif
-
-#ifndef STATUS_INVALID_TASK_INDEX
-# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L)
-#endif
-
-#ifndef STATUS_THREAD_ALREADY_IN_TASK
-# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L)
-#endif
-
-#ifndef STATUS_CALLBACK_BYPASS
-# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L)
-#endif
-
-#ifndef STATUS_FAIL_FAST_EXCEPTION
-# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L)
-#endif
-
-#ifndef STATUS_IMAGE_CERT_REVOKED
-# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L)
-#endif
-
-#ifndef STATUS_PORT_CLOSED
-# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L)
-#endif
-
-#ifndef STATUS_MESSAGE_LOST
-# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L)
-#endif
-
-#ifndef STATUS_INVALID_MESSAGE
-# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L)
-#endif
-
-#ifndef STATUS_REQUEST_CANCELED
-# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L)
-#endif
-
-#ifndef STATUS_RECURSIVE_DISPATCH
-# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L)
-#endif
-
-#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED
-# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L)
-#endif
-
-#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE
-# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L)
-#endif
-
-#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED
-# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L)
-#endif
-
-#ifndef STATUS_RESOURCE_IN_USE
-# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L)
-#endif
-
-#ifndef STATUS_HARDWARE_MEMORY_ERROR
-# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L)
-#endif
-
-#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION
-# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL)
-#endif
-
-#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
-# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL)
-#endif
-
-#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
-# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL)
-#endif
-
-#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
-# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL)
-#endif
-
-#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
-# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL)
-#endif
-
-#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION
-# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
-# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L)
-#endif
-
-#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING
-# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L)
-#endif
-
-#ifndef STATUS_PROCESS_IS_PROTECTED
-# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L)
-#endif
-
-#ifndef STATUS_MCA_EXCEPTION
-# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L)
-#endif
-
-#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
-# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L)
-#endif
-
-#ifndef STATUS_SYMLINK_CLASS_DISABLED
-# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L)
-#endif
-
-#ifndef STATUS_INVALID_IDN_NORMALIZATION
-# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L)
-#endif
-
-#ifndef STATUS_NO_UNICODE_TRANSLATION
-# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L)
-#endif
-
-#ifndef STATUS_ALREADY_REGISTERED
-# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L)
-#endif
-
-#ifndef STATUS_CONTEXT_MISMATCH
-# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L)
-#endif
-
-#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
-# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
-# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL)
-#endif
-
-#ifndef STATUS_INVALID_THREAD
-# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION
-# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK
-# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_LANG
-# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK
-# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L)
-#endif
-
-#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
-# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L)
-#endif
-
-#ifndef STATUS_DISK_REPAIR_DISABLED
-# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L)
-#endif
-
-#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
-# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L)
-#endif
-
-#ifndef STATUS_DISK_QUOTA_EXCEEDED
-# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L)
-#endif
-
-#ifndef STATUS_DATA_LOST_REPAIR
-# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L)
-#endif
-
-#ifndef STATUS_CONTENT_BLOCKED
-# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L)
-#endif
-
-#ifndef STATUS_BAD_CLUSTERS
-# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L)
-#endif
-
-#ifndef STATUS_VOLUME_DIRTY
-# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L)
-#endif
-
-#ifndef STATUS_FILE_CHECKED_OUT
-# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L)
-#endif
-
-#ifndef STATUS_CHECKOUT_REQUIRED
-# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L)
-#endif
-
-#ifndef STATUS_BAD_FILE_TYPE
-# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L)
-#endif
-
-#ifndef STATUS_FILE_TOO_LARGE
-# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L)
-#endif
-
-#ifndef STATUS_FORMS_AUTH_REQUIRED
-# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L)
-#endif
-
-#ifndef STATUS_VIRUS_INFECTED
-# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L)
-#endif
-
-#ifndef STATUS_VIRUS_DELETED
-# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L)
-#endif
-
-#ifndef STATUS_BAD_MCFG_TABLE
-# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L)
-#endif
-
-#ifndef STATUS_CANNOT_BREAK_OPLOCK
-# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L)
-#endif
-
-#ifndef STATUS_WOW_ASSERTION
-# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L)
-#endif
-
-#ifndef STATUS_INVALID_SIGNATURE
-# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L)
-#endif
-
-#ifndef STATUS_HMAC_NOT_SUPPORTED
-# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L)
-#endif
-
-#ifndef STATUS_AUTH_TAG_MISMATCH
-# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L)
-#endif
-
-#ifndef STATUS_IPSEC_QUEUE_OVERFLOW
-# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L)
-#endif
-
-#ifndef STATUS_ND_QUEUE_OVERFLOW
-# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L)
-#endif
-
-#ifndef STATUS_HOPLIMIT_EXCEEDED
-# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L)
-#endif
-
-#ifndef STATUS_PROTOCOL_NOT_SUPPORTED
-# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L)
-#endif
-
-#ifndef STATUS_FASTPATH_REJECTED
-# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L)
-#endif
-
-#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
-# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L)
-#endif
-
-#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
-# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L)
-#endif
-
-#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
-# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L)
-#endif
-
-#ifndef STATUS_XML_PARSE_ERROR
-# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L)
-#endif
-
-#ifndef STATUS_XMLDSIG_ERROR
-# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L)
-#endif
-
-#ifndef STATUS_WRONG_COMPARTMENT
-# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L)
-#endif
-
-#ifndef STATUS_AUTHIP_FAILURE
-# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L)
-#endif
-
-#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
-# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L)
-#endif
-
-#ifndef STATUS_DS_OID_NOT_FOUND
-# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L)
-#endif
-
-#ifndef STATUS_HASH_NOT_SUPPORTED
-# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L)
-#endif
-
-#ifndef STATUS_HASH_NOT_PRESENT
-# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
-#endif
-
-/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the DDK
- * got it wrong! */
-#ifdef NTSTATUS_FROM_WIN32
-# undef NTSTATUS_FROM_WIN32
-#endif
-#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \
- ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \
- (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
-
-#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY
-# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100
-#endif
-#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY
-# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200
-#endif
-#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
-# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400
-#endif
-#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK
-# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800
-#endif
-#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
-# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000
-#endif
-#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
-# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
-#endif
-
-#ifndef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE
-# define SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE 0x00000002
-#endif
-
-/* from winternl.h */
-#if !defined(__UNICODE_STRING_DEFINED) && defined(__MINGW32_)
-#define __UNICODE_STRING_DEFINED
-#endif
-typedef struct _UNICODE_STRING {
- USHORT Length;
- USHORT MaximumLength;
- PWSTR Buffer;
-} UNICODE_STRING, *PUNICODE_STRING;
-
-typedef const UNICODE_STRING *PCUNICODE_STRING;
-
-/* from ntifs.h */
-#ifndef DEVICE_TYPE
-# define DEVICE_TYPE DWORD
-#endif
-
-/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
- * not.
- */
-#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
- 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;
- };
- } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
-#endif
-
-typedef struct _IO_STATUS_BLOCK {
- union {
- NTSTATUS Status;
- PVOID Pointer;
- };
- ULONG_PTR Information;
-} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
-
-typedef enum _FILE_INFORMATION_CLASS {
- FileDirectoryInformation = 1,
- FileFullDirectoryInformation,
- FileBothDirectoryInformation,
- FileBasicInformation,
- FileStandardInformation,
- FileInternalInformation,
- FileEaInformation,
- FileAccessInformation,
- FileNameInformation,
- FileRenameInformation,
- FileLinkInformation,
- FileNamesInformation,
- FileDispositionInformation,
- FilePositionInformation,
- FileFullEaInformation,
- FileModeInformation,
- FileAlignmentInformation,
- FileAllInformation,
- FileAllocationInformation,
- FileEndOfFileInformation,
- FileAlternateNameInformation,
- FileStreamInformation,
- FilePipeInformation,
- FilePipeLocalInformation,
- FilePipeRemoteInformation,
- FileMailslotQueryInformation,
- FileMailslotSetInformation,
- FileCompressionInformation,
- FileObjectIdInformation,
- FileCompletionInformation,
- FileMoveClusterInformation,
- FileQuotaInformation,
- FileReparsePointInformation,
- FileNetworkOpenInformation,
- FileAttributeTagInformation,
- FileTrackingInformation,
- FileIdBothDirectoryInformation,
- FileIdFullDirectoryInformation,
- FileValidDataLengthInformation,
- FileShortNameInformation,
- FileIoCompletionNotificationInformation,
- FileIoStatusBlockRangeInformation,
- FileIoPriorityHintInformation,
- FileSfioReserveInformation,
- FileSfioVolumeInformation,
- FileHardLinkInformation,
- FileProcessIdsUsingFileInformation,
- FileNormalizedNameInformation,
- FileNetworkPhysicalNameInformation,
- FileIdGlobalTxDirectoryInformation,
- FileIsRemoteDeviceInformation,
- FileAttributeCacheInformation,
- FileNumaNodeInformation,
- FileStandardLinkInformation,
- FileRemoteProtocolInformation,
- FileMaximumInformation
-} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
-
-typedef struct _FILE_DIRECTORY_INFORMATION {
- ULONG NextEntryOffset;
- ULONG FileIndex;
- LARGE_INTEGER CreationTime;
- LARGE_INTEGER LastAccessTime;
- LARGE_INTEGER LastWriteTime;
- LARGE_INTEGER ChangeTime;
- LARGE_INTEGER EndOfFile;
- LARGE_INTEGER AllocationSize;
- ULONG FileAttributes;
- ULONG FileNameLength;
- WCHAR FileName[1];
-} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
-
-typedef struct _FILE_BOTH_DIR_INFORMATION {
- ULONG NextEntryOffset;
- ULONG FileIndex;
- LARGE_INTEGER CreationTime;
- LARGE_INTEGER LastAccessTime;
- LARGE_INTEGER LastWriteTime;
- LARGE_INTEGER ChangeTime;
- LARGE_INTEGER EndOfFile;
- LARGE_INTEGER AllocationSize;
- ULONG FileAttributes;
- ULONG FileNameLength;
- ULONG EaSize;
- CCHAR ShortNameLength;
- WCHAR ShortName[12];
- WCHAR FileName[1];
-} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
-
-typedef struct _FILE_BASIC_INFORMATION {
- LARGE_INTEGER CreationTime;
- LARGE_INTEGER LastAccessTime;
- LARGE_INTEGER LastWriteTime;
- LARGE_INTEGER ChangeTime;
- DWORD FileAttributes;
-} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
-
-typedef struct _FILE_STANDARD_INFORMATION {
- LARGE_INTEGER AllocationSize;
- LARGE_INTEGER EndOfFile;
- ULONG NumberOfLinks;
- BOOLEAN DeletePending;
- BOOLEAN Directory;
-} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
-
-typedef struct _FILE_INTERNAL_INFORMATION {
- LARGE_INTEGER IndexNumber;
-} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
-
-typedef struct _FILE_EA_INFORMATION {
- ULONG EaSize;
-} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
-
-typedef struct _FILE_ACCESS_INFORMATION {
- ACCESS_MASK AccessFlags;
-} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
-
-typedef struct _FILE_POSITION_INFORMATION {
- LARGE_INTEGER CurrentByteOffset;
-} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
-
-typedef struct _FILE_MODE_INFORMATION {
- ULONG Mode;
-} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
-
-typedef struct _FILE_ALIGNMENT_INFORMATION {
- ULONG AlignmentRequirement;
-} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;
-
-typedef struct _FILE_NAME_INFORMATION {
- ULONG FileNameLength;
- WCHAR FileName[1];
-} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
-
-typedef struct _FILE_END_OF_FILE_INFORMATION {
- LARGE_INTEGER EndOfFile;
-} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
-
-typedef struct _FILE_ALL_INFORMATION {
- FILE_BASIC_INFORMATION BasicInformation;
- FILE_STANDARD_INFORMATION StandardInformation;
- FILE_INTERNAL_INFORMATION InternalInformation;
- FILE_EA_INFORMATION EaInformation;
- FILE_ACCESS_INFORMATION AccessInformation;
- FILE_POSITION_INFORMATION PositionInformation;
- FILE_MODE_INFORMATION ModeInformation;
- FILE_ALIGNMENT_INFORMATION AlignmentInformation;
- FILE_NAME_INFORMATION NameInformation;
-} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
-
-typedef struct _FILE_DISPOSITION_INFORMATION {
- BOOLEAN DeleteFile;
-} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
-
-typedef struct _FILE_PIPE_LOCAL_INFORMATION {
- ULONG NamedPipeType;
- ULONG NamedPipeConfiguration;
- ULONG MaximumInstances;
- ULONG CurrentInstances;
- ULONG InboundQuota;
- ULONG ReadDataAvailable;
- ULONG OutboundQuota;
- ULONG WriteQuotaAvailable;
- ULONG NamedPipeState;
- ULONG NamedPipeEnd;
-} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
-
-#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
-#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
-
-typedef enum _FS_INFORMATION_CLASS {
- FileFsVolumeInformation = 1,
- FileFsLabelInformation = 2,
- FileFsSizeInformation = 3,
- FileFsDeviceInformation = 4,
- FileFsAttributeInformation = 5,
- FileFsControlInformation = 6,
- FileFsFullSizeInformation = 7,
- FileFsObjectIdInformation = 8,
- FileFsDriverPathInformation = 9,
- FileFsVolumeFlagsInformation = 10,
- FileFsSectorSizeInformation = 11
-} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
-
-typedef struct _FILE_FS_VOLUME_INFORMATION {
- LARGE_INTEGER VolumeCreationTime;
- ULONG VolumeSerialNumber;
- ULONG VolumeLabelLength;
- BOOLEAN SupportsObjects;
- WCHAR VolumeLabel[1];
-} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;
-
-typedef struct _FILE_FS_LABEL_INFORMATION {
- ULONG VolumeLabelLength;
- WCHAR VolumeLabel[1];
-} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;
-
-typedef struct _FILE_FS_SIZE_INFORMATION {
- LARGE_INTEGER TotalAllocationUnits;
- LARGE_INTEGER AvailableAllocationUnits;
- ULONG SectorsPerAllocationUnit;
- ULONG BytesPerSector;
-} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
-
-typedef struct _FILE_FS_DEVICE_INFORMATION {
- DEVICE_TYPE DeviceType;
- ULONG Characteristics;
-} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
-
-typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
- ULONG FileSystemAttributes;
- LONG MaximumComponentNameLength;
- ULONG FileSystemNameLength;
- WCHAR FileSystemName[1];
-} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
-
-typedef struct _FILE_FS_CONTROL_INFORMATION {
- LARGE_INTEGER FreeSpaceStartFiltering;
- LARGE_INTEGER FreeSpaceThreshold;
- LARGE_INTEGER FreeSpaceStopFiltering;
- LARGE_INTEGER DefaultQuotaThreshold;
- LARGE_INTEGER DefaultQuotaLimit;
- ULONG FileSystemControlFlags;
-} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
-
-typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
- LARGE_INTEGER TotalAllocationUnits;
- LARGE_INTEGER CallerAvailableAllocationUnits;
- LARGE_INTEGER ActualAvailableAllocationUnits;
- ULONG SectorsPerAllocationUnit;
- ULONG BytesPerSector;
-} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
-
-typedef struct _FILE_FS_OBJECTID_INFORMATION {
- UCHAR ObjectId[16];
- UCHAR ExtendedInfo[48];
-} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;
-
-typedef struct _FILE_FS_DRIVER_PATH_INFORMATION {
- BOOLEAN DriverInPath;
- ULONG DriverNameLength;
- WCHAR DriverName[1];
-} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;
-
-typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION {
- ULONG Flags;
-} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;
-
-typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
- ULONG LogicalBytesPerSector;
- ULONG PhysicalBytesPerSectorForAtomicity;
- ULONG PhysicalBytesPerSectorForPerformance;
- ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
- ULONG Flags;
- ULONG ByteOffsetForSectorAlignment;
- ULONG ByteOffsetForPartitionAlignment;
-} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
-
-typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
- LARGE_INTEGER IdleTime;
- LARGE_INTEGER KernelTime;
- LARGE_INTEGER UserTime;
- LARGE_INTEGER DpcTime;
- LARGE_INTEGER InterruptTime;
- ULONG InterruptCount;
-} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
-
-#ifndef SystemProcessorPerformanceInformation
-# define SystemProcessorPerformanceInformation 8
-#endif
-
-#ifndef FILE_DEVICE_FILE_SYSTEM
-# define FILE_DEVICE_FILE_SYSTEM 0x00000009
-#endif
-
-#ifndef FILE_DEVICE_NETWORK
-# define FILE_DEVICE_NETWORK 0x00000012
-#endif
-
-#ifndef METHOD_BUFFERED
-# define METHOD_BUFFERED 0
-#endif
-
-#ifndef METHOD_IN_DIRECT
-# define METHOD_IN_DIRECT 1
-#endif
-
-#ifndef METHOD_OUT_DIRECT
-# define METHOD_OUT_DIRECT 2
-#endif
-
-#ifndef METHOD_NEITHER
-#define METHOD_NEITHER 3
-#endif
-
-#ifndef METHOD_DIRECT_TO_HARDWARE
-# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
-#endif
-
-#ifndef METHOD_DIRECT_FROM_HARDWARE
-# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
-#endif
-
-#ifndef FILE_ANY_ACCESS
-# define FILE_ANY_ACCESS 0
-#endif
-
-#ifndef FILE_SPECIAL_ACCESS
-# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
-#endif
-
-#ifndef FILE_READ_ACCESS
-# define FILE_READ_ACCESS 0x0001
-#endif
-
-#ifndef FILE_WRITE_ACCESS
-# define FILE_WRITE_ACCESS 0x0002
-#endif
-
-#ifndef CTL_CODE
-# define CTL_CODE(device_type, function, method, access) \
- (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method))
-#endif
-
-#ifndef FSCTL_SET_REPARSE_POINT
-# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
- 41, \
- METHOD_BUFFERED, \
- FILE_SPECIAL_ACCESS)
-#endif
-
-#ifndef FSCTL_GET_REPARSE_POINT
-# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
- 42, \
- METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
-#endif
-
-#ifndef FSCTL_DELETE_REPARSE_POINT
-# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
- 43, \
- METHOD_BUFFERED, \
- FILE_SPECIAL_ACCESS)
-#endif
-
-#ifndef IO_REPARSE_TAG_SYMLINK
-# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
-#endif
-
-typedef VOID (NTAPI *PIO_APC_ROUTINE)
- (PVOID ApcContext,
- PIO_STATUS_BLOCK IoStatusBlock,
- ULONG Reserved);
-
-typedef NTSTATUS (NTAPI *sRtlGetVersion)
- (PRTL_OSVERSIONINFOW lpVersionInformation);
-
-typedef ULONG (NTAPI *sRtlNtStatusToDosError)
- (NTSTATUS Status);
-
-typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
- (HANDLE FileHandle,
- HANDLE Event,
- PIO_APC_ROUTINE ApcRoutine,
- PVOID ApcContext,
- PIO_STATUS_BLOCK IoStatusBlock,
- ULONG IoControlCode,
- PVOID InputBuffer,
- ULONG InputBufferLength,
- PVOID OutputBuffer,
- ULONG OutputBufferLength);
-
-typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
- (HANDLE FileHandle,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FileInformation,
- ULONG Length,
- FILE_INFORMATION_CLASS FileInformationClass);
-
-typedef NTSTATUS (NTAPI *sNtSetInformationFile)
- (HANDLE FileHandle,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FileInformation,
- ULONG Length,
- FILE_INFORMATION_CLASS FileInformationClass);
-
-typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile)
- (HANDLE FileHandle,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FsInformation,
- ULONG Length,
- FS_INFORMATION_CLASS FsInformationClass);
-
-typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
- (UINT SystemInformationClass,
- PVOID SystemInformation,
- ULONG SystemInformationLength,
- PULONG ReturnLength);
-
-typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
- (HANDLE FileHandle,
- HANDLE Event,
- PIO_APC_ROUTINE ApcRoutine,
- PVOID ApcContext,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FileInformation,
- ULONG Length,
- FILE_INFORMATION_CLASS FileInformationClass,
- BOOLEAN ReturnSingleEntry,
- PUNICODE_STRING FileName,
- BOOLEAN RestartScan
- );
-
-/*
- * Kernel32 headers
- */
-#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
-# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
-#endif
-
-#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE
-# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
-#endif
-
-#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
-# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
-#endif
-
-#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
- typedef struct _OVERLAPPED_ENTRY {
- ULONG_PTR lpCompletionKey;
- LPOVERLAPPED lpOverlapped;
- ULONG_PTR Internal;
- DWORD dwNumberOfBytesTransferred;
- } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
-#endif
-
-/* from wincon.h */
-#ifndef ENABLE_INSERT_MODE
-# define ENABLE_INSERT_MODE 0x20
-#endif
-
-#ifndef ENABLE_QUICK_EDIT_MODE
-# define ENABLE_QUICK_EDIT_MODE 0x40
-#endif
-
-#ifndef ENABLE_EXTENDED_FLAGS
-# define ENABLE_EXTENDED_FLAGS 0x80
-#endif
-
-/* from winerror.h */
-#ifndef ERROR_ELEVATION_REQUIRED
-# define ERROR_ELEVATION_REQUIRED 740
-#endif
-
-#ifndef ERROR_SYMLINK_NOT_SUPPORTED
-# define ERROR_SYMLINK_NOT_SUPPORTED 1464
-#endif
-
-#ifndef ERROR_MUI_FILE_NOT_FOUND
-# define ERROR_MUI_FILE_NOT_FOUND 15100
-#endif
-
-#ifndef ERROR_MUI_INVALID_FILE
-# define ERROR_MUI_INVALID_FILE 15101
-#endif
-
-#ifndef ERROR_MUI_INVALID_RC_CONFIG
-# define ERROR_MUI_INVALID_RC_CONFIG 15102
-#endif
-
-#ifndef ERROR_MUI_INVALID_LOCALE_NAME
-# define ERROR_MUI_INVALID_LOCALE_NAME 15103
-#endif
-
-#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
-# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
-#endif
-
-#ifndef ERROR_MUI_FILE_NOT_LOADED
-# define ERROR_MUI_FILE_NOT_LOADED 15105
-#endif
-
-typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
- (HANDLE CompletionPort,
- LPOVERLAPPED_ENTRY lpCompletionPortEntries,
- ULONG ulCount,
- PULONG ulNumEntriesRemoved,
- DWORD dwMilliseconds,
- BOOL fAlertable);
-
-/* from powerbase.h */
-#ifndef DEVICE_NOTIFY_CALLBACK
-# define DEVICE_NOTIFY_CALLBACK 2
-#endif
-
-#ifndef PBT_APMRESUMEAUTOMATIC
-# define PBT_APMRESUMEAUTOMATIC 18
-#endif
-
-#ifndef PBT_APMRESUMESUSPEND
-# define PBT_APMRESUMESUSPEND 7
-#endif
-
-typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
- PVOID Context,
- ULONG Type,
- PVOID Setting
-);
-typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
-
-typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
- _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
- PVOID Context;
-} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
-
-typedef PVOID _HPOWERNOTIFY;
-typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
-
-typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
- (DWORD Flags,
- HANDLE Recipient,
- _PHPOWERNOTIFY RegistrationHandle);
-
-/* from Winuser.h */
-typedef VOID (CALLBACK* WINEVENTPROC)
- (HWINEVENTHOOK hWinEventHook,
- DWORD event,
- HWND hwnd,
- LONG idObject,
- LONG idChild,
- DWORD idEventThread,
- DWORD dwmsEventTime);
-
-typedef HWINEVENTHOOK (WINAPI *sSetWinEventHook)
- (UINT eventMin,
- UINT eventMax,
- HMODULE hmodWinEventProc,
- WINEVENTPROC lpfnWinEventProc,
- DWORD idProcess,
- DWORD idThread,
- UINT dwflags);
-
-
-/* Ntdll function pointers */
-extern sRtlGetVersion pRtlGetVersion;
-extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
-extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
-extern sNtQueryInformationFile pNtQueryInformationFile;
-extern sNtSetInformationFile pNtSetInformationFile;
-extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
-extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
-extern sNtQuerySystemInformation pNtQuerySystemInformation;
-
-/* Kernel32 function pointers */
-extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
-
-/* Powrprof.dll function pointer */
-extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
-
-/* User32.dll function pointer */
-extern sSetWinEventHook pSetWinEventHook;
-
-#endif /* UV_WIN_WINAPI_H_ */
diff --git a/wpiutil/src/main/native/libuv/src/win/winsock.cpp b/wpiutil/src/main/native/libuv/src/win/winsock.cpp
deleted file mode 100644
index 668e3b6..0000000
--- a/wpiutil/src/main/native/libuv/src/win/winsock.cpp
+++ /dev/null
@@ -1,596 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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 <assert.h>
-#include <stdlib.h>
-
-#include "uv.h"
-#include "internal.h"
-
-
-#pragma comment(lib, "Ws2_32.lib")
-
-/* Whether there are any non-IFS LSPs stacked on TCP */
-int uv_tcp_non_ifs_lsp_ipv4;
-int uv_tcp_non_ifs_lsp_ipv6;
-
-/* Ip address used to bind to any port at any interface */
-struct sockaddr_in uv_addr_ip4_any_;
-struct sockaddr_in6 uv_addr_ip6_any_;
-
-
-/*
- * Retrieves the pointer to a winsock extension function.
- */
-static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
- void **target) {
- int result;
- DWORD bytes;
-
- result = WSAIoctl(socket,
- SIO_GET_EXTENSION_FUNCTION_POINTER,
- &guid,
- sizeof(guid),
- (void*)target,
- sizeof(*target),
- &bytes,
- NULL,
- NULL);
-
- if (result == SOCKET_ERROR) {
- *target = NULL;
- return FALSE;
- } else {
- return TRUE;
- }
-}
-
-
-BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
- const GUID wsaid_acceptex = WSAID_ACCEPTEX;
- return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
-}
-
-
-BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
- const GUID wsaid_connectex = WSAID_CONNECTEX;
- return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
-}
-
-
-static int error_means_no_support(DWORD error) {
- return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
- error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
-}
-
-
-void uv_winsock_init(void) {
- WSADATA wsa_data;
- int errorno;
- SOCKET dummy;
- WSAPROTOCOL_INFOW protocol_info;
- int opt_len;
-
- /* Set implicit binding address used by connectEx */
- if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
- abort();
- }
-
- if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
- abort();
- }
-
- /* Skip initialization in safe mode without network support */
- if (1 == GetSystemMetrics(SM_CLEANBOOT)) return;
-
- /* Initialize winsock */
- errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
- if (errorno != 0) {
- uv_fatal_error(errorno, "WSAStartup");
- }
-
- /* Detect non-IFS LSPs */
- dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
-
- if (dummy != INVALID_SOCKET) {
- opt_len = (int) sizeof protocol_info;
- if (getsockopt(dummy,
- SOL_SOCKET,
- SO_PROTOCOL_INFOW,
- (char*) &protocol_info,
- &opt_len) == SOCKET_ERROR)
- uv_fatal_error(WSAGetLastError(), "getsockopt");
-
- if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
- uv_tcp_non_ifs_lsp_ipv4 = 1;
-
- if (closesocket(dummy) == SOCKET_ERROR)
- uv_fatal_error(WSAGetLastError(), "closesocket");
-
- } else if (!error_means_no_support(WSAGetLastError())) {
- /* Any error other than "socket type not supported" is fatal. */
- uv_fatal_error(WSAGetLastError(), "socket");
- }
-
- /* Detect IPV6 support and non-IFS LSPs */
- dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
-
- if (dummy != INVALID_SOCKET) {
- opt_len = (int) sizeof protocol_info;
- if (getsockopt(dummy,
- SOL_SOCKET,
- SO_PROTOCOL_INFOW,
- (char*) &protocol_info,
- &opt_len) == SOCKET_ERROR)
- uv_fatal_error(WSAGetLastError(), "getsockopt");
-
- if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
- uv_tcp_non_ifs_lsp_ipv6 = 1;
-
- if (closesocket(dummy) == SOCKET_ERROR)
- uv_fatal_error(WSAGetLastError(), "closesocket");
-
- } else if (!error_means_no_support(WSAGetLastError())) {
- /* Any error other than "socket type not supported" is fatal. */
- uv_fatal_error(WSAGetLastError(), "socket");
- }
-}
-
-
-int uv_ntstatus_to_winsock_error(NTSTATUS status) {
- switch (status) {
- case STATUS_SUCCESS:
- return ERROR_SUCCESS;
-
- case STATUS_PENDING:
- return ERROR_IO_PENDING;
-
- case STATUS_INVALID_HANDLE:
- case STATUS_OBJECT_TYPE_MISMATCH:
- return WSAENOTSOCK;
-
- case STATUS_INSUFFICIENT_RESOURCES:
- case STATUS_PAGEFILE_QUOTA:
- case STATUS_COMMITMENT_LIMIT:
- case STATUS_WORKING_SET_QUOTA:
- case STATUS_NO_MEMORY:
- case STATUS_QUOTA_EXCEEDED:
- case STATUS_TOO_MANY_PAGING_FILES:
- case STATUS_REMOTE_RESOURCES:
- return WSAENOBUFS;
-
- case STATUS_TOO_MANY_ADDRESSES:
- case STATUS_SHARING_VIOLATION:
- case STATUS_ADDRESS_ALREADY_EXISTS:
- return WSAEADDRINUSE;
-
- case STATUS_LINK_TIMEOUT:
- case STATUS_IO_TIMEOUT:
- case STATUS_TIMEOUT:
- return WSAETIMEDOUT;
-
- case STATUS_GRACEFUL_DISCONNECT:
- return WSAEDISCON;
-
- case STATUS_REMOTE_DISCONNECT:
- case STATUS_CONNECTION_RESET:
- case STATUS_LINK_FAILED:
- case STATUS_CONNECTION_DISCONNECTED:
- case STATUS_PORT_UNREACHABLE:
- case STATUS_HOPLIMIT_EXCEEDED:
- return WSAECONNRESET;
-
- case STATUS_LOCAL_DISCONNECT:
- case STATUS_TRANSACTION_ABORTED:
- case STATUS_CONNECTION_ABORTED:
- return WSAECONNABORTED;
-
- case STATUS_BAD_NETWORK_PATH:
- case STATUS_NETWORK_UNREACHABLE:
- case STATUS_PROTOCOL_UNREACHABLE:
- return WSAENETUNREACH;
-
- case STATUS_HOST_UNREACHABLE:
- return WSAEHOSTUNREACH;
-
- case STATUS_CANCELLED:
- case STATUS_REQUEST_ABORTED:
- return WSAEINTR;
-
- case STATUS_BUFFER_OVERFLOW:
- case STATUS_INVALID_BUFFER_SIZE:
- return WSAEMSGSIZE;
-
- case STATUS_BUFFER_TOO_SMALL:
- case STATUS_ACCESS_VIOLATION:
- return WSAEFAULT;
-
- case STATUS_DEVICE_NOT_READY:
- case STATUS_REQUEST_NOT_ACCEPTED:
- return WSAEWOULDBLOCK;
-
- case STATUS_INVALID_NETWORK_RESPONSE:
- case STATUS_NETWORK_BUSY:
- case STATUS_NO_SUCH_DEVICE:
- case STATUS_NO_SUCH_FILE:
- case STATUS_OBJECT_PATH_NOT_FOUND:
- case STATUS_OBJECT_NAME_NOT_FOUND:
- case STATUS_UNEXPECTED_NETWORK_ERROR:
- return WSAENETDOWN;
-
- case STATUS_INVALID_CONNECTION:
- return WSAENOTCONN;
-
- case STATUS_REMOTE_NOT_LISTENING:
- case STATUS_CONNECTION_REFUSED:
- return WSAECONNREFUSED;
-
- case STATUS_PIPE_DISCONNECTED:
- return WSAESHUTDOWN;
-
- case STATUS_CONFLICTING_ADDRESSES:
- case STATUS_INVALID_ADDRESS:
- case STATUS_INVALID_ADDRESS_COMPONENT:
- return WSAEADDRNOTAVAIL;
-
- case STATUS_NOT_SUPPORTED:
- case STATUS_NOT_IMPLEMENTED:
- return WSAEOPNOTSUPP;
-
- case STATUS_ACCESS_DENIED:
- return WSAEACCES;
-
- default:
- if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
- (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
- /* It's a windows error that has been previously mapped to an ntstatus
- * code. */
- return (DWORD) (status & 0xffff);
- } else {
- /* The default fallback for unmappable ntstatus codes. */
- return WSAEINVAL;
- }
- }
-}
-
-
-/*
- * This function provides a workaround for a bug in the winsock implementation
- * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
- * used to avoid IOCP notifications of completed reads, WSARecv does not
- * reliably indicate whether we can expect a completion package to be posted
- * when the receive buffer is smaller than the received datagram.
- *
- * However it is desirable to use SetFileCompletionNotificationModes because
- * it yields a massive performance increase.
- *
- * This function provides a workaround for that bug, but it only works for the
- * specific case that we need it for. E.g. it assumes that the "avoid iocp"
- * bit has been set, and supports only overlapped operation. It also requires
- * the user to use the default msafd driver, doesn't work when other LSPs are
- * stacked on top of it.
- */
-int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
- DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
- NTSTATUS status;
- void* apc_context;
- IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
- AFD_RECV_INFO info;
- DWORD error;
-
- if (overlapped == NULL || completion_routine != NULL) {
- WSASetLastError(WSAEINVAL);
- return SOCKET_ERROR;
- }
-
- info.BufferArray = buffers;
- info.BufferCount = buffer_count;
- info.AfdFlags = AFD_OVERLAPPED;
- info.TdiFlags = TDI_RECEIVE_NORMAL;
-
- if (*flags & MSG_PEEK) {
- info.TdiFlags |= TDI_RECEIVE_PEEK;
- }
-
- if (*flags & MSG_PARTIAL) {
- info.TdiFlags |= TDI_RECEIVE_PARTIAL;
- }
-
- if (!((intptr_t) overlapped->hEvent & 1)) {
- apc_context = (void*) overlapped;
- } else {
- apc_context = NULL;
- }
-
- iosb->Status = STATUS_PENDING;
- iosb->Pointer = 0;
-
- status = pNtDeviceIoControlFile((HANDLE) socket,
- overlapped->hEvent,
- NULL,
- apc_context,
- iosb,
- IOCTL_AFD_RECEIVE,
- &info,
- sizeof(info),
- NULL,
- 0);
-
- *flags = 0;
- *bytes = (DWORD) iosb->Information;
-
- switch (status) {
- case STATUS_SUCCESS:
- error = ERROR_SUCCESS;
- break;
-
- case STATUS_PENDING:
- error = WSA_IO_PENDING;
- break;
-
- case STATUS_BUFFER_OVERFLOW:
- error = WSAEMSGSIZE;
- break;
-
- case STATUS_RECEIVE_EXPEDITED:
- error = ERROR_SUCCESS;
- *flags = MSG_OOB;
- break;
-
- case STATUS_RECEIVE_PARTIAL_EXPEDITED:
- error = ERROR_SUCCESS;
- *flags = MSG_PARTIAL | MSG_OOB;
- break;
-
- case STATUS_RECEIVE_PARTIAL:
- error = ERROR_SUCCESS;
- *flags = MSG_PARTIAL;
- break;
-
- default:
- error = uv_ntstatus_to_winsock_error(status);
- break;
- }
-
- WSASetLastError(error);
-
- if (error == ERROR_SUCCESS) {
- return 0;
- } else {
- return SOCKET_ERROR;
- }
-}
-
-
-/* See description of uv_wsarecv_workaround. */
-int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
- DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
- int* addr_len, WSAOVERLAPPED *overlapped,
- LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
- NTSTATUS status;
- void* apc_context;
- IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
- AFD_RECV_DATAGRAM_INFO info;
- DWORD error;
-
- if (overlapped == NULL || addr == NULL || addr_len == NULL ||
- completion_routine != NULL) {
- WSASetLastError(WSAEINVAL);
- return SOCKET_ERROR;
- }
-
- info.BufferArray = buffers;
- info.BufferCount = buffer_count;
- info.AfdFlags = AFD_OVERLAPPED;
- info.TdiFlags = TDI_RECEIVE_NORMAL;
- info.Address = addr;
- info.AddressLength = addr_len;
-
- if (*flags & MSG_PEEK) {
- info.TdiFlags |= TDI_RECEIVE_PEEK;
- }
-
- if (*flags & MSG_PARTIAL) {
- info.TdiFlags |= TDI_RECEIVE_PARTIAL;
- }
-
- if (!((intptr_t) overlapped->hEvent & 1)) {
- apc_context = (void*) overlapped;
- } else {
- apc_context = NULL;
- }
-
- iosb->Status = STATUS_PENDING;
- iosb->Pointer = 0;
-
- status = pNtDeviceIoControlFile((HANDLE) socket,
- overlapped->hEvent,
- NULL,
- apc_context,
- iosb,
- IOCTL_AFD_RECEIVE_DATAGRAM,
- &info,
- sizeof(info),
- NULL,
- 0);
-
- *flags = 0;
- *bytes = (DWORD) iosb->Information;
-
- switch (status) {
- case STATUS_SUCCESS:
- error = ERROR_SUCCESS;
- break;
-
- case STATUS_PENDING:
- error = WSA_IO_PENDING;
- break;
-
- case STATUS_BUFFER_OVERFLOW:
- error = WSAEMSGSIZE;
- break;
-
- case STATUS_RECEIVE_EXPEDITED:
- error = ERROR_SUCCESS;
- *flags = MSG_OOB;
- break;
-
- case STATUS_RECEIVE_PARTIAL_EXPEDITED:
- error = ERROR_SUCCESS;
- *flags = MSG_PARTIAL | MSG_OOB;
- break;
-
- case STATUS_RECEIVE_PARTIAL:
- error = ERROR_SUCCESS;
- *flags = MSG_PARTIAL;
- break;
-
- default:
- error = uv_ntstatus_to_winsock_error(status);
- break;
- }
-
- WSASetLastError(error);
-
- if (error == ERROR_SUCCESS) {
- return 0;
- } else {
- return SOCKET_ERROR;
- }
-}
-
-
-int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
- AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
- IO_STATUS_BLOCK iosb;
- IO_STATUS_BLOCK* iosb_ptr;
- HANDLE event = NULL;
- void* apc_context;
- NTSTATUS status;
- DWORD error;
-
- if (overlapped != NULL) {
- /* Overlapped operation. */
- iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
- event = overlapped->hEvent;
-
- /* Do not report iocp completion if hEvent is tagged. */
- if ((uintptr_t) event & 1) {
- event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
- apc_context = NULL;
- } else {
- apc_context = overlapped;
- }
-
- } else {
- /* Blocking operation. */
- iosb_ptr = &iosb;
- event = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (event == NULL) {
- return SOCKET_ERROR;
- }
- apc_context = NULL;
- }
-
- iosb_ptr->Status = STATUS_PENDING;
- status = pNtDeviceIoControlFile((HANDLE) socket,
- event,
- NULL,
- apc_context,
- iosb_ptr,
- IOCTL_AFD_POLL,
- info_in,
- sizeof *info_in,
- info_out,
- sizeof *info_out);
-
- if (overlapped == NULL) {
- /* If this is a blocking operation, wait for the event to become signaled,
- * and then grab the real status from the io status block. */
- if (status == STATUS_PENDING) {
- DWORD r = WaitForSingleObject(event, INFINITE);
-
- if (r == WAIT_FAILED) {
- DWORD saved_error = GetLastError();
- CloseHandle(event);
- WSASetLastError(saved_error);
- return SOCKET_ERROR;
- }
-
- status = iosb.Status;
- }
-
- CloseHandle(event);
- }
-
- switch (status) {
- case STATUS_SUCCESS:
- error = ERROR_SUCCESS;
- break;
-
- case STATUS_PENDING:
- error = WSA_IO_PENDING;
- break;
-
- default:
- error = uv_ntstatus_to_winsock_error(status);
- break;
- }
-
- WSASetLastError(error);
-
- if (error == ERROR_SUCCESS) {
- return 0;
- } else {
- return SOCKET_ERROR;
- }
-}
-
-int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
- struct sockaddr_storage* storage) {
- struct sockaddr_in* dest4;
- struct sockaddr_in6* dest6;
-
- if (addr == NULL)
- return UV_EINVAL;
-
- switch (addr->sa_family) {
- case AF_INET:
- dest4 = (struct sockaddr_in*) storage;
- memcpy(dest4, addr, sizeof(*dest4));
- if (dest4->sin_addr.s_addr == 0)
- dest4->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- return 0;
- case AF_INET6:
- dest6 = (struct sockaddr_in6*) storage;
- memcpy(dest6, addr, sizeof(*dest6));
- if (memcmp(&dest6->sin6_addr,
- &uv_addr_ip6_any_.sin6_addr,
- sizeof(uv_addr_ip6_any_.sin6_addr)) == 0) {
- struct in6_addr init_sin6_addr = IN6ADDR_LOOPBACK_INIT;
- dest6->sin6_addr = init_sin6_addr;
- }
- return 0;
- default:
- return UV_EINVAL;
- }
-}
diff --git a/wpiutil/src/main/native/libuv/src/win/winsock.h b/wpiutil/src/main/native/libuv/src/win/winsock.h
deleted file mode 100644
index 7ecb755..0000000
--- a/wpiutil/src/main/native/libuv/src/win/winsock.h
+++ /dev/null
@@ -1,193 +0,0 @@
-/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
- *
- * 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.
- */
-
-#ifndef UV_WIN_WINSOCK_H_
-#define UV_WIN_WINSOCK_H_
-
-#include <winsock2.h>
-#include <iptypes.h>
-#include <mswsock.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-
-#include "winapi.h"
-
-
-/*
- * MinGW is missing these too
- */
-#ifndef SO_UPDATE_CONNECT_CONTEXT
-# define SO_UPDATE_CONNECT_CONTEXT 0x7010
-#endif
-
-#ifndef TCP_KEEPALIVE
-# define TCP_KEEPALIVE 3
-#endif
-
-#ifndef IPV6_V6ONLY
-# define IPV6_V6ONLY 27
-#endif
-
-#ifndef IPV6_HOPLIMIT
-# define IPV6_HOPLIMIT 21
-#endif
-
-#ifndef SIO_BASE_HANDLE
-# define SIO_BASE_HANDLE 0x48000022
-#endif
-
-/*
- * TDI defines that are only in the DDK.
- * We only need receive flags so far.
- */
-#ifndef TDI_RECEIVE_NORMAL
- #define TDI_RECEIVE_BROADCAST 0x00000004
- #define TDI_RECEIVE_MULTICAST 0x00000008
- #define TDI_RECEIVE_PARTIAL 0x00000010
- #define TDI_RECEIVE_NORMAL 0x00000020
- #define TDI_RECEIVE_EXPEDITED 0x00000040
- #define TDI_RECEIVE_PEEK 0x00000080
- #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
- #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
- #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
- #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
- #define TDI_RECEIVE_CONTROL_INFO 0x00001000
- #define TDI_RECEIVE_FORCE_INDICATION 0x00002000
- #define TDI_RECEIVE_NO_PUSH 0x00004000
-#endif
-
-/*
- * The "Auxiliary Function Driver" is the windows kernel-mode driver that does
- * TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
- * Having these definitions allows us to bypass winsock and make an AFD kernel
- * call directly, avoiding a bug in winsock's recvfrom implementation.
- */
-
-#define AFD_NO_FAST_IO 0x00000001
-#define AFD_OVERLAPPED 0x00000002
-#define AFD_IMMEDIATE 0x00000004
-
-#define AFD_POLL_RECEIVE_BIT 0
-#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
-#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
-#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
-#define AFD_POLL_SEND_BIT 2
-#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
-#define AFD_POLL_DISCONNECT_BIT 3
-#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
-#define AFD_POLL_ABORT_BIT 4
-#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
-#define AFD_POLL_LOCAL_CLOSE_BIT 5
-#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
-#define AFD_POLL_CONNECT_BIT 6
-#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
-#define AFD_POLL_ACCEPT_BIT 7
-#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
-#define AFD_POLL_CONNECT_FAIL_BIT 8
-#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
-#define AFD_POLL_QOS_BIT 9
-#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
-#define AFD_POLL_GROUP_QOS_BIT 10
-#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
-
-#define AFD_NUM_POLL_EVENTS 11
-#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
-
-typedef struct _AFD_RECV_DATAGRAM_INFO {
- LPWSABUF BufferArray;
- ULONG BufferCount;
- ULONG AfdFlags;
- ULONG TdiFlags;
- struct sockaddr* Address;
- int* AddressLength;
-} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
-
-typedef struct _AFD_RECV_INFO {
- LPWSABUF BufferArray;
- ULONG BufferCount;
- ULONG AfdFlags;
- ULONG TdiFlags;
-} AFD_RECV_INFO, *PAFD_RECV_INFO;
-
-
-#define _AFD_CONTROL_CODE(operation, method) \
- ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
-
-#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
-
-#define AFD_RECEIVE 5
-#define AFD_RECEIVE_DATAGRAM 6
-#define AFD_POLL 9
-
-#define IOCTL_AFD_RECEIVE \
- _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
-
-#define IOCTL_AFD_RECEIVE_DATAGRAM \
- _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
-
-#define IOCTL_AFD_POLL \
- _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
-
-#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
-typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
- /* FIXME: __C89_NAMELESS was removed */
- /* __C89_NAMELESS */ union {
- ULONGLONG Alignment;
- /* __C89_NAMELESS */ struct {
- ULONG Length;
- DWORD Flags;
- };
- };
- struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
- SOCKET_ADDRESS Address;
- IP_PREFIX_ORIGIN PrefixOrigin;
- IP_SUFFIX_ORIGIN SuffixOrigin;
- IP_DAD_STATE DadState;
- ULONG ValidLifetime;
- ULONG PreferredLifetime;
- ULONG LeaseLifetime;
-} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
-
-typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
- union {
- ULONGLONG Alignment;
- struct {
- ULONG Length;
- DWORD Flags;
- };
- };
- struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
- SOCKET_ADDRESS Address;
- IP_PREFIX_ORIGIN PrefixOrigin;
- IP_SUFFIX_ORIGIN SuffixOrigin;
- IP_DAD_STATE DadState;
- ULONG ValidLifetime;
- ULONG PreferredLifetime;
- ULONG LeaseLifetime;
- UINT8 OnLinkPrefixLength;
-} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
-
-#endif
-
-int uv__convert_to_localhost_if_unspecified(const struct sockaddr* addr,
- struct sockaddr_storage* storage);
-
-#endif /* UV_WIN_WINSOCK_H_ */
diff --git a/wpiutil/src/main/native/linux/AvahiClient.cpp b/wpiutil/src/main/native/linux/AvahiClient.cpp
deleted file mode 100644
index 6a17ea0..0000000
--- a/wpiutil/src/main/native/linux/AvahiClient.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// 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 "AvahiClient.h"
-
-#include <wpi/mutex.h>
-
-#include <thread>
-
-#include "dlfcn.h"
-
-using namespace wpi;
-
-#define AvahiFunctionLoad(snake_name) \
- do { \
- snake_name = \
- reinterpret_cast<snake_name##_func>(dlsym(lib, "avahi_" #snake_name)); \
- if (!snake_name) { \
- return; \
- } \
- } while (false)
-
-AvahiFunctionTable::AvahiFunctionTable() {
- void* lib = dlopen("libavahi-common.so.3", RTLD_LAZY);
-
- valid = false;
-
- if (lib == nullptr) {
- return;
- }
-
- AvahiFunctionLoad(threaded_poll_new);
- AvahiFunctionLoad(threaded_poll_free);
- AvahiFunctionLoad(threaded_poll_get);
- AvahiFunctionLoad(threaded_poll_start);
- AvahiFunctionLoad(threaded_poll_stop);
- AvahiFunctionLoad(threaded_poll_lock);
- AvahiFunctionLoad(threaded_poll_unlock);
- AvahiFunctionLoad(string_list_new_from_array);
- AvahiFunctionLoad(string_list_free);
- AvahiFunctionLoad(unescape_label);
- AvahiFunctionLoad(alternative_service_name);
- AvahiFunctionLoad(free);
-
- lib = dlopen("libavahi-client.so.3", RTLD_LAZY);
-
- if (lib == nullptr) {
- return;
- }
-
- AvahiFunctionLoad(client_new);
- AvahiFunctionLoad(client_free);
- AvahiFunctionLoad(service_browser_new);
- AvahiFunctionLoad(service_browser_get_client);
- AvahiFunctionLoad(service_browser_free);
- AvahiFunctionLoad(service_resolver_new);
- AvahiFunctionLoad(service_resolver_free);
- AvahiFunctionLoad(entry_group_new);
- AvahiFunctionLoad(entry_group_free);
- AvahiFunctionLoad(entry_group_add_service_strlst);
- AvahiFunctionLoad(entry_group_reset);
- AvahiFunctionLoad(entry_group_is_empty);
- AvahiFunctionLoad(entry_group_commit);
- AvahiFunctionLoad(entry_group_get_client);
-
- valid = true;
-}
-
-AvahiFunctionTable& AvahiFunctionTable::Get() {
- static AvahiFunctionTable table;
- return table;
-}
-
-static wpi::mutex ThreadLoopLock;
-static std::weak_ptr<AvahiThread> ThreadLoop;
-
-std::shared_ptr<AvahiThread> AvahiThread::Get() {
- std::scoped_lock lock{ThreadLoopLock};
- auto locked = ThreadLoop.lock();
- if (!locked) {
- locked = std::make_unique<AvahiThread>(private_init{});
- ThreadLoop = locked;
- }
- return locked;
-}
-
-AvahiThread::AvahiThread(const private_init&) {
- if (!table.IsValid()) {
- return;
- }
-
- threadedPoll = table.threaded_poll_new();
- table.threaded_poll_start(threadedPoll);
-}
-
-AvahiThread::~AvahiThread() noexcept {
- if (!table.IsValid()) {
- return;
- }
-
- if (threadedPoll) {
- table.threaded_poll_stop(threadedPoll);
- table.threaded_poll_free(threadedPoll);
- }
-}
-
-void AvahiThread::lock() {
- table.threaded_poll_lock(threadedPoll);
-}
-
-void AvahiThread::unlock() {
- table.threaded_poll_unlock(threadedPoll);
-}
-
-const AvahiPoll* AvahiThread::GetPoll() const {
- return table.threaded_poll_get(threadedPoll);
-}
diff --git a/wpiutil/src/main/native/linux/AvahiClient.h b/wpiutil/src/main/native/linux/AvahiClient.h
deleted file mode 100644
index ca679bb..0000000
--- a/wpiutil/src/main/native/linux/AvahiClient.h
+++ /dev/null
@@ -1,316 +0,0 @@
-// 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 <memory>
-
-/***
- This file is part of avahi.
- avahi is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as
- published by the Free Software Foundation; either version 2.1 of the
- License, or (at your option) any later version.
- avahi is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
- Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with avahi; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- USA.
-***/
-
-typedef struct AvahiPoll AvahiPoll;
-
-typedef enum {
- AVAHI_SERVER_INVALID,
- AVAHI_SERVER_REGISTERING,
- AVAHI_SERVER_RUNNING,
- AVAHI_SERVER_COLLISION,
- AVAHI_SERVER_FAILURE
-} AvahiServerState;
-
-typedef struct AvahiClient AvahiClient;
-
-typedef enum {
- AVAHI_CLIENT_S_REGISTERING = AVAHI_SERVER_REGISTERING,
- AVAHI_CLIENT_S_RUNNING = AVAHI_SERVER_RUNNING,
- AVAHI_CLIENT_S_COLLISION = AVAHI_SERVER_COLLISION,
- AVAHI_CLIENT_FAILURE = 100,
- AVAHI_CLIENT_CONNECTING = 101
-} AvahiClientState;
-
-typedef enum {
- AVAHI_CLIENT_IGNORE_USER_CONFIG = 1,
- AVAHI_CLIENT_NO_FAIL = 2
-} AvahiClientFlags;
-
-typedef void (*AvahiClientCallback)(AvahiClient* s, AvahiClientState state,
- void* userdata);
-
-typedef struct AvahiServiceBrowser AvahiServiceBrowser;
-
-typedef int AvahiProtocol;
-
-typedef int AvahiIfIndex;
-
-typedef enum {
- AVAHI_BROWSER_NEW,
- AVAHI_BROWSER_REMOVE,
- AVAHI_BROWSER_CACHE_EXHAUSTED,
- AVAHI_BROWSER_ALL_FOR_NOW,
- AVAHI_BROWSER_FAILURE
-} AvahiBrowserEvent;
-
-typedef enum {
- AVAHI_LOOKUP_RESULT_CACHED = 1,
- AVAHI_LOOKUP_RESULT_WIDE_AREA = 2,
- AVAHI_LOOKUP_RESULT_MULTICAST = 4,
- AVAHI_LOOKUP_RESULT_LOCAL = 8,
- AVAHI_LOOKUP_RESULT_OUR_OWN = 16,
- AVAHI_LOOKUP_RESULT_STATIC = 32
-} AvahiLookupResultFlags;
-
-typedef void (*AvahiServiceBrowserCallback)(
- AvahiServiceBrowser* b, AvahiIfIndex interface, AvahiProtocol protocol,
- AvahiBrowserEvent event, const char* name, const char* type,
- const char* domain, AvahiLookupResultFlags flags, void* userdata);
-
-typedef enum {
- AVAHI_LOOKUP_USE_WIDE_AREA = 1,
- AVAHI_LOOKUP_USE_MULTICAST = 2,
-
- AVAHI_LOOKUP_NO_TXT = 4,
- AVAHI_LOOKUP_NO_ADDRESS = 8
-} AvahiLookupFlags;
-
-typedef struct AvahiServiceResolver AvahiServiceResolver;
-
-typedef enum {
- AVAHI_RESOLVER_FOUND,
- AVAHI_RESOLVER_FAILURE
-} AvahiResolverEvent;
-
-typedef struct AvahiIPv4Address {
- uint32_t address;
-} AvahiIPv4Address;
-
-typedef struct AvahiIPv6Address {
- uint8_t address[16];
-} AvahiIPv6Address;
-
-typedef struct AvahiAddress {
- AvahiProtocol proto;
-
- union {
- AvahiIPv6Address ipv6;
- AvahiIPv4Address ipv4;
- uint8_t data[1];
- } data;
-} AvahiAddress;
-
-typedef struct AvahiStringList {
- struct AvahiStringList* next;
- size_t size;
- uint8_t text[1];
-} AvahiStringList;
-
-typedef void (*AvahiServiceResolverCallback)(
- AvahiServiceResolver* r, AvahiIfIndex interface, AvahiProtocol protocol,
- AvahiResolverEvent event, const char* name, const char* type,
- const char* domain, const char* host_name, const AvahiAddress* a,
- uint16_t port, AvahiStringList* txt, AvahiLookupResultFlags flags,
- void* userdata);
-
-typedef struct AvahiThreadedPoll AvahiThreadedPoll;
-
-typedef struct AvahiEntryGroup AvahiEntryGroup;
-
-typedef enum {
- AVAHI_ENTRY_GROUP_UNCOMMITED,
- AVAHI_ENTRY_GROUP_REGISTERING,
- AVAHI_ENTRY_GROUP_ESTABLISHED,
- AVAHI_ENTRY_GROUP_COLLISION,
- AVAHI_ENTRY_GROUP_FAILURE
-} AvahiEntryGroupState;
-
-typedef void (*AvahiEntryGroupCallback)(AvahiEntryGroup* g,
- AvahiEntryGroupState state,
- void* userdata);
-
-typedef enum {
- AVAHI_PUBLISH_UNIQUE = 1,
- AVAHI_PUBLISH_NO_PROBE = 2,
- AVAHI_PUBLISH_NO_ANNOUNCE = 4,
- AVAHI_PUBLISH_ALLOW_MULTIPLE = 8,
-
- AVAHI_PUBLISH_NO_REVERSE = 16,
- AVAHI_PUBLISH_NO_COOKIE = 32,
- AVAHI_PUBLISH_UPDATE = 64,
- AVAHI_PUBLISH_USE_WIDE_AREA = 128,
- AVAHI_PUBLISH_USE_MULTICAST = 256
-} AvahiPublishFlags;
-
-enum { AVAHI_IF_UNSPEC = -1 };
-
-enum { AVAHI_PROTO_INET = 0, AVAHI_PROTO_INET6 = 1, AVAHI_PROTO_UNSPEC = -1 };
-
-enum {
- AVAHI_OK = 0,
- AVAHI_ERR_FAILURE = -1,
- AVAHI_ERR_BAD_STATE = -2,
- AVAHI_ERR_INVALID_HOST_NAME = -3,
- AVAHI_ERR_INVALID_DOMAIN_NAME = -4,
- AVAHI_ERR_NO_NETWORK = -5,
- AVAHI_ERR_INVALID_TTL = -6,
- AVAHI_ERR_IS_PATTERN = -7,
- AVAHI_ERR_COLLISION = -8,
- AVAHI_ERR_INVALID_RECORD = -9,
-
- AVAHI_ERR_INVALID_SERVICE_NAME = -10,
- AVAHI_ERR_INVALID_SERVICE_TYPE = -11,
- AVAHI_ERR_INVALID_PORT = -12,
- AVAHI_ERR_INVALID_KEY = -13,
- AVAHI_ERR_INVALID_ADDRESS = -14,
- AVAHI_ERR_TIMEOUT = -15,
- AVAHI_ERR_TOO_MANY_CLIENTS = -16,
- AVAHI_ERR_TOO_MANY_OBJECTS = -17,
- AVAHI_ERR_TOO_MANY_ENTRIES = -18,
- AVAHI_ERR_OS = -19,
-
- AVAHI_ERR_ACCESS_DENIED = -20,
- AVAHI_ERR_INVALID_OPERATION = -21,
- AVAHI_ERR_DBUS_ERROR = -22,
- AVAHI_ERR_DISCONNECTED = -23,
- AVAHI_ERR_NO_MEMORY = -24,
- AVAHI_ERR_INVALID_OBJECT = -25,
- AVAHI_ERR_NO_DAEMON = -26,
- AVAHI_ERR_INVALID_INTERFACE = -27,
- AVAHI_ERR_INVALID_PROTOCOL = -28,
- AVAHI_ERR_INVALID_FLAGS = -29,
-
- AVAHI_ERR_NOT_FOUND = -30,
- AVAHI_ERR_INVALID_CONFIG = -31,
- AVAHI_ERR_VERSION_MISMATCH = -32,
- AVAHI_ERR_INVALID_SERVICE_SUBTYPE = -33,
- AVAHI_ERR_INVALID_PACKET = -34,
- AVAHI_ERR_INVALID_DNS_ERROR = -35,
- AVAHI_ERR_DNS_FORMERR = -36,
- AVAHI_ERR_DNS_SERVFAIL = -37,
- AVAHI_ERR_DNS_NXDOMAIN = -38,
- AVAHI_ERR_DNS_NOTIMP = -39,
-
- AVAHI_ERR_DNS_REFUSED = -40,
- AVAHI_ERR_DNS_YXDOMAIN = -41,
- AVAHI_ERR_DNS_YXRRSET = -42,
- AVAHI_ERR_DNS_NXRRSET = -43,
- AVAHI_ERR_DNS_NOTAUTH = -44,
- AVAHI_ERR_DNS_NOTZONE = -45,
- AVAHI_ERR_INVALID_RDATA = -46,
- AVAHI_ERR_INVALID_DNS_CLASS = -47,
- AVAHI_ERR_INVALID_DNS_TYPE = -48,
- AVAHI_ERR_NOT_SUPPORTED = -49,
-
- AVAHI_ERR_NOT_PERMITTED = -50,
- AVAHI_ERR_INVALID_ARGUMENT = -51,
- AVAHI_ERR_IS_EMPTY = -52,
- AVAHI_ERR_NO_CHANGE = -53,
-
- AVAHI_ERR_MAX = -54
-};
-
-namespace wpi {
-class AvahiFunctionTable {
- public:
-#define AvahiFunction(CapName, RetType, Parameters) \
- using CapName##_func = RetType(*) Parameters; \
- CapName##_func CapName = nullptr
-
- AvahiFunction(threaded_poll_new, AvahiThreadedPoll*, (void));
- AvahiFunction(threaded_poll_free, void, (AvahiThreadedPoll*));
- AvahiFunction(threaded_poll_get, const AvahiPoll*, (AvahiThreadedPoll*));
- AvahiFunction(threaded_poll_start, int, (AvahiThreadedPoll*));
- AvahiFunction(threaded_poll_stop, int, (AvahiThreadedPoll*));
- AvahiFunction(threaded_poll_lock, int, (AvahiThreadedPoll*));
- AvahiFunction(threaded_poll_unlock, int, (AvahiThreadedPoll*));
-
- AvahiFunction(client_new, AvahiClient*,
- (const AvahiPoll* poll_api, AvahiClientFlags flags,
- AvahiClientCallback callback, void* userdata, int* error));
- AvahiFunction(client_free, void, (AvahiClient*));
-
- AvahiFunction(service_browser_new, AvahiServiceBrowser*,
- (AvahiClient * client, AvahiIfIndex interface,
- AvahiProtocol protocol, const char* type, const char* domain,
- AvahiLookupFlags flags, AvahiServiceBrowserCallback callback,
- void* userdata));
-
- AvahiFunction(service_browser_free, int, (AvahiServiceBrowser*));
-
- AvahiFunction(service_resolver_new, AvahiServiceResolver*,
- (AvahiClient * client, AvahiIfIndex interface,
- AvahiProtocol protocol, const char* name, const char* type,
- const char* domain, AvahiProtocol aprotocol,
- AvahiLookupFlags flags, AvahiServiceResolverCallback callback,
- void* userdata));
- AvahiFunction(service_resolver_free, int, (AvahiServiceResolver*));
-
- AvahiFunction(entry_group_new, AvahiEntryGroup*,
- (AvahiClient*, AvahiEntryGroupCallback, void*));
- AvahiFunction(entry_group_free, int, (AvahiEntryGroup*));
-
- AvahiFunction(entry_group_add_service_strlst, int,
- (AvahiEntryGroup * group, AvahiIfIndex interface,
- AvahiProtocol protocol, AvahiPublishFlags flags,
- const char* name, const char* type, const char* domain,
- const char* host, uint16_t port, AvahiStringList*));
-
- AvahiFunction(entry_group_reset, int, (AvahiEntryGroup*));
- AvahiFunction(entry_group_is_empty, int, (AvahiEntryGroup*));
- AvahiFunction(entry_group_commit, int, (AvahiEntryGroup*));
- AvahiFunction(entry_group_get_client, AvahiClient*, (AvahiEntryGroup*));
-
- AvahiFunction(string_list_new_from_array, AvahiStringList*,
- (const char** array, int len));
- AvahiFunction(string_list_free, void, (AvahiStringList*));
-
- AvahiFunction(service_browser_get_client, AvahiClient*,
- (AvahiServiceBrowser*));
-
- AvahiFunction(unescape_label, char*, (const char**, char*, size_t));
- AvahiFunction(alternative_service_name, char*, (const char*));
- AvahiFunction(free, void, (void*));
-
- bool IsValid() const { return valid; }
-
- static AvahiFunctionTable& Get();
-
- private:
- AvahiFunctionTable();
- bool valid;
-};
-
-class AvahiThread {
- private:
- struct private_init {};
-
- public:
- explicit AvahiThread(const private_init&);
- ~AvahiThread() noexcept;
-
- void lock();
- const AvahiPoll* GetPoll() const;
- void unlock();
-
- static std::shared_ptr<AvahiThread> Get();
-
- private:
- AvahiThreadedPoll* threadedPoll;
- AvahiFunctionTable& table = AvahiFunctionTable::Get();
-};
-
-} // namespace wpi
diff --git a/wpiutil/src/main/native/linux/MulticastServiceAnnouncer.cpp b/wpiutil/src/main/native/linux/MulticastServiceAnnouncer.cpp
deleted file mode 100644
index 1a7af39..0000000
--- a/wpiutil/src/main/native/linux/MulticastServiceAnnouncer.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-// 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/MulticastServiceAnnouncer.h"
-
-#include <vector>
-
-#include "AvahiClient.h"
-#include "fmt/format.h"
-#include "wpi/mutex.h"
-
-using namespace wpi;
-
-struct MulticastServiceAnnouncer::Impl {
- AvahiFunctionTable& table = AvahiFunctionTable::Get();
- std::shared_ptr<AvahiThread> thread = AvahiThread::Get();
- AvahiClient* client;
- AvahiEntryGroup* group = nullptr;
- std::string serviceName;
- std::string serviceType;
- int port;
- AvahiStringList* stringList = nullptr;
-
- ~Impl() noexcept {
- if (stringList != nullptr && table.IsValid()) {
- table.string_list_free(stringList);
- }
- }
-
- template <typename T>
- Impl(std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<T, T>> txt);
-};
-
-template <typename T>
-MulticastServiceAnnouncer::Impl::Impl(std::string_view serviceName,
- std::string_view serviceType, int port,
- wpi::span<const std::pair<T, T>> txt) {
- if (!this->table.IsValid()) {
- return;
- }
-
- this->serviceName = serviceName;
- this->serviceType = serviceType;
- this->port = port;
-
- std::vector<std::string> txts;
- for (auto&& i : txt) {
- txts.push_back(fmt::format("{}={}", i.first, i.second));
- }
-
- std::vector<const char*> txtArr;
- for (auto&& i : txts) {
- txtArr.push_back(i.c_str());
- }
-
- this->stringList =
- this->table.string_list_new_from_array(txtArr.data(), txtArr.size());
-}
-
-static void RegisterService(AvahiClient* client,
- MulticastServiceAnnouncer::Impl* impl);
-
-static void EntryGroupCallback(AvahiEntryGroup* group,
- AvahiEntryGroupState state, void* userdata) {
- if (state == AVAHI_ENTRY_GROUP_COLLISION) {
- // Remote collision
- MulticastServiceAnnouncer::Impl* impl =
- reinterpret_cast<MulticastServiceAnnouncer::Impl*>(userdata);
- char* newName =
- impl->table.alternative_service_name(impl->serviceName.c_str());
- impl->serviceName = newName;
- impl->table.free(newName);
- RegisterService(impl->table.entry_group_get_client(group), impl);
- }
-}
-
-static void RegisterService(AvahiClient* client,
- MulticastServiceAnnouncer::Impl* impl) {
- if (impl->group == nullptr) {
- impl->group = impl->table.entry_group_new(client, EntryGroupCallback, impl);
- }
-
- while (true) {
- if (impl->table.entry_group_is_empty(impl->group)) {
- auto ret = impl->table.entry_group_add_service_strlst(
- impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
- AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
- impl->serviceType.c_str(), "local", nullptr, impl->port,
- impl->stringList);
- if (ret == AVAHI_ERR_COLLISION) {
- // Local collision
- char* newName =
- impl->table.alternative_service_name(impl->serviceName.c_str());
- impl->serviceName = newName;
- impl->table.free(newName);
- continue;
- } else if (ret != AVAHI_OK) {
- break;
- }
- impl->table.entry_group_commit(impl->group);
- break;
- }
- }
-}
-
-static void ClientCallback(AvahiClient* client, AvahiClientState state,
- void* userdata) {
- MulticastServiceAnnouncer::Impl* impl =
- reinterpret_cast<MulticastServiceAnnouncer::Impl*>(userdata);
-
- if (state == AVAHI_CLIENT_S_RUNNING) {
- RegisterService(client, impl);
- } else if (state == AVAHI_CLIENT_S_COLLISION ||
- state == AVAHI_CLIENT_S_REGISTERING) {
- if (impl->group) {
- impl->table.entry_group_reset(impl->group);
- }
- }
-}
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string, std::string>> txt) {
- pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
-}
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string_view, std::string_view>> txt) {
- pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
-}
-
-MulticastServiceAnnouncer::~MulticastServiceAnnouncer() noexcept {
- Stop();
-}
-
-bool MulticastServiceAnnouncer::HasImplementation() const {
- return pImpl->table.IsValid();
-}
-
-void MulticastServiceAnnouncer::Start() {
- if (!pImpl->table.IsValid()) {
- return;
- }
- std::scoped_lock lock{*pImpl->thread};
- if (pImpl->client) {
- return;
- }
- pImpl->client =
- pImpl->table.client_new(pImpl->thread->GetPoll(), AVAHI_CLIENT_NO_FAIL,
- ClientCallback, pImpl.get(), nullptr);
-}
-
-void MulticastServiceAnnouncer::Stop() {
- if (!pImpl->table.IsValid()) {
- return;
- }
- std::scoped_lock lock{*pImpl->thread};
- if (pImpl->client) {
- if (pImpl->group) {
- pImpl->table.entry_group_free(pImpl->group);
- pImpl->group = nullptr;
- }
- pImpl->table.client_free(pImpl->client);
- pImpl->client = nullptr;
- }
-}
diff --git a/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp b/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp
deleted file mode 100644
index 6585443..0000000
--- a/wpiutil/src/main/native/linux/MulticastServiceResolver.cpp
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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/MulticastServiceResolver.h"
-
-#include "AvahiClient.h"
-#include "wpi/SmallString.h"
-#include "wpi/StringExtras.h"
-#include "wpi/mutex.h"
-
-using namespace wpi;
-
-struct MulticastServiceResolver::Impl {
- AvahiFunctionTable& table = AvahiFunctionTable::Get();
- std::shared_ptr<AvahiThread> thread = AvahiThread::Get();
- AvahiClient* client;
- AvahiServiceBrowser* browser;
- std::string serviceType;
- MulticastServiceResolver* resolver;
-
- void onFound(ServiceData&& data) {
- resolver->PushData(std::forward<ServiceData>(data));
- }
-};
-
-MulticastServiceResolver::MulticastServiceResolver(
- std::string_view serviceType) {
- pImpl = std::make_unique<Impl>();
- pImpl->serviceType = serviceType;
- pImpl->resolver = this;
-}
-
-MulticastServiceResolver::~MulticastServiceResolver() noexcept {
- Stop();
-}
-
-bool MulticastServiceResolver::HasImplementation() const {
- return pImpl->table.IsValid();
-}
-
-static void ResolveCallback(AvahiServiceResolver* r, AvahiIfIndex interface,
- AvahiProtocol protocol, AvahiResolverEvent event,
- const char* name, const char* type,
- const char* domain, const char* host_name,
- const AvahiAddress* address, uint16_t port,
- AvahiStringList* txt, AvahiLookupResultFlags flags,
- void* userdata) {
- MulticastServiceResolver::Impl* impl =
- reinterpret_cast<MulticastServiceResolver::Impl*>(userdata);
-
- if (event == AVAHI_RESOLVER_FOUND) {
- if (address->proto == AVAHI_PROTO_INET) {
- AvahiStringList* strLst = txt;
- MulticastServiceResolver::ServiceData data;
- while (strLst != nullptr) {
- std::string_view value{reinterpret_cast<const char*>(strLst->text),
- strLst->size};
- strLst = strLst->next;
- size_t splitIndex = value.find('=');
- if (splitIndex == value.npos) {
- // Todo make this just do key
- continue;
- }
- std::string_view key = wpi::substr(value, 0, splitIndex);
- value =
- wpi::substr(value, splitIndex + 1, value.size() - splitIndex - 1);
- data.txt.emplace_back(std::pair<std::string, std::string>{key, value});
- }
- wpi::SmallString<256> outputHostName;
- char label[256];
- do {
- impl->table.unescape_label(&host_name, label, sizeof(label));
- if (label[0] == '\0') {
- break;
- }
- outputHostName.append(label);
- outputHostName.append(".");
- } while (true);
-
- data.ipv4Address = address->data.ipv4.address;
- data.port = port;
- data.serviceName = name;
- data.hostName = outputHostName.string();
-
- impl->onFound(std::move(data));
- }
- }
-
- impl->table.service_resolver_free(r);
-}
-
-static void BrowseCallback(AvahiServiceBrowser* b, AvahiIfIndex interface,
- AvahiProtocol protocol, AvahiBrowserEvent event,
- const char* name, const char* type,
- const char* domain, AvahiLookupResultFlags flags,
- void* userdata) {
- MulticastServiceResolver::Impl* impl =
- reinterpret_cast<MulticastServiceResolver::Impl*>(userdata);
-
- if (event == AVAHI_BROWSER_NEW) {
- impl->table.service_resolver_new(
- impl->table.service_browser_get_client(b), interface, protocol, name,
- type, domain, AVAHI_PROTO_UNSPEC, AVAHI_LOOKUP_USE_MULTICAST,
- ResolveCallback, userdata);
- }
-}
-
-static void ClientCallback(AvahiClient* client, AvahiClientState state,
- void* userdata) {
- MulticastServiceResolver::Impl* impl =
- reinterpret_cast<MulticastServiceResolver::Impl*>(userdata);
-
- if (state == AVAHI_CLIENT_S_RUNNING) {
- impl->browser = impl->table.service_browser_new(
- client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, impl->serviceType.c_str(),
- "local", AvahiLookupFlags::AVAHI_LOOKUP_USE_MULTICAST, BrowseCallback,
- userdata);
- }
-}
-
-void MulticastServiceResolver::Start() {
- if (!pImpl->table.IsValid()) {
- return;
- }
- std::scoped_lock lock{*pImpl->thread};
- if (pImpl->client) {
- return;
- }
-
- pImpl->client =
- pImpl->table.client_new(pImpl->thread->GetPoll(), AVAHI_CLIENT_NO_FAIL,
- ClientCallback, pImpl.get(), nullptr);
-}
-
-void MulticastServiceResolver::Stop() {
- if (!pImpl->table.IsValid()) {
- return;
- }
- std::scoped_lock lock{*pImpl->thread};
- if (pImpl->client) {
- if (pImpl->browser) {
- pImpl->table.service_browser_free(pImpl->browser);
- pImpl->browser = nullptr;
- }
- pImpl->table.client_free(pImpl->client);
- pImpl->client = nullptr;
- }
-}
diff --git a/wpiutil/src/main/native/macOS/MulticastServiceAnnouncer.cpp b/wpiutil/src/main/native/macOS/MulticastServiceAnnouncer.cpp
deleted file mode 100644
index ad2ff48..0000000
--- a/wpiutil/src/main/native/macOS/MulticastServiceAnnouncer.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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/MulticastServiceAnnouncer.h"
-
-#include <wpi/SmallString.h>
-
-#include "dns_sd.h"
-
-using namespace wpi;
-
-struct MulticastServiceAnnouncer::Impl {
- std::string serviceName;
- std::string serviceType;
- int port;
- DNSServiceRef serviceRef{nullptr};
- TXTRecordRef txtRecord;
-
- Impl() { TXTRecordCreate(&txtRecord, 0, nullptr); }
-
- ~Impl() noexcept { TXTRecordDeallocate(&txtRecord); }
-};
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string, std::string>> txt) {
- pImpl = std::make_unique<Impl>();
- pImpl->serviceName = serviceName;
- pImpl->serviceType = serviceType;
- pImpl->port = port;
-
- for (auto&& i : txt) {
- TXTRecordSetValue(&pImpl->txtRecord, i.first.c_str(), i.second.length(),
- i.second.c_str());
- }
-}
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string_view, std::string_view>> txt) {
- pImpl = std::make_unique<Impl>();
- pImpl->serviceName = serviceName;
- pImpl->serviceType = serviceType;
- pImpl->port = port;
-
- wpi::SmallString<64> key;
-
- for (auto&& i : txt) {
- key.clear();
- key.append(i.first);
- key.emplace_back('\0');
-
- TXTRecordSetValue(&pImpl->txtRecord, key.data(), i.second.length(),
- i.second.data());
- }
-}
-
-MulticastServiceAnnouncer::~MulticastServiceAnnouncer() noexcept {
- Stop();
-}
-
-bool MulticastServiceAnnouncer::HasImplementation() const {
- return true;
-}
-
-void MulticastServiceAnnouncer::Start() {
- if (pImpl->serviceRef) {
- return;
- }
-
- uint16_t len = TXTRecordGetLength(&pImpl->txtRecord);
- const void* ptr = TXTRecordGetBytesPtr(&pImpl->txtRecord);
-
- (void)DNSServiceRegister(&pImpl->serviceRef, 0, 0, pImpl->serviceName.c_str(),
- pImpl->serviceType.c_str(), "local", nullptr,
- htons(pImpl->port), len, ptr, nullptr, nullptr);
-}
-
-void MulticastServiceAnnouncer::Stop() {
- if (!pImpl->serviceRef) {
- return;
- }
- DNSServiceRefDeallocate(pImpl->serviceRef);
- pImpl->serviceRef = nullptr;
-}
diff --git a/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp b/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp
deleted file mode 100644
index 4af8cad..0000000
--- a/wpiutil/src/main/native/macOS/MulticastServiceResolver.cpp
+++ /dev/null
@@ -1,213 +0,0 @@
-// 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/MulticastServiceResolver.h"
-
-#include <netinet/in.h>
-#include <poll.h>
-
-#include <atomic>
-#include <thread>
-#include <vector>
-
-#include "ResolverThread.h"
-#include "dns_sd.h"
-#include "wpi/SmallVector.h"
-
-using namespace wpi;
-
-struct DnsResolveState {
- DnsResolveState(MulticastServiceResolver::Impl* impl,
- std::string_view serviceNameView)
- : pImpl{impl} {
- data.serviceName = serviceNameView;
- }
-
- DNSServiceRef ResolveRef = nullptr;
- MulticastServiceResolver::Impl* pImpl;
-
- MulticastServiceResolver::ServiceData data;
-};
-
-struct MulticastServiceResolver::Impl {
- std::string serviceType;
- MulticastServiceResolver* resolver;
- std::shared_ptr<ResolverThread> thread = ResolverThread::Get();
- std::vector<std::unique_ptr<DnsResolveState>> ResolveStates;
- DNSServiceRef serviceRef = nullptr;
-
- void onFound(ServiceData&& data) {
- resolver->PushData(std::forward<ServiceData>(data));
- }
-};
-
-MulticastServiceResolver::MulticastServiceResolver(
- std::string_view serviceType) {
- pImpl = std::make_unique<Impl>();
- pImpl->serviceType = serviceType;
- pImpl->resolver = this;
-}
-
-MulticastServiceResolver::~MulticastServiceResolver() noexcept {
- Stop();
-}
-
-void ServiceGetAddrInfoReply(DNSServiceRef sdRef, DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* hostname,
- const struct sockaddr* address, uint32_t ttl,
- void* context) {
- if (errorCode != kDNSServiceErr_NoError) {
- return;
- }
-
- DnsResolveState* resolveState = static_cast<DnsResolveState*>(context);
-
- resolveState->data.hostName = hostname;
- resolveState->data.ipv4Address =
- reinterpret_cast<const struct sockaddr_in*>(address)->sin_addr.s_addr;
-
- resolveState->pImpl->onFound(std::move(resolveState->data));
-
- resolveState->pImpl->thread->RemoveServiceRefInThread(
- resolveState->ResolveRef);
-
- resolveState->pImpl->ResolveStates.erase(std::find_if(
- resolveState->pImpl->ResolveStates.begin(),
- resolveState->pImpl->ResolveStates.end(),
- [resolveState](auto& a) { return a.get() == resolveState; }));
-}
-
-void ServiceResolveReply(DNSServiceRef sdRef, DNSServiceFlags flags,
- uint32_t interfaceIndex, DNSServiceErrorType errorCode,
- const char* fullname, const char* hosttarget,
- uint16_t port, /* In network byte order */
- uint16_t txtLen, const unsigned char* txtRecord,
- void* context) {
- if (errorCode != kDNSServiceErr_NoError) {
- return;
- }
-
- DnsResolveState* resolveState = static_cast<DnsResolveState*>(context);
- resolveState->pImpl->thread->RemoveServiceRefInThread(
- resolveState->ResolveRef);
- DNSServiceRefDeallocate(resolveState->ResolveRef);
- resolveState->ResolveRef = nullptr;
- resolveState->data.port = ntohs(port);
-
- int txtCount = TXTRecordGetCount(txtLen, txtRecord);
- char keyBuf[256];
- uint8_t valueLen;
- const void* value;
-
- for (int i = 0; i < txtCount; i++) {
- errorCode = TXTRecordGetItemAtIndex(txtLen, txtRecord, i, sizeof(keyBuf),
- keyBuf, &valueLen, &value);
- if (errorCode == kDNSServiceErr_NoError) {
- if (valueLen == 0) {
- // No value
- resolveState->data.txt.emplace_back(
- std::pair<std::string, std::string>{std::string{keyBuf}, {}});
- } else {
- resolveState->data.txt.emplace_back(std::pair<std::string, std::string>{
- std::string{keyBuf},
- std::string{reinterpret_cast<const char*>(value), valueLen}});
- }
- }
- }
-
- errorCode = DNSServiceGetAddrInfo(
- &resolveState->ResolveRef, flags, interfaceIndex,
- kDNSServiceProtocol_IPv4, hosttarget, ServiceGetAddrInfoReply, context);
-
- if (errorCode == kDNSServiceErr_NoError) {
- dnssd_sock_t socket = DNSServiceRefSockFD(resolveState->ResolveRef);
- resolveState->pImpl->thread->AddServiceRef(resolveState->ResolveRef,
- socket);
- } else {
- resolveState->pImpl->thread->RemoveServiceRefInThread(
- resolveState->ResolveRef);
- resolveState->pImpl->ResolveStates.erase(std::find_if(
- resolveState->pImpl->ResolveStates.begin(),
- resolveState->pImpl->ResolveStates.end(),
- [resolveState](auto& a) { return a.get() == resolveState; }));
- }
-}
-
-static void DnsCompletion(DNSServiceRef sdRef, DNSServiceFlags flags,
- uint32_t interfaceIndex,
- DNSServiceErrorType errorCode,
- const char* serviceName, const char* regtype,
- const char* replyDomain, void* context) {
- if (errorCode != kDNSServiceErr_NoError) {
- return;
- }
- if (!(flags & kDNSServiceFlagsAdd)) {
- return;
- }
-
- MulticastServiceResolver::Impl* impl =
- static_cast<MulticastServiceResolver::Impl*>(context);
- auto& resolveState = impl->ResolveStates.emplace_back(
- std::make_unique<DnsResolveState>(impl, serviceName));
-
- errorCode = DNSServiceResolve(&resolveState->ResolveRef, 0, interfaceIndex,
- serviceName, regtype, replyDomain,
- ServiceResolveReply, resolveState.get());
-
- if (errorCode == kDNSServiceErr_NoError) {
- dnssd_sock_t socket = DNSServiceRefSockFD(resolveState->ResolveRef);
- resolveState->pImpl->thread->AddServiceRef(resolveState->ResolveRef,
- socket);
- } else {
- resolveState->pImpl->ResolveStates.erase(std::find_if(
- resolveState->pImpl->ResolveStates.begin(),
- resolveState->pImpl->ResolveStates.end(),
- [r = resolveState.get()](auto& a) { return a.get() == r; }));
- }
-}
-
-bool MulticastServiceResolver::HasImplementation() const {
- return true;
-}
-
-void MulticastServiceResolver::Start() {
- if (pImpl->serviceRef) {
- return;
- }
-
- DNSServiceErrorType status =
- DNSServiceBrowse(&pImpl->serviceRef, 0, 0, pImpl->serviceType.c_str(),
- "local", DnsCompletion, pImpl.get());
- if (status == kDNSServiceErr_NoError) {
- dnssd_sock_t socket = DNSServiceRefSockFD(pImpl->serviceRef);
- pImpl->thread->AddServiceRef(pImpl->serviceRef, socket);
- }
-}
-
-void MulticastServiceResolver::Stop() {
- if (!pImpl->serviceRef) {
- return;
- }
- wpi::SmallVector<WPI_EventHandle, 8> cleanupEvents;
- for (auto&& i : pImpl->ResolveStates) {
- cleanupEvents.push_back(
- pImpl->thread->RemoveServiceRefOutsideThread(i->ResolveRef));
- }
- cleanupEvents.push_back(
- pImpl->thread->RemoveServiceRefOutsideThread(pImpl->serviceRef));
- wpi::SmallVector<WPI_Handle, 8> signaledBuf;
- signaledBuf.resize(cleanupEvents.size());
- while (!cleanupEvents.empty()) {
- auto signaled = wpi::WaitForObjects(cleanupEvents, signaledBuf);
- for (auto&& s : signaled) {
- cleanupEvents.erase(
- std::find(cleanupEvents.begin(), cleanupEvents.end(), s));
- }
- }
-
- pImpl->ResolveStates.clear();
- pImpl->serviceRef = nullptr;
-}
diff --git a/wpiutil/src/main/native/macOS/ResolverThread.cpp b/wpiutil/src/main/native/macOS/ResolverThread.cpp
deleted file mode 100644
index b91d6b6..0000000
--- a/wpiutil/src/main/native/macOS/ResolverThread.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-// 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 "ResolverThread.h"
-
-#include "wpi/mutex.h"
-
-using namespace wpi;
-
-ResolverThread::ResolverThread(const private_init&) {}
-
-ResolverThread::~ResolverThread() noexcept {
- running = false;
- if (thread.joinable()) {
- thread.join();
- }
-}
-
-void ResolverThread::AddServiceRef(DNSServiceRef serviceRef,
- dnssd_sock_t socket) {
- std::scoped_lock lock{serviceRefMutex};
- serviceRefs.emplace_back(
- std::pair<DNSServiceRef, dnssd_sock_t>{serviceRef, socket});
- if (serviceRefs.size() == 1) {
- running = false;
- if (thread.joinable()) {
- thread.join();
- }
- running = true;
- thread = std::thread([=] { ThreadMain(); });
- }
-}
-
-void ResolverThread::RemoveServiceRefInThread(DNSServiceRef serviceRef) {
- std::scoped_lock lock{serviceRefMutex};
- serviceRefs.erase(
- std::find_if(serviceRefs.begin(), serviceRefs.end(),
- [=](auto& a) { return a.first == serviceRef; }));
- DNSServiceRefDeallocate(serviceRef);
-}
-
-WPI_EventHandle ResolverThread::RemoveServiceRefOutsideThread(
- DNSServiceRef serviceRef) {
- std::scoped_lock lock{serviceRefMutex};
- WPI_EventHandle handle = CreateEvent(true);
- serviceRefsToRemove.push_back({serviceRef, handle});
- return handle;
-}
-
-bool ResolverThread::CleanupRefs() {
- std::scoped_lock lock{serviceRefMutex};
- for (auto&& r : serviceRefsToRemove) {
- serviceRefs.erase(
- std::find_if(serviceRefs.begin(), serviceRefs.end(),
- [=](auto& a) { return a.first == r.first; }));
- DNSServiceRefDeallocate(r.first);
- wpi::SetEvent(r.second);
- }
- serviceRefsToRemove.clear();
- return serviceRefs.empty();
-}
-
-void ResolverThread::ThreadMain() {
- std::vector<pollfd> readSockets;
- std::vector<DNSServiceRef> serviceRefs;
-
- while (running) {
- readSockets.clear();
- serviceRefs.clear();
-
- for (auto&& i : this->serviceRefs) {
- readSockets.emplace_back(pollfd{i.second, POLLIN, 0});
- serviceRefs.emplace_back(i.first);
- }
-
- int res = poll(readSockets.begin().base(), readSockets.size(), 100);
-
- if (res > 0) {
- for (size_t i = 0; i < readSockets.size(); i++) {
- if (readSockets[i].revents == POLLIN) {
- DNSServiceProcessResult(serviceRefs[i]);
- }
- }
- } else if (res == 0) {
- if (!running) {
- CleanupRefs();
- break;
- }
- }
-
- if (CleanupRefs()) {
- break;
- }
- }
-}
-
-static wpi::mutex ThreadLoopLock;
-static std::weak_ptr<ResolverThread> ThreadLoop;
-
-std::shared_ptr<ResolverThread> ResolverThread::Get() {
- std::scoped_lock lock{ThreadLoopLock};
- auto locked = ThreadLoop.lock();
- if (!locked) {
- locked = std::make_unique<ResolverThread>(private_init{});
- ThreadLoop = locked;
- }
- return locked;
-}
diff --git a/wpiutil/src/main/native/macOS/ResolverThread.h b/wpiutil/src/main/native/macOS/ResolverThread.h
deleted file mode 100644
index 0162de5..0000000
--- a/wpiutil/src/main/native/macOS/ResolverThread.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// 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 <netinet/in.h>
-#include <poll.h>
-
-#include <atomic>
-#include <memory>
-#include <thread>
-#include <utility>
-#include <vector>
-
-#include "dns_sd.h"
-#include "wpi/Synchronization.h"
-#include "wpi/mutex.h"
-
-namespace wpi {
-class ResolverThread {
- private:
- struct private_init {};
-
- public:
- explicit ResolverThread(const private_init&);
- ~ResolverThread() noexcept;
-
- void AddServiceRef(DNSServiceRef serviceRef, dnssd_sock_t socket);
- void RemoveServiceRefInThread(DNSServiceRef serviceRef);
- WPI_EventHandle RemoveServiceRefOutsideThread(DNSServiceRef serviceRef);
-
- static std::shared_ptr<ResolverThread> Get();
-
- private:
- void ThreadMain();
- bool CleanupRefs();
-
- wpi::mutex serviceRefMutex;
- std::vector<std::pair<DNSServiceRef, WPI_EventHandle>> serviceRefsToRemove;
- std::vector<std::pair<DNSServiceRef, dnssd_sock_t>> serviceRefs;
- std::thread thread;
- std::atomic_bool running;
-};
-} // namespace wpi
diff --git a/wpiutil/src/main/native/resources/bootstrap-4.1.min.js.gz b/wpiutil/src/main/native/resources/bootstrap-4.1.min.js.gz
deleted file mode 100644
index a7797e1..0000000
--- a/wpiutil/src/main/native/resources/bootstrap-4.1.min.js.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/resources/coreui-2.1.min.css.gz b/wpiutil/src/main/native/resources/coreui-2.1.min.css.gz
deleted file mode 100644
index d4f43ad..0000000
--- a/wpiutil/src/main/native/resources/coreui-2.1.min.css.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/resources/coreui-2.1.min.js.gz b/wpiutil/src/main/native/resources/coreui-2.1.min.js.gz
deleted file mode 100644
index cf4ccb1..0000000
--- a/wpiutil/src/main/native/resources/coreui-2.1.min.js.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/resources/feather-4.8.min.js.gz b/wpiutil/src/main/native/resources/feather-4.8.min.js.gz
deleted file mode 100644
index d275865..0000000
--- a/wpiutil/src/main/native/resources/feather-4.8.min.js.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/resources/jquery-3.3.slim.min.js.gz b/wpiutil/src/main/native/resources/jquery-3.3.slim.min.js.gz
deleted file mode 100644
index 712e06c..0000000
--- a/wpiutil/src/main/native/resources/jquery-3.3.slim.min.js.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/resources/popper-1.14.min.js.gz b/wpiutil/src/main/native/resources/popper-1.14.min.js.gz
deleted file mode 100644
index c6ebec8..0000000
--- a/wpiutil/src/main/native/resources/popper-1.14.min.js.gz
+++ /dev/null
Binary files differ
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/args.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
similarity index 95%
rename from wpiutil/src/main/native/fmtlib/include/fmt/args.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
index 9a8e4ed..a3966d1 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/args.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/args.h
@@ -95,10 +95,10 @@
};
template <typename T>
- using stored_type = conditional_t<detail::is_string<T>::value &&
- !has_formatter<T, Context>::value &&
- !detail::is_reference_wrapper<T>::value,
- std::basic_string<char_type>, T>;
+ using stored_type = conditional_t<
+ std::is_convertible<T, std::basic_string<char_type>>::value &&
+ !detail::is_reference_wrapper<T>::value,
+ std::basic_string<char_type>, T>;
// Storage of basic_format_arg must be contiguous.
std::vector<basic_format_arg<Context>> data_;
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/chrono.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
similarity index 95%
rename from wpiutil/src/main/native/fmtlib/include/fmt/chrono.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
index 682efd8..b112f76 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/chrono.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/chrono.h
@@ -10,6 +10,8 @@
#include <algorithm>
#include <chrono>
+#include <cmath> // std::isfinite
+#include <cstring> // std::memcpy
#include <ctime>
#include <iterator>
#include <locale>
@@ -201,7 +203,7 @@
}
const auto min1 =
(std::numeric_limits<IntermediateRep>::min)() / Factor::num;
- if (count < min1) {
+ if (!std::is_unsigned<IntermediateRep>::value && count < min1) {
ec = 1;
return {};
}
@@ -321,14 +323,13 @@
template <typename CodeUnit>
void write_codecvt(codecvt_result<CodeUnit>& out, string_view in_buf,
const std::locale& loc) {
- using codecvt = std::codecvt<CodeUnit, char, std::mbstate_t>;
#if FMT_CLANG_VERSION
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated"
- auto& f = std::use_facet<codecvt>(loc);
+ auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
# pragma clang diagnostic pop
#else
- auto& f = std::use_facet<codecvt>(loc);
+ auto& f = std::use_facet<std::codecvt<CodeUnit, char, std::mbstate_t>>(loc);
#endif
auto mb = std::mbstate_t();
const char* from_next = nullptr;
@@ -344,7 +345,7 @@
if (detail::is_utf8() && loc != get_classic_locale()) {
// char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
// gcc-4.
-#if FMT_MSC_VER != 0 || \
+#if FMT_MSC_VERSION != 0 || \
(defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
// The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
// and newer.
@@ -468,7 +469,7 @@
bool fallback(int res) { return res == 0; }
-#if !FMT_MSC_VER
+#if !FMT_MSC_VERSION
bool fallback(detail::null<>) {
using namespace fmt::detail;
std::tm* tm = std::localtime(&time_);
@@ -514,7 +515,7 @@
bool fallback(int res) { return res == 0; }
-#if !FMT_MSC_VER
+#if !FMT_MSC_VERSION
bool fallback(detail::null<>) {
std::tm* tm = std::gmtime(&time_);
if (tm) tm_ = *tm;
@@ -562,10 +563,10 @@
constexpr const size_t len = 8;
if (const_check(is_big_endian())) {
char tmp[len];
- memcpy(tmp, &digits, len);
+ std::memcpy(tmp, &digits, len);
std::reverse_copy(tmp, tmp + len, buf);
} else {
- memcpy(buf, &digits, len);
+ std::memcpy(buf, &digits, len);
}
}
@@ -1214,7 +1215,7 @@
char buf[10];
size_t offset = 0;
if (year >= 0 && year < 10000) {
- copy2(buf, digits2(to_unsigned(year / 100)));
+ copy2(buf, digits2(static_cast<size_t>(year / 100)));
} else {
offset = 4;
write_year_extended(year);
@@ -1388,15 +1389,6 @@
};
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
-inline bool isnan(T) {
- return false;
-}
-template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-inline bool isnan(T value) {
- return std::isnan(value);
-}
-
-template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
inline bool isfinite(T) {
return true;
}
@@ -1404,7 +1396,8 @@
// 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(value >= 0 && to_unsigned(value) <= to_unsigned(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);
@@ -1470,14 +1463,22 @@
#endif
}
-// Returns the number of fractional digits in the range [0, 18] according to the
+// 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.
-constexpr int count_fractional_digits(long long num, long long den, int n = 0) {
- return num % den == 0
- ? n
- : (n > 18 ? 6 : count_fractional_digits(num * 10, den, n + 1));
-}
+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);
@@ -1663,9 +1664,11 @@
out = format_decimal<char_type>(out, n, num_digits).end;
}
- template <class Duration> void write_fractional_seconds(Duration d) {
+ 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);
+ count_fractional_digits<Duration::period::num,
+ Duration::period::den>::value;
using subsecond_precision = std::chrono::duration<
typename std::common_type<typename Duration::rep,
@@ -1674,12 +1677,9 @@
if (std::ratio_less<typename subsecond_precision::period,
std::chrono::seconds::period>::value) {
*out++ = '.';
- // Don't convert long double to integer seconds to avoid overflow.
- using sec = conditional_t<
- std::is_same<typename Duration::rep, long double>::value,
- std::chrono::duration<long double>, std::chrono::seconds>;
- auto fractional = detail::abs(d) - std::chrono::duration_cast<sec>(d);
- const auto subseconds =
+ 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()
@@ -1770,8 +1770,22 @@
if (handle_nan_inf()) return;
if (ns == numeric_system::standard) {
- write(second(), 2);
- write_fractional_seconds(std::chrono::duration<rep, Period>{val});
+ 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);
+ if (negative) *out++ = '-';
+ if (buf.size() < 2 || buf[1] == '.') *out++ = '0';
+ out = std::copy(buf.begin(), buf.end(), out);
+ } else {
+ write(second(), 2);
+ write_fractional_seconds(std::chrono::duration<rep, Period>(val));
+ }
return;
}
auto time = tm();
@@ -1988,13 +2002,9 @@
struct formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
Char> : formatter<std::tm, Char> {
FMT_CONSTEXPR formatter() {
- this->do_parse(default_specs,
- default_specs + sizeof(default_specs) / sizeof(Char));
- }
-
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return this->do_parse(ctx.begin(), ctx.end(), true);
+ basic_string_view<Char> default_specs =
+ detail::string_literal<Char, '%', 'F', ' ', '%', 'T'>{};
+ this->do_parse(default_specs.begin(), default_specs.end());
}
template <typename FormatContext>
@@ -2002,15 +2012,8 @@
FormatContext& ctx) const -> decltype(ctx.out()) {
return formatter<std::tm, Char>::format(localtime(val), ctx);
}
-
- static constexpr const Char default_specs[] = {'%', 'F', ' ', '%', 'T'};
};
-template <typename Char, typename Duration>
-constexpr const Char
- formatter<std::chrono::time_point<std::chrono::system_clock, Duration>,
- Char>::default_specs[];
-
template <typename Char> struct formatter<std::tm, Char> {
private:
enum class spec {
@@ -2022,13 +2025,18 @@
basic_string_view<Char> specs;
protected:
- template <typename It>
- FMT_CONSTEXPR auto do_parse(It begin, It end, bool with_default = false)
- -> It {
+ 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());
- if (!with_default || end != begin)
- specs = {begin, detail::to_unsigned(end - begin)};
+ // Replace default spec only if the new spec is not empty.
+ if (end != begin) specs = {begin, detail::to_unsigned(end - begin)};
+ return end;
+ }
+
+ 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'))
@@ -2039,12 +2047,6 @@
return end;
}
- public:
- template <typename ParseContext>
- FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
- return this->do_parse(ctx.begin(), ctx.end());
- }
-
template <typename FormatContext>
auto format(const std::tm& tm, FormatContext& ctx) const
-> decltype(ctx.out()) {
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/color.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
similarity index 80%
rename from wpiutil/src/main/native/fmtlib/include/fmt/color.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
index dfbe482..4c16327 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/color.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/color.h
@@ -10,13 +10,6 @@
#include "format.h"
-// __declspec(deprecated) is broken in some MSVC versions.
-#if FMT_MSC_VER
-# define FMT_DEPRECATED_NONMSVC
-#else
-# define FMT_DEPRECATED_NONMSVC FMT_DEPRECATED
-#endif
-
FMT_BEGIN_NAMESPACE
FMT_MODULE_EXPORT_BEGIN
@@ -214,17 +207,16 @@
// color is a struct of either a rgb color or a terminal color.
struct color_type {
- FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
- FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
- value{} {
+ FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
+ FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = static_cast<uint32_t>(rgb_color);
}
- FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
+ FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
}
- FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
- value{} {
+ FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
+ : is_rgb(), value{} {
value.term_color = static_cast<uint8_t>(term_color);
}
bool is_rgb;
@@ -239,10 +231,8 @@
/** A text style consisting of foreground and background colors and emphasis. */
class text_style {
public:
- FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
- : set_foreground_color(),
- set_background_color(),
- ems(em) {}
+ FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
+ : set_foreground_color(), set_background_color(), ems(em) {}
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
if (!set_foreground_color) {
@@ -273,44 +263,32 @@
return lhs |= rhs;
}
- FMT_DEPRECATED_NONMSVC FMT_CONSTEXPR text_style& operator&=(
- const text_style& rhs) {
- return and_assign(rhs);
- }
-
- FMT_DEPRECATED_NONMSVC friend FMT_CONSTEXPR text_style
- operator&(text_style lhs, const text_style& rhs) {
- return lhs.and_assign(rhs);
- }
-
- FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR bool has_foreground() const noexcept {
return set_foreground_color;
}
- FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR bool has_background() const noexcept {
return set_background_color;
}
- FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR bool has_emphasis() const noexcept {
return static_cast<uint8_t>(ems) != 0;
}
- FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
return foreground_color;
}
- FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR detail::color_type get_background() const noexcept {
FMT_ASSERT(has_background(), "no background specified for this style");
return background_color;
}
- FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
return ems;
}
private:
FMT_CONSTEXPR text_style(bool is_foreground,
- detail::color_type text_color) FMT_NOEXCEPT
- : set_foreground_color(),
- set_background_color(),
- ems() {
+ detail::color_type text_color) noexcept
+ : set_foreground_color(), set_background_color(), ems() {
if (is_foreground) {
foreground_color = text_color;
set_foreground_color = true;
@@ -320,36 +298,9 @@
}
}
- // DEPRECATED!
- FMT_CONSTEXPR text_style& and_assign(const text_style& rhs) {
- if (!set_foreground_color) {
- set_foreground_color = rhs.set_foreground_color;
- foreground_color = rhs.foreground_color;
- } else if (rhs.set_foreground_color) {
- if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb)
- FMT_THROW(format_error("can't AND a terminal color"));
- foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color;
- }
+ friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept;
- if (!set_background_color) {
- set_background_color = rhs.set_background_color;
- background_color = rhs.background_color;
- } else if (rhs.set_background_color) {
- if (!background_color.is_rgb || !rhs.background_color.is_rgb)
- FMT_THROW(format_error("can't AND a terminal color"));
- background_color.value.rgb_color &= rhs.background_color.value.rgb_color;
- }
-
- ems = static_cast<emphasis>(static_cast<uint8_t>(ems) &
- static_cast<uint8_t>(rhs.ems));
- return *this;
- }
-
- friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
- FMT_NOEXCEPT;
-
- friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
- FMT_NOEXCEPT;
+ friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept;
detail::color_type foreground_color;
detail::color_type background_color;
@@ -359,17 +310,16 @@
};
/** Creates a text style from the foreground (text) color. */
-FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
+FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
return text_style(true, foreground);
}
/** Creates a text style from the background color. */
-FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
+FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
return text_style(false, background);
}
-FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
- emphasis rhs) FMT_NOEXCEPT {
+FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
return text_style(lhs) | rhs;
}
@@ -377,7 +327,7 @@
template <typename Char> struct ansi_color_escape {
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
- const char* esc) FMT_NOEXCEPT {
+ const char* esc) noexcept {
// If we have a terminal color, we need to output another escape code
// sequence.
if (!text_color.is_rgb) {
@@ -412,7 +362,7 @@
to_esc(color.b, buffer + 15, 'm');
buffer[19] = static_cast<Char>(0);
}
- FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
+ FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
uint8_t em_codes[num_emphases] = {};
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
@@ -433,10 +383,10 @@
}
buffer[index++] = static_cast<Char>(0);
}
- FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
+ FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
- FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
- FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
+ FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
+ FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
return buffer + std::char_traits<Char>::length(buffer);
}
@@ -445,59 +395,64 @@
Char buffer[7u + 3u * num_emphases + 1u];
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
- char delimiter) FMT_NOEXCEPT {
+ char delimiter) noexcept {
out[0] = static_cast<Char>('0' + c / 100);
out[1] = static_cast<Char>('0' + c / 10 % 10);
out[2] = static_cast<Char>('0' + c % 10);
out[3] = static_cast<Char>(delimiter);
}
- static FMT_CONSTEXPR bool has_emphasis(emphasis em,
- emphasis mask) FMT_NOEXCEPT {
+ static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
}
};
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
- detail::color_type foreground) FMT_NOEXCEPT {
+ detail::color_type foreground) noexcept {
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
}
template <typename Char>
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
- detail::color_type background) FMT_NOEXCEPT {
+ detail::color_type background) noexcept {
return ansi_color_escape<Char>(background, "\x1b[48;2;");
}
template <typename Char>
-FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
+FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
return ansi_color_escape<Char>(em);
}
-template <typename Char>
-inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
- std::fputs(chars, stream);
+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) FMT_NOEXCEPT {
- std::fputws(chars, stream);
+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) FMT_NOEXCEPT {
+template <typename Char> inline void reset_color(FILE* stream) {
fputs("\x1b[0m", stream);
}
-template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
+template <> inline void reset_color<wchar_t>(FILE* stream) {
fputs(L"\x1b[0m", stream);
}
-template <typename Char>
-inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
+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());
}
+template <typename T> struct styled_arg {
+ const T& value;
+ text_style style;
+};
+
template <typename Char>
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
@@ -528,9 +483,13 @@
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, to_string_view(format), args);
- buf.push_back(Char(0));
- detail::fputs(buf.data(), f);
+ detail::vformat_to(buf, ts, detail::to_string_view(format), 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);
+ }
}
/**
@@ -549,7 +508,7 @@
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
vprint(f, ts, format_str,
- fmt::make_args_checked<Args...>(format_str, args...));
+ fmt::make_format_args<buffer_context<char_t<S>>>(args...));
}
/**
@@ -574,7 +533,7 @@
const text_style& ts, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
- detail::vformat_to(buf, ts, to_string_view(format_str), args);
+ detail::vformat_to(buf, ts, detail::to_string_view(format_str), args);
return fmt::to_string(buf);
}
@@ -593,8 +552,8 @@
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
- return fmt::vformat(ts, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
+ return fmt::vformat(ts, detail::to_string_view(format_str),
+ fmt::make_format_args<buffer_context<Char>>(args...));
}
/**
@@ -628,8 +587,62 @@
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
- return vformat_to(out, ts, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
+ return vformat_to(out, ts, detail::to_string_view(format_str),
+ fmt::make_format_args<buffer_context<char_t<S>>>(args...));
+}
+
+template <typename T, typename Char>
+struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
+ template <typename FormatContext>
+ auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
+ -> decltype(ctx.out()) {
+ const auto& ts = arg.style;
+ const auto& value = arg.value;
+ auto out = ctx.out();
+
+ bool has_style = false;
+ if (ts.has_emphasis()) {
+ has_style = true;
+ auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
+ out = std::copy(emphasis.begin(), emphasis.end(), out);
+ }
+ if (ts.has_foreground()) {
+ has_style = true;
+ auto foreground =
+ detail::make_foreground_color<Char>(ts.get_foreground());
+ out = std::copy(foreground.begin(), foreground.end(), out);
+ }
+ if (ts.has_background()) {
+ has_style = true;
+ auto background =
+ detail::make_background_color<Char>(ts.get_background());
+ out = std::copy(background.begin(), background.end(), out);
+ }
+ out = formatter<T, Char>::format(value, ctx);
+ if (has_style) {
+ auto reset_color = string_view("\x1b[0m");
+ out = std::copy(reset_color.begin(), reset_color.end(), out);
+ }
+ return out;
+ }
+};
+
+/**
+ \rst
+ Returns an argument that will be formatted using ANSI escape sequences,
+ to be used in a formatting function.
+
+ **Example**::
+
+ fmt::print("Elapsed time: {0:.2f} seconds",
+ fmt::styled(1.23, fmt::fg(fmt::color::green) |
+ fmt::bg(fmt::color::blue)));
+ \endrst
+ */
+template <typename T>
+FMT_CONSTEXPR auto styled(const T& value, text_style ts)
+ -> detail::styled_arg<remove_cvref_t<T>> {
+ return detail::styled_arg<remove_cvref_t<T>>{value, ts};
}
FMT_MODULE_EXPORT_END
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/compile.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
similarity index 88%
rename from wpiutil/src/main/native/fmtlib/include/fmt/compile.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
index 1dba3dd..933668c 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/compile.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/compile.h
@@ -13,48 +13,9 @@
FMT_BEGIN_NAMESPACE
namespace detail {
-// An output iterator that counts the number of objects written to it and
-// discards them.
-class counting_iterator {
- private:
- size_t count_;
-
- public:
- using iterator_category = std::output_iterator_tag;
- using difference_type = std::ptrdiff_t;
- using pointer = void;
- using reference = void;
- using _Unchecked_type = counting_iterator; // Mark iterator as checked.
-
- struct value_type {
- template <typename T> void operator=(const T&) {}
- };
-
- counting_iterator() : count_(0) {}
-
- size_t count() const { return count_; }
-
- counting_iterator& operator++() {
- ++count_;
- return *this;
- }
- counting_iterator operator++(int) {
- auto it = *this;
- ++*this;
- return it;
- }
-
- friend counting_iterator operator+(counting_iterator it, difference_type n) {
- it.count_ += static_cast<size_t>(n);
- return it;
- }
-
- value_type operator*() const { return {}; }
-};
-
template <typename Char, typename InputIt>
-inline counting_iterator copy_str(InputIt begin, InputIt end,
- counting_iterator it) {
+FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end,
+ counting_iterator it) {
return it + (end - begin);
}
@@ -75,8 +36,7 @@
using difference_type = std::ptrdiff_t;
using pointer = void;
using reference = void;
- using _Unchecked_type =
- truncating_iterator_base; // Mark iterator as checked.
+ FMT_UNCHECKED_ITERATOR(truncating_iterator_base);
OutputIt base() const { return out_; }
size_t count() const { return count_; }
@@ -163,12 +123,12 @@
# define FMT_COMPILE(s) FMT_STRING(s)
#endif
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct udl_compiled_string : compiled_string {
using char_type = Char;
- constexpr operator basic_string_view<char_type>() const {
+ explicit constexpr operator basic_string_view<char_type>() const {
return {Str.data, N - 1};
}
};
@@ -377,10 +337,11 @@
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 = basic_format_parse_context<Char>(str, {}, 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()) + 1,
+ return {f, pos + fmt::detail::to_unsigned(end - str.data()),
next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()};
}
@@ -436,13 +397,20 @@
return parse_tail<Args, END_POS + 1, NEXT_ID>(
field<char_type, typename field_type<T>::type, ARG_INDEX>(),
format_str);
- } else if constexpr (c == ':') {
+ } else if constexpr (c != ':') {
+ FMT_THROW(format_error("expected ':'"));
+ } else {
constexpr auto result = parse_specs<typename field_type<T>::type>(
str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID);
- return parse_tail<Args, result.end, result.next_arg_id>(
- spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
- result.fmt},
- format_str);
+ if constexpr (result.end >= str.size() || str[result.end] != '}') {
+ FMT_THROW(format_error("expected '}'"));
+ return 0;
+ } else {
+ return parse_tail<Args, result.end + 1, result.next_arg_id>(
+ spec_field<char_type, typename field_type<T>::type, ARG_INDEX>{
+ result.fmt},
+ format_str);
+ }
}
}
@@ -573,10 +541,11 @@
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
- return format(static_cast<basic_string_view<typename S::char_type>>(S()),
- std::forward<Args>(args)...);
+ return fmt::format(
+ static_cast<basic_string_view<typename S::char_type>>(S()),
+ std::forward<Args>(args)...);
} else {
- return format(compiled, std::forward<Args>(args)...);
+ return fmt::format(compiled, std::forward<Args>(args)...);
}
}
@@ -586,11 +555,11 @@
constexpr auto compiled = detail::compile<Args...>(S());
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
detail::unknown_format>()) {
- return format_to(out,
- static_cast<basic_string_view<typename S::char_type>>(S()),
- std::forward<Args>(args)...);
+ return fmt::format_to(
+ out, static_cast<basic_string_view<typename S::char_type>>(S()),
+ std::forward<Args>(args)...);
} else {
- return format_to(out, compiled, std::forward<Args>(args)...);
+ return fmt::format_to(out, compiled, std::forward<Args>(args)...);
}
}
#endif
@@ -599,22 +568,24 @@
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 = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
- std::forward<Args>(args)...);
+ auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
+ format_str, std::forward<Args>(args)...);
return {it.base(), it.count()};
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
-size_t formatted_size(const S& format_str, const Args&... args) {
- return format_to(detail::counting_iterator(), format_str, args...).count();
+FMT_CONSTEXPR20 size_t formatted_size(const S& format_str,
+ const Args&... args) {
+ return fmt::format_to(detail::counting_iterator(), format_str, args...)
+ .count();
}
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
void print(std::FILE* f, const S& format_str, const Args&... args) {
memory_buffer buffer;
- format_to(std::back_inserter(buffer), format_str, args...);
+ fmt::format_to(std::back_inserter(buffer), format_str, args...);
detail::print(f, {buffer.data(), buffer.size()});
}
@@ -624,14 +595,12 @@
print(stdout, format_str, args...);
}
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#if FMT_USE_NONTYPE_TEMPLATE_ARGS
inline namespace literals {
-template <detail_exported::fixed_string Str>
-constexpr detail::udl_compiled_string<
- remove_cvref_t<decltype(Str.data[0])>,
- sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
-operator""_cf() {
- return {};
+template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
+ using char_t = remove_cvref_t<decltype(Str.data[0])>;
+ return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
+ Str>();
}
} // namespace literals
#endif
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/core.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
similarity index 85%
rename from wpiutil/src/main/native/fmtlib/include/fmt/core.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
index 92a7aa1..5c210bc 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/core.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/core.h
@@ -10,14 +10,14 @@
#include <cstddef> // std::byte
#include <cstdio> // std::FILE
-#include <cstring>
+#include <cstring> // std::strlen
#include <iterator>
#include <limits>
#include <string>
#include <type_traits>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
-#define FMT_VERSION 80101
+#define FMT_VERSION 90100
#if defined(__clang__) && !defined(__ibmxl__)
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
@@ -49,29 +49,29 @@
# define FMT_ICC_VERSION 0
#endif
-#ifdef __NVCC__
-# define FMT_NVCC __NVCC__
-#else
-# define FMT_NVCC 0
-#endif
-
#ifdef _MSC_VER
-# define FMT_MSC_VER _MSC_VER
+# define FMT_MSC_VERSION _MSC_VER
# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__))
#else
-# define FMT_MSC_VER 0
+# define FMT_MSC_VERSION 0
# define FMT_MSC_WARNING(...)
#endif
+#ifdef _MSVC_LANG
+# define FMT_CPLUSPLUS _MSVC_LANG
+#else
+# define FMT_CPLUSPLUS __cplusplus
+#endif
+
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
#else
# define FMT_HAS_FEATURE(x) 0
#endif
-#if defined(__has_include) && \
- (!defined(__INTELLISENSE__) || FMT_MSC_VER > 1900) && \
- (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
+#if (defined(__has_include) || FMT_ICC_VERSION >= 1600 || \
+ FMT_MSC_VERSION > 1900) && \
+ !defined(__INTELLISENSE__)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
@@ -83,12 +83,6 @@
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
-#ifdef _MSVC_LANG
-# define FMT_CPLUSPLUS _MSVC_LANG
-#else
-# define FMT_CPLUSPLUS __cplusplus
-#endif
-
#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \
(FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute))
@@ -98,37 +92,38 @@
// Check if relaxed C++14 constexpr is supported.
// GCC doesn't allow throw in constexpr until version 6 (bug 67371).
#ifndef FMT_USE_CONSTEXPR
-# define FMT_USE_CONSTEXPR \
- (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1912 || \
- (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \
- !FMT_NVCC && !FMT_ICC_VERSION
+# if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \
+ (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \
+ !FMT_ICC_VERSION && !defined(__NVCC__)
+# define FMT_USE_CONSTEXPR 1
+# else
+# define FMT_USE_CONSTEXPR 0
+# endif
#endif
#if FMT_USE_CONSTEXPR
# define FMT_CONSTEXPR constexpr
-# define FMT_CONSTEXPR_DECL constexpr
#else
# define FMT_CONSTEXPR
-# define FMT_CONSTEXPR_DECL
#endif
-#if ((__cplusplus >= 202002L) && \
+#if ((FMT_CPLUSPLUS >= 202002L) && \
(!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \
- (__cplusplus >= 201709L && FMT_GCC_VERSION >= 1002)
+ (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002)
# define FMT_CONSTEXPR20 constexpr
#else
# define FMT_CONSTEXPR20
#endif
-// Check if constexpr std::char_traits<>::compare,length is supported.
+// Check if constexpr std::char_traits<>::{compare,length} are supported.
#if defined(__GLIBCXX__)
-# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \
+# if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \
_GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE.
# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
# endif
-#elif defined(_LIBCPP_VERSION) && __cplusplus >= 201703L && \
+#elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \
_LIBCPP_VERSION >= 4000
# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
-#elif FMT_MSC_VER >= 1914 && _MSVC_LANG >= 201703L
+#elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L
# define FMT_CONSTEXPR_CHAR_TRAITS constexpr
#endif
#ifndef FMT_CONSTEXPR_CHAR_TRAITS
@@ -138,57 +133,43 @@
// Check if exceptions are disabled.
#ifndef FMT_EXCEPTIONS
# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \
- FMT_MSC_VER && !_HAS_EXCEPTIONS
+ (FMT_MSC_VERSION && !_HAS_EXCEPTIONS)
# define FMT_EXCEPTIONS 0
# else
# define FMT_EXCEPTIONS 1
# endif
#endif
-// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature).
-#ifndef FMT_USE_NOEXCEPT
-# define FMT_USE_NOEXCEPT 0
-#endif
-
-#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
- FMT_GCC_VERSION >= 408 || FMT_MSC_VER >= 1900
-# define FMT_DETECTED_NOEXCEPT noexcept
-# define FMT_HAS_CXX11_NOEXCEPT 1
-#else
-# define FMT_DETECTED_NOEXCEPT throw()
-# define FMT_HAS_CXX11_NOEXCEPT 0
-#endif
-
-#ifndef FMT_NOEXCEPT
-# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT
-# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT
+#ifndef FMT_DEPRECATED
+# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900
+# define FMT_DEPRECATED [[deprecated]]
# else
-# define FMT_NOEXCEPT
+# 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.
-#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \
- !FMT_NVCC
+#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \
+ !defined(__NVCC__)
# define FMT_NORETURN [[noreturn]]
#else
# define FMT_NORETURN
#endif
-#if __cplusplus == 201103L || __cplusplus == 201402L
-# if defined(__INTEL_COMPILER) || defined(__PGI)
-# define FMT_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
-#elif FMT_HAS_CPP17_ATTRIBUTE(fallthrough)
+#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
@@ -219,24 +200,20 @@
# endif
#endif
-#ifndef FMT_DEPRECATED
-# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
-# define FMT_DEPRECATED [[deprecated]]
-# else
-# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
-# define FMT_DEPRECATED __attribute__((deprecated))
-# elif FMT_MSC_VER
-# define FMT_DEPRECATED __declspec(deprecated)
-# else
-# define FMT_DEPRECATED /* deprecated */
-# 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.
+#else
+# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It
#endif
#ifndef FMT_BEGIN_NAMESPACE
# define FMT_BEGIN_NAMESPACE \
namespace fmt { \
- inline namespace v8 {
+ inline namespace v9 {
# define FMT_END_NAMESPACE \
} \
}
@@ -270,25 +247,24 @@
#endif
// libc++ supports string_view in pre-c++17.
-#if (FMT_HAS_INCLUDE(<string_view>) && \
- (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \
- (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910)
+#if FMT_HAS_INCLUDE(<string_view>) && \
+ (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION))
# include <string_view>
# define FMT_USE_STRING_VIEW
-#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L
+#elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L
# include <experimental/string_view>
# define FMT_USE_EXPERIMENTAL_STRING_VIEW
#endif
#ifndef FMT_UNICODE
-# define FMT_UNICODE !FMT_MSC_VER
+# define FMT_UNICODE !FMT_MSC_VERSION
#endif
#ifndef FMT_CONSTEVAL
-# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
- __cplusplus > 201703L && !defined(__apple_build_version__)) || \
- (defined(__cpp_consteval) && \
- (!FMT_MSC_VER || _MSC_FULL_VER >= 193030704))
+# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \
+ FMT_CPLUSPLUS >= 202002L && !defined(__apple_build_version__)) || \
+ (defined(__cpp_consteval) && \
+ (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704))
// consteval is broken in MSVC before VS2022 and Apple clang 13.
# define FMT_CONSTEVAL consteval
# define FMT_HAS_CONSTEVAL
@@ -297,19 +273,20 @@
# endif
#endif
-#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-# if defined(__cpp_nontype_template_args) && \
- ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \
- __cpp_nontype_template_args >= 201911L)
-# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1
+#ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS
+# if defined(__cpp_nontype_template_args) && \
+ ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \
+ __cpp_nontype_template_args >= 201911L) && \
+ !defined(__NVCOMPILER)
+# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1
# else
-# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0
+# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0
# endif
#endif
// Enable minimal optimizations for more compact code in debug mode.
FMT_GCC_PRAGMA("GCC push_options")
-#ifndef __OPTIMIZE__
+#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER)
FMT_GCC_PRAGMA("GCC optimize(\"Og\")")
#endif
@@ -330,6 +307,20 @@
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
template <typename T> struct type_identity { using type = T; };
template <typename T> using type_identity_t = typename type_identity<T>::type;
+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> {};
struct monostate {
constexpr monostate() {}
@@ -346,13 +337,13 @@
FMT_BEGIN_DETAIL_NAMESPACE
-// Suppress "unused variable" warnings with the method described in
+// 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.
template <typename... T> FMT_CONSTEXPR void ignore_unused(const T&...) {}
-constexpr FMT_INLINE auto is_constant_evaluated(bool default_value = false)
- FMT_NOEXCEPT -> bool {
+constexpr FMT_INLINE auto is_constant_evaluated(
+ bool default_value = false) noexcept -> bool {
#ifdef __cpp_lib_is_constant_evaluated
ignore_unused(default_value);
return std::is_constant_evaluated();
@@ -361,7 +352,7 @@
#endif
}
-// A function to suppress "conditional expression is constant" warnings.
+// Suppresses "conditional expression is constant" warnings.
template <typename T> constexpr FMT_INLINE auto const_check(T value) -> T {
return value;
}
@@ -371,7 +362,7 @@
#ifndef FMT_ASSERT
# ifdef NDEBUG
-// FMT_ASSERT is not empty to avoid -Werror=empty-body.
+// FMT_ASSERT is not empty to avoid -Wempty-body.
# define FMT_ASSERT(condition, message) \
::fmt::detail::ignore_unused((condition), (message))
# else
@@ -382,12 +373,6 @@
# endif
#endif
-#ifdef __cpp_lib_byte
-using byte = std::byte;
-#else
-enum class byte : unsigned char {};
-#endif
-
#if defined(FMT_USE_STRING_VIEW)
template <typename Char> using std_string_view = std::basic_string_view<Char>;
#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW)
@@ -399,11 +384,11 @@
#ifdef FMT_USE_INT128
// Do nothing.
-#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
- !(FMT_CLANG_VERSION && FMT_MSC_VER)
+#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \
+ !(FMT_CLANG_VERSION && FMT_MSC_VERSION)
# define FMT_USE_INT128 1
-using int128_t = __int128_t;
-using uint128_t = __uint128_t;
+using int128_opt = __int128_t; // An optional native 128-bit integer.
+using uint128_opt = __uint128_t;
template <typename T> inline auto convert_for_visit(T value) -> T {
return value;
}
@@ -411,27 +396,24 @@
# define FMT_USE_INT128 0
#endif
#if !FMT_USE_INT128
-enum class int128_t {};
-enum class uint128_t {};
+enum class int128_opt {};
+enum class uint128_opt {};
// Reduce template instantiations.
-template <typename T> inline auto convert_for_visit(T) -> monostate {
- return {};
-}
+template <typename T> auto convert_for_visit(T) -> monostate { return {}; }
#endif
// Casts a nonnegative integer to unsigned.
template <typename Int>
FMT_CONSTEXPR auto to_unsigned(Int value) ->
typename std::make_unsigned<Int>::type {
- FMT_ASSERT(value >= 0, "negative value");
+ FMT_ASSERT(std::is_unsigned<Int>::value || value >= 0, "negative value");
return static_cast<typename std::make_unsigned<Int>::type>(value);
}
FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5";
constexpr auto is_utf8() -> bool {
- // Avoid buggy sign extensions in MSVC's constant evaluation mode.
- // https://developercommunity.visualstudio.com/t/C-difference-in-behavior-for-unsigned/1233612
+ // 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);
@@ -454,12 +436,11 @@
using value_type = Char;
using iterator = const Char*;
- constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {}
+ constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {}
/** Constructs a string reference object from a C string and a size. */
- constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT
- : data_(s),
- size_(count) {}
+ constexpr basic_string_view(const Char* s, size_t count) noexcept
+ : data_(s), size_(count) {}
/**
\rst
@@ -479,29 +460,28 @@
/** Constructs a string reference from a ``std::basic_string`` object. */
template <typename Traits, typename Alloc>
FMT_CONSTEXPR basic_string_view(
- const std::basic_string<Char, Traits, Alloc>& s) FMT_NOEXCEPT
- : data_(s.data()),
- size_(s.size()) {}
+ const std::basic_string<Char, Traits, Alloc>& s) noexcept
+ : data_(s.data()), size_(s.size()) {}
template <typename S, FMT_ENABLE_IF(std::is_same<
S, detail::std_string_view<Char>>::value)>
- FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()),
- size_(s.size()) {}
+ FMT_CONSTEXPR basic_string_view(S s) noexcept
+ : data_(s.data()), size_(s.size()) {}
/** Returns a pointer to the string data. */
- constexpr auto data() const FMT_NOEXCEPT -> const Char* { return data_; }
+ constexpr auto data() const noexcept -> const Char* { return data_; }
/** Returns the string size. */
- constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
+ constexpr auto size() const noexcept -> size_t { return size_; }
- constexpr auto begin() const FMT_NOEXCEPT -> iterator { return data_; }
- constexpr auto end() const FMT_NOEXCEPT -> iterator { return data_ + size_; }
+ constexpr auto begin() const noexcept -> iterator { return data_; }
+ constexpr auto end() const noexcept -> iterator { return data_ + size_; }
- constexpr auto operator[](size_t pos) const FMT_NOEXCEPT -> const Char& {
+ constexpr auto operator[](size_t pos) const noexcept -> const Char& {
return data_[pos];
}
- FMT_CONSTEXPR void remove_prefix(size_t n) FMT_NOEXCEPT {
+ FMT_CONSTEXPR void remove_prefix(size_t n) noexcept {
data_ += n;
size_ -= n;
}
@@ -543,6 +523,14 @@
template <typename T> struct is_char : std::false_type {};
template <> struct is_char<char> : std::true_type {};
+FMT_BEGIN_DETAIL_NAMESPACE
+
+// A base class for compile-time strings.
+struct compile_string {};
+
+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> {
@@ -559,33 +547,21 @@
return s;
}
template <typename Char,
- FMT_ENABLE_IF(!std::is_empty<detail::std_string_view<Char>>::value)>
-inline auto to_string_view(detail::std_string_view<Char> s)
- -> basic_string_view<Char> {
+ FMT_ENABLE_IF(!std::is_empty<std_string_view<Char>>::value)>
+inline auto to_string_view(std_string_view<Char> s) -> basic_string_view<Char> {
return s;
}
-
-// A base class for compile-time strings. It is defined in the fmt namespace to
-// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42).
-struct compile_string {};
-
-template <typename S>
-struct is_compile_string : std::is_base_of<compile_string, S> {};
-
template <typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
constexpr auto to_string_view(const S& s)
-> basic_string_view<typename S::char_type> {
return basic_string_view<typename S::char_type>(s);
}
-
-FMT_BEGIN_DETAIL_NAMESPACE
-
void to_string_view(...);
-using fmt::to_string_view;
// 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!
template <typename S>
struct is_string : std::is_class<decltype(to_string_view(std::declval<S>()))> {
};
@@ -596,17 +572,60 @@
using type = typename result::value_type;
};
-// Reports a compile-time error if S is not a valid format string.
-template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
-FMT_INLINE void check_format_string(const S&) {
-#ifdef FMT_ENFORCE_COMPILE_STRING
- static_assert(is_compile_string<S>::value,
- "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
- "FMT_STRING.");
-#endif
+enum class type {
+ none_type,
+ // Integer types should go first,
+ int_type,
+ uint_type,
+ long_long_type,
+ ulong_long_type,
+ int128_type,
+ uint128_type,
+ bool_type,
+ char_type,
+ last_integer_type = char_type,
+ // followed by floating-point types.
+ float_type,
+ double_type,
+ long_double_type,
+ last_numeric_type = long_double_type,
+ cstring_type,
+ string_type,
+ pointer_type,
+ custom_type
+};
+
+// Maps core type T to the corresponding type enum constant.
+template <typename T, typename Char>
+struct type_constant : std::integral_constant<type, type::custom_type> {};
+
+#define FMT_TYPE_CONSTANT(Type, constant) \
+ template <typename Char> \
+ struct type_constant<Type, Char> \
+ : std::integral_constant<type, type::constant> {}
+
+FMT_TYPE_CONSTANT(int, int_type);
+FMT_TYPE_CONSTANT(unsigned, uint_type);
+FMT_TYPE_CONSTANT(long long, long_long_type);
+FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
+FMT_TYPE_CONSTANT(int128_opt, int128_type);
+FMT_TYPE_CONSTANT(uint128_opt, uint128_type);
+FMT_TYPE_CONSTANT(bool, bool_type);
+FMT_TYPE_CONSTANT(Char, char_type);
+FMT_TYPE_CONSTANT(float, float_type);
+FMT_TYPE_CONSTANT(double, double_type);
+FMT_TYPE_CONSTANT(long double, long_double_type);
+FMT_TYPE_CONSTANT(const Char*, cstring_type);
+FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
+FMT_TYPE_CONSTANT(const void*, pointer_type);
+
+constexpr bool is_integral_type(type t) {
+ return t > type::none_type && t <= type::last_integer_type;
}
-template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
-void check_format_string(S);
+
+constexpr bool is_arithmetic_type(type t) {
+ return t > type::none_type && t <= type::last_numeric_type;
+}
FMT_NORETURN FMT_API void throw_format_error(const char* message);
@@ -615,7 +634,9 @@
constexpr error_handler(const error_handler&) = default;
// This function is intentionally not constexpr to give a compile-time error.
- FMT_NORETURN FMT_API void on_error(const char* message);
+ FMT_NORETURN void on_error(const char* message) {
+ throw_format_error(message);
+ }
};
FMT_END_DETAIL_NAMESPACE
@@ -635,6 +656,8 @@
basic_string_view<Char> format_str_;
int next_arg_id_;
+ FMT_CONSTEXPR void do_check_arg_id(int id);
+
public:
using char_type = Char;
using iterator = typename basic_string_view<Char>::iterator;
@@ -648,16 +671,14 @@
Returns an iterator to the beginning of the format string range being
parsed.
*/
- constexpr auto begin() const FMT_NOEXCEPT -> iterator {
+ constexpr auto begin() const noexcept -> iterator {
return format_str_.begin();
}
/**
Returns an iterator past the end of the format string range being parsed.
*/
- constexpr auto end() const FMT_NOEXCEPT -> iterator {
- return format_str_.end();
- }
+ constexpr auto end() const noexcept -> iterator { return format_str_.end(); }
/** Advances the begin iterator to ``it``. */
FMT_CONSTEXPR void advance_to(iterator it) {
@@ -669,25 +690,29 @@
the next argument index and switches to the automatic indexing.
*/
FMT_CONSTEXPR auto next_arg_id() -> int {
- // Don't check if the argument id is valid to avoid overhead and because it
- // will be checked during formatting anyway.
- if (next_arg_id_ >= 0) return next_arg_id_++;
- on_error("cannot switch from manual to automatic argument indexing");
- return 0;
+ if (next_arg_id_ < 0) {
+ on_error("cannot switch from manual to automatic argument indexing");
+ return 0;
+ }
+ int id = next_arg_id_++;
+ do_check_arg_id(id);
+ return id;
}
/**
Reports an error if using the automatic argument indexing; otherwise
switches to the manual indexing.
*/
- FMT_CONSTEXPR void check_arg_id(int) {
- if (next_arg_id_ > 0)
+ FMT_CONSTEXPR void check_arg_id(int id) {
+ if (next_arg_id_ > 0) {
on_error("cannot switch from automatic to manual argument indexing");
- else
- next_arg_id_ = -1;
+ return;
+ }
+ next_arg_id_ = -1;
+ do_check_arg_id(id);
}
-
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);
@@ -698,6 +723,65 @@
using format_parse_context = basic_format_parse_context<char>;
+FMT_BEGIN_DETAIL_NAMESPACE
+// 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> {
+ private:
+ int num_args_;
+ const type* types_;
+ using base = basic_format_parse_context<Char, ErrorHandler>;
+
+ 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) {}
+
+ 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");
+ 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");
+ }
+ using base::check_arg_id;
+
+ FMT_CONSTEXPR void check_dynamic_spec(int arg_id) {
+ if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id]))
+ this->on_error("width/precision is not integer");
+ }
+};
+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;
@@ -744,10 +828,10 @@
template <typename Container>
inline auto get_container(std::back_insert_iterator<Container> it)
-> Container& {
- using bi_iterator = std::back_insert_iterator<Container>;
- struct accessor : bi_iterator {
- accessor(bi_iterator iter) : bi_iterator(iter) {}
- using bi_iterator::container;
+ using base = std::back_insert_iterator<Container>;
+ struct accessor : base {
+ accessor(base b) : base(b) {}
+ using base::container;
};
return *accessor(it).container;
}
@@ -784,18 +868,16 @@
protected:
// Don't initialize ptr_ since it is not accessed to save a few cycles.
FMT_MSC_WARNING(suppress : 26495)
- buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {}
+ buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {}
- FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0,
- size_t cap = 0) FMT_NOEXCEPT : ptr_(p),
- size_(sz),
- capacity_(cap) {}
+ FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept
+ : ptr_(p), size_(sz), capacity_(cap) {}
FMT_CONSTEXPR20 ~buffer() = default;
buffer(buffer&&) = default;
/** Sets the buffer data and capacity. */
- FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
+ FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept {
ptr_ = buf_data;
capacity_ = buf_capacity;
}
@@ -810,23 +892,23 @@
buffer(const buffer&) = delete;
void operator=(const buffer&) = delete;
- auto begin() FMT_NOEXCEPT -> T* { return ptr_; }
- auto end() FMT_NOEXCEPT -> T* { return ptr_ + size_; }
+ auto begin() noexcept -> T* { return ptr_; }
+ auto end() noexcept -> T* { return ptr_ + size_; }
- auto begin() const FMT_NOEXCEPT -> const T* { return ptr_; }
- auto end() const FMT_NOEXCEPT -> const T* { return ptr_ + size_; }
+ auto begin() const noexcept -> const T* { return ptr_; }
+ auto end() const noexcept -> const T* { return ptr_ + size_; }
/** Returns the size of this buffer. */
- constexpr auto size() const FMT_NOEXCEPT -> size_t { return size_; }
+ constexpr auto size() const noexcept -> size_t { return size_; }
/** Returns the capacity of this buffer. */
- constexpr auto capacity() const FMT_NOEXCEPT -> size_t { return capacity_; }
+ constexpr auto capacity() const noexcept -> size_t { return capacity_; }
/** Returns a pointer to the buffer data. */
- FMT_CONSTEXPR auto data() FMT_NOEXCEPT -> T* { return ptr_; }
+ FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; }
/** Returns a pointer to the buffer data. */
- FMT_CONSTEXPR auto data() const FMT_NOEXCEPT -> const T* { return ptr_; }
+ FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; }
/** Clears this buffer. */
void clear() { size_ = 0; }
@@ -854,11 +936,11 @@
/** Appends data to the end of the buffer. */
template <typename U> void append(const U* begin, const U* end);
- template <typename I> FMT_CONSTEXPR auto operator[](I index) -> T& {
+ template <typename Idx> FMT_CONSTEXPR auto operator[](Idx index) -> T& {
return ptr_[index];
}
- template <typename I>
- FMT_CONSTEXPR auto operator[](I index) const -> const T& {
+ template <typename Idx>
+ FMT_CONSTEXPR auto operator[](Idx index) const -> const T& {
return ptr_[index];
}
};
@@ -993,6 +1075,7 @@
: buffer<typename Container::value_type>(c.size()), container_(c) {}
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
: iterator_buffer(get_container(out)) {}
+
auto out() -> std::back_insert_iterator<Container> {
return std::back_inserter(container_);
}
@@ -1044,7 +1127,11 @@
// 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 {};
@@ -1128,61 +1215,6 @@
return count<is_statically_named_arg<Args>::value...>();
}
-enum class type {
- none_type,
- // Integer types should go first,
- int_type,
- uint_type,
- long_long_type,
- ulong_long_type,
- int128_type,
- uint128_type,
- bool_type,
- char_type,
- last_integer_type = char_type,
- // followed by floating-point types.
- float_type,
- double_type,
- long_double_type,
- last_numeric_type = long_double_type,
- cstring_type,
- string_type,
- pointer_type,
- custom_type
-};
-
-// Maps core type T to the corresponding type enum constant.
-template <typename T, typename Char>
-struct type_constant : std::integral_constant<type, type::custom_type> {};
-
-#define FMT_TYPE_CONSTANT(Type, constant) \
- template <typename Char> \
- struct type_constant<Type, Char> \
- : std::integral_constant<type, type::constant> {}
-
-FMT_TYPE_CONSTANT(int, int_type);
-FMT_TYPE_CONSTANT(unsigned, uint_type);
-FMT_TYPE_CONSTANT(long long, long_long_type);
-FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type);
-FMT_TYPE_CONSTANT(int128_t, int128_type);
-FMT_TYPE_CONSTANT(uint128_t, uint128_type);
-FMT_TYPE_CONSTANT(bool, bool_type);
-FMT_TYPE_CONSTANT(Char, char_type);
-FMT_TYPE_CONSTANT(float, float_type);
-FMT_TYPE_CONSTANT(double, double_type);
-FMT_TYPE_CONSTANT(long double, long_double_type);
-FMT_TYPE_CONSTANT(const Char*, cstring_type);
-FMT_TYPE_CONSTANT(basic_string_view<Char>, string_type);
-FMT_TYPE_CONSTANT(const void*, pointer_type);
-
-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;
-}
-
struct unformattable {};
struct unformattable_char : unformattable {};
struct unformattable_const : unformattable {};
@@ -1215,8 +1247,8 @@
unsigned uint_value;
long long long_long_value;
unsigned long long ulong_long_value;
- int128_t int128_value;
- uint128_t uint128_value;
+ int128_opt int128_value;
+ uint128_opt uint128_value;
bool bool_value;
char_type char_value;
float float_value;
@@ -1233,8 +1265,8 @@
constexpr FMT_INLINE value(unsigned val) : uint_value(val) {}
constexpr FMT_INLINE value(long long val) : long_long_value(val) {}
constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {}
- FMT_INLINE value(int128_t val) : int128_value(val) {}
- FMT_INLINE value(uint128_t val) : uint128_value(val) {}
+ FMT_INLINE value(int128_opt val) : int128_value(val) {}
+ FMT_INLINE value(uint128_opt val) : uint128_value(val) {}
constexpr FMT_INLINE value(float val) : float_value(val) {}
constexpr FMT_INLINE value(double val) : double_value(val) {}
FMT_INLINE value(long double val) : long_double_value(val) {}
@@ -1284,7 +1316,7 @@
};
template <typename Context, typename T>
-FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context>;
+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.
@@ -1292,6 +1324,21 @@
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 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 };
+};
+
// Maps formatting arguments to core types.
// arg_mapper reports errors by returning unformattable instead of using
// static_assert because it's used in the is_formattable trait.
@@ -1317,8 +1364,12 @@
-> unsigned long long {
return val;
}
- FMT_CONSTEXPR FMT_INLINE auto map(int128_t val) -> int128_t { return val; }
- FMT_CONSTEXPR FMT_INLINE auto map(uint128_t val) -> uint128_t { return val; }
+ FMT_CONSTEXPR FMT_INLINE auto map(int128_opt val) -> int128_opt {
+ return val;
+ }
+ FMT_CONSTEXPR FMT_INLINE auto map(uint128_opt val) -> uint128_opt {
+ return val;
+ }
FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; }
template <typename T, FMT_ENABLE_IF(std::is_same<T, char>::value ||
@@ -1365,45 +1416,24 @@
}
template <typename T,
FMT_ENABLE_IF(
- std::is_constructible<basic_string_view<char_type>, T>::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 basic_string_view<char_type>(val);
}
- template <
- typename T,
- FMT_ENABLE_IF(
- std::is_constructible<std_string_view<char_type>, T>::value &&
- !std::is_constructible<basic_string_view<char_type>, T>::value &&
- !is_string<T>::value && !has_formatter<T, Context>::value &&
- !has_fallback_formatter<T, char_type>::value)>
+ 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);
}
- using cstring_result = conditional_t<std::is_same<char_type, char>::value,
- const char*, unformattable_pointer>;
-
- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const signed char* val)
- -> cstring_result {
- return map(reinterpret_cast<const char*>(val));
- }
- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const unsigned char* val)
- -> cstring_result {
- return map(reinterpret_cast<const char*>(val));
- }
- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(signed char* val)
- -> cstring_result {
- return map(reinterpret_cast<const char*>(val));
- }
- FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(unsigned char* val)
- -> cstring_result {
- return map(reinterpret_cast<const char*>(val));
- }
-
FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; }
FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* {
return val;
@@ -1417,10 +1447,11 @@
template <
typename T,
FMT_ENABLE_IF(
- std::is_member_pointer<T>::value ||
+ 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))>
+ !std::is_convertible<const T&, const char_type*>::value &&
+ !has_formatter<T, Context>::value))>
FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer {
return {};
}
@@ -1434,16 +1465,19 @@
template <typename T,
FMT_ENABLE_IF(
std::is_enum<T>::value&& std::is_convertible<T, int>::value &&
- !has_formatter<T, Context>::value &&
+ !has_format_as<T>::value && !has_formatter<T, Context>::value &&
!has_fallback_formatter<T, char_type>::value)>
- FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
+ FMT_DEPRECATED FMT_CONSTEXPR FMT_INLINE auto map(const T& val)
-> decltype(std::declval<arg_mapper>().map(
- static_cast<typename std::underlying_type<T>::type>(val))) {
- return map(static_cast<typename std::underlying_type<T>::type>(val));
+ static_cast<underlying_t<T>>(val))) {
+ return map(static_cast<underlying_t<T>>(val));
}
- FMT_CONSTEXPR FMT_INLINE auto map(detail::byte val) -> unsigned {
- return map(static_cast<unsigned char>(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()))) {
+ return map(format_as(val));
}
template <typename T, typename U = remove_cvref_t<T>>
@@ -1452,8 +1486,9 @@
!std::is_const<remove_reference_t<T>>::value ||
has_fallback_formatter<U, char_type>::value> {};
-#if FMT_MSC_VER != 0 && FMT_MSC_VER < 1910
- // Workaround a bug in MSVC.
+#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;
}
@@ -1471,6 +1506,8 @@
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)
@@ -1513,12 +1550,11 @@
public:
using std::back_insert_iterator<detail::buffer<char>>::back_insert_iterator;
- appender(base it) FMT_NOEXCEPT : base(it) {}
- using _Unchecked_type = appender; // Mark iterator as checked.
+ appender(base it) noexcept : base(it) {}
+ FMT_UNCHECKED_ITERATOR(appender);
- auto operator++() FMT_NOEXCEPT -> appender& { return *this; }
-
- auto operator++(int) FMT_NOEXCEPT -> appender { return *this; }
+ auto operator++() noexcept -> appender& { return *this; }
+ auto operator++(int) noexcept -> appender { return *this; }
};
// A formatting argument. It is a trivially copyable/constructible type to
@@ -1529,7 +1565,7 @@
detail::type type_;
template <typename ContextType, typename T>
- friend FMT_CONSTEXPR auto detail::make_arg(const T& value)
+ friend FMT_CONSTEXPR auto detail::make_arg(T&& value)
-> basic_format_arg<ContextType>;
template <typename Visitor, typename Ctx>
@@ -1564,7 +1600,7 @@
constexpr basic_format_arg() : type_(detail::type::none_type) {}
- constexpr explicit operator bool() const FMT_NOEXCEPT {
+ constexpr explicit operator bool() const noexcept {
return type_ != detail::type::none_type;
}
@@ -1632,6 +1668,11 @@
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; };
@@ -1665,7 +1706,7 @@
template <>
struct is_contiguous_back_insert_iterator<appender> : std::true_type {};
-// A type-erased reference to an std::locale to avoid heavy <locale> include.
+// 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.
@@ -1674,7 +1715,7 @@
constexpr locale_ref() : locale_(nullptr) {}
template <typename Locale> explicit locale_ref(const Locale& loc);
- explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; }
+ explicit operator bool() const noexcept { return locale_ != nullptr; }
template <typename Locale> auto get() const -> Locale;
};
@@ -1690,20 +1731,8 @@
}
template <typename Context, typename T>
-FMT_CONSTEXPR auto make_arg(const T& value) -> basic_format_arg<Context> {
- basic_format_arg<Context> arg;
- arg.type_ = mapped_type_constant<T, Context>::value;
- arg.value_ = arg_mapper<Context>().map(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> {
- const auto& arg = arg_mapper<Context>().map(std::forward<T>(val));
+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;
@@ -1731,9 +1760,26 @@
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)>
-inline auto make_arg(const T& value) -> basic_format_arg<Context> {
+FMT_CONSTEXPR inline auto make_arg(T&& value) -> basic_format_arg<Context> {
return make_arg<Context>(value);
}
FMT_END_DETAIL_NAMESPACE
@@ -1853,7 +1899,7 @@
data_{detail::make_arg<
is_packed, Context,
detail::mapped_type_constant<remove_cvref_t<T>, Context>::value>(
- std::forward<T>(args))...} {
+ FMT_FORWARD(args))...} {
detail::init_named_args(data_.named_args(), 0, 0, args...);
}
};
@@ -1869,7 +1915,7 @@
template <typename Context = format_context, typename... Args>
constexpr auto make_format_args(Args&&... args)
-> format_arg_store<Context, remove_cvref_t<Args>...> {
- return {std::forward<Args>(args)...};
+ return {FMT_FORWARD(args)...};
}
/**
@@ -2015,14 +2061,22 @@
// between clang and gcc on ARM (#1919).
using format_args = basic_format_args<format_context>;
-// We cannot use enum classes as bit fields because of a gcc bug
-// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414.
+// 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).
+// Additionally, if an underlying type is specified, older gcc incorrectly warns
+// that the type is too small. Both bugs are fixed in gcc 9.3.
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903
+# define FMT_ENUM_UNDERLYING_TYPE(type)
+#else
+# define FMT_ENUM_UNDERLYING_TYPE(type) : type
+#endif
namespace align {
-enum type { none, left, right, center, numeric };
+enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center,
+ numeric};
}
using align_t = align::type;
namespace sign {
-enum type { none, minus, plus, space };
+enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space};
}
using sign_t = sign::type;
@@ -2072,7 +2126,8 @@
general_upper, // 'G'
chr, // 'c'
string, // 's'
- pointer // 'p'
+ pointer, // 'p'
+ debug // '?'
};
// Format specifiers for built-in and string types.
@@ -2209,11 +2264,14 @@
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 {
- return arg_ref_type(context_.next_arg_id());
+ 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)
@@ -2231,21 +2289,23 @@
// Converts a character to ASCII. Returns a number > 127 on conversion failure.
template <typename Char, FMT_ENABLE_IF(std::is_integral<Char>::value)>
-constexpr auto to_ascii(Char value) -> Char {
- return value;
+constexpr auto to_ascii(Char c) -> Char {
+ return c;
}
template <typename Char, FMT_ENABLE_IF(std::is_enum<Char>::value)>
-constexpr auto to_ascii(Char value) ->
- typename std::underlying_type<Char>::type {
- return value;
+constexpr auto to_ascii(Char c) -> underlying_t<Char> {
+ return c;
+}
+
+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];
}
template <typename Char>
FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int {
if (const_check(sizeof(Char) != 1)) return 1;
- auto lengths =
- "\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";
- int len = lengths[static_cast<unsigned char>(*begin) >> 3];
+ 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
@@ -2302,7 +2362,7 @@
FMT_ASSERT(begin != end, "");
auto align = align::none;
auto p = begin + code_point_length(begin);
- if (p >= end) p = begin;
+ if (end - p <= 0) p = begin;
for (;;) {
switch (to_ascii(*p)) {
case '<':
@@ -2488,6 +2548,8 @@
return presentation_type::string;
case 'p':
return presentation_type::pointer;
+ case '?':
+ return presentation_type::debug;
default:
return presentation_type::none;
}
@@ -2635,21 +2697,21 @@
return;
}
struct writer {
- FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) {
- if (pbegin == pend) return;
+ FMT_CONSTEXPR void operator()(const Char* from, const Char* to) {
+ if (from == to) return;
for (;;) {
const Char* p = nullptr;
- if (!find<IS_CONSTEXPR>(pbegin, pend, Char('}'), p))
- return handler_.on_text(pbegin, pend);
+ if (!find<IS_CONSTEXPR>(from, to, Char('}'), p))
+ return handler_.on_text(from, to);
++p;
- if (p == pend || *p != '}')
+ if (p == to || *p != '}')
return handler_.on_error("unmatched '}' in format string");
- handler_.on_text(pbegin, p);
- pbegin = p + 1;
+ handler_.on_text(from, p);
+ from = p + 1;
}
}
Handler& handler_;
- } write{handler};
+ } write = {handler};
while (begin != end) {
// Doing two passes with memchr (one for '{' and another for '}') is up to
// 2.5x faster than the naive one-pass implementation on big format strings.
@@ -2661,50 +2723,29 @@
}
}
+template <typename T, bool = is_named_arg<T>::value> struct strip_named_arg {
+ using type = T;
+};
+template <typename T> struct strip_named_arg<T, true> {
+ using type = remove_cvref_t<decltype(T::value)>;
+};
+
template <typename T, typename ParseContext>
FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
-> 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&>())), T>;
+ 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<T, char_type>>();
+ fallback_formatter<stripped_type, char_type>>();
return f.parse(ctx);
}
-// A parse context with extra argument id checks. It is only used at compile
-// time because adding checks at runtime would introduce substantial overhead
-// and would be redundant since argument ids are checked when arguments are
-// retrieved anyway.
-template <typename Char, typename ErrorHandler = error_handler>
-class compile_parse_context
- : public basic_format_parse_context<Char, ErrorHandler> {
- private:
- int num_args_;
- using base = basic_format_parse_context<Char, ErrorHandler>;
-
- public:
- explicit FMT_CONSTEXPR compile_parse_context(
- basic_string_view<Char> format_str,
- int num_args = (std::numeric_limits<int>::max)(), ErrorHandler eh = {})
- : base(format_str, eh), num_args_(num_args) {}
-
- FMT_CONSTEXPR auto next_arg_id() -> int {
- int id = base::next_arg_id();
- if (id >= num_args_) this->on_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");
- }
- using base::check_arg_id;
-};
-
template <typename ErrorHandler>
FMT_CONSTEXPR void check_int_type_spec(presentation_type type,
ErrorHandler&& eh) {
@@ -2717,7 +2758,8 @@
FMT_CONSTEXPR auto check_char_specs(const basic_format_specs<Char>& specs,
ErrorHandler&& eh = {}) -> bool {
if (specs.type != presentation_type::none &&
- specs.type != presentation_type::chr) {
+ specs.type != presentation_type::chr &&
+ specs.type != presentation_type::debug) {
check_int_type_spec(specs.type, eh);
return false;
}
@@ -2741,7 +2783,6 @@
bool upper : 1;
bool locale : 1;
bool binary32 : 1;
- bool fallback : 1;
bool showpoint : 1;
};
@@ -2792,7 +2833,8 @@
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)
+ 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;
@@ -2801,7 +2843,8 @@
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)
+ if (type != presentation_type::none && type != presentation_type::string &&
+ type != presentation_type::debug)
eh.on_error("invalid type specifier");
}
@@ -2835,7 +2878,8 @@
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::char_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);
@@ -2864,7 +2908,7 @@
constexpr int invalid_arg_index = -1;
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#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>()) {
@@ -2879,7 +2923,7 @@
template <typename... Args, typename Char>
FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#if FMT_USE_NONTYPE_TEMPLATE_ARGS
if constexpr (sizeof...(Args) > 0)
return get_arg_index_by_name<0, Args...>(name);
#endif
@@ -2890,20 +2934,28 @@
template <typename Char, typename ErrorHandler, 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>;
- enum { num_args = sizeof...(Args) };
+ static constexpr int num_args = sizeof...(Args);
// Format specifier parsing function.
using parse_func = const Char* (*)(parse_context_type&);
parse_context_type context_;
- parse_func parse_funcs_[num_args > 0 ? num_args : 1];
+ 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, eh),
- parse_funcs_{&parse_format_specs<Args, parse_context_type>...} {}
+ : 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...} {
+ }
FMT_CONSTEXPR void on_text(const Char*, const Char*) {}
@@ -2912,7 +2964,7 @@
return context_.check_arg_id(id), id;
}
FMT_CONSTEXPR auto on_arg_id(basic_string_view<Char> id) -> int {
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#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;
@@ -2937,10 +2989,19 @@
}
};
+// Reports a compile-time error if S is not a valid format string.
+template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
+FMT_INLINE void check_format_string(const S&) {
+#ifdef FMT_ENFORCE_COMPILE_STRING
+ static_assert(is_compile_string<S>::value,
+ "FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
+ "FMT_STRING.");
+#endif
+}
template <typename... Args, typename S,
- enable_if_t<(is_compile_string<S>::value), int>>
+ FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S format_str) {
- FMT_CONSTEXPR auto s = to_string_view(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 =
@@ -3038,11 +3099,41 @@
return it;
}
+ 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;
+ }
+
template <typename FormatContext>
FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const
-> 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; };
/** A compile-time format string. */
@@ -3078,10 +3169,8 @@
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
-template <typename... Args> using format_string = string_view;
-template <typename S> auto runtime(const S& s) -> basic_string_view<char_t<S>> {
- return s;
-}
+template <typename...> using format_string = string_view;
+inline auto runtime(string_view s) -> string_view { return s; }
#else
template <typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>;
@@ -3095,9 +3184,7 @@
fmt::print(fmt::runtime("{:d}"), "I am not a number");
\endrst
*/
-template <typename S> auto runtime(const S& s) -> basic_runtime<char_t<S>> {
- return {{s}};
-}
+inline auto runtime(string_view s) -> basic_runtime<char> { return {{s}}; }
#endif
FMT_API auto vformat(string_view fmt, format_args args) -> std::string;
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
new file mode 100644
index 0000000..abe4ff1
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format-inl.h
@@ -0,0 +1,1721 @@
+// Formatting library for C++ - implementation
+//
+// Copyright (c) 2012 - 2016, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_FORMAT_INL_H_
+#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
+# include <locale>
+#endif
+
+#ifdef _WIN32
+# include <io.h> // _isatty
+#endif
+
+#include "format.h"
+
+FMT_BEGIN_NAMESPACE
+namespace detail {
+
+FMT_FUNC void assert_fail(const char* file, int line, const char* message) {
+ // Use unchecked std::fprintf to avoid triggering another assertion when
+ // writing to stderr fails
+ std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message);
+ // Chosen instead of std::abort to satisfy Clang in CUDA mode during device
+ // code pass.
+ std::terminate();
+}
+
+FMT_FUNC void throw_format_error(const char* message) {
+ FMT_THROW(format_error(message));
+}
+
+FMT_FUNC void format_error_code(detail::buffer<char>& out, int error_code,
+ string_view message) noexcept {
+ // Report error code making sure that the output fits into
+ // inline_buffer_size to avoid dynamic memory allocation and potential
+ // bad_alloc.
+ out.try_resize(0);
+ static const char SEP[] = ": ";
+ static const char ERROR_STR[] = "error ";
+ // Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
+ size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
+ auto abs_value = static_cast<uint32_or_64_or_128_t<int>>(error_code);
+ if (detail::is_negative(error_code)) {
+ abs_value = 0 - abs_value;
+ ++error_code_size;
+ }
+ error_code_size += detail::to_unsigned(detail::count_digits(abs_value));
+ auto it = buffer_appender<char>(out);
+ if (message.size() <= inline_buffer_size - error_code_size)
+ format_to(it, FMT_STRING("{}{}"), message, SEP);
+ format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code);
+ FMT_ASSERT(out.size() <= inline_buffer_size, "");
+}
+
+FMT_FUNC void report_error(format_func func, int error_code,
+ const char* message) noexcept {
+ memory_buffer full_message;
+ func(full_message, error_code, message);
+ // Don't use fwrite_fully because the latter may throw.
+ if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0)
+ std::fputc('\n', stderr);
+}
+
+// A wrapper around fwrite that throws on error.
+inline void fwrite_fully(const void* ptr, size_t size, size_t count,
+ FILE* stream) {
+ std::fwrite(ptr, size, count, stream);
+}
+
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+template <typename Locale>
+locale_ref::locale_ref(const Locale& loc) : locale_(&loc) {
+ static_assert(std::is_same<Locale, std::locale>::value, "");
+}
+
+template <typename Locale> Locale locale_ref::get() const {
+ static_assert(std::is_same<Locale, std::locale>::value, "");
+ return locale_ ? *static_cast<const std::locale*>(locale_) : std::locale();
+}
+
+template <typename Char>
+FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result<Char> {
+ auto& facet = std::use_facet<std::numpunct<Char>>(loc.get<std::locale>());
+ auto grouping = facet.grouping();
+ auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep();
+ return {std::move(grouping), thousands_sep};
+}
+template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref loc) {
+ return std::use_facet<std::numpunct<Char>>(loc.get<std::locale>())
+ .decimal_point();
+}
+#else
+template <typename Char>
+FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result<Char> {
+ return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR};
+}
+template <typename Char> FMT_FUNC Char decimal_point_impl(locale_ref) {
+ return '.';
+}
+#endif
+} // namespace detail
+
+#if !FMT_MSC_VERSION
+FMT_API FMT_FUNC format_error::~format_error() noexcept = default;
+#endif
+
+FMT_FUNC std::system_error vsystem_error(int error_code, string_view format_str,
+ format_args args) {
+ auto ec = std::error_code(error_code, std::generic_category());
+ return std::system_error(ec, vformat(format_str, args));
+}
+
+namespace detail {
+
+template <typename F> inline bool operator==(basic_fp<F> x, basic_fp<F> y) {
+ return x.f == y.f && x.e == y.e;
+}
+
+// Compilers should be able to optimize this into the ror instruction.
+FMT_CONSTEXPR inline uint32_t rotr(uint32_t n, uint32_t r) noexcept {
+ r &= 31;
+ return (n >> r) | (n << (32 - r));
+}
+FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept {
+ r &= 63;
+ 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 {
+ return umul128_upper64(static_cast<uint64_t>(x) << 32, y);
+}
+
+// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a
+// 128-bit unsigned integer.
+inline uint128_fallback umul192_lower128(uint64_t x,
+ uint128_fallback y) noexcept {
+ uint64_t high = x * y.high();
+ uint128_fallback high_low = umul128(x, y.low());
+ return {high + high_low.high(), high_low.low()};
+}
+
+// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a
+// 64-bit unsigned integer.
+inline uint64_t umul96_lower64(uint32_t x, uint64_t y) noexcept {
+ 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 {
+ uint32_t divisor;
+ int shift_amount;
+} div_small_pow10_infos[] = {{10, 16}, {100, 16}};
+
+// Replaces n by floor(n / pow(10, N)) returning true if and only if n is
+// divisible by pow(10, N).
+// Precondition: n <= pow(10, N + 1).
+template <int N>
+bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept {
+ // The numbers below are chosen such that:
+ // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100,
+ // 2. nm mod 2^k < m if and only if n is divisible by d,
+ // where m is magic_number, k is shift_amount
+ // and d is divisor.
+ //
+ // Item 1 is a common technique of replacing division by a constant with
+ // multiplication, see e.g. "Division by Invariant Integers Using
+ // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set
+ // to ceil(2^k/d) for large enough k.
+ // The idea for item 2 originates from Schubfach.
+ constexpr auto info = div_small_pow10_infos[N - 1];
+ FMT_ASSERT(n <= info.divisor * 10, "n is too large");
+ constexpr uint32_t magic_number =
+ (1u << info.shift_amount) / info.divisor + 1;
+ n *= magic_number;
+ const uint32_t comparison_mask = (1u << info.shift_amount) - 1;
+ bool result = (n & comparison_mask) < magic_number;
+ n >>= info.shift_amount;
+ return result;
+}
+
+// Computes floor(n / pow(10, N)) for small n and N.
+// Precondition: n <= pow(10, N + 1).
+template <int N> uint32_t small_division_by_pow10(uint32_t n) noexcept {
+ constexpr auto info = div_small_pow10_infos[N - 1];
+ FMT_ASSERT(n <= info.divisor * 10, "n is too large");
+ constexpr uint32_t magic_number =
+ (1u << info.shift_amount) / info.divisor + 1;
+ return (n * magic_number) >> info.shift_amount;
+}
+
+// Computes floor(n / 10^(kappa + 1)) (float)
+inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) noexcept {
+ // 1374389535 = ceil(2^37/100)
+ return static_cast<uint32_t>((static_cast<uint64_t>(n) * 1374389535) >> 37);
+}
+// Computes floor(n / 10^(kappa + 1)) (double)
+inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) noexcept {
+ // 2361183241434822607 = ceil(2^(64+7)/1000)
+ return umul128_upper64(n, 2361183241434822607ull) >> 7;
+}
+
+// Various subroutines using pow10 cache
+template <class T> struct cache_accessor;
+
+template <> struct cache_accessor<float> {
+ using carrier_uint = float_info<float>::carrier_uint;
+ using cache_entry_type = uint64_t;
+
+ static uint64_t get_cached_power(int k) noexcept {
+ FMT_ASSERT(k >= float_info<float>::min_k && k <= float_info<float>::max_k,
+ "k is out of range");
+ static constexpr const uint64_t pow10_significands[] = {
+ 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f,
+ 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb,
+ 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28,
+ 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb,
+ 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a,
+ 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810,
+ 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff,
+ 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd,
+ 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424,
+ 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b,
+ 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000,
+ 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000,
+ 0xc350000000000000, 0xf424000000000000, 0x9896800000000000,
+ 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000,
+ 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000,
+ 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000,
+ 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000,
+ 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000,
+ 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0,
+ 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985,
+ 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297,
+ 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7,
+ 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21,
+ 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe,
+ 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a,
+ 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f};
+ return pow10_significands[k - float_info<float>::min_k];
+ }
+
+ struct compute_mul_result {
+ carrier_uint result;
+ bool is_integer;
+ };
+ struct compute_mul_parity_result {
+ bool parity;
+ bool is_integer;
+ };
+
+ static compute_mul_result compute_mul(
+ carrier_uint u, const cache_entry_type& cache) noexcept {
+ auto r = umul96_upper64(u, cache);
+ return {static_cast<carrier_uint>(r >> 32),
+ static_cast<carrier_uint>(r) == 0};
+ }
+
+ static uint32_t compute_delta(const cache_entry_type& cache,
+ int beta) noexcept {
+ return static_cast<uint32_t>(cache >> (64 - 1 - beta));
+ }
+
+ static compute_mul_parity_result compute_mul_parity(
+ carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept {
+ FMT_ASSERT(beta >= 1, "");
+ FMT_ASSERT(beta < 64, "");
+
+ auto r = umul96_lower64(two_f, cache);
+ return {((r >> (64 - beta)) & 1) != 0,
+ static_cast<uint32_t>(r >> (32 - beta)) == 0};
+ }
+
+ static carrier_uint compute_left_endpoint_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return static_cast<carrier_uint>(
+ (cache - (cache >> (num_significand_bits<float>() + 2))) >>
+ (64 - num_significand_bits<float>() - 1 - beta));
+ }
+
+ static carrier_uint compute_right_endpoint_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return static_cast<carrier_uint>(
+ (cache + (cache >> (num_significand_bits<float>() + 1))) >>
+ (64 - num_significand_bits<float>() - 1 - beta));
+ }
+
+ static carrier_uint compute_round_up_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return (static_cast<carrier_uint>(
+ cache >> (64 - num_significand_bits<float>() - 2 - beta)) +
+ 1) /
+ 2;
+ }
+};
+
+template <> struct cache_accessor<double> {
+ using carrier_uint = float_info<double>::carrier_uint;
+ using cache_entry_type = uint128_fallback;
+
+ static uint128_fallback get_cached_power(int k) noexcept {
+ FMT_ASSERT(k >= float_info<double>::min_k && k <= float_info<double>::max_k,
+ "k is out of range");
+
+ static constexpr const uint128_fallback pow10_significands[] = {
+#if FMT_USE_FULL_CACHE_DRAGONBOX
+ {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
+ {0x9faacf3df73609b1, 0x77b191618c54e9ad},
+ {0xc795830d75038c1d, 0xd59df5b9ef6a2418},
+ {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e},
+ {0x9becce62836ac577, 0x4ee367f9430aec33},
+ {0xc2e801fb244576d5, 0x229c41f793cda740},
+ {0xf3a20279ed56d48a, 0x6b43527578c11110},
+ {0x9845418c345644d6, 0x830a13896b78aaaa},
+ {0xbe5691ef416bd60c, 0x23cc986bc656d554},
+ {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9},
+ {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa},
+ {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54},
+ {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69},
+ {0x91376c36d99995be, 0x23100809b9c21fa2},
+ {0xb58547448ffffb2d, 0xabd40a0c2832a78b},
+ {0xe2e69915b3fff9f9, 0x16c90c8f323f516d},
+ {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4},
+ {0xb1442798f49ffb4a, 0x99cd11cfdf41779d},
+ {0xdd95317f31c7fa1d, 0x40405643d711d584},
+ {0x8a7d3eef7f1cfc52, 0x482835ea666b2573},
+ {0xad1c8eab5ee43b66, 0xda3243650005eed0},
+ {0xd863b256369d4a40, 0x90bed43e40076a83},
+ {0x873e4f75e2224e68, 0x5a7744a6e804a292},
+ {0xa90de3535aaae202, 0x711515d0a205cb37},
+ {0xd3515c2831559a83, 0x0d5a5b44ca873e04},
+ {0x8412d9991ed58091, 0xe858790afe9486c3},
+ {0xa5178fff668ae0b6, 0x626e974dbe39a873},
+ {0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
+ {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a},
+ {0xa139029f6a239f72, 0x1c1fffc1ebc44e81},
+ {0xc987434744ac874e, 0xa327ffb266b56221},
+ {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9},
+ {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa},
+ {0xc4ce17b399107c22, 0xcb550fb4384d21d4},
+ {0xf6019da07f549b2b, 0x7e2a53a146606a49},
+ {0x99c102844f94e0fb, 0x2eda7444cbfc426e},
+ {0xc0314325637a1939, 0xfa911155fefb5309},
+ {0xf03d93eebc589f88, 0x793555ab7eba27cb},
+ {0x96267c7535b763b5, 0x4bc1558b2f3458df},
+ {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17},
+ {0xea9c227723ee8bcb, 0x465e15a979c1cadd},
+ {0x92a1958a7675175f, 0x0bfacd89ec191eca},
+ {0xb749faed14125d36, 0xcef980ec671f667c},
+ {0xe51c79a85916f484, 0x82b7e12780e7401b},
+ {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811},
+ {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16},
+ {0xdfbdcece67006ac9, 0x67a791e093e1d49b},
+ {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1},
+ {0xaecc49914078536d, 0x58fae9f773886e19},
+ {0xda7f5bf590966848, 0xaf39a475506a899f},
+ {0x888f99797a5e012d, 0x6d8406c952429604},
+ {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84},
+ {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65},
+ {0x855c3be0a17fcd26, 0x5cf2eea09a550680},
+ {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f},
+ {0xd0601d8efc57b08b, 0xf13b94daf124da27},
+ {0x823c12795db6ce57, 0x76c53d08d6b70859},
+ {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f},
+ {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a},
+ {0xfe5d54150b090b02, 0xd3f93b35435d7c4d},
+ {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0},
+ {0xc6b8e9b0709f109a, 0x359ab6419ca1091c},
+ {0xf867241c8cc6d4c0, 0xc30163d203c94b63},
+ {0x9b407691d7fc44f8, 0x79e0de63425dcf1e},
+ {0xc21094364dfb5636, 0x985915fc12f542e5},
+ {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e},
+ {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43},
+ {0xbd8430bd08277231, 0x50c6ff782a838354},
+ {0xece53cec4a314ebd, 0xa4f8bf5635246429},
+ {0x940f4613ae5ed136, 0x871b7795e136be9a},
+ {0xb913179899f68584, 0x28e2557b59846e40},
+ {0xe757dd7ec07426e5, 0x331aeada2fe589d0},
+ {0x9096ea6f3848984f, 0x3ff0d2c85def7622},
+ {0xb4bca50b065abe63, 0x0fed077a756b53aa},
+ {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895},
+ {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d},
+ {0xb080392cc4349dec, 0xbd8d794d96aacfb4},
+ {0xdca04777f541c567, 0xecf0d7a0fc5583a1},
+ {0x89e42caaf9491b60, 0xf41686c49db57245},
+ {0xac5d37d5b79b6239, 0x311c2875c522ced6},
+ {0xd77485cb25823ac7, 0x7d633293366b828c},
+ {0x86a8d39ef77164bc, 0xae5dff9c02033198},
+ {0xa8530886b54dbdeb, 0xd9f57f830283fdfd},
+ {0xd267caa862a12d66, 0xd072df63c324fd7c},
+ {0x8380dea93da4bc60, 0x4247cb9e59f71e6e},
+ {0xa46116538d0deb78, 0x52d9be85f074e609},
+ {0xcd795be870516656, 0x67902e276c921f8c},
+ {0x806bd9714632dff6, 0x00ba1cd8a3db53b7},
+ {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5},
+ {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce},
+ {0xfad2a4b13d1b5d6c, 0x796b805720085f82},
+ {0x9cc3a6eec6311a63, 0xcbe3303674053bb1},
+ {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d},
+ {0xf4f1b4d515acb93b, 0xee92fb5515482d45},
+ {0x991711052d8bf3c5, 0x751bdd152d4d1c4b},
+ {0xbf5cd54678eef0b6, 0xd262d45a78a0635e},
+ {0xef340a98172aace4, 0x86fb897116c87c35},
+ {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1},
+ {0xbae0a846d2195712, 0x8974836059cca10a},
+ {0xe998d258869facd7, 0x2bd1a438703fc94c},
+ {0x91ff83775423cc06, 0x7b6306a34627ddd0},
+ {0xb67f6455292cbf08, 0x1a3bc84c17b1d543},
+ {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94},
+ {0x8e938662882af53e, 0x547eb47b7282ee9d},
+ {0xb23867fb2a35b28d, 0xe99e619a4f23aa44},
+ {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5},
+ {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05},
+ {0xae0b158b4738705e, 0x9624ab50b148d446},
+ {0xd98ddaee19068c76, 0x3badd624dd9b0958},
+ {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7},
+ {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d},
+ {0xd47487cc8470652b, 0x7647c32000696720},
+ {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074},
+ {0xa5fb0a17c777cf09, 0xf468107100525891},
+ {0xcf79cc9db955c2cc, 0x7182148d4066eeb5},
+ {0x81ac1fe293d599bf, 0xc6f14cd848405531},
+ {0xa21727db38cb002f, 0xb8ada00e5a506a7d},
+ {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d},
+ {0xfd442e4688bd304a, 0x908f4a166d1da664},
+ {0x9e4a9cec15763e2e, 0x9a598e4e043287ff},
+ {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe},
+ {0xf7549530e188c128, 0xd12bee59e68ef47d},
+ {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf},
+ {0xc13a148e3032d6e7, 0xe36a52363c1faf02},
+ {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2},
+ {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba},
+ {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8},
+ {0xebdf661791d60f56, 0x111b495b3464ad22},
+ {0x936b9fcebb25c995, 0xcab10dd900beec35},
+ {0xb84687c269ef3bfb, 0x3d5d514f40eea743},
+ {0xe65829b3046b0afa, 0x0cb4a5a3112a5113},
+ {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac},
+ {0xb3f4e093db73a093, 0x59ed216765690f57},
+ {0xe0f218b8d25088b8, 0x306869c13ec3532d},
+ {0x8c974f7383725573, 0x1e414218c73a13fc},
+ {0xafbd2350644eeacf, 0xe5d1929ef90898fb},
+ {0xdbac6c247d62a583, 0xdf45f746b74abf3a},
+ {0x894bc396ce5da772, 0x6b8bba8c328eb784},
+ {0xab9eb47c81f5114f, 0x066ea92f3f326565},
+ {0xd686619ba27255a2, 0xc80a537b0efefebe},
+ {0x8613fd0145877585, 0xbd06742ce95f5f37},
+ {0xa798fc4196e952e7, 0x2c48113823b73705},
+ {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6},
+ {0x82ef85133de648c4, 0x9a984d73dbe722fc},
+ {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb},
+ {0xcc963fee10b7d1b3, 0x318df905079926a9},
+ {0xffbbcfe994e5c61f, 0xfdf17746497f7053},
+ {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634},
+ {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1},
+ {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1},
+ {0x9c1661a651213e2d, 0x06bea10ca65c084f},
+ {0xc31bfa0fe5698db8, 0x486e494fcff30a63},
+ {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb},
+ {0x986ddb5c6b3a76b7, 0xf89629465a75e01d},
+ {0xbe89523386091465, 0xf6bbb397f1135824},
+ {0xee2ba6c0678b597f, 0x746aa07ded582e2d},
+ {0x94db483840b717ef, 0xa8c2a44eb4571cdd},
+ {0xba121a4650e4ddeb, 0x92f34d62616ce414},
+ {0xe896a0d7e51e1566, 0x77b020baf9c81d18},
+ {0x915e2486ef32cd60, 0x0ace1474dc1d122f},
+ {0xb5b5ada8aaff80b8, 0x0d819992132456bb},
+ {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a},
+ {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2},
+ {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3},
+ {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf},
+ {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c},
+ {0xad4ab7112eb3929d, 0x86c16c98d2c953c7},
+ {0xd89d64d57a607744, 0xe871c7bf077ba8b8},
+ {0x87625f056c7c4a8b, 0x11471cd764ad4973},
+ {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0},
+ {0xd389b47879823479, 0x4aff1d108d4ec2c4},
+ {0x843610cb4bf160cb, 0xcedf722a585139bb},
+ {0xa54394fe1eedb8fe, 0xc2974eb4ee658829},
+ {0xce947a3da6a9273e, 0x733d226229feea33},
+ {0x811ccc668829b887, 0x0806357d5a3f5260},
+ {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8},
+ {0xc9bcff6034c13052, 0xfc89b393dd02f0b6},
+ {0xfc2c3f3841f17c67, 0xbbac2078d443ace3},
+ {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e},
+ {0xc5029163f384a931, 0x0a9e795e65d4df12},
+ {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6},
+ {0x99ea0196163fa42e, 0x504bced1bf8e4e46},
+ {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7},
+ {0xf07da27a82c37088, 0x5d767327bb4e5a4d},
+ {0x964e858c91ba2655, 0x3a6a07f8d510f870},
+ {0xbbe226efb628afea, 0x890489f70a55368c},
+ {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f},
+ {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e},
+ {0xb77ada0617e3bbcb, 0x09ce6ebb40173745},
+ {0xe55990879ddcaabd, 0xcc420a6a101d0516},
+ {0x8f57fa54c2a9eab6, 0x9fa946824a12232e},
+ {0xb32df8e9f3546564, 0x47939822dc96abfa},
+ {0xdff9772470297ebd, 0x59787e2b93bc56f8},
+ {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b},
+ {0xaefae51477a06b03, 0xede622920b6b23f2},
+ {0xdab99e59958885c4, 0xe95fab368e45ecee},
+ {0x88b402f7fd75539b, 0x11dbcb0218ebb415},
+ {0xaae103b5fcd2a881, 0xd652bdc29f26a11a},
+ {0xd59944a37c0752a2, 0x4be76d3346f04960},
+ {0x857fcae62d8493a5, 0x6f70a4400c562ddc},
+ {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953},
+ {0xd097ad07a71f26b2, 0x7e2000a41346a7a8},
+ {0x825ecc24c873782f, 0x8ed400668c0c28c9},
+ {0xa2f67f2dfa90563b, 0x728900802f0f32fb},
+ {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba},
+ {0xfea126b7d78186bc, 0xe2f610c84987bfa9},
+ {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca},
+ {0xc6ede63fa05d3143, 0x91503d1c79720dbc},
+ {0xf8a95fcf88747d94, 0x75a44c6397ce912b},
+ {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb},
+ {0xc24452da229b021b, 0xfbe85badce996169},
+ {0xf2d56790ab41c2a2, 0xfae27299423fb9c4},
+ {0x97c560ba6b0919a5, 0xdccd879fc967d41b},
+ {0xbdb6b8e905cb600f, 0x5400e987bbc1c921},
+ {0xed246723473e3813, 0x290123e9aab23b69},
+ {0x9436c0760c86e30b, 0xf9a0b6720aaf6522},
+ {0xb94470938fa89bce, 0xf808e40e8d5b3e6a},
+ {0xe7958cb87392c2c2, 0xb60b1d1230b20e05},
+ {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3},
+ {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4},
+ {0xe2280b6c20dd5232, 0x25c6da63c38de1b1},
+ {0x8d590723948a535f, 0x579c487e5a38ad0f},
+ {0xb0af48ec79ace837, 0x2d835a9df0c6d852},
+ {0xdcdb1b2798182244, 0xf8e431456cf88e66},
+ {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900},
+ {0xac8b2d36eed2dac5, 0xe272467e3d222f40},
+ {0xd7adf884aa879177, 0x5b0ed81dcc6abb10},
+ {0x86ccbb52ea94baea, 0x98e947129fc2b4ea},
+ {0xa87fea27a539e9a5, 0x3f2398d747b36225},
+ {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae},
+ {0x83a3eeeef9153e89, 0x1953cf68300424ad},
+ {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8},
+ {0xcdb02555653131b6, 0x3792f412cb06794e},
+ {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1},
+ {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5},
+ {0xc8de047564d20a8b, 0xf245825a5a445276},
+ {0xfb158592be068d2e, 0xeed6e2f0f0d56713},
+ {0x9ced737bb6c4183d, 0x55464dd69685606c},
+ {0xc428d05aa4751e4c, 0xaa97e14c3c26b887},
+ {0xf53304714d9265df, 0xd53dd99f4b3066a9},
+ {0x993fe2c6d07b7fab, 0xe546a8038efe402a},
+ {0xbf8fdb78849a5f96, 0xde98520472bdd034},
+ {0xef73d256a5c0f77c, 0x963e66858f6d4441},
+ {0x95a8637627989aad, 0xdde7001379a44aa9},
+ {0xbb127c53b17ec159, 0x5560c018580d5d53},
+ {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7},
+ {0x9226712162ab070d, 0xcab3961304ca70e9},
+ {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23},
+ {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b},
+ {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243},
+ {0xb267ed1940f1c61c, 0x55f038b237591ed4},
+ {0xdf01e85f912e37a3, 0x6b6c46dec52f6689},
+ {0x8b61313bbabce2c6, 0x2323ac4b3b3da016},
+ {0xae397d8aa96c1b77, 0xabec975e0a0d081b},
+ {0xd9c7dced53c72255, 0x96e7bd358c904a22},
+ {0x881cea14545c7575, 0x7e50d64177da2e55},
+ {0xaa242499697392d2, 0xdde50bd1d5d0b9ea},
+ {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865},
+ {0x84ec3c97da624ab4, 0xbd5af13bef0b113f},
+ {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f},
+ {0xcfb11ead453994ba, 0x67de18eda5814af3},
+ {0x81ceb32c4b43fcf4, 0x80eacf948770ced8},
+ {0xa2425ff75e14fc31, 0xa1258379a94d028e},
+ {0xcad2f7f5359a3b3e, 0x096ee45813a04331},
+ {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd},
+ {0x9e74d1b791e07e48, 0x775ea264cf55347e},
+ {0xc612062576589dda, 0x95364afe032a819e},
+ {0xf79687aed3eec551, 0x3a83ddbd83f52205},
+ {0x9abe14cd44753b52, 0xc4926a9672793543},
+ {0xc16d9a0095928a27, 0x75b7053c0f178294},
+ {0xf1c90080baf72cb1, 0x5324c68b12dd6339},
+ {0x971da05074da7bee, 0xd3f6fc16ebca5e04},
+ {0xbce5086492111aea, 0x88f4bb1ca6bcf585},
+ {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6},
+ {0x9392ee8e921d5d07, 0x3aff322e62439fd0},
+ {0xb877aa3236a4b449, 0x09befeb9fad487c3},
+ {0xe69594bec44de15b, 0x4c2ebe687989a9b4},
+ {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11},
+ {0xb424dc35095cd80f, 0x538484c19ef38c95},
+ {0xe12e13424bb40e13, 0x2865a5f206b06fba},
+ {0x8cbccc096f5088cb, 0xf93f87b7442e45d4},
+ {0xafebff0bcb24aafe, 0xf78f69a51539d749},
+ {0xdbe6fecebdedd5be, 0xb573440e5a884d1c},
+ {0x89705f4136b4a597, 0x31680a88f8953031},
+ {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e},
+ {0xd6bf94d5e57a42bc, 0x3d32907604691b4d},
+ {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110},
+ {0xa7c5ac471b478423, 0x0fcf80dc33721d54},
+ {0xd1b71758e219652b, 0xd3c36113404ea4a9},
+ {0x83126e978d4fdf3b, 0x645a1cac083126ea},
+ {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4},
+ {0xcccccccccccccccc, 0xcccccccccccccccd},
+ {0x8000000000000000, 0x0000000000000000},
+ {0xa000000000000000, 0x0000000000000000},
+ {0xc800000000000000, 0x0000000000000000},
+ {0xfa00000000000000, 0x0000000000000000},
+ {0x9c40000000000000, 0x0000000000000000},
+ {0xc350000000000000, 0x0000000000000000},
+ {0xf424000000000000, 0x0000000000000000},
+ {0x9896800000000000, 0x0000000000000000},
+ {0xbebc200000000000, 0x0000000000000000},
+ {0xee6b280000000000, 0x0000000000000000},
+ {0x9502f90000000000, 0x0000000000000000},
+ {0xba43b74000000000, 0x0000000000000000},
+ {0xe8d4a51000000000, 0x0000000000000000},
+ {0x9184e72a00000000, 0x0000000000000000},
+ {0xb5e620f480000000, 0x0000000000000000},
+ {0xe35fa931a0000000, 0x0000000000000000},
+ {0x8e1bc9bf04000000, 0x0000000000000000},
+ {0xb1a2bc2ec5000000, 0x0000000000000000},
+ {0xde0b6b3a76400000, 0x0000000000000000},
+ {0x8ac7230489e80000, 0x0000000000000000},
+ {0xad78ebc5ac620000, 0x0000000000000000},
+ {0xd8d726b7177a8000, 0x0000000000000000},
+ {0x878678326eac9000, 0x0000000000000000},
+ {0xa968163f0a57b400, 0x0000000000000000},
+ {0xd3c21bcecceda100, 0x0000000000000000},
+ {0x84595161401484a0, 0x0000000000000000},
+ {0xa56fa5b99019a5c8, 0x0000000000000000},
+ {0xcecb8f27f4200f3a, 0x0000000000000000},
+ {0x813f3978f8940984, 0x4000000000000000},
+ {0xa18f07d736b90be5, 0x5000000000000000},
+ {0xc9f2c9cd04674ede, 0xa400000000000000},
+ {0xfc6f7c4045812296, 0x4d00000000000000},
+ {0x9dc5ada82b70b59d, 0xf020000000000000},
+ {0xc5371912364ce305, 0x6c28000000000000},
+ {0xf684df56c3e01bc6, 0xc732000000000000},
+ {0x9a130b963a6c115c, 0x3c7f400000000000},
+ {0xc097ce7bc90715b3, 0x4b9f100000000000},
+ {0xf0bdc21abb48db20, 0x1e86d40000000000},
+ {0x96769950b50d88f4, 0x1314448000000000},
+ {0xbc143fa4e250eb31, 0x17d955a000000000},
+ {0xeb194f8e1ae525fd, 0x5dcfab0800000000},
+ {0x92efd1b8d0cf37be, 0x5aa1cae500000000},
+ {0xb7abc627050305ad, 0xf14a3d9e40000000},
+ {0xe596b7b0c643c719, 0x6d9ccd05d0000000},
+ {0x8f7e32ce7bea5c6f, 0xe4820023a2000000},
+ {0xb35dbf821ae4f38b, 0xdda2802c8a800000},
+ {0xe0352f62a19e306e, 0xd50b2037ad200000},
+ {0x8c213d9da502de45, 0x4526f422cc340000},
+ {0xaf298d050e4395d6, 0x9670b12b7f410000},
+ {0xdaf3f04651d47b4c, 0x3c0cdd765f114000},
+ {0x88d8762bf324cd0f, 0xa5880a69fb6ac800},
+ {0xab0e93b6efee0053, 0x8eea0d047a457a00},
+ {0xd5d238a4abe98068, 0x72a4904598d6d880},
+ {0x85a36366eb71f041, 0x47a6da2b7f864750},
+ {0xa70c3c40a64e6c51, 0x999090b65f67d924},
+ {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d},
+ {0x82818f1281ed449f, 0xbff8f10e7a8921a5},
+ {0xa321f2d7226895c7, 0xaff72d52192b6a0e},
+ {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491},
+ {0xfee50b7025c36a08, 0x02f236d04753d5b5},
+ {0x9f4f2726179a2245, 0x01d762422c946591},
+ {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6},
+ {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3},
+ {0x9b934c3b330c8577, 0x63cc55f49f88eb30},
+ {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc},
+ {0xf316271c7fc3908a, 0x8bef464e3945ef7b},
+ {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad},
+ {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318},
+ {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde},
+ {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b},
+ {0xb975d6b6ee39e436, 0xb3e2fd538e122b45},
+ {0xe7d34c64a9c85d44, 0x60dbbca87196b617},
+ {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce},
+ {0xb51d13aea4a488dd, 0x6babab6398bdbe42},
+ {0xe264589a4dcdab14, 0xc696963c7eed2dd2},
+ {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3},
+ {0xb0de65388cc8ada8, 0x3b25a55f43294bcc},
+ {0xdd15fe86affad912, 0x49ef0eb713f39ebf},
+ {0x8a2dbf142dfcc7ab, 0x6e3569326c784338},
+ {0xacb92ed9397bf996, 0x49c2c37f07965405},
+ {0xd7e77a8f87daf7fb, 0xdc33745ec97be907},
+ {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4},
+ {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d},
+ {0xd2d80db02aabd62b, 0xf50a3fa490c30191},
+ {0x83c7088e1aab65db, 0x792667c6da79e0fb},
+ {0xa4b8cab1a1563f52, 0x577001b891185939},
+ {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87},
+ {0x80b05e5ac60b6178, 0x544f8158315b05b5},
+ {0xa0dc75f1778e39d6, 0x696361ae3db1c722},
+ {0xc913936dd571c84c, 0x03bc3a19cd1e38ea},
+ {0xfb5878494ace3a5f, 0x04ab48a04065c724},
+ {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77},
+ {0xc45d1df942711d9a, 0x3ba5d0bd324f8395},
+ {0xf5746577930d6500, 0xca8f44ec7ee3647a},
+ {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc},
+ {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f},
+ {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f},
+ {0x95d04aee3b80ece5, 0xbba1f1d158724a13},
+ {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98},
+ {0xea1575143cf97226, 0xf52d09d71a3293be},
+ {0x924d692ca61be758, 0x593c2626705f9c57},
+ {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d},
+ {0xe498f455c38b997a, 0x0b6dfb9c0f956448},
+ {0x8edf98b59a373fec, 0x4724bd4189bd5ead},
+ {0xb2977ee300c50fe7, 0x58edec91ec2cb658},
+ {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee},
+ {0x8b865b215899f46c, 0xbd79e0d20082ee75},
+ {0xae67f1e9aec07187, 0xecd8590680a3aa12},
+ {0xda01ee641a708de9, 0xe80e6f4820cc9496},
+ {0x884134fe908658b2, 0x3109058d147fdcde},
+ {0xaa51823e34a7eede, 0xbd4b46f0599fd416},
+ {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b},
+ {0x850fadc09923329e, 0x03e2cf6bc604ddb1},
+ {0xa6539930bf6bff45, 0x84db8346b786151d},
+ {0xcfe87f7cef46ff16, 0xe612641865679a64},
+ {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f},
+ {0xa26da3999aef7749, 0xe3be5e330f38f09e},
+ {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6},
+ {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7},
+ {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb},
+ {0xc646d63501a1511d, 0xb281e1fd541501b9},
+ {0xf7d88bc24209a565, 0x1f225a7ca91a4227},
+ {0x9ae757596946075f, 0x3375788de9b06959},
+ {0xc1a12d2fc3978937, 0x0052d6b1641c83af},
+ {0xf209787bb47d6b84, 0xc0678c5dbd23a49b},
+ {0x9745eb4d50ce6332, 0xf840b7ba963646e1},
+ {0xbd176620a501fbff, 0xb650e5a93bc3d899},
+ {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf},
+ {0x93ba47c980e98cdf, 0xc66f336c36b10138},
+ {0xb8a8d9bbe123f017, 0xb80b0047445d4185},
+ {0xe6d3102ad96cec1d, 0xa60dc059157491e6},
+ {0x9043ea1ac7e41392, 0x87c89837ad68db30},
+ {0xb454e4a179dd1877, 0x29babe4598c311fc},
+ {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b},
+ {0x8ce2529e2734bb1d, 0x1899e4a65f58660d},
+ {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90},
+ {0xdc21a1171d42645d, 0x76707543f4fa1f74},
+ {0x899504ae72497eba, 0x6a06494a791c53a9},
+ {0xabfa45da0edbde69, 0x0487db9d17636893},
+ {0xd6f8d7509292d603, 0x45a9d2845d3c42b7},
+ {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3},
+ {0xa7f26836f282b732, 0x8e6cac7768d7141f},
+ {0xd1ef0244af2364ff, 0x3207d795430cd927},
+ {0x8335616aed761f1f, 0x7f44e6bd49e807b9},
+ {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7},
+ {0xcd036837130890a1, 0x36dba887c37a8c10},
+ {0x802221226be55a64, 0xc2494954da2c978a},
+ {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d},
+ {0xc83553c5c8965d3d, 0x6f92829494e5acc8},
+ {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa},
+ {0x9c69a97284b578d7, 0xff2a760414536efc},
+ {0xc38413cf25e2d70d, 0xfef5138519684abb},
+ {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a},
+ {0x98bf2f79d5993802, 0xef2f773ffbd97a62},
+ {0xbeeefb584aff8603, 0xaafb550ffacfd8fb},
+ {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39},
+ {0x952ab45cfa97a0b2, 0xdd945a747bf26184},
+ {0xba756174393d88df, 0x94f971119aeef9e5},
+ {0xe912b9d1478ceb17, 0x7a37cd5601aab85e},
+ {0x91abb422ccb812ee, 0xac62e055c10ab33b},
+ {0xb616a12b7fe617aa, 0x577b986b314d600a},
+ {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c},
+ {0x8e41ade9fbebc27d, 0x14588f13be847308},
+ {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9},
+ {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc},
+ {0x8aec23d680043bee, 0x25de7bb9480d5855},
+ {0xada72ccc20054ae9, 0xaf561aa79a10ae6b},
+ {0xd910f7ff28069da4, 0x1b2ba1518094da05},
+ {0x87aa9aff79042286, 0x90fb44d2f05d0843},
+ {0xa99541bf57452b28, 0x353a1607ac744a54},
+ {0xd3fa922f2d1675f2, 0x42889b8997915ce9},
+ {0x847c9b5d7c2e09b7, 0x69956135febada12},
+ {0xa59bc234db398c25, 0x43fab9837e699096},
+ {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc},
+ {0x8161afb94b44f57d, 0x1d1be0eebac278f6},
+ {0xa1ba1ba79e1632dc, 0x6462d92a69731733},
+ {0xca28a291859bbf93, 0x7d7b8f7503cfdcff},
+ {0xfcb2cb35e702af78, 0x5cda735244c3d43f},
+ {0x9defbf01b061adab, 0x3a0888136afa64a8},
+ {0xc56baec21c7a1916, 0x088aaa1845b8fdd1},
+ {0xf6c69a72a3989f5b, 0x8aad549e57273d46},
+ {0x9a3c2087a63f6399, 0x36ac54e2f678864c},
+ {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de},
+ {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6},
+ {0x969eb7c47859e743, 0x9f644ae5a4b1b326},
+ {0xbc4665b596706114, 0x873d5d9f0dde1fef},
+ {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb},
+ {0x9316ff75dd87cbd8, 0x09a7f12442d588f3},
+ {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30},
+ {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb},
+ {0x8fa475791a569d10, 0xf96e017d694487bd},
+ {0xb38d92d760ec4455, 0x37c981dcc395a9ad},
+ {0xe070f78d3927556a, 0x85bbe253f47b1418},
+ {0x8c469ab843b89562, 0x93956d7478ccec8f},
+ {0xaf58416654a6babb, 0x387ac8d1970027b3},
+ {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f},
+ {0x88fcf317f22241e2, 0x441fece3bdf81f04},
+ {0xab3c2fddeeaad25a, 0xd527e81cad7626c4},
+ {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075},
+ {0x85c7056562757456, 0xf6872d5667844e4a},
+ {0xa738c6bebb12d16c, 0xb428f8ac016561dc},
+ {0xd106f86e69d785c7, 0xe13336d701beba53},
+ {0x82a45b450226b39c, 0xecc0024661173474},
+ {0xa34d721642b06084, 0x27f002d7f95d0191},
+ {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5},
+ {0xff290242c83396ce, 0x7e67047175a15272},
+ {0x9f79a169bd203e41, 0x0f0062c6e984d387},
+ {0xc75809c42c684dd1, 0x52c07b78a3e60869},
+ {0xf92e0c3537826145, 0xa7709a56ccdf8a83},
+ {0x9bbcc7a142b17ccb, 0x88a66076400bb692},
+ {0xc2abf989935ddbfe, 0x6acff893d00ea436},
+ {0xf356f7ebf83552fe, 0x0583f6b8c4124d44},
+ {0x98165af37b2153de, 0xc3727a337a8b704b},
+ {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d},
+ {0xeda2ee1c7064130c, 0x1162def06f79df74},
+ {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9},
+ {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693},
+ {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438},
+ {0x910ab1d4db9914a0, 0x1d9c9892400a22a3},
+ {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c},
+ {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e},
+ {0x8da471a9de737e24, 0x5ceaecfed289e5d3},
+ {0xb10d8e1456105dad, 0x7425a83e872c5f48},
+ {0xdd50f1996b947518, 0xd12f124e28f7771a},
+ {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70},
+ {0xace73cbfdc0bfb7b, 0x636cc64d1001550c},
+ {0xd8210befd30efa5a, 0x3c47f7e05401aa4f},
+ {0x8714a775e3e95c78, 0x65acfaec34810a72},
+ {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e},
+ {0xd31045a8341ca07c, 0x1ede48111209a051},
+ {0x83ea2b892091e44d, 0x934aed0aab460433},
+ {0xa4e4b66b68b65d60, 0xf81da84d56178540},
+ {0xce1de40642e3f4b9, 0x36251260ab9d668f},
+ {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a},
+ {0xa1075a24e4421730, 0xb24cf65b8612f820},
+ {0xc94930ae1d529cfc, 0xdee033f26797b628},
+ {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2},
+ {0x9d412e0806e88aa5, 0x8e1f289560ee864f},
+ {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3},
+ {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc},
+ {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a},
+ {0xbff610b0cc6edd3f, 0x17fd090a58d32af4},
+ {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1},
+ {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f},
+ {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2},
+ {0xea53df5fd18d5513, 0x84c86189216dc5ee},
+ {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5},
+ {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2},
+ {0xe4d5e82392a40515, 0x0fabaf3feaa5334b},
+ {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f},
+ {0xb2c71d5bca9023f8, 0x743e20e9ef511013},
+ {0xdf78e4b2bd342cf6, 0x914da9246b255417},
+ {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f},
+ {0xae9672aba3d0c320, 0xa184ac2473b529b2},
+ {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f},
+ {0x8865899617fb1871, 0x7e2fa67c7a658893},
+ {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8},
+ {0xd51ea6fa85785631, 0x552a74227f3ea566},
+ {0x8533285c936b35de, 0xd53a88958f872760},
+ {0xa67ff273b8460356, 0x8a892abaf368f138},
+ {0xd01fef10a657842c, 0x2d2b7569b0432d86},
+ {0x8213f56a67f6b29b, 0x9c3b29620e29fc74},
+ {0xa298f2c501f45f42, 0x8349f3ba91b47b90},
+ {0xcb3f2f7642717713, 0x241c70a936219a74},
+ {0xfe0efb53d30dd4d7, 0xed238cd383aa0111},
+ {0x9ec95d1463e8a506, 0xf4363804324a40ab},
+ {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6},
+ {0xf81aa16fdc1b81da, 0xdd94b7868e94050b},
+ {0x9b10a4e5e9913128, 0xca7cf2b4191c8327},
+ {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1},
+ {0xf24a01a73cf2dccf, 0xbc633b39673c8ced},
+ {0x976e41088617ca01, 0xd5be0503e085d814},
+ {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19},
+ {0xec9c459d51852ba2, 0xddf8e7d60ed1219f},
+ {0x93e1ab8252f33b45, 0xcabb90e5c942b504},
+ {0xb8da1662e7b00a17, 0x3d6a751f3b936244},
+ {0xe7109bfba19c0c9d, 0x0cc512670a783ad5},
+ {0x906a617d450187e2, 0x27fb2b80668b24c6},
+ {0xb484f9dc9641e9da, 0xb1f9f660802dedf7},
+ {0xe1a63853bbd26451, 0x5e7873f8a0396974},
+ {0x8d07e33455637eb2, 0xdb0b487b6423e1e9},
+ {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63},
+ {0xdc5c5301c56b75f7, 0x7641a140cc7810fc},
+ {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e},
+ {0xac2820d9623bf429, 0x546345fa9fbdcd45},
+ {0xd732290fbacaf133, 0xa97c177947ad4096},
+ {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e},
+ {0xa81f301449ee8c70, 0x5c68f256bfff5a75},
+ {0xd226fc195c6a2f8c, 0x73832eec6fff3112},
+ {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac},
+ {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56},
+ {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec},
+ {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4},
+ {0xa0555e361951c366, 0xd7e105bcc3326220},
+ {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8},
+ {0xfa856334878fc150, 0xb14f98f6f0feb952},
+ {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4},
+ {0xc3b8358109e84f07, 0x0a862f80ec4700c9},
+ {0xf4a642e14c6262c8, 0xcd27bb612758c0fb},
+ {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d},
+ {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4},
+ {0xeeea5d5004981478, 0x1858ccfce06cac75},
+ {0x95527a5202df0ccb, 0x0f37801e0c43ebc9},
+ {0xbaa718e68396cffd, 0xd30560258f54e6bb},
+ {0xe950df20247c83fd, 0x47c6b82ef32a206a},
+ {0x91d28b7416cdd27e, 0x4cdc331d57fa5442},
+ {0xb6472e511c81471d, 0xe0133fe4adf8e953},
+ {0xe3d8f9e563a198e5, 0x58180fddd97723a7},
+ {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649},
+ {0xb201833b35d63f73, 0x2cd2cc6551e513db},
+ {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2},
+ {0x8b112e86420f6191, 0xfb04afaf27faf783},
+ {0xadd57a27d29339f6, 0x79c5db9af1f9b564},
+ {0xd94ad8b1c7380874, 0x18375281ae7822bd},
+ {0x87cec76f1c830548, 0x8f2293910d0b15b6},
+ {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23},
+ {0xd433179d9c8cb841, 0x5fa60692a46151ec},
+ {0x849feec281d7f328, 0xdbc7c41ba6bcd334},
+ {0xa5c7ea73224deff3, 0x12b9b522906c0801},
+ {0xcf39e50feae16bef, 0xd768226b34870a01},
+ {0x81842f29f2cce375, 0xe6a1158300d46641},
+ {0xa1e53af46f801c53, 0x60495ae3c1097fd1},
+ {0xca5e89b18b602368, 0x385bb19cb14bdfc5},
+ {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6},
+ {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2},
+ {0xc5a05277621be293, 0xc7098b7305241886},
+ { 0xf70867153aa2db38,
+ 0xb8cbee4fc66d1ea8 }
+#else
+ {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b},
+ {0xce5d73ff402d98e3, 0xfb0a3d212dc81290},
+ {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f},
+ {0x86a8d39ef77164bc, 0xae5dff9c02033198},
+ {0xd98ddaee19068c76, 0x3badd624dd9b0958},
+ {0xafbd2350644eeacf, 0xe5d1929ef90898fb},
+ {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2},
+ {0xe55990879ddcaabd, 0xcc420a6a101d0516},
+ {0xb94470938fa89bce, 0xf808e40e8d5b3e6a},
+ {0x95a8637627989aad, 0xdde7001379a44aa9},
+ {0xf1c90080baf72cb1, 0x5324c68b12dd6339},
+ {0xc350000000000000, 0x0000000000000000},
+ {0x9dc5ada82b70b59d, 0xf020000000000000},
+ {0xfee50b7025c36a08, 0x02f236d04753d5b5},
+ {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87},
+ {0xa6539930bf6bff45, 0x84db8346b786151d},
+ {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3},
+ {0xd910f7ff28069da4, 0x1b2ba1518094da05},
+ {0xaf58416654a6babb, 0x387ac8d1970027b3},
+ {0x8da471a9de737e24, 0x5ceaecfed289e5d3},
+ {0xe4d5e82392a40515, 0x0fabaf3feaa5334b},
+ {0xb8da1662e7b00a17, 0x3d6a751f3b936244},
+ { 0x95527a5202df0ccb,
+ 0x0f37801e0c43ebc9 }
+#endif
+ };
+
+#if FMT_USE_FULL_CACHE_DRAGONBOX
+ return pow10_significands[k - float_info<double>::min_k];
+#else
+ static constexpr const uint64_t powers_of_5_64[] = {
+ 0x0000000000000001, 0x0000000000000005, 0x0000000000000019,
+ 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35,
+ 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1,
+ 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd,
+ 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9,
+ 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5,
+ 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631,
+ 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed,
+ 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9};
+
+ static const int compression_ratio = 27;
+
+ // Compute base index.
+ int cache_index = (k - float_info<double>::min_k) / compression_ratio;
+ int kb = cache_index * compression_ratio + float_info<double>::min_k;
+ int offset = k - kb;
+
+ // Get base cache.
+ uint128_fallback base_cache = pow10_significands[cache_index];
+ if (offset == 0) return base_cache;
+
+ // Compute the required amount of bit-shift.
+ int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset;
+ FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected");
+
+ // Try to recover the real cache.
+ uint64_t pow5 = powers_of_5_64[offset];
+ uint128_fallback recovered_cache = umul128(base_cache.high(), pow5);
+ uint128_fallback middle_low = umul128(base_cache.low(), pow5);
+
+ recovered_cache += middle_low.high();
+
+ uint64_t high_to_middle = recovered_cache.high() << (64 - alpha);
+ uint64_t middle_to_low = recovered_cache.low() << (64 - alpha);
+
+ recovered_cache =
+ uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle,
+ ((middle_low.low() >> alpha) | middle_to_low)};
+ FMT_ASSERT(recovered_cache.low() + 1 != 0, "");
+ return {recovered_cache.high(), recovered_cache.low() + 1};
+#endif
+ }
+
+ struct compute_mul_result {
+ carrier_uint result;
+ bool is_integer;
+ };
+ struct compute_mul_parity_result {
+ bool parity;
+ bool is_integer;
+ };
+
+ static compute_mul_result compute_mul(
+ carrier_uint u, const cache_entry_type& cache) noexcept {
+ auto r = umul192_upper128(u, cache);
+ return {r.high(), r.low() == 0};
+ }
+
+ static uint32_t compute_delta(cache_entry_type const& cache,
+ int beta) noexcept {
+ return static_cast<uint32_t>(cache.high() >> (64 - 1 - beta));
+ }
+
+ static compute_mul_parity_result compute_mul_parity(
+ carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept {
+ FMT_ASSERT(beta >= 1, "");
+ FMT_ASSERT(beta < 64, "");
+
+ auto r = umul192_lower128(two_f, cache);
+ return {((r.high() >> (64 - beta)) & 1) != 0,
+ ((r.high() << beta) | (r.low() >> (64 - beta))) == 0};
+ }
+
+ static carrier_uint compute_left_endpoint_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return (cache.high() -
+ (cache.high() >> (num_significand_bits<double>() + 2))) >>
+ (64 - num_significand_bits<double>() - 1 - beta);
+ }
+
+ static carrier_uint compute_right_endpoint_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return (cache.high() +
+ (cache.high() >> (num_significand_bits<double>() + 1))) >>
+ (64 - num_significand_bits<double>() - 1 - beta);
+ }
+
+ static carrier_uint compute_round_up_for_shorter_interval_case(
+ const cache_entry_type& cache, int beta) noexcept {
+ return ((cache.high() >> (64 - num_significand_bits<double>() - 2 - beta)) +
+ 1) /
+ 2;
+ }
+};
+
+// Various integer checks
+template <class 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;
+ return exponent >= case_shorter_interval_left_endpoint_lower_threshold &&
+ exponent <= case_shorter_interval_left_endpoint_upper_threshold;
+}
+
+// Remove trailing zeros from n and return the number of zeros removed (float)
+FMT_INLINE int remove_trailing_zeros(uint32_t& n) noexcept {
+ FMT_ASSERT(n != 0, "");
+ const uint32_t mod_inv_5 = 0xcccccccd;
+ const uint32_t mod_inv_25 = 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;
+ n = q;
+ s += 2;
+ }
+ auto q = rotr(n * mod_inv_5, 1);
+ if (q <= max_value<uint32_t>() / 10) {
+ n = q;
+ s |= 1;
+ }
+
+ return s;
+}
+
+// Removes trailing zeros and returns the number of zeros removed (double)
+FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept {
+ FMT_ASSERT(n != 0, "");
+
+ // This magic number is ceil(2^90 / 10^8).
+ constexpr uint64_t magic_number = 12379400392853802749ull;
+ auto nm = umul128(n, magic_number);
+
+ // 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.
+ 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;
+ }
+
+ 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;
+
+ int s = 0;
+ while (true) {
+ auto q = rotr(n * mod_inv_25, 2);
+ if (q > max_value<uint64_t>() / 100) break;
+ n = q;
+ s += 2;
+ }
+ auto q = rotr(n * mod_inv_5, 1);
+ if (q <= max_value<uint64_t>() / 10) {
+ n = q;
+ s |= 1;
+ }
+
+ return s;
+}
+
+// The main algorithm for shorter interval case
+template <class T>
+FMT_INLINE decimal_fp<T> shorter_interval_case(int exponent) noexcept {
+ decimal_fp<T> ret_value;
+ // Compute k and beta
+ const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent);
+ const int beta = exponent + floor_log2_pow10(-minus_k);
+
+ // Compute xi and zi
+ using cache_entry_type = typename cache_accessor<T>::cache_entry_type;
+ const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
+
+ auto xi = cache_accessor<T>::compute_left_endpoint_for_shorter_interval_case(
+ cache, beta);
+ auto zi = cache_accessor<T>::compute_right_endpoint_for_shorter_interval_case(
+ cache, beta);
+
+ // If the left endpoint is not an integer, increase it
+ if (!is_left_endpoint_integer_shorter_interval<T>(exponent)) ++xi;
+
+ // Try bigger divisor
+ ret_value.significand = zi / 10;
+
+ // If succeed, remove trailing zeros if necessary and return
+ if (ret_value.significand * 10 >= xi) {
+ ret_value.exponent = minus_k + 1;
+ ret_value.exponent += remove_trailing_zeros(ret_value.significand);
+ return ret_value;
+ }
+
+ // Otherwise, compute the round-up of y
+ ret_value.significand =
+ cache_accessor<T>::compute_round_up_for_shorter_interval_case(cache,
+ beta);
+ ret_value.exponent = minus_k;
+
+ // When tie occurs, choose one of them according to the rule
+ if (exponent >= float_info<T>::shorter_interval_tie_lower_threshold &&
+ exponent <= float_info<T>::shorter_interval_tie_upper_threshold) {
+ ret_value.significand = ret_value.significand % 2 == 0
+ ? ret_value.significand
+ : ret_value.significand - 1;
+ } else if (ret_value.significand < xi) {
+ ++ret_value.significand;
+ }
+ return ret_value;
+}
+
+template <typename T> decimal_fp<T> to_decimal(T x) noexcept {
+ // Step 1: integer promotion & Schubfach multiplier calculation.
+
+ using carrier_uint = typename float_info<T>::carrier_uint;
+ using cache_entry_type = typename cache_accessor<T>::cache_entry_type;
+ auto br = bit_cast<carrier_uint>(x);
+
+ // Extract significand bits and exponent bits.
+ const carrier_uint significand_mask =
+ (static_cast<carrier_uint>(1) << num_significand_bits<T>()) - 1;
+ carrier_uint significand = (br & significand_mask);
+ int exponent =
+ static_cast<int>((br & exponent_mask<T>()) >> num_significand_bits<T>());
+
+ if (exponent != 0) { // Check if normal.
+ exponent -= exponent_bias<T>() + num_significand_bits<T>();
+
+ // Shorter interval case; proceed like Schubfach.
+ // In fact, when exponent == 1 and significand == 0, the interval is
+ // regular. However, it can be shown that the end-results are anyway same.
+ if (significand == 0) return shorter_interval_case<T>(exponent);
+
+ significand |= (static_cast<carrier_uint>(1) << num_significand_bits<T>());
+ } else {
+ // Subnormal case; the interval is always regular.
+ if (significand == 0) return {0, 0};
+ exponent =
+ std::numeric_limits<T>::min_exponent - num_significand_bits<T>() - 1;
+ }
+
+ const bool include_left_endpoint = (significand % 2 == 0);
+ const bool include_right_endpoint = include_left_endpoint;
+
+ // Compute k and beta.
+ const int minus_k = floor_log10_pow2(exponent) - float_info<T>::kappa;
+ const cache_entry_type cache = cache_accessor<T>::get_cached_power(-minus_k);
+ const int beta = exponent + floor_log2_pow10(-minus_k);
+
+ // Compute zi and deltai.
+ // 10^kappa <= deltai < 10^(kappa + 1)
+ const uint32_t deltai = cache_accessor<T>::compute_delta(cache, beta);
+ const carrier_uint two_fc = significand << 1;
+
+ // For the case of binary32, the result of integer check is not correct for
+ // 29711844 * 2^-82
+ // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18
+ // and 29711844 * 2^-81
+ // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17,
+ // and they are the unique counterexamples. However, since 29711844 is even,
+ // this does not cause any problem for the endpoints calculations; it can only
+ // cause a problem when we need to perform integer check for the center.
+ // Fortunately, with these inputs, that branch is never executed, so we are
+ // fine.
+ const typename cache_accessor<T>::compute_mul_result z_mul =
+ cache_accessor<T>::compute_mul((two_fc | 1) << beta, cache);
+
+ // Step 2: Try larger divisor; remove trailing zeros if necessary.
+
+ // Using an upper bound on zi, we might be able to optimize the division
+ // better than the compiler; we are computing zi / big_divisor here.
+ decimal_fp<T> ret_value;
+ ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result);
+ uint32_t r = static_cast<uint32_t>(z_mul.result - float_info<T>::big_divisor *
+ ret_value.significand);
+
+ if (r < deltai) {
+ // Exclude the right endpoint if necessary.
+ if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) {
+ --ret_value.significand;
+ r = float_info<T>::big_divisor;
+ goto small_divisor_case_label;
+ }
+ } else if (r > deltai) {
+ goto small_divisor_case_label;
+ } else {
+ // r == deltai; compare fractional parts.
+ const typename cache_accessor<T>::compute_mul_parity_result x_mul =
+ cache_accessor<T>::compute_mul_parity(two_fc - 1, cache, beta);
+
+ if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint)))
+ goto small_divisor_case_label;
+ }
+ ret_value.exponent = minus_k + float_info<T>::kappa + 1;
+
+ // We may need to remove trailing zeros.
+ ret_value.exponent += remove_trailing_zeros(ret_value.significand);
+ return ret_value;
+
+ // Step 3: Find the significand with the smaller divisor.
+
+small_divisor_case_label:
+ ret_value.significand *= 10;
+ ret_value.exponent = minus_k + float_info<T>::kappa;
+
+ uint32_t dist = r - (deltai / 2) + (float_info<T>::small_divisor / 2);
+ const bool approx_y_parity =
+ ((dist ^ (float_info<T>::small_divisor / 2)) & 1) != 0;
+
+ // Is dist divisible by 10^kappa?
+ const bool divisible_by_small_divisor =
+ check_divisibility_and_divide_by_pow10<float_info<T>::kappa>(dist);
+
+ // Add dist / 10^kappa to the significand.
+ ret_value.significand += dist;
+
+ if (!divisible_by_small_divisor) return ret_value;
+
+ // Check z^(f) >= epsilon^(f).
+ // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1,
+ // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f).
+ // Since there are only 2 possibilities, we only need to care about the
+ // parity. Also, zi and r should have the same parity since the divisor
+ // is an even number.
+ const auto y_mul = cache_accessor<T>::compute_mul_parity(two_fc, cache, beta);
+
+ // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f),
+ // or equivalently, when y is an integer.
+ if (y_mul.parity != approx_y_parity)
+ --ret_value.significand;
+ else if (y_mul.is_integer & (ret_value.significand % 2 != 0))
+ --ret_value.significand;
+ 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> {
+ FMT_CONSTEXPR auto parse(format_parse_context& ctx)
+ -> format_parse_context::iterator {
+ return ctx.begin();
+ }
+
+ template <typename FormatContext>
+ auto format(const detail::bigint& n, FormatContext& ctx) const ->
+ typename FormatContext::iterator {
+ auto out = ctx.out();
+ bool first = true;
+ for (auto i = n.bigits_.size(); i > 0; --i) {
+ auto value = n.bigits_[i - 1u];
+ if (first) {
+ out = format_to(out, FMT_STRING("{:x}"), value);
+ first = false;
+ continue;
+ }
+ out = format_to(out, FMT_STRING("{:08x}"), value);
+ }
+ if (n.exp_ > 0)
+ out = format_to(out, FMT_STRING("p{}"),
+ n.exp_ * detail::bigint::bigit_bits);
+ return out;
+ }
+};
+
+FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) {
+ for_each_codepoint(s, [this](uint32_t cp, string_view) {
+ if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8"));
+ if (cp <= 0xFFFF) {
+ buffer_.push_back(static_cast<wchar_t>(cp));
+ } else {
+ cp -= 0x10000;
+ buffer_.push_back(static_cast<wchar_t>(0xD800 + (cp >> 10)));
+ buffer_.push_back(static_cast<wchar_t>(0xDC00 + (cp & 0x3FF)));
+ }
+ return true;
+ });
+ buffer_.push_back(0);
+}
+
+FMT_FUNC void format_system_error(detail::buffer<char>& out, int error_code,
+ const char* message) noexcept {
+ FMT_TRY {
+ auto ec = std::error_code(error_code, std::generic_category());
+ write(std::back_inserter(out), std::system_error(ec, message).what());
+ return;
+ }
+ FMT_CATCH(...) {}
+ format_error_code(out, error_code, message);
+}
+
+FMT_FUNC void report_system_error(int error_code,
+ const char* message) noexcept {
+ report_error(format_system_error, error_code, message);
+}
+
+FMT_FUNC std::string vformat(string_view fmt, format_args args) {
+ // Don't optimize the "{}" case to keep the binary size small and because it
+ // can be better optimized in fmt::format anyway.
+ auto buffer = memory_buffer();
+ detail::vformat_to(buffer, fmt, args);
+ return to_string(buffer);
+}
+
+namespace detail {
+#ifdef _WIN32
+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()});
+}
+
+#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,
+ 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);
+}
+
+namespace detail {
+
+struct singleton {
+ unsigned char upper;
+ unsigned char lower_count;
+};
+
+inline auto is_printable(uint16_t x, const singleton* singletons,
+ size_t singletons_size,
+ const unsigned char* singleton_lowers,
+ const unsigned char* normal, size_t normal_size)
+ -> bool {
+ auto upper = x >> 8;
+ auto lower_start = 0;
+ for (size_t i = 0; i < singletons_size; ++i) {
+ auto s = singletons[i];
+ auto lower_end = lower_start + s.lower_count;
+ if (upper < s.upper) break;
+ if (upper == s.upper) {
+ for (auto j = lower_start; j < lower_end; ++j) {
+ if (singleton_lowers[j] == (x & 0xff)) return false;
+ }
+ }
+ lower_start = lower_end;
+ }
+
+ auto xsigned = static_cast<int>(x);
+ auto current = true;
+ for (size_t i = 0; i < normal_size; ++i) {
+ auto v = static_cast<int>(normal[i]);
+ auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v;
+ xsigned -= len;
+ if (xsigned < 0) break;
+ current = !current;
+ }
+ return current;
+}
+
+// This code is generated by support/printable.py.
+FMT_FUNC auto is_printable(uint32_t cp) -> bool {
+ static constexpr singleton singletons0[] = {
+ {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
+ {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
+ {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
+ {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
+ {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
+ {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
+ {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
+ };
+ static constexpr unsigned char singletons0_lower[] = {
+ 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
+ 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
+ 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
+ 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
+ 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
+ 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
+ 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
+ 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
+ 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
+ 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
+ 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
+ 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
+ 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
+ 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
+ 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
+ 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
+ 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
+ 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
+ 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
+ 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
+ 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
+ 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
+ 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
+ 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
+ 0xfe, 0xff,
+ };
+ static constexpr singleton singletons1[] = {
+ {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
+ {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
+ {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
+ {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
+ {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
+ {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
+ {0xfa, 2}, {0xfb, 1},
+ };
+ static constexpr unsigned char singletons1_lower[] = {
+ 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
+ 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
+ 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
+ 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
+ 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
+ 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
+ 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
+ 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
+ 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
+ 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
+ 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
+ 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
+ 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
+ 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
+ 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
+ };
+ static constexpr unsigned char normal0[] = {
+ 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
+ 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
+ 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
+ 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
+ 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
+ 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
+ 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
+ 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
+ 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
+ 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
+ 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
+ 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
+ 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
+ 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
+ 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
+ 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
+ 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
+ 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
+ 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
+ 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
+ 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
+ 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
+ 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
+ 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
+ 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
+ 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
+ };
+ static constexpr unsigned char normal1[] = {
+ 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
+ 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
+ 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
+ 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
+ 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
+ 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
+ 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
+ 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
+ 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
+ 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
+ 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
+ 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
+ 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
+ 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
+ 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
+ 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
+ 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
+ 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
+ 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
+ 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
+ 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
+ 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
+ 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
+ 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
+ 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
+ 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
+ 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
+ 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
+ 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
+ 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
+ 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
+ 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
+ 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
+ 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
+ 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
+ };
+ auto lower = static_cast<uint16_t>(cp);
+ if (cp < 0x10000) {
+ return is_printable(lower, singletons0,
+ sizeof(singletons0) / sizeof(*singletons0),
+ singletons0_lower, normal0, sizeof(normal0));
+ }
+ if (cp < 0x20000) {
+ return is_printable(lower, singletons1,
+ sizeof(singletons1) / sizeof(*singletons1),
+ singletons1_lower, normal1, sizeof(normal1));
+ }
+ if (0x2a6de <= cp && cp < 0x2a700) return false;
+ if (0x2b735 <= cp && cp < 0x2b740) return false;
+ if (0x2b81e <= cp && cp < 0x2b820) return false;
+ if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
+ if (0x2ebe1 <= cp && cp < 0x2f800) return false;
+ if (0x2fa1e <= cp && cp < 0x30000) return false;
+ if (0x3134b <= cp && cp < 0xe0100) return false;
+ if (0xe01f0 <= cp && cp < 0x110000) return false;
+ return cp < 0x110000;
+}
+
+} // namespace detail
+
+FMT_END_NAMESPACE
+
+#endif // FMT_FORMAT_INL_H_
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/format.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
similarity index 62%
rename from wpiutil/src/main/native/fmtlib/include/fmt/format.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
index ee69651..7c607db 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/format.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/format.h
@@ -1,33 +1,33 @@
/*
- Formatting library for C++
+ Formatting library for C++
- Copyright (c) 2012 - present, Victor Zverovich
+ Copyright (c) 2012 - present, Victor Zverovich
- 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:
+ 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 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.
+ 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.
- --- Optional exception to the license ---
+ --- Optional exception to the license ---
- As an exception, if, as a result of your compiling your source code, portions
- of this Software are embedded into a machine-executable object form of such
- source code, you may redistribute such embedded portions in such object form
- without including the above copyright and permission notices.
+ As an exception, if, as a result of your compiling your source code, portions
+ of this Software are embedded into a machine-executable object form of such
+ source code, you may redistribute such embedded portions in such object form
+ without including the above copyright and permission notices.
*/
#ifndef FMT_FORMAT_H_
@@ -35,11 +35,11 @@
#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 <utility> // std::swap
#ifdef __cpp_lib_bit_cast
# include <bit> // std::bitcast
@@ -71,7 +71,7 @@
# define FMT_NOINLINE
#endif
-#if FMT_MSC_VER
+#if FMT_MSC_VERSION
# define FMT_MSC_DEFAULT = default
#else
# define FMT_MSC_DEFAULT
@@ -79,7 +79,7 @@
#ifndef FMT_THROW
# if FMT_EXCEPTIONS
-# if FMT_MSC_VER || FMT_NVCC
+# if FMT_MSC_VERSION || defined(__NVCC__)
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Exception> inline void do_throw(const Exception& x) {
@@ -118,17 +118,10 @@
# endif
#endif
-// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers.
-#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC
-# define FMT_DEPRECATED_ALIAS
-#else
-# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED
-#endif
-
#ifndef FMT_USE_USER_DEFINED_LITERALS
// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs.
# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \
- FMT_MSC_VER >= 1900) && \
+ FMT_MSC_VERSION >= 1900) && \
(!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480)
# define FMT_USE_USER_DEFINED_LITERALS 1
# else
@@ -146,7 +139,7 @@
// __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519.
-#if !FMT_MSC_VER
+#if !FMT_MSC_VERSION
# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION
# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
# endif
@@ -158,22 +151,25 @@
// __builtin_ctz is broken in Intel Compiler Classic on Windows:
// https://github.com/fmtlib/fmt/issues/2510.
#ifndef __ICL
-# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION
+# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \
+ defined(__NVCOMPILER)
# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n)
# endif
-# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || FMT_ICC_VERSION
+# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \
+ FMT_ICC_VERSION || defined(__NVCOMPILER)
# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n)
# endif
#endif
-#if FMT_MSC_VER
+#if FMT_MSC_VERSION
# include <intrin.h> // _BitScanReverse[64], _BitScanForward[64], _umul128
#endif
// Some compilers masquerade as both MSVC and GCC-likes or otherwise support
// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the
// MSVC intrinsics if the clz and clzll builtins are not available.
-#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(FMT_BUILTIN_CTZLL)
+#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \
+ !defined(FMT_BUILTIN_CTZLL)
FMT_BEGIN_NAMESPACE
namespace detail {
// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning.
@@ -243,15 +239,28 @@
FMT_END_NAMESPACE
#endif
-#ifdef FMT_HEADER_ONLY
-# define FMT_HEADER_ONLY_CONSTEXPR20 FMT_CONSTEXPR20
-#else
-# define FMT_HEADER_ONLY_CONSTEXPR20
-#endif
-
FMT_BEGIN_NAMESPACE
namespace detail {
+FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) {
+ ignore_unused(condition);
+#ifdef FMT_FUZZ
+ if (condition) throw std::runtime_error("fuzzing limit reached");
+#endif
+}
+
+template <typename CharT, CharT... C> struct string_literal {
+ static constexpr CharT value[sizeof...(C)] = {C...};
+ constexpr operator basic_string_view<CharT>() const {
+ return {value, sizeof...(C)};
+ }
+};
+
+#if FMT_CPLUSPLUS < 201703L
+template <typename CharT, CharT... C>
+constexpr CharT string_literal<CharT, C...>::value[sizeof...(C)];
+#endif
+
template <typename Streambuf> class formatbuf : public Streambuf {
private:
using char_type = typename Streambuf::char_type;
@@ -284,14 +293,14 @@
};
// Implementation of std::bit_cast for pre-C++20.
-template <typename To, typename From>
+template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) == sizeof(From))>
FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To {
- static_assert(sizeof(To) == sizeof(From), "size mismatch");
#ifdef __cpp_lib_bit_cast
if (is_constant_evaluated()) return std::bit_cast<To>(from);
#endif
auto to = To();
- std::memcpy(&to, &from, sizeof(to));
+ // The cast suppresses a bogus -Wclass-memaccess on GCC.
+ std::memcpy(static_cast<void*>(&to), &from, sizeof(to));
return to;
}
@@ -310,29 +319,117 @@
#endif
}
-// A fallback implementation of uintptr_t for systems that lack it.
-struct fallback_uintptr {
- unsigned char value[sizeof(void*)];
+class uint128_fallback {
+ private:
+ uint64_t lo_, hi_;
- fallback_uintptr() = default;
- explicit fallback_uintptr(const void* p) {
- *this = bit_cast<fallback_uintptr>(p);
- if (const_check(is_big_endian())) {
- for (size_t i = 0, j = sizeof(void*) - 1; i < j; ++i, --j)
- std::swap(value[i], value[j]);
+ 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) {}
+
+ constexpr uint64_t high() const noexcept { return hi_; }
+ constexpr uint64_t low() const noexcept { return lo_; }
+
+ template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
+ constexpr explicit operator T() const {
+ return static_cast<T>(lo_);
+ }
+
+ friend constexpr auto operator==(const uint128_fallback& lhs,
+ const uint128_fallback& rhs) -> bool {
+ return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_;
+ }
+ friend constexpr auto operator!=(const uint128_fallback& lhs,
+ const uint128_fallback& rhs) -> bool {
+ return !(lhs == rhs);
+ }
+ friend constexpr auto operator>(const uint128_fallback& lhs,
+ const uint128_fallback& rhs) -> bool {
+ return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_;
+ }
+ friend constexpr auto operator|(const uint128_fallback& lhs,
+ const uint128_fallback& rhs)
+ -> uint128_fallback {
+ return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_};
+ }
+ friend constexpr auto operator&(const uint128_fallback& lhs,
+ const uint128_fallback& rhs)
+ -> uint128_fallback {
+ return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_};
+ }
+ friend auto operator+(const uint128_fallback& lhs,
+ const uint128_fallback& rhs) -> uint128_fallback {
+ auto result = uint128_fallback(lhs);
+ result += rhs;
+ return result;
+ }
+ friend auto operator*(const uint128_fallback& lhs, uint32_t rhs)
+ -> uint128_fallback {
+ FMT_ASSERT(lhs.hi_ == 0, "");
+ uint64_t hi = (lhs.lo_ >> 32) * rhs;
+ uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs;
+ uint64_t new_lo = (hi << 32) + lo;
+ return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo};
+ }
+ friend auto operator-(const uint128_fallback& lhs, uint64_t rhs)
+ -> uint128_fallback {
+ return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs};
+ }
+ FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback {
+ if (shift == 64) return {0, hi_};
+ if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64);
+ return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)};
+ }
+ FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback {
+ if (shift == 64) return {lo_, 0};
+ if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64);
+ return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)};
+ }
+ FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& {
+ return *this = *this >> shift;
+ }
+ FMT_CONSTEXPR void operator+=(uint128_fallback n) {
+ uint64_t new_lo = lo_ + n.lo_;
+ uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0);
+ FMT_ASSERT(new_hi >= hi_, "");
+ lo_ = new_lo;
+ hi_ = new_hi;
+ }
+
+ FMT_CONSTEXPR20 uint128_fallback& operator+=(uint64_t n) noexcept {
+ if (is_constant_evaluated()) {
+ lo_ += n;
+ hi_ += (lo_ < n ? 1 : 0);
+ return *this;
}
+#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__)
+ unsigned long long carry;
+ lo_ = __builtin_addcll(lo_, n, 0, &carry);
+ hi_ += carry;
+#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__)
+ unsigned long long result;
+ auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result);
+ lo_ = result;
+ hi_ += carry;
+#elif defined(_MSC_VER) && defined(_M_X64)
+ auto carry = _addcarry_u64(0, lo_, n, &lo_);
+ _addcarry_u64(carry, hi_, 0, &hi_);
+#else
+ lo_ += n;
+ hi_ += (lo_ < n ? 1 : 0);
+#endif
+ return *this;
}
};
+
+using uint128_t = conditional_t<FMT_USE_INT128, uint128_opt, uint128_fallback>;
+
#ifdef UINTPTR_MAX
using uintptr_t = ::uintptr_t;
-inline auto to_uintptr(const void* p) -> uintptr_t {
- return bit_cast<uintptr_t>(p);
-}
#else
-using uintptr_t = fallback_uintptr;
-inline auto to_uintptr(const void* p) -> fallback_uintptr {
- return fallback_uintptr(p);
-}
+using uintptr_t = uint128_t;
#endif
// Returns the largest possible value for type T. Same as
@@ -344,16 +441,31 @@
return std::numeric_limits<T>::digits;
}
// std::numeric_limits<T>::digits may return 0 for 128-bit ints.
-template <> constexpr auto num_bits<int128_t>() -> int { return 128; }
+template <> constexpr auto num_bits<int128_opt>() -> int { return 128; }
template <> constexpr auto num_bits<uint128_t>() -> int { return 128; }
-template <> constexpr auto num_bits<fallback_uintptr>() -> int {
- return static_cast<int>(sizeof(void*) *
- std::numeric_limits<unsigned char>::digits);
+
+// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t
+// and 128-bit pointers to uint128_fallback.
+template <typename To, typename From, FMT_ENABLE_IF(sizeof(To) > sizeof(From))>
+inline auto bit_cast(const From& from) -> To {
+ constexpr auto size = static_cast<int>(sizeof(From) / sizeof(unsigned));
+ struct data_t {
+ unsigned value[static_cast<unsigned>(size)];
+ } data = bit_cast<data_t>(from);
+ auto result = To();
+ if (const_check(is_big_endian())) {
+ for (int i = 0; i < size; ++i)
+ result = (result << num_bits<unsigned>()) | data.value[i];
+ } else {
+ for (int i = size - 1; i >= 0; --i)
+ result = (result << num_bits<unsigned>()) | data.value[i];
+ }
+ return result;
}
FMT_INLINE void assume(bool condition) {
(void)condition;
-#if FMT_HAS_BUILTIN(__builtin_assume)
+#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION
__builtin_assume(condition);
#endif
}
@@ -495,19 +607,23 @@
constexpr const int shiftc[] = {0, 18, 12, 6, 0};
constexpr const int shifte[] = {0, 6, 4, 2, 0};
- int len = code_point_length(s);
- const char* next = s + len;
+ int len = code_point_length_impl(*s);
+ // 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.
+ const char* next = s + len + !len;
+
+ using uchar = unsigned char;
// Assume a four-byte character and load four bytes. Unused bits are
// shifted out.
- *c = uint32_t(s[0] & masks[len]) << 18;
- *c |= uint32_t(s[1] & 0x3f) << 12;
- *c |= uint32_t(s[2] & 0x3f) << 6;
- *c |= uint32_t(s[3] & 0x3f) << 0;
+ *c = uint32_t(uchar(s[0]) & masks[len]) << 18;
+ *c |= uint32_t(uchar(s[1]) & 0x3f) << 12;
+ *c |= uint32_t(uchar(s[2]) & 0x3f) << 6;
+ *c |= uint32_t(uchar(s[3]) & 0x3f) << 0;
*c >>= shiftc[len];
// Accumulate the various error conditions.
- using uchar = unsigned char;
*e = (*c < mins[len]) << 6; // non-canonical encoding
*e |= ((*c >> 11) == 0x1b) << 7; // surrogate half?
*e |= (*c > 0x10FFFF) << 8; // out of range?
@@ -531,8 +647,8 @@
auto error = 0;
auto end = utf8_decode(buf_ptr, &cp, &error);
bool result = f(error ? invalid_code_point : cp,
- string_view(ptr, to_unsigned(end - buf_ptr)));
- return result ? end : nullptr;
+ string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr)));
+ return result ? (error ? buf_ptr + 1 : end) : nullptr;
};
auto p = s.data();
const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars.
@@ -595,8 +711,8 @@
}
inline auto compute_width(basic_string_view<char8_type> s) -> size_t {
- return compute_width(basic_string_view<char>(
- reinterpret_cast<const char*>(s.data()), s.size()));
+ return compute_width(
+ string_view(reinterpret_cast<const char*>(s.data()), s.size()));
}
template <typename Char>
@@ -606,9 +722,8 @@
}
// Calculates the index of the nth code point in a UTF-8 string.
-inline auto code_point_index(basic_string_view<char8_type> s, size_t n)
- -> size_t {
- const char8_type* data = s.data();
+inline auto code_point_index(string_view s, size_t n) -> size_t {
+ const char* data = s.data();
size_t num_code_points = 0;
for (size_t i = 0, size = s.size(); i != size; ++i) {
if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i;
@@ -616,11 +731,38 @@
return s.size();
}
+inline auto code_point_index(basic_string_view<char8_type> s, size_t n)
+ -> size_t {
+ return code_point_index(
+ string_view(reinterpret_cast<const char*>(s.data()), s.size()), n);
+}
+
+#ifndef FMT_USE_FLOAT128
+# ifdef __SIZEOF_FLOAT128__
+# define FMT_USE_FLOAT128 1
+# else
+# define FMT_USE_FLOAT128 0
+# endif
+#endif
+#if FMT_USE_FLOAT128
+using float128 = __float128;
+#else
+using float128 = void;
+#endif
+template <typename T> using is_float128 = std::is_same<T, float128>;
+
+template <typename T>
+using is_floating_point =
+ bool_constant<std::is_floating_point<T>::value || is_float128<T>::value>;
+
template <typename T, bool = std::is_floating_point<T>::value>
struct is_fast_float : bool_constant<std::numeric_limits<T>::is_iec559 &&
sizeof(T) <= sizeof(double)> {};
template <typename T> struct is_fast_float<T, false> : std::false_type {};
+template <typename T>
+using is_double_double = bool_constant<std::numeric_limits<T>::digits == 106>;
+
#ifndef FMT_USE_FULL_CACHE_DRAGONBOX
# define FMT_USE_FULL_CACHE_DRAGONBOX 0
#endif
@@ -698,9 +840,7 @@
const Allocator& alloc = Allocator())
: alloc_(alloc) {
this->set(store_, SIZE);
- if (detail::is_constant_evaluated()) {
- detail::fill_n(store_, SIZE, T{});
- }
+ if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T());
}
FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); }
@@ -712,18 +852,14 @@
size_t size = other.size(), capacity = other.capacity();
if (data == other.store_) {
this->set(store_, capacity);
- if (detail::is_constant_evaluated()) {
- detail::copy_str<T>(other.store_, other.store_ + size,
- detail::make_checked(store_, capacity));
- } else {
- std::uninitialized_copy(other.store_, other.store_ + size,
- detail::make_checked(store_, capacity));
- }
+ detail::copy_str<T>(other.store_, other.store_ + size,
+ detail::make_checked(store_, capacity));
} else {
this->set(data, capacity);
// Set pointer to the inline array so that delete is not called
// when deallocating.
other.set(other.store_, 0);
+ other.clear();
}
this->resize(size);
}
@@ -735,8 +871,7 @@
of the other object to it.
\endrst
*/
- FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other)
- FMT_NOEXCEPT {
+ FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept {
move(other);
}
@@ -745,8 +880,7 @@
Moves the content of the other ``basic_memory_buffer`` object to this one.
\endrst
*/
- auto operator=(basic_memory_buffer&& other) FMT_NOEXCEPT
- -> basic_memory_buffer& {
+ auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& {
FMT_ASSERT(this != &other, "");
deallocate();
move(other);
@@ -776,9 +910,7 @@
template <typename T, size_t SIZE, typename Allocator>
FMT_CONSTEXPR20 void basic_memory_buffer<T, SIZE, Allocator>::grow(
size_t size) {
-#ifdef FMT_FUZZ
- if (size > 5000) throw std::runtime_error("fuzz mode - won't grow that much");
-#endif
+ 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;
@@ -806,8 +938,11 @@
};
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
@@ -820,39 +955,17 @@
format_error& operator=(const format_error&) = default;
format_error(format_error&&) = default;
format_error& operator=(format_error&&) = default;
- ~format_error() FMT_NOEXCEPT override FMT_MSC_DEFAULT;
+ ~format_error() noexcept override FMT_MSC_DEFAULT;
};
-/**
- \rst
- Constructs a `~fmt::format_arg_store` object that contains references
- to arguments and can be implicitly converted to `~fmt::format_args`.
- If ``fmt`` is a compile-time string then `make_args_checked` checks
- its validity at compile time.
- \endrst
- */
-template <typename... Args, typename S, typename Char = char_t<S>>
-FMT_INLINE auto make_args_checked(const S& fmt,
- const remove_reference_t<Args>&... args)
- -> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
- static_assert(
- detail::count<(
- std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
- std::is_reference<Args>::value)...>() == 0,
- "passing views as lvalues is disallowed");
- detail::check_format_string<Args...>(fmt);
- return {args...};
-}
-
-// compile-time support
namespace detail_exported {
-#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename Char, size_t N> struct fixed_string {
constexpr fixed_string(const Char (&str)[N]) {
detail::copy_str<Char, const Char*, Char*>(static_cast<const Char*>(str),
str + N, data);
}
- Char data[N]{};
+ Char data[N] = {};
};
#endif
@@ -874,30 +987,31 @@
FMT_BEGIN_DETAIL_NAMESPACE
template <typename T> struct is_integral : std::is_integral<T> {};
-template <> struct is_integral<int128_t> : std::true_type {};
+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_t>::value>;
+ std::is_same<T, int128_opt>::value>;
// Returns true if value is negative, false otherwise.
// Same as `value < 0` but doesn't produce warnings if T is an unsigned type.
template <typename T, FMT_ENABLE_IF(is_signed<T>::value)>
-FMT_CONSTEXPR auto is_negative(T value) -> bool {
+constexpr auto is_negative(T value) -> bool {
return value < 0;
}
template <typename T, FMT_ENABLE_IF(!is_signed<T>::value)>
-FMT_CONSTEXPR auto is_negative(T) -> bool {
+constexpr auto is_negative(T) -> bool {
return false;
}
-template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-FMT_CONSTEXPR auto is_supported_floating_point(T) -> uint16_t {
- return (std::is_same<T, float>::value && FMT_USE_FLOAT) ||
- (std::is_same<T, double>::value && FMT_USE_DOUBLE) ||
- (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
+template <typename T>
+FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool {
+ if (std::is_same<T, float>()) return FMT_USE_FLOAT;
+ if (std::is_same<T, double>()) return FMT_USE_DOUBLE;
+ if (std::is_same<T, long double>()) return FMT_USE_LONG_DOUBLE;
+ return true;
}
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to
@@ -948,7 +1062,7 @@
}
}
#if FMT_USE_INT128
-FMT_CONSTEXPR inline auto count_digits(uint128_t n) -> int {
+FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int {
return count_digits_fallback(n);
}
#endif
@@ -989,7 +1103,7 @@
template <int BITS, typename UInt>
FMT_CONSTEXPR auto count_digits(UInt n) -> int {
#ifdef FMT_BUILTIN_CLZ
- if (num_bits<UInt>() == 32)
+ if (!is_constant_evaluated() && num_bits<UInt>() == 32)
return (FMT_BUILTIN_CLZ(static_cast<uint32_t>(n) | 1) ^ 31) / BITS + 1;
#endif
// Lambda avoids unreachable code warnings from NVHPC.
@@ -1002,8 +1116,6 @@
}(n);
}
-template <> auto count_digits<4>(detail::fallback_uintptr n) -> int;
-
#ifdef FMT_BUILTIN_CLZ
// It is a separate function rather than a part of count_digits to workaround
// the lack of static constexpr in constexpr functions.
@@ -1039,15 +1151,11 @@
return count_digits_fallback(n);
}
-template <typename Int> constexpr auto digits10() FMT_NOEXCEPT -> int {
+template <typename Int> constexpr auto digits10() noexcept -> int {
return std::numeric_limits<Int>::digits10;
}
-template <> constexpr auto digits10<int128_t>() FMT_NOEXCEPT -> int {
- return 38;
-}
-template <> constexpr auto digits10<uint128_t>() FMT_NOEXCEPT -> int {
- return 38;
-}
+template <> constexpr auto digits10<int128_opt>() noexcept -> int { return 38; }
+template <> constexpr auto digits10<uint128_t>() noexcept -> int { return 38; }
template <typename Char> struct thousands_sep_result {
std::string grouping;
@@ -1127,7 +1235,7 @@
template <typename Char, typename UInt, typename Iterator,
FMT_ENABLE_IF(!std::is_pointer<remove_cvref_t<Iterator>>::value)>
-inline auto format_decimal(Iterator out, UInt value, int size)
+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];
@@ -1142,35 +1250,13 @@
Char* end = buffer;
do {
const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef";
- unsigned digit = (value & ((1 << BASE_BITS) - 1));
+ unsigned digit = static_cast<unsigned>(value & ((1 << BASE_BITS) - 1));
*--buffer = static_cast<Char>(BASE_BITS < 4 ? static_cast<char>('0' + digit)
: digits[digit]);
} while ((value >>= BASE_BITS) != 0);
return end;
}
-template <unsigned BASE_BITS, typename Char>
-auto format_uint(Char* buffer, detail::fallback_uintptr n, int num_digits,
- bool = false) -> Char* {
- auto char_digits = std::numeric_limits<unsigned char>::digits / 4;
- int start = (num_digits + char_digits - 1) / char_digits - 1;
- if (int start_digits = num_digits % char_digits) {
- unsigned value = n.value[start--];
- buffer = format_uint<BASE_BITS>(buffer, value, start_digits);
- }
- for (; start >= 0; --start) {
- unsigned value = n.value[start];
- buffer += char_digits;
- auto p = buffer;
- for (int i = 0; i < char_digits; ++i) {
- unsigned digit = (value & ((1 << BASE_BITS) - 1));
- *--p = static_cast<Char>("0123456789abcdef"[digit]);
- value >>= BASE_BITS;
- }
- }
- return buffer;
-}
-
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 {
@@ -1200,58 +1286,45 @@
namespace dragonbox {
// Type-specific information that Dragonbox uses.
-template <class T> struct float_info;
+template <typename T, typename Enable = void> struct float_info;
template <> struct float_info<float> {
using carrier_uint = uint32_t;
- static const int significand_bits = 23;
static const int exponent_bits = 8;
- static const int min_exponent = -126;
- static const int max_exponent = 127;
- static const int exponent_bias = -127;
- static const int decimal_digits = 9;
static const int kappa = 1;
static const int big_divisor = 100;
static const int small_divisor = 10;
static const int min_k = -31;
static const int max_k = 46;
- static const int cache_bits = 64;
- static const int divisibility_check_by_5_threshold = 39;
- static const int case_fc_pm_half_lower_threshold = -1;
- static const int case_fc_pm_half_upper_threshold = 6;
- static const int case_fc_lower_threshold = -2;
- static const int case_fc_upper_threshold = 6;
- static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
- static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
static const int shorter_interval_tie_lower_threshold = -35;
static const int shorter_interval_tie_upper_threshold = -35;
- static const int max_trailing_zeros = 7;
};
template <> struct float_info<double> {
using carrier_uint = uint64_t;
- static const int significand_bits = 52;
static const int exponent_bits = 11;
- static const int min_exponent = -1022;
- static const int max_exponent = 1023;
- static const int exponent_bias = -1023;
- static const int decimal_digits = 17;
static const int kappa = 2;
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 cache_bits = 128;
- static const int divisibility_check_by_5_threshold = 86;
- static const int case_fc_pm_half_lower_threshold = -2;
- static const int case_fc_pm_half_upper_threshold = 9;
- static const int case_fc_lower_threshold = -4;
- static const int case_fc_upper_threshold = 9;
- static const int case_shorter_interval_left_endpoint_lower_threshold = 2;
- static const int case_shorter_interval_left_endpoint_upper_threshold = 3;
static const int shorter_interval_tie_lower_threshold = -77;
static const int shorter_interval_tie_upper_threshold = -77;
- static const int max_trailing_zeros = 16;
+};
+
+// An 80- or 128-bit floating point number.
+template <typename T>
+struct float_info<T, enable_if_t<std::numeric_limits<T>::digits == 64 ||
+ std::numeric_limits<T>::digits == 113 ||
+ is_float128<T>::value>> {
+ using carrier_uint = detail::uint128_t;
+ static const int exponent_bits = 15;
+};
+
+// A double-double floating point number.
+template <typename T>
+struct float_info<T, enable_if_t<is_double_double<T>::value>> {
+ using carrier_uint = detail::uint128_t;
};
template <typename T> struct decimal_fp {
@@ -1260,16 +1333,35 @@
int exponent;
};
-template <typename T>
-FMT_API auto to_decimal(T x) FMT_NOEXCEPT -> decimal_fp<T>;
+template <typename T> FMT_API auto to_decimal(T x) noexcept -> decimal_fp<T>;
} // namespace dragonbox
-template <typename T>
+// Returns true iff Float has the implicit bit which is not stored.
+template <typename Float> constexpr bool has_implicit_bit() {
+ // An 80-bit FP number has a 64-bit significand an no implicit bit.
+ return std::numeric_limits<Float>::digits != 64;
+}
+
+// Returns the number of significand bits stored in Float. The implicit bit is
+// not counted since it is not stored.
+template <typename Float> constexpr int num_significand_bits() {
+ // std::numeric_limits may not support __float128.
+ return is_float128<Float>() ? 112
+ : (std::numeric_limits<Float>::digits -
+ (has_implicit_bit<Float>() ? 1 : 0));
+}
+
+template <typename Float>
constexpr auto exponent_mask() ->
- typename dragonbox::float_info<T>::carrier_uint {
- using uint = typename dragonbox::float_info<T>::carrier_uint;
- return ((uint(1) << dragonbox::float_info<T>::exponent_bits) - 1)
- << dragonbox::float_info<T>::significand_bits;
+ 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)
+ << num_significand_bits<Float>();
+}
+template <typename Float> constexpr auto exponent_bias() -> int {
+ // std::numeric_limits may not support __float128.
+ return is_float128<Float>() ? 16383
+ : std::numeric_limits<Float>::max_exponent - 1;
}
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
@@ -1294,21 +1386,251 @@
return it;
}
-template <typename T>
-FMT_HEADER_ONLY_CONSTEXPR20 auto format_float(T value, int precision,
- float_specs specs,
- buffer<char>& buf) -> int;
+// A floating-point number f * pow(2, e) where F is an unsigned type.
+template <typename F> struct basic_fp {
+ F f;
+ int e;
-// Formats a floating-point number with snprintf.
-template <typename T>
-auto snprintf_float(T value, int precision, float_specs specs,
- buffer<char>& buf) -> int;
+ static constexpr const int num_significand_bits =
+ static_cast<int>(sizeof(F) * num_bits<unsigned char>());
-template <typename T> constexpr auto promote_float(T value) -> T {
+ constexpr basic_fp() : f(0), e(0) {}
+ constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {}
+
+ // Constructs fp from an IEEE754 floating-point number.
+ template <typename Float> FMT_CONSTEXPR basic_fp(Float n) { assign(n); }
+
+ // Assigns n to this and return true iff predecessor is closer than successor.
+ template <typename Float, FMT_ENABLE_IF(!is_double_double<Float>::value)>
+ FMT_CONSTEXPR auto assign(Float n) -> bool {
+ static_assert(std::numeric_limits<Float>::digits <= 113, "unsupported FP");
+ // Assume Float is in the format [sign][exponent][significand].
+ using carrier_uint = typename dragonbox::float_info<Float>::carrier_uint;
+ const auto num_float_significand_bits =
+ detail::num_significand_bits<Float>();
+ const auto implicit_bit = carrier_uint(1) << num_float_significand_bits;
+ const auto significand_mask = implicit_bit - 1;
+ auto u = bit_cast<carrier_uint>(n);
+ f = static_cast<F>(u & significand_mask);
+ auto biased_e = static_cast<int>((u & exponent_mask<Float>()) >>
+ num_float_significand_bits);
+ // The predecessor is closer if n is a normalized power of 2 (f == 0)
+ // other than the smallest normalized number (biased_e > 1).
+ auto is_predecessor_closer = f == 0 && biased_e > 1;
+ if (biased_e == 0)
+ biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
+ else if (has_implicit_bit<Float>())
+ f += static_cast<F>(implicit_bit);
+ e = biased_e - exponent_bias<Float>() - num_float_significand_bits;
+ if (!has_implicit_bit<Float>()) ++e;
+ return is_predecessor_closer;
+ }
+
+ template <typename Float, FMT_ENABLE_IF(is_double_double<Float>::value)>
+ FMT_CONSTEXPR auto assign(Float n) -> bool {
+ static_assert(std::numeric_limits<double>::is_iec559, "unsupported FP");
+ return assign(static_cast<double>(n));
+ }
+};
+
+using fp = basic_fp<unsigned long long>;
+
+// Normalizes the value converted from double and multiplied by (1 << SHIFT).
+template <int SHIFT = 0, typename F>
+FMT_CONSTEXPR basic_fp<F> normalize(basic_fp<F> value) {
+ // Handle subnormals.
+ const auto implicit_bit = F(1) << num_significand_bits<double>();
+ const auto shifted_implicit_bit = implicit_bit << SHIFT;
+ while ((value.f & shifted_implicit_bit) == 0) {
+ value.f <<= 1;
+ --value.e;
+ }
+ // Subtract 1 to account for hidden bit.
+ const auto offset = basic_fp<F>::num_significand_bits -
+ num_significand_bits<double>() - SHIFT - 1;
+ value.f <<= offset;
+ value.e -= offset;
return value;
}
-constexpr auto promote_float(float value) -> double {
- return static_cast<double>(value);
+
+// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking.
+FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) {
+#if FMT_USE_INT128
+ auto product = static_cast<__uint128_t>(lhs) * rhs;
+ auto f = static_cast<uint64_t>(product >> 64);
+ return (static_cast<uint64_t>(product) & (1ULL << 63)) != 0 ? f + 1 : f;
+#else
+ // Multiply 32-bit parts of significands.
+ uint64_t mask = (1ULL << 32) - 1;
+ uint64_t a = lhs >> 32, b = lhs & mask;
+ uint64_t c = rhs >> 32, d = rhs & mask;
+ uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d;
+ // Compute mid 64-bit of result and round.
+ uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31);
+ return ac + (ad >> 32) + (bc >> 32) + (mid >> 32);
+#endif
+}
+
+FMT_CONSTEXPR inline fp operator*(fp x, fp y) {
+ return {multiply(x.f, y.f), x.e + y.e + 64};
+}
+
+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,
+ };
+
+#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.
+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, "");
+
+ // 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>
+using convert_float_result =
+ conditional_t<std::is_same<T, float>::value || sizeof(T) == sizeof(double),
+ double, T>;
+
+template <typename T>
+constexpr auto convert_float(T value) -> convert_float_result<T> {
+ return static_cast<convert_float_result<T>>(value);
}
template <typename OutputIt, typename Char>
@@ -1377,11 +1699,172 @@
: base_iterator(out, write(reserve(out, size)));
}
+// Returns true iff the code point cp is printable.
+FMT_API auto is_printable(uint32_t cp) -> bool;
+
+inline auto needs_escape(uint32_t cp) -> bool {
+ return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
+ !is_printable(cp);
+}
+
+template <typename Char> struct find_escape_result {
+ const Char* begin;
+ const Char* end;
+ uint32_t cp;
+};
+
+template <typename Char>
+using make_unsigned_char =
+ typename conditional_t<std::is_integral<Char>::value,
+ std::make_unsigned<Char>,
+ type_identity<uint32_t>>::type;
+
+template <typename Char>
+auto find_escape(const Char* begin, const Char* end)
+ -> find_escape_result<Char> {
+ for (; begin != end; ++begin) {
+ uint32_t cp = static_cast<make_unsigned_char<Char>>(*begin);
+ if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue;
+ if (needs_escape(cp)) return {begin, begin + 1, cp};
+ }
+ return {begin, nullptr, 0};
+}
+
+inline auto find_escape(const char* begin, const char* end)
+ -> find_escape_result<char> {
+ if (!is_utf8()) return find_escape<char>(begin, end);
+ auto result = find_escape_result<char>{end, nullptr, 0};
+ for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
+ [&](uint32_t cp, string_view sv) {
+ if (needs_escape(cp)) {
+ result = {sv.begin(), sv.end(), cp};
+ return false;
+ }
+ return true;
+ });
+ return result;
+}
+
+#define FMT_STRING_IMPL(s, base, explicit) \
+ [] { \
+ /* 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 { \
+ 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 { \
+ return fmt::detail_exported::compile_string_to_view<char_type>(s); \
+ } \
+ }; \
+ return FMT_COMPILE_STRING(); \
+ }()
+
+/**
+ \rst
+ Constructs a compile-time format string from a string literal *s*.
+
+ **Example**::
+
+ // A compile-time error because 'd' is an invalid specifier for strings.
+ std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
+ \endrst
+ */
+#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, )
+
+template <size_t width, typename Char, typename OutputIt>
+auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt {
+ *out++ = static_cast<Char>('\\');
+ *out++ = static_cast<Char>(prefix);
+ Char buf[width];
+ fill_n(buf, width, static_cast<Char>('0'));
+ format_uint<4>(buf, cp, width);
+ return copy_str<Char>(buf, buf + width, out);
+}
+
+template <typename OutputIt, typename Char>
+auto write_escaped_cp(OutputIt out, const find_escape_result<Char>& escape)
+ -> OutputIt {
+ auto c = static_cast<Char>(escape.cp);
+ switch (escape.cp) {
+ case '\n':
+ *out++ = static_cast<Char>('\\');
+ c = static_cast<Char>('n');
+ break;
+ case '\r':
+ *out++ = static_cast<Char>('\\');
+ c = static_cast<Char>('r');
+ break;
+ case '\t':
+ *out++ = static_cast<Char>('\\');
+ c = static_cast<Char>('t');
+ break;
+ case '"':
+ FMT_FALLTHROUGH;
+ case '\'':
+ FMT_FALLTHROUGH;
+ case '\\':
+ *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);
+ }
+ }
+ for (Char escape_char : basic_string_view<Char>(
+ escape.begin, to_unsigned(escape.end - escape.begin))) {
+ out = write_codepoint<2, Char>(out, 'x',
+ static_cast<uint32_t>(escape_char) & 0xFF);
+ }
+ return out;
+ }
+ *out++ = c;
+ return out;
+}
+
+template <typename Char, typename OutputIt>
+auto write_escaped_string(OutputIt out, basic_string_view<Char> str)
+ -> OutputIt {
+ *out++ = static_cast<Char>('"');
+ auto begin = str.begin(), end = str.end();
+ do {
+ auto escape = find_escape(begin, end);
+ out = copy_str<Char>(begin, escape.begin, out);
+ begin = escape.end;
+ if (!begin) break;
+ out = write_escaped_cp<OutputIt, Char>(out, escape);
+ } while (begin != end);
+ *out++ = static_cast<Char>('"');
+ return out;
+}
+
+template <typename Char, typename OutputIt>
+auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
+ *out++ = static_cast<Char>('\'');
+ if ((needs_escape(static_cast<uint32_t>(v)) && v != static_cast<Char>('"')) ||
+ v == static_cast<Char>('\'')) {
+ out = write_escaped_cp(
+ out, find_escape_result<Char>{&v, &v + 1, static_cast<uint32_t>(v)});
+ } else {
+ *out++ = v;
+ }
+ *out++ = static_cast<Char>('\'');
+ return out;
+}
+
template <typename Char, typename OutputIt>
FMT_CONSTEXPR auto write_char(OutputIt out, Char value,
const basic_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);
*it++ = value;
return it;
});
@@ -1519,7 +2002,10 @@
grouping.count_separators(num_digits));
return write_padded<align::right>(
out, specs, size, size, [&](reserve_iterator<OutputIt> it) {
- if (prefix != 0) *it++ = static_cast<Char>(prefix);
+ if (prefix != 0) {
+ char sign = static_cast<char>(prefix);
+ *it++ = static_cast<Char>(sign);
+ }
return grouping.apply(it, string_view(digits, to_unsigned(num_digits)));
});
}
@@ -1647,6 +2133,46 @@
return write_int(out, make_write_int_arg(value, specs.sign), specs, loc);
}
+// An output iterator that counts the number of objects written to it and
+// discards them.
+class counting_iterator {
+ private:
+ size_t count_;
+
+ public:
+ using iterator_category = std::output_iterator_tag;
+ using difference_type = std::ptrdiff_t;
+ using pointer = void;
+ using reference = void;
+ FMT_UNCHECKED_ITERATOR(counting_iterator);
+
+ struct value_type {
+ template <typename T> FMT_CONSTEXPR void operator=(const T&) {}
+ };
+
+ FMT_CONSTEXPR counting_iterator() : count_(0) {}
+
+ FMT_CONSTEXPR size_t count() const { return count_; }
+
+ FMT_CONSTEXPR counting_iterator& operator++() {
+ ++count_;
+ return *this;
+ }
+ FMT_CONSTEXPR counting_iterator operator++(int) {
+ auto it = *this;
+ ++*this;
+ return it;
+ }
+
+ FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it,
+ difference_type n) {
+ it.count_ += static_cast<size_t>(n);
+ return it;
+ }
+
+ FMT_CONSTEXPR value_type operator*() const { return {}; }
+};
+
template <typename Char, typename OutputIt>
FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s,
const basic_format_specs<Char>& specs) -> OutputIt {
@@ -1654,10 +2180,17 @@
auto size = s.size();
if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
size = code_point_index(s, to_unsigned(specs.precision));
- auto width =
- specs.width != 0 ? compute_width(basic_string_view<Char>(data, size)) : 0;
+ bool is_debug = specs.type == presentation_type::debug;
+ size_t width = 0;
+ if (specs.width != 0) {
+ if (is_debug)
+ width = write_escaped_string(counting_iterator{}, s).count();
+ else
+ width = compute_width(basic_string_view<Char>(data, size));
+ }
return write_padded(out, specs, size, width,
[=](reserve_iterator<OutputIt> it) {
+ if (is_debug) return write_escaped_string(it, s);
return copy_str<Char>(data, data + size, it);
});
}
@@ -1675,15 +2208,37 @@
-> OutputIt {
return check_cstring_type_spec(specs.type)
? write(out, basic_string_view<Char>(s), specs, {})
- : write_ptr<Char>(out, to_uintptr(s), &specs);
+ : write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
+}
+
+template <typename Char, typename OutputIt, typename T,
+ FMT_ENABLE_IF(is_integral<T>::value &&
+ !std::is_same<T, bool>::value &&
+ !std::is_same<T, Char>::value)>
+FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
+ auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
+ bool negative = is_negative(value);
+ // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
+ if (negative) abs_value = ~abs_value + 1;
+ int num_digits = count_digits(abs_value);
+ auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
+ auto it = reserve(out, size);
+ if (auto ptr = to_pointer<Char>(it, size)) {
+ if (negative) *ptr++ = static_cast<Char>('-');
+ format_decimal<Char>(ptr, abs_value, num_digits);
+ return out;
+ }
+ if (negative) *it++ = static_cast<Char>('-');
+ it = format_decimal<Char>(it, abs_value, num_digits).end;
+ return base_iterator(out, it);
}
template <typename Char, typename OutputIt>
-FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isinf,
+FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
basic_format_specs<Char> specs,
const float_specs& fspecs) -> OutputIt {
auto str =
- isinf ? (fspecs.upper ? "INF" : "inf") : (fspecs.upper ? "NAN" : "nan");
+ isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf");
constexpr size_t str_size = 3;
auto sign = fspecs.sign;
auto size = str_size + (sign ? 1 : 0);
@@ -1704,12 +2259,12 @@
int exponent;
};
-constexpr auto get_significand_size(const big_decimal_fp& fp) -> int {
- return fp.significand_size;
+constexpr auto get_significand_size(const big_decimal_fp& f) -> int {
+ return f.significand_size;
}
template <typename T>
-inline auto get_significand_size(const dragonbox::decimal_fp<T>& fp) -> int {
- return count_digits(fp.significand);
+inline auto get_significand_size(const dragonbox::decimal_fp<T>& f) -> int {
+ return count_digits(f.significand);
}
template <typename Char, typename OutputIt>
@@ -1747,7 +2302,7 @@
int floating_size = significand_size - integral_size;
for (int i = floating_size / 2; i > 0; --i) {
out -= 2;
- copy2(out, digits2(significand % 100));
+ copy2(out, digits2(static_cast<std::size_t>(significand % 100)));
significand /= 100;
}
if (floating_size % 2 != 0) {
@@ -1803,13 +2358,13 @@
template <typename OutputIt, typename DecimalFP, typename Char,
typename Grouping = digit_grouping<Char>>
-FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& fp,
+FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
const basic_format_specs<Char>& specs,
float_specs fspecs, locale_ref loc)
-> OutputIt {
- auto significand = fp.significand;
- int significand_size = get_significand_size(fp);
- constexpr Char zero = static_cast<Char>('0');
+ auto significand = f.significand;
+ int significand_size = get_significand_size(f);
+ const Char zero = static_cast<Char>('0');
auto sign = fspecs.sign;
size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
using iterator = reserve_iterator<OutputIt>;
@@ -1817,7 +2372,7 @@
Char decimal_point =
fspecs.locale ? detail::decimal_point<Char>(loc) : static_cast<Char>('.');
- int output_exp = fp.exponent + significand_size - 1;
+ int output_exp = f.exponent + significand_size - 1;
auto use_exp_format = [=]() {
if (fspecs.format == float_format::exp) return true;
if (fspecs.format != float_format::general) return false;
@@ -1855,25 +2410,23 @@
: base_iterator(out, write(reserve(out, size)));
}
- int exp = fp.exponent + significand_size;
- if (fp.exponent >= 0) {
+ int exp = f.exponent + significand_size;
+ if (f.exponent >= 0) {
// 1234e5 -> 123400000[.0+]
- size += to_unsigned(fp.exponent);
+ size += to_unsigned(f.exponent);
int num_zeros = fspecs.precision - exp;
-#ifdef FMT_FUZZ
- if (num_zeros > 5000)
- throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
-#endif
+ 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) size += to_unsigned(num_zeros) + 1;
+ if (num_zeros > 0) size += to_unsigned(num_zeros);
}
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<Char>(it, significand, significand_size,
- fp.exponent, grouping);
+ f.exponent, grouping);
if (!fspecs.showpoint) return it;
*it++ = decimal_point;
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
@@ -1924,63 +2477,713 @@
};
template <typename OutputIt, typename DecimalFP, typename Char>
-FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& fp,
+FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f,
const basic_format_specs<Char>& specs,
float_specs fspecs, locale_ref loc)
-> OutputIt {
if (is_constant_evaluated()) {
return do_write_float<OutputIt, DecimalFP, Char,
- fallback_digit_grouping<Char>>(out, fp, specs, fspecs,
+ fallback_digit_grouping<Char>>(out, f, specs, fspecs,
loc);
} else {
- return do_write_float(out, fp, specs, fspecs, loc);
+ return do_write_float(out, f, specs, fspecs, loc);
}
}
-template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
-FMT_CONSTEXPR20 bool isinf(T value) {
- if (is_constant_evaluated()) {
-#if defined(__cpp_if_constexpr)
- if constexpr (std::numeric_limits<double>::is_iec559) {
- auto bits = detail::bit_cast<uint64_t>(static_cast<double>(value));
- constexpr auto significand_bits =
- dragonbox::float_info<double>::significand_bits;
- return (bits & exponent_mask<double>()) &&
- !(bits & ((uint64_t(1) << significand_bits) - 1));
- }
-#endif
- }
- return std::isinf(value);
+template <typename T> constexpr bool isnan(T value) {
+ return !(value >= value); // std::isnan doesn't support __float128.
}
-template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+template <typename T, typename Enable = void>
+struct has_isfinite : std::false_type {};
+
+template <typename T>
+struct has_isfinite<T, enable_if_t<sizeof(std::isfinite(T())) != 0>>
+ : std::true_type {};
+
+template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value&&
+ has_isfinite<T>::value)>
FMT_CONSTEXPR20 bool isfinite(T value) {
- if (is_constant_evaluated()) {
-#if defined(__cpp_if_constexpr)
- if constexpr (std::numeric_limits<double>::is_iec559) {
- auto bits = detail::bit_cast<uint64_t>(static_cast<double>(value));
- return (bits & exponent_mask<double>()) != exponent_mask<double>();
- }
-#endif
- }
+ constexpr T inf = T(std::numeric_limits<double>::infinity());
+ if (is_constant_evaluated())
+ 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;
+}
-template <typename T, FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+template <typename T, FMT_ENABLE_IF(is_floating_point<T>::value)>
FMT_INLINE FMT_CONSTEXPR bool signbit(T value) {
if (is_constant_evaluated()) {
#ifdef __cpp_if_constexpr
if constexpr (std::numeric_limits<double>::is_iec559) {
auto bits = detail::bit_cast<uint64_t>(static_cast<double>(value));
- return (bits & (uint64_t(1) << (num_bits<uint64_t>() - 1))) != 0;
+ return (bits >> (num_bits<uint64_t>() - 1)) != 0;
}
#endif
}
- return std::signbit(value);
+ 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.
+ if (exp10 > 0 && precision > max_value<int>() - exp10)
+ FMT_THROW(format_error("number is too big"));
+ 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
+ // 0 being the least significant one.
+ using bigit = uint32_t;
+ using double_bigit = uint64_t;
+ enum { bigits_capacity = 32 };
+ basic_memory_buffer<bigit, bigits_capacity> bigits_;
+ int exp_;
+
+ FMT_CONSTEXPR20 bigit operator[](int index) const {
+ return bigits_[to_unsigned(index)];
+ }
+ FMT_CONSTEXPR20 bigit& operator[](int index) {
+ return bigits_[to_unsigned(index)];
+ }
+
+ static constexpr const int bigit_bits = num_bits<bigit>();
+
+ friend struct formatter<bigint>;
+
+ FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) {
+ auto result = static_cast<double_bigit>((*this)[index]) - other - borrow;
+ (*this)[index] = static_cast<bigit>(result);
+ borrow = static_cast<bigit>(result >> (bigit_bits * 2 - 1));
+ }
+
+ FMT_CONSTEXPR20 void remove_leading_zeros() {
+ int num_bigits = static_cast<int>(bigits_.size()) - 1;
+ while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits;
+ bigits_.resize(to_unsigned(num_bigits + 1));
+ }
+
+ // Computes *this -= other assuming aligned bigints and *this >= other.
+ FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) {
+ FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints");
+ FMT_ASSERT(compare(*this, other) >= 0, "");
+ bigit borrow = 0;
+ int i = other.exp_ - exp_;
+ for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j)
+ subtract_bigits(i, other.bigits_[j], borrow);
+ while (borrow > 0) subtract_bigits(i, 0, borrow);
+ remove_leading_zeros();
+ }
+
+ FMT_CONSTEXPR20 void multiply(uint32_t value) {
+ const double_bigit wide_value = value;
+ bigit carry = 0;
+ for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
+ double_bigit result = bigits_[i] * wide_value + carry;
+ bigits_[i] = static_cast<bigit>(result);
+ carry = static_cast<bigit>(result >> bigit_bits);
+ }
+ if (carry != 0) bigits_.push_back(carry);
+ }
+
+ template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
+ std::is_same<UInt, uint128_t>::value)>
+ FMT_CONSTEXPR20 void multiply(UInt value) {
+ using half_uint =
+ conditional_t<std::is_same<UInt, uint128_t>::value, uint64_t, uint32_t>;
+ const int shift = num_bits<half_uint>() - bigit_bits;
+ const UInt lower = static_cast<half_uint>(value);
+ const UInt upper = value >> num_bits<half_uint>();
+ UInt carry = 0;
+ for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
+ UInt result = lower * bigits_[i] + static_cast<bigit>(carry);
+ carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) +
+ (carry >> bigit_bits);
+ bigits_[i] = static_cast<bigit>(result);
+ }
+ while (carry != 0) {
+ bigits_.push_back(static_cast<bigit>(carry));
+ carry >>= bigit_bits;
+ }
+ }
+
+ template <typename UInt, FMT_ENABLE_IF(std::is_same<UInt, uint64_t>::value ||
+ std::is_same<UInt, uint128_t>::value)>
+ FMT_CONSTEXPR20 void assign(UInt n) {
+ size_t num_bigits = 0;
+ do {
+ bigits_[num_bigits++] = static_cast<bigit>(n);
+ n >>= bigit_bits;
+ } while (n != 0);
+ bigits_.resize(num_bigits);
+ exp_ = 0;
+ }
+
+ public:
+ FMT_CONSTEXPR20 bigint() : exp_(0) {}
+ explicit bigint(uint64_t n) { assign(n); }
+
+ bigint(const bigint&) = delete;
+ void operator=(const bigint&) = delete;
+
+ FMT_CONSTEXPR20 void assign(const bigint& other) {
+ auto size = other.bigits_.size();
+ bigits_.resize(size);
+ auto data = other.bigits_.data();
+ std::copy(data, data + size, make_checked(bigits_.data(), size));
+ exp_ = other.exp_;
+ }
+
+ template <typename Int> FMT_CONSTEXPR20 void operator=(Int n) {
+ FMT_ASSERT(n > 0, "");
+ assign(uint64_or_128_t<Int>(n));
+ }
+
+ FMT_CONSTEXPR20 int num_bigits() const {
+ return static_cast<int>(bigits_.size()) + exp_;
+ }
+
+ FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) {
+ FMT_ASSERT(shift >= 0, "");
+ exp_ += shift / bigit_bits;
+ shift %= bigit_bits;
+ if (shift == 0) return *this;
+ bigit carry = 0;
+ for (size_t i = 0, n = bigits_.size(); i < n; ++i) {
+ bigit c = bigits_[i] >> (bigit_bits - shift);
+ bigits_[i] = (bigits_[i] << shift) + carry;
+ carry = c;
+ }
+ if (carry != 0) bigits_.push_back(carry);
+ return *this;
+ }
+
+ template <typename Int> FMT_CONSTEXPR20 bigint& operator*=(Int value) {
+ FMT_ASSERT(value > 0, "");
+ multiply(uint32_or_64_or_128_t<Int>(value));
+ return *this;
+ }
+
+ friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) {
+ int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits();
+ if (num_lhs_bigits != num_rhs_bigits)
+ return num_lhs_bigits > num_rhs_bigits ? 1 : -1;
+ int i = static_cast<int>(lhs.bigits_.size()) - 1;
+ int j = static_cast<int>(rhs.bigits_.size()) - 1;
+ int end = i - j;
+ if (end < 0) end = 0;
+ for (; i >= end; --i, --j) {
+ bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j];
+ if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1;
+ }
+ if (i != j) return i > j ? 1 : -1;
+ return 0;
+ }
+
+ // Returns compare(lhs1 + lhs2, rhs).
+ friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2,
+ const bigint& rhs) {
+ auto minimum = [](int a, int b) { return a < b ? a : b; };
+ auto maximum = [](int a, int b) { return a > b ? a : b; };
+ int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits());
+ int num_rhs_bigits = rhs.num_bigits();
+ if (max_lhs_bigits + 1 < num_rhs_bigits) return -1;
+ if (max_lhs_bigits > num_rhs_bigits) return 1;
+ auto get_bigit = [](const bigint& n, int i) -> bigit {
+ return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0;
+ };
+ double_bigit borrow = 0;
+ int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_);
+ for (int i = num_rhs_bigits - 1; i >= min_exp; --i) {
+ double_bigit sum =
+ static_cast<double_bigit>(get_bigit(lhs1, i)) + get_bigit(lhs2, i);
+ bigit rhs_bigit = get_bigit(rhs, i);
+ if (sum > rhs_bigit + borrow) return 1;
+ borrow = rhs_bigit + borrow - sum;
+ if (borrow > 1) return -1;
+ borrow <<= bigit_bits;
+ }
+ return borrow != 0 ? -1 : 0;
+ }
+
+ // Assigns pow(10, exp) to this bigint.
+ FMT_CONSTEXPR20 void assign_pow10(int exp) {
+ FMT_ASSERT(exp >= 0, "");
+ if (exp == 0) return *this = 1;
+ // Find the top bit.
+ int bitmask = 1;
+ while (exp >= bitmask) bitmask <<= 1;
+ bitmask >>= 1;
+ // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by
+ // repeated squaring and multiplication.
+ *this = 5;
+ bitmask >>= 1;
+ while (bitmask != 0) {
+ square();
+ if ((exp & bitmask) != 0) *this *= 5;
+ bitmask >>= 1;
+ }
+ *this <<= exp; // Multiply by pow(2, exp) by shifting.
+ }
+
+ FMT_CONSTEXPR20 void square() {
+ int num_bigits = static_cast<int>(bigits_.size());
+ int num_result_bigits = 2 * num_bigits;
+ basic_memory_buffer<bigit, bigits_capacity> n(std::move(bigits_));
+ bigits_.resize(to_unsigned(num_result_bigits));
+ auto sum = uint128_t();
+ for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) {
+ // Compute bigit at position bigit_index of the result by adding
+ // cross-product terms n[i] * n[j] such that i + j == bigit_index.
+ for (int i = 0, j = bigit_index; j >= 0; ++i, --j) {
+ // Most terms are multiplied twice which can be optimized in the future.
+ sum += static_cast<double_bigit>(n[i]) * n[j];
+ }
+ (*this)[bigit_index] = static_cast<bigit>(sum);
+ sum >>= num_bits<bigit>(); // Compute the carry.
+ }
+ // Do the same for the top half.
+ for (int bigit_index = num_bigits; bigit_index < num_result_bigits;
+ ++bigit_index) {
+ for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;)
+ sum += static_cast<double_bigit>(n[i++]) * n[j--];
+ (*this)[bigit_index] = static_cast<bigit>(sum);
+ sum >>= num_bits<bigit>();
+ }
+ remove_leading_zeros();
+ exp_ *= 2;
+ }
+
+ // If this bigint has a bigger exponent than other, adds trailing zero to make
+ // exponents equal. This simplifies some operations such as subtraction.
+ FMT_CONSTEXPR20 void align(const bigint& other) {
+ int exp_difference = exp_ - other.exp_;
+ if (exp_difference <= 0) return;
+ int num_bigits = static_cast<int>(bigits_.size());
+ bigits_.resize(to_unsigned(num_bigits + exp_difference));
+ for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j)
+ bigits_[j] = bigits_[i];
+ std::uninitialized_fill_n(bigits_.data(), exp_difference, 0);
+ exp_ -= exp_difference;
+ }
+
+ // Divides this bignum by divisor, assigning the remainder to this and
+ // returning the quotient.
+ FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) {
+ FMT_ASSERT(this != &divisor, "");
+ if (compare(*this, divisor) < 0) return 0;
+ FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, "");
+ align(divisor);
+ int quotient = 0;
+ do {
+ subtract_aligned(divisor);
+ ++quotient;
+ } while (compare(*this, divisor) >= 0);
+ return quotient;
+ }
+};
+
+// format_dragon flags.
+enum dragon {
+ predecessor_closer = 1,
+ fixup = 2, // Run fixup to correct exp10 which can be off by one.
+ fixed = 4,
+};
+
+// Formats a floating-point number using a variation of the Fixed-Precision
+// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White:
+// https://fmt.dev/papers/p372-steele.pdf.
+FMT_CONSTEXPR20 inline void format_dragon(basic_fp<uint128_t> value,
+ unsigned flags, int num_digits,
+ buffer<char>& buf, int& exp10) {
+ bigint numerator; // 2 * R in (FPP)^2.
+ bigint denominator; // 2 * S in (FPP)^2.
+ // lower and upper are differences between value and corresponding boundaries.
+ bigint lower; // (M^- in (FPP)^2).
+ bigint upper_store; // upper's value if different from lower.
+ bigint* upper = nullptr; // (M^+ in (FPP)^2).
+ // Shift numerator and denominator by an extra bit or two (if lower boundary
+ // is closer) to make lower and upper integers. This eliminates multiplication
+ // by 2 during later computations.
+ bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0;
+ int shift = is_predecessor_closer ? 2 : 1;
+ if (value.e >= 0) {
+ numerator = value.f;
+ numerator <<= value.e + shift;
+ lower = 1;
+ lower <<= value.e;
+ if (is_predecessor_closer) {
+ upper_store = 1;
+ upper_store <<= value.e + 1;
+ upper = &upper_store;
+ }
+ denominator.assign_pow10(exp10);
+ denominator <<= shift;
+ } else if (exp10 < 0) {
+ numerator.assign_pow10(-exp10);
+ lower.assign(numerator);
+ if (is_predecessor_closer) {
+ upper_store.assign(numerator);
+ upper_store <<= 1;
+ upper = &upper_store;
+ }
+ numerator *= value.f;
+ numerator <<= shift;
+ denominator = 1;
+ denominator <<= shift - value.e;
+ } else {
+ numerator = value.f;
+ numerator <<= shift;
+ denominator.assign_pow10(exp10);
+ denominator <<= shift - value.e;
+ lower = 1;
+ if (is_predecessor_closer) {
+ upper_store = 1ULL << 1;
+ upper = &upper_store;
+ }
+ }
+ int even = static_cast<int>((value.f & 1) == 0);
+ if (!upper) upper = &lower;
+ if ((flags & dragon::fixup) != 0) {
+ if (add_compare(numerator, *upper, denominator) + even <= 0) {
+ --exp10;
+ numerator *= 10;
+ if (num_digits < 0) {
+ lower *= 10;
+ if (upper != &lower) *upper *= 10;
+ }
+ }
+ if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1);
+ }
+ // Invariant: value == (numerator / denominator) * pow(10, exp10).
+ if (num_digits < 0) {
+ // Generate the shortest representation.
+ num_digits = 0;
+ char* data = buf.data();
+ for (;;) {
+ int digit = numerator.divmod_assign(denominator);
+ bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower.
+ // numerator + upper >[=] pow10:
+ bool high = add_compare(numerator, *upper, denominator) + even > 0;
+ data[num_digits++] = static_cast<char>('0' + digit);
+ if (low || high) {
+ if (!low) {
+ ++data[num_digits - 1];
+ } else if (high) {
+ int result = add_compare(numerator, numerator, denominator);
+ // Round half to even.
+ if (result > 0 || (result == 0 && (digit % 2) != 0))
+ ++data[num_digits - 1];
+ }
+ buf.try_resize(to_unsigned(num_digits));
+ exp10 -= num_digits - 1;
+ return;
+ }
+ numerator *= 10;
+ lower *= 10;
+ if (upper != &lower) *upper *= 10;
+ }
+ }
+ // Generate the given number of digits.
+ exp10 -= num_digits - 1;
+ if (num_digits == 0) {
+ denominator *= 10;
+ auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0';
+ buf.push_back(digit);
+ return;
+ }
+ buf.try_resize(to_unsigned(num_digits));
+ for (int i = 0; i < num_digits - 1; ++i) {
+ int digit = numerator.divmod_assign(denominator);
+ buf[i] = static_cast<char>('0' + digit);
+ numerator *= 10;
+ }
+ int digit = numerator.divmod_assign(denominator);
+ auto result = add_compare(numerator, numerator, denominator);
+ if (result > 0 || (result == 0 && (digit % 2) != 0)) {
+ if (digit == 9) {
+ const auto overflow = '0' + 10;
+ buf[num_digits - 1] = overflow;
+ // Propagate the carry.
+ for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) {
+ buf[i] = '0';
+ ++buf[i - 1];
+ }
+ if (buf[0] == overflow) {
+ buf[0] = '1';
+ ++exp10;
+ }
+ return;
+ }
+ ++digit;
+ }
+ buf[num_digits - 1] = static_cast<char>('0' + digit);
+}
+
+template <typename Float>
+FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
+ buffer<char>& buf) -> int {
+ // float is passed as double to reduce the number of instantiations.
+ static_assert(!std::is_same<Float, float>::value, "");
+ FMT_ASSERT(value >= 0, "value is negative");
+ auto converted_value = convert_float(value);
+
+ const bool fixed = specs.format == float_format::fixed;
+ if (value <= 0) { // <= instead of == to silence a warning.
+ if (precision <= 0 || !fixed) {
+ buf.push_back('0');
+ return 0;
+ }
+ buf.try_resize(to_unsigned(precision));
+ fill_n(buf.data(), precision, '0');
+ return -precision;
+ }
+
+ int exp = 0;
+ bool use_dragon = true;
+ unsigned dragon_flags = 0;
+ if (!is_fast_float<Float>()) {
+ 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);
+ // Compute exp, an approximate power of 10, such that
+ // 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));
+ dragon_flags = dragon::fixup;
+ } else if (!is_constant_evaluated() && precision < 0) {
+ // Use Dragonbox for the shortest format.
+ if (specs.binary32) {
+ auto dec = dragonbox::to_decimal(static_cast<float>(value));
+ write<char>(buffer_appender<char>(buf), dec.significand);
+ return dec.exponent;
+ }
+ auto dec = dragonbox::to_decimal(static_cast<double>(value));
+ 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;
+ } else {
+ exp += handler.size - cached_exp10 - 1;
+ precision = handler.precision;
+ }
+ }
+ if (use_dragon) {
+ auto f = basic_fp<uint128_t>();
+ bool is_predecessor_closer = specs.binary32
+ ? f.assign(static_cast<float>(value))
+ : f.assign(converted_value);
+ if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer;
+ if (fixed) dragon_flags |= dragon::fixed;
+ // Limit precision to the maximum possible number of significant digits in
+ // an IEEE754 double because we don't need to generate zeros.
+ const int max_double_digits = 767;
+ if (precision > max_double_digits) precision = max_double_digits;
+ format_dragon(f, dragon_flags, precision, buf, exp);
+ }
+ if (!fixed && !specs.showpoint) {
+ // Remove trailing zeros.
+ auto num_digits = buf.size();
+ while (num_digits > 0 && buf[num_digits - 1] == '0') {
+ --num_digits;
+ ++exp;
+ }
+ buf.try_resize(num_digits);
+ }
+ return exp;
}
template <typename Char, typename OutputIt, typename T,
- FMT_ENABLE_IF(std::is_floating_point<T>::value)>
+ FMT_ENABLE_IF(is_floating_point<T>::value)>
FMT_CONSTEXPR20 auto write(OutputIt out, T value,
basic_format_specs<Char> specs, locale_ref loc = {})
-> OutputIt {
@@ -1995,7 +3198,7 @@
}
if (!detail::isfinite(value))
- return write_nonfinite(out, detail::isinf(value), specs, fspecs);
+ return write_nonfinite(out, detail::isnan(value), specs, fspecs);
if (specs.align == align::numeric && fspecs.sign) {
auto it = reserve(out, 1);
@@ -2008,7 +3211,7 @@
memory_buffer buffer;
if (fspecs.format == float_format::hex) {
if (fspecs.sign) buffer.push_back(detail::sign<char>(fspecs.sign));
- snprintf_float(promote_float(value), specs.precision, fspecs, buffer);
+ snprintf_float(convert_float(value), specs.precision, fspecs, buffer);
return write_bytes<align::right>(out, {buffer.data(), buffer.size()},
specs);
}
@@ -2020,28 +3223,23 @@
throw_format_error("number is too big");
else
++precision;
+ } else if (fspecs.format != float_format::fixed && precision == 0) {
+ precision = 1;
}
if (const_check(std::is_same<T, float>())) fspecs.binary32 = true;
- if (!is_fast_float<T>()) fspecs.fallback = true;
- int exp = format_float(promote_float(value), precision, fspecs, buffer);
+ int exp = format_float(convert_float(value), precision, fspecs, buffer);
fspecs.precision = precision;
- auto fp = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
- return write_float(out, fp, specs, fspecs, loc);
+ auto f = big_decimal_fp{buffer.data(), static_cast<int>(buffer.size()), exp};
+ return write_float(out, f, specs, fspecs, 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()) {
+ if (is_constant_evaluated())
return write(out, value, basic_format_specs<Char>());
- }
-
if (const_check(!is_supported_floating_point(value))) return out;
- using floaty = conditional_t<std::is_same<T, long double>::value, double, T>;
- using uint = typename dragonbox::float_info<floaty>::carrier_uint;
- auto bits = bit_cast<uint>(value);
-
auto fspecs = float_specs();
if (detail::signbit(value)) {
fspecs.sign = sign::minus;
@@ -2049,16 +3247,18 @@
}
constexpr auto specs = basic_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 ((bits & mask) == mask)
- return write_nonfinite(out, std::isinf(value), specs, fspecs);
+ if ((bit_cast<uint>(value) & mask) == mask)
+ return write_nonfinite(out, std::isnan(value), specs, fspecs);
auto dec = dragonbox::to_decimal(static_cast<floaty>(value));
return write_float(out, dec, specs, fspecs, {});
}
template <typename Char, typename OutputIt, typename T,
- FMT_ENABLE_IF(std::is_floating_point<T>::value &&
+ 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>());
@@ -2085,28 +3285,6 @@
return write<Char>(out, to_string_view(value));
}
-template <typename Char, typename OutputIt, typename T,
- FMT_ENABLE_IF(is_integral<T>::value &&
- !std::is_same<T, bool>::value &&
- !std::is_same<T, Char>::value)>
-FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
- auto abs_value = static_cast<uint32_or_64_or_128_t<T>>(value);
- bool negative = is_negative(value);
- // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer.
- if (negative) abs_value = ~abs_value + 1;
- int num_digits = count_digits(abs_value);
- auto size = (negative ? 1 : 0) + static_cast<size_t>(num_digits);
- auto it = reserve(out, size);
- if (auto ptr = to_pointer<Char>(it, size)) {
- if (negative) *ptr++ = static_cast<Char>('-');
- format_decimal<Char>(ptr, abs_value, num_digits);
- return out;
- }
- if (negative) *it++ = static_cast<Char>('-');
- it = format_decimal<Char>(it, abs_value, num_digits).end;
- return base_iterator(out, it);
-}
-
// FMT_ENABLE_IF() condition separated to workaround an MSVC bug.
template <
typename Char, typename OutputIt, typename T,
@@ -2116,8 +3294,7 @@
type::custom_type,
FMT_ENABLE_IF(check)>
FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt {
- return write<Char>(
- out, static_cast<typename std::underlying_type<T>::type>(value));
+ return write<Char>(out, static_cast<underlying_t<T>>(value));
}
template <typename Char, typename OutputIt, typename T,
@@ -2155,7 +3332,7 @@
const basic_format_specs<Char>& specs = {}, locale_ref = {})
-> OutputIt {
check_pointer_type_spec(specs.type, error_handler());
- return write_ptr<Char>(out, to_uintptr(value), &specs);
+ return write_ptr<Char>(out, bit_cast<uintptr_t>(value), &specs);
}
// A write overload that handles implicit conversions.
@@ -2163,7 +3340,7 @@
typename Context = basic_format_context<OutputIt, Char>>
FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t<
std::is_class<T>::value && !is_string<T>::value &&
- !std::is_same<T, Char>::value &&
+ !is_floating_point<T>::value && !std::is_same<T, Char>::value &&
!std::is_same<const T&,
decltype(arg_mapper<Context>().map(value))>::value,
OutputIt> {
@@ -2356,43 +3533,17 @@
}
}
-#define FMT_STRING_IMPL(s, base, explicit) \
- [] { \
- /* 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 { \
- using char_type = fmt::remove_cvref_t<decltype(s[0])>; \
- FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \
- operator fmt::basic_string_view<char_type>() const { \
- return fmt::detail_exported::compile_string_to_view<char_type>(s); \
- } \
- }; \
- return FMT_COMPILE_STRING(); \
- }()
-
-/**
- \rst
- Constructs a compile-time format string from a string literal *s*.
-
- **Example**::
-
- // A compile-time error because 'd' is an invalid specifier for strings.
- std::string s = fmt::format(FMT_STRING("{:d}"), "foo");
- \endrst
- */
-#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string, )
-
#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_args_checked<T...>(str, args...));
+ return vformat(str, fmt::make_format_args<buffer_context<Char>>(args...));
}
};
-# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+# if FMT_USE_NONTYPE_TEMPLATE_ARGS
template <typename T, typename Char, size_t N,
fmt::detail_exported::fixed_string<Char, N> Str>
struct statically_named_arg : view {
@@ -2441,10 +3592,10 @@
using format_func = void (*)(detail::buffer<char>&, int, const char*);
FMT_API void format_error_code(buffer<char>& out, int error_code,
- string_view message) FMT_NOEXCEPT;
+ string_view message) noexcept;
FMT_API void report_error(format_func func, int error_code,
- const char* message) FMT_NOEXCEPT;
+ const char* message) noexcept;
FMT_END_DETAIL_NAMESPACE
FMT_API auto vsystem_error(int error_code, string_view format_str,
@@ -2490,12 +3641,11 @@
\endrst
*/
FMT_API void format_system_error(detail::buffer<char>& out, int error_code,
- const char* message) FMT_NOEXCEPT;
+ const char* message) noexcept;
// Reports a system error without throwing an exception.
// Can be used to report errors from destructors.
-FMT_API void report_system_error(int error_code,
- const char* message) FMT_NOEXCEPT;
+FMT_API void report_system_error(int error_code, const char* message) noexcept;
/** Fast integer formatter. */
class format_int {
@@ -2577,28 +3727,6 @@
return detail::write<Char>(ctx.out(), val, specs_, ctx.locale());
}
-#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::byte, unsigned char);
-FMT_FORMAT_AS(detail::std_string_view<Char>, basic_string_view<Char>);
-
template <typename Char>
struct formatter<void*, Char> : formatter<const void*, Char> {
template <typename FormatContext>
@@ -2688,6 +3816,28 @@
return p.get();
}
+/**
+ \rst
+ Converts ``e`` to the underlying type.
+
+ **Example**::
+
+ enum class color { red, green, blue };
+ auto s = fmt::format("{}", fmt::underlying(color::red));
+ \endrst
+ */
+template <typename Enum>
+constexpr auto underlying(Enum e) noexcept -> underlying_t<Enum> {
+ return static_cast<underlying_t<Enum>>(e);
+}
+
+namespace enums {
+template <typename Enum, FMT_ENABLE_IF(std::is_enum<Enum>::value)>
+constexpr auto format_as(Enum e) noexcept -> underlying_t<Enum> {
+ return static_cast<underlying_t<Enum>>(e);
+}
+} // namespace enums
+
class bytes {
private:
string_view data_;
@@ -2779,9 +3929,6 @@
};
template <typename It, typename Sentinel, typename Char>
-using arg_join FMT_DEPRECATED_ALIAS = join_view<It, Sentinel, Char>;
-
-template <typename It, typename Sentinel, typename Char>
struct formatter<join_view<It, Sentinel, Char>, Char> {
private:
using value_type =
@@ -2818,8 +3965,8 @@
}
template <typename FormatContext>
- auto format(const join_view<It, Sentinel, Char>& value, FormatContext& ctx)
- -> decltype(ctx.out()) {
+ auto format(const join_view<It, Sentinel, Char>& value,
+ FormatContext& ctx) const -> decltype(ctx.out()) {
auto it = value.begin;
auto out = ctx.out();
if (it != value.end) {
@@ -2936,9 +4083,10 @@
basic_format_parse_context<Char> parse_context;
buffer_context<Char> context;
- format_handler(buffer_appender<Char> out, basic_string_view<Char> str,
- basic_format_args<buffer_context<Char>> args, locale_ref loc)
- : parse_context(str), context(out, args, loc) {}
+ format_handler(buffer_appender<Char> p_out, basic_string_view<Char> str,
+ basic_format_args<buffer_context<Char>> p_args,
+ locale_ref p_loc)
+ : parse_context(str), context(p_out, p_args, p_loc) {}
void on_text(const Char* begin, const Char* end) {
auto text = basic_string_view<Char>(begin, to_unsigned(end - begin));
@@ -2995,20 +4143,6 @@
-> thousands_sep_result<wchar_t>;
extern template FMT_API auto decimal_point_impl(locale_ref) -> char;
extern template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
-extern template auto format_float<double>(double value, int precision,
- float_specs specs, buffer<char>& buf)
- -> int;
-extern template auto format_float<long double>(long double value, int precision,
- float_specs specs,
- buffer<char>& buf) -> int;
-void snprintf_float(float, int, float_specs, buffer<char>&) = delete;
-extern template auto snprintf_float<double>(double value, int precision,
- float_specs specs,
- buffer<char>& buf) -> int;
-extern template auto snprintf_float<long double>(long double value,
- int precision,
- float_specs specs,
- buffer<char>& buf) -> int;
#endif // FMT_HEADER_ONLY
FMT_END_DETAIL_NAMESPACE
@@ -3025,25 +4159,16 @@
fmt::print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
\endrst
*/
-# if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
-template <detail_exported::fixed_string Str>
-constexpr auto operator""_a()
- -> detail::udl_arg<remove_cvref_t<decltype(Str.data[0])>,
- sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str> {
- return {};
+# if FMT_USE_NONTYPE_TEMPLATE_ARGS
+template <detail_exported::fixed_string Str> constexpr auto operator""_a() {
+ using char_t = remove_cvref_t<decltype(Str.data[0])>;
+ return detail::udl_arg<char_t, sizeof(Str.data) / sizeof(char_t), Str>();
}
# else
constexpr auto operator"" _a(const char* s, size_t) -> detail::udl_arg<char> {
return {s};
}
# endif
-
-// DEPRECATED!
-// User-defined literal equivalent of fmt::format.
-FMT_DEPRECATED constexpr auto operator"" _format(const char* s, size_t n)
- -> detail::udl_formatter<char> {
- return {{s, n}};
-}
} // namespace literals
#endif // FMT_USE_USER_DEFINED_LITERALS
@@ -3060,14 +4185,6 @@
return vformat(loc, string_view(fmt), fmt::make_format_args(args...));
}
-template <typename... T, size_t SIZE, typename Allocator>
-FMT_DEPRECATED auto format_to(basic_memory_buffer<char, SIZE, Allocator>& buf,
- format_string<T...> fmt, T&&... args)
- -> appender {
- detail::vformat_to(buf, string_view(fmt), fmt::make_format_args(args...));
- return appender(buf);
-}
-
template <typename OutputIt, typename Locale,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char>::value&&
detail::is_locale<Locale>::value)>
@@ -3090,10 +4207,6 @@
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
-#ifdef FMT_DEPRECATED_INCLUDE_XCHAR
-# include "xchar.h"
-#endif
-
#ifdef FMT_HEADER_ONLY
# define FMT_FUNC inline
# include "format-inl.h"
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/os.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
similarity index 82%
rename from wpiutil/src/main/native/fmtlib/include/fmt/os.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
index b64f8bb..d82be11 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/os.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/os.h
@@ -9,10 +9,8 @@
#define FMT_OS_H_
#include <cerrno>
-#include <clocale> // locale_t
#include <cstddef>
#include <cstdio>
-#include <cstdlib> // strtod_l
#include <system_error> // std::system_error
#if defined __APPLE__ || defined(__FreeBSD__)
@@ -141,7 +139,7 @@
};
#ifdef _WIN32
-FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
+FMT_API const std::error_category& system_category() noexcept;
FMT_BEGIN_DETAIL_NAMESPACE
// A converter from UTF-16 to UTF-8.
@@ -165,7 +163,7 @@
};
FMT_API void format_windows_error(buffer<char>& out, int error_code,
- const char* message) FMT_NOEXCEPT;
+ const char* message) noexcept;
FMT_END_DETAIL_NAMESPACE
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
@@ -207,10 +205,9 @@
// Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors.
-FMT_API void report_windows_error(int error_code,
- const char* message) FMT_NOEXCEPT;
+FMT_API void report_windows_error(int error_code, const char* message) noexcept;
#else
-inline const std::error_category& system_category() FMT_NOEXCEPT {
+inline const std::error_category& system_category() noexcept {
return std::system_category();
}
#endif // _WIN32
@@ -237,13 +234,13 @@
void operator=(const buffered_file&) = delete;
// Constructs a buffered_file object which doesn't represent any file.
- buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
+ buffered_file() noexcept : file_(nullptr) {}
// Destroys the object closing the file it represents if any.
- FMT_API ~buffered_file() FMT_NOEXCEPT;
+ FMT_API ~buffered_file() noexcept;
public:
- buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
+ buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
other.file_ = nullptr;
}
@@ -261,11 +258,9 @@
FMT_API void close();
// Returns the pointer to a FILE object representing this file.
- FILE* get() const FMT_NOEXCEPT { return file_; }
+ FILE* get() const noexcept { return file_; }
- // We place parentheses around fileno to workaround a bug in some versions
- // of MinGW that define fileno as a macro.
- FMT_API int(fileno)() const;
+ FMT_API int descriptor() const;
void vprint(string_view format_str, format_args args) {
fmt::vprint(file_, format_str, args);
@@ -279,12 +274,12 @@
#if FMT_USE_FCNTL
// A file. Closed file is represented by a file object with descriptor -1.
-// Methods that are not declared with FMT_NOEXCEPT may throw
+// Methods that are not declared with noexcept may throw
// fmt::system_error in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
-class file {
+class FMT_API file {
private:
int fd_; // File descriptor.
@@ -303,16 +298,16 @@
};
// Constructs a file object which doesn't represent any file.
- file() FMT_NOEXCEPT : fd_(-1) {}
+ file() noexcept : fd_(-1) {}
// Opens a file and constructs a file object representing this file.
- FMT_API file(cstring_view path, int oflag);
+ file(cstring_view path, int oflag);
public:
file(const file&) = delete;
void operator=(const file&) = delete;
- file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
+ file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
// Move assignment is not noexcept because close may throw.
file& operator=(file&& other) {
@@ -323,43 +318,43 @@
}
// Destroys the object closing the file it represents if any.
- FMT_API ~file() FMT_NOEXCEPT;
+ ~file() noexcept;
// Returns the file descriptor.
- int descriptor() const FMT_NOEXCEPT { return fd_; }
+ int descriptor() const noexcept { return fd_; }
// Closes the file.
- FMT_API void close();
+ void close();
// Returns the file size. The size has signed type for consistency with
// stat::st_size.
- FMT_API long long size() const;
+ long long size() const;
// Attempts to read count bytes from the file into the specified buffer.
- FMT_API size_t read(void* buffer, size_t count);
+ size_t read(void* buffer, size_t count);
// Attempts to write count bytes from the specified buffer to the file.
- FMT_API size_t write(const void* buffer, size_t count);
+ size_t write(const void* buffer, size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
- FMT_API static file dup(int fd);
+ static file dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
- FMT_API void dup2(int fd);
+ void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
- FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
+ void dup2(int fd, std::error_code& ec) noexcept;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
- FMT_API static void pipe(file& read_end, file& write_end);
+ static void pipe(file& read_end, file& write_end);
// Creates a buffered_file object associated with this file and detaches
// this file object from the file.
- FMT_API buffered_file fdopen(const char* mode);
+ buffered_file fdopen(const char* mode);
};
// Returns the memory page size.
@@ -462,7 +457,7 @@
* ``<integer>``: Flags passed to `open
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
- (``file::WRONLY | file::CREATE`` by default)
+ (``file::WRONLY | file::CREATE | file::TRUNC`` by default)
* ``buffer_size=<integer>``: Output buffer size
**Example**::
@@ -477,50 +472,6 @@
}
#endif // FMT_USE_FCNTL
-#ifdef FMT_LOCALE
-// A "C" numeric locale.
-class locale {
- private:
-# ifdef _WIN32
- using locale_t = _locale_t;
-
- static void freelocale(locale_t loc) { _free_locale(loc); }
-
- static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
- return _strtod_l(nptr, endptr, loc);
- }
-# endif
-
- locale_t locale_;
-
- public:
- using type = locale_t;
- locale(const locale&) = delete;
- void operator=(const locale&) = delete;
-
- locale() {
-# ifndef _WIN32
- locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
-# else
- locale_ = _create_locale(LC_NUMERIC, "C");
-# endif
- if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
- }
- ~locale() { freelocale(locale_); }
-
- type get() const { return locale_; }
-
- // Converts string to floating-point number and advances str past the end
- // of the parsed input.
- FMT_DEPRECATED double strtod(const char*& str) const {
- char* end = nullptr;
- double result = strtod_l(str, &end, locale_);
- str = end;
- return result;
- }
-};
-using Locale FMT_DEPRECATED_ALIAS = locale;
-#endif // FMT_LOCALE
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
new file mode 100644
index 0000000..c3cdd4a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ostream.h
@@ -0,0 +1,237 @@
+// Formatting library for C++ - std::ostream support
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_OSTREAM_H_
+#define FMT_OSTREAM_H_
+
+#include <fstream>
+#include <ostream>
+#if defined(_WIN32) && defined(__GLIBCXX__)
+# include <ext/stdio_filebuf.h>
+# include <ext/stdio_sync_filebuf.h>
+#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
+# include <__std_stream>
+#endif
+
+#include "format.h"
+
+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>
+class file_access {
+ friend auto get_file(BufType& obj) -> FILE* { return obj.*FileMemberPtr; }
+};
+
+#if FMT_MSC_VERSION
+template class file_access<file_access_tag, std::filebuf,
+ &std::filebuf::_Myfile>;
+auto get_file(std::filebuf&) -> FILE*;
+#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
+template class file_access<file_access_tag, std::__stdoutbuf<char>,
+ &std::__stdoutbuf<char>::__file_>;
+auto get_file(std::__stdoutbuf<char>&) -> FILE*;
+#endif
+
+inline bool write_ostream_unicode(std::ostream& os, fmt::string_view data) {
+#if FMT_MSC_VERSION
+ if (auto* buf = dynamic_cast<std::filebuf*>(os.rdbuf()))
+ if (FILE* f = get_file(*buf)) return write_console(f, data);
+#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();
+ else if (auto* fbuf = dynamic_cast<__gnu_cxx::stdio_filebuf<char>*>(rdbuf))
+ c_file = fbuf->file();
+ else
+ return false;
+ if (c_file) return write_console(c_file, data);
+#elif defined(_WIN32) && defined(_LIBCPP_VERSION)
+ if (auto* buf = dynamic_cast<std::__stdoutbuf<char>*>(os.rdbuf()))
+ if (FILE* f = get_file(*buf)) return write_console(f, data);
+#else
+ ignore_unused(os, data);
+#endif
+ return false;
+}
+inline bool write_ostream_unicode(std::wostream&,
+ fmt::basic_string_view<wchar_t>) {
+ return false;
+}
+
+// Write the content of buf to os.
+// It is a separate function rather than a part of vprint to simplify testing.
+template <typename Char>
+void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
+ const Char* buf_data = buf.data();
+ using unsigned_streamsize = std::make_unsigned<std::streamsize>::type;
+ unsigned_streamsize size = buf.size();
+ unsigned_streamsize max_size = to_unsigned(max_value<std::streamsize>());
+ do {
+ unsigned_streamsize n = size <= max_size ? size : max_size;
+ os.write(buf_data, static_cast<std::streamsize>(n));
+ buf_data += n;
+ size -= n;
+ } while (size != 0);
+}
+
+template <typename Char, typename T>
+void format_value(buffer<Char>& buf, const T& value,
+ locale_ref loc = locale_ref()) {
+ auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
+ auto&& output = std::basic_ostream<Char>(&format_buf);
+#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
+ if (loc) output.imbue(loc.get<std::locale>());
+#endif
+ output << value;
+ output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
+}
+
+template <typename T> struct streamed_view { const T& value; };
+
+} // namespace detail
+
+// Formats an object of type T that has an overloaded ostream operator<<.
+template <typename Char>
+struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
+ void set_debug_format() = delete;
+
+ template <typename T, typename OutputIt>
+ 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());
+ return formatter<basic_string_view<Char>, Char>::format(
+ {buffer.data(), buffer.size()}, ctx);
+ }
+};
+
+using ostream_formatter = basic_ostream_formatter<char>;
+
+template <typename T, typename Char>
+struct formatter<detail::streamed_view<T>, Char>
+ : basic_ostream_formatter<Char> {
+ template <typename OutputIt>
+ auto format(detail::streamed_view<T> view,
+ basic_format_context<OutputIt, Char>& ctx) const -> OutputIt {
+ return basic_ostream_formatter<Char>::format(view.value, ctx);
+ }
+};
+
+/**
+ \rst
+ Returns a view that formats `value` via an ostream ``operator<<``.
+
+ **Example**::
+
+ fmt::print("Current thread id: {}\n",
+ fmt::streamed(std::this_thread::get_id()));
+ \endrst
+ */
+template <typename T>
+auto streamed(const T& value) -> detail::streamed_view<T> {
+ return {value};
+}
+
+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();
+ detail::vformat_to(buffer, format_str, args);
+ detail::write_buffer(os, buffer);
+}
+
+} // namespace detail
+
+FMT_MODULE_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) {
+ auto buffer = basic_memory_buffer<Char>();
+ detail::vformat_to(buffer, format_str, args);
+ if (detail::write_ostream_unicode(os, {buffer.data(), buffer.size()})) return;
+ detail::write_buffer(os, buffer);
+}
+
+/**
+ \rst
+ Prints formatted data to the stream *os*.
+
+ **Example**::
+
+ fmt::print(cerr, "Don't {}!", "panic");
+ \endrst
+ */
+FMT_MODULE_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())
+ vprint(os, fmt, vargs);
+ else
+ detail::vprint_directly(os, fmt, vargs);
+}
+
+FMT_MODULE_EXPORT
+template <typename... Args>
+void print(std::wostream& os,
+ basic_format_string<wchar_t, type_identity_t<Args>...> fmt,
+ Args&&... args) {
+ vprint(os, fmt, fmt::make_format_args<buffer_context<wchar_t>>(args...));
+}
+
+FMT_END_NAMESPACE
+
+#endif // FMT_OSTREAM_H_
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/printf.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
similarity index 94%
rename from wpiutil/src/main/native/fmtlib/include/fmt/printf.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
index 19d550f..70a592d 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/printf.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/printf.h
@@ -10,7 +10,6 @@
#include <algorithm> // std::max
#include <limits> // std::numeric_limits
-#include <ostream>
#include "format.h"
@@ -561,7 +560,7 @@
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(fmt), args);
+ vprintf(buffer, detail::to_string_view(fmt), args);
return to_string(buffer);
}
@@ -578,7 +577,8 @@
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(to_string_view(fmt), fmt::make_format_args<context>(args...));
+ return vsprintf(detail::to_string_view(fmt),
+ fmt::make_format_args<context>(args...));
}
template <typename S, typename Char = char_t<S>>
@@ -587,7 +587,7 @@
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(fmt), args);
+ vprintf(buffer, detail::to_string_view(fmt), args);
size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size
? -1
@@ -606,7 +606,7 @@
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, to_string_view(fmt),
+ return vfprintf(f, detail::to_string_view(fmt),
fmt::make_format_args<context>(args...));
}
@@ -615,7 +615,7 @@
const S& fmt,
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
-> int {
- return vfprintf(stdout, to_string_view(fmt), args);
+ return vfprintf(stdout, detail::to_string_view(fmt), args);
}
/**
@@ -630,27 +630,10 @@
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(
- to_string_view(fmt),
+ detail::to_string_view(fmt),
fmt::make_format_args<basic_printf_context_t<char_t<S>>>(args...));
}
-template <typename S, typename Char = char_t<S>>
-FMT_DEPRECATED auto vfprintf(
- std::basic_ostream<Char>& os, const S& fmt,
- basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args)
- -> int {
- basic_memory_buffer<Char> buffer;
- vprintf(buffer, to_string_view(fmt), args);
- os.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
- return static_cast<int>(buffer.size());
-}
-template <typename S, typename... T, typename Char = char_t<S>>
-FMT_DEPRECATED auto fprintf(std::basic_ostream<Char>& os, const S& fmt,
- const T&... args) -> int {
- return vfprintf(os, to_string_view(fmt),
- fmt::make_format_args<basic_printf_context_t<Char>>(args...));
-}
-
FMT_MODULE_EXPORT_END
FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
new file mode 100644
index 0000000..dea7d60
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/ranges.h
@@ -0,0 +1,722 @@
+// Formatting library for C++ - experimental range support
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+//
+// Copyright (c) 2018 - present, Remotion (Igor Schulz)
+// All Rights Reserved
+// {fmt} support for ranges, containers and types tuple interface.
+
+#ifndef FMT_RANGES_H_
+#define FMT_RANGES_H_
+
+#include <initializer_list>
+#include <tuple>
+#include <type_traits>
+
+#include "format.h"
+
+FMT_BEGIN_NAMESPACE
+
+namespace detail {
+
+template <typename RangeT, typename OutputIterator>
+OutputIterator copy(const RangeT& range, OutputIterator out) {
+ 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) {
+ while (*str) *out++ = *str++;
+ return out;
+}
+
+template <typename OutputIterator>
+OutputIterator copy(char ch, OutputIterator out) {
+ *out++ = ch;
+ return out;
+}
+
+template <typename OutputIterator>
+OutputIterator copy(wchar_t ch, OutputIterator out) {
+ *out++ = ch;
+ return out;
+}
+
+// Returns true if T has a std::string-like interface, like std::string_view.
+template <typename T> class is_std_string_like {
+ template <typename U>
+ static auto check(U* p)
+ -> decltype((void)p->find('a'), p->length(), (void)p->data(), int());
+ template <typename> static void check(...);
+
+ public:
+ static constexpr const bool value =
+ is_string<T>::value ||
+ std::is_convertible<T, std_string_view<char>>::value ||
+ !std::is_void<decltype(check<T>(nullptr))>::value;
+};
+
+template <typename Char>
+struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
+
+template <typename T> class is_map {
+ template <typename U> static auto check(U*) -> typename U::mapped_type;
+ template <typename> static void check(...);
+
+ public:
+#ifdef FMT_FORMAT_MAP_AS_LIST
+ static constexpr const bool value = false;
+#else
+ static constexpr const bool value =
+ !std::is_void<decltype(check<T>(nullptr))>::value;
+#endif
+};
+
+template <typename T> class is_set {
+ template <typename U> static auto check(U*) -> typename U::key_type;
+ template <typename> static void check(...);
+
+ public:
+#ifdef FMT_FORMAT_SET_AS_LIST
+ static constexpr const bool value = false;
+#else
+ static constexpr const bool value =
+ !std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
+#endif
+};
+
+template <typename... Ts> struct conditional_helper {};
+
+template <typename T, typename _ = void> struct is_range_ : std::false_type {};
+
+#if !FMT_MSC_VERSION || FMT_MSC_VERSION > 1800
+
+# define FMT_DECLTYPE_RETURN(val) \
+ ->decltype(val) { return val; } \
+ static_assert( \
+ true, "") // This makes it so that a semicolon is required after the
+ // macro, which helps clang-format handle the formatting.
+
+// C array overload
+template <typename T, std::size_t N>
+auto range_begin(const T (&arr)[N]) -> const T* {
+ return arr;
+}
+template <typename T, std::size_t N>
+auto range_end(const T (&arr)[N]) -> const T* {
+ return arr + N;
+}
+
+template <typename T, typename Enable = void>
+struct has_member_fn_begin_end_t : std::false_type {};
+
+template <typename T>
+struct has_member_fn_begin_end_t<T, void_t<decltype(std::declval<T>().begin()),
+ decltype(std::declval<T>().end())>>
+ : std::true_type {};
+
+// Member function overload
+template <typename T>
+auto range_begin(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).begin());
+template <typename T>
+auto range_end(T&& rng) FMT_DECLTYPE_RETURN(static_cast<T&&>(rng).end());
+
+// ADL overload. Only participates in overload resolution if member functions
+// are not found.
+template <typename T>
+auto range_begin(T&& rng)
+ -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
+ decltype(begin(static_cast<T&&>(rng)))> {
+ return begin(static_cast<T&&>(rng));
+}
+template <typename T>
+auto range_end(T&& rng) -> enable_if_t<!has_member_fn_begin_end_t<T&&>::value,
+ decltype(end(static_cast<T&&>(rng)))> {
+ return end(static_cast<T&&>(rng));
+}
+
+template <typename T, typename Enable = void>
+struct has_const_begin_end : std::false_type {};
+template <typename T, typename Enable = void>
+struct has_mutable_begin_end : std::false_type {};
+
+template <typename T>
+struct has_const_begin_end<
+ T,
+ void_t<
+ decltype(detail::range_begin(std::declval<const remove_cvref_t<T>&>())),
+ decltype(detail::range_end(std::declval<const remove_cvref_t<T>&>()))>>
+ : std::true_type {};
+
+template <typename T>
+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 {};
+
+template <typename T>
+struct is_range_<T, void>
+ : std::integral_constant<bool, (has_const_begin_end<T>::value ||
+ has_mutable_begin_end<T>::value)> {};
+# undef FMT_DECLTYPE_RETURN
+#endif
+
+// tuple_size and tuple_element check.
+template <typename T> class is_tuple_like_ {
+ template <typename U>
+ static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
+ template <typename> static void check(...);
+
+ public:
+ static constexpr const bool value =
+ !std::is_void<decltype(check<T>(nullptr))>::value;
+};
+
+// Check for integer_sequence
+#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
+template <typename T, T... N>
+using integer_sequence = std::integer_sequence<T, N...>;
+template <size_t... N> using index_sequence = std::index_sequence<N...>;
+template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
+#else
+template <typename T, T... N> struct integer_sequence {
+ using value_type = T;
+
+ static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
+};
+
+template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
+
+template <typename T, size_t N, T... Ns>
+struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
+template <typename T, T... Ns>
+struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
+
+template <size_t N>
+using make_index_sequence = make_integer_sequence<size_t, N>;
+#endif
+
+template <typename T>
+using tuple_index_sequence = make_index_sequence<std::tuple_size<T>::value>;
+
+template <typename T, typename C, bool = is_tuple_like_<T>::value>
+class is_tuple_formattable_ {
+ public:
+ 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)...>);
+ static std::false_type check2(...);
+ template <std::size_t... I>
+ static decltype(check2(
+ index_sequence<I...>{},
+ integer_sequence<
+ bool, (is_formattable<typename std::tuple_element<I, T>::type,
+ C>::value)...>{})) check(index_sequence<I...>);
+
+ 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 {
+ using std::get;
+ // using free function get<I>(T) now.
+ const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
+ (void)_; // blocks warnings
+}
+
+template <class T>
+FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(
+ T const&) {
+ return {};
+}
+
+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));
+}
+
+#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 {
+ using type = decltype(*detail::range_begin(std::declval<R&>()));
+};
+
+template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
+ using type = T&;
+};
+
+template <typename T>
+using range_reference_type = typename range_reference_type_impl<T>::type;
+#else
+template <typename Range>
+using range_reference_type =
+ decltype(*detail::range_begin(std::declval<Range&>()));
+#endif
+
+// We don't use the Range's value_type for anything, but we do need the Range's
+// reference type, with cv-ref stripped.
+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 Char, typename OutputIt>
+auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
+ return write_escaped_string(out, str);
+}
+
+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 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);
+}
+
+} // namespace detail
+
+template <typename T> struct is_tuple_like {
+ static constexpr const bool value =
+ detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
+};
+
+template <typename T, typename C> struct is_tuple_formattable {
+ static constexpr const bool value =
+ 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>> {
+ private:
+ 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() {}
+
+ FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
+ separator_ = sep;
+ }
+
+ FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
+ basic_string_view<Char> close) {
+ opening_bracket_ = open;
+ closing_bracket_ = close;
+ }
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ template <typename FormatContext = format_context>
+ auto format(const TupleT& values, 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;
+ }
+};
+
+template <typename T, typename Char> struct is_range {
+ static constexpr const bool value =
+ detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
+ !std::is_convertible<T, std::basic_string<Char>>::value &&
+ !std::is_convertible<T, detail::std_string_view<Char>>::value;
+};
+
+namespace detail {
+template <typename Context> struct range_mapper {
+ using mapper = arg_mapper<Context>;
+
+ template <typename T,
+ FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
+ static auto map(T&& value) -> T&& {
+ return static_cast<T&&>(value);
+ }
+ template <typename T,
+ FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
+ static auto map(T&& value)
+ -> decltype(mapper().map(static_cast<T&&>(value))) {
+ return mapper().map(static_cast<T&&>(value));
+ }
+};
+
+template <typename Char, typename Element>
+using range_formatter_type = conditional_t<
+ is_formattable<Element, Char>::value,
+ formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
+ std::declval<Element>()))>,
+ Char>,
+ fallback_formatter<Element, Char>>;
+
+template <typename R>
+using maybe_const_range =
+ conditional_t<has_const_begin_end<R>::value, const R, R>;
+
+// Workaround a bug in MSVC 2015 and earlier.
+#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>> {};
+#endif
+
+} // namespace detail
+
+template <typename T, typename Char, typename Enable = void>
+struct range_formatter;
+
+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>> {
+ 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() {}
+
+ FMT_CONSTEXPR auto underlying() -> detail::range_formatter_type<Char, T>& {
+ return underlying_;
+ }
+
+ FMT_CONSTEXPR void set_separator(basic_string_view<Char> sep) {
+ separator_ = sep;
+ }
+
+ FMT_CONSTEXPR void set_brackets(basic_string_view<Char> open,
+ basic_string_view<Char> close) {
+ opening_bracket_ = open;
+ closing_bracket_ = close;
+ }
+
+ template <typename ParseContext>
+ 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') {
+ set_brackets({}, {});
+ ++it;
+ }
+
+ if (*it == '}') {
+ maybe_set_debug_format();
+ return it;
+ }
+
+ 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>
+ auto format(R&& range, FormatContext& ctx) const -> decltype(ctx.out()) {
+ detail::range_mapper<buffer_context<Char>> mapper;
+ auto out = ctx.out();
+ out = detail::copy_str<Char>(opening_bracket_, out);
+ int i = 0;
+ auto it = detail::range_begin(range);
+ 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;
+ }
+ out = detail::copy_str<Char>(closing_bracket_, out);
+ return out;
+ }
+};
+
+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 <range_format K, typename R, typename Char, typename Enable = void>
+struct range_default_formatter;
+
+template <range_format K>
+using range_format_constant = std::integral_constant<range_format, K>;
+
+template <range_format K, typename R, typename Char>
+struct range_default_formatter<
+ K, R, Char,
+ enable_if_t<(K == range_format::sequence || K == range_format::map ||
+ K == range_format::set)>> {
+ using range_type = detail::maybe_const_range<R>;
+ range_formatter<detail::uncvref_type<range_type>, Char> underlying_;
+
+ FMT_CONSTEXPR range_default_formatter() { init(range_format_constant<K>()); }
+
+ FMT_CONSTEXPR void init(range_format_constant<range_format::set>) {
+ underlying_.set_brackets(detail::string_literal<Char, '{'>{},
+ detail::string_literal<Char, '}'>{});
+ }
+
+ FMT_CONSTEXPR void init(range_format_constant<range_format::map>) {
+ underlying_.set_brackets(detail::string_literal<Char, '{'>{},
+ detail::string_literal<Char, '}'>{});
+ underlying_.underlying().set_brackets({}, {});
+ underlying_.underlying().set_separator(
+ detail::string_literal<Char, ':', ' '>{});
+ }
+
+ FMT_CONSTEXPR void init(range_format_constant<range_format::sequence>) {}
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return underlying_.parse(ctx);
+ }
+
+ template <typename FormatContext>
+ auto format(range_type& range, FormatContext& ctx) const
+ -> decltype(ctx.out()) {
+ return underlying_.format(range, ctx);
+ }
+};
+} // namespace detail
+
+template <typename T, typename Char, typename Enable = void>
+struct range_format_kind
+ : conditional_t<
+ is_range<T, Char>::value, detail::range_format_kind_<T>,
+ std::integral_constant<range_format, range_format::disabled>> {};
+
+template <typename R, typename Char>
+struct formatter<
+ R, Char,
+ enable_if_t<conjunction<bool_constant<range_format_kind<R, Char>::value !=
+ range_format::disabled>
+// Workaround a bug in MSVC 2015 and earlier.
+#if !FMT_MSC_VERSION || FMT_MSC_VERSION >= 1910
+ ,
+ detail::is_formattable_delayed<R, Char>
+#endif
+ >::value>>
+ : detail::range_default_formatter<range_format_kind<R, Char>::value, R,
+ Char> {
+};
+
+template <typename Char, typename... T> struct tuple_join_view : detail::view {
+ const std::tuple<T...>& tuple;
+ basic_string_view<Char> sep;
+
+ tuple_join_view(const std::tuple<T...>& t, basic_string_view<Char> s)
+ : 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.
+#ifndef FMT_TUPLE_JOIN_SPECIFIERS
+# define FMT_TUPLE_JOIN_SPECIFIERS 0
+#endif
+
+template <typename Char, typename... T>
+struct formatter<tuple_join_view<Char, T...>, Char> {
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
+ }
+
+ template <typename FormatContext>
+ auto format(const tuple_join_view<Char, T...>& value,
+ FormatContext& ctx) const -> typename FormatContext::iterator {
+ return do_format(value, ctx,
+ std::integral_constant<size_t, sizeof...(T)>());
+ }
+
+ private:
+ std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
+
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
+ std::integral_constant<size_t, 0>)
+ -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ template <typename ParseContext, size_t N>
+ FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
+ std::integral_constant<size_t, N>)
+ -> decltype(ctx.begin()) {
+ auto end = ctx.begin();
+#if FMT_TUPLE_JOIN_SPECIFIERS
+ end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
+ if (N > 1) {
+ auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
+ if (end != end1)
+ FMT_THROW(format_error("incompatible format specs for tuple elements"));
+ }
+#endif
+ return end;
+ }
+
+ template <typename FormatContext>
+ auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
+ std::integral_constant<size_t, 0>) const ->
+ typename FormatContext::iterator {
+ return ctx.out();
+ }
+
+ template <typename FormatContext, size_t N>
+ auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
+ std::integral_constant<size_t, N>) const ->
+ typename FormatContext::iterator {
+ auto out = std::get<sizeof...(T) - N>(formatters_)
+ .format(std::get<sizeof...(T) - N>(value.tuple), ctx);
+ if (N > 1) {
+ out = std::copy(value.sep.begin(), value.sep.end(), out);
+ ctx.advance_to(out);
+ return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
+ }
+ return out;
+ }
+};
+
+FMT_MODULE_EXPORT_BEGIN
+
+/**
+ \rst
+ Returns an object that formats `tuple` with elements separated by `sep`.
+
+ **Example**::
+
+ std::tuple<int, char> t = {1, 'a'};
+ fmt::print("{}", fmt::join(t, ", "));
+ // Output: "1, a"
+ \endrst
+ */
+template <typename... T>
+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple, string_view sep)
+ -> tuple_join_view<char, T...> {
+ return {tuple, sep};
+}
+
+template <typename... T>
+FMT_CONSTEXPR auto join(const std::tuple<T...>& tuple,
+ basic_string_view<wchar_t> sep)
+ -> tuple_join_view<wchar_t, T...> {
+ return {tuple, sep};
+}
+
+/**
+ \rst
+ Returns an object that formats `initializer_list` with elements separated by
+ `sep`.
+
+ **Example**::
+
+ fmt::print("{}", fmt::join({1, 2, 3}, ", "));
+ // Output: "1, 2, 3"
+ \endrst
+ */
+template <typename T>
+auto join(std::initializer_list<T> list, string_view sep)
+ -> join_view<const T*, const T*> {
+ return join(std::begin(list), std::end(list), sep);
+}
+
+FMT_MODULE_EXPORT_END
+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
new file mode 100644
index 0000000..41d2b28
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/std.h
@@ -0,0 +1,171 @@
+// Formatting library for C++ - formatters for standard library types
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_STD_H_
+#define FMT_STD_H_
+
+#include <thread>
+#include <type_traits>
+#include <utility>
+
+#include "ostream.h"
+
+#if FMT_HAS_INCLUDE(<version>)
+# include <version>
+#endif
+// Checking FMT_CPLUSPLUS for warning suppression in MSVC.
+#if FMT_CPLUSPLUS >= 201703L
+# if FMT_HAS_INCLUDE(<filesystem>)
+# include <filesystem>
+# endif
+# if FMT_HAS_INCLUDE(<variant>)
+# include <variant>
+# endif
+#endif
+
+#ifdef __cpp_lib_filesystem
+FMT_BEGIN_NAMESPACE
+
+namespace detail {
+
+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()));
+}
+# endif
+template <>
+inline void write_escaped_path<std::filesystem::path::value_type>(
+ basic_memory_buffer<std::filesystem::path::value_type>& quoted,
+ const std::filesystem::path& p) {
+ write_escaped_string<std::filesystem::path::value_type>(
+ std::back_inserter(quoted), p.native());
+}
+
+} // namespace detail
+
+template <typename Char>
+struct formatter<std::filesystem::path, Char>
+ : formatter<basic_string_view<Char>> {
+ template <typename FormatContext>
+ auto format(const std::filesystem::path& p, FormatContext& ctx) const ->
+ typename FormatContext::iterator {
+ basic_memory_buffer<Char> quoted;
+ detail::write_escaped_path(quoted, p);
+ return formatter<basic_string_view<Char>>::format(
+ basic_string_view<Char>(quoted.data(), quoted.size()), ctx);
+ }
+};
+FMT_END_NAMESPACE
+#endif
+
+FMT_BEGIN_NAMESPACE
+template <typename Char>
+struct formatter<std::thread::id, Char> : basic_ostream_formatter<Char> {};
+FMT_END_NAMESPACE
+
+#ifdef __cpp_lib_variant
+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();
+ }
+
+ template <typename FormatContext>
+ auto format(const std::monostate&, FormatContext& ctx) const
+ -> decltype(ctx.out()) {
+ auto out = ctx.out();
+ out = detail::write<Char>(out, "monostate");
+ return out;
+ }
+};
+
+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 {};
+
+// formattable element check
+template <typename T, typename C> class is_variant_formattable_ {
+ template <std::size_t... I>
+ static std::conjunction<
+ is_formattable<std::variant_alternative_t<I, T>, C>...>
+ check(std::index_sequence<I...>);
+
+ public:
+ static constexpr const bool value =
+ decltype(check(variant_index_sequence<T>{}))::value;
+};
+
+template <typename Char, typename OutputIt, typename T>
+auto write_variant_alternative(OutputIt out, const T& v) -> OutputIt {
+ if constexpr (is_string<T>::value)
+ return write_escaped_string<Char>(out, detail::to_string_view(v));
+ else if constexpr (std::is_same_v<T, Char>)
+ return write_escaped_char(out, v);
+ else
+ return write<Char>(out, v);
+}
+
+} // namespace detail
+
+template <typename T> struct is_variant_like {
+ static constexpr const bool value = detail::is_variant_like_<T>::value;
+};
+
+template <typename T, typename C> struct is_variant_formattable {
+ static constexpr const bool value =
+ detail::is_variant_formattable_<T, C>::value;
+};
+
+template <typename Variant, typename Char>
+struct formatter<
+ Variant, Char,
+ std::enable_if_t<std::conjunction_v<
+ is_variant_like<Variant>, is_variant_formattable<Variant, Char>>>> {
+ template <typename ParseContext>
+ FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
+ return ctx.begin();
+ }
+
+ template <typename FormatContext>
+ auto format(const Variant& value, FormatContext& ctx) const
+ -> decltype(ctx.out()) {
+ auto out = ctx.out();
+
+ out = detail::write<Char>(out, "variant(");
+ std::visit(
+ [&](const auto& v) {
+ out = detail::write_variant_alternative<Char>(out, v);
+ },
+ value);
+ *out++ = ')';
+ return out;
+ }
+};
+FMT_END_NAMESPACE
+#endif
+
+#endif // FMT_STD_H_
diff --git a/wpiutil/src/main/native/fmtlib/include/fmt/xchar.h b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
similarity index 80%
rename from wpiutil/src/main/native/fmtlib/include/fmt/xchar.h
rename to wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
index 9acb893..fc3c67f 100644
--- a/wpiutil/src/main/native/fmtlib/include/fmt/xchar.h
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/include/fmt/xchar.h
@@ -9,7 +9,6 @@
#define FMT_XCHAR_H_
#include <cwchar>
-#include <tuple>
#include "format.h"
@@ -30,9 +29,11 @@
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
// Workaround broken conversion on older gcc.
template <typename... Args> using wformat_string = wstring_view;
+inline auto runtime(wstring_view s) -> wstring_view { return s; }
#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}}; }
#endif
template <> struct is_char<wchar_t> : std::true_type {};
@@ -47,12 +48,7 @@
}
inline namespace literals {
-constexpr auto operator"" _format(const wchar_t* s, size_t n)
- -> detail::udl_formatter<wchar_t> {
- return {{s, n}};
-}
-
-#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
+#if FMT_USE_USER_DEFINED_LITERALS && !FMT_USE_NONTYPE_TEMPLATE_ARGS
constexpr detail::udl_arg<wchar_t> operator"" _a(const wchar_t* s, size_t) {
return {s};
}
@@ -87,13 +83,19 @@
return to_string(buffer);
}
+template <typename... T>
+auto format(wformat_string<T...> fmt, T&&... args) -> std::wstring {
+ return vformat(fmt::wstring_view(fmt), fmt::make_wformat_args(args...));
+}
+
// 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>,
- FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
+ 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> {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return vformat(to_string_view(format_str), vargs);
+ return vformat(detail::to_string_view(format_str),
+ fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename Char = char_t<S>,
@@ -103,7 +105,7 @@
const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> std::basic_string<Char> {
- return detail::vformat(loc, to_string_view(format_str), args);
+ return detail::vformat(loc, detail::to_string_view(format_str), args);
}
template <typename Locale, typename S, typename... Args,
@@ -112,8 +114,8 @@
detail::is_exotic_char<Char>::value)>
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
-> std::basic_string<Char> {
- return detail::vformat(loc, to_string_view(format_str),
- fmt::make_args_checked<Args...>(format_str, args...));
+ return detail::vformat(loc, detail::to_string_view(format_str),
+ fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename S, typename Char = char_t<S>,
@@ -123,7 +125,7 @@
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
- detail::vformat_to(buf, to_string_view(format_str), args);
+ detail::vformat_to(buf, detail::to_string_view(format_str), args);
return detail::get_iterator(buf);
}
@@ -132,18 +134,8 @@
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 {
- const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
- return vformat_to(out, to_string_view(fmt), vargs);
-}
-
-template <typename S, typename... Args, typename Char, size_t SIZE,
- typename Allocator, FMT_ENABLE_IF(detail::is_string<S>::value)>
-FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
- const S& format_str, Args&&... args) ->
- typename buffer_context<Char>::iterator {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- detail::vformat_to(buf, to_string_view(format_str), vargs, {});
- return detail::buffer_appender<Char>(buf);
+ return vformat_to(out, detail::to_string_view(fmt),
+ fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename Locale, typename S, typename OutputIt, typename... Args,
@@ -155,7 +147,8 @@
OutputIt out, const Locale& loc, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) -> OutputIt {
auto&& buf = detail::get_buffer<Char>(out);
- vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
+ vformat_to(buf, detail::to_string_view(format_str), args,
+ detail::locale_ref(loc));
return detail::get_iterator(buf);
}
@@ -167,8 +160,8 @@
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
- const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
- return vformat_to(out, loc, to_string_view(format_str), vargs);
+ return vformat_to(out, loc, to_string_view(format_str),
+ fmt::make_format_args<buffer_context<Char>>(args...));
}
template <typename OutputIt, typename Char, typename... Args,
@@ -190,16 +183,16 @@
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> {
- const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
- return vformat_to_n(out, n, to_string_view(fmt), vargs);
+ 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>,
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;
- const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
- detail::vformat_to(buf, to_string_view(fmt), vargs);
+ detail::vformat_to(buf, detail::to_string_view(fmt),
+ fmt::make_format_args<buffer_context<Char>>(args...));
return buf.count();
}
diff --git a/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp b/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
new file mode 100644
index 0000000..99b7e9d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/src/format.cpp
@@ -0,0 +1,47 @@
+// Formatting library for C++
+//
+// Copyright (c) 2012 - 2016, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#include "fmt/format-inl.h"
+
+FMT_BEGIN_NAMESPACE
+namespace detail {
+
+template FMT_API auto dragonbox::to_decimal(float x) noexcept
+ -> dragonbox::decimal_fp<float>;
+template FMT_API auto dragonbox::to_decimal(double x) noexcept
+ -> dragonbox::decimal_fp<double>;
+
+#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
+template FMT_API locale_ref::locale_ref(const std::locale& loc);
+template FMT_API auto locale_ref::get<std::locale>() const -> std::locale;
+#endif
+
+// Explicit instantiations for char.
+
+template FMT_API auto thousands_sep_impl(locale_ref)
+ -> thousands_sep_result<char>;
+template FMT_API auto decimal_point_impl(locale_ref) -> char;
+
+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);
+
+// Explicit instantiations for wchar_t.
+
+template FMT_API auto thousands_sep_impl(locale_ref)
+ -> thousands_sep_result<wchar_t>;
+template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t;
+
+template FMT_API void buffer<wchar_t>::append(const wchar_t*, const wchar_t*);
+
+} // namespace detail
+FMT_END_NAMESPACE
diff --git a/wpiutil/src/main/native/fmtlib/src/os.cpp b/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
similarity index 90%
rename from wpiutil/src/main/native/fmtlib/src/os.cpp
rename to wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
index 4eb3e1f..2c49951 100644
--- a/wpiutil/src/main/native/fmtlib/src/os.cpp
+++ b/wpiutil/src/main/native/thirdparty/fmtlib/src/os.cpp
@@ -35,9 +35,15 @@
# ifndef S_IRGRP
# define S_IRGRP 0
# endif
+# ifndef S_IWGRP
+# define S_IWGRP 0
+# endif
# ifndef S_IROTH
# define S_IROTH 0
# endif
+# ifndef S_IWOTH
+# define S_IWOTH 0
+# endif
# endif // _WIN32
#endif // FMT_USE_FCNTL
@@ -45,10 +51,6 @@
# include <windows.h>
#endif
-#ifdef fileno
-# undef fileno
-#endif
-
namespace {
#ifdef _WIN32
// Return type of read and write functions.
@@ -107,7 +109,7 @@
unsigned long result_;
wchar_t* message_;
- static bool is_whitespace(wchar_t c) FMT_NOEXCEPT {
+ static bool is_whitespace(wchar_t c) noexcept {
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
}
@@ -126,15 +128,15 @@
}
}
~system_message() { LocalFree(message_); }
- explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
- operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
+ explicit operator bool() const noexcept { return result_ != 0; }
+ operator basic_string_view<wchar_t>() const noexcept {
return basic_string_view<wchar_t>(message_, result_);
}
};
class utf8_system_category final : public std::error_category {
public:
- const char* name() const FMT_NOEXCEPT override { return "system"; }
+ const char* name() const noexcept override { return "system"; }
std::string message(int error_code) const override {
system_message msg(error_code);
if (msg) {
@@ -149,7 +151,7 @@
} // namespace detail
-FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
+FMT_API const std::error_category& system_category() noexcept {
static const detail::utf8_system_category category;
return category;
}
@@ -161,13 +163,13 @@
}
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
- const char* message) FMT_NOEXCEPT {
+ const char* message) noexcept {
FMT_TRY {
system_message msg(error_code);
if (msg) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(msg) == ERROR_SUCCESS) {
- format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
+ fmt::format_to(buffer_appender<char>(out), "{}: {}", message, utf8_message);
return;
}
}
@@ -176,12 +178,12 @@
format_error_code(out, error_code, message);
}
-void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT {
+void report_windows_error(int error_code, const char* message) noexcept {
report_error(detail::format_windows_error, error_code, message);
}
#endif // _WIN32
-buffered_file::~buffered_file() FMT_NOEXCEPT {
+buffered_file::~buffered_file() noexcept {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
report_system_error(errno, "cannot close file");
}
@@ -200,11 +202,8 @@
if (result != 0) FMT_THROW(system_error(errno, "cannot close file"));
}
-// A macro used to prevent expansion of fileno on broken versions of MinGW.
-#define FMT_ARGS
-
-int buffered_file::fileno() const {
- int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
+int buffered_file::descriptor() const {
+ int fd = FMT_POSIX_CALL(fileno(file_));
if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor"));
return fd;
}
@@ -214,7 +213,8 @@
# ifdef _WIN32
using mode_t = int;
# endif
- mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ constexpr mode_t mode =
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
# if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
@@ -225,7 +225,7 @@
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
}
-file::~file() FMT_NOEXCEPT {
+file::~file() noexcept {
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
@@ -298,7 +298,7 @@
}
}
-void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT {
+void file::dup2(int fd, std::error_code& ec) noexcept {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) ec = std::error_code(errno, std::generic_category());
diff --git a/wpiutil/src/main/native/include/wpi/ghc/filesystem.hpp b/wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
similarity index 100%
rename from wpiutil/src/main/native/include/wpi/ghc/filesystem.hpp
rename to wpiutil/src/main/native/thirdparty/ghc/include/wpi/ghc/filesystem.hpp
diff --git a/wpiutil/src/main/native/cpp/json.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
similarity index 100%
rename from wpiutil/src/main/native/cpp/json.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json.cpp
diff --git a/wpiutil/src/main/native/cpp/json_binary_reader.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
similarity index 99%
rename from wpiutil/src/main/native/cpp/json_binary_reader.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
index cee5e39..2081359 100644
--- a/wpiutil/src/main/native/cpp/json_binary_reader.cpp
+++ b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_reader.cpp
@@ -1384,7 +1384,7 @@
return binary_reader(is).parse_cbor(strict);
}
-json json::from_cbor(span<const uint8_t> arr, const bool strict)
+json json::from_cbor(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_cbor(is, strict);
@@ -1395,7 +1395,7 @@
return binary_reader(is).parse_msgpack(strict);
}
-json json::from_msgpack(span<const uint8_t> arr, const bool strict)
+json json::from_msgpack(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_msgpack(is, strict);
@@ -1406,7 +1406,7 @@
return binary_reader(is).parse_ubjson(strict);
}
-json json::from_ubjson(span<const uint8_t> arr, const bool strict)
+json json::from_ubjson(std::span<const uint8_t> arr, const bool strict)
{
raw_mem_istream is(arr);
return from_ubjson(is, strict);
diff --git a/wpiutil/src/main/native/cpp/json_binary_writer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
similarity index 98%
rename from wpiutil/src/main/native/cpp/json_binary_writer.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
index db23f8d..e25d478 100644
--- a/wpiutil/src/main/native/cpp/json_binary_writer.cpp
+++ b/wpiutil/src/main/native/thirdparty/json/cpp/json_binary_writer.cpp
@@ -813,7 +813,7 @@
std::reverse(vec.begin(), vec.end());
}
- o << span{vec.data(), sizeof(NumberType)};
+ o << std::span{vec.data(), sizeof(NumberType)};
}
template<typename NumberType, typename std::enable_if<
@@ -1004,7 +1004,7 @@
return result;
}
-span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
+std::span<uint8_t> json::to_cbor(const json& j, std::vector<uint8_t>& buf)
{
buf.clear();
raw_uvector_ostream os(buf);
@@ -1012,7 +1012,7 @@
return os.array();
}
-span<uint8_t> json::to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf)
+std::span<uint8_t> json::to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf)
{
buf.clear();
raw_usvector_ostream os(buf);
@@ -1033,7 +1033,7 @@
return result;
}
-span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
+std::span<uint8_t> json::to_msgpack(const json& j, std::vector<uint8_t>& buf)
{
buf.clear();
raw_uvector_ostream os(buf);
@@ -1041,7 +1041,7 @@
return os.array();
}
-span<uint8_t> json::to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf)
+std::span<uint8_t> json::to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf)
{
buf.clear();
raw_usvector_ostream os(buf);
@@ -1064,7 +1064,7 @@
return result;
}
-span<uint8_t> json::to_ubjson(const json& j, std::vector<uint8_t>& buf,
+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();
@@ -1073,7 +1073,7 @@
return os.array();
}
-span<uint8_t> json::to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
+std::span<uint8_t> json::to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
const bool use_size, const bool use_type)
{
buf.clear();
diff --git a/wpiutil/src/main/native/cpp/json_parser.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
similarity index 99%
rename from wpiutil/src/main/native/cpp/json_parser.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
index db1ed11..3c29489 100644
--- a/wpiutil/src/main/native/cpp/json_parser.cpp
+++ b/wpiutil/src/main/native/thirdparty/json/cpp/json_parser.cpp
@@ -1921,11 +1921,11 @@
const parser_callback_t cb,
const bool allow_exceptions)
{
- raw_mem_istream is(span<const char>(s.data(), s.size()));
+ raw_mem_istream is(std::span<const char>(s.data(), s.size()));
return parse(is, cb, allow_exceptions);
}
-json json::parse(span<const uint8_t> arr,
+json json::parse(std::span<const uint8_t> arr,
const parser_callback_t cb,
const bool allow_exceptions)
{
@@ -1944,11 +1944,11 @@
bool json::accept(std::string_view s)
{
- raw_mem_istream is(span<const char>(s.data(), s.size()));
+ raw_mem_istream is(std::span<const char>(s.data(), s.size()));
return parser(is).accept(true);
}
-bool json::accept(span<const uint8_t> arr)
+bool json::accept(std::span<const uint8_t> arr)
{
raw_mem_istream is(arr);
return parser(is).accept(true);
diff --git a/wpiutil/src/main/native/cpp/json_pointer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
similarity index 100%
rename from wpiutil/src/main/native/cpp/json_pointer.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json_pointer.cpp
diff --git a/wpiutil/src/main/native/cpp/json_serializer.cpp b/wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
similarity index 100%
rename from wpiutil/src/main/native/cpp/json_serializer.cpp
rename to wpiutil/src/main/native/thirdparty/json/cpp/json_serializer.cpp
diff --git a/wpiutil/src/main/native/include/wpi/json.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
similarity index 99%
rename from wpiutil/src/main/native/include/wpi/json.h
rename to wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
index 1a4e410..1c07deb 100644
--- a/wpiutil/src/main/native/include/wpi/json.h
+++ b/wpiutil/src/main/native/thirdparty/json/include/wpi/json.h
@@ -43,7 +43,6 @@
#include <algorithm> // all_of, copy, find, for_each, generate_n, min, reverse, remove, fill, none_of, transform
#include <array> // array
#include <cassert> // assert
-#include <ciso646> // and, not, or
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <exception> // exception
@@ -52,6 +51,7 @@
#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>
@@ -61,7 +61,6 @@
#include <vector> // vector
#include "wpi/StringMap.h"
-#include "wpi/span.h"
namespace wpi
{
@@ -1126,7 +1125,7 @@
}
template<typename BasicJsonType, typename T>
- static void construct(BasicJsonType& j, span<T> arr)
+ static void construct(BasicJsonType& j, std::span<T> arr)
{
using std::begin;
using std::end;
@@ -7015,7 +7014,7 @@
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true);
- static json parse(span<const uint8_t> arr,
+ static json parse(std::span<const uint8_t> arr,
const parser_callback_t cb = nullptr,
const bool allow_exceptions = true);
@@ -7028,7 +7027,7 @@
static bool accept(std::string_view s);
- static bool accept(span<const uint8_t> arr);
+ static bool accept(std::span<const uint8_t> arr);
static bool accept(raw_istream& i);
@@ -7206,8 +7205,8 @@
@since version 2.0.9
*/
static std::vector<uint8_t> to_cbor(const json& j);
- static span<uint8_t> to_cbor(const json& j, std::vector<uint8_t>& buf);
- static span<uint8_t> to_cbor(const json& j, SmallVectorImpl<uint8_t>& buf);
+ 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);
/*!
@@ -7291,8 +7290,8 @@
@since version 2.0.9
*/
static std::vector<uint8_t> to_msgpack(const json& j);
- static span<uint8_t> to_msgpack(const json& j, std::vector<uint8_t>& buf);
- static span<uint8_t> to_msgpack(const json& j, SmallVectorImpl<uint8_t>& buf);
+ 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);
/*!
@@ -7378,9 +7377,9 @@
static std::vector<uint8_t> to_ubjson(const json& j,
const bool use_size = false,
const bool use_type = false);
- static span<uint8_t> to_ubjson(const json& j, std::vector<uint8_t>& buf,
+ 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 span<uint8_t> to_ubjson(const json& j, SmallVectorImpl<uint8_t>& buf,
+ 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);
@@ -7484,7 +7483,7 @@
/*!
@copydoc from_cbor(raw_istream&, const bool)
*/
- static json from_cbor(span<const uint8_t> arr, const bool strict = true);
+ 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
@@ -7565,7 +7564,7 @@
/*!
@copydoc from_msgpack(raw_istream&, const bool)
*/
- static json from_msgpack(span<const uint8_t> arr, const bool strict = true);
+ 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
@@ -7623,7 +7622,7 @@
static json from_ubjson(raw_istream& is,
const bool strict = true);
- static json from_ubjson(span<const uint8_t> arr, const bool strict = true);
+ static json from_ubjson(std::span<const uint8_t> arr, const bool strict = true);
/// @}
diff --git a/wpiutil/src/main/native/include/wpi/json_serializer.h b/wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
similarity index 100%
rename from wpiutil/src/main/native/include/wpi/json_serializer.h
rename to wpiutil/src/main/native/thirdparty/json/include/wpi/json_serializer.h
diff --git a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
similarity index 98%
rename from wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
index 3050e63..dbf41ab 100644
--- a/wpiutil/src/main/native/cpp/llvm/ConvertUTF.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTF.cpp
@@ -1,9 +1,8 @@
/*===--- ConvertUTF.c - Universal Character Names conversions ---------------===
*
- * The LLVM Compiler Infrastructure
- *
- * This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
+ * 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
*
*===------------------------------------------------------------------------=*/
/*
@@ -755,7 +754,7 @@
}
utf16.reserve(len + 1);
- utf16.set_size(len);
+ utf16.resize_for_overwrite(len);
len = ::MultiByteToWideChar(codepage, MB_ERR_INVALID_CHARS, original.data(),
original.size(), utf16.begin(), utf16.size());
@@ -796,7 +795,7 @@
}
converted.reserve(len);
- converted.set_size(len);
+ converted.resize_for_overwrite(len);
// Now do the actual conversion.
len = ::WideCharToMultiByte(codepage, 0, utf16, utf16_len, converted.data(),
@@ -829,6 +828,6 @@
#endif // _WIN32
-} // namespace llvm
+} // namespace wpi
ConvertUTF_RESTORE_WARNINGS
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
new file mode 100644
index 0000000..e95c04f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ConvertUTFWrapper.cpp
@@ -0,0 +1,253 @@
+//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----===
+//
+// 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 <span>
+#include "wpi/ConvertUTF.h"
+#include "wpi/SmallVector.h"
+#include "wpi/ErrorHandling.h"
+#include "wpi/SwapByteOrder.h"
+#include <string>
+#include <string_view>
+#include <vector>
+
+namespace wpi {
+
+bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
+ char *&ResultPtr, const UTF8 *&ErrorPtr) {
+ assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4);
+ ConversionResult result = conversionOK;
+ // Copy the character std::span over.
+ if (WideCharWidth == 1) {
+ const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.data());
+ if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.data() + Source.size()))) {
+ result = sourceIllegal;
+ ErrorPtr = Pos;
+ } else {
+ memcpy(ResultPtr, Source.data(), Source.size());
+ ResultPtr += Source.size();
+ }
+ } else if (WideCharWidth == 2) {
+ 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);
+ ConversionFlags flags = strictConversion;
+ result = ConvertUTF8toUTF16(
+ &sourceStart, sourceStart + Source.size(),
+ &targetStart, targetStart + Source.size(), flags);
+ if (result == conversionOK)
+ ResultPtr = reinterpret_cast<char*>(targetStart);
+ else
+ ErrorPtr = sourceStart;
+ } else if (WideCharWidth == 4) {
+ 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);
+ ConversionFlags flags = strictConversion;
+ result = ConvertUTF8toUTF32(
+ &sourceStart, sourceStart + Source.size(),
+ &targetStart, targetStart + Source.size(), flags);
+ if (result == conversionOK)
+ ResultPtr = reinterpret_cast<char*>(targetStart);
+ else
+ ErrorPtr = sourceStart;
+ }
+ assert((result != targetExhausted)
+ && "ConvertUTF8toUTFXX exhausted target buffer");
+ return result == conversionOK;
+}
+
+bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) {
+ const UTF32 *SourceStart = &Source;
+ const UTF32 *SourceEnd = SourceStart + 1;
+ UTF8 *TargetStart = reinterpret_cast<UTF8 *>(ResultPtr);
+ UTF8 *TargetEnd = TargetStart + 4;
+ ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd,
+ &TargetStart, TargetEnd,
+ strictConversion);
+ if (CR != conversionOK)
+ return false;
+
+ 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')));
+}
+
+bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<char> &Out) {
+ assert(Out.empty());
+
+ // Error out on an uneven byte count.
+ if (SrcBytes.size() % 2)
+ return false;
+
+ // Avoid OOB by returning early on empty input.
+ if (SrcBytes.empty())
+ return true;
+
+ const UTF16 *Src = reinterpret_cast<const UTF16 *>(&*SrcBytes.begin());
+ const UTF16 *SrcEnd = reinterpret_cast<const UTF16 *>(&*SrcBytes.begin() + SrcBytes.size());
+
+ assert((uintptr_t)Src % sizeof(UTF16) == 0);
+
+ // Byteswap if necessary.
+ std::vector<UTF16> ByteSwapped;
+ if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) {
+ ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd);
+ for (UTF16 &I : ByteSwapped)
+ I = wpi::ByteSwap_16(I);
+ Src = &ByteSwapped[0];
+ SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1;
+ }
+
+ // Skip the BOM for conversion.
+ if (Src[0] == UNI_UTF16_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 =
+ ConvertUTF16toUTF8(&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 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);
+}
+
+bool convertUTF8ToUTF16String(std::string_view SrcUTF8,
+ SmallVectorImpl<UTF16> &DstUTF16) {
+ assert(DstUTF16.empty());
+
+ // Avoid OOB by returning early on empty input.
+ if (SrcUTF8.empty()) {
+ DstUTF16.push_back(0);
+ DstUTF16.pop_back();
+ return true;
+ }
+
+ const UTF8 *Src = reinterpret_cast<const UTF8 *>(SrcUTF8.data());
+ const UTF8 *SrcEnd = reinterpret_cast<const UTF8 *>(SrcUTF8.data() + SrcUTF8.size());
+
+ // Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding
+ // as UTF-16 should always require the same amount or less code units than the
+ // UTF-8 encoding. Allocate one extra byte for the null terminator though,
+ // so that someone calling DstUTF16.data() gets a null terminated string.
+ // We resize down later so we don't have to worry that this over allocates.
+ DstUTF16.resize(SrcUTF8.size()+1);
+ UTF16 *Dst = &DstUTF16[0];
+ UTF16 *DstEnd = Dst + DstUTF16.size();
+
+ ConversionResult CR =
+ ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion);
+ assert(CR != targetExhausted);
+
+ if (CR != conversionOK) {
+ DstUTF16.clear();
+ return false;
+ }
+
+ DstUTF16.resize(Dst - &DstUTF16[0]);
+ DstUTF16.push_back(0);
+ DstUTF16.pop_back();
+ return true;
+}
+
+static_assert(sizeof(wchar_t) == 1 || sizeof(wchar_t) == 2 ||
+ sizeof(wchar_t) == 4,
+ "Expected wchar_t to be 1, 2, or 4 bytes");
+
+template <typename TResult>
+static inline bool ConvertUTF8toWideInternal(std::string_view Source,
+ TResult &Result) {
+ // Even in the case of UTF-16, the number of bytes in a UTF-8 string is
+ // at least as large as the number of elements in the resulting wide
+ // string, because surrogate pairs take at least 4 bytes in UTF-8.
+ Result.resize(Source.size() + 1);
+ char *ResultPtr = reinterpret_cast<char *>(&Result[0]);
+ const UTF8 *ErrorPtr;
+ if (!ConvertUTF8toWide(sizeof(wchar_t), Source, ResultPtr, ErrorPtr)) {
+ Result.clear();
+ return false;
+ }
+ Result.resize(reinterpret_cast<wchar_t *>(ResultPtr) - &Result[0]);
+ return true;
+}
+
+bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result) {
+ return ConvertUTF8toWideInternal(Source, Result);
+}
+
+bool ConvertUTF8toWide(const char *Source, std::wstring &Result) {
+ if (!Source) {
+ Result.clear();
+ return true;
+ }
+ return ConvertUTF8toWide(std::string_view(Source), Result);
+}
+
+bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result) {
+ if (sizeof(wchar_t) == 1) {
+ const UTF8 *Start = reinterpret_cast<const UTF8 *>(Source.data());
+ const UTF8 *End =
+ reinterpret_cast<const UTF8 *>(Source.data() + Source.size());
+ if (!isLegalUTF8String(&Start, End))
+ return false;
+ Result.resize(Source.size());
+ memcpy(&Result[0], Source.data(), Source.size());
+ return true;
+ } else if (sizeof(wchar_t) == 2) {
+ return convertUTF16ToUTF8String(
+ std::span<const UTF16>(reinterpret_cast<const UTF16 *>(Source.data()),
+ Source.size()),
+ Result);
+ } else if (sizeof(wchar_t) == 4) {
+ const UTF32 *Start = reinterpret_cast<const UTF32 *>(Source.data());
+ const UTF32 *End =
+ reinterpret_cast<const UTF32 *>(Source.data() + Source.size());
+ Result.resize(UNI_MAX_UTF8_BYTES_PER_CODE_POINT * Source.size());
+ UTF8 *ResultPtr = reinterpret_cast<UTF8 *>(&Result[0]);
+ UTF8 *ResultEnd = reinterpret_cast<UTF8 *>(&Result[0] + Result.size());
+ if (ConvertUTF32toUTF8(&Start, End, &ResultPtr, ResultEnd,
+ strictConversion) == conversionOK) {
+ Result.resize(reinterpret_cast<char *>(ResultPtr) - &Result[0]);
+ return true;
+ } else {
+ Result.clear();
+ return false;
+ }
+ } else {
+ wpi_unreachable(
+ "Control should never reach this point; see static_assert further up");
+ }
+}
+
+} // end namespace wpi
+
diff --git a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
similarity index 85%
rename from wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
index 22ae636..ea89b38 100644
--- a/wpiutil/src/main/native/cpp/llvm/ErrorHandling.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/ErrorHandling.cpp
@@ -1,9 +1,8 @@
//===- lib/Support/ErrorHandling.cpp - Callbacks for errors ---------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,10 +13,10 @@
#include "wpi/ErrorHandling.h"
#include "wpi/SmallVector.h"
+#include "wpi/Errc.h"
#include "wpi/WindowsError.h"
#include "fmt/format.h"
#include <cassert>
-#include <cstdio>
#include <cstdlib>
#include <mutex>
#include <new>
@@ -25,7 +24,6 @@
#ifndef _WIN32
#include <unistd.h>
#endif
-
#if defined(_MSC_VER)
#include <io.h>
#endif
@@ -53,7 +51,7 @@
static std::mutex BadAllocErrorHandlerMutex;
void wpi::install_fatal_error_handler(fatal_error_handler_t handler,
- void *user_data) {
+ void *user_data) {
std::scoped_lock Lock(ErrorHandlerMutex);
assert(!ErrorHandler && "Error handler already registered!\n");
ErrorHandler = handler;
@@ -86,7 +84,7 @@
}
if (handler) {
- handler(handlerData, std::string{Reason}, GenCrashDiag);
+ handler(handlerData, std::string{Reason}.c_str(), GenCrashDiag);
} else {
fmt::print(stderr, "LLVM ERROR: {}\n", Reason);
}
@@ -95,7 +93,7 @@
}
void wpi::install_bad_alloc_error_handler(fatal_error_handler_t handler,
- void *user_data) {
+ void *user_data) {
std::scoped_lock Lock(BadAllocErrorHandlerMutex);
assert(!ErrorHandler && "Bad alloc error handler already registered!\n");
BadAllocErrorHandler = handler;
@@ -126,13 +124,17 @@
// Don't call the normal error handler. It may allocate memory. Directly write
// an OOM to stderr and abort.
- char OOMMessage[] = "LLVM ERROR: out of memory\n";
+ const char *OOMMessage = "LLVM ERROR: out of memory\n";
+ const char *Newline = "\n";
#ifdef _WIN32
- int written = ::_write(2, OOMMessage, strlen(OOMMessage));
+ (void)!::_write(2, OOMMessage, strlen(OOMMessage));
+ (void)!::_write(2, Reason, strlen(Reason));
+ (void)!::_write(2, Newline, strlen(Newline));
#else
- ssize_t written = ::write(2, OOMMessage, strlen(OOMMessage));
+ (void)!::write(2, OOMMessage, strlen(OOMMessage));
+ (void)!::write(2, Reason, strlen(Reason));
+ (void)!::write(2, Newline, strlen(Newline));
#endif
- (void)written;
abort();
}
@@ -142,28 +144,17 @@
wpi::report_bad_alloc_error("Allocation failed");
}
-// Installs new handler that causes crash on allocation failure. It does not
-// need to be called explicitly, if this file is linked to application, because
-// in this case it is called during construction of 'new_handler_installer'.
+// Installs new handler that causes crash on allocation failure. It is called by
+// InitLLVM.
void wpi::install_out_of_memory_new_handler() {
- static bool out_of_memory_new_handler_installed = false;
- if (!out_of_memory_new_handler_installed) {
- std::set_new_handler(out_of_memory_new_handler);
- out_of_memory_new_handler_installed = true;
- }
+ std::new_handler old = std::set_new_handler(out_of_memory_new_handler);
+ (void)old;
+ assert((old == nullptr || old == out_of_memory_new_handler) &&
+ "new-handler already installed");
}
-// Static object that causes installation of 'out_of_memory_new_handler' before
-// execution of 'main'.
-static class NewHandlerInstaller {
-public:
- NewHandlerInstaller() {
- install_out_of_memory_new_handler();
- }
-} new_handler_installer;
-
void wpi::wpi_unreachable_internal(const char *msg, const char *file,
- unsigned line) {
+ unsigned line) {
// This code intentionally doesn't call the ErrorHandler callback, because
// wpi_unreachable is intended to be used to indicate "impossible"
// situations, and not legitimate runtime errors.
@@ -172,7 +163,7 @@
std::fputs("UNREACHABLE executed", stderr);
if (file)
fmt::print(stderr, " at {}:{}", file, line);
- fmt::print(stderr, "{}", "!\n");
+ fmt::print(stderr, "!\n");
abort();
#ifdef LLVM_BUILTIN_UNREACHABLE
// Windows systems and possibly others don't declare abort() to be noreturn,
@@ -183,7 +174,6 @@
#ifdef _WIN32
-#include <system_error>
#include <winerror.h>
// I'd rather not double the line count of the following.
@@ -195,7 +185,10 @@
switch (EV) {
MAP_ERR_TO_COND(ERROR_ACCESS_DENIED, permission_denied);
MAP_ERR_TO_COND(ERROR_ALREADY_EXISTS, file_exists);
+ MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
+ MAP_ERR_TO_COND(ERROR_BAD_PATHNAME, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_BAD_UNIT, no_such_device);
+ MAP_ERR_TO_COND(ERROR_BROKEN_PIPE, broken_pipe);
MAP_ERR_TO_COND(ERROR_BUFFER_OVERFLOW, filename_too_long);
MAP_ERR_TO_COND(ERROR_BUSY, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_BUSY_DRIVE, device_or_resource_busy);
@@ -217,18 +210,20 @@
MAP_ERR_TO_COND(ERROR_INVALID_FUNCTION, function_not_supported);
MAP_ERR_TO_COND(ERROR_INVALID_HANDLE, invalid_argument);
MAP_ERR_TO_COND(ERROR_INVALID_NAME, invalid_argument);
+ MAP_ERR_TO_COND(ERROR_INVALID_PARAMETER, invalid_argument);
MAP_ERR_TO_COND(ERROR_LOCK_VIOLATION, no_lock_available);
MAP_ERR_TO_COND(ERROR_LOCKED, no_lock_available);
MAP_ERR_TO_COND(ERROR_NEGATIVE_SEEK, invalid_argument);
MAP_ERR_TO_COND(ERROR_NOACCESS, permission_denied);
MAP_ERR_TO_COND(ERROR_NOT_ENOUGH_MEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_NOT_READY, resource_unavailable_try_again);
+ MAP_ERR_TO_COND(ERROR_NOT_SUPPORTED, not_supported);
MAP_ERR_TO_COND(ERROR_OPEN_FAILED, io_error);
MAP_ERR_TO_COND(ERROR_OPEN_FILES, device_or_resource_busy);
MAP_ERR_TO_COND(ERROR_OUTOFMEMORY, not_enough_memory);
MAP_ERR_TO_COND(ERROR_PATH_NOT_FOUND, no_such_file_or_directory);
- MAP_ERR_TO_COND(ERROR_BAD_NETPATH, no_such_file_or_directory);
MAP_ERR_TO_COND(ERROR_READ_FAULT, io_error);
+ MAP_ERR_TO_COND(ERROR_REPARSE_TAG_INVALID, invalid_argument);
MAP_ERR_TO_COND(ERROR_RETRY, resource_unavailable_try_again);
MAP_ERR_TO_COND(ERROR_SEEK, io_error);
MAP_ERR_TO_COND(ERROR_SHARING_VIOLATION, permission_denied);
diff --git a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
similarity index 82%
rename from wpiutil/src/main/native/cpp/llvm/Hashing.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
index e916751..a719d3f 100644
--- a/wpiutil/src/main/native/cpp/llvm/Hashing.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Hashing.cpp
@@ -1,9 +1,8 @@
//===-------------- lib/Support/Hashing.cpp -------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
new file mode 100644
index 0000000..e2c662c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemAlloc.cpp
@@ -0,0 +1,35 @@
+//===- MemAlloc.cpp - Memory allocation functions -------------------------===//
+//
+// 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/MemAlloc.h"
+#include <new>
+
+// These are out of line to have __cpp_aligned_new not affect ABI.
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+wpi::allocate_buffer(size_t Size, size_t Alignment) {
+ return ::operator new(Size
+#ifdef __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
+
+void wpi::deallocate_buffer(void *Ptr, size_t Size, size_t Alignment) {
+ ::operator delete(Ptr
+#ifdef __cpp_sized_deallocation
+ ,
+ Size
+#endif
+#ifdef __cpp_aligned_new
+ ,
+ std::align_val_t(Alignment)
+#endif
+ );
+}
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
new file mode 100644
index 0000000..5beeb38
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/MemoryBuffer.cpp
@@ -0,0 +1,522 @@
+// 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.
+
+//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/MemoryBuffer.h"
+
+#ifdef _MSC_VER
+// no matching operator delete
+#pragma warning(disable : 4291)
+#endif
+
+#ifdef _WIN32
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#include <windows.h> // NOLINT(build/include_order)
+
+#endif
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef _MSC_VER
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <new>
+#include <system_error>
+
+#include "wpi/Errc.h"
+#include "wpi/Errno.h"
+#include "wpi/MappedFileRegion.h"
+#include "wpi/MathExtras.h"
+#include "wpi/SmallVector.h"
+#include "wpi/SmallVectorMemoryBuffer.h"
+#include "wpi/fs.h"
+
+#ifdef _WIN32
+#include "wpi/WindowsError.h"
+#endif
+
+using namespace wpi;
+
+//===----------------------------------------------------------------------===//
+// MemoryBuffer implementation itself.
+//===----------------------------------------------------------------------===//
+
+MemoryBuffer::~MemoryBuffer() {}
+
+/// init - Initialize this MemoryBuffer as a reference to externally allocated
+/// memory.
+void MemoryBuffer::Init(const uint8_t* bufStart, const uint8_t* bufEnd) {
+ m_bufferStart = bufStart;
+ m_bufferEnd = bufEnd;
+}
+
+//===----------------------------------------------------------------------===//
+// MemoryBufferMem implementation.
+//===----------------------------------------------------------------------===//
+
+/// CopyStringRef - Copies contents of a StringRef into a block of memory and
+/// null-terminates it.
+static void CopyStringView(uint8_t* memory, std::string_view data) {
+ if (!data.empty()) {
+ std::memcpy(memory, data.data(), data.size());
+ }
+ memory[data.size()] = 0; // Null terminate string.
+}
+
+namespace {
+struct NamedBufferAlloc {
+ std::string_view name;
+ explicit NamedBufferAlloc(std::string_view name) : name(name) {}
+};
+} // namespace
+
+void* operator new(size_t N, NamedBufferAlloc alloc) {
+ uint8_t* mem = static_cast<uint8_t*>(operator new(N + alloc.name.size() + 1));
+ CopyStringView(mem + N, alloc.name);
+ return mem;
+}
+
+namespace {
+/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
+template <typename MB>
+class MemoryBufferMem : public MB {
+ public:
+ explicit MemoryBufferMem(std::span<const uint8_t> inputData) {
+ MemoryBuffer::Init(inputData.data(), inputData.data() + inputData.size());
+ }
+
+ /// Disable sized deallocation for MemoryBufferMem, because it has
+ /// tail-allocated data.
+ void operator delete(void* p) { ::operator delete(p); } // NOLINT
+
+ std::string_view GetBufferIdentifier() const override {
+ // The name is stored after the class itself.
+ return std::string_view(reinterpret_cast<const char*>(this + 1));
+ }
+
+ MemoryBuffer::BufferKind GetBufferKind() const override {
+ return MemoryBuffer::MemoryBuffer_Malloc;
+ }
+};
+} // namespace
+
+template <typename MB>
+static std::unique_ptr<MB> GetFileAux(std::string_view filename,
+ std::error_code& ec, int64_t fileSize,
+ uint64_t mapSize, uint64_t offset);
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(
+ std::span<const uint8_t> inputData, std::string_view bufferName) {
+ auto* ret = new (NamedBufferAlloc(bufferName))
+ MemoryBufferMem<MemoryBuffer>(inputData);
+ return std::unique_ptr<MemoryBuffer>(ret);
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBuffer(MemoryBufferRef ref) {
+ return std::unique_ptr<MemoryBuffer>(
+ GetMemBuffer(ref.GetBuffer(), ref.GetBufferIdentifier()));
+}
+
+static std::unique_ptr<WritableMemoryBuffer> GetMemBufferCopyImpl(
+ std::span<const uint8_t> inputData, std::string_view bufferName,
+ std::error_code& ec) {
+ auto buf =
+ WritableMemoryBuffer::GetNewUninitMemBuffer(inputData.size(), bufferName);
+ if (!buf) {
+ ec = make_error_code(errc::not_enough_memory);
+ return nullptr;
+ }
+ std::memcpy(buf->begin(), inputData.data(), inputData.size());
+ return buf;
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetMemBufferCopy(
+ std::span<const uint8_t> inputData, std::string_view bufferName) {
+ std::error_code ec;
+ return GetMemBufferCopyImpl(inputData, bufferName, ec);
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileSlice(
+ std::string_view filePath, std::error_code& ec, uint64_t mapSize,
+ uint64_t offset) {
+ return GetFileAux<MemoryBuffer>(filePath, ec, -1, mapSize, offset);
+}
+
+//===----------------------------------------------------------------------===//
+// MemoryBuffer::getFile implementation.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+template <typename MB>
+constexpr auto kMapMode = MappedFileRegion::kReadOnly;
+template <>
+constexpr auto kMapMode<MemoryBuffer> = MappedFileRegion::kReadOnly;
+template <>
+constexpr auto kMapMode<WritableMemoryBuffer> = MappedFileRegion::kPriv;
+template <>
+constexpr auto kMapMode<WriteThroughMemoryBuffer> =
+ MappedFileRegion::kReadWrite;
+
+/// Memory maps a file descriptor using MappedFileRegion.
+///
+/// This handles converting the offset into a legal offset on the platform.
+template <typename MB>
+class MemoryBufferMMapFile : public MB {
+ MappedFileRegion m_mfr;
+
+ static uint64_t getLegalMapOffset(uint64_t offset) {
+ return offset & ~(MappedFileRegion::GetAlignment() - 1);
+ }
+
+ static uint64_t getLegalMapSize(uint64_t len, uint64_t offset) {
+ return len + (offset - getLegalMapOffset(offset));
+ }
+
+ const uint8_t* getStart(uint64_t len, uint64_t offset) {
+ return m_mfr.const_data() + (offset - getLegalMapOffset(offset));
+ }
+
+ public:
+ MemoryBufferMMapFile(fs::file_t f, uint64_t len, uint64_t offset,
+ std::error_code& ec)
+ : m_mfr(f, getLegalMapSize(len, offset), getLegalMapOffset(offset),
+ kMapMode<MB>, ec) {
+ if (!ec) {
+ const uint8_t* Start = getStart(len, offset);
+ MemoryBuffer::Init(Start, Start + len);
+ }
+ }
+
+ /// Disable sized deallocation for MemoryBufferMMapFile, because it has
+ /// tail-allocated data.
+ void operator delete(void* p) { ::operator delete(p); } // NOLINT
+
+ std::string_view GetBufferIdentifier() const override {
+ // The name is stored after the class itself.
+ return std::string_view(reinterpret_cast<const char*>(this + 1));
+ }
+
+ MemoryBuffer::BufferKind GetBufferKind() const override {
+ return MemoryBuffer::MemoryBuffer_MMap;
+ }
+};
+} // namespace
+
+static std::unique_ptr<WritableMemoryBuffer> GetMemoryBufferForStream(
+ fs::file_t f, std::string_view bufferName, std::error_code& ec) {
+ constexpr size_t ChunkSize = 4096 * 4;
+ SmallVector<uint8_t, ChunkSize> buffer;
+#ifdef _WIN32
+ DWORD readBytes;
+#else
+ ssize_t readBytes;
+#endif
+ // Read into Buffer until we hit EOF.
+ do {
+ buffer.resize_for_overwrite(buffer.size() + ChunkSize);
+#ifdef _WIN32
+ if (!ReadFile(f, buffer.end(), ChunkSize, &readBytes, nullptr)) {
+ ec = mapWindowsError(GetLastError());
+ return nullptr;
+ }
+#else
+ readBytes = sys::RetryAfterSignal(-1, ::read, f, buffer.end(), ChunkSize);
+ if (readBytes == -1) {
+ ec = std::error_code(errno, std::generic_category());
+ return nullptr;
+ }
+#endif
+ } while (readBytes != 0);
+
+ return GetMemBufferCopyImpl(buffer, bufferName, ec);
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFile(std::string_view filename,
+ std::error_code& ec,
+ int64_t fileSize) {
+ return GetFileAux<MemoryBuffer>(filename, ec, fileSize, fileSize, 0);
+}
+
+template <typename MB>
+static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
+ std::string_view filename,
+ std::error_code& ec,
+ uint64_t fileSize, uint64_t mapSize,
+ int64_t offset);
+
+template <typename MB>
+static std::unique_ptr<MB> GetFileAux(std::string_view filename,
+ std::error_code& ec, int64_t fileSize,
+ uint64_t mapSize, uint64_t offset) {
+ fs::file_t F = fs::OpenFileForRead(filename, ec, fs::OF_None);
+ if (ec) {
+ return nullptr;
+ }
+
+ auto Ret = GetOpenFileImpl<MB>(F, filename, ec, fileSize, mapSize, offset);
+ fs::CloseFile(F);
+ return Ret;
+}
+
+std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFile(
+ std::string_view filename, std::error_code& ec, int64_t fileSize) {
+ return GetFileAux<WritableMemoryBuffer>(filename, ec, fileSize, fileSize, 0);
+}
+
+std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetFileSlice(
+ std::string_view filename, std::error_code& ec, uint64_t mapSize,
+ uint64_t offset) {
+ return GetFileAux<WritableMemoryBuffer>(filename, ec, -1, mapSize, offset);
+}
+
+std::unique_ptr<WritableMemoryBuffer>
+WritableMemoryBuffer::GetNewUninitMemBuffer(size_t size,
+ std::string_view bufferName) {
+ using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
+ // Allocate space for the MemoryBuffer, the data and the name. It is important
+ // that MemoryBuffer and data are aligned so PointerIntPair works with them.
+ // TODO: Is 16-byte alignment enough? We copy small object files with large
+ // alignment expectations into this buffer.
+ size_t alignedStringLen =
+ alignTo(sizeof(MemBuffer) + bufferName.size() + 1, 16);
+ size_t realLen = alignedStringLen + size + 1;
+ uint8_t* mem = static_cast<uint8_t*>(operator new(realLen, std::nothrow));
+ if (!mem) {
+ return nullptr;
+ }
+
+ // The name is stored after the class itself.
+ CopyStringView(mem + sizeof(MemBuffer), bufferName);
+
+ // The buffer begins after the name and must be aligned.
+ uint8_t* buf = mem + alignedStringLen;
+ buf[size] = 0; // Null terminate buffer.
+
+ auto* ret = new (mem) MemBuffer({buf, size});
+ return std::unique_ptr<WritableMemoryBuffer>(ret);
+}
+
+std::unique_ptr<WritableMemoryBuffer> WritableMemoryBuffer::GetNewMemBuffer(
+ size_t size, std::string_view bufferName) {
+ auto sb = WritableMemoryBuffer::GetNewUninitMemBuffer(size, bufferName);
+ if (!sb) {
+ return nullptr;
+ }
+ std::memset(sb->begin(), 0, size);
+ return sb;
+}
+
+static std::unique_ptr<WriteThroughMemoryBuffer> GetReadWriteFile(
+ std::string_view filename, std::error_code& ec, uint64_t fileSize,
+ uint64_t mapSize, uint64_t offset) {
+ fs::file_t f =
+ fs::OpenFileForReadWrite(filename, ec, fs::CD_OpenExisting, fs::OF_None);
+ if (ec) {
+ return nullptr;
+ }
+
+ // Default is to map the full file.
+ if (mapSize == uint64_t(-1)) {
+ // If we don't know the file size, use fstat to find out. fstat on an open
+ // file descriptor is cheaper than stat on a random path.
+ if (fileSize == uint64_t(-1)) {
+#ifdef _WIN32
+ // If this not a file or a block device (e.g. it's a named pipe
+ // or character device), we can't mmap it, so error out.
+ if (GetFileType(f) != FILE_TYPE_DISK) {
+ ec = std::error_code(errno, std::generic_category());
+ return nullptr;
+ }
+
+ LARGE_INTEGER fileSizeWin;
+ if (!GetFileSizeEx(f, &fileSizeWin)) {
+ ec = wpi::mapWindowsError(GetLastError());
+ return nullptr;
+ }
+ fileSize = fileSizeWin.QuadPart;
+#else
+ struct stat status;
+ if (fstat(f, &status) < 0) {
+ ec = std::error_code(errno, std::generic_category());
+ return nullptr;
+ }
+
+ // If this not a file or a block device (e.g. it's a named pipe
+ // or character device), we can't mmap it, so error out.
+ if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
+ ec = make_error_code(errc::invalid_argument);
+ return nullptr;
+ }
+
+ fileSize = status.st_size;
+#endif
+ }
+ mapSize = fileSize;
+ }
+
+ std::unique_ptr<WriteThroughMemoryBuffer> result(new (NamedBufferAlloc(
+ filename)) MemoryBufferMMapFile<WriteThroughMemoryBuffer>(f, mapSize,
+ offset, ec));
+ if (ec) {
+ return nullptr;
+ }
+ return result;
+}
+
+std::unique_ptr<WriteThroughMemoryBuffer> WriteThroughMemoryBuffer::GetFile(
+ std::string_view filename, std::error_code& ec, int64_t fileSize) {
+ return GetReadWriteFile(filename, ec, fileSize, fileSize, 0);
+}
+
+/// Map a subrange of the specified file as a WritableMemoryBuffer.
+std::unique_ptr<WriteThroughMemoryBuffer>
+WriteThroughMemoryBuffer::GetFileSlice(std::string_view filename,
+ std::error_code& ec, uint64_t mapSize,
+ uint64_t offset) {
+ return GetReadWriteFile(filename, ec, -1, mapSize, offset);
+}
+
+template <typename MB>
+static std::unique_ptr<MB> GetOpenFileImpl(fs::file_t f,
+ std::string_view filename,
+ std::error_code& ec,
+ uint64_t fileSize, uint64_t mapSize,
+ int64_t offset) {
+ // Default is to map the full file.
+ if (mapSize == uint64_t(-1)) {
+ // If we don't know the file size, use fstat to find out. fstat on an open
+ // file descriptor is cheaper than stat on a random path.
+ if (fileSize == uint64_t(-1)) {
+#ifdef _WIN32
+ // If this not a file or a block device (e.g. it's a named pipe
+ // or character device), we can't trust the size. Create the memory
+ // buffer by copying off the stream.
+ LARGE_INTEGER fileSizeWin;
+ if (GetFileType(f) != FILE_TYPE_DISK || !GetFileSizeEx(f, &fileSizeWin)) {
+ return GetMemoryBufferForStream(f, filename, ec);
+ }
+ fileSize = fileSizeWin.QuadPart;
+#else
+ struct stat status;
+ if (fstat(f, &status) < 0) {
+ ec = std::error_code(errno, std::generic_category());
+ return nullptr;
+ }
+
+ // If this not a file or a block device (e.g. it's a named pipe
+ // or character device), we can't trust the size. Create the memory
+ // buffer by copying off the stream.
+ if (status.st_mode != S_IFREG && status.st_mode != S_IFBLK) {
+ return GetMemoryBufferForStream(f, filename, ec);
+ }
+
+ fileSize = status.st_size;
+#endif
+ }
+ mapSize = fileSize;
+ }
+
+ // Don't use mmap for small files
+ if (mapSize >= 4 * 4096) {
+ std::unique_ptr<MB> result(new (NamedBufferAlloc(
+ filename)) MemoryBufferMMapFile<MB>(f, mapSize, offset, ec));
+ if (!ec) {
+ return result;
+ }
+ }
+
+ auto buf = WritableMemoryBuffer::GetNewUninitMemBuffer(mapSize, filename);
+ if (!buf) {
+ // Failed to create a buffer. The only way it can fail is if
+ // new(std::nothrow) returns 0.
+ ec = make_error_code(errc::not_enough_memory);
+ return nullptr;
+ }
+
+ uint8_t* bufPtr = buf.get()->begin();
+
+ size_t bytesLeft = mapSize;
+ while (bytesLeft) {
+#ifdef _WIN32
+ LARGE_INTEGER offsetWin;
+ offsetWin.QuadPart = offset;
+ DWORD numRead;
+ if (!SetFilePointerEx(f, offsetWin, nullptr, FILE_BEGIN) ||
+ !ReadFile(f, bufPtr, bytesLeft, &numRead, nullptr)) {
+ ec = mapWindowsError(GetLastError());
+ return nullptr;
+ }
+// TODO
+#else
+ ssize_t numRead = sys::RetryAfterSignal(-1, ::pread, f, bufPtr, bytesLeft,
+ mapSize - bytesLeft + offset);
+ if (numRead == -1) {
+ // Error while reading.
+ ec = std::error_code(errno, std::generic_category());
+ return nullptr;
+ }
+#endif
+ if (numRead == 0) {
+ std::memset(bufPtr, 0, bytesLeft); // zero-initialize rest of the buffer.
+ break;
+ }
+ bytesLeft -= numRead;
+ bufPtr += numRead;
+ }
+
+ return buf;
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFile(
+ fs::file_t f, std::string_view filename, std::error_code& ec,
+ uint64_t fileSize) {
+ return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, fileSize, fileSize, 0);
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetOpenFileSlice(
+ fs::file_t f, std::string_view filename, std::error_code& ec,
+ uint64_t mapSize, int64_t offset) {
+ assert(mapSize != uint64_t(-1));
+ return GetOpenFileImpl<MemoryBuffer>(f, filename, ec, -1, mapSize, offset);
+}
+
+std::unique_ptr<MemoryBuffer> MemoryBuffer::GetFileAsStream(
+ std::string_view filename, std::error_code& ec) {
+ fs::file_t f = fs::OpenFileForRead(filename, ec, fs::OF_None);
+ if (ec) {
+ return nullptr;
+ }
+ std::unique_ptr<MemoryBuffer> ret = GetMemoryBufferForStream(f, filename, ec);
+ fs::CloseFile(f);
+ return ret;
+}
+
+MemoryBufferRef MemoryBuffer::GetMemBufferRef() const {
+ return MemoryBufferRef(GetBuffer(), GetBufferIdentifier());
+}
+
+SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() {}
diff --git a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
similarity index 97%
rename from wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
index 1b33f4c..f356728 100644
--- a/wpiutil/src/main/native/cpp/llvm/SmallPtrSet.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallPtrSet.cpp
@@ -1,9 +1,8 @@
//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -16,7 +15,6 @@
#include "wpi/DenseMapInfo.h"
#include "wpi/MathExtras.h"
#include "wpi/MemAlloc.h"
-#include "wpi/ErrorHandling.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
@@ -60,6 +58,7 @@
else
++NumNonEmpty; // Track density.
*Bucket = Ptr;
+ incrementEpoch();
return std::make_pair(Bucket, true);
}
diff --git a/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
new file mode 100644
index 0000000..04f4e06
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/SmallVector.cpp
@@ -0,0 +1,129 @@
+//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
+//
+// 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 implements the SmallVector class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "wpi/SmallVector.h"
+#include "wpi/MemAlloc.h"
+#include <cstdint>
+#ifdef LLVM_ENABLE_EXCEPTIONS
+#include <stdexcept>
+#endif
+using namespace wpi;
+
+// Check that no bytes are wasted and everything is well-aligned.
+namespace {
+// These structures may cause binary compat warnings on AIX. Suppress the
+// warning since we are only using these types for the static assertions below.
+#if defined(_AIX)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Waix-compat"
+#endif
+struct Struct16B {
+ alignas(16) void *X;
+};
+struct Struct32B {
+ alignas(32) void *X;
+};
+#if defined(_AIX)
+#pragma GCC diagnostic pop
+#endif
+}
+static_assert(sizeof(SmallVector<void *, 0>) ==
+ sizeof(unsigned) * 2 + sizeof(void *),
+ "wasted space in SmallVector size 0");
+static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+ "wrong alignment for 16-byte aligned T");
+static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+ "wrong alignment for 32-byte aligned T");
+static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
+ "missing padding for 16-byte aligned T");
+static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
+ "missing padding for 32-byte aligned T");
+static_assert(sizeof(SmallVector<void *, 1>) ==
+ sizeof(unsigned) * 2 + sizeof(void *) * 2,
+ "wasted space in SmallVector size 1");
+
+/// Report that MinSize doesn't fit into this vector's size type. Throws
+/// std::length_error or calls report_fatal_error.
+[[noreturn]] static void report_size_overflow(size_t MinSize, size_t MaxSize);
+static void report_size_overflow(size_t MinSize, size_t MaxSize) {
+ std::string Reason = "SmallVector unable to grow. Requested capacity (" +
+ std::to_string(MinSize) +
+ ") is larger than maximum value for size type (" +
+ std::to_string(MaxSize) + ")";
+#ifdef LLVM_ENABLE_EXCEPTIONS
+ throw std::length_error(Reason);
+#else
+ report_fatal_error(Reason);
+#endif
+}
+
+/// Report that this vector is already at maximum capacity. Throws
+/// std::length_error or calls report_fatal_error.
+[[noreturn]] static void report_at_maximum_capacity(size_t MaxSize);
+static void report_at_maximum_capacity(size_t MaxSize) {
+ std::string Reason =
+ "SmallVector capacity unable to grow. Already at maximum size " +
+ std::to_string(MaxSize);
+#ifdef LLVM_ENABLE_EXCEPTIONS
+ throw std::length_error(Reason);
+#else
+ report_fatal_error(Reason);
+#endif
+}
+
+// Note: Moving this function into the header may cause performance regression.
+static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
+ constexpr size_t MaxSize = std::numeric_limits<unsigned>::max();
+
+ // Ensure we can fit the new capacity.
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (MinSize > MaxSize)
+ report_size_overflow(MinSize, MaxSize);
+
+ // Ensure we can meet the guarantee of space for at least one more element.
+ // The above check alone will not catch the case where grow is called with a
+ // default MinSize of 0, but the current capacity cannot be increased.
+ // This is only going to be applicable when the capacity is 32 bit.
+ if (OldCapacity == MaxSize)
+ report_at_maximum_capacity(MaxSize);
+
+ // 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);
+}
+
+// Note: Moving this function into the header may cause performance regression.
+void *SmallVectorBase::mallocForGrow(size_t MinSize, size_t TSize,
+ size_t &NewCapacity) {
+ NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
+ return wpi::safe_malloc(NewCapacity * TSize);
+}
+
+// Note: Moving this function into the header may cause performance regression.
+void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSize,
+ size_t TSize) {
+ size_t NewCapacity = getNewCapacity(MinSize, TSize, this->capacity());
+ void *NewElts;
+ if (BeginX == FirstEl) {
+ NewElts = safe_malloc(NewCapacity * TSize);
+
+ // 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);
+ }
+
+ this->BeginX = NewElts;
+ this->Capacity = NewCapacity;
+}
diff --git a/wpiutil/src/main/native/cpp/StringExtras.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
similarity index 83%
rename from wpiutil/src/main/native/cpp/StringExtras.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
index 968ffc3..9307724 100644
--- a/wpiutil/src/main/native/cpp/StringExtras.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringExtras.cpp
@@ -358,3 +358,85 @@
}
return val;
}
+
+std::pair<std::string_view, std::string_view> wpi::UnescapeCString(
+ std::string_view str, wpi::SmallVectorImpl<char>& buf) {
+ buf.clear();
+ buf.reserve(str.size());
+ const char* s = str.data();
+ const char* end = str.data() + str.size();
+ for (; s != end && *s != '"'; ++s) {
+ if (*s != '\\' || (s + 1) >= end) {
+ buf.push_back(*s);
+ continue;
+ }
+ switch (*++s) {
+ case 'a':
+ buf.push_back('\a');
+ break;
+ case 'b':
+ buf.push_back('\b');
+ break;
+ case 'f':
+ buf.push_back('\f');
+ break;
+ case 'n':
+ buf.push_back('\n');
+ break;
+ case 'r':
+ buf.push_back('\r');
+ break;
+ case 't':
+ buf.push_back('\t');
+ break;
+ case 'v':
+ buf.push_back('\v');
+ break;
+ case 'x': {
+ // hex escape
+ if ((s + 1) >= end || !isxdigit(*(s + 1))) {
+ buf.push_back('x'); // treat it like a unknown escape
+ break;
+ }
+ unsigned int ch = wpi::hexDigitValue(*++s);
+ if ((s + 1) < end && std::isxdigit(*(s + 1))) {
+ ch <<= 4;
+ ch |= wpi::hexDigitValue(*++s);
+ }
+ buf.push_back(static_cast<char>(ch));
+ break;
+ }
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ // octal escape
+ unsigned int ch = *s - '0';
+ if ((s + 1) < end && wpi::isDigit(*(s + 1))) {
+ ch <<= 3;
+ ch |= *++s - '0';
+ }
+ if ((s + 1) < end && wpi::isDigit(*(s + 1))) {
+ ch <<= 3;
+ ch |= *++s - '0';
+ }
+ buf.push_back(static_cast<char>(ch));
+ break;
+ }
+ default:
+ buf.push_back(*s);
+ break;
+ }
+ }
+ if (s == end) {
+ return {{buf.data(), buf.size()}, {}};
+ } else {
+ return {{buf.data(), buf.size()}, {s, static_cast<size_t>(end - s)}};
+ }
+}
diff --git a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
similarity index 78%
rename from wpiutil/src/main/native/cpp/llvm/StringMap.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
index 768801d..2405f2f 100644
--- a/wpiutil/src/main/native/cpp/llvm/StringMap.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/StringMap.cpp
@@ -1,9 +1,8 @@
//===--- StringMap.cpp - String Hash table map implementation -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -12,28 +11,11 @@
//===----------------------------------------------------------------------===//
#include "wpi/StringMap.h"
-#include "wpi/StringExtras.h"
-#include "wpi/Compiler.h"
+#include "wpi/DJB.h"
#include "wpi/MathExtras.h"
-#include <cassert>
using namespace wpi;
-/// HashString - Hash function for strings.
-///
-/// This is the Bernstein hash function.
-//
-// FIXME: Investigate whether a modified bernstein hash function performs
-// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
-// X*33+c -> X*33^c
-static inline unsigned HashString(std::string_view str,
- unsigned result = 0) noexcept {
- for (std::string_view::size_type i = 0, e = str.size(); i != e; ++i) {
- result = result * 33 + static_cast<unsigned char>(str[i]);
- }
- return result;
-}
-
/// 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) {
@@ -65,23 +47,22 @@
}
void StringMapImpl::init(unsigned InitSize) {
- assert((InitSize & (InitSize-1)) == 0 &&
+ assert((InitSize & (InitSize - 1)) == 0 &&
"Init Size must be a power of 2 or zero!");
unsigned NewNumBuckets = InitSize ? InitSize : 16;
NumItems = 0;
NumTombstones = 0;
- TheTable = static_cast<StringMapEntryBase **>(
- safe_calloc(NewNumBuckets+1,
- sizeof(StringMapEntryBase **) + sizeof(unsigned)));
+ TheTable = static_cast<StringMapEntryBase **>(safe_calloc(
+ NewNumBuckets + 1, sizeof(StringMapEntryBase **) + sizeof(unsigned)));
// 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;
+ TheTable[NumBuckets] = (StringMapEntryBase *)2;
}
/// LookupBucketFor - Look up the bucket that the specified string should end
@@ -91,12 +72,12 @@
/// of the string.
unsigned StringMapImpl::LookupBucketFor(std::string_view Name) {
unsigned HTSize = NumBuckets;
- if (HTSize == 0) { // Hash table unallocated so far?
+ if (HTSize == 0) { // Hash table unallocated so far?
init(16);
HTSize = NumBuckets;
}
- unsigned FullHashValue = HashString(Name);
- unsigned BucketNo = FullHashValue & (HTSize-1);
+ unsigned FullHashValue = djbHash(Name, 0);
+ unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -118,7 +99,8 @@
if (BucketItem == getTombstoneVal()) {
// Skip over tombstones. However, remember the first one we see.
- if (FirstTombstone == -1) FirstTombstone = BucketNo;
+ if (FirstTombstone == -1)
+ FirstTombstone = BucketNo;
} else if (LLVM_LIKELY(HashTable[BucketNo] == FullHashValue)) {
// If the full hash value matches, check deeply for a match. The common
// case here is that we are only looking at the buckets (for item info
@@ -127,7 +109,7 @@
// Do the comparison like this because Name isn't necessarily
// null-terminated!
- char *ItemStr = (char*)BucketItem+ItemSize;
+ char *ItemStr = (char *)BucketItem + ItemSize;
if (Name == std::string_view(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -135,7 +117,7 @@
}
// Okay, we didn't find the item. Probe to the next bucket.
- BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+ BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
@@ -148,9 +130,10 @@
/// This does not modify the map.
int StringMapImpl::FindKey(std::string_view Key) const {
unsigned HTSize = NumBuckets;
- if (HTSize == 0) return -1; // Really empty table?
- unsigned FullHashValue = HashString(Key);
- unsigned BucketNo = FullHashValue & (HTSize-1);
+ if (HTSize == 0)
+ return -1; // Really empty table?
+ unsigned FullHashValue = djbHash(Key, 0);
+ unsigned BucketNo = FullHashValue & (HTSize - 1);
unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1);
unsigned ProbeAmt = 1;
@@ -170,7 +153,7 @@
// Do the comparison like this because NameStart isn't necessarily
// null-terminated!
- char *ItemStr = (char*)BucketItem+ItemSize;
+ char *ItemStr = (char *)BucketItem + ItemSize;
if (Key == std::string_view(ItemStr, BucketItem->getKeyLength())) {
// We found a match!
return BucketNo;
@@ -178,7 +161,7 @@
}
// Okay, we didn't find the item. Probe to the next bucket.
- BucketNo = (BucketNo+ProbeAmt) & (HTSize-1);
+ BucketNo = (BucketNo + ProbeAmt) & (HTSize - 1);
// Use quadratic probing, it has fewer clumping artifacts than linear
// probing and has good cache behavior in the common case.
@@ -189,7 +172,7 @@
/// RemoveKey - Remove the specified StringMapEntry from the table, but do not
/// delete it. This aborts if the value isn't in the table.
void StringMapImpl::RemoveKey(StringMapEntryBase *V) {
- const char *VStr = (char*)V + ItemSize;
+ const char *VStr = (char *)V + ItemSize;
StringMapEntryBase *V2 = RemoveKey(std::string_view(VStr, V->getKeyLength()));
(void)V2;
assert(V == V2 && "Didn't find key?");
@@ -199,7 +182,8 @@
/// table, returning it. If the key is not in the table, this returns null.
StringMapEntryBase *StringMapImpl::RemoveKey(std::string_view Key) {
int Bucket = FindKey(Key);
- if (Bucket == -1) return nullptr;
+ if (Bucket == -1)
+ return nullptr;
StringMapEntryBase *Result = TheTable[Bucket];
TheTable[Bucket] = getTombstoneVal();
@@ -220,7 +204,7 @@
// the buckets are empty (meaning that many are filled with tombstones),
// grow/rehash the table.
if (LLVM_UNLIKELY(NumItems * 4 > NumBuckets * 3)) {
- NewSize = NumBuckets*2;
+ NewSize = NumBuckets * 2;
} else if (LLVM_UNLIKELY(NumBuckets - (NumItems + NumTombstones) <=
NumBuckets / 8)) {
NewSize = NumBuckets;
@@ -231,11 +215,11 @@
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)));
+ auto NewTableArray = static_cast<StringMapEntryBase **>(safe_calloc(
+ NewSize + 1, sizeof(StringMapEntryBase *) + sizeof(unsigned)));
unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1);
- NewTableArray[NewSize] = (StringMapEntryBase*)2;
+ NewTableArray[NewSize] = (StringMapEntryBase *)2;
// 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.
@@ -244,10 +228,10 @@
if (Bucket && Bucket != getTombstoneVal()) {
// Fast case, bucket available.
unsigned FullHash = HashTable[I];
- unsigned NewBucket = FullHash & (NewSize-1);
+ unsigned NewBucket = FullHash & (NewSize - 1);
if (!NewTableArray[NewBucket]) {
- NewTableArray[FullHash & (NewSize-1)] = Bucket;
- NewHashArray[FullHash & (NewSize-1)] = FullHash;
+ NewTableArray[FullHash & (NewSize - 1)] = Bucket;
+ NewHashArray[FullHash & (NewSize - 1)] = FullHash;
if (I == BucketNo)
NewBucketNo = NewBucket;
continue;
@@ -256,7 +240,7 @@
// Otherwise probe for a spot.
unsigned ProbeSize = 1;
do {
- NewBucket = (NewBucket + ProbeSize++) & (NewSize-1);
+ NewBucket = (NewBucket + ProbeSize++) & (NewSize - 1);
} while (NewTableArray[NewBucket]);
// Finally found a slot. Fill it in.
diff --git a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
similarity index 82%
rename from wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
index 7307337..01200e2 100644
--- a/wpiutil/src/main/native/cpp/llvm/Windows/WindowsSupport.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/Windows/WindowsSupport.h
@@ -1,9 +1,8 @@
//===- WindowsSupport.h - Common Windows Include File -----------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -19,8 +18,8 @@
//=== is guaranteed to work on *all* Win32 variants.
//===----------------------------------------------------------------------===//
-#ifndef LLVM_SUPPORT_WINDOWSSUPPORT_H
-#define LLVM_SUPPORT_WINDOWSSUPPORT_H
+#ifndef WPIUTIL_WPI_WINDOWSSUPPORT_H
+#define WPIUTIL_WPI_WINDOWSSUPPORT_H
// mingw-w64 tends to define it as 0x0502 in its headers.
#undef _WIN32_WINNT
@@ -38,10 +37,10 @@
#include "wpi/StringExtras.h"
#include "wpi/Chrono.h"
#include "wpi/Compiler.h"
+#include "wpi/ErrorHandling.h"
#include "wpi/VersionTuple.h"
#include <cassert>
#include <string>
-#include <string_view>
#include <system_error>
#define WIN32_NO_STATUS
#include <windows.h>
@@ -49,6 +48,9 @@
#include <winternl.h>
#include <ntstatus.h>
+// Must be included after windows.h
+#include <wincrypt.h>
+
namespace wpi {
/// Returns the Windows version as Major.Minor.0.BuildNumber. Uses
@@ -81,23 +83,19 @@
return GetWindowsOSVersion() >= wpi::VersionTuple(6, 2, 0, 0);
}
-inline bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix) {
- if (!ErrMsg)
- return true;
- char *buffer = NULL;
- DWORD LastError = GetLastError();
- DWORD R = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM |
- FORMAT_MESSAGE_MAX_WIDTH_MASK,
- NULL, LastError, 0, (LPSTR)&buffer, 1, NULL);
- if (R)
- *ErrMsg = prefix + ": " + buffer;
- else
- *ErrMsg = prefix + ": Unknown error";
- *ErrMsg += " (0x" + wpi::utohexstr(LastError) + ")";
+/// 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
+/// be useful for working around certain kernel bugs.
+wpi::VersionTuple GetWindowsOSVersion();
- LocalFree(buffer);
- return R != 0;
+bool MakeErrMsg(std::string *ErrMsg, const std::string &prefix);
+
+// Include GetLastError() in a fatal error message.
+[[noreturn]] inline void ReportLastErrorFatal(const char *Msg) {
+ std::string ErrMsg;
+ MakeErrMsg(&ErrMsg, Msg);
+ wpi::report_fatal_error(ErrMsg);
}
template <typename HandleTraits>
@@ -164,6 +162,22 @@
}
};
+struct CryptContextTraits : CommonHandleTraits {
+ typedef HCRYPTPROV handle_type;
+
+ static handle_type GetInvalid() {
+ return 0;
+ }
+
+ static void Close(handle_type h) {
+ ::CryptReleaseContext(h, 0);
+ }
+
+ static bool IsValid(handle_type h) {
+ return h != GetInvalid();
+ }
+};
+
struct RegTraits : CommonHandleTraits {
typedef HKEY handle_type;
@@ -190,6 +204,7 @@
typedef ScopedHandle<CommonHandleTraits> ScopedCommonHandle;
typedef ScopedHandle<FileHandleTraits> ScopedFileHandle;
+typedef ScopedHandle<CryptContextTraits> ScopedCryptContext;
typedef ScopedHandle<RegTraits> ScopedRegHandle;
typedef ScopedHandle<FindHandleTraits> ScopedFindHandle;
typedef ScopedHandle<JobHandleTraits> ScopedJobHandle;
diff --git a/wpiutil/src/main/native/cpp/llvm/raw_os_ostream.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
similarity index 79%
rename from wpiutil/src/main/native/cpp/llvm/raw_os_ostream.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
index 1fb6c51..682a9a0 100644
--- a/wpiutil/src/main/native/cpp/llvm/raw_os_ostream.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_os_ostream.cpp
@@ -1,9 +1,8 @@
//===--- raw_os_ostream.cpp - Implement the raw_os_ostream class ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
similarity index 87%
rename from wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
rename to wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
index 622e0bf..a2d586b 100644
--- a/wpiutil/src/main/native/cpp/llvm/raw_ostream.cpp
+++ b/wpiutil/src/main/native/thirdparty/llvm/cpp/llvm/raw_ostream.cpp
@@ -1,9 +1,8 @@
//===--- raw_ostream.cpp - Implement the raw_ostream classes --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -21,19 +20,15 @@
#include "wpi/StringExtras.h"
#include "wpi/Compiler.h"
#include "wpi/ErrorHandling.h"
-#include "wpi/MathExtras.h"
-#include "wpi/WindowsError.h"
#include "wpi/fs.h"
+#include "wpi/MathExtras.h"
#include <algorithm>
-#include <cctype>
#include <cerrno>
#include <cstdio>
-#include <iterator>
#include <sys/stat.h>
-#include <system_error>
// <fcntl.h> may provide O_BINARY.
-#include <fcntl.h>
+# include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
@@ -64,6 +59,17 @@
using namespace wpi;
+constexpr raw_ostream::Colors raw_ostream::BLACK;
+constexpr raw_ostream::Colors raw_ostream::RED;
+constexpr raw_ostream::Colors raw_ostream::GREEN;
+constexpr raw_ostream::Colors raw_ostream::YELLOW;
+constexpr raw_ostream::Colors raw_ostream::BLUE;
+constexpr raw_ostream::Colors raw_ostream::MAGENTA;
+constexpr raw_ostream::Colors raw_ostream::CYAN;
+constexpr raw_ostream::Colors raw_ostream::WHITE;
+constexpr raw_ostream::Colors raw_ostream::SAVEDCOLOR;
+constexpr raw_ostream::Colors raw_ostream::RESET;
+
namespace {
// Find the length of an array.
template <class T, std::size_t N>
@@ -78,13 +84,10 @@
assert(OutBufCur == OutBufStart &&
"raw_ostream destructor called with non-empty buffer!");
- if (BufferMode == InternalBuffer)
+ if (BufferMode == BufferKind::InternalBuffer)
delete [] OutBufStart;
}
-// An out of line virtual method to provide a home for the class vtable.
-void raw_ostream::handle() {}
-
size_t raw_ostream::preferred_buffer_size() const {
// BUFSIZ is intended to be a reasonable default.
return BUFSIZ;
@@ -101,14 +104,14 @@
void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size,
BufferKind Mode) {
- assert(((Mode == Unbuffered && !BufferStart && Size == 0) ||
- (Mode != Unbuffered && BufferStart && Size != 0)) &&
+ assert(((Mode == BufferKind::Unbuffered && !BufferStart && Size == 0) ||
+ (Mode != BufferKind::Unbuffered && BufferStart && Size != 0)) &&
"stream must be unbuffered or have at least one byte");
// Make sure the current buffer is free of content (we can't flush here; the
// child buffer management logic will be in write_impl).
assert(GetNumBytesInBuffer() == 0 && "Current buffer is non-empty!");
- if (BufferMode == InternalBuffer)
+ if (BufferMode == BufferKind::InternalBuffer)
delete [] OutBufStart;
OutBufStart = BufferStart;
OutBufEnd = OutBufStart+Size;
@@ -143,7 +146,7 @@
// Write out the escaped representation.
if (UseHexEscapes) {
*this << '\\' << 'x';
- *this << hexdigit((c >> 4 & 0xF));
+ *this << hexdigit((c >> 4) & 0xF);
*this << hexdigit((c >> 0) & 0xF);
} else {
// Always use a full 3-character octal escape.
@@ -162,15 +165,15 @@
assert(OutBufCur > OutBufStart && "Invalid call to flush_nonempty.");
size_t Length = OutBufCur - OutBufStart;
OutBufCur = OutBufStart;
- write_impl(OutBufStart, Length);
+ flush_tied_then_write(OutBufStart, Length);
}
raw_ostream &raw_ostream::write(unsigned char C) {
// Group exceptional cases into a single branch.
if (LLVM_UNLIKELY(OutBufCur >= OutBufEnd)) {
if (LLVM_UNLIKELY(!OutBufStart)) {
- if (BufferMode == Unbuffered) {
- write_impl(reinterpret_cast<char*>(&C), 1);
+ if (BufferMode == BufferKind::Unbuffered) {
+ flush_tied_then_write(reinterpret_cast<char *>(&C), 1);
return *this;
}
// Set up a buffer and start over.
@@ -189,8 +192,8 @@
// Group exceptional cases into a single branch.
if (LLVM_UNLIKELY(size_t(OutBufEnd - OutBufCur) < Size)) {
if (LLVM_UNLIKELY(!OutBufStart)) {
- if (BufferMode == Unbuffered) {
- write_impl(Ptr, Size);
+ if (BufferMode == BufferKind::Unbuffered) {
+ flush_tied_then_write(Ptr, Size);
return *this;
}
// Set up a buffer and start over.
@@ -206,7 +209,7 @@
if (LLVM_UNLIKELY(OutBufCur == OutBufStart)) {
assert(NumBytes != 0 && "undefined behavior");
size_t BytesToWrite = Size - (Size % NumBytes);
- write_impl(Ptr, BytesToWrite);
+ flush_tied_then_write(Ptr, BytesToWrite);
size_t BytesRemaining = Size - BytesToWrite;
if (BytesRemaining > size_t(OutBufEnd - OutBufCur)) {
// Too much left over to copy into our buffer.
@@ -247,6 +250,13 @@
OutBufCur += Size;
}
+void raw_ostream::flush_tied_then_write(const char *Ptr, size_t Size) {
+ if (TiedStream)
+ TiedStream->flush();
+ 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,
@@ -294,8 +304,7 @@
// the owner of stdout and may set the "binary" flag globally based on Flags.
if (Filename == "-") {
EC = std::error_code();
- // If user requested binary then put stdout into binary mode if
- // possible.
+ // Change stdout's text/binary mode based on the Flags.
if (!(Flags & fs::OF_Text)) {
#if defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY);
@@ -305,11 +314,10 @@
}
fs::file_t F;
- if (Access & fs::FA_Read) {
+ if (Access & fs::FA_Read)
F = fs::OpenFileForReadWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
- } else {
+ else
F = fs::OpenFileForWrite(fs::path{std::string_view{Filename.data(), Filename.size()}}, EC, Disp, Flags);
- }
if (EC)
return -1;
int FD = fs::FileToFd(F, EC, Flags);
@@ -345,13 +353,16 @@
/// FD is the file descriptor that this writes to. If ShouldClose is true, this
/// closes the file when the stream is destroyed.
-raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered)
- : raw_pwrite_stream(unbuffered), FD(fd), ShouldClose(shouldClose) {
+raw_fd_ostream::raw_fd_ostream(int fd, bool shouldClose, bool unbuffered,
+ OStreamKind K)
+ : raw_pwrite_stream(unbuffered, K), FD(fd), ShouldClose(shouldClose) {
if (FD < 0 ) {
ShouldClose = false;
return;
}
+ enable_colors(true);
+
// Do not attempt to close stdout or stderr. We used to try to maintain the
// property that tools that support writing file to stdout should not also
// write informational output to stdout, but in practice we were never able to
@@ -370,10 +381,9 @@
// Get the starting position.
off_t loc = ::lseek(FD, 0, SEEK_CUR);
#ifdef _WIN32
- // MSVCRT's _lseek(SEEK_CUR) doesn't return -1 for pipes.
SupportsSeeking = loc != (off_t)-1 && ::GetFileType(reinterpret_cast<HANDLE>(::_get_osfhandle(FD))) != FILE_TYPE_PIPE;
#else
- SupportsSeeking = loc != (off_t)-1;
+ SupportsSeeking = !EC && loc != (off_t)-1;
#endif
if (!SupportsSeeking)
pos = 0;
@@ -402,7 +412,7 @@
// destructing raw_ostream objects which may have errors.
if (has_error())
report_fatal_error("IO failure on output stream: " + error().message(),
- /*GenCrashDiag=*/false);
+ /*gen_crash_diag=*/false);
}
#if defined(_WIN32)
@@ -565,7 +575,7 @@
// If this is a terminal, don't use buffering. Line buffering
// would be a more traditional thing to do, but it's not worth
// the complexity.
- if (S_ISCHR(statbuf.st_mode) && isatty(FD))
+ if (S_ISCHR(statbuf.st_mode) && is_displayed())
return 0;
// Return the preferred block size.
return statbuf.st_blksize;
@@ -580,38 +590,50 @@
// outs(), errs(), nulls()
//===----------------------------------------------------------------------===//
-/// outs() - This returns a reference to a raw_ostream for standard output.
-/// Use it like: outs() << "foo" << "bar";
-raw_ostream &wpi::outs() {
+raw_fd_ostream &wpi::outs() {
// Set buffer settings to model stdout behavior.
std::error_code EC;
- static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::F_None);
+ static raw_fd_ostream* S = new raw_fd_ostream("-", EC, fs::OF_None);
assert(!EC);
return *S;
}
-/// errs() - This returns a reference to a raw_ostream for standard error.
-/// Use it like: errs() << "foo" << "bar";
-raw_ostream &wpi::errs() {
- // Set standard error to be unbuffered by default.
+raw_fd_ostream &wpi::errs() {
+ // Set standard error to be unbuffered and tied to outs() by default.
static raw_fd_ostream* S = new raw_fd_ostream(STDERR_FILENO, false, true);
return *S;
}
/// nulls() - This returns a reference to a raw_ostream which discards output.
raw_ostream &wpi::nulls() {
- static raw_null_ostream* S = new raw_null_ostream;
- return *S;
+ static raw_null_ostream S;
+ return S;
+}
+
+//===----------------------------------------------------------------------===//
+// File Streams
+//===----------------------------------------------------------------------===//
+
+raw_fd_stream::raw_fd_stream(std::string_view Filename, std::error_code &EC)
+ : raw_fd_ostream(getFD(Filename, EC, fs::CD_CreateAlways,
+ fs::FA_Write | fs::FA_Read,
+ fs::OF_None),
+ true, false, OStreamKind::OK_FDStream) {
+ if (EC)
+ return;
+
+ if (!isRegularFile())
+ EC = std::make_error_code(std::errc::invalid_argument);
+}
+
+bool raw_fd_stream::classof(const raw_ostream *OS) {
+ return OS->get_kind() == OStreamKind::OK_FDStream;
}
//===----------------------------------------------------------------------===//
// raw_string_ostream
//===----------------------------------------------------------------------===//
-raw_string_ostream::~raw_string_ostream() {
- flush();
-}
-
void raw_string_ostream::write_impl(const char *Ptr, size_t Size) {
OS.append(Ptr, Size);
}
@@ -691,15 +713,18 @@
#endif
}
-void raw_null_ostream::write_impl(const char * /*Ptr*/, size_t /*Size*/) {}
+void raw_null_ostream::write_impl(const char *Ptr, size_t Size) {
+}
uint64_t raw_null_ostream::current_pos() const {
return 0;
}
-void raw_null_ostream::pwrite_impl(const char * /*Ptr*/, size_t /*Size*/,
- uint64_t /*Offset*/) {}
+void raw_null_ostream::pwrite_impl(const char *Ptr, size_t Size,
+ uint64_t Offset) {}
void raw_pwrite_stream::anchor() {}
void buffer_ostream::anchor() {}
+
+void buffer_unique_ostream::anchor() {}
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
new file mode 100644
index 0000000..5d400e4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AlignOf.h
@@ -0,0 +1,34 @@
+//===--- AlignOf.h - Portable calculation of type alignment -----*- 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 AlignedCharArrayUnion class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_ALIGNOF_H
+#define WPIUTIL_WPI_ALIGNOF_H
+
+#include <type_traits>
+
+namespace wpi {
+
+/// A suitably aligned and sized character array member which can hold elements
+/// of any type.
+///
+/// This template is equivalent to std::aligned_union_t<1, ...>, but we cannot
+/// use it due to a bug in the MSVC x86 compiler:
+/// https://github.com/microsoft/STL/issues/1533
+/// Using `alignas` here works around the bug.
+template <typename T, typename... Ts> struct AlignedCharArrayUnion {
+ using AlignedUnion = std::aligned_union_t<1, T, Ts...>;
+ alignas(alignof(AlignedUnion)) char buffer[sizeof(AlignedUnion)];
+};
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_ALIGNOF_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
new file mode 100644
index 0000000..29ba16f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/AllocatorBase.h
@@ -0,0 +1,104 @@
+//===- AllocatorBase.h - Simple memory allocation abstraction ---*- 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 MallocAllocator. MallocAllocator conforms to the LLVM
+/// "Allocator" concept which consists of an Allocate method accepting a size
+/// and alignment, and a Deallocate accepting a pointer and size. Further, the
+/// LLVM "Allocator" concept has overloads of Allocate and Deallocate for
+/// setting size and alignment based on the final type. These overloads are
+/// typically provided by a base class template \c AllocatorBase.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_ALLOCATORBASE_H
+#define WPIUTIL_WPI_ALLOCATORBASE_H
+
+#include "wpi/Compiler.h"
+#include "wpi/MemAlloc.h"
+#include <type_traits>
+
+namespace wpi {
+
+/// CRTP base class providing obvious overloads for the core \c
+/// Allocate() methods of LLVM-style allocators.
+///
+/// This base class both documents the full public interface exposed by all
+/// LLVM-style allocators, and redirects all of the overloads to a single core
+/// set of methods which the derived class must define.
+template <typename DerivedT> class AllocatorBase {
+public:
+ /// Allocate \a Size bytes of \a Alignment aligned memory. This method
+ /// must be implemented by \c DerivedT.
+ void *Allocate(size_t Size, size_t Alignment) {
+#ifdef __clang__
+ static_assert(static_cast<void *(AllocatorBase::*)(size_t, size_t)>(
+ &AllocatorBase::Allocate) !=
+ static_cast<void *(DerivedT::*)(size_t, size_t)>(
+ &DerivedT::Allocate),
+ "Class derives from AllocatorBase without implementing the "
+ "core Allocate(size_t, size_t) overload!");
+#endif
+ return static_cast<DerivedT *>(this)->Allocate(Size, Alignment);
+ }
+
+ /// Deallocate \a Ptr to \a Size bytes of memory allocated by this
+ /// allocator.
+ void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
+#ifdef __clang__
+ static_assert(
+ static_cast<void (AllocatorBase::*)(const void *, size_t, size_t)>(
+ &AllocatorBase::Deallocate) !=
+ static_cast<void (DerivedT::*)(const void *, size_t, size_t)>(
+ &DerivedT::Deallocate),
+ "Class derives from AllocatorBase without implementing the "
+ "core Deallocate(void *) overload!");
+#endif
+ return static_cast<DerivedT *>(this)->Deallocate(Ptr, Size, Alignment);
+ }
+
+ // The rest of these methods are helpers that redirect to one of the above
+ // core methods.
+
+ /// Allocate space for a sequence of objects without constructing them.
+ template <typename T> T *Allocate(size_t Num = 1) {
+ return static_cast<T *>(Allocate(Num * sizeof(T), alignof(T)));
+ }
+
+ /// 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>
+ Deallocate(T *Ptr, size_t Num = 1) {
+ Deallocate(static_cast<const void *>(Ptr), Num * sizeof(T), alignof(T));
+ }
+};
+
+class MallocAllocator : public AllocatorBase<MallocAllocator> {
+public:
+ void Reset() {}
+
+ LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t Size, size_t Alignment) {
+ return allocate_buffer(Size, Alignment);
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<MallocAllocator>::Allocate;
+
+ void Deallocate(const void *Ptr, size_t Size, size_t Alignment) {
+ deallocate_buffer(const_cast<void *>(Ptr), Size, Alignment);
+ }
+
+ // Pull in base class overloads.
+ using AllocatorBase<MallocAllocator>::Deallocate;
+
+ void PrintStats() const {}
+};
+
+} // namespace wpi
+
+#endif // WPIUTIL_WPI_ALLOCATORBASE_H
diff --git a/wpiutil/src/main/native/include/wpi/Chrono.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
similarity index 70%
rename from wpiutil/src/main/native/include/wpi/Chrono.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
index 33341c6..221f6dc 100644
--- a/wpiutil/src/main/native/include/wpi/Chrono.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Chrono.h
@@ -1,9 +1,8 @@
//===- llvm/Support/Chrono.h - Utilities for Timing Manipulation-*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -14,6 +13,7 @@
#include <chrono>
#include <ctime>
+#include <ratio>
namespace wpi {
@@ -23,31 +23,31 @@
/// A time point on the system clock. This is provided for two reasons:
/// - to insulate us against subtle differences in behavior to differences in
-/// system clock precision (which is implementation-defined and differs between
-/// platforms).
+/// system clock precision (which is implementation-defined and differs
+/// between platforms).
/// - to shorten the type name
-/// The default precision is nanoseconds. If need a specific precision specify
-/// it explicitly. If unsure, use the default. If you need a time point on a
-/// clock other than the system_clock, use std::chrono directly.
+/// The default precision is nanoseconds. If you need a specific precision
+/// specify it explicitly. If unsure, use the default. If you need a time point
+/// on a clock other than the system_clock, use std::chrono directly.
template <typename D = std::chrono::nanoseconds>
using TimePoint = std::chrono::time_point<std::chrono::system_clock, D>;
/// Convert a TimePoint to std::time_t
-LLVM_ATTRIBUTE_ALWAYS_INLINE std::time_t toTimeT(TimePoint<> TP) {
+inline std::time_t toTimeT(TimePoint<> TP) {
using namespace std::chrono;
return system_clock::to_time_t(
time_point_cast<system_clock::time_point::duration>(TP));
}
/// Convert a std::time_t to a TimePoint
-LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint<std::chrono::seconds>
+inline TimePoint<std::chrono::seconds>
toTimePoint(std::time_t T) {
using namespace std::chrono;
return time_point_cast<seconds>(system_clock::from_time_t(T));
}
/// Convert a std::time_t + nanoseconds to a TimePoint
-LLVM_ATTRIBUTE_ALWAYS_INLINE TimePoint<>
+inline TimePoint<>
toTimePoint(std::time_t T, uint32_t nsec) {
using namespace std::chrono;
return time_point_cast<nanoseconds>(system_clock::from_time_t(T))
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
new file mode 100644
index 0000000..c98386e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Compiler.h
@@ -0,0 +1,619 @@
+//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- 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 several macros, based on the current compiler. This allows
+// use of compiler-specific features in a way that remains portable. This header
+// can be included from either C or C++.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_COMPILER_H
+#define WPIUTIL_WPI_COMPILER_H
+
+
+#include <stddef.h>
+
+#if defined(_MSC_VER)
+#include <sal.h>
+#endif
+
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#ifndef __has_extension
+# define __has_extension(x) 0
+#endif
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(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
+#if defined(__cplusplus) && defined(__has_cpp_attribute)
+# define LLVM_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
+#else
+# define LLVM_HAS_CPP_ATTRIBUTE(x) 0
+#endif
+#endif
+
+/// \macro LLVM_GNUC_PREREQ
+/// Extend the default __GNUC_PREREQ even if glibc's features.h isn't
+/// available.
+#ifndef LLVM_GNUC_PREREQ
+# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
+ ((maj) << 20) + ((min) << 10) + (patch))
+# elif defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define LLVM_GNUC_PREREQ(maj, min, patch) \
+ ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
+# else
+# define LLVM_GNUC_PREREQ(maj, min, patch) 0
+# endif
+#endif
+
+/// \macro LLVM_MSC_PREREQ
+/// Is the compiler MSVC of at least the specified version?
+/// The common \param version values to check for are:
+/// * 1910: VS2017, version 15.1 & 15.2
+/// * 1911: VS2017, version 15.3 & 15.4
+/// * 1912: VS2017, version 15.5
+/// * 1913: VS2017, version 15.6
+/// * 1914: VS2017, version 15.7
+/// * 1915: VS2017, version 15.8
+/// * 1916: VS2017, version 15.9
+/// * 1920: VS2019, version 16.0
+/// * 1921: VS2019, version 16.1
+/// * 1922: VS2019, version 16.2
+/// * 1923: VS2019, version 16.3
+/// * 1924: VS2019, version 16.4
+/// * 1925: VS2019, version 16.5
+/// * 1926: VS2019, version 16.6
+/// * 1927: VS2019, version 16.7
+/// * 1928: VS2019, version 16.8 + 16.9
+/// * 1929: VS2019, version 16.10 + 16.11
+/// * 1930: VS2022, version 17.0
+#ifndef LLVM_MSC_PREREQ
+#ifdef _MSC_VER
+#define LLVM_MSC_PREREQ(version) (_MSC_VER >= (version))
+
+// We require at least VS 2019.
+#if !defined(LLVM_FORCE_USE_OLD_TOOLCHAIN)
+#if !LLVM_MSC_PREREQ(1920)
+#error LLVM requires at least VS 2019.
+#endif
+#endif
+
+#else
+#define LLVM_MSC_PREREQ(version) 0
+#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
+/// functions, making them private to any shared library they are linked into.
+/// On PE/COFF targets, library visibility is the default, so this isn't needed.
+///
+/// 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 defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
+#define LLVM_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
+#else
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+#else
+#define LLVM_LIBRARY_VISIBILITY
+#define LLVM_EXTERNAL_VISIBILITY
+#endif
+
+#ifndef LLVM_PREFETCH
+#if defined(__GNUC__)
+#define LLVM_PREFETCH(addr, rw, locality) __builtin_prefetch(addr, rw, locality)
+#else
+#define LLVM_PREFETCH(addr, rw, locality)
+#endif
+#endif
+
+#ifndef LLVM_ATTRIBUTE_USED
+#if __has_attribute(used)
+#define LLVM_ATTRIBUTE_USED __attribute__((__used__))
+#else
+#define LLVM_ATTRIBUTE_USED
+#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]]
+#else
+#define LLVM_NODISCARD
+#endif
+#endif
+
+// Indicate that a non-static, non-const C++ member function reinitializes
+// the entire object to a known state, independent of the previous state of
+// the object.
+//
+// The clang-tidy check bugprone-use-after-move recognizes this attribute as a
+// marker that a moved-from object has left the indeterminate state and can be
+// reused.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::reinitializes)
+#define LLVM_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
+#else
+#define LLVM_ATTRIBUTE_REINITIALIZES
+#endif
+
+// Some compilers warn about unused functions. When a function is sometimes
+// used or not depending on build settings (e.g. a function only called from
+// within "assert"), this attribute can be used to suppress such warnings.
+//
+// However, it shouldn't be used for unused *variables*, as those have a much
+// more portable solution:
+// (void)unused_var_name;
+// Prefer cast-to-void wherever it is sufficient.
+#ifndef LLVM_ATTRIBUTE_UNUSED
+#if __has_attribute(unused)
+#define LLVM_ATTRIBUTE_UNUSED __attribute__((__unused__))
+#else
+#define LLVM_ATTRIBUTE_UNUSED
+#endif
+#endif
+
+// FIXME: Provide this for PE/COFF targets.
+#if __has_attribute(weak) && !defined(__MINGW32__) && !defined(__CYGWIN__) && \
+ !defined(_WIN32)
+#define LLVM_ATTRIBUTE_WEAK __attribute__((__weak__))
+#else
+#define LLVM_ATTRIBUTE_WEAK
+#endif
+
+#ifndef LLVM_READNONE
+// Prior to clang 3.2, clang did not accept any spelling of
+// __has_attribute(const), so assume it is supported.
+#if defined(__clang__) || defined(__GNUC__)
+// aka 'CONST' but following LLVM Conventions.
+#define LLVM_READNONE __attribute__((__const__))
+#else
+#define LLVM_READNONE
+#endif
+#endif
+
+#ifndef LLVM_READONLY
+#if __has_attribute(pure) || defined(__GNUC__)
+// aka 'PURE' but following LLVM Conventions.
+#define LLVM_READONLY __attribute__((__pure__))
+#else
+#define LLVM_READONLY
+#endif
+#endif
+
+#if __has_attribute(minsize)
+#define LLVM_ATTRIBUTE_MINSIZE __attribute__((minsize))
+#else
+#define LLVM_ATTRIBUTE_MINSIZE
+#endif
+
+#ifndef LLVM_LIKELY
+#if __has_builtin(__builtin_expect) || defined(__GNUC__)
+#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true)
+#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false)
+#else
+#define LLVM_LIKELY(EXPR) (EXPR)
+#define LLVM_UNLIKELY(EXPR) (EXPR)
+#endif
+#endif
+
+/// LLVM_ATTRIBUTE_NOINLINE - On compilers where we have a directive to do so,
+/// mark a method "not for inlining".
+#ifndef LLVM_ATTRIBUTE_NOINLINE
+#if __has_attribute(noinline)
+#define LLVM_ATTRIBUTE_NOINLINE __attribute__((noinline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_NOINLINE __declspec(noinline)
+#else
+#define LLVM_ATTRIBUTE_NOINLINE
+#endif
+#endif
+
+/// LLVM_ATTRIBUTE_ALWAYS_INLINE - On compilers where we have a directive to do
+/// so, mark a method "always inline" because it is performance sensitive.
+#ifndef LLVM_ATTRIBUTE_ALWAYS_INLINE
+#if __has_attribute(always_inline)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline __attribute__((always_inline))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE __forceinline
+#else
+#define LLVM_ATTRIBUTE_ALWAYS_INLINE inline
+#endif
+#endif
+
+/// LLVM_ATTRIBUTE_NO_DEBUG - On compilers where we have a directive to do
+/// so, mark a method "no debug" because debug info makes the debugger
+/// experience worse.
+#if __has_attribute(nodebug)
+#define LLVM_ATTRIBUTE_NODEBUG __attribute__((nodebug))
+#else
+#define LLVM_ATTRIBUTE_NODEBUG
+#endif
+
+#ifndef LLVM_ATTRIBUTE_RETURNS_NONNULL
+#if __has_attribute(returns_nonnull)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL _Ret_notnull_
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NONNULL
+#endif
+#endif
+
+/// \macro LLVM_ATTRIBUTE_RETURNS_NOALIAS Used to mark a function as returning a
+/// pointer that does not alias any other valid pointer.
+#ifndef LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#ifdef __GNUC__
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
+#elif defined(_MSC_VER)
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
+#else
+#define LLVM_ATTRIBUTE_RETURNS_NOALIAS
+#endif
+#endif
+
+/// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements.
+#ifndef LLVM_FALLTHROUGH
+#if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough)
+#define LLVM_FALLTHROUGH [[fallthrough]]
+#elif LLVM_HAS_CPP_ATTRIBUTE(gnu::fallthrough)
+#define LLVM_FALLTHROUGH [[gnu::fallthrough]]
+#elif __has_attribute(fallthrough)
+#define LLVM_FALLTHROUGH __attribute__((fallthrough))
+#elif LLVM_HAS_CPP_ATTRIBUTE(clang::fallthrough)
+#define LLVM_FALLTHROUGH [[clang::fallthrough]]
+#else
+#define LLVM_FALLTHROUGH
+#endif
+#endif
+
+/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that
+/// they are constant initialized.
+#if LLVM_HAS_CPP_ATTRIBUTE(clang::require_constant_initialization)
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \
+ [[clang::require_constant_initialization]]
+#else
+#define LLVM_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+
+/// LLVM_GSL_OWNER - Apply this to owning classes like SmallVector to enable
+/// lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Owner)
+#define LLVM_GSL_OWNER [[gsl::Owner]]
+#else
+#define LLVM_GSL_OWNER
+#endif
+
+/// LLVM_GSL_POINTER - Apply this to non-owning classes like
+/// std::string_view to enable lifetime warnings.
+#if LLVM_HAS_CPP_ATTRIBUTE(gsl::Pointer)
+#define LLVM_GSL_POINTER [[gsl::Pointer]]
+#else
+#define LLVM_GSL_POINTER
+#endif
+
+/// LLVM_EXTENSION - Support compilers where we have a keyword to suppress
+/// pedantic diagnostics.
+#ifndef LLVM_EXTENSION
+#ifdef __GNUC__
+#define LLVM_EXTENSION __extension__
+#else
+#define LLVM_EXTENSION
+#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.
+#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
+
+/// LLVM_BUILTIN_TRAP - On compilers which support it, expands to an expression
+/// which causes the program to exit abnormally.
+#ifndef LLVM_BUILTIN_TRAP
+#if __has_builtin(__builtin_trap) || defined(__GNUC__)
+# define LLVM_BUILTIN_TRAP __builtin_trap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC, does not require forward
+// declarations involving platform-specific typedefs (unlike RaiseException),
+// results in a call to vectored exception handlers, and encodes to a short
+// instruction that still causes the trapping behavior we want.
+# define LLVM_BUILTIN_TRAP __debugbreak()
+#else
+# define LLVM_BUILTIN_TRAP *(volatile int*)0x11 = 0
+#endif
+#endif
+
+/// LLVM_BUILTIN_DEBUGTRAP - On compilers which support it, expands to
+/// an expression which causes the program to break while running
+/// under a debugger.
+#ifndef LLVM_BUILTIN_DEBUGTRAP
+#if __has_builtin(__builtin_debugtrap)
+# define LLVM_BUILTIN_DEBUGTRAP __builtin_debugtrap()
+#elif defined(_MSC_VER)
+// The __debugbreak intrinsic is supported by MSVC and breaks while
+// running under the debugger, and also supports invoking a debugger
+// when the OS is configured appropriately.
+# define LLVM_BUILTIN_DEBUGTRAP __debugbreak()
+#else
+// Just continue execution when built with compilers that have no
+// support. This is a debugging aid and not intended to force the
+// program to abort if encountered.
+# define LLVM_BUILTIN_DEBUGTRAP
+#endif
+#endif
+
+/// \macro LLVM_ASSUME_ALIGNED
+/// Returns a pointer with an assumed alignment.
+#ifndef LLVM_ASSUME_ALIGNED
+#if __has_builtin(__builtin_assume_aligned) || defined(__GNUC__)
+# define LLVM_ASSUME_ALIGNED(p, a) __builtin_assume_aligned(p, a)
+#elif defined(LLVM_BUILTIN_UNREACHABLE)
+# define LLVM_ASSUME_ALIGNED(p, a) \
+ (((uintptr_t(p) % (a)) == 0) ? (p) : (LLVM_BUILTIN_UNREACHABLE, (p)))
+#else
+# define LLVM_ASSUME_ALIGNED(p, a) (p)
+#endif
+#endif
+
+/// \macro LLVM_PACKED
+/// Used to specify a packed structure.
+/// LLVM_PACKED(
+/// struct A {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// });
+///
+/// LLVM_PACKED_START
+/// struct B {
+/// int i;
+/// int j;
+/// int k;
+/// long long l;
+/// };
+/// LLVM_PACKED_END
+#ifndef LLVM_PACKED
+#ifdef _MSC_VER
+# define LLVM_PACKED(d) __pragma(pack(push, 1)) d __pragma(pack(pop))
+# define LLVM_PACKED_START __pragma(pack(push, 1))
+# define LLVM_PACKED_END __pragma(pack(pop))
+#else
+# define LLVM_PACKED(d) d __attribute__((packed))
+# define LLVM_PACKED_START _Pragma("pack(push, 1)")
+# define LLVM_PACKED_END _Pragma("pack(pop)")
+#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)
+# define LLVM_MEMORY_SANITIZER_BUILD 1
+# include <sanitizer/msan_interface.h>
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE __attribute__((no_sanitize_memory))
+#else
+# define LLVM_MEMORY_SANITIZER_BUILD 0
+# define __msan_allocated_memory(p, size)
+# define __msan_unpoison(p, size)
+# define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
+#endif
+
+/// \macro LLVM_ADDRESS_SANITIZER_BUILD
+/// Whether LLVM itself is built with AddressSanitizer instrumentation.
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define LLVM_ADDRESS_SANITIZER_BUILD 1
+# include <sanitizer/asan_interface.h>
+#else
+# define LLVM_ADDRESS_SANITIZER_BUILD 0
+# define __asan_poison_memory_region(p, size)
+# define __asan_unpoison_memory_region(p, size)
+#endif
+
+/// \macro LLVM_THREAD_SANITIZER_BUILD
+/// Whether LLVM itself is built with ThreadSanitizer instrumentation.
+#if __has_feature(thread_sanitizer) || defined(__SANITIZE_THREAD__)
+# define LLVM_THREAD_SANITIZER_BUILD 1
+#else
+# define LLVM_THREAD_SANITIZER_BUILD 0
+#endif
+
+#if LLVM_THREAD_SANITIZER_BUILD
+// Thread Sanitizer is a tool that finds races in code.
+// See http://code.google.com/p/data-race-test/wiki/DynamicAnnotations .
+// tsan detects these exact functions by name.
+#ifdef __cplusplus
+extern "C" {
+#endif
+void AnnotateHappensAfter(const char *file, int line, const volatile void *cv);
+void AnnotateHappensBefore(const char *file, int line, const volatile void *cv);
+void AnnotateIgnoreWritesBegin(const char *file, int line);
+void AnnotateIgnoreWritesEnd(const char *file, int line);
+#ifdef __cplusplus
+}
+#endif
+
+// This marker is used to define a happens-before arc. The race detector will
+// infer an arc from the begin to the end when they share the same pointer
+// argument.
+# define TsanHappensBefore(cv) AnnotateHappensBefore(__FILE__, __LINE__, cv)
+
+// This marker defines the destination of a happens-before arc.
+# define TsanHappensAfter(cv) AnnotateHappensAfter(__FILE__, __LINE__, cv)
+
+// Ignore any races on writes between here and the next TsanIgnoreWritesEnd.
+# define TsanIgnoreWritesBegin() AnnotateIgnoreWritesBegin(__FILE__, __LINE__)
+
+// Resume checking for racy writes.
+# define TsanIgnoreWritesEnd() AnnotateIgnoreWritesEnd(__FILE__, __LINE__)
+#else
+# define TsanHappensBefore(cv)
+# define TsanHappensAfter(cv)
+# define TsanIgnoreWritesBegin()
+# define TsanIgnoreWritesEnd()
+#endif
+
+/// \macro LLVM_NO_SANITIZE
+/// Disable a particular sanitizer for a function.
+#ifndef LLVM_NO_SANITIZE
+#if __has_attribute(no_sanitize)
+#define LLVM_NO_SANITIZE(KIND) __attribute__((no_sanitize(KIND)))
+#else
+#define LLVM_NO_SANITIZE(KIND)
+#endif
+#endif
+
+/// Mark debug helper function definitions like dump() that should not be
+/// stripped from debug builds.
+/// Note that you should also surround dump() functions with
+/// `#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)` so they do always
+/// get stripped in release builds.
+// FIXME: Move this to a private config.h as it's not usable in public headers.
+#ifndef LLVM_DUMP_METHOD
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE LLVM_ATTRIBUTE_USED
+#else
+#define LLVM_DUMP_METHOD LLVM_ATTRIBUTE_NOINLINE
+#endif
+#endif
+
+/// \macro LLVM_PRETTY_FUNCTION
+/// Gets a user-friendly looking function signature for the current scope
+/// using the best available method on each platform. The exact format of the
+/// resulting string is implementation specific and non-portable, so this should
+/// only be used, for example, for logging or diagnostics.
+#ifndef LLVM_PRETTY_FUNCTION
+#if defined(_MSC_VER)
+#define LLVM_PRETTY_FUNCTION __FUNCSIG__
+#elif defined(__GNUC__) || defined(__clang__)
+#define LLVM_PRETTY_FUNCTION __PRETTY_FUNCTION__
+#else
+#define LLVM_PRETTY_FUNCTION __func__
+#endif
+#endif
+
+/// \macro LLVM_THREAD_LOCAL
+/// A thread-local storage specifier which can be used with globals,
+/// extern globals, and static globals.
+///
+/// This is essentially an extremely restricted analog to C++11's thread_local
+/// support. It uses thread_local if available, falling back on gcc __thread
+/// if not. __thread doesn't support many of the C++11 thread_local's
+/// features. You should only use this for PODs that you can statically
+/// initialize to some constant value. In almost all circumstances this is most
+/// appropriate for use with a pointer, integer, or small aggregation of
+/// pointers and integers.
+#if __has_feature(cxx_thread_local) || defined(_MSC_VER)
+#define LLVM_THREAD_LOCAL thread_local
+#else
+// Clang, GCC, and other compatible compilers used __thread prior to C++11 and
+// we only need the restricted functionality that provides.
+#define LLVM_THREAD_LOCAL __thread
+#endif
+
+/// \macro LLVM_ENABLE_EXCEPTIONS
+/// Whether LLVM is built with exception support.
+#if __has_feature(cxx_exceptions)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(__GNUC__) && defined(__EXCEPTIONS)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#elif defined(_MSC_VER) && defined(_CPPUNWIND)
+#define LLVM_ENABLE_EXCEPTIONS 1
+#endif
+
+/// \macro LLVM_NO_PROFILE_INSTRUMENT_FUNCTION
+/// Disable the profile instrument for a function.
+#if __has_attribute(no_profile_instrument_function)
+#define LLVM_NO_PROFILE_INSTRUMENT_FUNCTION \
+ __attribute__((no_profile_instrument_function))
+#else
+#define LLVM_NO_PROFILE_INSTRUMENT_FUNCTION
+#endif
+
+#endif
diff --git a/wpiutil/src/main/native/include/wpi/ConvertUTF.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
similarity index 79%
rename from wpiutil/src/main/native/include/wpi/ConvertUTF.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
index aa113b1..436bc6d 100644
--- a/wpiutil/src/main/native/include/wpi/ConvertUTF.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ConvertUTF.h
@@ -1,9 +1,8 @@
/*===--- ConvertUTF.h - Universal Character Names conversions ---------------===
*
- * The LLVM Compiler Infrastructure
- *
- * This file is distributed under the University of Illinois Open Source
- * License. See LICENSE.TXT for details.
+ * 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
*
*==------------------------------------------------------------------------==*/
/*
@@ -87,24 +86,21 @@
------------------------------------------------------------------------ */
-#ifndef LLVM_SUPPORT_CONVERTUTF_H
-#define LLVM_SUPPORT_CONVERTUTF_H
+#ifndef WPIUTIL_WPI_CONVERTUTF_H
+#define WPIUTIL_WPI_CONVERTUTF_H
-#include "wpi/span.h"
+#include <span>
#include <cstddef>
#include <string>
#include <string_view>
#include <system_error>
-// Wrap everything in namespace wpi so that programs can link with wpiutil and
+// Wrap everything in namespace wpi so that programs can link with llvm and
// their own version of the unicode libraries.
namespace wpi {
-template <typename T>
-class SmallVectorImpl;
-
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
@@ -187,6 +183,38 @@
/*************************************************************************/
/* Below are LLVM-specific wrappers of the functions above. */
+template <typename T> class SmallVectorImpl;
+
+/**
+ * Convert an UTF8 string_view to UTF8, UTF16, or UTF32 depending on
+ * WideCharWidth. The converted data is written to ResultPtr, which needs to
+ * point to at least WideCharWidth * (Source.Size() + 1) bytes. On success,
+ * ResultPtr will point one after the end of the copied string. On failure,
+ * ResultPtr will not be changed, and ErrorPtr will be set to the location of
+ * the first character which could not be converted.
+ * \return true on success.
+ */
+bool ConvertUTF8toWide(unsigned WideCharWidth, std::string_view Source,
+ char *&ResultPtr, const UTF8 *&ErrorPtr);
+
+/**
+* Converts a UTF-8 string_view to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(std::string_view Source, std::wstring &Result);
+
+/**
+* Converts a UTF-8 C-string to a std::wstring.
+* \return true on success.
+*/
+bool ConvertUTF8toWide(const char *Source, std::wstring &Result);
+
+/**
+* Converts a std::wstring to a UTF-8 encoded std::string.
+* \return true on success.
+*/
+bool convertWideToUTF8(const std::wstring &Source, SmallVectorImpl<char> &Result);
+
/**
* Convert an Unicode code point to UTF8 sequence.
@@ -215,10 +243,10 @@
*
* \sa ConvertUTF8toUTF32
*/
-static inline ConversionResult convertUTF8Sequence(const UTF8 **source,
- const UTF8 *sourceEnd,
- UTF32 *target,
- ConversionFlags flags) {
+inline ConversionResult convertUTF8Sequence(const UTF8 **source,
+ const UTF8 *sourceEnd,
+ UTF32 *target,
+ ConversionFlags flags) {
if (*source == sourceEnd)
return sourceExhausted;
unsigned size = getNumBytesForUTF8(**source);
@@ -231,15 +259,25 @@
* Returns true if a blob of text starts with a UTF-16 big or little endian byte
* order mark.
*/
-bool hasUTF16ByteOrderMark(span<const char> SrcBytes);
+bool hasUTF16ByteOrderMark(std::span<const char> SrcBytes);
/**
- * Converts a UTF-16 string into a UTF-8 string.
+ * Converts a stream of raw bytes assumed to be UTF16 into a UTF8 std::string.
*
+ * \param [in] SrcBytes A buffer of what is assumed to be UTF-16 encoded text.
+ * \param [out] Out Converted UTF-8 is stored here on success.
* \returns true on success
*/
-bool convertUTF16ToUTF8String(span<const UTF16> SrcUTF16,
- SmallVectorImpl<char> &DstUTF8);
+bool convertUTF16ToUTF8String(std::span<const char> SrcBytes, SmallVectorImpl<char> &Out);
+
+/**
+* Converts a UTF16 string into a UTF8 std::string.
+*
+* \param [in] Src A buffer of UTF-16 encoded text.
+* \param [out] Out Converted UTF-8 is stored here on success.
+* \returns true on success
+*/
+bool convertUTF16ToUTF8String(std::span<const UTF16> Src, SmallVectorImpl<char> &Out);
/**
* Converts a UTF-8 string into a UTF-16 string with native endianness.
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
new file mode 100644
index 0000000..2615bba
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DJB.h
@@ -0,0 +1,29 @@
+//===-- 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/include/wpi/DenseMap.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
similarity index 83%
rename from wpiutil/src/main/native/include/wpi/DenseMap.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
index 12bb712..b1ffd43 100644
--- a/wpiutil/src/main/native/include/wpi/DenseMap.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMap.h
@@ -1,14 +1,14 @@
//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 DenseMap class.
-//
+///
+/// \file
+/// This file defines the DenseMap class.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_DENSEMAP_H
@@ -19,12 +19,14 @@
#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/MathExtras.h"
-#include "wpi/PointerLikeTypeTraits.h"
+#include "wpi/MemAlloc.h"
+#include "wpi/ReverseIteration.h"
#include "wpi/type_traits.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstring>
+#include <initializer_list>
#include <iterator>
#include <new>
#include <type_traits>
@@ -38,6 +40,8 @@
// implementation without requiring two members.
template <typename KeyT, typename ValueT>
struct DenseMapPair : public std::pair<KeyT, ValueT> {
+ using std::pair<KeyT, ValueT>::pair;
+
KeyT &getFirst() { return std::pair<KeyT, ValueT>::first; }
const KeyT &getFirst() const { return std::pair<KeyT, ValueT>::first; }
ValueT &getSecond() { return std::pair<KeyT, ValueT>::second; }
@@ -73,6 +77,8 @@
// empty buckets.
if (empty())
return end();
+ if (shouldReverseIterate<KeyT>())
+ return makeIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeIterator(getBuckets(), getBucketsEnd(), *this);
}
inline iterator end() {
@@ -81,6 +87,8 @@
inline const_iterator begin() const {
if (empty())
return end();
+ if (shouldReverseIterate<KeyT>())
+ return makeConstIterator(getBucketsEnd() - 1, getBuckets(), *this);
return makeConstIterator(getBuckets(), getBucketsEnd(), *this);
}
inline const_iterator end() const {
@@ -113,8 +121,8 @@
}
const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey();
- if (isPodLike<KeyT>::value && isPodLike<ValueT>::value) {
- // Use a simpler loop when these are trivial types.
+ if (std::is_trivially_destructible<ValueT>::value) {
+ // Use a simpler loop when values don't need destruction.
for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P)
P->getFirst() = EmptyKey;
} else {
@@ -143,13 +151,19 @@
iterator find(const_arg_type_t<KeyT> Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeIterator(TheBucket, getBucketsEnd(), *this, true);
+ return makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>() ? getBuckets()
+ : getBucketsEnd(),
+ *this, true);
return end();
}
const_iterator find(const_arg_type_t<KeyT> Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
+ return makeConstIterator(TheBucket,
+ shouldReverseIterate<KeyT>() ? getBuckets()
+ : getBucketsEnd(),
+ *this, true);
return end();
}
@@ -162,14 +176,20 @@
iterator find_as(const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeIterator(TheBucket, getBucketsEnd(), *this, true);
+ return makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>() ? getBuckets()
+ : getBucketsEnd(),
+ *this, true);
return end();
}
template<class LookupKeyT>
const_iterator find_as(const LookupKeyT &Val) const {
const BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return makeConstIterator(TheBucket, getBucketsEnd(), *this, true);
+ return makeConstIterator(TheBucket,
+ shouldReverseIterate<KeyT>() ? getBuckets()
+ : getBucketsEnd(),
+ *this, true);
return end();
}
@@ -203,16 +223,22 @@
std::pair<iterator, bool> try_emplace(KeyT &&Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- false); // Already in map.
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ false); // Already in map.
// Otherwise, insert the new element.
TheBucket =
InsertIntoBucket(TheBucket, std::move(Key), std::forward<Ts>(Args)...);
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- true);
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ true);
}
// Inserts key,value pair into the map if the key isn't already in the map.
@@ -222,15 +248,21 @@
std::pair<iterator, bool> try_emplace(const KeyT &Key, Ts &&... Args) {
BucketT *TheBucket;
if (LookupBucketFor(Key, TheBucket))
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- false); // Already in map.
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucket(TheBucket, Key, std::forward<Ts>(Args)...);
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- true);
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ true);
}
/// Alternate version of insert() which allows a different, and possibly
@@ -243,16 +275,22 @@
const LookupKeyT &Val) {
BucketT *TheBucket;
if (LookupBucketFor(Val, TheBucket))
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- false); // Already in map.
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ false); // Already in map.
// Otherwise, insert the new element.
TheBucket = InsertIntoBucketWithLookup(TheBucket, std::move(KV.first),
std::move(KV.second), Val);
- return std::make_pair(
- makeIterator(TheBucket, getBucketsEnd(), *this, true),
- true);
+ return std::make_pair(makeIterator(TheBucket,
+ shouldReverseIterate<KeyT>()
+ ? getBuckets()
+ : getBucketsEnd(),
+ *this, true),
+ true);
}
/// insert - Range insertion of pairs.
@@ -389,7 +427,8 @@
setNumEntries(other.getNumEntries());
setNumTombstones(other.getNumTombstones());
- if (isPodLike<KeyT>::value && isPodLike<ValueT>::value)
+ if (std::is_trivially_copyable<KeyT>::value &&
+ std::is_trivially_copyable<ValueT>::value)
memcpy(reinterpret_cast<void *>(getBuckets()), other.getBuckets(),
getNumBuckets() * sizeof(BucketT));
else
@@ -426,12 +465,20 @@
iterator makeIterator(BucketT *P, BucketT *E,
DebugEpochBase &Epoch,
bool NoAdvance=false) {
+ if (shouldReverseIterate<KeyT>()) {
+ BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
+ return iterator(B, E, Epoch, NoAdvance);
+ }
return iterator(P, E, Epoch, NoAdvance);
}
const_iterator makeConstIterator(const BucketT *P, const BucketT *E,
const DebugEpochBase &Epoch,
const bool NoAdvance=false) const {
+ if (shouldReverseIterate<KeyT>()) {
+ const BucketT *B = P == getBucketsEnd() ? getBuckets() : P + 1;
+ return const_iterator(B, E, Epoch, NoAdvance);
+ }
return const_iterator(P, E, Epoch, NoAdvance);
}
@@ -679,7 +726,7 @@
unsigned NumBuckets;
public:
- /// Create a DenseMap wth an optional \p InitialReserve that guarantee that
+ /// Create a DenseMap with an optional \p InitialReserve that guarantee that
/// this number of elements can be inserted in the map without grow()
explicit DenseMap(unsigned InitialReserve = 0) { init(InitialReserve); }
@@ -706,7 +753,7 @@
~DenseMap() {
this->destroyAll();
- operator delete(Buckets);
+ deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
}
void swap(DenseMap& RHS) {
@@ -726,7 +773,7 @@
DenseMap& operator=(DenseMap &&other) {
this->destroyAll();
- operator delete(Buckets);
+ deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
init(0);
swap(other);
return *this;
@@ -734,7 +781,7 @@
void copyFrom(const DenseMap& other) {
this->destroyAll();
- operator delete(Buckets);
+ deallocate_buffer(Buckets, sizeof(BucketT) * NumBuckets, alignof(BucketT));
if (allocateBuckets(other.NumBuckets)) {
this->BaseT::copyFrom(other);
} else {
@@ -767,10 +814,12 @@
this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets);
// Free the old table.
- operator delete(OldBuckets);
+ deallocate_buffer(OldBuckets, sizeof(BucketT) * OldNumBuckets,
+ alignof(BucketT));
}
void shrink_and_clear() {
+ unsigned OldNumBuckets = NumBuckets;
unsigned OldNumEntries = NumEntries;
this->destroyAll();
@@ -783,7 +832,8 @@
return;
}
- operator delete(Buckets);
+ deallocate_buffer(Buckets, sizeof(BucketT) * OldNumBuckets,
+ alignof(BucketT));
init(NewNumBuckets);
}
@@ -819,7 +869,8 @@
return false;
}
- Buckets = static_cast<BucketT*>(operator new(sizeof(BucketT) * NumBuckets));
+ Buckets = static_cast<BucketT *>(
+ allocate_buffer(sizeof(BucketT) * NumBuckets, alignof(BucketT)));
return true;
}
};
@@ -874,6 +925,9 @@
this->insert(I, E);
}
+ SmallDenseMap(std::initializer_list<typename BaseT::value_type> Vals)
+ : SmallDenseMap(Vals.begin(), Vals.end()) {}
+
~SmallDenseMap() {
this->destroyAll();
deallocateBuckets();
@@ -904,7 +958,7 @@
std::swap(*LHSB, *RHSB);
continue;
}
- // Swap separately and handle any assymetry.
+ // Swap separately and handle any asymmetry.
std::swap(LHSB->getFirst(), RHSB->getFirst());
if (hasLHSValue) {
::new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond()));
@@ -986,16 +1040,13 @@
}
void grow(unsigned AtLeast) {
- if (AtLeast >= InlineBuckets)
+ if (AtLeast > InlineBuckets)
AtLeast = std::max<unsigned>(64, NextPowerOf2(AtLeast-1));
if (Small) {
- if (AtLeast < InlineBuckets)
- return; // Nothing to do.
-
// First move the inline buckets into a temporary storage.
AlignedCharArrayUnion<BucketT[InlineBuckets]> TmpStorage;
- BucketT *TmpBegin = reinterpret_cast<BucketT *>(TmpStorage.buffer);
+ BucketT *TmpBegin = reinterpret_cast<BucketT *>(&TmpStorage);
BucketT *TmpEnd = TmpBegin;
// Loop over the buckets, moving non-empty, non-tombstones into the
@@ -1015,10 +1066,13 @@
P->getFirst().~KeyT();
}
- // Now make this map use the large rep, and move all the entries back
- // into it.
- Small = false;
- new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
+ // AtLeast == InlineBuckets can happen if there are many tombstones,
+ // and grow() is used to remove them. Usually we always switch to the
+ // large rep here.
+ if (AtLeast > InlineBuckets) {
+ Small = false;
+ new (getLargeRep()) LargeRep(allocateBuckets(AtLeast));
+ }
this->moveFromOldBuckets(TmpBegin, TmpEnd);
return;
}
@@ -1034,7 +1088,8 @@
this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets);
// Free the old table.
- operator delete(OldRep.Buckets);
+ deallocate_buffer(OldRep.Buckets, sizeof(BucketT) * OldRep.NumBuckets,
+ alignof(BucketT));
}
void shrink_and_clear() {
@@ -1081,8 +1136,8 @@
assert(Small);
// Note that this cast does not violate aliasing rules as we assert that
// the memory's dynamic type is the small, inline bucket buffer, and the
- // 'storage.buffer' static type is 'char *'.
- return reinterpret_cast<const BucketT *>(storage.buffer);
+ // 'storage' is a POD containing a char buffer.
+ return reinterpret_cast<const BucketT *>(&storage);
}
BucketT *getInlineBuckets() {
@@ -1093,7 +1148,7 @@
const LargeRep *getLargeRep() const {
assert(!Small);
// Note, same rule about aliasing as with getInlineBuckets.
- return reinterpret_cast<const LargeRep *>(storage.buffer);
+ return reinterpret_cast<const LargeRep *>(&storage);
}
LargeRep *getLargeRep() {
@@ -1118,15 +1173,17 @@
if (Small)
return;
- operator delete(getLargeRep()->Buckets);
+ deallocate_buffer(getLargeRep()->Buckets,
+ sizeof(BucketT) * getLargeRep()->NumBuckets,
+ alignof(BucketT));
getLargeRep()->~LargeRep();
}
LargeRep allocateBuckets(unsigned Num) {
assert(Num > InlineBuckets && "Must allocate more buckets than are inline");
- LargeRep Rep = {
- static_cast<BucketT*>(operator new(sizeof(BucketT) * Num)), Num
- };
+ LargeRep Rep = {static_cast<BucketT *>(allocate_buffer(
+ sizeof(BucketT) * Num, alignof(BucketT))),
+ Num};
return Rep;
}
};
@@ -1137,8 +1194,6 @@
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
friend class DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, false>;
- using ConstIterator = DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, true>;
-
public:
using difference_type = ptrdiff_t;
using value_type =
@@ -1160,6 +1215,10 @@
assert(isHandleInSync() && "invalid construction!");
if (NoAdvance) return;
+ if (shouldReverseIterate<KeyT>()) {
+ RetreatPastEmptyBuckets();
+ return;
+ }
AdvancePastEmptyBuckets();
}
@@ -1167,37 +1226,48 @@
// for const iterator destinations so it doesn't end up as a user defined copy
// constructor.
template <bool IsConstSrc,
- typename = typename std::enable_if<!IsConstSrc && IsConst>::type>
+ typename = std::enable_if_t<!IsConstSrc && IsConst>>
DenseMapIterator(
const DenseMapIterator<KeyT, ValueT, KeyInfoT, Bucket, IsConstSrc> &I)
: DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {}
reference operator*() const {
assert(isHandleInSync() && "invalid iterator access!");
+ assert(Ptr != End && "dereferencing end() iterator");
+ if (shouldReverseIterate<KeyT>())
+ return Ptr[-1];
return *Ptr;
}
pointer operator->() const {
assert(isHandleInSync() && "invalid iterator access!");
+ assert(Ptr != End && "dereferencing end() iterator");
+ if (shouldReverseIterate<KeyT>())
+ return &(Ptr[-1]);
return Ptr;
}
- bool operator==(const ConstIterator &RHS) const {
- assert((!Ptr || isHandleInSync()) && "handle not in sync!");
+ friend bool operator==(const DenseMapIterator &LHS,
+ const DenseMapIterator &RHS) {
+ assert((!LHS.Ptr || LHS.isHandleInSync()) && "handle not in sync!");
assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
- assert(getEpochAddress() == RHS.getEpochAddress() &&
+ assert(LHS.getEpochAddress() == RHS.getEpochAddress() &&
"comparing incomparable iterators!");
- return Ptr == RHS.Ptr;
+ return LHS.Ptr == RHS.Ptr;
}
- bool operator!=(const ConstIterator &RHS) const {
- assert((!Ptr || isHandleInSync()) && "handle not in sync!");
- assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!");
- assert(getEpochAddress() == RHS.getEpochAddress() &&
- "comparing incomparable iterators!");
- return Ptr != RHS.Ptr;
+
+ friend bool operator!=(const DenseMapIterator &LHS,
+ const DenseMapIterator &RHS) {
+ return !(LHS == RHS);
}
inline DenseMapIterator& operator++() { // Preincrement
assert(isHandleInSync() && "invalid iterator access!");
+ assert(Ptr != End && "incrementing end() iterator");
+ if (shouldReverseIterate<KeyT>()) {
+ --Ptr;
+ RetreatPastEmptyBuckets();
+ return *this;
+ }
++Ptr;
AdvancePastEmptyBuckets();
return *this;
@@ -1236,4 +1306,4 @@
} // end namespace wpi
-#endif // LLVM_ADT_DENSEMAP_H
+#endif // WPIUTIL_WPI_DENSEMAP_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
new file mode 100644
index 0000000..0ff8fc9
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/DenseMapInfo.h
@@ -0,0 +1,293 @@
+//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- 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.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_DENSEMAPINFO_H
+#define WPIUTIL_WPI_DENSEMAPINFO_H
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <tuple>
+#include <utility>
+
+namespace wpi {
+
+namespace detail {
+
+/// Simplistic combination of 32-bit hash values into 32-bit hash values.
+static inline unsigned combineHashValue(unsigned a, unsigned b) {
+ uint64_t key = (uint64_t)a << 32 | (uint64_t)b;
+ key += ~(key << 32);
+ key ^= (key >> 22);
+ key += ~(key << 13);
+ key ^= (key >> 8);
+ key += (key << 3);
+ key ^= (key >> 15);
+ key += ~(key << 27);
+ key ^= (key >> 31);
+ return (unsigned)key;
+}
+
+} // end namespace detail
+
+/// An information struct used to provide DenseMap with the various necessary
+/// components for a given value type `T`. `Enable` is an optional additional
+/// parameter that is used to support SFINAE (generally using std::enable_if_t)
+/// in derived DenseMapInfo specializations; in non-SFINAE use cases this should
+/// just be `void`.
+template<typename T, typename Enable = void>
+struct DenseMapInfo {
+ //static inline T getEmptyKey();
+ //static inline T getTombstoneKey();
+ //static unsigned getHashValue(const T &Val);
+ //static bool isEqual(const T &LHS, const T &RHS);
+};
+
+// Provide DenseMapInfo for all pointers. Come up with sentinel pointer values
+// that are aligned to alignof(T) bytes, but try to avoid requiring T to be
+// complete. This allows clients to instantiate DenseMap<T*, ...> with forward
+// declared key types. Assume that no pointer key type requires more than 4096
+// bytes of alignment.
+template<typename T>
+struct DenseMapInfo<T*> {
+ // The following should hold, but it would require T to be complete:
+ // static_assert(alignof(T) <= (1 << Log2MaxAlign),
+ // "DenseMap does not support pointer keys requiring more than "
+ // "Log2MaxAlign bits of alignment");
+ static constexpr uintptr_t Log2MaxAlign = 12;
+
+ static inline T* getEmptyKey() {
+ uintptr_t Val = static_cast<uintptr_t>(-1);
+ Val <<= Log2MaxAlign;
+ return reinterpret_cast<T*>(Val);
+ }
+
+ static inline T* getTombstoneKey() {
+ uintptr_t Val = static_cast<uintptr_t>(-2);
+ Val <<= Log2MaxAlign;
+ return reinterpret_cast<T*>(Val);
+ }
+
+ static unsigned getHashValue(const T *PtrVal) {
+ return (unsigned((uintptr_t)PtrVal) >> 4) ^
+ (unsigned((uintptr_t)PtrVal) >> 9);
+ }
+
+ static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; }
+};
+
+// Provide DenseMapInfo for chars.
+template<> struct DenseMapInfo<char> {
+ static inline char getEmptyKey() { return ~0; }
+ static inline char getTombstoneKey() { return ~0 - 1; }
+ static unsigned getHashValue(const char& Val) { return Val * 37U; }
+
+ static bool isEqual(const char &LHS, const char &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for unsigned chars.
+template <> struct DenseMapInfo<unsigned char> {
+ static inline unsigned char getEmptyKey() { return ~0; }
+ static inline unsigned char getTombstoneKey() { return ~0 - 1; }
+ static unsigned getHashValue(const unsigned char &Val) { return Val * 37U; }
+
+ static bool isEqual(const unsigned char &LHS, const unsigned char &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for unsigned shorts.
+template <> struct DenseMapInfo<unsigned short> {
+ static inline unsigned short getEmptyKey() { return 0xFFFF; }
+ static inline unsigned short getTombstoneKey() { return 0xFFFF - 1; }
+ static unsigned getHashValue(const unsigned short &Val) { return Val * 37U; }
+
+ static bool isEqual(const unsigned short &LHS, const unsigned short &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for unsigned ints.
+template<> struct DenseMapInfo<unsigned> {
+ static inline unsigned getEmptyKey() { return ~0U; }
+ static inline unsigned getTombstoneKey() { return ~0U - 1; }
+ static unsigned getHashValue(const unsigned& Val) { return Val * 37U; }
+
+ static bool isEqual(const unsigned& LHS, const unsigned& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for unsigned longs.
+template<> struct DenseMapInfo<unsigned long> {
+ static inline unsigned long getEmptyKey() { return ~0UL; }
+ static inline unsigned long getTombstoneKey() { return ~0UL - 1L; }
+
+ static unsigned getHashValue(const unsigned long& Val) {
+ return (unsigned)(Val * 37UL);
+ }
+
+ static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for unsigned long longs.
+template<> struct DenseMapInfo<unsigned long long> {
+ static inline unsigned long long getEmptyKey() { return ~0ULL; }
+ static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; }
+
+ static unsigned getHashValue(const unsigned long long& Val) {
+ return (unsigned)(Val * 37ULL);
+ }
+
+ static bool isEqual(const unsigned long long& LHS,
+ const unsigned long long& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for shorts.
+template <> struct DenseMapInfo<short> {
+ static inline short getEmptyKey() { return 0x7FFF; }
+ static inline short getTombstoneKey() { return -0x7FFF - 1; }
+ static unsigned getHashValue(const short &Val) { return Val * 37U; }
+ static bool isEqual(const short &LHS, const short &RHS) { return LHS == RHS; }
+};
+
+// Provide DenseMapInfo for ints.
+template<> struct DenseMapInfo<int> {
+ static inline int getEmptyKey() { return 0x7fffffff; }
+ static inline int getTombstoneKey() { return -0x7fffffff - 1; }
+ static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); }
+
+ static bool isEqual(const int& LHS, const int& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for longs.
+template<> struct DenseMapInfo<long> {
+ static inline long getEmptyKey() {
+ return (1UL << (sizeof(long) * 8 - 1)) - 1UL;
+ }
+
+ static inline long getTombstoneKey() { return getEmptyKey() - 1L; }
+
+ static unsigned getHashValue(const long& Val) {
+ return (unsigned)(Val * 37UL);
+ }
+
+ static bool isEqual(const long& LHS, const long& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for long longs.
+template<> struct DenseMapInfo<long long> {
+ static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; }
+ static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; }
+
+ static unsigned getHashValue(const long long& Val) {
+ return (unsigned)(Val * 37ULL);
+ }
+
+ static bool isEqual(const long long& LHS,
+ const long long& RHS) {
+ return LHS == RHS;
+ }
+};
+
+// Provide DenseMapInfo for all pairs whose members have info.
+template<typename T, typename U>
+struct DenseMapInfo<std::pair<T, U>> {
+ using Pair = std::pair<T, U>;
+ using FirstInfo = DenseMapInfo<T>;
+ using SecondInfo = DenseMapInfo<U>;
+
+ static inline Pair getEmptyKey() {
+ return std::make_pair(FirstInfo::getEmptyKey(),
+ SecondInfo::getEmptyKey());
+ }
+
+ static inline Pair getTombstoneKey() {
+ return std::make_pair(FirstInfo::getTombstoneKey(),
+ SecondInfo::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const Pair& PairVal) {
+ return detail::combineHashValue(FirstInfo::getHashValue(PairVal.first),
+ SecondInfo::getHashValue(PairVal.second));
+ }
+
+ static bool isEqual(const Pair &LHS, const Pair &RHS) {
+ return FirstInfo::isEqual(LHS.first, RHS.first) &&
+ SecondInfo::isEqual(LHS.second, RHS.second);
+ }
+};
+
+// Provide DenseMapInfo for all tuples whose members have info.
+template <typename... Ts> struct DenseMapInfo<std::tuple<Ts...>> {
+ using Tuple = std::tuple<Ts...>;
+
+ static inline Tuple getEmptyKey() {
+ return Tuple(DenseMapInfo<Ts>::getEmptyKey()...);
+ }
+
+ static inline Tuple getTombstoneKey() {
+ return Tuple(DenseMapInfo<Ts>::getTombstoneKey()...);
+ }
+
+ template <unsigned I>
+ static unsigned getHashValueImpl(const Tuple &values, std::false_type) {
+ using EltType = typename std::tuple_element<I, Tuple>::type;
+ std::integral_constant<bool, I + 1 == sizeof...(Ts)> atEnd;
+ return detail::combineHashValue(
+ DenseMapInfo<EltType>::getHashValue(std::get<I>(values)),
+ getHashValueImpl<I + 1>(values, atEnd));
+ }
+
+ template <unsigned I>
+ static unsigned getHashValueImpl(const Tuple &, std::true_type) {
+ return 0;
+ }
+
+ static unsigned getHashValue(const std::tuple<Ts...> &values) {
+ std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
+ return getHashValueImpl<0>(values, atEnd);
+ }
+
+ template <unsigned I>
+ static bool isEqualImpl(const Tuple &lhs, const Tuple &rhs, std::false_type) {
+ using EltType = typename std::tuple_element<I, Tuple>::type;
+ 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);
+ }
+
+ template <unsigned I>
+ static bool isEqualImpl(const Tuple &, const Tuple &, std::true_type) {
+ return true;
+ }
+
+ static bool isEqual(const Tuple &lhs, const Tuple &rhs) {
+ std::integral_constant<bool, 0 == sizeof...(Ts)> atEnd;
+ return isEqualImpl<0>(lhs, rhs, atEnd);
+ }
+};
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_DENSEMAPINFO_H
diff --git a/wpiutil/src/main/native/include/wpi/Endian.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
similarity index 85%
rename from wpiutil/src/main/native/include/wpi/Endian.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
index b31cb2d..d243a13 100644
--- a/wpiutil/src/main/native/include/wpi/Endian.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Endian.h
@@ -1,9 +1,8 @@
//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -14,14 +13,8 @@
#ifndef WPIUTIL_WPI_ENDIAN_H
#define WPIUTIL_WPI_ENDIAN_H
-#include "wpi/AlignOf.h"
#include "wpi/Compiler.h"
#include "wpi/SwapByteOrder.h"
-
-#if defined(__linux__) || defined(__GNU__)
-#include <endian.h>
-#endif
-
#include <cassert>
#include <cstddef>
#include <cstdint>
@@ -38,7 +31,7 @@
namespace detail {
-// value is either alignment, or alignof(T) if alignment is 0.
+/// ::value is either alignment, or alignof(T) if alignment is 0.
template<class T, int alignment>
struct PickAlignment {
enum { value = alignment == 0 ? alignof(T) : alignment };
@@ -49,13 +42,7 @@
namespace endian {
constexpr endianness system_endianness() {
-#ifdef _WIN32
- return little;
-#elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
- return big;
-#else
- return little;
-#endif
+ return sys::IsBigEndianHost ? big : little;
}
template <typename value_type>
@@ -89,13 +76,7 @@
endianness endian,
std::size_t alignment>
inline value_type read(const void *memory) {
- value_type ret;
-
- memcpy(&ret,
- LLVM_ASSUME_ALIGNED(
- memory, (detail::PickAlignment<value_type, alignment>::value)),
- sizeof(value_type));
- return byte_swap<value_type, endian>(ret);
+ return read<value_type, alignment>(memory, endian);
}
/// Read a value of a particular endianness from a buffer, and increment the
@@ -110,9 +91,7 @@
template<typename value_type, endianness endian, std::size_t alignment,
typename CharT>
inline value_type readNext(const CharT *&memory) {
- value_type ret = read<value_type, endian, alignment>(memory);
- memory += sizeof(value_type);
- return ret;
+ return readNext<value_type, alignment, CharT>(memory, endian);
}
/// Write a value to memory with a particular endianness.
@@ -128,12 +107,12 @@
endianness endian,
std::size_t alignment>
inline void write(void *memory, value_type value) {
- value = byte_swap<value_type, endian>(value);
- memcpy(LLVM_ASSUME_ALIGNED(
- memory, (detail::PickAlignment<value_type, alignment>::value)),
- &value, sizeof(value_type));
+ write<value_type, alignment>(memory, value, endian);
}
+template <typename value_type>
+using make_unsigned_t = std::make_unsigned_t<value_type>;
+
/// Read a value of a particular endianness from memory, for a location
/// that starts at the given bit offset within the first byte.
template <typename value_type, endianness endian, std::size_t alignment>
@@ -152,15 +131,15 @@
val[1] = byte_swap<value_type, endian>(val[1]);
// Shift bits from the lower value into place.
- std::make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
+ make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
// Mask off upper bits after right shift in case of signed type.
- std::make_unsigned_t<value_type> numBitsFirstVal =
+ make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
- lowerVal &= ((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
+ lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
// Get the bits from the upper value.
- std::make_unsigned_t<value_type> upperVal =
- val[1] & (((std::make_unsigned_t<value_type>)1 << startBit) - 1);
+ make_unsigned_t<value_type> upperVal =
+ val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
// Shift them in to place.
upperVal <<= numBitsFirstVal;
@@ -188,15 +167,15 @@
// Mask off any existing bits in the upper part of the lower value that
// we want to replace.
- val[0] &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
- std::make_unsigned_t<value_type> numBitsFirstVal =
+ val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
+ make_unsigned_t<value_type> numBitsFirstVal =
(sizeof(value_type) * 8) - startBit;
- std::make_unsigned_t<value_type> lowerVal = value;
+ make_unsigned_t<value_type> lowerVal = value;
if (startBit > 0) {
// Mask off the upper bits in the new value that are not going to go into
// the lower value. This avoids a left shift of a negative value, which
// is undefined behavior.
- lowerVal &= (((std::make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
+ lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
// Now shift the new bits into place
lowerVal <<= startBit;
}
@@ -204,11 +183,11 @@
// Mask off any existing bits in the lower part of the upper value that
// we want to replace.
- val[1] &= ~(((std::make_unsigned_t<value_type>)1 << startBit) - 1);
+ val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
// Next shift the bits that go into the upper value into position.
- std::make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
+ make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
// Mask off upper bits after right shift in case of signed type.
- upperVal &= ((std::make_unsigned_t<value_type>)1 << startBit) - 1;
+ upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
val[1] |= upperVal;
// Finally, rewrite values.
@@ -224,10 +203,13 @@
namespace detail {
-template<typename value_type,
- endianness endian,
- std::size_t alignment>
+template <typename ValueType, endianness Endian, std::size_t Alignment,
+ std::size_t ALIGN = PickAlignment<ValueType, Alignment>::value>
struct packed_endian_specific_integral {
+ using value_type = ValueType;
+ static constexpr endianness endian = Endian;
+ static constexpr std::size_t alignment = Alignment;
+
packed_endian_specific_integral() = default;
explicit packed_endian_specific_integral(value_type val) { *this = val; }
@@ -263,8 +245,9 @@
}
private:
- AlignedCharArray<PickAlignment<value_type, alignment>::value,
- sizeof(value_type)> Value;
+ struct {
+ alignas(ALIGN) char buffer[sizeof(value_type)];
+ } Value;
public:
struct ref {
@@ -355,6 +338,17 @@
using unaligned_int64_t =
detail::packed_endian_specific_integral<int64_t, native, unaligned>;
+template <typename T>
+using little_t = detail::packed_endian_specific_integral<T, little, unaligned>;
+template <typename T>
+using big_t = detail::packed_endian_specific_integral<T, big, unaligned>;
+
+template <typename T>
+using aligned_little_t =
+ detail::packed_endian_specific_integral<T, little, aligned>;
+template <typename T>
+using aligned_big_t = detail::packed_endian_specific_integral<T, big, aligned>;
+
namespace endian {
template <typename T> inline T read(const void *P, endianness E) {
diff --git a/wpiutil/src/main/native/include/wpi/EpochTracker.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
similarity index 83%
rename from wpiutil/src/main/native/include/wpi/EpochTracker.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
index b26800b..6417c05 100644
--- a/wpiutil/src/main/native/include/wpi/EpochTracker.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/EpochTracker.h
@@ -1,41 +1,27 @@
//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 DebugEpochBase and DebugEpochBase::HandleBase classes.
-// These can be used to write iterators that are fail-fast when LLVM is built
-// with asserts enabled.
-//
+///
+/// \file
+/// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes.
+/// These can be used to write iterators that are fail-fast when LLVM is built
+/// with asserts enabled.
+///
//===----------------------------------------------------------------------===//
-#ifndef WPIUTIL_WPI_EPOCH_TRACKER_H
-#define WPIUTIL_WPI_EPOCH_TRACKER_H
+#ifndef WPIUTIL_WPI_EPOCHTRACKER_H
+#define WPIUTIL_WPI_EPOCHTRACKER_H
+
#include <cstdint>
namespace wpi {
-#ifdef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
-
-class DebugEpochBase {
-public:
- void incrementEpoch() {}
-
- class HandleBase {
- public:
- HandleBase() = default;
- explicit HandleBase(const DebugEpochBase *) {}
- bool isHandleInSync() const { return true; }
- const void *getEpochAddress() const { return nullptr; }
- };
-};
-
-#else
+#ifndef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS
/// A base class for data structure classes wishing to make iterators
/// ("handles") pointing into themselves fail-fast. When building without
@@ -90,6 +76,21 @@
};
};
+#else
+
+class DebugEpochBase {
+public:
+ void incrementEpoch() {}
+
+ class HandleBase {
+ public:
+ HandleBase() = default;
+ explicit HandleBase(const DebugEpochBase *) {}
+ bool isHandleInSync() const { return true; }
+ const void *getEpochAddress() const { return nullptr; }
+ };
+};
+
#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/Errc.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
similarity index 88%
rename from wpiutil/src/main/native/include/wpi/Errc.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
index ebce58a..dee28df 100644
--- a/wpiutil/src/main/native/include/wpi/Errc.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errc.h
@@ -1,9 +1,8 @@
-//===- llvm/Support/Errc.h - Defines the llvm::errc enum --------*- C++ -*-===//
+//===- llvm/Support/Errc.h - Defines the wpi::errc enum --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -11,7 +10,7 @@
// some problems with std::errc that can be avoided by using our own
// enumeration:
//
-// * std::errc is a namespace in some implementations. That meas that ADL
+// * std::errc is a namespace in some implementations. That means that ADL
// doesn't work and it is sometimes necessary to write std::make_error_code
// or in templates:
// using std::make_error_code;
@@ -23,7 +22,7 @@
// the intersection of all the ones we support.
//
// * std::errc is just marked with is_error_condition_enum. This means that
-// common patters like AnErrorCode == errc::no_such_file_or_directory take
+// common patterns like AnErrorCode == errc::no_such_file_or_directory take
// 4 virtual calls instead of two comparisons.
//===----------------------------------------------------------------------===//
diff --git a/wpiutil/src/main/native/include/wpi/Errno.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
similarity index 66%
rename from wpiutil/src/main/native/include/wpi/Errno.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
index 042d432..febfc37 100644
--- a/wpiutil/src/main/native/include/wpi/Errno.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Errno.h
@@ -1,9 +1,8 @@
//===- llvm/Support/Errno.h - Portable+convenient errno handling -*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -22,8 +21,8 @@
namespace sys {
template <typename FailT, typename Fun, typename... Args>
-inline auto RetryAfterSignal(const FailT &Fail, const Fun &F,
- const Args &... As) -> decltype(F(As...)) {
+inline decltype(auto) RetryAfterSignal(const FailT &Fail, const Fun &F,
+ const Args &... As) {
decltype(F(As...)) Res;
do {
errno = 0;
@@ -35,4 +34,4 @@
} // namespace sys
} // namespace wpi
-#endif // WPIUTIL_WPI_ERRNO_H
+#endif // WPIUTIL_WPI_ERRNO_H
diff --git a/wpiutil/src/main/native/include/wpi/ErrorHandling.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
similarity index 79%
rename from wpiutil/src/main/native/include/wpi/ErrorHandling.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
index da9af4b..7b43671 100644
--- a/wpiutil/src/main/native/include/wpi/ErrorHandling.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ErrorHandling.h
@@ -1,9 +1,8 @@
//===- llvm/Support/ErrorHandling.h - Fatal error handling ------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -20,9 +19,10 @@
#include <string_view>
namespace wpi {
+
/// An error handler callback.
typedef void (*fatal_error_handler_t)(void *user_data,
- const std::string& reason,
+ const char *reason,
bool gen_crash_diag);
/// install_fatal_error_handler - Installs a new error handler to be used
@@ -65,14 +65,14 @@
///
/// If no error handler is installed the default is to print the message to
/// standard error, followed by a newline.
-/// After the error handler is called this function will call exit(1), it
+/// After the error handler is called this function will call abort(), it
/// does not return.
-LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const char *reason,
- bool gen_crash_diag = true);
-LLVM_ATTRIBUTE_NORETURN void report_fatal_error(const std::string &reason,
- bool gen_crash_diag = true);
-LLVM_ATTRIBUTE_NORETURN void report_fatal_error(std::string_view reason,
- bool gen_crash_diag = true);
+[[noreturn]] void report_fatal_error(const char *reason,
+ bool gen_crash_diag = true);
+[[noreturn]] void report_fatal_error(const std::string &reason,
+ bool gen_crash_diag = true);
+[[noreturn]] void report_fatal_error(std::string_view reason,
+ bool gen_crash_diag = true);
/// Installs a new bad alloc error handler that should be used whenever a
/// bad alloc error, e.g. failing malloc/calloc, is encountered by LLVM.
@@ -100,31 +100,32 @@
/// Reports a bad alloc error, calling any user defined bad alloc
/// error handler. In contrast to the generic 'report_fatal_error'
-/// functions, this function is expected to return, e.g. the user
-/// defined error handler throws an exception.
+/// functions, this function might not terminate, e.g. the user
+/// defined error handler throws an exception, but it won't return.
///
/// Note: When throwing an exception in the bad alloc handler, make sure that
/// the following unwind succeeds, e.g. do not trigger additional allocations
/// in the unwind chain.
///
-/// If no error handler is installed (default), then a bad_alloc exception
-/// is thrown, if LLVM is compiled with exception support, otherwise an
-/// assertion is called.
-void report_bad_alloc_error(const char *Reason, bool GenCrashDiag = true);
+/// If no error handler is installed (default), throws a bad_alloc exception
+/// if LLVM is compiled with exception support. Otherwise prints the error
+/// to standard error and calls abort().
+[[noreturn]] void report_bad_alloc_error(const char *Reason,
+ bool GenCrashDiag = true);
/// This function calls abort(), and prints the optional message to stderr.
/// Use the wpi_unreachable macro (that adds location info), instead of
/// calling this function directly.
-LLVM_ATTRIBUTE_NORETURN void
+[[noreturn]] void
wpi_unreachable_internal(const char *msg = nullptr, const char *file = nullptr,
- unsigned line = 0);
+ unsigned line = 0);
}
/// 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.
+/// such hints, prints a reduced message instead and aborts the program.
///
/// Use this instead of assert(0). It conveys intent more clearly and
/// allows compilers to omit some unnecessary code.
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
new file mode 100644
index 0000000..681b87e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/FunctionExtras.h
@@ -0,0 +1,427 @@
+//===- FunctionExtras.h - Function type erasure 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file provides a collection of function (or more generally, callable)
+/// type erasure utilities supplementing those provided by the standard library
+/// in `<function>`.
+///
+/// It provides `unique_function`, which works like `std::function` but supports
+/// move-only callable objects and const-qualification.
+///
+/// Future plans:
+/// - Add a `function` that provides ref-qualified support, which doesn't work
+/// with `std::function`.
+/// - Provide support for specifying multiple signatures to type erase callable
+/// objects with an overload set, such as those produced by generic lambdas.
+/// - Expand to include a copyable utility that directly replaces std::function
+/// but brings the above improvements.
+///
+/// Note that LLVM's utilities are greatly simplified by not supporting
+/// allocators.
+///
+/// If the standard library ever begins to provide comparable facilities we can
+/// consider switching to those.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_FUNCTIONEXTRAS_H
+#define WPIUTIL_WPI_FUNCTIONEXTRAS_H
+
+#include "wpi/PointerIntPair.h"
+#include "wpi/PointerUnion.h"
+#include "wpi/STLForwardCompat.h"
+#include "wpi/MemAlloc.h"
+#include "wpi/type_traits.h"
+#include <cstring>
+#include <memory>
+#include <type_traits>
+
+namespace wpi {
+
+/// unique_function is a type-erasing functor similar to std::function.
+///
+/// It can hold move-only function objects, like lambdas capturing unique_ptrs.
+/// Accordingly, it is movable but not copyable.
+///
+/// It supports const-qualification:
+/// - unique_function<int() const> has a const operator().
+/// It can only hold functions which themselves have a const operator().
+/// - unique_function<int()> has a non-const operator().
+/// It can hold functions with a non-const operator(), like mutable lambdas.
+template <typename FunctionT> class unique_function;
+
+// GCC warns on OutOfLineStorage
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warray-bounds"
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+namespace detail {
+
+template <typename T>
+using EnableIfTrivial =
+ std::enable_if_t<wpi::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<
+ std::is_void<Ret>,
+ std::is_same<decltype(std::declval<CallableT>()(std::declval<Params>()...)),
+ Ret>,
+ std::is_same<const decltype(std::declval<CallableT>()(
+ std::declval<Params>()...)),
+ Ret>,
+ std::is_convertible<decltype(std::declval<CallableT>()(
+ std::declval<Params>()...)),
+ Ret>>::value>;
+
+template <typename ReturnT, typename... ParamTs> class UniqueFunctionBase {
+protected:
+ static constexpr size_t InlineStorageSize = sizeof(void *) * 4;
+
+ template <typename T, class = void>
+ struct IsSizeLessThanThresholdT : std::false_type {};
+
+ template <typename T>
+ struct IsSizeLessThanThresholdT<
+ T, std::enable_if_t<sizeof(T) <= 2 * sizeof(void *)>> : std::true_type {};
+
+ // Provide a type function to map parameters that won't observe extra copies
+ // or moves and which are small enough to likely pass in register to values
+ // and all other types to l-value reference types. We use this to compute the
+ // types used in our erased call utility to minimize copies and moves unless
+ // doing so would force things unnecessarily into memory.
+ //
+ // The heuristic used is related to common ABI register passing conventions.
+ // It doesn't have to be exact though, and in one way it is more strict
+ // because we want to still be able to observe either moves *or* copies.
+ 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;
+ };
+
+ // This specialization ensures that 'AdjustedParam<V<T>&>' or
+ // 'AdjustedParam<V<T>&&>' does not trigger a compile-time error when 'T' is
+ // an incomplete type and V a templated type.
+ template <typename T> struct AdjustedParamTBase<T &> { using type = T &; };
+ template <typename T> struct AdjustedParamTBase<T &&> { using type = T &; };
+
+ template <typename T>
+ using AdjustedParamT = typename AdjustedParamTBase<T>::type;
+
+ // The type of the erased function pointer we use as a callback to dispatch to
+ // the stored callable when it is trivial to move and destroy.
+ using CallPtrT = ReturnT (*)(void *CallableAddr,
+ AdjustedParamT<ParamTs>... Params);
+ using MovePtrT = void (*)(void *LHSCallableAddr, void *RHSCallableAddr);
+ using DestroyPtrT = void (*)(void *CallableAddr);
+
+ /// A struct to hold a single trivial callback with sufficient alignment for
+ /// our bitpacking.
+ struct alignas(8) TrivialCallback {
+ CallPtrT CallPtr;
+ };
+
+ /// A struct we use to aggregate three callbacks when we need full set of
+ /// operations.
+ struct alignas(8) NonTrivialCallbacks {
+ CallPtrT CallPtr;
+ MovePtrT MovePtr;
+ DestroyPtrT DestroyPtr;
+ };
+
+ // Create a pointer union between either a pointer to a static trivial call
+ // pointer in a struct or a pointer to a static struct of the call, move, and
+ // destroy pointers.
+ using CallbackPointerUnionT =
+ PointerUnion<TrivialCallback *, NonTrivialCallbacks *>;
+
+ // The main storage buffer. This will either have a pointer to out-of-line
+ // storage or an inline buffer storing the callable.
+ union StorageUnionT {
+ // For out-of-line storage we keep a pointer to the underlying storage and
+ // the size. This is enough to deallocate the memory.
+ struct OutOfLineStorageT {
+ void *StoragePtr;
+ size_t Size;
+ size_t Alignment;
+ } OutOfLineStorage;
+ static_assert(
+ sizeof(OutOfLineStorageT) <= InlineStorageSize,
+ "Should always use all of the out-of-line storage for inline storage!");
+
+ // For in-line storage, we just provide an aligned character buffer. We
+ // 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;
+ } StorageUnion;
+
+ // A compressed pointer to either our dispatching callback or our table of
+ // dispatching callbacks and the flag for whether the callable itself is
+ // stored inline or not.
+ PointerIntPair<CallbackPointerUnionT, 1, bool> CallbackAndInlineFlag;
+
+ bool isInlineStorage() const { return CallbackAndInlineFlag.getInt(); }
+
+ bool isTrivialCallback() const {
+ return CallbackAndInlineFlag.getPointer().template is<TrivialCallback *>();
+ }
+
+ CallPtrT getTrivialCallback() const {
+ return CallbackAndInlineFlag.getPointer().template get<TrivialCallback *>()->CallPtr;
+ }
+
+ NonTrivialCallbacks *getNonTrivialCallbacks() const {
+ return CallbackAndInlineFlag.getPointer()
+ .template get<NonTrivialCallbacks *>();
+ }
+
+ CallPtrT getCallPtr() const {
+ return isTrivialCallback() ? getTrivialCallback()
+ : getNonTrivialCallbacks()->CallPtr;
+ }
+
+ // These three functions are only const in the narrow sense. They return
+ // mutable pointers to function state.
+ // This allows unique_function<T const>::operator() to be const, even if the
+ // underlying functor may be internally mutable.
+ //
+ // const callers must ensure they're only used in const-correct ways.
+ void *getCalleePtr() const {
+ return isInlineStorage() ? getInlineStorage() : getOutOfLineStorage();
+ }
+ void *getInlineStorage() const { return &StorageUnion.InlineStorage; }
+ void *getOutOfLineStorage() const {
+ return StorageUnion.OutOfLineStorage.StoragePtr;
+ }
+
+ size_t getOutOfLineStorageSize() const {
+ return StorageUnion.OutOfLineStorage.Size;
+ }
+ size_t getOutOfLineStorageAlignment() const {
+ return StorageUnion.OutOfLineStorage.Alignment;
+ }
+
+ void setOutOfLineStorage(void *Ptr, size_t Size, size_t Alignment) {
+ StorageUnion.OutOfLineStorage = {Ptr, Size, Alignment};
+ }
+
+ template <typename CalledAsT>
+ static ReturnT CallImpl(void *CallableAddr,
+ AdjustedParamT<ParamTs>... Params) {
+ auto &Func = *reinterpret_cast<CalledAsT *>(CallableAddr);
+ return Func(std::forward<ParamTs>(Params)...);
+ }
+
+ template <typename CallableT>
+ static void MoveImpl(void *LHSCallableAddr, void *RHSCallableAddr) noexcept {
+ new (LHSCallableAddr)
+ CallableT(std::move(*reinterpret_cast<CallableT *>(RHSCallableAddr)));
+ }
+
+ template <typename CallableT>
+ static void DestroyImpl(void *CallableAddr) noexcept {
+ reinterpret_cast<CallableT *>(CallableAddr)->~CallableT();
+ }
+
+ // The pointers to call/move/destroy functions are determined for each
+ // callable type (and called-as type, which determines the overload chosen).
+ // (definitions are out-of-line).
+
+ // By default, we need an object that contains all the different
+ // type erased behaviors needed. Create a static instance of the struct type
+ // here and each instance will contain a pointer to it.
+ // Wrap in a struct to avoid https://gcc.gnu.org/PR71954
+ template <typename CallableT, typename CalledAs, typename Enable = void>
+ struct CallbacksHolder {
+ static NonTrivialCallbacks Callbacks;
+ };
+ // See if we can create a trivial callback. We need the callable to be
+ // trivially moved and trivially destroyed so that we don't have to store
+ // type erased callbacks for those operations.
+ template <typename CallableT, typename CalledAs>
+ struct CallbacksHolder<CallableT, CalledAs, EnableIfTrivial<CallableT>> {
+ static TrivialCallback Callbacks;
+ };
+
+ // A simple tag type so the call-as type to be passed to the constructor.
+ template <typename T> struct CalledAs {};
+
+ // Essentially the "main" unique_function constructor, but subclasses
+ // provide the qualified type to be used for the call.
+ // (We always store a T, even if the call will use a pointer to const T).
+ template <typename CallableT, typename CalledAsT>
+ UniqueFunctionBase(CallableT Callable, CalledAs<CalledAsT>) {
+ bool IsInlineStorage = true;
+ void *CallableAddr = getInlineStorage();
+ if (sizeof(CallableT) > InlineStorageSize ||
+ alignof(CallableT) > alignof(decltype(StorageUnion.InlineStorage))) {
+ IsInlineStorage = false;
+ // Allocate out-of-line storage. FIXME: Use an explicit alignment
+ // parameter in C++17 mode.
+ auto Size = sizeof(CallableT);
+ auto Alignment = alignof(CallableT);
+ CallableAddr = allocate_buffer(Size, Alignment);
+ setOutOfLineStorage(CallableAddr, Size, Alignment);
+ }
+
+ // Now move into the storage.
+ new (CallableAddr) CallableT(std::move(Callable));
+ CallbackAndInlineFlag.setPointerAndInt(
+ &CallbacksHolder<CallableT, CalledAsT>::Callbacks, IsInlineStorage);
+ }
+
+ ~UniqueFunctionBase() {
+ if (!CallbackAndInlineFlag.getPointer())
+ return;
+
+ // Cache this value so we don't re-check it after type-erased operations.
+ bool IsInlineStorage = isInlineStorage();
+
+ if (!isTrivialCallback())
+ getNonTrivialCallbacks()->DestroyPtr(
+ IsInlineStorage ? getInlineStorage() : getOutOfLineStorage());
+
+ if (!IsInlineStorage)
+ deallocate_buffer(getOutOfLineStorage(), getOutOfLineStorageSize(),
+ getOutOfLineStorageAlignment());
+ }
+
+ UniqueFunctionBase(UniqueFunctionBase &&RHS) noexcept {
+ // Copy the callback and inline flag.
+ CallbackAndInlineFlag = RHS.CallbackAndInlineFlag;
+
+ // If the RHS is empty, just copying the above is sufficient.
+ if (!RHS)
+ return;
+
+ if (!isInlineStorage()) {
+ // The out-of-line case is easiest to move.
+ StorageUnion.OutOfLineStorage = RHS.StorageUnion.OutOfLineStorage;
+ } else if (isTrivialCallback()) {
+ // Move is trivial, just memcpy the bytes across.
+ memcpy(getInlineStorage(), RHS.getInlineStorage(), InlineStorageSize);
+ } else {
+ // Non-trivial move, so dispatch to a type-erased implementation.
+ getNonTrivialCallbacks()->MovePtr(getInlineStorage(),
+ RHS.getInlineStorage());
+ }
+
+ // Clear the old callback and inline flag to get back to as-if-null.
+ RHS.CallbackAndInlineFlag = {};
+
+#ifndef NDEBUG
+ // In debug builds, we also scribble across the rest of the storage.
+ memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize);
+#endif
+ }
+
+ UniqueFunctionBase &operator=(UniqueFunctionBase &&RHS) noexcept {
+ if (this == &RHS)
+ return *this;
+
+ // Because we don't try to provide any exception safety guarantees we can
+ // implement move assignment very simply by first destroying the current
+ // object and then move-constructing over top of it.
+ this->~UniqueFunctionBase();
+ new (this) UniqueFunctionBase(std::move(RHS));
+ return *this;
+ }
+
+ UniqueFunctionBase() = default;
+
+public:
+ explicit operator bool() const {
+ return (bool)CallbackAndInlineFlag.getPointer();
+ }
+};
+
+template <typename R, typename... P>
+template <typename CallableT, typename CalledAsT, typename Enable>
+typename UniqueFunctionBase<R, P...>::NonTrivialCallbacks UniqueFunctionBase<
+ R, P...>::CallbacksHolder<CallableT, CalledAsT, Enable>::Callbacks = {
+ &CallImpl<CalledAsT>, &MoveImpl<CallableT>, &DestroyImpl<CallableT>};
+
+template <typename R, typename... P>
+template <typename CallableT, typename CalledAsT>
+typename UniqueFunctionBase<R, P...>::TrivialCallback
+ UniqueFunctionBase<R, P...>::CallbacksHolder<
+ CallableT, CalledAsT, EnableIfTrivial<CallableT>>::Callbacks{
+ &CallImpl<CalledAsT>};
+
+} // namespace detail
+
+template <typename R, typename... P>
+class unique_function<R(P...)> : public detail::UniqueFunctionBase<R, P...> {
+ using Base = detail::UniqueFunctionBase<R, P...>;
+
+public:
+ unique_function() = default;
+ unique_function(std::nullptr_t) {}
+ unique_function(unique_function &&) = default;
+ unique_function(const unique_function &) = delete;
+ unique_function &operator=(unique_function &&) = default;
+ unique_function &operator=(const unique_function &) = delete;
+
+ template <typename CallableT>
+ unique_function(
+ CallableT Callable,
+ detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
+ detail::EnableIfCallable<CallableT, R, P...> * = nullptr)
+ : Base(std::forward<CallableT>(Callable),
+ typename Base::template CalledAs<CallableT>{}) {}
+
+ R operator()(P... Params) {
+ return this->getCallPtr()(this->getCalleePtr(), Params...);
+ }
+};
+
+template <typename R, typename... P>
+class unique_function<R(P...) const>
+ : public detail::UniqueFunctionBase<R, P...> {
+ using Base = detail::UniqueFunctionBase<R, P...>;
+
+public:
+ unique_function() = default;
+ unique_function(std::nullptr_t) {}
+ unique_function(unique_function &&) = default;
+ unique_function(const unique_function &) = delete;
+ unique_function &operator=(unique_function &&) = default;
+ unique_function &operator=(const unique_function &) = delete;
+
+ template <typename CallableT>
+ unique_function(
+ CallableT Callable,
+ detail::EnableUnlessSameType<CallableT, unique_function> * = nullptr,
+ detail::EnableIfCallable<const CallableT, R, P...> * = nullptr)
+ : Base(std::forward<CallableT>(Callable),
+ typename Base::template CalledAs<const CallableT>{}) {}
+
+ R operator()(P... Params) const {
+ return this->getCallPtr()(this->getCalleePtr(), Params...);
+ }
+};
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_FUNCTIONEXTRAS_H
diff --git a/wpiutil/src/main/native/include/wpi/Hashing.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
similarity index 90%
rename from wpiutil/src/main/native/include/wpi/Hashing.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
index e58bfdd..0d4a4c6 100644
--- a/wpiutil/src/main/native/include/wpi/Hashing.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/Hashing.h
@@ -1,9 +1,8 @@
//===-- llvm/ADT/Hashing.h - Utilities for hashing --------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -45,15 +44,14 @@
#ifndef WPIUTIL_WPI_HASHING_H
#define WPIUTIL_WPI_HASHING_H
-#include "wpi/Endian.h"
+#include "wpi/ErrorHandling.h"
#include "wpi/SwapByteOrder.h"
#include "wpi/type_traits.h"
-#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cstring>
#include <string>
-#include <string_view>
+#include <tuple>
#include <utility>
#ifdef _WIN32
@@ -62,6 +60,7 @@
#endif
namespace wpi {
+template <typename T, typename Enable> struct DenseMapInfo;
/// An opaque object representing a hash code.
///
@@ -108,8 +107,7 @@
/// differing argument types even if they would implicit promote to a common
/// type without changing the value.
template <typename T>
-typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
-hash_value(T value);
+std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value);
/// Compute a hash_code for a pointer's address.
///
@@ -120,6 +118,10 @@
template <typename T, typename U>
hash_code hash_value(const std::pair<T, U> &arg);
+/// Compute a hash_code for a tuple.
+template <typename... Ts>
+hash_code hash_value(const std::tuple<Ts...> &arg);
+
/// Compute a hash_code for a standard string.
template <typename T>
hash_code hash_value(const std::basic_string<T> &arg);
@@ -151,7 +153,7 @@
inline uint64_t fetch64(const char *p) {
uint64_t result;
memcpy(&result, p, sizeof(result));
- if (support::endian::system_endianness() == support::big)
+ if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
@@ -159,16 +161,16 @@
inline uint32_t fetch32(const char *p) {
uint32_t result;
memcpy(&result, p, sizeof(result));
- if (support::endian::system_endianness() == support::big)
+ if (sys::IsBigEndianHost)
sys::swapByteOrder(result);
return result;
}
/// Some primes between 2^63 and 2^64 for various uses.
-static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
-static const uint64_t k1 = 0xb492b66fbe98f273ULL;
-static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
-static const uint64_t k3 = 0xc949d7c7509e6557ULL;
+static constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
+static constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
+static constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
+static constexpr uint64_t k3 = 0xc949d7c7509e6557ULL;
/// Bitwise right rotate.
/// Normally this will compile to a single instruction, especially if the
@@ -198,7 +200,7 @@
uint8_t b = s[len >> 1];
uint8_t c = s[len - 1];
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
- uint32_t z = static_cast<uint32_t>(len + (static_cast<uint64_t>(c) << 2));
+ uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
return shift_mix(y * k2 ^ z * k3 ^ seed) * k2;
}
@@ -264,7 +266,7 @@
/// Currently, the algorithm for computing hash codes is based on CityHash and
/// keeps 56 bytes of arbitrary state.
struct hash_state {
- uint64_t h0, h1, h2, h3, h4, h5, h6;
+ uint64_t h0 = 0, h1 = 0, h2 = 0, h3 = 0, h4 = 0, h5 = 0, h6 = 0;
/// Create a new hash_state structure and initialize it based on the
/// seed and the first 64-byte chunk.
@@ -367,7 +369,7 @@
/// Helper to get the hashable data representation for a type.
/// This variant is enabled when the type itself can be used.
template <typename T>
-typename std::enable_if<is_hashable_data<T>::value, T>::type
+std::enable_if_t<is_hashable_data<T>::value, T>
get_hashable_data(const T &value) {
return value;
}
@@ -375,7 +377,7 @@
/// This variant is enabled when we must first call hash_value and use the
/// result as our data.
template <typename T>
-typename std::enable_if<!is_hashable_data<T>::value, size_t>::type
+std::enable_if_t<!is_hashable_data<T>::value, size_t>
get_hashable_data(const T &value) {
using ::wpi::hash_value;
return hash_value(value);
@@ -449,7 +451,7 @@
/// are stored in contiguous memory, this routine avoids copying each value
/// and directly reads from the underlying memory.
template <typename ValueT>
-typename std::enable_if<is_hashable_data<ValueT>::value, hash_code>::type
+std::enable_if_t<is_hashable_data<ValueT>::value, hash_code>
hash_combine_range_impl(ValueT *first, ValueT *last) {
const uint64_t seed = get_execution_seed();
const char *s_begin = reinterpret_cast<const char *>(first);
@@ -499,7 +501,7 @@
/// useful at minimizing the code in the recursive calls to ease the pain
/// caused by a lack of variadic functions.
struct hash_combine_recursive_helper {
- char buffer[64];
+ char buffer[64] = {};
hash_state state;
const uint64_t seed;
@@ -547,7 +549,7 @@
// store types smaller than the buffer.
if (!store_and_advance(buffer_ptr, buffer_end, data,
partial_store_size))
- abort();
+ wpi_unreachable("buffer smaller than stored type");
}
return buffer_ptr;
}
@@ -574,7 +576,7 @@
// Check whether the entire set of values fit in the buffer. If so, we'll
// use the optimized short hashing routine and skip state entirely.
if (length == 0)
- return static_cast<size_t>(hash_short(buffer, buffer_ptr - buffer, seed));
+ return hash_short(buffer, buffer_ptr - buffer, seed);
// Mix the final buffer, rotating it if we did a partial fill in order to
// simulate doing a mix of the last 64-bytes. That is how the algorithm
@@ -586,7 +588,7 @@
state.mix(buffer);
length += buffer_ptr - buffer;
- return static_cast<size_t>(state.finalize(length));
+ return state.finalize(length);
}
};
@@ -625,7 +627,7 @@
const uint64_t seed = get_execution_seed();
const char *s = reinterpret_cast<const char *>(&value);
const uint64_t a = fetch32(s);
- return static_cast<size_t>(hash_16_bytes(seed + (a << 3), fetch32(s + 4)));
+ return hash_16_bytes(seed + (a << 3), fetch32(s + 4));
}
} // namespace detail
@@ -634,8 +636,7 @@
// Declared and documented above, but defined here so that any of the hashing
// infrastructure is available.
template <typename T>
-typename std::enable_if<is_integral_or_enum<T>::value, hash_code>::type
-hash_value(T value) {
+std::enable_if_t<is_integral_or_enum<T>::value, hash_code> hash_value(T value) {
return ::wpi::hashing::detail::hash_integer_value(
static_cast<uint64_t>(value));
}
@@ -654,6 +655,26 @@
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...>());
+}
+
// Declared and documented above, but defined here so that any of the hashing
// infrastructure is available.
template <typename T>
@@ -661,10 +682,12 @@
return hash_combine_range(arg.begin(), arg.end());
}
-template <typename T>
-hash_code hash_value(const std::basic_string_view<T> &arg) {
- return hash_combine_range(arg.begin(), arg.end());
-}
+template <> struct DenseMapInfo<hash_code, void> {
+ static inline hash_code getEmptyKey() { return hash_code(-1); }
+ static inline hash_code getTombstoneKey() { return hash_code(-2); }
+ static unsigned getHashValue(hash_code val) { return val; }
+ static bool isEqual(hash_code LHS, hash_code RHS) { return LHS == RHS; }
+};
} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/MapVector.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
similarity index 93%
rename from wpiutil/src/main/native/include/wpi/MapVector.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
index 34e0267..e4706c7 100644
--- a/wpiutil/src/main/native/include/wpi/MapVector.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MapVector.h
@@ -1,17 +1,17 @@
//===- llvm/ADT/MapVector.h - Map w/ deterministic value order --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 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.
-//
+///
+/// \file
+/// 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.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_MAPVECTOR_H
@@ -19,7 +19,6 @@
#include "wpi/DenseMap.h"
#include "wpi/SmallVector.h"
-#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>
@@ -44,6 +43,7 @@
"The mapped_type of the specified Map must be an integral type");
public:
+ using key_type = KeyT;
using value_type = typename VectorType::value_type;
using size_type = typename VectorType::size_type;
@@ -237,4 +237,4 @@
} // end namespace wpi
-#endif // LLVM_ADT_MAPVECTOR_H
+#endif // WPIUTIL_WPI_MAPVECTOR_H
diff --git a/wpiutil/src/main/native/include/wpi/MathExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
similarity index 81%
rename from wpiutil/src/main/native/include/wpi/MathExtras.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
index ac88cb9..ea669ee 100644
--- a/wpiutil/src/main/native/include/wpi/MathExtras.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MathExtras.h
@@ -1,9 +1,8 @@
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,15 +14,18 @@
#define WPIUTIL_WPI_MATHEXTRAS_H
#include "wpi/Compiler.h"
-#include <cstdint>
-#include <algorithm>
#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.
@@ -37,6 +39,7 @@
#endif
namespace wpi {
+
/// The behavior an operation has on an input of 0.
enum ZeroBehavior {
/// The returned value is undefined.
@@ -49,14 +52,14 @@
namespace detail {
template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
- static std::size_t count(T Val, ZeroBehavior) {
+ static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
if (Val & 0x1)
return 0;
// Bisection method.
- std::size_t ZeroBits = 0;
+ unsigned ZeroBits = 0;
T Shift = std::numeric_limits<T>::digits >> 1;
T Mask = (std::numeric_limits<T>::max)() >> Shift;
while (Shift) {
@@ -71,13 +74,13 @@
}
};
-#if __GNUC__ >= 4 || defined(_MSC_VER)
+#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct TrailingZerosCounter<T, 4> {
- static std::size_t count(T Val, ZeroBehavior ZB) {
+ static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
-#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
+#if __has_builtin(__builtin_ctz) || defined(__GNUC__)
return __builtin_ctz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -89,11 +92,11 @@
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct TrailingZerosCounter<T, 8> {
- static std::size_t count(T Val, ZeroBehavior ZB) {
+ static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
-#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
+#if __has_builtin(__builtin_ctzll) || defined(__GNUC__)
return __builtin_ctzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -114,7 +117,7 @@
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
-std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
+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.");
@@ -123,12 +126,12 @@
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
- static std::size_t count(T Val, ZeroBehavior) {
+ static unsigned count(T Val, ZeroBehavior) {
if (!Val)
return std::numeric_limits<T>::digits;
// Bisection method.
- std::size_t ZeroBits = 0;
+ unsigned ZeroBits = 0;
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
T Tmp = Val >> Shift;
if (Tmp)
@@ -140,13 +143,13 @@
}
};
-#if __GNUC__ >= 4 || defined(_MSC_VER)
+#if defined(__GNUC__) || defined(_MSC_VER)
template <typename T> struct LeadingZerosCounter<T, 4> {
- static std::size_t count(T Val, ZeroBehavior ZB) {
+ static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 32;
-#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0)
+#if __has_builtin(__builtin_clz) || defined(__GNUC__)
return __builtin_clz(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -158,11 +161,11 @@
#if !defined(_MSC_VER) || defined(_M_X64)
template <typename T> struct LeadingZerosCounter<T, 8> {
- static std::size_t count(T Val, ZeroBehavior ZB) {
+ static unsigned count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0)
return 64;
-#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0)
+#if __has_builtin(__builtin_clzll) || defined(__GNUC__)
return __builtin_clzll(Val);
#elif defined(_MSC_VER)
unsigned long Index;
@@ -183,7 +186,7 @@
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
-std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
+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.");
@@ -273,6 +276,34 @@
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,14 +356,12 @@
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
/// left too many places.
template <unsigned N>
-constexpr inline typename std::enable_if<(N < 64), bool>::type
-isUInt(uint64_t X) {
+constexpr inline std::enable_if_t<(N < 64), 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 typename std::enable_if<N >= 64, bool>::type
-isUInt(uint64_t X) {
+constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t) {
return true;
}
@@ -379,7 +408,7 @@
inline int64_t minIntN(int64_t N) {
assert(N > 0 && N <= 64 && "integer width out of range");
- return -(UINT64_C(1)<<(N-1));
+ return UINT64_C(1) + ~(UINT64_C(1) << (N - 1));
}
#ifdef _WIN32
@@ -450,7 +479,7 @@
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
-std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
+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.");
@@ -466,7 +495,7 @@
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
/// ZB_Undefined are valid arguments.
template <typename T>
-std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
+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.");
@@ -478,7 +507,7 @@
static unsigned count(T Value) {
// Generic version, forward to 32 bits.
static_assert(SizeOfT <= 4, "Not implemented!");
-#if __GNUC__ >= 4
+#if defined(__GNUC__)
return __builtin_popcount(Value);
#else
uint32_t v = Value;
@@ -491,7 +520,7 @@
template <typename T> struct PopulationCounter<T, 8> {
static unsigned count(T Value) {
-#if __GNUC__ >= 4
+#if defined(__GNUC__)
return __builtin_popcountll(Value);
#else
uint64_t v = Value;
@@ -515,6 +544,16 @@
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
}
+/// Compile time Log2.
+/// Valid only for positive powers of two.
+template <size_t kValue> constexpr inline size_t CTLog2() {
+ static_assert(kValue > 0 && wpi::isPowerOf2_64(kValue),
+ "Value is not a valid power of 2");
+ return 1 + CTLog2<kValue / 2>();
+}
+
+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
@@ -551,15 +590,20 @@
}
/// Return the greatest common divisor of the values using Euclid's algorithm.
-inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
+template <typename T>
+inline T greatestCommonDivisor(T A, T B) {
while (B) {
- uint64_t T = B;
+ T Tmp = B;
B = A % B;
- A = T;
+ 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;
@@ -607,25 +651,6 @@
return (A | B) & (1 + ~(A | B));
}
-/// Aligns \c Addr to \c Alignment bytes, rounding up.
-///
-/// Alignment should be a power of two. This method rounds up, so
-/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
-inline uintptr_t alignAddr(const void *Addr, size_t Alignment) {
- assert(Alignment && isPowerOf2_64((uint64_t)Alignment) &&
- "Alignment is not a power of two!");
-
- assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
-
- return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
-}
-
-/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment
-/// bytes, rounding up.
-inline size_t alignmentAdjustment(const void *Ptr, size_t Alignment) {
- return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
-}
-
/// 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) {
@@ -691,18 +716,10 @@
return alignTo(Numerator, Denominator) / Denominator;
}
-/// \c alignTo for contexts where a constant expression is required.
-/// \sa alignTo
-///
-/// \todo FIXME: remove when \c constexpr becomes really \c constexpr
-template <uint64_t Align>
-struct AlignTo {
- static_assert(Align != 0u, "Align must be non-zero");
- template <uint64_t Value>
- struct from_value {
- static const uint64_t value = (Value + Align - 1) / Align * Align;
- };
-};
+/// Returns the integer nearest(Numerator / Denominator).
+inline uint64_t divideNearest(uint64_t Numerator, uint64_t Denominator) {
+ return (Numerator + (Denominator / 2)) / Denominator;
+}
/// Returns the largest uint64_t less than or equal to \p Value and is
/// \p Skew mod \p Align. \p Align must be non-zero
@@ -712,13 +729,6 @@
return (Value - Skew) / Align * Align + Skew;
}
-/// Returns the offset to 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.
-inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
- return alignTo(Value, Align) - Value;
-}
-
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
/// Requires 0 < B <= 32.
template <unsigned B> constexpr inline int32_t SignExtend32(uint32_t X) {
@@ -728,7 +738,7 @@
}
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
-/// Requires 0 < B < 32.
+/// Requires 0 < B <= 32.
inline int32_t SignExtend32(uint32_t X, unsigned B) {
assert(B > 0 && "Bit width can't be 0.");
assert(B <= 32 && "Bit width out of range.");
@@ -736,7 +746,7 @@
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
-/// Requires 0 < B < 64.
+/// Requires 0 < B <= 64.
template <unsigned B> constexpr inline int64_t SignExtend64(uint64_t x) {
static_assert(B > 0, "Bit width can't be 0.");
static_assert(B <= 64, "Bit width out of range.");
@@ -744,7 +754,7 @@
}
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
-/// Requires 0 < B < 64.
+/// Requires 0 < B <= 64.
inline int64_t SignExtend64(uint64_t X, unsigned B) {
assert(B > 0 && "Bit width can't be 0.");
assert(B <= 64 && "Bit width out of range.");
@@ -754,16 +764,15 @@
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
/// value of the result.
template <typename T>
-typename std::enable_if<std::is_unsigned<T>::value, T>::type
-AbsoluteDifference(T X, T Y) {
- return (std::max)(X, Y) - (std::min)(X, Y);
+std::enable_if_t<std::is_unsigned<T>::value, T> AbsoluteDifference(T X, T Y) {
+ return X > Y ? (X - Y) : (Y - X);
}
/// Add 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>
-typename std::enable_if<std::is_unsigned<T>::value, T>::type
+std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingAdd(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -780,7 +789,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>
-typename std::enable_if<std::is_unsigned<T>::value, T>::type
+std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingMultiply(T X, T Y, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -826,7 +835,7 @@
/// overflow. ResultOverflowed indicates if the result is larger than the
/// maximum representable value of type T.
template <typename T>
-typename std::enable_if<std::is_unsigned<T>::value, T>::type
+std::enable_if_t<std::is_unsigned<T>::value, T>
SaturatingMultiplyAdd(T X, T Y, T A, bool *ResultOverflowed = nullptr) {
bool Dummy;
bool &Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
@@ -838,6 +847,89 @@
return SaturatingAdd(A, Product, &Overflowed);
}
+/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
+extern const float huge_valf;
+
+
+/// Add two signed integers, computing the two's complement truncated result,
+/// returning true if overflow occured.
+template <typename T>
+std::enable_if_t<std::is_signed<T>::value, T> AddOverflow(T X, T Y, T &Result) {
+#if __has_builtin(__builtin_add_overflow)
+ return __builtin_add_overflow(X, Y, &Result);
+#else
+ // Perform the unsigned addition.
+ using U = std::make_unsigned_t<T>;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX + UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Adding two positive numbers should result in a positive number.
+ if (X > 0 && Y > 0)
+ return Result <= 0;
+ // Adding two negatives should result in a negative number.
+ if (X < 0 && Y < 0)
+ return Result >= 0;
+ return false;
+#endif
+}
+
+/// 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) {
+#if __has_builtin(__builtin_sub_overflow)
+ return __builtin_sub_overflow(X, Y, &Result);
+#else
+ // Perform the unsigned addition.
+ using U = std::make_unsigned_t<T>;
+ const U UX = static_cast<U>(X);
+ const U UY = static_cast<U>(Y);
+ const U UResult = UX - UY;
+
+ // Convert to signed.
+ Result = static_cast<T>(UResult);
+
+ // Subtracting a positive number from a negative results in a negative number.
+ if (X <= 0 && Y > 0)
+ return Result >= 0;
+ // Subtracting a negative number from a positive results in a positive number.
+ if (X >= 0 && Y < 0)
+ return Result <= 0;
+ return false;
+#endif
+}
+
+/// 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) {
+ // 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);
+ const U UY = Y < 0 ? (0 - static_cast<U>(Y)) : static_cast<U>(Y);
+ const U UResult = UX * UY;
+
+ // Convert to signed.
+ const bool IsNegative = (X < 0) ^ (Y < 0);
+ Result = IsNegative ? (0 - UResult) : UResult;
+
+ // If any of the args was 0, result is 0 and no overflow occurs.
+ if (UX == 0 || UY == 0)
+ return false;
+
+ // UX and UY are in [1, 2^n], where n is the number of digits.
+ // Check how the max allowed absolute value (2^n for negative, 2^(n-1) for
+ // positive) divided by an argument compares to the other.
+ if (IsNegative)
+ return UX > (static_cast<U>((std::numeric_limits<T>::max)()) + U(1)) / UY;
+ else
+ return UX > (static_cast<U>((std::numeric_limits<T>::max)())) / UY;
+}
+
// Typesafe implementation of the signum function.
// Returns -1 if negative, 1 if positive, 0 if 0.
template <typename T>
@@ -858,7 +950,6 @@
constexpr T Lerp(const T& startValue, const T& endValue, double t) {
return startValue + (endValue - startValue) * t;
}
-
-} // namespace wpi
+} // End wpi namespace
#endif
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
new file mode 100644
index 0000000..32909ff
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemAlloc.h
@@ -0,0 +1,100 @@
+//===- MemAlloc.h - Memory allocation functions -----------------*- 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 counterparts of C library allocation functions defined in
+/// the namespace 'std'. The new allocation functions crash on allocation
+/// failure instead of returning null pointer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_MEMALLOC_H
+#define WPIUTIL_WPI_MEMALLOC_H
+
+#include "wpi/Compiler.h"
+#include "wpi/ErrorHandling.h"
+#include <cstdlib>
+
+namespace wpi {
+
+#ifdef _WIN32
+#pragma warning(push)
+// Warning on NONNULL, report is not known to abort
+#pragma warning(disable : 6387)
+#pragma warning(disable : 28196)
+#pragma warning(disable : 28183)
+#endif
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_malloc(size_t Sz) {
+ void *Result = std::malloc(Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_calloc(size_t Count,
+ size_t Sz) {
+ void *Result = std::calloc(Count, Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Count == 0 || Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+LLVM_ATTRIBUTE_RETURNS_NONNULL inline void *safe_realloc(void *Ptr, size_t Sz) {
+ void *Result = std::realloc(Ptr, Sz);
+ if (Result == nullptr) {
+ // It is implementation-defined whether allocation occurs if the space
+ // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
+ // non-zero, if the space requested was zero.
+ if (Sz == 0)
+ return safe_malloc(1);
+ report_bad_alloc_error("Allocation failed");
+ }
+ return Result;
+}
+
+/// Allocate a buffer of memory with the given size and alignment.
+///
+/// When the compiler supports aligned operator new, this will use it to to
+/// handle even over-aligned allocations.
+///
+/// However, this doesn't make any attempt to leverage the fancier techniques
+/// like posix_memalign due to portability. It is mostly intended to allow
+/// compatibility with platforms that, after aligned allocation was added, use
+/// reduced default alignment.
+LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void *
+allocate_buffer(size_t Size, size_t Alignment);
+
+/// Deallocate a buffer of memory with the given size and alignment.
+///
+/// If supported, this will used the sized delete operator. Also if supported,
+/// this will pass the alignment to the delete operator.
+///
+/// The pointer must have been allocated with the corresponding new operator,
+/// most likely using the above helper.
+void deallocate_buffer(void *Ptr, size_t Size, size_t Alignment);
+
+} // namespace wpi
+
+#ifdef _WIN32
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
new file mode 100644
index 0000000..7907c07
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/MemoryBuffer.h
@@ -0,0 +1,239 @@
+// 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.
+
+//===--- MemoryBuffer.h - Memory Buffer Interface ---------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MemoryBuffer interface.
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include <stdint.h>
+
+#include <cstddef>
+#include <memory>
+#include <span>
+#include <string_view>
+#include <system_error>
+
+// Duplicated from fs.h to avoid a dependency
+namespace fs {
+#if defined(_WIN32)
+// A Win32 HANDLE is a typedef of void*
+using file_t = void*;
+#else
+using file_t = int;
+#endif
+} // namespace fs
+
+namespace wpi {
+
+class MemoryBufferRef;
+
+/// This interface provides simple read-only access to a block of memory, and
+/// provides simple methods for reading files and standard input into a memory
+/// buffer.
+class MemoryBuffer {
+ const uint8_t* m_bufferStart; // Start of the buffer.
+ const uint8_t* m_bufferEnd; // End of the buffer.
+
+ protected:
+ MemoryBuffer() = default;
+
+ void Init(const uint8_t* bufStart, const uint8_t* bufEnd);
+
+ public:
+ MemoryBuffer(const MemoryBuffer&) = delete;
+ MemoryBuffer& operator=(const MemoryBuffer&) = delete;
+ virtual ~MemoryBuffer();
+
+ const uint8_t* begin() const { return m_bufferStart; }
+ const uint8_t* end() const { return m_bufferEnd; }
+ size_t size() const { return m_bufferEnd - m_bufferStart; }
+
+ std::span<const uint8_t> GetBuffer() const { return {begin(), end()}; }
+
+ /// Return an identifier for this buffer, typically the filename it was read
+ /// from.
+ virtual std::string_view GetBufferIdentifier() const {
+ return "Unknown buffer";
+ }
+
+ /// Open the specified file as a MemoryBuffer, returning a new MemoryBuffer
+ /// if successful, otherwise returning null. If FileSize is specified, this
+ /// means that the client knows that the file exists and that it has the
+ /// specified size.
+ static std::unique_ptr<MemoryBuffer> GetFile(std::string_view filename,
+ std::error_code& ec,
+ int64_t fileSize = -1);
+
+ /// Read all of the specified file into a MemoryBuffer as a stream
+ /// (i.e. until EOF reached). This is useful for special files that
+ /// look like a regular file but have 0 size (e.g. /proc/cpuinfo on Linux).
+ static std::unique_ptr<MemoryBuffer> GetFileAsStream(
+ std::string_view filename, std::error_code& ec);
+
+ /// Given an already-open file descriptor, map some slice of it into a
+ /// MemoryBuffer. The slice is specified by an \p Offset and \p MapSize.
+ static std::unique_ptr<MemoryBuffer> GetOpenFileSlice(
+ fs::file_t f, std::string_view filename, std::error_code& ec,
+ uint64_t mapSize, int64_t offset);
+
+ /// Given an already-open file descriptor, read the file and return a
+ /// MemoryBuffer.
+ static std::unique_ptr<MemoryBuffer> GetOpenFile(fs::file_t f,
+ std::string_view filename,
+ std::error_code& ec,
+ uint64_t fileSize);
+
+ /// Open the specified memory range as a MemoryBuffer.
+ static std::unique_ptr<MemoryBuffer> GetMemBuffer(
+ std::span<const uint8_t> inputData, std::string_view bufferName = "");
+
+ static std::unique_ptr<MemoryBuffer> GetMemBuffer(MemoryBufferRef ref);
+
+ /// Open the specified memory range as a MemoryBuffer, copying the contents
+ /// and taking ownership of it.
+ static std::unique_ptr<MemoryBuffer> GetMemBufferCopy(
+ std::span<const uint8_t> inputData, std::string_view bufferName = "");
+
+ /// Map a subrange of the specified file as a MemoryBuffer.
+ static std::unique_ptr<MemoryBuffer> GetFileSlice(std::string_view filename,
+ std::error_code& ec,
+ uint64_t mapSize,
+ uint64_t offset);
+
+ //===--------------------------------------------------------------------===//
+ // Provided for performance analysis.
+ //===--------------------------------------------------------------------===//
+
+ /// The kind of memory backing used to support the MemoryBuffer.
+ enum BufferKind { MemoryBuffer_Malloc, MemoryBuffer_MMap };
+
+ /// Return information on the memory mechanism used to support the
+ /// MemoryBuffer.
+ virtual BufferKind GetBufferKind() const = 0;
+
+ MemoryBufferRef GetMemBufferRef() const;
+};
+
+/// This class is an extension of MemoryBuffer, which allows copy-on-write
+/// access to the underlying contents. It only supports creation methods that
+/// are guaranteed to produce a writable buffer. For example, mapping a file
+/// read-only is not supported.
+class WritableMemoryBuffer : public MemoryBuffer {
+ protected:
+ WritableMemoryBuffer() = default;
+
+ public:
+ using MemoryBuffer::begin;
+ using MemoryBuffer::end;
+ using MemoryBuffer::GetBuffer;
+ using MemoryBuffer::size;
+
+ // const_cast is well-defined here, because the underlying buffer is
+ // guaranteed to have been initialized with a mutable buffer.
+ uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
+ uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
+ std::span<uint8_t> GetBuffer() { return {begin(), end()}; }
+
+ static std::unique_ptr<WritableMemoryBuffer> GetFile(
+ std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
+
+ /// Map a subrange of the specified file as a WritableMemoryBuffer.
+ static std::unique_ptr<WritableMemoryBuffer> GetFileSlice(
+ std::string_view filename, std::error_code& ec, uint64_t mapSize,
+ uint64_t offset);
+
+ /// Allocate a new MemoryBuffer of the specified size that is not initialized.
+ /// Note that the caller should initialize the memory allocated by this
+ /// method. The memory is owned by the MemoryBuffer object.
+ static std::unique_ptr<WritableMemoryBuffer> GetNewUninitMemBuffer(
+ size_t size, std::string_view bufferName = "");
+
+ /// Allocate a new zero-initialized MemoryBuffer of the specified size. Note
+ /// that the caller need not initialize the memory allocated by this method.
+ /// The memory is owned by the MemoryBuffer object.
+ static std::unique_ptr<WritableMemoryBuffer> GetNewMemBuffer(
+ size_t size, std::string_view bufferName = "");
+
+ private:
+ // Hide these base class factory function so one can't write
+ // WritableMemoryBuffer::getXXX()
+ // and be surprised that they got a read-only Buffer.
+ using MemoryBuffer::GetFileAsStream;
+ using MemoryBuffer::GetMemBuffer;
+ using MemoryBuffer::GetMemBufferCopy;
+ using MemoryBuffer::GetOpenFile;
+ using MemoryBuffer::GetOpenFileSlice;
+};
+
+/// This class is an extension of MemoryBuffer, which allows write access to
+/// the underlying contents and committing those changes to the original source.
+/// It only supports creation methods that are guaranteed to produce a writable
+/// buffer. For example, mapping a file read-only is not supported.
+class WriteThroughMemoryBuffer : public MemoryBuffer {
+ protected:
+ WriteThroughMemoryBuffer() = default;
+
+ public:
+ using MemoryBuffer::begin;
+ using MemoryBuffer::end;
+ using MemoryBuffer::GetBuffer;
+ using MemoryBuffer::size;
+
+ // const_cast is well-defined here, because the underlying buffer is
+ // guaranteed to have been initialized with a mutable buffer.
+ uint8_t* begin() { return const_cast<uint8_t*>(MemoryBuffer::begin()); }
+ uint8_t* end() { return const_cast<uint8_t*>(MemoryBuffer::end()); }
+ std::span<uint8_t> GetBuffer() { return {begin(), end()}; }
+
+ static std::unique_ptr<WriteThroughMemoryBuffer> GetFile(
+ std::string_view filename, std::error_code& ec, int64_t fileSize = -1);
+
+ /// Map a subrange of the specified file as a ReadWriteMemoryBuffer.
+ static std::unique_ptr<WriteThroughMemoryBuffer> GetFileSlice(
+ std::string_view filename, std::error_code& ec, uint64_t mapSize,
+ uint64_t offset);
+
+ private:
+ // Hide these base class factory function so one can't write
+ // WritableMemoryBuffer::getXXX()
+ // and be surprised that they got a read-only Buffer.
+ using MemoryBuffer::GetFileAsStream;
+ using MemoryBuffer::GetMemBuffer;
+ using MemoryBuffer::GetMemBufferCopy;
+ using MemoryBuffer::GetOpenFile;
+ using MemoryBuffer::GetOpenFileSlice;
+};
+
+class MemoryBufferRef {
+ std::span<const uint8_t> m_buffer;
+ std::string_view m_id;
+
+ public:
+ MemoryBufferRef() = default;
+ MemoryBufferRef(MemoryBuffer& buffer) // NOLINT
+ : m_buffer(buffer.GetBuffer()), m_id(buffer.GetBufferIdentifier()) {}
+ MemoryBufferRef(std::span<const uint8_t> buffer, std::string_view id)
+ : m_buffer(buffer), m_id(id) {}
+
+ std::span<const uint8_t> GetBuffer() const { return m_buffer; }
+
+ std::string_view GetBufferIdentifier() const { return m_id; }
+
+ const uint8_t* begin() const { return &*m_buffer.begin(); }
+ const uint8_t* end() const { return &*m_buffer.end(); }
+ size_t size() const { return m_buffer.size(); }
+};
+
+} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/PointerIntPair.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
similarity index 88%
rename from wpiutil/src/main/native/include/wpi/PointerIntPair.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
index e6a1212..34ff4e1 100644
--- a/wpiutil/src/main/native/include/wpi/PointerIntPair.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerIntPair.h
@@ -1,27 +1,29 @@
//===- llvm/ADT/PointerIntPair.h - Pair for pointer and int -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 PointerIntPair class.
-//
+///
+/// \file
+/// This file defines the PointerIntPair class.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_POINTERINTPAIR_H
#define WPIUTIL_WPI_POINTERINTPAIR_H
+#include "wpi/Compiler.h"
#include "wpi/PointerLikeTypeTraits.h"
+#include "wpi/type_traits.h"
#include <cassert>
#include <cstdint>
#include <limits>
namespace wpi {
-template <typename T> struct DenseMapInfo;
+template <typename T, typename Enable> struct DenseMapInfo;
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo;
@@ -59,19 +61,19 @@
IntType getInt() const { return (IntType)Info::getInt(Value); }
- void setPointer(PointerTy PtrVal) {
+ void setPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(Value, PtrVal);
}
- void setInt(IntType IntVal) {
+ void setInt(IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Value, static_cast<intptr_t>(IntVal));
}
- void initWithPointer(PointerTy PtrVal) {
+ void initWithPointer(PointerTy PtrVal) LLVM_LVALUE_FUNCTION {
Value = Info::updatePointer(0, PtrVal);
}
- void setPointerAndInt(PointerTy PtrVal, IntType IntVal) {
+ void setPointerAndInt(PointerTy PtrVal, IntType IntVal) LLVM_LVALUE_FUNCTION {
Value = Info::updateInt(Info::updatePointer(0, PtrVal),
static_cast<intptr_t>(IntVal));
}
@@ -89,7 +91,7 @@
void *getOpaqueValue() const { return reinterpret_cast<void *>(Value); }
- void setFromOpaqueValue(void *Val) {
+ void setFromOpaqueValue(void *Val) LLVM_LVALUE_FUNCTION {
Value = reinterpret_cast<intptr_t>(Val);
}
@@ -126,6 +128,7 @@
}
};
+
template <typename PointerT, unsigned IntBits, typename PtrTraits>
struct PointerIntPairInfo {
static_assert(PtrTraits::NumLowBitsAvailable <
@@ -133,7 +136,7 @@
"cannot use a pointer type that has all bits free");
static_assert(IntBits <= PtrTraits::NumLowBitsAvailable,
"PointerIntPair with integer size too large for pointer");
- enum : uintptr_t {
+ enum MaskAndShiftConstants : uintptr_t {
/// PointerBitMask - The bits that come from the pointer.
PointerBitMask =
~(uintptr_t)(((intptr_t)1 << PtrTraits::NumLowBitsAvailable) - 1),
@@ -176,15 +179,9 @@
}
};
-template <typename T> struct isPodLike;
-template <typename PointerTy, unsigned IntBits, typename IntType>
-struct isPodLike<PointerIntPair<PointerTy, IntBits, IntType>> {
- static const bool value = true;
-};
-
// Provide specialization of DenseMapInfo for PointerIntPair.
template <typename PointerTy, unsigned IntBits, typename IntType>
-struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>> {
+struct DenseMapInfo<PointerIntPair<PointerTy, IntBits, IntType>, void> {
using Ty = PointerIntPair<PointerTy, IntBits, IntType>;
static Ty getEmptyKey() {
@@ -227,7 +224,8 @@
return PointerIntPair<PointerTy, IntBits, IntType>::getFromOpaqueValue(P);
}
- enum { NumLowBitsAvailable = PtrTraits::NumLowBitsAvailable - IntBits };
+ static constexpr int NumLowBitsAvailable =
+ PtrTraits::NumLowBitsAvailable - IntBits;
};
} // end namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/PointerLikeTypeTraits.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
similarity index 86%
rename from wpiutil/src/main/native/include/wpi/PointerLikeTypeTraits.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
index fa136e0..ffca61a 100644
--- a/wpiutil/src/main/native/include/wpi/PointerLikeTypeTraits.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerLikeTypeTraits.h
@@ -1,9 +1,8 @@
//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,8 +14,8 @@
#ifndef WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
#define WPIUTIL_WPI_POINTERLIKETYPETRAITS_H
+#include <cassert>
#include <cstdint>
-#include <cstdlib>
#include <type_traits>
namespace wpi {
@@ -38,8 +37,9 @@
};
// sizeof(T) is valid only for a complete T.
-template <typename T> struct HasPointerLikeTypeTraits<
- T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
+template <typename T>
+struct HasPointerLikeTypeTraits<
+ T, decltype((sizeof(PointerLikeTypeTraits<T>) + sizeof(T)), void())> {
static const bool value = true;
};
@@ -57,7 +57,8 @@
static inline void *getAsVoidPointer(T *P) { return P; }
static inline T *getFromVoidPointer(void *P) { return static_cast<T *>(P); }
- enum { NumLowBitsAvailable = detail::ConstantLog2<alignof(T)>::value };
+ static constexpr int NumLowBitsAvailable =
+ detail::ConstantLog2<alignof(T)>::value;
};
template <> struct PointerLikeTypeTraits<void *> {
@@ -71,7 +72,7 @@
///
/// All clients should use assertions to do a run-time check to ensure that
/// this is actually true.
- enum { NumLowBitsAvailable = 2 };
+ static constexpr int NumLowBitsAvailable = 2;
};
// Provide PointerLikeTypeTraits for const things.
@@ -84,7 +85,7 @@
static inline const T getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
- enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
+ static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for const pointers.
@@ -97,7 +98,7 @@
static inline const T *getFromVoidPointer(const void *P) {
return NonConst::getFromVoidPointer(const_cast<void *>(P));
}
- enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable };
+ static constexpr int NumLowBitsAvailable = NonConst::NumLowBitsAvailable;
};
// Provide PointerLikeTypeTraits for uintptr_t.
@@ -109,7 +110,7 @@
return reinterpret_cast<uintptr_t>(P);
}
// No bits are available!
- enum { NumLowBitsAvailable = 0 };
+ static constexpr int NumLowBitsAvailable = 0;
};
/// Provide suitable custom traits struct for function pointers.
@@ -122,7 +123,8 @@
/// potentially use alignment attributes on functions to satisfy that.
template <int Alignment, typename FunctionPointerT>
struct FunctionPointerLikeTypeTraits {
- enum { NumLowBitsAvailable = detail::ConstantLog2<Alignment>::value };
+ static constexpr int NumLowBitsAvailable =
+ detail::ConstantLog2<Alignment>::value;
static inline void *getAsVoidPointer(FunctionPointerT P) {
assert((reinterpret_cast<uintptr_t>(P) &
~((uintptr_t)-1 << NumLowBitsAvailable)) == 0 &&
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
new file mode 100644
index 0000000..cc12bbc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/PointerUnion.h
@@ -0,0 +1,295 @@
+//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- 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 the PointerUnion class, which is a discriminated union of
+/// pointer types.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_POINTERUNION_H
+#define WPIUTIL_WPI_POINTERUNION_H
+
+#include "wpi/DenseMapInfo.h"
+#include "wpi/PointerIntPair.h"
+#include "wpi/PointerLikeTypeTraits.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <type_traits>
+
+namespace wpi {
+
+namespace detail {
+template <typename T, typename... Us> struct TypesAreDistinct;
+template <typename T, typename... Us>
+struct TypesAreDistinct
+ : std::integral_constant<bool, !std::disjunction_v<std::is_same<T, Us>...> &&
+ TypesAreDistinct<Us...>::value> {};
+template <typename T> struct TypesAreDistinct<T> : std::true_type {};
+} // namespace detail
+
+/// Determine if all types in Ts are distinct.
+///
+/// Useful to statically assert when Ts is intended to describe a non-multi set
+/// of types.
+///
+/// Expensive (currently quadratic in sizeof(Ts...)), and so should only be
+/// asserted once per instantiation of a type which requires it.
+template <typename... Ts> struct TypesAreDistinct;
+template <> struct TypesAreDistinct<> : std::true_type {};
+template <typename... Ts>
+struct TypesAreDistinct
+ : std::integral_constant<bool, detail::TypesAreDistinct<Ts...>::value> {};
+
+/// Find the first index where a type appears in a list of types.
+///
+/// FirstIndexOfType<T, Us...>::value is the first index of T in Us.
+///
+/// Typically only meaningful when it is otherwise statically known that the
+/// type pack has no duplicate types. This should be guaranteed explicitly with
+/// static_assert(TypesAreDistinct<Us...>::value).
+///
+/// It is a compile-time error to instantiate when T is not present in Us, i.e.
+/// if is_one_of<T, Us...>::value is false.
+template <typename T, typename... Us> struct FirstIndexOfType;
+template <typename T, typename U, typename... Us>
+struct FirstIndexOfType<T, U, Us...>
+ : std::integral_constant<size_t, 1 + FirstIndexOfType<T, Us...>::value> {};
+template <typename T, typename... Us>
+struct FirstIndexOfType<T, T, Us...> : std::integral_constant<size_t, 0> {};
+
+/// Find the type at a given index in a list of types.
+///
+/// TypeAtIndex<I, Ts...> is the type at index I in Ts.
+template <size_t I, typename... Ts>
+using TypeAtIndex = std::tuple_element_t<I, std::tuple<Ts...>>;
+
+namespace pointer_union_detail {
+ /// Determine the number of bits required to store integers with values < n.
+ /// This is ceil(log2(n)).
+ constexpr int bitsRequired(unsigned n) {
+ return n > 1 ? 1 + bitsRequired((n + 1) / 2) : 0;
+ }
+
+ template <typename... Ts> constexpr int lowBitsAvailable() {
+ return std::min<int>({PointerLikeTypeTraits<Ts>::NumLowBitsAvailable...});
+ }
+
+ /// Find the first type in a list of types.
+ template <typename T, typename...> struct GetFirstType {
+ using type = T;
+ };
+
+ /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion
+ /// for the template arguments.
+ template <typename ...PTs> class PointerUnionUIntTraits {
+ public:
+ static inline void *getAsVoidPointer(void *P) { return P; }
+ static inline void *getFromVoidPointer(void *P) { return P; }
+ static constexpr int NumLowBitsAvailable = lowBitsAvailable<PTs...>();
+ };
+
+ template <typename Derived, typename ValTy, int I, typename ...Types>
+ class PointerUnionMembers;
+
+ template <typename Derived, typename ValTy, int I>
+ class PointerUnionMembers<Derived, ValTy, I> {
+ protected:
+ ValTy Val;
+ PointerUnionMembers() = default;
+ PointerUnionMembers(ValTy Val) : Val(Val) {}
+
+ friend struct PointerLikeTypeTraits<Derived>;
+ };
+
+ template <typename Derived, typename ValTy, int I, typename Type,
+ typename ...Types>
+ class PointerUnionMembers<Derived, ValTy, I, Type, Types...>
+ : public PointerUnionMembers<Derived, ValTy, I + 1, Types...> {
+ using Base = PointerUnionMembers<Derived, ValTy, I + 1, Types...>;
+ public:
+ using Base::Base;
+ PointerUnionMembers() = default;
+ PointerUnionMembers(Type V)
+ : Base(ValTy(const_cast<void *>(
+ PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
+ I)) {}
+
+ using Base::operator=;
+ Derived &operator=(Type V) {
+ this->Val = ValTy(
+ const_cast<void *>(PointerLikeTypeTraits<Type>::getAsVoidPointer(V)),
+ I);
+ return static_cast<Derived &>(*this);
+ };
+ };
+}
+
+/// A discriminated union of two or more pointer types, with the discriminator
+/// in the low bit of the pointer.
+///
+/// This implementation is extremely efficient in space due to leveraging the
+/// low bits of the pointer, while exposing a natural and type-safe API.
+///
+/// Common use patterns would be something like this:
+/// PointerUnion<int*, float*> P;
+/// P = (int*)0;
+/// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0"
+/// X = P.get<int*>(); // ok.
+/// Y = P.get<float*>(); // runtime assertion failure.
+/// Z = P.get<double*>(); // compile time failure.
+/// P = (float*)0;
+/// Y = P.get<float*>(); // ok.
+/// X = P.get<int*>(); // runtime assertion failure.
+/// PointerUnion<int*, int*> Q; // compile time failure.
+template <typename... PTs>
+class PointerUnion
+ : public pointer_union_detail::PointerUnionMembers<
+ PointerUnion<PTs...>,
+ PointerIntPair<
+ void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int,
+ pointer_union_detail::PointerUnionUIntTraits<PTs...>>,
+ 0, PTs...> {
+ static_assert(TypesAreDistinct<PTs...>::value,
+ "PointerUnion alternative types cannot be repeated");
+ // The first type is special because we want to directly cast a pointer to a
+ // default-initialized union to a pointer to the first type. But we don't
+ // want PointerUnion to be a 'template <typename First, typename ...Rest>'
+ // because it's much more convenient to have a name for the whole pack. So
+ // split off the first type here.
+ using First = TypeAtIndex<0, PTs...>;
+ using Base = typename PointerUnion::PointerUnionMembers;
+
+public:
+ PointerUnion() = default;
+
+ PointerUnion(std::nullptr_t) : PointerUnion() {}
+ using Base::Base;
+
+ /// Test if the pointer held in the union is null, regardless of
+ /// which type it is.
+ bool isNull() const { return !this->Val.getPointer(); }
+
+ explicit operator bool() const { return !isNull(); }
+
+ /// Test if the Union currently holds the type matching T.
+ template <typename T> bool is() const {
+ return this->Val.getInt() == FirstIndexOfType<T, PTs...>::value;
+ }
+
+ /// 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());
+ }
+
+ /// 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();
+ }
+
+ /// If the union is set to the first pointer type get an address pointing to
+ /// it.
+ First const *getAddrOfPtr1() const {
+ return const_cast<PointerUnion *>(this)->getAddrOfPtr1();
+ }
+
+ /// 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(
+ PointerLikeTypeTraits<First>::getAsVoidPointer(get<First>()) ==
+ this->Val.getPointer() &&
+ "Can't get the address because PointerLikeTypeTraits changes the ptr");
+ return const_cast<First *>(
+ reinterpret_cast<const First *>(this->Val.getAddrOfPointer()));
+ }
+
+ /// Assignment from nullptr which just clears the union.
+ const PointerUnion &operator=(std::nullptr_t) {
+ this->Val.initWithPointer(nullptr);
+ return *this;
+ }
+
+ /// Assignment from elements of the union.
+ using Base::operator=;
+
+ void *getOpaqueValue() const { return this->Val.getOpaqueValue(); }
+ static inline PointerUnion getFromOpaqueValue(void *VP) {
+ PointerUnion V;
+ V.Val = decltype(V.Val)::getFromOpaqueValue(VP);
+ return V;
+ }
+};
+
+template <typename ...PTs>
+bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+ return lhs.getOpaqueValue() == rhs.getOpaqueValue();
+}
+
+template <typename ...PTs>
+bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+ return lhs.getOpaqueValue() != rhs.getOpaqueValue();
+}
+
+template <typename ...PTs>
+bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) {
+ return lhs.getOpaqueValue() < rhs.getOpaqueValue();
+}
+
+// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
+// # low bits available = min(PT1bits,PT2bits)-1.
+template <typename ...PTs>
+struct PointerLikeTypeTraits<PointerUnion<PTs...>> {
+ static inline void *getAsVoidPointer(const PointerUnion<PTs...> &P) {
+ return P.getOpaqueValue();
+ }
+
+ static inline PointerUnion<PTs...> getFromVoidPointer(void *P) {
+ return PointerUnion<PTs...>::getFromOpaqueValue(P);
+ }
+
+ // The number of bits available are the min of the pointer types minus the
+ // bits needed for the discriminator.
+ static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits<decltype(
+ PointerUnion<PTs...>::Val)>::NumLowBitsAvailable;
+};
+
+// Teach DenseMap how to use PointerUnions as keys.
+template <typename ...PTs> struct DenseMapInfo<PointerUnion<PTs...>> {
+ using Union = PointerUnion<PTs...>;
+ using FirstInfo =
+ DenseMapInfo<typename pointer_union_detail::GetFirstType<PTs...>::type>;
+
+ static inline Union getEmptyKey() { return Union(FirstInfo::getEmptyKey()); }
+
+ static inline Union getTombstoneKey() {
+ return Union(FirstInfo::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const Union &UnionVal) {
+ intptr_t key = (intptr_t)UnionVal.getOpaqueValue();
+ return DenseMapInfo<intptr_t>::getHashValue(key);
+ }
+
+ static bool isEqual(const Union &LHS, const Union &RHS) {
+ return LHS == RHS;
+ }
+};
+
+} // end namespace wpi
+
+#endif // WPIUTIL_WPI_POINTERUNION_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
new file mode 100644
index 0000000..f46d38d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/ReverseIteration.h
@@ -0,0 +1,18 @@
+#ifndef WPIUTIL_WPI_REVERSEITERATION_H
+#define WPIUTIL_WPI_REVERSEITERATION_H
+
+#include "wpi/PointerLikeTypeTraits.h"
+
+namespace wpi {
+
+template<class T = void *>
+bool shouldReverseIterate() {
+#if LLVM_ENABLE_REVERSE_ITERATION
+ return detail::IsPointerLike<T>::value;
+#else
+ return false;
+#endif
+}
+
+}
+#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
new file mode 100644
index 0000000..7f8f068
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/STLForwardCompat.h
@@ -0,0 +1,83 @@
+//===- STLForwardCompat.h - Library features from future STLs ------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 contains library features backported from future STL versions.
+///
+/// These should be replaced with their STL counterparts as the C++ version LLVM
+/// is compiled with is updated.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_STLFORWARDCOMPAT_H
+#define WPIUTIL_WPI_STLFORWARDCOMPAT_H
+
+#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
+//===----------------------------------------------------------------------===//
+
+template <typename T>
+struct remove_cvref // NOLINT(readability-identifier-naming)
+{
+ using type = std::remove_cv_t<std::remove_reference_t<T>>;
+};
+
+template <typename T>
+using remove_cvref_t // NOLINT(readability-identifier-naming)
+ = typename wpi::remove_cvref<T>::type;
+
+} // namespace wpi
+
+#endif // WPIUTIL_WPI_STLFORWARDCOMPAT_H
diff --git a/wpiutil/src/main/native/include/wpi/SmallPtrSet.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
similarity index 83%
rename from wpiutil/src/main/native/include/wpi/SmallPtrSet.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
index 8669527..1ada1e0 100644
--- a/wpiutil/src/main/native/include/wpi/SmallPtrSet.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallPtrSet.h
@@ -1,26 +1,26 @@
//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 SmallPtrSet class. See the doxygen comment for
-// SmallPtrSetImplBase for more details on the algorithm used.
+///
+/// \file
+/// This file defines the SmallPtrSet class. See the doxygen comment for
+/// SmallPtrSetImplBase for more details on the algorithm used.
//
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_SMALLPTRSET_H
#define WPIUTIL_WPI_SMALLPTRSET_H
+#include "wpi/EpochTracker.h"
#include "wpi/Compiler.h"
-#include "wpi/PointerLikeTypeTraits.h"
+#include "wpi/ReverseIteration.h"
#include "wpi/type_traits.h"
#include <cassert>
#include <cstddef>
-#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <initializer_list>
@@ -47,7 +47,7 @@
/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or
/// more. When this happens, the table is doubled in size.
///
-class SmallPtrSetImplBase {
+class SmallPtrSetImplBase : public DebugEpochBase {
friend class SmallPtrSetIteratorImpl;
protected:
@@ -93,6 +93,7 @@
size_type size() const { return NumNonEmpty - NumTombstones; }
void clear() {
+ incrementEpoch();
// If the capacity of the array is huge, and the # elements used is small,
// shrink the array.
if (!isSmall()) {
@@ -139,12 +140,14 @@
if (LastTombstone != nullptr) {
*LastTombstone = Ptr;
--NumTombstones;
+ incrementEpoch();
return std::make_pair(LastTombstone, true);
}
// Nope, there isn't. If we stay small, just 'pushback' now.
if (NumNonEmpty < CurArraySize) {
SmallArray[NumNonEmpty++] = Ptr;
+ incrementEpoch();
return std::make_pair(SmallArray + (NumNonEmpty - 1), true);
}
// Otherwise, hit the big set case, which will call grow.
@@ -224,6 +227,10 @@
public:
explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E)
: Bucket(BP), End(E) {
+ if (shouldReverseIterate()) {
+ RetreatIfNotValid();
+ return;
+ }
AdvanceIfNotValid();
}
@@ -257,7 +264,8 @@
/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet.
template <typename PtrTy>
-class SmallPtrSetIterator : public SmallPtrSetIteratorImpl {
+class SmallPtrSetIterator : public SmallPtrSetIteratorImpl,
+ DebugEpochBase::HandleBase {
using PtrTraits = PointerLikeTypeTraits<PtrTy>;
public:
@@ -267,17 +275,29 @@
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
- explicit SmallPtrSetIterator(const void *const *BP, const void *const *E)
- : SmallPtrSetIteratorImpl(BP, E) {}
+ explicit SmallPtrSetIterator(const void *const *BP, const void *const *E,
+ const DebugEpochBase &Epoch)
+ : SmallPtrSetIteratorImpl(BP, E), DebugEpochBase::HandleBase(&Epoch) {}
- // Most methods provided by baseclass.
+ // Most methods are provided by the base class.
const PtrTy operator*() const {
+ assert(isHandleInSync() && "invalid iterator access!");
+ if (shouldReverseIterate()) {
+ assert(Bucket > End);
+ return PtrTraits::getFromVoidPointer(const_cast<void *>(Bucket[-1]));
+ }
assert(Bucket < End);
return PtrTraits::getFromVoidPointer(const_cast<void*>(*Bucket));
}
inline SmallPtrSetIterator& operator++() { // Preincrement
+ assert(isHandleInSync() && "invalid iterator access!");
+ if (shouldReverseIterate()) {
+ --Bucket;
+ RetreatIfNotValid();
+ return *this;
+ }
++Bucket;
AdvanceIfNotValid();
return *this;
@@ -327,14 +347,8 @@
using ConstPtrTraits = PointerLikeTypeTraits<ConstPtrType>;
protected:
- // Constructors that forward to the base.
- SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that)
- : SmallPtrSetImplBase(SmallStorage, that) {}
- SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize,
- SmallPtrSetImpl &&that)
- : SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {}
- explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize)
- : SmallPtrSetImplBase(SmallStorage, SmallSize) {}
+ // Forward constructors to the base.
+ using SmallPtrSetImplBase::SmallPtrSetImplBase;
public:
using iterator = SmallPtrSetIterator<PtrType>;
@@ -353,17 +367,28 @@
return std::make_pair(makeIterator(p.first), p.second);
}
+ /// Insert the given pointer with an iterator hint that is ignored. This is
+ /// identical to calling insert(Ptr), but allows SmallPtrSet to be used by
+ /// std::insert_iterator and std::inserter().
+ iterator insert(iterator, PtrType Ptr) {
+ return insert(Ptr).first;
+ }
+
/// erase - If the set contains the specified pointer, remove it and return
/// true, otherwise return false.
bool erase(PtrType Ptr) {
return erase_imp(PtrTraits::getAsVoidPointer(Ptr));
}
-
/// count - Return 1 if the specified pointer is in the set, 0 otherwise.
- size_type count(ConstPtrType Ptr) const { return find(Ptr) != end() ? 1 : 0; }
+ size_type count(ConstPtrType Ptr) const {
+ return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
+ }
iterator find(ConstPtrType Ptr) const {
return makeIterator(find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)));
}
+ bool contains(ConstPtrType Ptr) const {
+ return find_imp(ConstPtrTraits::getAsVoidPointer(Ptr)) != EndPointer();
+ }
template <typename IterT>
void insert(IterT I, IterT E) {
@@ -376,6 +401,8 @@
}
iterator begin() const {
+ if (shouldReverseIterate())
+ return makeIterator(EndPointer() - 1);
return makeIterator(CurArray);
}
iterator end() const { return makeIterator(EndPointer()); }
@@ -383,10 +410,38 @@
private:
/// Create an iterator that dereferences to same place as the given pointer.
iterator makeIterator(const void *const *P) const {
- return iterator(P, EndPointer());
+ if (shouldReverseIterate())
+ return iterator(P == EndPointer() ? CurArray : P + 1, CurArray, *this);
+ return iterator(P, EndPointer(), *this);
}
};
+/// Equality comparison for SmallPtrSet.
+///
+/// Iterates over elements of LHS confirming that each value from LHS is also in
+/// RHS, and that no additional values are in RHS.
+template <typename PtrType>
+bool operator==(const SmallPtrSetImpl<PtrType> &LHS,
+ const SmallPtrSetImpl<PtrType> &RHS) {
+ if (LHS.size() != RHS.size())
+ return false;
+
+ for (const auto *KV : LHS)
+ if (!RHS.count(KV))
+ return false;
+
+ return true;
+}
+
+/// Inequality comparison for SmallPtrSet.
+///
+/// Equivalent to !(LHS == RHS).
+template <typename PtrType>
+bool operator!=(const SmallPtrSetImpl<PtrType> &LHS,
+ const SmallPtrSetImpl<PtrType> &RHS) {
+ return !(LHS == RHS);
+}
+
/// SmallPtrSet - This class implements a set which is optimized for holding
/// SmallSize or less elements. This internally rounds up SmallSize to the next
/// power of two if it is not already a power of two. See the comments above
@@ -460,4 +515,4 @@
} // end namespace std
-#endif // LLVM_ADT_SMALLPTRSET_H
+#endif // WPIUTIL_WPI_SMALLPTRSET_H
diff --git a/wpiutil/src/main/native/include/wpi/SmallSet.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
similarity index 83%
rename from wpiutil/src/main/native/include/wpi/SmallSet.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
index dca204e..7b1b283 100644
--- a/wpiutil/src/main/native/include/wpi/SmallSet.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallSet.h
@@ -1,14 +1,14 @@
//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 SmallSet class.
-//
+///
+/// \file
+/// This file defines the SmallSet class.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_SMALLSET_H
@@ -16,8 +16,8 @@
#include "wpi/SmallPtrSet.h"
#include "wpi/SmallVector.h"
-#include "wpi/Compiler.h"
#include "wpi/iterator.h"
+#include "wpi/Compiler.h"
#include "wpi/type_traits.h"
#include <cstddef>
#include <functional>
@@ -233,6 +233,13 @@
return {Set.end()};
}
+ /// Check if the SmallSet contains the given element.
+ bool contains(const T &V) const {
+ if (isSmall())
+ return vfind(V) != Vector.end();
+ return Set.find(V) != Set.end();
+ }
+
private:
bool isSmall() const { return Set.empty(); }
@@ -249,6 +256,31 @@
template <typename PointeeType, unsigned N>
class SmallSet<PointeeType*, N> : public SmallPtrSet<PointeeType*, N> {};
+/// Equality comparison for SmallSet.
+///
+/// Iterates over elements of LHS confirming that each element is also a member
+/// of RHS, and that RHS contains no additional values.
+/// Equivalent to N calls to RHS.count.
+/// For small-set mode amortized complexity is O(N^2)
+/// For large-set mode amortized complexity is linear, worst case is O(N^2) (if
+/// every hash collides).
+template <typename T, unsigned LN, unsigned RN, typename C>
+bool operator==(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
+ if (LHS.size() != RHS.size())
+ return false;
+
+ // All elements in LHS must also be in RHS
+ return std::all_of(LHS.begin(), LHS.end(), [&RHS](const T &E) { return RHS.count(E); });
+}
+
+/// Inequality comparison for SmallSet.
+///
+/// Equivalent to !(LHS == RHS). See operator== for performance notes.
+template <typename T, unsigned LN, unsigned RN, typename C>
+bool operator!=(const SmallSet<T, LN, C> &LHS, const SmallSet<T, RN, C> &RHS) {
+ return !(LHS == RHS);
+}
+
} // end namespace wpi
-#endif // LLVM_ADT_SMALLSET_H
+#endif // WPIUTIL_WPI_SMALLSET_H
diff --git a/wpiutil/src/main/native/include/wpi/SmallString.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
similarity index 71%
rename from wpiutil/src/main/native/include/wpi/SmallString.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
index da4b2e4..4a53fee 100644
--- a/wpiutil/src/main/native/include/wpi/SmallString.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallString.h
@@ -1,14 +1,14 @@
//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 SmallString class.
-//
+///
+/// \file
+/// This file defines the SmallString class.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_SMALLSTRING_H
@@ -16,6 +16,7 @@
#include "wpi/SmallVector.h"
#include <cstddef>
+#include <string>
#include <string_view>
namespace wpi {
@@ -29,66 +30,58 @@
SmallString() = default;
/// Initialize from a std::string_view.
- SmallString(std::string_view S)
- : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
+ SmallString(std::string_view S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
+
+ /// Initialize by concatenating a list of std::string_views.
+ SmallString(std::initializer_list<std::string_view> Refs)
+ : SmallVector<char, InternalLen>() {
+ this->append(Refs);
+ }
/// Initialize with a range.
template<typename ItTy>
SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {}
- // Note that in order to add new overloads for append & assign, we have to
- // duplicate the inherited versions so as not to inadvertently hide them.
-
/// @}
/// @name String Assignment
/// @{
- /// Assign from a repeated element.
- void assign(size_t NumElts, char Elt) {
- this->SmallVectorImpl<char>::assign(NumElts, Elt);
- }
-
- /// Assign from an iterator pair.
- template<typename in_iter>
- void assign(in_iter S, in_iter E) {
- this->clear();
- SmallVectorImpl<char>::append(S, E);
- }
+ using SmallVector<char, InternalLen>::assign;
/// Assign from a std::string_view.
void assign(std::string_view RHS) {
- this->clear();
- SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+ SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
}
- /// Assign from a SmallVector.
- void assign(const SmallVectorImpl<char> &RHS) {
+ /// Assign from a list of std::string_views.
+ void assign(std::initializer_list<std::string_view> Refs) {
this->clear();
- SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+ append(Refs);
}
/// @}
/// @name String Concatenation
/// @{
- /// Append from an iterator pair.
- template<typename in_iter>
- void append(in_iter S, in_iter E) {
- SmallVectorImpl<char>::append(S, E);
- }
-
- void append(size_t NumInputs, char Elt) {
- SmallVectorImpl<char>::append(NumInputs, Elt);
- }
+ using SmallVector<char, InternalLen>::append;
/// Append from a std::string_view.
void append(std::string_view RHS) {
SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
}
- /// Append from a SmallVector.
- void append(const SmallVectorImpl<char> &RHS) {
- SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
+ /// Append from a list of std::string_views.
+ void append(std::initializer_list<std::string_view> Refs) {
+ size_t CurrentSize = this->size();
+ size_t SizeNeeded = CurrentSize;
+ for (std::string_view Ref : Refs)
+ SizeNeeded += Ref.size();
+ this->resize_for_overwrite(SizeNeeded);
+ for (std::string_view Ref : Refs) {
+ std::copy(Ref.begin(), Ref.end(), this->begin() + CurrentSize);
+ CurrentSize += Ref.size();
+ }
+ assert(CurrentSize == this->size());
}
/// @}
@@ -185,10 +178,7 @@
// Extra methods.
/// Explicit conversion to std::string_view.
- std::string_view str() const { return {this->begin(), this->size()}; }
-
- /// Explicit conversion to std::string.
- std::string string() const { return {this->begin(), this->size()}; }
+ std::string_view str() const { return std::string_view(this->begin(), this->size()); }
// TODO: Make this const, if it's safe...
const char* c_str() {
@@ -200,13 +190,14 @@
/// Implicit conversion to std::string_view.
operator std::string_view() const { return str(); }
- /// Implicit conversion to std::string.
- operator std::string() const { return string(); }
+ explicit operator std::string() const {
+ return std::string(this->data(), this->size());
+ }
// Extra operators.
- const SmallString &operator=(std::string_view RHS) {
- this->clear();
- return *this += RHS;
+ SmallString &operator=(std::string_view RHS) {
+ this->assign(RHS);
+ return *this;
}
SmallString &operator+=(std::string_view RHS) {
@@ -221,4 +212,4 @@
} // end namespace wpi
-#endif // LLVM_ADT_SMALLSTRING_H
+#endif // WPIUTIL_WPI_SMALLSTRING_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
new file mode 100644
index 0000000..134ce67
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVector.h
@@ -0,0 +1,1312 @@
+//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- 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 the SmallVector class.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_SMALLVECTOR_H
+#define WPIUTIL_WPI_SMALLVECTOR_H
+
+// This file uses std::memcpy() to copy std::pair<unsigned int, unsigned int>.
+// That type is POD, but the standard doesn't guarantee that. GCC doesn't treat
+// the type as POD so it throws a warning. We want to consider this a warning
+// instead of an error.
+#if __GNUC__ >= 8
+#pragma GCC diagnostic warning "-Wclass-memaccess"
+#endif
+
+#include "wpi/Compiler.h"
+#include "wpi/type_traits.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <initializer_list>
+#include <iterator>
+#include <limits>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace wpi {
+
+template <typename IteratorT> class iterator_range;
+
+/// This is all the stuff common to all SmallVectors.
+///
+/// The template parameter specifies the type which should be used to hold the
+/// Size and Capacity of the SmallVector, so it can be adjusted.
+/// Using 32 bit size is desirable to shrink the size of the SmallVector.
+/// Using 64 bit size is desirable for cases like SmallVector<char>, where a
+/// 32 bit size would limit the vector to ~4GB. SmallVectors are used for
+/// buffering bitcode output - which can exceed 4GB.
+class SmallVectorBase {
+protected:
+ void *BeginX;
+ unsigned Size = 0, Capacity;
+
+ /// The maximum value of the Size_T used.
+ static constexpr size_t SizeTypeMax() {
+ return (std::numeric_limits<unsigned>::max)();
+ }
+
+ SmallVectorBase() = delete;
+ SmallVectorBase(void *FirstEl, size_t TotalCapacity)
+ : BeginX(FirstEl), Capacity(static_cast<unsigned>(TotalCapacity)) {}
+
+ /// 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);
+
+ /// 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);
+
+public:
+ size_t size() const { return Size; }
+ size_t capacity() const { return Capacity; }
+
+ LLVM_NODISCARD bool empty() const { return !Size; }
+
+protected:
+ /// Set the array size to \p N, which the current array must have enough
+ /// capacity for.
+ ///
+ /// This does not construct or destroy any elements in the vector.
+ void set_size(size_t N) {
+ assert(N <= capacity());
+ Size = static_cast<unsigned>(N);
+ }
+};
+
+/// Figure out the offset of the first element.
+template <class T, typename = void> struct SmallVectorAlignmentAndSize {
+ alignas(SmallVectorBase) char Base[sizeof(
+ SmallVectorBase)];
+ alignas(T) char FirstEl[sizeof(T)];
+};
+
+/// 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
+/// to avoid unnecessarily requiring T to be complete.
+template <typename T, typename = void>
+class SmallVectorTemplateCommon
+ : public SmallVectorBase {
+ using Base = SmallVectorBase;
+
+ /// 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.
+ void *getFirstEl() const {
+ return const_cast<void *>(reinterpret_cast<const void *>(
+ reinterpret_cast<const char *>(this) +
+ offsetof(SmallVectorAlignmentAndSize<T>, FirstEl)));
+ }
+ // 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) {
+ Base::grow_pod(getFirstEl(), MinSize, TSize);
+ }
+
+ /// Return true if this is a smallvector which has not had dynamic
+ /// memory allocated for it.
+ bool isSmall() const { return this->BeginX == getFirstEl(); }
+
+ /// Put this vector in a state of being small.
+ void resetToSmall() {
+ this->BeginX = getFirstEl();
+ this->Size = this->Capacity = 0; // FIXME: Setting Capacity to 0 is suspect.
+ }
+
+ /// Return true if V is an internal reference to the given range.
+ bool isReferenceToRange(const void *V, const void *First, const void *Last) const {
+ // Use std::less to avoid UB.
+ std::less<> LessThan;
+ return !LessThan(V, First) && LessThan(V, Last);
+ }
+
+ /// Return true if V is an internal reference to this vector.
+ bool isReferenceToStorage(const void *V) const {
+ return isReferenceToRange(V, this->begin(), this->end());
+ }
+
+ /// Return true if First and Last form a valid (possibly empty) range in this
+ /// vector's storage.
+ bool isRangeInStorage(const void *First, const void *Last) const {
+ // Use std::less to avoid UB.
+ std::less<> LessThan;
+ return !LessThan(First, this->begin()) && !LessThan(Last, First) &&
+ !LessThan(this->end(), Last);
+ }
+
+ /// Return true unless Elt will be invalidated by resizing the vector to
+ /// NewSize.
+ bool isSafeToReferenceAfterResize(const void *Elt, size_t NewSize) {
+ // Past the end.
+ if (LLVM_LIKELY(!isReferenceToStorage(Elt)))
+ return true;
+
+ // Return false if Elt will be destroyed by shrinking.
+ if (NewSize <= this->size())
+ return Elt < this->begin() + NewSize;
+
+ // Return false if we need to grow.
+ return NewSize <= this->capacity();
+ }
+
+ /// Check whether Elt will be invalidated by resizing the vector to NewSize.
+ void assertSafeToReferenceAfterResize(const void *Elt, size_t NewSize) {
+ assert(isSafeToReferenceAfterResize(Elt, NewSize) &&
+ "Attempting to reference an element of the vector in an operation "
+ "that invalidates it");
+ }
+
+ /// Check whether Elt will be invalidated by increasing the size of the
+ /// vector by N.
+ void assertSafeToAdd(const void *Elt, size_t N = 1) {
+ this->assertSafeToReferenceAfterResize(Elt, this->size() + N);
+ }
+
+ /// Check whether any part of the range will be invalidated by clearing.
+ void assertSafeToReferenceAfterClear(const T *From, const T *To) {
+ if (From == To)
+ return;
+ this->assertSafeToReferenceAfterResize(From, 0);
+ this->assertSafeToReferenceAfterResize(To - 1, 0);
+ }
+ template <
+ class ItTy,
+ std::enable_if_t<!std::is_same<std::remove_const_t<ItTy>, T *>::value,
+ bool> = false>
+ void assertSafeToReferenceAfterClear(ItTy, ItTy) {}
+
+ /// Check whether any part of the range will be invalidated by growing.
+ void assertSafeToAddRange(const T *From, const T *To) {
+ if (From == To)
+ return;
+ this->assertSafeToAdd(From, To - From);
+ this->assertSafeToAdd(To - 1, To - From);
+ }
+ template <
+ class ItTy,
+ std::enable_if_t<!std::is_same<std::remove_const_t<ItTy>, T *>::value,
+ bool> = false>
+ void assertSafeToAddRange(ItTy, ItTy) {}
+
+ /// Reserve enough space to add one element, and return the updated element
+ /// pointer in case it was a reference to the storage.
+ template <class U>
+ static const T *reserveForParamAndGetAddressImpl(U *This, const T &Elt,
+ size_t N) {
+ size_t NewSize = This->size() + N;
+ if (LLVM_LIKELY(NewSize <= This->capacity()))
+ return &Elt;
+
+ bool ReferencesStorage = false;
+ int64_t Index = -1;
+ if (!U::TakesParamByValue) {
+ if (LLVM_UNLIKELY(This->isReferenceToStorage(&Elt))) {
+ ReferencesStorage = true;
+ Index = &Elt - This->begin();
+ }
+ }
+ This->grow(NewSize);
+ return ReferencesStorage ? This->begin() + Index : &Elt;
+ }
+
+public:
+ using size_type = size_t;
+ using difference_type = ptrdiff_t;
+ using value_type = T;
+ using iterator = T *;
+ using const_iterator = const T *;
+
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+ using reverse_iterator = std::reverse_iterator<iterator>;
+
+ using reference = T &;
+ using const_reference = const T &;
+ using pointer = T *;
+ using const_pointer = const T *;
+
+ using Base::capacity;
+ using Base::empty;
+ using Base::size;
+
+ // forward iterator creation methods.
+ iterator begin() { return (iterator)this->BeginX; }
+ const_iterator begin() const { return (const_iterator)this->BeginX; }
+ iterator end() { return begin() + size(); }
+ const_iterator end() const { return begin() + size(); }
+
+ // reverse iterator creation methods.
+ 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());}
+
+ size_type size_in_bytes() const { return size() * sizeof(T); }
+ size_type max_size() const {
+ return (std::min)(this->SizeTypeMax(), size_type(-1) / sizeof(T));
+ }
+
+ size_t capacity_in_bytes() const { return capacity() * sizeof(T); }
+
+ /// Return a pointer to the vector's buffer, even if empty().
+ pointer data() { return pointer(begin()); }
+ /// Return a pointer to the vector's buffer, even if empty().
+ const_pointer data() const { return const_pointer(begin()); }
+
+ reference operator[](size_type idx) {
+ assert(idx < size());
+ return begin()[idx];
+ }
+ const_reference operator[](size_type idx) const {
+ assert(idx < size());
+ return begin()[idx];
+ }
+
+ reference front() {
+ assert(!empty());
+ return begin()[0];
+ }
+ const_reference front() const {
+ assert(!empty());
+ return begin()[0];
+ }
+
+ reference back() {
+ assert(!empty());
+ return end()[-1];
+ }
+ const_reference back() const {
+ assert(!empty());
+ return end()[-1];
+ }
+};
+
+/// SmallVectorTemplateBase<TriviallyCopyable = false> - This is where we put
+/// method implementations that are designed to work with non-trivial T's.
+///
+/// We approximate is_trivially_copyable with trivial move/copy construction and
+/// trivial destruction. While the standard doesn't specify that you're allowed
+/// 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) &&
+ std::is_trivially_destructible<T>::value>
+class SmallVectorTemplateBase : public SmallVectorTemplateCommon<T> {
+ friend class SmallVectorTemplateCommon<T>;
+
+protected:
+ static constexpr bool TakesParamByValue = false;
+ using ValueParamT = const T &;
+
+ SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
+
+ static void destroy_range(T *S, T *E) {
+ while (S != E) {
+ --E;
+ E->~T();
+ }
+ }
+
+ /// Move the range [I, E) into the uninitialized memory starting with "Dest",
+ /// 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);
+ }
+
+ /// Copy the range [I, E) onto the uninitialized memory starting with "Dest",
+ /// constructing elements as needed.
+ template<typename It1, typename It2>
+ static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
+ std::uninitialized_copy(I, E, Dest);
+ }
+
+ /// Grow the allocated memory (without initializing new elements), doubling
+ /// the size of the allocated memory. Guarantees space for at least one more
+ /// element, or MinSize more elements if specified.
+ void grow(size_t MinSize = 0);
+
+ /// 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));
+ }
+
+ /// Move existing elements over to the new allocation \p NewElts, the middle
+ /// section of \a grow().
+ void moveElementsForGrow(T *NewElts);
+
+ /// Transfer ownership of the allocation, finishing up \a grow().
+ void takeAllocationForGrow(T *NewElts, size_t NewCapacity);
+
+ /// Reserve enough space to add one element, and return the updated element
+ /// pointer in case it was a reference to the storage.
+ const T *reserveForParamAndGetAddress(const T &Elt, size_t N = 1) {
+ return this->reserveForParamAndGetAddressImpl(this, Elt, N);
+ }
+
+ /// Reserve enough space to add one element, and return the updated element
+ /// pointer in case it was a reference to the storage.
+ T *reserveForParamAndGetAddress(T &Elt, size_t N = 1) {
+ return const_cast<T *>(
+ this->reserveForParamAndGetAddressImpl(this, Elt, N));
+ }
+
+ static T &&forward_value_param(T &&V) { return std::move(V); }
+ static const T &forward_value_param(const T &V) { return V; }
+
+ void growAndAssign(size_t NumElts, const T &Elt) {
+ // Grow manually in case Elt is an internal reference.
+ size_t NewCapacity;
+ T *NewElts = mallocForGrow(NumElts, NewCapacity);
+ std::uninitialized_fill_n(NewElts, NumElts, Elt);
+ this->destroy_range(this->begin(), this->end());
+ takeAllocationForGrow(NewElts, NewCapacity);
+ this->set_size(NumElts);
+ }
+
+ template <typename... ArgTypes> T &growAndEmplaceBack(ArgTypes &&... Args) {
+ // Grow manually in case one of Args is an internal reference.
+ size_t NewCapacity;
+ T *NewElts = mallocForGrow(0, NewCapacity);
+ ::new ((void *)(NewElts + this->size())) T(std::forward<ArgTypes>(Args)...);
+ moveElementsForGrow(NewElts);
+ takeAllocationForGrow(NewElts, NewCapacity);
+ this->set_size(this->size() + 1);
+ return this->back();
+ }
+
+public:
+ void push_back(const T &Elt) {
+ const T *EltPtr = reserveForParamAndGetAddress(Elt);
+ ::new ((void *)this->end()) T(*EltPtr);
+ this->set_size(this->size() + 1);
+ }
+
+ void push_back(T &&Elt) {
+ T *EltPtr = reserveForParamAndGetAddress(Elt);
+ ::new ((void *)this->end()) T(::std::move(*EltPtr));
+ this->set_size(this->size() + 1);
+ }
+
+ void pop_back() {
+ this->set_size(this->size() - 1);
+ this->end()->~T();
+ }
+};
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T, bool TriviallyCopyable>
+void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) {
+ size_t NewCapacity;
+ T *NewElts = mallocForGrow(MinSize, NewCapacity);
+ moveElementsForGrow(NewElts);
+ takeAllocationForGrow(NewElts, NewCapacity);
+}
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T, bool TriviallyCopyable>
+void SmallVectorTemplateBase<T, TriviallyCopyable>::moveElementsForGrow(
+ T *NewElts) {
+ // Move the elements over.
+ this->uninitialized_move(this->begin(), this->end(), NewElts);
+
+ // Destroy the original elements.
+ destroy_range(this->begin(), this->end());
+}
+
+// Define this out-of-line to dissuade the C++ compiler from inlining it.
+template <typename T, bool TriviallyCopyable>
+void SmallVectorTemplateBase<T, TriviallyCopyable>::takeAllocationForGrow(
+ T *NewElts, size_t NewCapacity) {
+ // If this wasn't grown from the inline copy, deallocate the old space.
+ if (!this->isSmall())
+ free(this->begin());
+
+ this->BeginX = NewElts;
+ this->Capacity = static_cast<unsigned>(NewCapacity);
+}
+
+/// SmallVectorTemplateBase<TriviallyCopyable = true> - This is where we put
+/// method implementations that are designed to work with trivially copyable
+/// T's. This allows using memcpy in place of copy/move construction and
+/// skipping destruction.
+template <typename T>
+class SmallVectorTemplateBase<T, true> : public SmallVectorTemplateCommon<T> {
+ friend class SmallVectorTemplateCommon<T>;
+
+protected:
+ /// True if it's cheap enough to take parameters by value. Doing so avoids
+ /// overhead related to mitigations for reference invalidation.
+ static constexpr bool TakesParamByValue = sizeof(T) <= 2 * sizeof(void *);
+
+ /// 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;
+
+ SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon<T>(Size) {}
+
+ // No need to do a destroy loop for POD's.
+ static void destroy_range(T *, T *) {}
+
+ /// Move the range [I, E) onto the uninitialized memory
+ /// starting with "Dest", constructing elements into it as needed.
+ template<typename It1, typename It2>
+ static void uninitialized_move(It1 I, It1 E, It2 Dest) {
+ // Just do a copy.
+ uninitialized_copy(I, E, Dest);
+ }
+
+ /// Copy the range [I, E) onto the uninitialized memory
+ /// starting with "Dest", constructing elements into it as needed.
+ template<typename It1, typename It2>
+ static void uninitialized_copy(It1 I, It1 E, It2 Dest) {
+ // Arbitrary iterator types; just use the basic implementation.
+ std::uninitialized_copy(I, E, Dest);
+ }
+
+ /// Copy the range [I, E) onto the uninitialized memory
+ /// starting with "Dest", constructing elements into it as needed.
+ 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) {
+ // 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
+ // invalid for memcpy if they are equal.
+ if (I != E)
+ memcpy(reinterpret_cast<void *>(Dest), I, (E - I) * sizeof(T));
+ }
+
+ /// Double the size of the allocated memory, guaranteeing space for at
+ /// least one more element or MinSize if specified.
+ void grow(size_t MinSize = 0) { this->grow_pod(MinSize, sizeof(T)); }
+
+ /// Reserve enough space to add one element, and return the updated element
+ /// pointer in case it was a reference to the storage.
+ const T *reserveForParamAndGetAddress(const T &Elt, size_t N = 1) {
+ return this->reserveForParamAndGetAddressImpl(this, Elt, N);
+ }
+
+ /// Reserve enough space to add one element, and return the updated element
+ /// pointer in case it was a reference to the storage.
+ T *reserveForParamAndGetAddress(T &Elt, size_t N = 1) {
+ return const_cast<T *>(
+ this->reserveForParamAndGetAddressImpl(this, Elt, N));
+ }
+
+ /// Copy \p V or return a reference, depending on \a ValueParamT.
+ static ValueParamT forward_value_param(ValueParamT V) { return V; }
+
+ void growAndAssign(size_t NumElts, T Elt) {
+ // Elt has been copied in case it's an internal reference, side-stepping
+ // reference invalidation problems without losing the realloc optimization.
+ this->set_size(0);
+ this->grow(NumElts);
+ std::uninitialized_fill_n(this->begin(), NumElts, Elt);
+ this->set_size(NumElts);
+ }
+
+ template <typename... ArgTypes> T &growAndEmplaceBack(ArgTypes &&... Args) {
+ // Use push_back with a copy in case Args has an internal reference,
+ // side-stepping reference invalidation problems without losing the realloc
+ // optimization.
+ push_back(T(std::forward<ArgTypes>(Args)...));
+ return this->back();
+ }
+
+public:
+ void push_back(ValueParamT Elt) {
+ const T *EltPtr = reserveForParamAndGetAddress(Elt);
+ memcpy(reinterpret_cast<void *>(this->end()), EltPtr, sizeof(T));
+ this->set_size(this->size() + 1);
+ }
+
+ void pop_back() { this->set_size(this->size() - 1); }
+};
+
+/// This class consists of common code factored out of the SmallVector class to
+/// reduce code duplication based on the SmallVector 'N' template parameter.
+template <typename T>
+class SmallVectorImpl : public SmallVectorTemplateBase<T> {
+ using SuperClass = SmallVectorTemplateBase<T>;
+
+public:
+ using iterator = typename SuperClass::iterator;
+ using const_iterator = typename SuperClass::const_iterator;
+ using reference = typename SuperClass::reference;
+ using size_type = typename SuperClass::size_type;
+
+protected:
+ using SmallVectorTemplateBase<T>::TakesParamByValue;
+ using ValueParamT = typename SuperClass::ValueParamT;
+
+ // Default ctor - Initialize to empty.
+ explicit SmallVectorImpl(unsigned N)
+ : SmallVectorTemplateBase<T>(N) {}
+
+ void assignRemote(SmallVectorImpl &&RHS) {
+ this->destroy_range(this->begin(), this->end());
+ if (!this->isSmall())
+ free(this->begin());
+ this->BeginX = RHS.BeginX;
+ this->Size = RHS.Size;
+ this->Capacity = RHS.Capacity;
+ RHS.resetToSmall();
+ }
+
+public:
+ SmallVectorImpl(const SmallVectorImpl &) = delete;
+
+ ~SmallVectorImpl() {
+ // Subclass has already destructed this vector's elements.
+ // If this wasn't grown from the inline copy, deallocate the old space.
+ if (!this->isSmall())
+ free(this->begin());
+ }
+
+ void clear() {
+ this->destroy_range(this->begin(), this->end());
+ this->Size = 0;
+ }
+
+private:
+ // Make set_size() private to avoid misuse in subclasses.
+ using SuperClass::set_size;
+
+ template <bool ForOverwrite> void resizeImpl(size_type N) {
+ if (N == this->size())
+ return;
+
+ if (N < this->size()) {
+ this->truncate(N);
+ return;
+ }
+
+ this->reserve(N);
+ for (auto I = this->end(), E = this->begin() + N; I != E; ++I)
+ if (ForOverwrite)
+ new (&*I) T;
+ else
+ new (&*I) T();
+ this->set_size(N);
+ }
+
+public:
+ void resize(size_type N) { resizeImpl<false>(N); }
+
+ /// Like resize, but \ref T is POD, the new values won't be initialized.
+ void resize_for_overwrite(size_type N) { resizeImpl<true>(N); }
+
+ /// Like resize, but requires that \p N is less than \a size().
+ void truncate(size_type N) {
+ assert(this->size() >= N && "Cannot increase size with truncate");
+ this->destroy_range(this->begin() + N, this->end());
+ this->set_size(N);
+ }
+
+ void resize(size_type N, ValueParamT NV) {
+ if (N == this->size())
+ return;
+
+ if (N < this->size()) {
+ this->truncate(N);
+ return;
+ }
+
+ // N > this->size(). Defer to append.
+ this->append(N - this->size(), NV);
+ }
+
+ void reserve(size_type N) {
+ if (this->capacity() < N)
+ this->grow(N);
+ }
+
+ void pop_back_n(size_type NumItems) {
+ assert(this->size() >= NumItems);
+ truncate(this->size() - NumItems);
+ }
+
+ LLVM_NODISCARD T pop_back_val() {
+ T Result = ::std::move(this->back());
+ this->pop_back();
+ return Result;
+ }
+
+ 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) {
+ this->assertSafeToAddRange(in_start, in_end);
+ size_type NumInputs = std::distance(in_start, in_end);
+ this->reserve(this->size() + NumInputs);
+ this->uninitialized_copy(in_start, in_end, this->end());
+ this->set_size(this->size() + NumInputs);
+ }
+
+ /// Append \p NumInputs copies of \p Elt to the end.
+ void append(size_type NumInputs, ValueParamT Elt) {
+ const T *EltPtr = this->reserveForParamAndGetAddress(Elt, NumInputs);
+ std::uninitialized_fill_n(this->end(), NumInputs, *EltPtr);
+ this->set_size(this->size() + NumInputs);
+ }
+
+ void append(std::initializer_list<T> IL) {
+ append(IL.begin(), IL.end());
+ }
+
+ void append(const SmallVectorImpl &RHS) { append(RHS.begin(), RHS.end()); }
+
+ void assign(size_type NumElts, ValueParamT Elt) {
+ // Note that Elt could be an internal reference.
+ if (NumElts > this->capacity()) {
+ this->growAndAssign(NumElts, Elt);
+ return;
+ }
+
+ // Assign over existing elements.
+ std::fill_n(this->begin(), (std::min)(NumElts, this->size()), Elt);
+ if (NumElts > this->size())
+ std::uninitialized_fill_n(this->end(), NumElts - this->size(), Elt);
+ else if (NumElts < this->size())
+ this->destroy_range(this->begin() + NumElts, this->end());
+ this->set_size(NumElts);
+ }
+
+ // 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) {
+ this->assertSafeToReferenceAfterClear(in_start, in_end);
+ clear();
+ append(in_start, in_end);
+ }
+
+ void assign(std::initializer_list<T> IL) {
+ clear();
+ append(IL);
+ }
+
+ void assign(const SmallVectorImpl &RHS) { assign(RHS.begin(), RHS.end()); }
+
+ iterator erase(const_iterator CI) {
+ // Just cast away constness because this is a non-const member function.
+ iterator I = const_cast<iterator>(CI);
+
+ assert(this->isReferenceToStorage(CI) && "Iterator to erase is out of bounds.");
+
+ iterator N = I;
+ // Shift all elts down one.
+ std::move(I+1, this->end(), I);
+ // Drop the last elt.
+ this->pop_back();
+ return(N);
+ }
+
+ iterator erase(const_iterator CS, const_iterator CE) {
+ // Just cast away constness because this is a non-const member function.
+ iterator S = const_cast<iterator>(CS);
+ iterator E = const_cast<iterator>(CE);
+
+ assert(this->isRangeInStorage(S, E) && "Range to erase is out of bounds.");
+
+ iterator N = S;
+ // Shift all elts down.
+ iterator I = std::move(E, this->end(), S);
+ // Drop the last elts.
+ this->destroy_range(I, this->end());
+ this->set_size(I - this->begin());
+ return(N);
+ }
+
+private:
+ template <class ArgType> iterator insert_one_impl(iterator I, ArgType &&Elt) {
+ // Callers ensure that ArgType is derived from T.
+ static_assert(
+ std::is_same<std::remove_const_t<std::remove_reference_t<ArgType>>,
+ T>::value,
+ "ArgType must be derived from T!");
+
+ if (I == this->end()) { // Important special case for empty vector.
+ this->push_back(::std::forward<ArgType>(Elt));
+ return this->end()-1;
+ }
+
+ assert(this->isReferenceToStorage(I) && "Insertion iterator is out of bounds.");
+
+ // Grow if necessary.
+ size_t Index = I - this->begin();
+ std::remove_reference_t<ArgType> *EltPtr =
+ this->reserveForParamAndGetAddress(Elt);
+ I = this->begin() + Index;
+
+ ::new ((void*) this->end()) T(::std::move(this->back()));
+ // Push everything else over.
+ std::move_backward(I, this->end()-1, this->end());
+ this->set_size(this->size() + 1);
+
+ // If we just moved the element we're inserting, be sure to update
+ // the reference (never happens if TakesParamByValue).
+ static_assert(!TakesParamByValue || std::is_same<ArgType, T>::value,
+ "ArgType must be 'T' when taking by value!");
+ if (!TakesParamByValue && this->isReferenceToRange(EltPtr, I, this->end()))
+ ++EltPtr;
+
+ *I = ::std::forward<ArgType>(*EltPtr);
+ return I;
+ }
+
+public:
+ iterator insert(iterator I, T &&Elt) {
+ return insert_one_impl(I, this->forward_value_param(std::move(Elt)));
+ }
+
+ iterator insert(iterator I, const T &Elt) {
+ return insert_one_impl(I, this->forward_value_param(Elt));
+ }
+
+ iterator insert(iterator I, size_type NumToInsert, ValueParamT Elt) {
+ // Convert iterator to elt# to avoid invalidating iterator when we reserve()
+ size_t InsertElt = I - this->begin();
+
+ if (I == this->end()) { // Important special case for empty vector.
+ append(NumToInsert, Elt);
+ return this->begin()+InsertElt;
+ }
+
+ assert(this->isReferenceToStorage(I) && "Insertion iterator is out of bounds.");
+
+ // Ensure there is enough space, and get the (maybe updated) address of
+ // Elt.
+ const T *EltPtr = this->reserveForParamAndGetAddress(Elt, NumToInsert);
+
+ // Uninvalidate the iterator.
+ I = this->begin()+InsertElt;
+
+ // If there are more elements between the insertion point and the end of the
+ // range than there are being inserted, we can use a simple approach to
+ // insertion. Since we already reserved space, we know that this won't
+ // reallocate the vector.
+ if (size_t(this->end()-I) >= NumToInsert) {
+ T *OldEnd = this->end();
+ append(std::move_iterator<iterator>(this->end() - NumToInsert),
+ std::move_iterator<iterator>(this->end()));
+
+ // Copy the existing elements that get replaced.
+ std::move_backward(I, OldEnd-NumToInsert, OldEnd);
+
+ // If we just moved the element we're inserting, be sure to update
+ // the reference (never happens if TakesParamByValue).
+ if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end())
+ EltPtr += NumToInsert;
+
+ std::fill_n(I, NumToInsert, *EltPtr);
+ return I;
+ }
+
+ // Otherwise, we're inserting more elements than exist already, and we're
+ // not inserting at the end.
+
+ // Move over the elements that we're about to overwrite.
+ T *OldEnd = this->end();
+ this->set_size(this->size() + NumToInsert);
+ size_t NumOverwritten = OldEnd-I;
+ this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
+
+ // If we just moved the element we're inserting, be sure to update
+ // the reference (never happens if TakesParamByValue).
+ if (!TakesParamByValue && I <= EltPtr && EltPtr < this->end())
+ EltPtr += NumToInsert;
+
+ // Replace the overwritten part.
+ std::fill_n(I, NumOverwritten, *EltPtr);
+
+ // Insert the non-overwritten middle part.
+ std::uninitialized_fill_n(OldEnd, NumToInsert - NumOverwritten, *EltPtr);
+ 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>>
+ 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();
+
+ if (I == this->end()) { // Important special case for empty vector.
+ append(From, To);
+ return this->begin()+InsertElt;
+ }
+
+ assert(this->isReferenceToStorage(I) && "Insertion iterator is out of bounds.");
+
+ // Check that the reserve that follows doesn't invalidate the iterators.
+ this->assertSafeToAddRange(From, To);
+
+ size_t NumToInsert = std::distance(From, To);
+
+ // Ensure there is enough space.
+ reserve(this->size() + NumToInsert);
+
+ // Uninvalidate the iterator.
+ I = this->begin()+InsertElt;
+
+ // If there are more elements between the insertion point and the end of the
+ // range than there are being inserted, we can use a simple approach to
+ // insertion. Since we already reserved space, we know that this won't
+ // reallocate the vector.
+ if (size_t(this->end()-I) >= NumToInsert) {
+ T *OldEnd = this->end();
+ append(std::move_iterator<iterator>(this->end() - NumToInsert),
+ std::move_iterator<iterator>(this->end()));
+
+ // Copy the existing elements that get replaced.
+ std::move_backward(I, OldEnd-NumToInsert, OldEnd);
+
+ std::copy(From, To, I);
+ return I;
+ }
+
+ // Otherwise, we're inserting more elements than exist already, and we're
+ // not inserting at the end.
+
+ // Move over the elements that we're about to overwrite.
+ T *OldEnd = this->end();
+ this->set_size(this->size() + NumToInsert);
+ size_t NumOverwritten = OldEnd-I;
+ this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten);
+
+ // Replace the overwritten part.
+ for (T *J = I; NumOverwritten > 0; --NumOverwritten) {
+ *J = *From;
+ ++J; ++From;
+ }
+
+ // Insert the non-overwritten middle part.
+ this->uninitialized_copy(From, To, OldEnd);
+ return I;
+ }
+
+ void insert(iterator I, std::initializer_list<T> IL) {
+ insert(I, IL.begin(), IL.end());
+ }
+
+ template <typename... ArgTypes> reference emplace_back(ArgTypes &&... Args) {
+ if (LLVM_UNLIKELY(this->size() >= this->capacity()))
+ return this->growAndEmplaceBack(std::forward<ArgTypes>(Args)...);
+
+ ::new ((void *)this->end()) T(std::forward<ArgTypes>(Args)...);
+ this->set_size(this->size() + 1);
+ return this->back();
+ }
+
+ SmallVectorImpl &operator=(const SmallVectorImpl &RHS);
+
+ SmallVectorImpl &operator=(SmallVectorImpl &&RHS);
+
+ bool operator==(const SmallVectorImpl &RHS) const {
+ if (this->size() != RHS.size()) return false;
+ return std::equal(this->begin(), this->end(), RHS.begin());
+ }
+ bool operator!=(const SmallVectorImpl &RHS) const {
+ return !(*this == RHS);
+ }
+
+ bool operator<(const SmallVectorImpl &RHS) const {
+ return std::lexicographical_compare(this->begin(), this->end(),
+ RHS.begin(), RHS.end());
+ }
+};
+
+template <typename T>
+void SmallVectorImpl<T>::swap(SmallVectorImpl<T> &RHS) {
+ if (this == &RHS) return;
+
+ // We can only avoid copying elements if neither vector is small.
+ if (!this->isSmall() && !RHS.isSmall()) {
+ std::swap(this->BeginX, RHS.BeginX);
+ std::swap(this->Size, RHS.Size);
+ std::swap(this->Capacity, RHS.Capacity);
+ return;
+ }
+ this->reserve(RHS.size());
+ RHS.reserve(this->size());
+
+ // Swap the shared elements.
+ size_t NumShared = this->size();
+ if (NumShared > RHS.size()) NumShared = RHS.size();
+ for (size_type i = 0; i != NumShared; ++i)
+ std::swap((*this)[i], RHS[i]);
+
+ // Copy over the extra elts.
+ if (this->size() > RHS.size()) {
+ size_t EltDiff = this->size() - RHS.size();
+ this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end());
+ RHS.set_size(RHS.size() + EltDiff);
+ this->destroy_range(this->begin()+NumShared, this->end());
+ this->set_size(NumShared);
+ } else if (RHS.size() > this->size()) {
+ size_t EltDiff = RHS.size() - this->size();
+ this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end());
+ this->set_size(this->size() + EltDiff);
+ this->destroy_range(RHS.begin()+NumShared, RHS.end());
+ RHS.set_size(NumShared);
+ }
+}
+
+template <typename T>
+SmallVectorImpl<T> &SmallVectorImpl<T>::
+ operator=(const SmallVectorImpl<T> &RHS) {
+ // Avoid self-assignment.
+ if (this == &RHS) return *this;
+
+ // If we already have sufficient space, assign the common elements, then
+ // destroy any excess.
+ size_t RHSSize = RHS.size();
+ size_t CurSize = this->size();
+ if (CurSize >= RHSSize) {
+ // Assign common elements.
+ iterator NewEnd;
+ if (RHSSize)
+ NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin());
+ else
+ NewEnd = this->begin();
+
+ // Destroy excess elements.
+ this->destroy_range(NewEnd, this->end());
+
+ // Trim.
+ this->set_size(RHSSize);
+ return *this;
+ }
+
+ // If we have to grow to have enough elements, destroy the current elements.
+ // This allows us to avoid copying them during the grow.
+ // FIXME: don't do this if they're efficiently moveable.
+ if (this->capacity() < RHSSize) {
+ // Destroy current elements.
+ this->clear();
+ CurSize = 0;
+ this->grow(RHSSize);
+ } else if (CurSize) {
+ // Otherwise, use assignment for the already-constructed elements.
+ std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin());
+ }
+
+ // Copy construct the new elements in place.
+ this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(),
+ this->begin()+CurSize);
+
+ // Set end.
+ this->set_size(RHSSize);
+ return *this;
+}
+
+template <typename T>
+SmallVectorImpl<T> &SmallVectorImpl<T>::operator=(SmallVectorImpl<T> &&RHS) {
+ // Avoid self-assignment.
+ if (this == &RHS) return *this;
+
+ // If the RHS isn't small, clear this vector and then steal its buffer.
+ if (!RHS.isSmall()) {
+ this->assignRemote(std::move(RHS));
+ return *this;
+ }
+
+ // If we already have sufficient space, assign the common elements, then
+ // destroy any excess.
+ size_t RHSSize = RHS.size();
+ size_t CurSize = this->size();
+ if (CurSize >= RHSSize) {
+ // Assign common elements.
+ iterator NewEnd = this->begin();
+ if (RHSSize)
+ NewEnd = std::move(RHS.begin(), RHS.end(), NewEnd);
+
+ // Destroy excess elements and trim the bounds.
+ this->destroy_range(NewEnd, this->end());
+ this->set_size(RHSSize);
+
+ // Clear the RHS.
+ RHS.clear();
+
+ return *this;
+ }
+
+ // If we have to grow to have enough elements, destroy the current elements.
+ // This allows us to avoid copying them during the grow.
+ // FIXME: this may not actually make any sense if we can efficiently move
+ // elements.
+ if (this->capacity() < RHSSize) {
+ // Destroy current elements.
+ this->clear();
+ CurSize = 0;
+ this->grow(RHSSize);
+ } else if (CurSize) {
+ // Otherwise, use assignment for the already-constructed elements.
+ std::move(RHS.begin(), RHS.begin()+CurSize, this->begin());
+ }
+
+ // Move-construct the new elements in place.
+ this->uninitialized_move(RHS.begin()+CurSize, RHS.end(),
+ this->begin()+CurSize);
+
+ // Set end.
+ this->set_size(RHSSize);
+
+ RHS.clear();
+ return *this;
+}
+
+/// Storage for the SmallVector elements. This is specialized for the N=0 case
+/// to avoid allocating unnecessary storage.
+template <typename T, unsigned N>
+struct SmallVectorStorage {
+ alignas(T) char InlineElts[N * sizeof(T)];
+};
+
+/// We need the storage to be properly aligned even for small-size of 0 so that
+/// the pointer math in \a SmallVectorTemplateCommon::getFirstEl() is
+/// well-defined.
+template <typename T> struct alignas(T) SmallVectorStorage<T, 0> {};
+
+/// Forward declaration of SmallVector so that
+/// calculateSmallVectorDefaultInlinedElements can reference
+/// `sizeof(SmallVector<T, 0>)`.
+template <typename T, unsigned N> class LLVM_GSL_OWNER SmallVector;
+
+/// Helper class for calculating the default number of inline elements for
+/// `SmallVector<T>`.
+///
+/// This should be migrated to a constexpr function when our minimum
+/// compiler support is enough for multi-statement constexpr functions.
+template <typename T> struct CalculateSmallVectorDefaultInlinedElements {
+ // Parameter controlling the default number of inlined elements
+ // for `SmallVector<T>`.
+ //
+ // The default number of inlined elements ensures that
+ // 1. There is at least one inlined element.
+ // 2. `sizeof(SmallVector<T>) <= kPreferredSmallVectorSizeof` unless
+ // it contradicts 1.
+ static constexpr size_t kPreferredSmallVectorSizeof = 64;
+
+ // static_assert that sizeof(T) is not "too big".
+ //
+ // Because our policy guarantees at least one inlined element, it is possible
+ // for an arbitrarily large inlined element to allocate an arbitrarily large
+ // amount of inline storage. We generally consider it an antipattern for a
+ // SmallVector to allocate an excessive amount of inline storage, so we want
+ // to call attention to these cases and make sure that users are making an
+ // intentional decision if they request a lot of inline storage.
+ //
+ // We want this assertion to trigger in pathological cases, but otherwise
+ // not be too easy to hit. To accomplish that, the cutoff is actually somewhat
+ // larger than kPreferredSmallVectorSizeof (otherwise,
+ // `SmallVector<SmallVector<T>>` would be one easy way to trip it, and that
+ // pattern seems useful in practice).
+ //
+ // One wrinkle is that this assertion is in theory non-portable, since
+ // sizeof(T) is in general platform-dependent. However, we don't expect this
+ // to be much of an issue, because most LLVM development happens on 64-bit
+ // hosts, and therefore sizeof(T) is expected to *decrease* when compiled for
+ // 32-bit hosts, dodging the issue. The reverse situation, where development
+ // happens on a 32-bit host and then fails due to sizeof(T) *increasing* on a
+ // 64-bit host, is expected to be very rare.
+ static_assert(
+ sizeof(T) <= 256,
+ "You are trying to use a default number of inlined elements for "
+ "`SmallVector<T>` but `sizeof(T)` is really big! Please use an "
+ "explicit number of inlined elements with `SmallVector<T, N>` to make "
+ "sure you really want that much inline storage.");
+
+ // Discount the size of the header itself when calculating the maximum inline
+ // bytes.
+ static constexpr size_t PreferredInlineBytes =
+ kPreferredSmallVectorSizeof - sizeof(SmallVector<T, 0>);
+ static constexpr size_t NumElementsThatFit = PreferredInlineBytes / sizeof(T);
+ static constexpr size_t value =
+ NumElementsThatFit == 0 ? 1 : NumElementsThatFit;
+};
+
+/// This is a 'vector' (really, a variable-sized array), optimized
+/// for the case when the array is small. It contains some number of elements
+/// in-place, which allows it to avoid heap allocation when the actual number of
+/// elements is below that threshold. This allows normal "small" cases to be
+/// fast without losing generality for large inputs.
+///
+/// \note
+/// In the absence of a well-motivated choice for the number of inlined
+/// elements \p N, it is recommended to use \c SmallVector<T> (that is,
+/// omitting the \p N). This will choose a default number of inlined elements
+/// reasonable for allocation on the stack (for example, trying to keep \c
+/// sizeof(SmallVector<T>) around 64 bytes).
+///
+/// \warning This does not attempt to be exception safe.
+///
+/// \see https://llvm.org/docs/ProgrammersManual.html#llvm-adt-smallvector-h
+template <typename T,
+ unsigned N = CalculateSmallVectorDefaultInlinedElements<T>::value>
+class LLVM_GSL_OWNER SmallVector : public SmallVectorImpl<T>,
+ SmallVectorStorage<T, N> {
+public:
+ SmallVector() : SmallVectorImpl<T>(N) {}
+
+ ~SmallVector() {
+ // Destroy the constructed elements in the vector.
+ this->destroy_range(this->begin(), this->end());
+ }
+
+ explicit SmallVector(size_t Size, const T &Value = T())
+ : 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>>
+ SmallVector(ItTy S, ItTy E) : SmallVectorImpl<T>(N) {
+ this->append(S, E);
+ }
+
+ template <typename RangeTy>
+ explicit SmallVector(const iterator_range<RangeTy> &R)
+ : SmallVectorImpl<T>(N) {
+ this->append(R.begin(), R.end());
+ }
+
+ SmallVector(std::initializer_list<T> IL) : SmallVectorImpl<T>(N) {
+ this->assign(IL);
+ }
+
+ SmallVector(const SmallVector &RHS) : SmallVectorImpl<T>(N) {
+ if (!RHS.empty())
+ SmallVectorImpl<T>::operator=(RHS);
+ }
+
+ SmallVector &operator=(const SmallVector &RHS) {
+ SmallVectorImpl<T>::operator=(RHS);
+ return *this;
+ }
+
+ SmallVector(SmallVector &&RHS) : SmallVectorImpl<T>(N) {
+ if (!RHS.empty())
+ SmallVectorImpl<T>::operator=(::std::move(RHS));
+ }
+
+ SmallVector(SmallVectorImpl<T> &&RHS) : SmallVectorImpl<T>(N) {
+ if (!RHS.empty())
+ SmallVectorImpl<T>::operator=(::std::move(RHS));
+ }
+
+ SmallVector &operator=(SmallVector &&RHS) {
+ if (N) {
+ SmallVectorImpl<T>::operator=(::std::move(RHS));
+ return *this;
+ }
+ // SmallVectorImpl<T>::operator= does not leverage N==0. Optimize the
+ // case.
+ if (this == &RHS)
+ return *this;
+ if (RHS.empty()) {
+ this->destroy_range(this->begin(), this->end());
+ this->Size = 0;
+ } else {
+ this->assignRemote(std::move(RHS));
+ }
+ return *this;
+ }
+
+ SmallVector &operator=(SmallVectorImpl<T> &&RHS) {
+ SmallVectorImpl<T>::operator=(::std::move(RHS));
+ return *this;
+ }
+
+ SmallVector &operator=(std::initializer_list<T> IL) {
+ this->assign(IL);
+ return *this;
+ }
+};
+
+template <typename T, unsigned N>
+inline size_t capacity_in_bytes(const SmallVector<T, N> &X) {
+ return X.capacity_in_bytes();
+}
+
+template <typename RangeType>
+using ValueTypeFromRangeType =
+ typename std::remove_const<typename std::remove_reference<
+ decltype(*std::begin(std::declval<RangeType &>()))>::type>::type;
+
+/// Given a range of type R, iterate the entire range and return a
+/// SmallVector with elements of the vector. This is useful, for example,
+/// when you want to iterate a range and then sort the results.
+template <unsigned Size, typename R>
+SmallVector<ValueTypeFromRangeType<R>, Size> to_vector(R &&Range) {
+ return {std::begin(Range), std::end(Range)};
+}
+template <typename R>
+SmallVector<ValueTypeFromRangeType<R>,
+ CalculateSmallVectorDefaultInlinedElements<
+ ValueTypeFromRangeType<R>>::value>
+to_vector(R &&Range) {
+ return {std::begin(Range), std::end(Range)};
+}
+
+} // end namespace wpi
+
+namespace std {
+
+ /// Implement std::swap in terms of SmallVector swap.
+ template<typename T>
+ inline void
+ swap(wpi::SmallVectorImpl<T> &LHS, wpi::SmallVectorImpl<T> &RHS) {
+ LHS.swap(RHS);
+ }
+
+ /// Implement std::swap in terms of SmallVector swap.
+ template<typename T, unsigned N>
+ inline void
+ swap(wpi::SmallVector<T, N> &LHS, wpi::SmallVector<T, N> &RHS) {
+ LHS.swap(RHS);
+ }
+
+} // end namespace std
+
+#endif // WPIUTIL_WPI_SMALLVECTOR_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
new file mode 100644
index 0000000..6173714
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SmallVectorMemoryBuffer.h
@@ -0,0 +1,63 @@
+// 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.
+
+//===- SmallVectorMemoryBuffer.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares a wrapper class to hold the memory into which an
+// object will be generated.
+//
+//===----------------------------------------------------------------------===//
+
+#pragma once
+
+#include <string>
+#include <string_view>
+#include <utility>
+
+#include "wpi/MemoryBuffer.h"
+#include "wpi/SmallVector.h"
+#include "wpi/raw_ostream.h"
+
+namespace wpi {
+
+/// SmallVector-backed MemoryBuffer instance.
+///
+/// This class enables efficient construction of MemoryBuffers from SmallVector
+/// instances.
+class SmallVectorMemoryBuffer : public MemoryBuffer {
+ public:
+ /// Construct an SmallVectorMemoryBuffer from the given SmallVector
+ /// r-value.
+ SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv) // NOLINT
+ : m_sv(std::move(sv)), m_bufferName("<in-memory object>") {
+ Init(this->m_sv.begin(), this->m_sv.end());
+ }
+
+ /// Construct a named SmallVectorMemoryBuffer from the given
+ /// SmallVector r-value and StringRef.
+ SmallVectorMemoryBuffer(SmallVectorImpl<uint8_t>&& sv, std::string_view name)
+ : m_sv(std::move(sv)), m_bufferName(name) {
+ Init(this->m_sv.begin(), this->m_sv.end());
+ }
+
+ // Key function.
+ ~SmallVectorMemoryBuffer() override;
+
+ std::string_view GetBufferIdentifier() const override { return m_bufferName; }
+
+ BufferKind GetBufferKind() const override { return MemoryBuffer_Malloc; }
+
+ private:
+ SmallVector<uint8_t, 0> m_sv;
+ std::string m_bufferName;
+};
+
+} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/StringExtras.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
similarity index 97%
rename from wpiutil/src/main/native/include/wpi/StringExtras.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
index 9e70f52..75c637b 100644
--- a/wpiutil/src/main/native/include/wpi/StringExtras.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringExtras.h
@@ -709,4 +709,16 @@
std::optional<long double> parse_float<long double>(
std::string_view str) noexcept;
+/**
+ * Unescapes a C-style string (reverse operation to raw_ostream::write_escaped).
+ * Scans through @p str until either the end is reached or an unescaped double
+ * quote character is found.
+ *
+ * @param str input string
+ * @param buf buffer for unescaped characters
+ * @return pair of the unescaped string and any remaining input
+ */
+std::pair<std::string_view, std::string_view> UnescapeCString(
+ std::string_view str, SmallVectorImpl<char>& buf);
+
} // namespace wpi
diff --git a/wpiutil/src/main/native/include/wpi/StringMap.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
similarity index 73%
rename from wpiutil/src/main/native/include/wpi/StringMap.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
index dac2f20..c7da670 100644
--- a/wpiutil/src/main/native/include/wpi/StringMap.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMap.h
@@ -1,51 +1,35 @@
//===- StringMap.h - String Hash table map interface ------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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 StringMap class.
-//
+///
+/// \file
+/// This file defines the StringMap class.
+///
//===----------------------------------------------------------------------===//
#ifndef WPIUTIL_WPI_STRINGMAP_H
#define WPIUTIL_WPI_STRINGMAP_H
+#include "wpi/StringMapEntry.h"
+#include "wpi/iterator.h"
+#include "wpi/AllocatorBase.h"
+#include "wpi/MemAlloc.h"
#include "wpi/SmallVector.h"
#include "wpi/iterator.h"
#include "wpi/iterator_range.h"
-#include "wpi/MemAlloc.h"
#include "wpi/PointerLikeTypeTraits.h"
-#include "wpi/ErrorHandling.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <cstdlib>
-#include <cstring>
#include <initializer_list>
#include <iterator>
-#include <string_view>
-#include <utility>
namespace wpi {
-template<typename ValueTy> class StringMapConstIterator;
-template<typename ValueTy> class StringMapIterator;
-template<typename ValueTy> class StringMapKeyIterator;
-template<typename ValueTy> class StringMapEntry;
-
-/// StringMapEntryBase - Shared base class of StringMapEntry instances.
-class StringMapEntryBase {
- size_t StrLen;
-
-public:
- explicit StringMapEntryBase(size_t Len) : StrLen(Len) {}
-
- size_t getKeyLength() const { return StrLen; }
-};
+template <typename ValueTy> class StringMapConstIterator;
+template <typename ValueTy> class StringMapIterator;
+template <typename ValueTy> class StringMapKeyIterator;
/// StringMapImpl - This is the base class of StringMap that is shared among
/// all of its instantiations.
@@ -61,8 +45,7 @@
unsigned ItemSize;
protected:
- explicit StringMapImpl(unsigned itemSize)
- : ItemSize(itemSize) {}
+ explicit StringMapImpl(unsigned itemSize) : ItemSize(itemSize) {}
StringMapImpl(StringMapImpl &&RHS) noexcept
: TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets),
NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones),
@@ -101,10 +84,12 @@
void init(unsigned Size);
public:
+ static constexpr uintptr_t TombstoneIntVal =
+ static_cast<uintptr_t>(-1)
+ << PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
+
static StringMapEntryBase *getTombstoneVal() {
- uintptr_t Val = static_cast<uintptr_t>(-1);
- Val <<= PointerLikeTypeTraits<StringMapEntryBase *>::NumLowBitsAvailable;
- return reinterpret_cast<StringMapEntryBase *>(Val);
+ return reinterpret_cast<StringMapEntryBase *>(TombstoneIntVal);
}
unsigned getNumBuckets() const { return NumBuckets; }
@@ -121,108 +106,41 @@
}
};
-/// StringMapEntry - This is used to represent one value that is inserted into
-/// a StringMap. It contains the Value itself and the key: the string length
-/// and data.
-template<typename ValueTy>
-class StringMapEntry : public StringMapEntryBase {
-public:
- ValueTy second;
-
- explicit StringMapEntry(size_t strLen)
- : StringMapEntryBase(strLen), second() {}
- template <typename... InitTy>
- StringMapEntry(size_t strLen, InitTy &&... InitVals)
- : StringMapEntryBase(strLen), second(std::forward<InitTy>(InitVals)...) {}
- StringMapEntry(StringMapEntry &E) = delete;
-
- std::string_view getKey() const {
- return {getKeyData(), getKeyLength()};
- }
-
- const ValueTy &getValue() const { return second; }
- ValueTy &getValue() { return second; }
-
- void setValue(const ValueTy &V) { second = V; }
-
- /// getKeyData - Return the start of the string data that is the key for this
- /// value. The string data is always stored immediately after the
- /// StringMapEntry object.
- const char *getKeyData() const {return reinterpret_cast<const char*>(this+1);}
-
- std::string_view first() const { return {getKeyData(), getKeyLength()}; }
-
- /// Create a StringMapEntry for the specified key construct the value using
- /// \p InitiVals.
- template <typename... InitTy>
- static StringMapEntry *Create(std::string_view Key, InitTy &&... InitVals) {
- size_t KeyLength = Key.size();
-
- // Allocate a new item with space for the string at the end and a null
- // terminator.
- size_t AllocSize = sizeof(StringMapEntry) + KeyLength + 1;
-
- StringMapEntry *NewItem =
- static_cast<StringMapEntry*>(safe_malloc(AllocSize));
-
- // Construct the value.
- new (NewItem) StringMapEntry(KeyLength, std::forward<InitTy>(InitVals)...);
-
- // Copy the string information.
- char *StrBuffer = const_cast<char*>(NewItem->getKeyData());
- if (KeyLength > 0)
- memcpy(StrBuffer, Key.data(), KeyLength);
- StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients.
- return NewItem;
- }
-
- static StringMapEntry *Create(std::string_view Key) {
- return Create(Key, ValueTy());
- }
-
- /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
- /// into a StringMapEntry, return the StringMapEntry itself.
- static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) {
- char *Ptr = const_cast<char*>(KeyData) - sizeof(StringMapEntry<ValueTy>);
- return *reinterpret_cast<StringMapEntry*>(Ptr);
- }
-
- /// Destroy - Destroy this StringMapEntry, releasing memory back to the
- /// specified allocator.
- void Destroy() {
- // Free memory referenced by the item.
- this->~StringMapEntry();
- std::free(static_cast<void *>(this));
- }
-};
-
-
/// StringMap - This is an unconventional map that is specialized for handling
/// keys that are "strings", which are basically ranges of bytes. This does some
/// funky memory allocation and hashing things to make it extremely efficient,
/// storing the string data *after* the value in the map.
-template<typename ValueTy>
+template <typename ValueTy, typename AllocatorTy = MallocAllocator>
class StringMap : public StringMapImpl {
+ AllocatorTy Allocator;
+
public:
using MapEntryTy = StringMapEntry<ValueTy>;
StringMap() : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {}
explicit StringMap(unsigned InitialSize)
- : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
+ : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))) {}
+
+ explicit StringMap(AllocatorTy A)
+ : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))), Allocator(A) {
+ }
+
+ StringMap(unsigned InitialSize, AllocatorTy A)
+ : StringMapImpl(InitialSize, static_cast<unsigned>(sizeof(MapEntryTy))),
+ Allocator(A) {}
StringMap(std::initializer_list<std::pair<std::string_view, ValueTy>> List)
: StringMapImpl(List.size(), static_cast<unsigned>(sizeof(MapEntryTy))) {
- for (const auto &P : List) {
- insert(P);
- }
+ insert(List);
}
StringMap(StringMap &&RHS)
- : StringMapImpl(std::move(RHS)) {}
+ : StringMapImpl(std::move(RHS)), Allocator(std::move(RHS.Allocator)) {}
- StringMap(const StringMap &RHS) :
- StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))) {
+ StringMap(const StringMap &RHS)
+ : StringMapImpl(static_cast<unsigned>(sizeof(MapEntryTy))),
+ Allocator(RHS.Allocator) {
if (RHS.empty())
return;
@@ -242,7 +160,7 @@
}
TheTable[I] = MapEntryTy::Create(
- static_cast<MapEntryTy *>(Bucket)->getKey(),
+ static_cast<MapEntryTy *>(Bucket)->getKey(), Allocator,
static_cast<MapEntryTy *>(Bucket)->getValue());
HashTable[I] = RHSHashTable[I];
}
@@ -257,6 +175,7 @@
StringMap &operator=(StringMap RHS) {
StringMapImpl::swap(RHS);
+ std::swap(Allocator, RHS.Allocator);
return *this;
}
@@ -268,14 +187,17 @@
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
- static_cast<MapEntryTy*>(Bucket)->Destroy();
+ static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
}
}
}
free(TheTable);
}
- using key_type = const char*;
+ AllocatorTy &getAllocator() { return Allocator; }
+ const AllocatorTy &getAllocator() const { return Allocator; }
+
+ using key_type = const char *;
using mapped_type = ValueTy;
using value_type = StringMapEntry<ValueTy>;
using size_type = size_t;
@@ -283,17 +205,13 @@
using const_iterator = StringMapConstIterator<ValueTy>;
using iterator = StringMapIterator<ValueTy>;
- iterator begin() {
- return iterator(TheTable, NumBuckets == 0);
- }
- iterator end() {
- return iterator(TheTable+NumBuckets, true);
- }
+ iterator begin() { return iterator(TheTable, NumBuckets == 0); }
+ iterator end() { return iterator(TheTable + NumBuckets, true); }
const_iterator begin() const {
return const_iterator(TheTable, NumBuckets == 0);
}
const_iterator end() const {
- return const_iterator(TheTable+NumBuckets, true);
+ return const_iterator(TheTable + NumBuckets, true);
}
iterator_range<StringMapKeyIterator<ValueTy>> keys() const {
@@ -303,14 +221,16 @@
iterator find(std::string_view Key) {
int Bucket = FindKey(Key);
- if (Bucket == -1) return end();
- return iterator(TheTable+Bucket, true);
+ if (Bucket == -1)
+ return end();
+ return iterator(TheTable + Bucket, true);
}
const_iterator find(std::string_view Key) const {
int Bucket = FindKey(Key);
- if (Bucket == -1) return end();
- return const_iterator(TheTable+Bucket, true);
+ if (Bucket == -1)
+ return end();
+ return const_iterator(TheTable + Bucket, true);
}
/// lookup - Return the entry for the specified key, or a default
@@ -327,10 +247,33 @@
ValueTy &operator[](std::string_view Key) { return try_emplace(Key).first->second; }
/// 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 find(Key) == end() ? 0 : 1; }
+
+ template <typename InputTy>
+ size_type count(const StringMapEntry<InputTy> &MapEntry) const {
+ return count(MapEntry.getKey());
}
+ /// equal - check whether both of the containers are equal.
+ bool operator==(const StringMap &RHS) const {
+ if (size() != RHS.size())
+ return false;
+
+ for (const auto &KeyValue : *this) {
+ auto FindInRHS = RHS.find(KeyValue.getKey());
+
+ if (FindInRHS == RHS.end())
+ return false;
+
+ if (!(KeyValue.getValue() == FindInRHS->getValue()))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool operator!=(const StringMap &RHS) const { return !(*this == RHS); }
+
/// insert - Insert the specified key/value pair into the map. If the key
/// already exists in the map, return false and ignore the request, otherwise
/// insert it and return true.
@@ -338,7 +281,7 @@
unsigned BucketNo = LookupBucketFor(KeyValue->getKey());
StringMapEntryBase *&Bucket = TheTable[BucketNo];
if (Bucket && Bucket != getTombstoneVal())
- return false; // Already exists in map.
+ return false; // Already exists in map.
if (Bucket == getTombstoneVal())
--NumTombstones;
@@ -358,6 +301,31 @@
return try_emplace(KV.first, std::move(KV.second));
}
+ /// Inserts elements from range [first, last). If multiple elements in the
+ /// range have keys that compare equivalent, it is unspecified which element
+ /// is inserted .
+ template <typename InputIt> void insert(InputIt First, InputIt Last) {
+ for (InputIt It = First; It != Last; ++It)
+ insert(*It);
+ }
+
+ /// Inserts elements from initializer list ilist. If multiple elements in
+ /// the range have keys that compare equivalent, it is unspecified which
+ /// element is inserted
+ void insert(std::initializer_list<std::pair<std::string_view, ValueTy>> List) {
+ insert(List.begin(), List.end());
+ }
+
+ /// Inserts an element or assigns to the current element if the key already
+ /// exists. The return type is the same as try_emplace.
+ template <typename V>
+ std::pair<iterator, bool> insert_or_assign(std::string_view Key, V &&Val) {
+ auto Ret = try_emplace(Key, std::forward<V>(Val));
+ if (!Ret.second)
+ Ret.first->second = std::forward<V>(Val);
+ return Ret;
+ }
+
/// Emplace a new element for the specified key into the map if the key isn't
/// already in the map. The bool component of the returned pair is true
/// if and only if the insertion takes place, and the iterator component of
@@ -372,7 +340,7 @@
if (Bucket == getTombstoneVal())
--NumTombstones;
- Bucket = MapEntryTy::Create(Key, std::forward<ArgsTy>(Args)...);
+ Bucket = MapEntryTy::Create(Key, Allocator, std::forward<ArgsTy>(Args)...);
++NumItems;
assert(NumItems + NumTombstones <= NumBuckets);
@@ -382,14 +350,15 @@
// clear - Empties out the StringMap
void clear() {
- if (empty()) return;
+ if (empty())
+ return;
// Zap all values, resetting the keys back to non-present (not tombstone),
// which is safe because we're removing all elements.
for (unsigned I = 0, E = NumBuckets; I != E; ++I) {
StringMapEntryBase *&Bucket = TheTable[I];
if (Bucket && Bucket != getTombstoneVal()) {
- static_cast<MapEntryTy*>(Bucket)->Destroy();
+ static_cast<MapEntryTy *>(Bucket)->Destroy(Allocator);
}
Bucket = nullptr;
}
@@ -400,19 +369,18 @@
/// remove - Remove the specified key/value pair from the map, but do not
/// erase it. This aborts if the key is not in the map.
- void remove(MapEntryTy *KeyValue) {
- RemoveKey(KeyValue);
- }
+ void remove(MapEntryTy *KeyValue) { RemoveKey(KeyValue); }
void erase(iterator I) {
MapEntryTy &V = *I;
remove(&V);
- V.Destroy();
+ V.Destroy(Allocator);
}
bool erase(std::string_view Key) {
iterator I = find(Key);
- if (I == end()) return false;
+ if (I == end())
+ return false;
erase(I);
return true;
}
@@ -431,7 +399,8 @@
explicit StringMapIterBase(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: Ptr(Bucket) {
- if (!NoAdvance) AdvancePastEmptyBuckets();
+ if (!NoAdvance)
+ AdvancePastEmptyBuckets();
}
DerivedTy &operator=(const DerivedTy &Other) {
@@ -439,13 +408,9 @@
return static_cast<DerivedTy &>(*this);
}
-#if __cplusplus < 202002L
- bool operator==(const DerivedTy &RHS) const { return Ptr == RHS.Ptr; }
-#else
friend bool operator==(const DerivedTy &LHS, const DerivedTy &RHS) {
return LHS.Ptr == RHS.Ptr;
}
-#endif
DerivedTy &operator++() { // Preincrement
++Ptr;
@@ -490,15 +455,13 @@
const StringMapEntry<ValueTy>>;
public:
- using value_type = const StringMapEntry<ValueTy>;
-
StringMapConstIterator() = default;
explicit StringMapConstIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: base(Bucket, NoAdvance) {}
- value_type &operator*() const {
- return *static_cast<value_type *>(*this->Ptr);
+ const StringMapEntry<ValueTy> &operator*() const {
+ return *static_cast<const StringMapEntry<ValueTy> *>(*this->Ptr);
}
};
@@ -509,15 +472,13 @@
StringMapIterBase<StringMapIterator<ValueTy>, StringMapEntry<ValueTy>>;
public:
- using value_type = StringMapEntry<ValueTy>;
-
StringMapIterator() = default;
explicit StringMapIterator(StringMapEntryBase **Bucket,
bool NoAdvance = false)
: base(Bucket, NoAdvance) {}
- value_type &operator*() const {
- return *static_cast<value_type *>(*this->Ptr);
+ StringMapEntry<ValueTy> &operator*() const {
+ return *static_cast<StringMapEntry<ValueTy> *>(*this->Ptr);
}
operator StringMapConstIterator<ValueTy>() const {
@@ -539,13 +500,7 @@
explicit StringMapKeyIterator(StringMapConstIterator<ValueTy> Iter)
: base(std::move(Iter)) {}
- std::string_view &operator*() {
- Key = this->wrapped()->getKey();
- return Key;
- }
-
-private:
- std::string_view Key;
+ std::string_view operator*() const { return this->wrapped()->getKey(); }
};
template <typename ValueTy>
@@ -635,4 +590,4 @@
} // end namespace wpi
-#endif // LLVM_ADT_STRINGMAP_H
+#endif // WPIUTIL_WPI_STRINGMAP_H
diff --git a/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
new file mode 100644
index 0000000..2b33aa6
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/StringMapEntry.h
@@ -0,0 +1,153 @@
+//===- StringMapEntry.h - String Hash table map interface -------*- 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 the StringMapEntry class - it is intended to be a low
+/// dependency implementation detail of StringMap that is more suitable for
+/// inclusion in public headers than StringMap.h itself is.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_STRINGMAPENTRY_H
+#define WPIUTIL_WPI_STRINGMAPENTRY_H
+
+#include "wpi/MemAlloc.h"
+
+#include <cassert>
+#include <cstring>
+#include <optional>
+#include <string_view>
+
+namespace wpi {
+
+/// StringMapEntryBase - Shared base class of StringMapEntry instances.
+class StringMapEntryBase {
+ size_t keyLength;
+
+public:
+ explicit StringMapEntryBase(size_t keyLength) : keyLength(keyLength) {}
+
+ size_t getKeyLength() const { return keyLength; }
+
+protected:
+ /// Helper to tail-allocate \p Key. It'd be nice to generalize this so it
+ /// could be reused elsewhere, maybe even taking an wpi::function_ref to
+ /// type-erase the allocator and put it in a source file.
+ template <typename AllocatorTy>
+ static void *allocateWithKey(size_t EntrySize, size_t EntryAlign,
+ std::string_view Key, AllocatorTy &Allocator);
+};
+
+// Define out-of-line to dissuade inlining.
+template <typename AllocatorTy>
+void *StringMapEntryBase::allocateWithKey(size_t EntrySize, size_t EntryAlign,
+ std::string_view Key,
+ AllocatorTy &Allocator) {
+ size_t KeyLength = Key.size();
+
+ // Allocate a new item with space for the string at the end and a null
+ // terminator.
+ size_t AllocSize = EntrySize + KeyLength + 1;
+ void *Allocation = Allocator.Allocate(AllocSize, EntryAlign);
+ assert(Allocation && "Unhandled out-of-memory");
+
+ // Copy the string information.
+ char *Buffer = reinterpret_cast<char *>(Allocation) + EntrySize;
+ if (KeyLength > 0)
+ ::memcpy(Buffer, Key.data(), KeyLength);
+ Buffer[KeyLength] = 0; // Null terminate for convenience of clients.
+ return Allocation;
+}
+
+/// StringMapEntryStorage - Holds the value in a StringMapEntry.
+///
+/// Factored out into a separate base class to make it easier to specialize.
+/// This is primarily intended to support StringSet, which doesn't need a value
+/// stored at all.
+template <typename ValueTy>
+class StringMapEntryStorage : public StringMapEntryBase {
+public:
+ ValueTy second;
+
+ explicit StringMapEntryStorage(size_t keyLength)
+ : StringMapEntryBase(keyLength), second() {}
+ template <typename... InitTy>
+ StringMapEntryStorage(size_t keyLength, InitTy &&... initVals)
+ : StringMapEntryBase(keyLength),
+ second(std::forward<InitTy>(initVals)...) {}
+ StringMapEntryStorage(StringMapEntryStorage &e) = delete;
+
+ const ValueTy &getValue() const { return second; }
+ ValueTy &getValue() { return second; }
+
+ void setValue(const ValueTy &V) { second = V; }
+};
+
+template <> class StringMapEntryStorage<std::nullopt_t> : public StringMapEntryBase {
+public:
+ explicit StringMapEntryStorage(size_t keyLength, std::nullopt_t = std::nullopt)
+ : StringMapEntryBase(keyLength) {}
+ StringMapEntryStorage(StringMapEntryStorage &entry) = delete;
+
+ std::nullopt_t getValue() const { return std::nullopt; }
+};
+
+/// StringMapEntry - This is used to represent one value that is inserted into
+/// a StringMap. It contains the Value itself and the key: the string length
+/// and data.
+template <typename ValueTy>
+class StringMapEntry final : public StringMapEntryStorage<ValueTy> {
+public:
+ using StringMapEntryStorage<ValueTy>::StringMapEntryStorage;
+
+ std::string_view getKey() const {
+ return std::string_view(getKeyData(), this->getKeyLength());
+ }
+
+ /// getKeyData - Return the start of the string data that is the key for this
+ /// value. The string data is always stored immediately after the
+ /// StringMapEntry object.
+ const char *getKeyData() const {
+ return reinterpret_cast<const char *>(this + 1);
+ }
+
+ std::string_view first() const {
+ return std::string_view(getKeyData(), this->getKeyLength());
+ }
+
+ /// 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,
+ InitTy &&... initVals) {
+ return new (StringMapEntryBase::allocateWithKey(
+ sizeof(StringMapEntry), alignof(StringMapEntry), key, allocator))
+ StringMapEntry(key.size(), std::forward<InitTy>(initVals)...);
+ }
+
+ /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded
+ /// into a StringMapEntry, return the StringMapEntry itself.
+ static StringMapEntry &GetStringMapEntryFromKeyData(const char *keyData) {
+ char *ptr = const_cast<char *>(keyData) - sizeof(StringMapEntry<ValueTy>);
+ return *reinterpret_cast<StringMapEntry *>(ptr);
+ }
+
+ /// Destroy - Destroy this StringMapEntry, releasing memory back to the
+ /// specified allocator.
+ template <typename AllocatorTy> void Destroy(AllocatorTy &allocator) {
+ // Free memory referenced by the item.
+ size_t AllocSize = sizeof(StringMapEntry) + this->getKeyLength() + 1;
+ this->~StringMapEntry();
+ allocator.Deallocate(static_cast<void *>(this), AllocSize,
+ alignof(StringMapEntry));
+ }
+};
+
+} // end namespace wpi
+
+#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
new file mode 100644
index 0000000..ab2791a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/SwapByteOrder.h
@@ -0,0 +1,165 @@
+//===- SwapByteOrder.h - Generic and optimized byte swaps -------*- 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 declares generic and optimized functions to swap the byte order of
+// an integral type.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_SWAPBYTEORDER_H
+#define WPIUTIL_WPI_SWAPBYTEORDER_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__)
+#include <endian.h>
+#elif defined(_AIX)
+#include <sys/machine.h>
+#elif defined(__sun)
+/* Solaris provides _BIG_ENDIAN/_LITTLE_ENDIAN selector in sys/types.h */
+#include <sys/types.h>
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#if defined(_BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#elif defined(__MVS__)
+#define BIG_ENDIAN 4321
+#define LITTLE_ENDIAN 1234
+#define BYTE_ORDER BIG_ENDIAN
+#else
+#if !defined(BYTE_ORDER) && !defined(_WIN32)
+#include <machine/endian.h>
+#endif
+#endif
+
+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
+constexpr bool IsBigEndianHost = true;
+#else
+constexpr bool IsBigEndianHost = false;
+#endif
+
+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 short getSwappedBytes(unsigned short C) { return ByteSwap_16(C); }
+inline signed short getSwappedBytes( signed short C) { return ByteSwap_16(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 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 long getSwappedBytes(unsigned long long C) {
+ return ByteSwap_64(C);
+}
+inline signed long long getSwappedBytes(signed long long C) {
+ return ByteSwap_64(C);
+}
+
+inline float getSwappedBytes(float C) {
+ union {
+ uint32_t i;
+ float f;
+ } in, out;
+ in.f = C;
+ out.i = ByteSwap_32(in.i);
+ return out.f;
+}
+
+inline double getSwappedBytes(double C) {
+ union {
+ uint64_t i;
+ double d;
+ } in, out;
+ in.d = C;
+ out.i = ByteSwap_64(in.i);
+ return out.d;
+}
+
+template <typename T>
+inline std::enable_if_t<std::is_enum<T>::value, T> getSwappedBytes(T C) {
+ return static_cast<T>(
+ getSwappedBytes(static_cast<std::underlying_type_t<T>>(C)));
+}
+
+template<typename T>
+inline void swapByteOrder(T &Value) {
+ Value = getSwappedBytes(Value);
+}
+
+} // end namespace sys
+} // end namespace wpi
+
+#endif
diff --git a/wpiutil/src/main/native/include/wpi/VersionTuple.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
similarity index 82%
rename from wpiutil/src/main/native/include/wpi/VersionTuple.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
index 59df41c..c08ff37 100644
--- a/wpiutil/src/main/native/include/wpi/VersionTuple.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/VersionTuple.h
@@ -1,9 +1,8 @@
//===- VersionTuple.h - Version Number Handling -----------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
///
@@ -15,10 +14,14 @@
#ifndef WPIUTIL_WPI_VERSIONTUPLE_H
#define WPIUTIL_WPI_VERSIONTUPLE_H
+#include "wpi/DenseMapInfo.h"
+#include "wpi/Hashing.h"
#include <optional>
#include <string>
+#include <tuple>
namespace wpi {
+class raw_ostream;
/// Represents a version number in the form major[.minor[.subminor[.build]]].
class VersionTuple {
@@ -85,6 +88,27 @@
return Build;
}
+ /// Return a version tuple that contains only the first 3 version components.
+ VersionTuple withoutBuild() const {
+ if (HasBuild)
+ return VersionTuple(Major, Minor, Subminor);
+ return *this;
+ }
+
+ /// Return a version tuple that contains only components that are non-zero.
+ VersionTuple normalize() const {
+ VersionTuple Result = *this;
+ if (Result.Build == 0) {
+ Result.HasBuild = false;
+ if (Result.Subminor == 0) {
+ Result.HasSubminor = false;
+ if (Result.Minor == 0)
+ Result.HasMinor = false;
+ }
+ }
+ return Result;
+ }
+
/// Determine if two version numbers are equivalent. If not
/// provided, minor and subminor version numbers are considered to be zero.
friend bool operator==(const VersionTuple &X, const VersionTuple &Y) {
diff --git a/wpiutil/src/main/native/include/wpi/WindowsError.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
similarity index 62%
rename from wpiutil/src/main/native/include/wpi/WindowsError.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
index 565e2b7..54a5236 100644
--- a/wpiutil/src/main/native/include/wpi/WindowsError.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/WindowsError.h
@@ -1,9 +1,8 @@
//===-- WindowsError.h - Support for mapping windows errors to posix-------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
diff --git a/wpiutil/src/main/native/include/wpi/function_ref.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
similarity index 100%
rename from wpiutil/src/main/native/include/wpi/function_ref.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/function_ref.h
diff --git a/wpiutil/src/main/native/include/wpi/iterator.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
similarity index 77%
rename from wpiutil/src/main/native/include/wpi/iterator.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
index 70bbdab..f959fac 100644
--- a/wpiutil/src/main/native/include/wpi/iterator.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator.h
@@ -1,9 +1,8 @@
//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -11,7 +10,6 @@
#define WPIUTIL_WPI_ITERATOR_H
#include "wpi/iterator_range.h"
-#include <algorithm>
#include <cstddef>
#include <iterator>
#include <type_traits>
@@ -37,6 +35,21 @@
/// terms of addition of one. These aren't equivalent for all iterator
/// categories, and respecting that adds a lot of complexity for little gain.
///
+/// Iterators are expected to have const rules analogous to pointers, with a
+/// single, const-qualified operator*() that returns ReferenceT. This matches
+/// the second and third pointers in the following example:
+/// \code
+/// int Value;
+/// { int *I = &Value; } // ReferenceT 'int&'
+/// { int *const I = &Value; } // ReferenceT 'int&'; const
+/// { const int *I = &Value; } // ReferenceT 'const int&'
+/// { const int *const I = &Value; } // ReferenceT 'const int&'; const
+/// \endcode
+/// If an iterator facade returns a handle to its own state, then T (and
+/// PointerT and ReferenceT) should usually be const-qualified. Otherwise, if
+/// clients are expected to modify the handle itself, the field can be declared
+/// mutable or use const_cast.
+///
/// Classes wishing to use `iterator_facade_base` should implement the following
/// methods:
///
@@ -44,8 +57,7 @@
/// (All of the following methods)
/// - DerivedT &operator=(const DerivedT &R);
/// - bool operator==(const DerivedT &R) const;
-/// - const T &operator*() const;
-/// - T &operator*();
+/// - T &operator*() const;
/// - DerivedT &operator++();
///
/// Bidirectional Iterators:
@@ -65,9 +77,14 @@
template <typename DerivedT, typename IteratorCategoryT, typename T,
typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
typename ReferenceT = T &>
-class iterator_facade_base
- : public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
- ReferenceT> {
+class iterator_facade_base {
+public:
+ using iterator_category = IteratorCategoryT;
+ using value_type = T;
+ using difference_type = DifferenceTypeT;
+ using pointer = PointerT;
+ using reference = ReferenceT;
+
protected:
enum {
IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
@@ -92,6 +109,22 @@
operator ReferenceT() const { return *I; }
};
+ /// A proxy object for computing a pointer via indirecting a copy of a
+ /// reference. This is used in APIs which need to produce a pointer but for
+ /// which the reference might be a temporary. The proxy preserves the
+ /// reference internally and exposes the pointer via a arrow operator.
+ class PointerProxy {
+ friend iterator_facade_base;
+
+ ReferenceT R;
+
+ template <typename RefT>
+ PointerProxy(RefT &&R) : R(std::forward<RefT>(R)) {}
+
+ public:
+ PointerT operator->() const { return &R; }
+ };
+
public:
DerivedT operator+(DifferenceTypeT n) const {
static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
@@ -143,43 +176,39 @@
return tmp;
}
+#ifndef __cpp_impl_three_way_comparison
bool operator!=(const DerivedT &RHS) const {
- return !static_cast<const DerivedT *>(this)->operator==(RHS);
+ return !(static_cast<const DerivedT &>(*this) == RHS);
}
+#endif
bool operator>(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
- return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
- !static_cast<const DerivedT *>(this)->operator==(RHS);
+ return !(static_cast<const DerivedT &>(*this) < RHS) &&
+ !(static_cast<const DerivedT &>(*this) == RHS);
}
bool operator<=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
- return !static_cast<const DerivedT *>(this)->operator>(RHS);
+ return !(static_cast<const DerivedT &>(*this) > RHS);
}
bool operator>=(const DerivedT &RHS) const {
static_assert(
IsRandomAccess,
"Relational operators are only defined for random access iterators.");
- return !static_cast<const DerivedT *>(this)->operator<(RHS);
+ return !(static_cast<const DerivedT &>(*this) < RHS);
}
- PointerT operator->() { return &static_cast<DerivedT *>(this)->operator*(); }
- PointerT operator->() const {
- return &static_cast<const DerivedT *>(this)->operator*();
- }
- ReferenceProxy operator[](DifferenceTypeT n) {
- static_assert(IsRandomAccess,
- "Subscripting is only defined for random access iterators.");
- return ReferenceProxy(static_cast<DerivedT *>(this)->operator+(n));
+ PointerProxy operator->() const {
+ return static_cast<const DerivedT *>(this)->operator*();
}
ReferenceProxy operator[](DifferenceTypeT n) const {
static_assert(IsRandomAccess,
"Subscripting is only defined for random access iterators.");
- return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
+ return static_cast<const DerivedT *>(this)->operator+(n);
}
};
@@ -195,14 +224,14 @@
typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
typename DifferenceTypeT =
typename std::iterator_traits<WrappedIteratorT>::difference_type,
- typename PointerT = typename std::conditional<
+ typename PointerT = std::conditional_t<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
- typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
- typename ReferenceT = typename std::conditional<
+ typename std::iterator_traits<WrappedIteratorT>::pointer, T *>,
+ typename ReferenceT = std::conditional_t<
std::is_same<T, typename std::iterator_traits<
WrappedIteratorT>::value_type>::value,
- typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type>
+ typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
class iterator_adaptor_base
: public iterator_facade_base<DerivedT, IteratorCategoryT, T,
DifferenceTypeT, PointerT, ReferenceT> {
@@ -261,12 +290,16 @@
return *static_cast<DerivedT *>(this);
}
- bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
- bool operator<(const DerivedT &RHS) const {
+ friend bool operator==(const iterator_adaptor_base &LHS,
+ const iterator_adaptor_base &RHS) {
+ return LHS.I == RHS.I;
+ }
+ friend bool operator<(const iterator_adaptor_base &LHS,
+ const iterator_adaptor_base &RHS) {
static_assert(
BaseT::IsRandomAccess,
"Relational operators are only defined for random access iterators.");
- return I < RHS.I;
+ return LHS.I < RHS.I;
}
ReferenceT operator*() const { return *I; }
@@ -282,8 +315,8 @@
/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
/// \endcode
template <typename WrappedIteratorT,
- typename T = typename std::remove_reference<
- decltype(**std::declval<WrappedIteratorT>())>::type>
+ typename T = std::remove_reference_t<decltype(
+ **std::declval<WrappedIteratorT>())>>
struct pointee_iterator
: iterator_adaptor_base<
pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT,
@@ -321,8 +354,7 @@
explicit pointer_iterator(WrappedIteratorT u)
: pointer_iterator::iterator_adaptor_base(std::move(u)) {}
- T &operator*() { return Ptr = &*this->I; }
- const T &operator*() const { return Ptr = &*this->I; }
+ T &operator*() const { return Ptr = &*this->I; }
};
template <typename RangeT, typename WrappedIteratorT =
@@ -334,6 +366,13 @@
PointerIteratorT(std::end(std::forward<RangeT>(Range))));
}
+template <typename WrappedIteratorT,
+ typename T1 = std::remove_reference_t<decltype(
+ **std::declval<WrappedIteratorT>())>,
+ typename T2 = std::add_pointer_t<T1>>
+using raw_pointer_iterator =
+ pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>;
+
} // end namespace wpi
-#endif // LLVM_ADT_ITERATOR_H
+#endif // WPIUTIL_WPI_ITERATOR_H
diff --git a/wpiutil/src/main/native/include/wpi/iterator_range.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
similarity index 82%
rename from wpiutil/src/main/native/include/wpi/iterator_range.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
index 78a60c2..ce0e4ee 100644
--- a/wpiutil/src/main/native/include/wpi/iterator_range.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/iterator_range.h
@@ -1,9 +1,8 @@
//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
@@ -19,7 +18,6 @@
#ifndef WPIUTIL_WPI_ITERATOR_RANGE_H
#define WPIUTIL_WPI_ITERATOR_RANGE_H
-#include <iterator>
#include <utility>
namespace wpi {
@@ -45,6 +43,7 @@
IteratorT begin() const { return begin_iterator; }
IteratorT end() const { return end_iterator; }
+ bool empty() const { return begin_iterator == end_iterator; }
};
/// Convenience function for iterating over sub-ranges.
@@ -59,11 +58,6 @@
return iterator_range<T>(std::move(p.first), std::move(p.second));
}
-template <typename T>
-iterator_range<decltype(adl_begin(std::declval<T>()))> drop_begin(T &&t,
- int n) {
- return make_range(std::next(adl_begin(t), n), adl_end(t));
-}
}
#endif
diff --git a/wpiutil/src/main/native/include/wpi/raw_os_ostream.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
similarity index 84%
rename from wpiutil/src/main/native/include/wpi/raw_os_ostream.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
index 4335e02..87cd596 100644
--- a/wpiutil/src/main/native/include/wpi/raw_os_ostream.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_os_ostream.h
@@ -1,9 +1,8 @@
//===- raw_os_ostream.h - std::ostream adaptor for raw_ostream --*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
diff --git a/wpiutil/src/main/native/include/wpi/raw_ostream.h b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
similarity index 74%
rename from wpiutil/src/main/native/include/wpi/raw_ostream.h
rename to wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
index 84ec925..350262b 100644
--- a/wpiutil/src/main/native/include/wpi/raw_ostream.h
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/raw_ostream.h
@@ -1,9 +1,8 @@
//===--- raw_ostream.h - Raw output stream ----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// 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
//
//===----------------------------------------------------------------------===//
//
@@ -15,20 +14,25 @@
#define WPIUTIL_WPI_RAW_OSTREAM_H
#include "wpi/SmallVector.h"
-#include "wpi/span.h"
+#include <span>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
+#if __cplusplus > 201402L
#include <string_view>
-#include <vector>
+#endif
#include <system_error>
+#include <type_traits>
+#include <vector>
+
namespace fs {
enum FileAccess : unsigned;
enum OpenFlags : unsigned;
enum CreationDisposition : unsigned;
+class FileLocker;
} // end namespace fs
namespace wpi {
@@ -38,7 +42,16 @@
/// buffered disciplines etc. It is a simple buffer that outputs
/// a chunk at a time.
class raw_ostream {
+public:
+ // Class kinds to support LLVM-style RTTI.
+ enum class OStreamKind {
+ OK_OStream,
+ OK_FDStream,
+ };
+
private:
+ OStreamKind Kind;
+
/// The buffer is handled in such a way that the buffer is
/// uninitialized, unbuffered, or out of space when OutBufCur >=
/// OutBufEnd. Thus a single comparison suffices to determine if we
@@ -59,7 +72,11 @@
/// this buffer.
char *OutBufStart, *OutBufEnd, *OutBufCur;
- enum BufferKind {
+ /// Optional stream this stream is tied to. If this stream is written to, the
+ /// tied-to stream will be flushed first.
+ raw_ostream *TiedStream = nullptr;
+
+ enum class BufferKind {
Unbuffered = 0,
InternalBuffer,
ExternalBuffer
@@ -67,7 +84,7 @@
public:
// color order matches ANSI escape sequence, don't change
- enum Colors {
+ enum class Colors {
BLACK = 0,
RED,
GREEN,
@@ -76,11 +93,25 @@
MAGENTA,
CYAN,
WHITE,
- SAVEDCOLOR
+ SAVEDCOLOR,
+ RESET,
};
- explicit raw_ostream(bool unbuffered = false)
- : BufferMode(unbuffered ? Unbuffered : InternalBuffer) {
+ static constexpr Colors BLACK = Colors::BLACK;
+ static constexpr Colors RED = Colors::RED;
+ static constexpr Colors GREEN = Colors::GREEN;
+ static constexpr Colors YELLOW = Colors::YELLOW;
+ static constexpr Colors BLUE = Colors::BLUE;
+ static constexpr Colors MAGENTA = Colors::MAGENTA;
+ static constexpr Colors CYAN = Colors::CYAN;
+ static constexpr Colors WHITE = Colors::WHITE;
+ static constexpr Colors SAVEDCOLOR = Colors::SAVEDCOLOR;
+ static constexpr Colors RESET = Colors::RESET;
+
+ explicit raw_ostream(bool unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream)
+ : Kind(K), BufferMode(unbuffered ? BufferKind::Unbuffered
+ : BufferKind::InternalBuffer) {
// Start out ready to flush.
OutBufStart = OutBufEnd = OutBufCur = nullptr;
}
@@ -93,10 +124,19 @@
/// tell - Return the current offset with the file.
uint64_t tell() const { return current_pos() + GetNumBytesInBuffer(); }
+ OStreamKind get_kind() const { return Kind; }
+
//===--------------------------------------------------------------------===//
// Configuration Interface
//===--------------------------------------------------------------------===//
+ /// If possible, pre-allocate \p ExtraSize bytes for stream data.
+ /// i.e. it extends internal buffers to keep additional ExtraSize bytes.
+ /// So that the stream could keep at least tell() + ExtraSize bytes
+ /// without re-allocations. reserveExtraSpace() does not change
+ /// the size/data of the stream.
+ virtual void reserveExtraSpace(uint64_t ExtraSize) {}
+
/// Set the stream to be buffered, with an automatically determined buffer
/// size.
void SetBuffered();
@@ -104,13 +144,13 @@
/// Set the stream to be buffered, using the specified buffer size.
void SetBufferSize(size_t Size) {
flush();
- SetBufferAndMode(new char[Size], Size, InternalBuffer);
+ SetBufferAndMode(new char[Size], Size, BufferKind::InternalBuffer);
}
size_t GetBufferSize() const {
// If we're supposed to be buffered but haven't actually gotten around
// to allocating the buffer yet, return the value that would be used.
- if (BufferMode != Unbuffered && OutBufStart == nullptr)
+ if (BufferMode != BufferKind::Unbuffered && OutBufStart == nullptr)
return preferred_buffer_size();
// Otherwise just return the size of the allocated buffer.
@@ -122,7 +162,7 @@
/// when the stream is being set to unbuffered.
void SetUnbuffered() {
flush();
- SetBufferAndMode(nullptr, 0, Unbuffered);
+ SetBufferAndMode(nullptr, 0, BufferKind::Unbuffered);
}
size_t GetNumBytesInBuffer() const {
@@ -159,7 +199,7 @@
return *this;
}
- raw_ostream &operator<<(span<const uint8_t> Arr) {
+ raw_ostream &operator<<(std::span<const uint8_t> Arr) {
// Inline fast path, particularly for arrays with a known length.
size_t Size = Arr.size();
@@ -237,9 +277,8 @@
/// @param Bold bold/brighter text, default false
/// @param BG if true change the background, default: change foreground
/// @returns itself so it can be used within << invocations
- virtual raw_ostream &changeColor(enum Colors Color,
- bool Bold = false,
- bool BG = false) {
+ virtual raw_ostream &changeColor(enum Colors Color, bool Bold = false,
+ bool BG = false) {
(void)Color;
(void)Bold;
(void)BG;
@@ -259,8 +298,19 @@
virtual bool is_displayed() const { return false; }
/// This function determines if this stream is displayed and supports colors.
+ /// The result is unaffected by calls to enable_color().
virtual bool has_colors() const { return is_displayed(); }
+ // Enable or disable colors. Once enable_colors(false) is called,
+ // changeColor() has no effect until enable_colors(true) is called.
+ virtual void enable_colors(bool /*enable*/) {}
+
+ bool colors_enabled() const { return false; }
+
+ /// Tie this stream to the specified stream. Replaces any existing tied-to
+ /// stream. Specifying a nullptr unties the stream.
+ void tie(raw_ostream *TieTo) { TiedStream = TieTo; }
+
//===--------------------------------------------------------------------===//
// Subclass Interface
//===--------------------------------------------------------------------===//
@@ -281,9 +331,6 @@
/// \invariant { Size > 0 }
virtual void write_impl(const char *Ptr, size_t Size) = 0;
- // An out of line virtual method to provide a home for the class vtable.
- virtual void handle();
-
/// Return the current position within the stream, not counting the bytes
/// currently in the buffer.
virtual uint64_t current_pos() const = 0;
@@ -293,7 +340,7 @@
/// use only by subclasses which can arrange for the output to go directly
/// into the desired output buffer, instead of being copied on each flush.
void SetBuffer(char *BufferStart, size_t Size) {
- SetBufferAndMode(BufferStart, Size, ExternalBuffer);
+ SetBufferAndMode(BufferStart, Size, BufferKind::ExternalBuffer);
}
/// Return an efficient buffer size for the underlying output mechanism.
@@ -318,9 +365,23 @@
/// unused bytes in the buffer.
void copy_to_buffer(const char *Ptr, size_t Size);
+ /// Flush the tied-to stream (if present) and then write the required data.
+ void flush_tied_then_write(const char *Ptr, size_t Size);
+
virtual void anchor();
};
+/// 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,
+ OStream &&>
+operator<<(OStream &&OS, const T &Value) {
+ OS << Value;
+ return std::move(OS);
+}
+
/// An abstract base class for streams implementations that also support a
/// pwrite operation. This is useful for code that can mostly stream out data,
/// but needs to patch in a header that needs to know the output size.
@@ -329,10 +390,11 @@
void anchor() override;
public:
- explicit raw_pwrite_stream(bool Unbuffered = false)
- : raw_ostream(Unbuffered) {}
+ explicit raw_pwrite_stream(bool Unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream)
+ : raw_ostream(Unbuffered, K) {}
void pwrite(const char *Ptr, size_t Size, uint64_t Offset) {
-#ifndef NDBEBUG
+#ifndef NDEBUG
uint64_t Pos = tell();
// /dev/null always reports a pos of 0, so we cannot perform this check
// in that case.
@@ -352,8 +414,8 @@
class raw_fd_ostream : public raw_pwrite_stream {
int FD;
bool ShouldClose;
-
- bool SupportsSeeking;
+ bool SupportsSeeking = false;
+ bool IsRegularFile = false;
#ifdef _WIN32
/// True if this fd refers to a Windows console device. Mintty and other
@@ -363,7 +425,7 @@
std::error_code EC;
- uint64_t pos;
+ uint64_t pos = 0;
/// See raw_ostream::write_impl.
void write_impl(const char *Ptr, size_t Size) override;
@@ -377,10 +439,17 @@
/// Determine an efficient buffer size.
size_t preferred_buffer_size() const override;
+ void anchor() override;
+
+protected:
/// Set the flag indicating that an output error has been encountered.
void error_detected(std::error_code EC) { this->EC = EC; }
- void anchor() override;
+ /// Return the file descriptor.
+ int get_fd() const { return FD; }
+
+ // Update the file position by increasing \p Delta.
+ void inc_pos(uint64_t Delta) { pos += Delta; }
public:
/// Open the specified file for writing. If an error occurs, information
@@ -405,7 +474,8 @@
/// FD is the file descriptor that this writes to. If ShouldClose is true,
/// this closes the file when the stream is destroyed. If FD is for stdout or
/// stderr, it will not be closed.
- raw_fd_ostream(int fd, bool shouldClose, bool unbuffered=false);
+ raw_fd_ostream(int fd, bool shouldClose, bool unbuffered = false,
+ OStreamKind K = OStreamKind::OK_OStream);
~raw_fd_ostream() override;
@@ -413,7 +483,9 @@
/// fsync.
void close();
- bool supportsSeeking() { return SupportsSeeking; }
+ bool supportsSeeking() const { return SupportsSeeking; }
+
+ bool isRegularFile() const { return IsRegularFile; }
/// Flushes the stream and repositions the underlying file descriptor position
/// to the offset specified from the beginning of the file.
@@ -439,23 +511,46 @@
void clear_error() { EC = std::error_code(); }
};
-/// This returns a reference to a raw_ostream for standard output. Use it like:
-/// outs() << "foo" << "bar";
-raw_ostream &outs();
+/// This returns a reference to a raw_fd_ostream for standard output. Use it
+/// like: outs() << "foo" << "bar";
+raw_fd_ostream &outs();
-/// This returns a reference to a raw_ostream for standard error. Use it like:
-/// errs() << "foo" << "bar";
-raw_ostream &errs();
+/// This returns a reference to a raw_ostream for standard error.
+/// Use it like: errs() << "foo" << "bar";
+/// By default, the stream is tied to stdout to ensure stdout is flushed before
+/// stderr is written, to ensure the error messages are written in their
+/// expected place.
+raw_fd_ostream &errs();
/// This returns a reference to a raw_ostream which simply discards output.
raw_ostream &nulls();
//===----------------------------------------------------------------------===//
+// File Streams
+//===----------------------------------------------------------------------===//
+
+/// A raw_ostream of a file for reading/writing/seeking.
+///
+class raw_fd_stream : public raw_fd_ostream {
+public:
+ /// Open the specified file for reading/writing/seeking. If an error occurs,
+ /// information about the error is put into EC, and the stream should be
+ /// immediately destroyed.
+ raw_fd_stream(std::string_view Filename, std::error_code &EC);
+
+ /// Check if \p OS is a pointer of type raw_fd_stream*.
+ static bool classof(const raw_ostream *OS);
+};
+
+//===----------------------------------------------------------------------===//
// Output Stream Adaptors
//===----------------------------------------------------------------------===//
/// A raw_ostream that writes to an std::string. This is a simple adaptor
/// class. This class does not encounter output errors.
+/// raw_string_ostream operates without a buffer, delegating all memory
+/// management to the std::string. Thus the std::string is always up-to-date,
+/// may be used directly and there is no need to call flush().
class raw_string_ostream : public raw_ostream {
std::string &OS;
@@ -467,14 +562,17 @@
uint64_t current_pos() const override { return OS.size(); }
public:
- explicit raw_string_ostream(std::string &O) : OS(O) {}
- ~raw_string_ostream() override;
+ explicit raw_string_ostream(std::string &O) : OS(O) {
+ SetUnbuffered();
+ }
- /// Flushes the stream contents to the target string and returns the string's
- /// reference.
- std::string& str() {
- flush();
- return OS;
+ /// Returns the string's reference. In most cases it is better to simply use
+ /// the underlying std::string directly.
+ /// TODO: Consider removing this API.
+ std::string &str() { return OS; }
+
+ void reserveExtraSpace(uint64_t ExtraSize) override {
+ OS.reserve(tell() + ExtraSize);
}
};
@@ -508,7 +606,11 @@
void flush() = delete;
/// Return a std::string_view for the vector contents.
- std::string_view str() { return std::string_view(OS.data(), OS.size()); }
+ std::string_view str() const { return std::string_view(OS.data(), OS.size()); }
+
+ void reserveExtraSpace(uint64_t ExtraSize) override {
+ OS.reserve(tell() + ExtraSize);
+ }
};
/// A raw_ostream that writes to a vector. This is a
@@ -573,9 +675,9 @@
void flush() = delete;
- /// Return an span for the vector contents.
- span<uint8_t> array() { return {OS.data(), OS.size()}; }
- span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
+ /// Return an std::span for the vector contents.
+ std::span<uint8_t> array() { return {OS.data(), OS.size()}; }
+ std::span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
};
/// A raw_ostream that writes to a vector. This is a
@@ -607,9 +709,9 @@
void flush() = delete;
- /// Return a span for the vector contents.
- span<uint8_t> array() { return {OS.data(), OS.size()}; }
- span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
+ /// Return a std::span for the vector contents.
+ std::span<uint8_t> array() { return {OS.data(), OS.size()}; }
+ std::span<const uint8_t> array() const { return {OS.data(), OS.size()}; }
};
@@ -639,6 +741,22 @@
~buffer_ostream() override { OS << str(); }
};
+class buffer_unique_ostream : public raw_svector_ostream {
+ std::unique_ptr<raw_ostream> OS;
+ SmallVector<char, 0> Buffer;
+
+ virtual void anchor() override;
+
+public:
+ buffer_unique_ostream(std::unique_ptr<raw_ostream> OS)
+ : raw_svector_ostream(Buffer), OS(std::move(OS)) {
+ // Turn off buffering on OS, which we now own, to avoid allocating a buffer
+ // when the destructor writes only to be immediately flushed again.
+ this->OS->SetUnbuffered();
+ }
+ ~buffer_unique_ostream() override { *OS << str(); }
+};
+
} // end namespace wpi
-#endif // LLVM_SUPPORT_RAW_OSTREAM_H
+#endif // WPIUTIL_WPI_RAW_OSTREAM_H
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
new file mode 100644
index 0000000..53e18d3
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/llvm/include/wpi/type_traits.h
@@ -0,0 +1,104 @@
+//===- llvm/Support/type_traits.h - Simplfied type traits -------*- 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 provides useful additions to the standard type_traits library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef WPIUTIL_WPI_TYPE_TRAITS_H
+#define WPIUTIL_WPI_TYPE_TRAITS_H
+
+#include "wpi/Compiler.h"
+#include <type_traits>
+#include <utility>
+
+namespace wpi {
+
+
+/// Metafunction that determines whether the given type is either an
+/// integral type or an enumeration type, including enum classes.
+///
+/// Note that this accepts potentially more integral types than is_integral
+/// because it is based on being implicitly convertible to an integral type.
+/// Also note that enum classes aren't implicitly convertible to integral types,
+/// the value may therefore need to be explicitly converted before being used.
+template <typename T> class is_integral_or_enum {
+ using UnderlyingT = std::remove_reference_t<T>;
+
+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);
+};
+
+/// If T is a pointer, just return it. If it is not, return T&.
+template<typename T, typename Enable = void>
+struct add_lvalue_reference_if_not_pointer { using type = T &; };
+
+template <typename T>
+struct add_lvalue_reference_if_not_pointer<
+ T, std::enable_if_t<std::is_pointer<T>::value>> {
+ using type = T;
+};
+
+/// If T is a pointer to X, return a pointer to const X. If it is not,
+/// return const T.
+template<typename T, typename Enable = void>
+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>> {
+ using type = const std::remove_pointer_t<T> *;
+};
+
+template <typename T, typename Enable = void>
+struct const_pointer_or_const_ref {
+ using type = const T &;
+};
+template <typename T>
+struct const_pointer_or_const_ref<T,
+ std::enable_if_t<std::is_pointer<T>::value>> {
+ 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;
+};
+
+} // 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/memory/include/wpi/memory/aligned_allocator.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp
new file mode 100644
index 0000000..8118ec4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/aligned_allocator.hpp
@@ -0,0 +1,197 @@
+// 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.
+
+#ifndef WPI_MEMORY_ALIGNED_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_ALIGNED_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::aligned_allocator and related functions.
+
+#include <type_traits>
+
+#include "detail/assert.hpp"
+#include "detail/utility.hpp"
+#include "allocator_traits.hpp"
+#include "config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A \concept{concept_rawallocator,RawAllocator} adapter that ensures a minimum alignment.
+ /// It adjusts the alignment value so that it is always larger than the minimum and forwards to the specified allocator.
+ /// \ingroup adapter
+ template <class RawAllocator>
+ class aligned_allocator : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ using traits = allocator_traits<RawAllocator>;
+ using composable_traits = composable_allocator_traits<RawAllocator>;
+ using composable = is_composable_allocator<typename traits::allocator_type>;
+
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+ using is_stateful = std::true_type;
+
+ /// \effects Creates it passing it the minimum alignment value and the allocator object.
+ /// \requires \c min_alignment must be less than \c this->max_alignment().
+ explicit aligned_allocator(std::size_t min_alignment, allocator_type&& alloc = {})
+ : allocator_type(detail::move(alloc)), min_alignment_(min_alignment)
+ {
+ WPI_MEMORY_ASSERT(min_alignment_ <= max_alignment());
+ }
+
+ /// @{
+ /// \effects Moves the \c aligned_allocator object.
+ /// It simply moves the underlying allocator.
+ aligned_allocator(aligned_allocator&& other) noexcept
+ : allocator_type(detail::move(other)), min_alignment_(other.min_alignment_)
+ {
+ }
+
+ aligned_allocator& operator=(aligned_allocator&& other) noexcept
+ {
+ allocator_type::operator=(detail::move(other));
+ min_alignment_ = other.min_alignment_;
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// \effects Forwards to the underlying allocator through the \ref allocator_traits.
+ /// If the \c alignment is less than the \c min_alignment(), it is set to the minimum alignment.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return traits::allocate_node(get_allocator(), size, alignment);
+ }
+
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return traits::allocate_array(get_allocator(), count, size, alignment);
+ }
+
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ traits::deallocate_node(get_allocator(), ptr, size, alignment);
+ }
+
+ void deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ traits::deallocate_array(get_allocator(), ptr, count, size, alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \effects Forwards to the underlying allocator through the \ref composable_allocator_traits.
+ /// If the \c alignment is less than the \c min_alignment(), it is set to the minimum alignment.
+ /// \requires The underyling allocator must be composable.
+ WPI_ENABLE_IF(composable::value)
+ void* try_allocate_node(std::size_t size, std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return composable_traits::try_allocate_node(get_allocator(), size, alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ void* try_allocate_array(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return composable_traits::try_allocate_array(get_allocator(), count, size,
+ alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ bool try_deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return composable_traits::try_deallocate_node(get_allocator(), ptr, size,
+ alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ bool try_deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (min_alignment_ > alignment)
+ alignment = min_alignment_;
+ return composable_traits::try_deallocate_array(get_allocator(), ptr, count, size,
+ alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \returns The value returned by the \ref allocator_traits for the underlying allocator.
+ std::size_t max_node_size() const
+ {
+ return traits::max_node_size(get_allocator());
+ }
+
+ std::size_t max_array_size() const
+ {
+ return traits::max_array_size(get_allocator());
+ }
+
+ std::size_t max_alignment() const
+ {
+ return traits::max_alignment(get_allocator());
+ }
+ /// @}
+
+ /// @{
+ /// \returns A reference to the underlying allocator.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ /// \returns The minimum alignment.
+ std::size_t min_alignment() const noexcept
+ {
+ return min_alignment_;
+ }
+
+ /// \effects Sets the minimum alignment to a new value.
+ /// \requires \c min_alignment must be less than \c this->max_alignment().
+ void set_min_alignment(std::size_t min_alignment)
+ {
+ WPI_MEMORY_ASSERT(min_alignment <= max_alignment());
+ min_alignment_ = min_alignment;
+ }
+
+ private:
+ std::size_t min_alignment_;
+ };
+
+ /// \returns A new \ref aligned_allocator created by forwarding the parameters to the constructor.
+ /// \relates aligned_allocator
+ template <class RawAllocator>
+ auto make_aligned_allocator(std::size_t min_alignment, RawAllocator&& allocator) noexcept
+ -> aligned_allocator<typename std::decay<RawAllocator>::type>
+ {
+ return aligned_allocator<
+ typename std::decay<RawAllocator>::type>{min_alignment,
+ detail::forward<RawAllocator>(allocator)};
+ }
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_ALIGNED_ALLOCATOR_HPP_INCLUDED
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
new file mode 100644
index 0000000..8dab2e0
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_storage.hpp
@@ -0,0 +1,932 @@
+// 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.
+
+#ifndef WPI_MEMORY_ALLOCATOR_STORAGE_HPP_INCLUDED
+#define WPI_MEMORY_ALLOCATOR_STORAGE_HPP_INCLUDED
+
+/// \file
+/// Class template \ref wpi::memory::allocator_storage, some policies and resulting typedefs.
+
+#include <new>
+#include <type_traits>
+
+#include "detail/utility.hpp"
+#include "config.hpp"
+#include "allocator_traits.hpp"
+#include "threading.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <class Alloc>
+ void* try_allocate_node(std::true_type, Alloc& alloc, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return composable_allocator_traits<Alloc>::try_allocate_node(alloc, size,
+ alignment);
+ }
+
+ template <class Alloc>
+ void* try_allocate_array(std::true_type, Alloc& alloc, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return composable_allocator_traits<Alloc>::try_allocate_array(alloc, count, size,
+ alignment);
+ }
+
+ template <class Alloc>
+ bool try_deallocate_node(std::true_type, Alloc& alloc, void* ptr, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return composable_allocator_traits<Alloc>::try_deallocate_node(alloc, ptr, size,
+ alignment);
+ }
+
+ template <class Alloc>
+ bool try_deallocate_array(std::true_type, Alloc& alloc, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return composable_allocator_traits<Alloc>::try_deallocate_array(alloc, ptr, count,
+ size, alignment);
+ }
+
+ template <class Alloc>
+ void* try_allocate_node(std::false_type, Alloc&, std::size_t, std::size_t) noexcept
+ {
+ WPI_MEMORY_UNREACHABLE("Allocator is not compositioning");
+ return nullptr;
+ }
+
+ template <class Alloc>
+ void* try_allocate_array(std::false_type, Alloc&, std::size_t, std::size_t,
+ std::size_t) noexcept
+ {
+ WPI_MEMORY_UNREACHABLE("Allocator is not compositioning");
+ return nullptr;
+ }
+
+ template <class Alloc>
+ bool try_deallocate_node(std::false_type, Alloc&, void*, std::size_t,
+ std::size_t) noexcept
+ {
+ WPI_MEMORY_UNREACHABLE("Allocator is not compositioning");
+ return false;
+ }
+
+ template <class Alloc>
+ bool try_deallocate_array(std::false_type, Alloc&, void*, std::size_t, std::size_t,
+ std::size_t) noexcept
+ {
+ WPI_MEMORY_UNREACHABLE("Allocator is not compositioning");
+ return false;
+ }
+ } // namespace detail
+
+ /// A \concept{concept_rawallocator,RawAllocator} that stores another allocator.
+ /// The \concept{concept_storagepolicy,StoragePolicy} defines the allocator type being stored and how it is stored.
+ /// The \c Mutex controls synchronization of the access.
+ /// \ingroup storage
+ template <class StoragePolicy, class Mutex>
+ class allocator_storage
+ : WPI_EBO(StoragePolicy,
+ detail::mutex_storage<
+ detail::mutex_for<typename StoragePolicy::allocator_type, Mutex>>)
+ {
+ using traits = allocator_traits<typename StoragePolicy::allocator_type>;
+ using composable_traits =
+ composable_allocator_traits<typename StoragePolicy::allocator_type>;
+ using composable = is_composable_allocator<typename StoragePolicy::allocator_type>;
+ using actual_mutex = const detail::mutex_storage<
+ detail::mutex_for<typename StoragePolicy::allocator_type, Mutex>>;
+
+ public:
+ using allocator_type = typename StoragePolicy::allocator_type;
+ using storage_policy = StoragePolicy;
+ using mutex = Mutex;
+ using is_stateful = typename traits::is_stateful;
+
+ /// \effects Creates it by default-constructing the \c StoragePolicy.
+ /// \requires The \c StoragePolicy must be default-constructible.
+ /// \notes The default constructor may create an invalid allocator storage not associated with any allocator.
+ /// If that is the case, it must not be used.
+ allocator_storage() = default;
+
+ /// \effects Creates it by passing it an allocator.
+ /// The allocator will be forwarded to the \c StoragePolicy, it decides whether it will be moved, its address stored or something else.
+ /// \requires The expression <tt>new storage_policy(std::forward<Alloc>(alloc))</tt> must be well-formed,
+ /// otherwise this constructor does not participate in overload resolution.
+ template <
+ class Alloc,
+ // MSVC seems to ignore access rights in SFINAE below
+ // use this to prevent this constructor being chosen instead of move for types inheriting from it
+ 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))))
+ : storage_policy(detail::forward<Alloc>(alloc))
+ {
+ }
+
+ /// \effects Creates it by passing it another \c allocator_storage with a different \c StoragePolicy but the same \c Mutex type.
+ /// Initializes it with the result of \c other.get_allocator().
+ /// \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())))
+ : storage_policy(other.get_allocator())
+ {
+ }
+
+ /// @{
+ /// \effects Moves the \c allocator_storage object.
+ /// A moved-out \c allocator_storage object must still store a valid allocator object.
+ allocator_storage(allocator_storage&& other) noexcept
+ : storage_policy(detail::move(other)),
+ detail::mutex_storage<
+ detail::mutex_for<typename StoragePolicy::allocator_type, Mutex>>(
+ detail::move(other))
+ {
+ }
+
+ allocator_storage& operator=(allocator_storage&& other) noexcept
+ {
+ storage_policy:: operator=(detail::move(other));
+ detail::mutex_storage<detail::mutex_for<typename StoragePolicy::allocator_type,
+ Mutex>>::operator=(detail::move(other));
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// \effects Copies the \c allocator_storage object.
+ /// \requires The \c StoragePolicy must be copyable.
+ allocator_storage(const allocator_storage&) = default;
+ allocator_storage& operator=(const allocator_storage&) = default;
+ /// @}
+
+ /// @{
+ /// \effects Calls the function on the stored allocator.
+ /// The \c Mutex will be locked during the operation.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return traits::allocate_node(alloc, size, alignment);
+ }
+
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return traits::allocate_array(alloc, count, size, alignment);
+ }
+
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ traits::deallocate_node(alloc, ptr, size, alignment);
+ }
+
+ void deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ traits::deallocate_array(alloc, ptr, count, size, alignment);
+ }
+
+ std::size_t max_node_size() const
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return traits::max_node_size(alloc);
+ }
+
+ std::size_t max_array_size() const
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return traits::max_array_size(alloc);
+ }
+
+ std::size_t max_alignment() const
+ {
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return traits::max_alignment(alloc);
+ }
+ /// @}
+
+ /// @{
+ /// \effects Calls the function on the stored composable allocator.
+ /// The \c Mutex will be locked during the operation.
+ /// \requires The allocator must be composable,
+ /// i.e. \ref is_composable() must return `true`.
+ /// \note This check is done at compile-time where possible,
+ /// and at runtime in the case of type-erased storage.
+ WPI_ENABLE_IF(composable::value)
+ void* try_allocate_node(std::size_t size, std::size_t alignment) noexcept
+ {
+ WPI_MEMORY_ASSERT(is_composable());
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return composable_traits::try_allocate_node(alloc, size, alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ void* try_allocate_array(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ WPI_MEMORY_ASSERT(is_composable());
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return composable_traits::try_allocate_array(alloc, count, size, alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ bool try_deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ WPI_MEMORY_ASSERT(is_composable());
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return composable_traits::try_deallocate_node(alloc, ptr, size, alignment);
+ }
+
+ WPI_ENABLE_IF(composable::value)
+ bool try_deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ WPI_MEMORY_ASSERT(is_composable());
+ std::lock_guard<actual_mutex> lock(*this);
+ auto&& alloc = get_allocator();
+ return composable_traits::try_deallocate_array(alloc, ptr, count, size, alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \effects Forwards to the \c StoragePolicy.
+ /// \returns Returns a reference to the stored allocator.
+ /// \note This does not lock the \c Mutex.
+ auto get_allocator() noexcept
+ -> decltype(std::declval<storage_policy>().get_allocator())
+ {
+ return storage_policy::get_allocator();
+ }
+
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<const storage_policy>().get_allocator())
+ {
+ return storage_policy::get_allocator();
+ }
+ /// @}
+
+ /// @{
+ /// \returns A proxy object that acts like a pointer to the stored allocator.
+ /// It cannot be reassigned to point to another allocator object and only moving is supported, which is destructive.
+ /// As long as the proxy object lives and is not moved from, the \c Mutex will be kept locked.
+ auto lock() noexcept -> WPI_IMPL_DEFINED(decltype(detail::lock_allocator(
+ std::declval<storage_policy>().get_allocator(), std::declval<actual_mutex&>())))
+ {
+ 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&>())))
+ {
+ return detail::lock_allocator(get_allocator(), static_cast<actual_mutex&>(*this));
+ }
+ /// @}.
+
+ /// \returns Whether or not the stored allocator is composable,
+ /// that is you can use the compositioning functions.
+ /// \note Due to type-erased allocators,
+ /// this function can not be `constexpr`.
+ bool is_composable() const noexcept
+ {
+ return StoragePolicy::is_composable();
+ }
+ };
+
+ /// Tag type that enables type-erasure in \ref reference_storage.
+ /// It can be used everywhere a \ref allocator_reference is used internally.
+ /// \ingroup storage
+ struct any_allocator
+ {
+ };
+
+ /// A \concept{concept_storagepolicy,StoragePolicy} that stores the allocator directly.
+ /// It embeds the allocator inside it, i.e. moving the storage policy will move the allocator.
+ /// \ingroup storage
+ template <class RawAllocator>
+ class direct_storage : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ static_assert(!std::is_same<RawAllocator, any_allocator>::value,
+ "cannot type-erase in direct_storage");
+
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+
+ /// \effects Creates it by default-constructing the allocator.
+ /// \requires The \c RawAllcoator must be default constructible.
+ direct_storage() = default;
+
+ /// \effects Creates it by moving in an allocator object.
+ direct_storage(allocator_type&& allocator) noexcept
+ : allocator_type(detail::move(allocator))
+ {
+ }
+
+ /// @{
+ /// \effects Moves the \c direct_storage object.
+ /// This will move the stored allocator.
+ direct_storage(direct_storage&& other) noexcept : allocator_type(detail::move(other)) {}
+
+ direct_storage& operator=(direct_storage&& other) noexcept
+ {
+ allocator_type::operator=(detail::move(other));
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (\c const) reference to the stored allocator.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ protected:
+ ~direct_storage() noexcept = default;
+
+ bool is_composable() const noexcept
+ {
+ return is_composable_allocator<allocator_type>::value;
+ }
+ };
+
+ /// An alias template for \ref allocator_storage using the \ref direct_storage policy without a mutex.
+ /// It has the effect of giving any \concept{concept_rawallocator,RawAllocator} the interface with all member functions,
+ /// avoiding the need to wrap it inside the \ref allocator_traits.
+ /// \ingroup storage
+ template <class RawAllocator>
+ WPI_ALIAS_TEMPLATE(allocator_adapter,
+ allocator_storage<direct_storage<RawAllocator>, no_mutex>);
+
+ /// \returns A new \ref allocator_adapter object created by forwarding to the constructor.
+ /// \relates allocator_adapter
+ template <class RawAllocator>
+ auto make_allocator_adapter(RawAllocator&& allocator) noexcept
+ -> allocator_adapter<typename std::decay<RawAllocator>::type>
+ {
+ return {detail::forward<RawAllocator>(allocator)};
+ }
+
+/// An alias template for \ref allocator_storage using the \ref direct_storage policy with a mutex.
+/// It has a similar effect as \ref allocator_adapter but performs synchronization.
+/// The \c Mutex will default to \c std::mutex if threading is supported,
+/// otherwise there is no default.
+/// \ingroup storage
+#if WPI_HOSTED_IMPLEMENTATION
+ template <class RawAllocator, class Mutex = std::mutex>
+ WPI_ALIAS_TEMPLATE(thread_safe_allocator,
+ allocator_storage<direct_storage<RawAllocator>, Mutex>);
+#else
+ template <class RawAllocator, class Mutex>
+ WPI_ALIAS_TEMPLATE(thread_safe_allocator,
+ allocator_storage<direct_storage<RawAllocator>, Mutex>);
+#endif
+
+#if WPI_HOSTED_IMPLEMENTATION
+ /// \returns A new \ref thread_safe_allocator object created by forwarding to the constructor/
+ /// \relates thread_safe_allocator
+ template <class RawAllocator>
+ auto make_thread_safe_allocator(RawAllocator&& allocator)
+ -> thread_safe_allocator<typename std::decay<RawAllocator>::type>
+ {
+ return detail::forward<RawAllocator>(allocator);
+ }
+#endif
+
+ /// \returns A new \ref thread_safe_allocator object created by forwarding to the constructor,
+ /// specifying a certain mutex type.
+ /// \requires It requires threading support from the implementation.
+ /// \relates thread_safe_allocator
+ template <class Mutex, class RawAllocator>
+ auto make_thread_safe_allocator(RawAllocator&& allocator)
+ -> thread_safe_allocator<typename std::decay<RawAllocator>::type, Mutex>
+ {
+ return detail::forward<RawAllocator>(allocator);
+ }
+
+ namespace detail
+ {
+ struct reference_stateful
+ {
+ };
+ struct reference_stateless
+ {
+ };
+ struct reference_shared
+ {
+ };
+
+ reference_stateful reference_type(std::true_type stateful, std::false_type shared);
+ reference_stateless reference_type(std::false_type stateful, std::true_type shared);
+ reference_stateless reference_type(std::false_type stateful, std::false_type shared);
+ reference_shared reference_type(std::true_type stateful, std::true_type shared);
+
+ template <class RawAllocator, class Tag>
+ class reference_storage_impl;
+
+ // reference to stateful: stores a pointer to an allocator
+ template <class RawAllocator>
+ class reference_storage_impl<RawAllocator, reference_stateful>
+ {
+ protected:
+ reference_storage_impl() noexcept : alloc_(nullptr) {}
+
+ reference_storage_impl(RawAllocator& allocator) noexcept : alloc_(&allocator) {}
+
+ bool is_valid() const noexcept
+ {
+ return alloc_ != nullptr;
+ }
+
+ RawAllocator& get_allocator() const noexcept
+ {
+ WPI_MEMORY_ASSERT(alloc_ != nullptr);
+ return *alloc_;
+ }
+
+ private:
+ RawAllocator* alloc_;
+ };
+
+ // reference to stateless: store in static storage
+ template <class RawAllocator>
+ class reference_storage_impl<RawAllocator, reference_stateless>
+ {
+ protected:
+ reference_storage_impl() noexcept = default;
+
+ reference_storage_impl(const RawAllocator&) noexcept {}
+
+ bool is_valid() const noexcept
+ {
+ return true;
+ }
+
+ RawAllocator& get_allocator() const noexcept
+ {
+ static RawAllocator alloc;
+ return alloc;
+ }
+ };
+
+ // reference to shared: stores RawAllocator directly
+ template <class RawAllocator>
+ class reference_storage_impl<RawAllocator, reference_shared>
+ {
+ protected:
+ reference_storage_impl() noexcept = default;
+
+ reference_storage_impl(const RawAllocator& alloc) noexcept : alloc_(alloc) {}
+
+ bool is_valid() const noexcept
+ {
+ return true;
+ }
+
+ RawAllocator& get_allocator() const noexcept
+ {
+ return alloc_;
+ }
+
+ private:
+ mutable RawAllocator alloc_;
+ };
+ } // namespace detail
+
+ /// Specifies whether or not a \concept{concept_rawallocator,RawAllocator} has shared semantics.
+ /// It is shared, if - like \ref allocator_reference - if multiple objects refer to the same internal allocator and if it can be copied.
+ /// This sharing is stateful, however, stateless allocators are not considered shared in the meaning of this traits. <br>
+ /// If a \c RawAllocator is shared, it will be directly embedded inside \ref reference_storage since it already provides \ref allocator_reference like semantics, so there is no need to add them manually,<br>
+ /// Specialize it for your own types, if they provide sharing semantics and can be copied.
+ /// They also must provide an `operator==` to check whether two allocators refer to the same shared one.
+ /// \note This makes no guarantees about the lifetime of the shared object, the sharing allocators can either own or refer to a shared object.
+ /// \ingroup storage
+ template <class RawAllocator>
+ struct is_shared_allocator : std::false_type
+ {
+ };
+
+ /// A \concept{concept_storagepolicy,StoragePolicy} that stores a reference to an allocator.
+ /// For stateful allocators it only stores a pointer to an allocator object and copying/moving only copies the pointer.
+ /// For stateless allocators it does not store anything, an allocator will be constructed as needed.
+ /// For allocators that are already shared (determined through \ref is_shared_allocator) it will store the allocator type directly.
+ /// \note It does not take ownership over the allocator in the stateful case, the user has to ensure that the allocator object stays valid.
+ /// In the other cases the lifetime does not matter.
+ /// \ingroup storage
+ template <class RawAllocator>
+ class reference_storage
+#ifndef DOXYGEN
+ : WPI_EBO(detail::reference_storage_impl<
+ typename allocator_traits<RawAllocator>::allocator_type,
+ decltype(detail::reference_type(
+ typename allocator_traits<RawAllocator>::is_stateful{},
+ is_shared_allocator<RawAllocator>{}))>)
+#endif
+ {
+ 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>{}))>;
+
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+
+ /// Default constructor.
+ /// \effects If the allocator is stateless, this has no effect and the object is usable as an allocator.
+ /// If the allocator is stateful, creates an invalid reference without any associated allocator.
+ /// Then it must not be used.
+ /// If the allocator is shared, default constructs the shared allocator.
+ /// If the shared allocator does not have a default constructor, this constructor is ill-formed.
+ reference_storage() noexcept = default;
+
+ /// \effects Creates it from a stateless or shared allocator.
+ /// It will not store anything, only creates the allocator as needed.
+ /// \requires The \c RawAllocator is stateless or shared.
+ reference_storage(const allocator_type& alloc) noexcept : storage(alloc) {}
+
+ /// \effects Creates it from a reference to a stateful allocator.
+ /// It will store a pointer to this allocator object.
+ /// \note The user has to take care that the lifetime of the reference does not exceed the allocator lifetime.
+ reference_storage(allocator_type& alloc) noexcept : storage(alloc) {}
+
+ /// @{
+ /// \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& operator=(const reference_storage&) noexcept = default;
+ /// @}
+
+ /// \returns Whether or not the reference is valid.
+ /// It is only invalid, if it was created by the default constructor and the allocator is stateful.
+ explicit operator bool() const noexcept
+ {
+ return storage::is_valid();
+ }
+
+ /// \returns Returns a reference to the allocator.
+ /// \requires The reference must be valid.
+ allocator_type& get_allocator() const noexcept
+ {
+ return storage::get_allocator();
+ }
+
+ protected:
+ ~reference_storage() noexcept = default;
+
+ bool is_composable() const noexcept
+ {
+ return is_composable_allocator<allocator_type>::value;
+ }
+ };
+
+ /// Specialization of the class template \ref reference_storage that is type-erased.
+ /// It is triggered by the tag type \ref any_allocator.
+ /// The specialization can store a reference to any allocator type.
+ /// \ingroup storage
+ template <>
+ class reference_storage<any_allocator>
+ {
+ class base_allocator
+ {
+ public:
+ using is_stateful = std::true_type;
+
+ virtual ~base_allocator() = default;
+
+ virtual void clone(void* storage) const noexcept = 0;
+
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ return allocate_impl(1, size, alignment);
+ }
+
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ return allocate_impl(count, size, alignment);
+ }
+
+ void deallocate_node(void* node, std::size_t size, std::size_t alignment) noexcept
+ {
+ deallocate_impl(node, 1, size, alignment);
+ }
+
+ void deallocate_array(void* array, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ deallocate_impl(array, count, size, alignment);
+ }
+
+ void* try_allocate_node(std::size_t size, std::size_t alignment) noexcept
+ {
+ return try_allocate_impl(1, size, alignment);
+ }
+
+ void* try_allocate_array(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return try_allocate_impl(count, size, alignment);
+ }
+
+ bool try_deallocate_node(void* node, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return try_deallocate_impl(node, 1, size, alignment);
+ }
+
+ bool try_deallocate_array(void* array, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return try_deallocate_impl(array, count, size, alignment);
+ }
+
+ // count 1 means node
+ virtual void* allocate_impl(std::size_t count, std::size_t size,
+ std::size_t alignment) = 0;
+ virtual void deallocate_impl(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept = 0;
+
+ virtual void* try_allocate_impl(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept = 0;
+
+ virtual bool try_deallocate_impl(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept = 0;
+
+ std::size_t max_node_size() const
+ {
+ return max(query::node_size);
+ }
+
+ std::size_t max_array_size() const
+ {
+ return max(query::array_size);
+ }
+
+ std::size_t max_alignment() const
+ {
+ return max(query::alignment);
+ }
+
+ virtual bool is_composable() const noexcept = 0;
+
+ protected:
+ enum class query
+ {
+ node_size,
+ array_size,
+ alignment
+ };
+
+ virtual std::size_t max(query q) const = 0;
+ };
+
+ public:
+ using allocator_type = WPI_IMPL_DEFINED(base_allocator);
+
+ /// \effects Creates it from a reference to any stateful \concept{concept_rawallocator,RawAllocator}.
+ /// It will store a pointer to this allocator object.
+ /// \note The user has to take care that the lifetime of the reference does not exceed the allocator lifetime.
+ template <class RawAllocator>
+ reference_storage(RawAllocator& alloc) noexcept
+ {
+ static_assert(sizeof(basic_allocator<RawAllocator>)
+ <= sizeof(basic_allocator<default_instantiation>),
+ "requires all instantiations to have certain maximum size");
+ ::new (static_cast<void*>(&storage_)) basic_allocator<RawAllocator>(alloc);
+ }
+
+ // \effects Creates it from any stateless \concept{concept_rawallocator,RawAllocator}.
+ /// It will not store anything, only creates the allocator as needed.
+ /// \requires The \c RawAllocator is stateless.
+ template <class RawAllocator>
+ reference_storage(
+ const RawAllocator& alloc,
+ WPI_REQUIRES(!allocator_traits<RawAllocator>::is_stateful::value)) noexcept
+ {
+ static_assert(sizeof(basic_allocator<RawAllocator>)
+ <= sizeof(basic_allocator<default_instantiation>),
+ "requires all instantiations to have certain maximum size");
+ ::new (static_cast<void*>(&storage_)) basic_allocator<RawAllocator>(alloc);
+ }
+
+ /// \effects Creates it from the internal base class for the type-erasure.
+ /// Has the same effect as if the actual stored allocator were passed to the other constructor overloads.
+ /// \note This constructor is used internally to avoid double-nesting.
+ reference_storage(const WPI_IMPL_DEFINED(base_allocator) & alloc) noexcept
+ {
+ alloc.clone(&storage_);
+ }
+
+ /// \effects Creates it from the internal base class for the type-erasure.
+ /// Has the same effect as if the actual stored allocator were passed to the other constructor overloads.
+ /// \note This constructor is used internally to avoid double-nesting.
+ reference_storage(WPI_IMPL_DEFINED(base_allocator) & alloc) noexcept
+ : reference_storage(static_cast<const base_allocator&>(alloc))
+ {
+ }
+
+ /// @{
+ /// \effects Copies the \c reference_storage object.
+ /// It only copies the pointer to the allocator.
+ reference_storage(const reference_storage& other) noexcept
+ {
+ other.get_allocator().clone(&storage_);
+ }
+
+ reference_storage& operator=(const reference_storage& other) noexcept
+ {
+ get_allocator().~allocator_type();
+ other.get_allocator().clone(&storage_);
+ return *this;
+ }
+ /// @}
+
+ /// \returns A reference to the allocator.
+ /// The actual type is implementation-defined since it is the base class used in the type-erasure,
+ /// but it provides the full \concept{concept_rawallocator,RawAllocator} member functions.
+ /// \note There is no way to access any custom member functions of the allocator type.
+ allocator_type& get_allocator() const noexcept
+ {
+ auto mem = static_cast<void*>(&storage_);
+ return *static_cast<base_allocator*>(mem);
+ }
+
+ protected:
+ ~reference_storage() noexcept
+ {
+ get_allocator().~allocator_type();
+ }
+
+ bool is_composable() const noexcept
+ {
+ return get_allocator().is_composable();
+ }
+
+ private:
+ template <class RawAllocator>
+ class basic_allocator
+ : 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>{}))>
+ {
+ using traits = allocator_traits<RawAllocator>;
+ using composable = is_composable_allocator<typename traits::allocator_type>;
+ 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>{}))>;
+
+ public:
+ // non stateful
+ basic_allocator(const RawAllocator& alloc) noexcept : storage(alloc) {}
+
+ // stateful
+ basic_allocator(RawAllocator& alloc) noexcept : storage(alloc) {}
+
+ private:
+ typename traits::allocator_type& get() const noexcept
+ {
+ return storage::get_allocator();
+ }
+
+ void clone(void* storage) const noexcept override
+ {
+ ::new (storage) basic_allocator(get());
+ }
+
+ void* allocate_impl(std::size_t count, std::size_t size,
+ std::size_t alignment) override
+ {
+ auto&& alloc = get();
+ if (count == 1u)
+ return traits::allocate_node(alloc, size, alignment);
+ else
+ return traits::allocate_array(alloc, count, size, alignment);
+ }
+
+ void deallocate_impl(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept override
+ {
+ auto&& alloc = get();
+ if (count == 1u)
+ traits::deallocate_node(alloc, ptr, size, alignment);
+ else
+ traits::deallocate_array(alloc, ptr, count, size, alignment);
+ }
+
+ void* try_allocate_impl(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept override
+ {
+ auto&& alloc = get();
+ if (count == 1u)
+ return detail::try_allocate_node(composable{}, alloc, size, alignment);
+ else
+ return detail::try_allocate_array(composable{}, alloc, count, size,
+ alignment);
+ }
+
+ bool try_deallocate_impl(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept override
+ {
+ auto&& alloc = get();
+ if (count == 1u)
+ return detail::try_deallocate_node(composable{}, alloc, ptr, size,
+ alignment);
+ else
+ return detail::try_deallocate_array(composable{}, alloc, ptr, count, size,
+ alignment);
+ }
+
+ bool is_composable() const noexcept override
+ {
+ return composable::value;
+ }
+
+ std::size_t max(query q) const override
+ {
+ auto&& alloc = get();
+ if (q == query::node_size)
+ return traits::max_node_size(alloc);
+ else if (q == query::array_size)
+ return traits::max_array_size(alloc);
+ return traits::max_alignment(alloc);
+ }
+ };
+
+ // use a stateful instantiation to determine size and alignment
+ // base_allocator is stateful
+ using default_instantiation = basic_allocator<base_allocator>;
+ alignas(default_instantiation) mutable char storage_[sizeof(default_instantiation)];
+ };
+
+ /// An alias template for \ref allocator_storage using the \ref reference_storage policy.
+ /// It will store a reference to the given allocator type. The tag type \ref any_allocator enables type-erasure.
+ /// Wrap the allocator in a \ref thread_safe_allocator if you want thread safety.
+ /// \ingroup storage
+ template <class RawAllocator>
+ WPI_ALIAS_TEMPLATE(allocator_reference,
+ allocator_storage<reference_storage<RawAllocator>, no_mutex>);
+
+ /// \returns A new \ref allocator_reference object by forwarding the allocator to the constructor.
+ /// \relates allocator_reference
+ template <class RawAllocator>
+ auto make_allocator_reference(RawAllocator&& allocator) noexcept
+ -> allocator_reference<typename std::decay<RawAllocator>::type>
+ {
+ return {detail::forward<RawAllocator>(allocator)};
+ }
+
+ /// An alias for the \ref reference_storage specialization using type-erasure.
+ /// \ingroup storage
+ using any_reference_storage = reference_storage<any_allocator>;
+
+ /// An alias for \ref allocator_storage using the \ref any_reference_storage.
+ /// It will store a reference to any \concept{concept_rawallocator,RawAllocator}.
+ /// This is the same as passing the tag type \ref any_allocator to the alias \ref allocator_reference.
+ /// Wrap the allocator in a \ref thread_safe_allocator if you want thread safety.
+ /// \ingroup storage
+ using any_allocator_reference = allocator_storage<any_reference_storage, no_mutex>;
+
+ /// \returns A new \ref any_allocator_reference object by forwarding the allocator to the constructor.
+ /// \relates any_allocator_reference
+ template <class RawAllocator>
+ auto make_any_allocator_reference(RawAllocator&& allocator) noexcept
+ -> any_allocator_reference
+ {
+ return {detail::forward<RawAllocator>(allocator)};
+ }
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_ALLOCATOR_STORAGE_HPP_INCLUDED
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
new file mode 100644
index 0000000..47b6ffb
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/allocator_traits.hpp
@@ -0,0 +1,603 @@
+// 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.
+
+#ifndef WPI_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED
+#define WPI_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED
+
+/// \file
+/// The default specialization of the \ref wpi::memory::allocator_traits.
+
+#include <cstddef>
+#include <type_traits>
+
+#include "detail/align.hpp"
+#include "detail/utility.hpp"
+#include "config.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <memory>
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <class Allocator>
+ std::true_type has_construct(int, WPI_SFINAE(std::declval<Allocator>().construct(
+ std::declval<typename Allocator::pointer>(),
+ std::declval<typename Allocator::value_type>())));
+
+ template <class Allocator>
+ std::false_type has_construct(short);
+
+ template <class Allocator>
+ std::true_type has_destroy(int, WPI_SFINAE(std::declval<Allocator>().destroy(
+ std::declval<typename Allocator::pointer>())));
+
+ template <class Allocator>
+ std::false_type has_destroy(short);
+
+ template <class Allocator>
+ struct check_standard_allocator
+ {
+ using custom_construct = decltype(has_construct<Allocator>(0));
+ using custom_destroy = decltype(has_destroy<Allocator>(0));
+
+ using valid = std::integral_constant<bool, !custom_construct::value
+ && !custom_destroy::value>;
+ };
+ } // namespace detail
+
+ /// Traits class that checks whether or not a standard \c Allocator can be used as \concept{concept_rawallocator,RawAllocator}.
+ /// It checks the existence of a custom \c construct(), \c destroy() function, if provided,
+ /// it cannot be used since it would not be called.<br>
+ /// Specialize it for custom \c Allocator types to override this check.
+ /// \ingroup core
+ template <class Allocator>
+ struct allocator_is_raw_allocator
+ : WPI_EBO(detail::check_standard_allocator<Allocator>::valid)
+ {
+ };
+
+ /// Specialization of \ref allocator_is_raw_allocator that allows \c std::allocator again.
+ /// \ingroup core
+ template <typename T>
+ struct allocator_is_raw_allocator<std::allocator<T>> : std::true_type
+ {
+ };
+
+ namespace traits_detail // use seperate namespace to avoid name clashes
+ {
+ // full_concept has the best conversion rank, error the lowest
+ // used to give priority to the functions
+ struct error
+ {
+ operator void*() const noexcept
+ {
+ WPI_MEMORY_UNREACHABLE(
+ "this is just to hide an error and move static_assert to the front");
+ return nullptr;
+ }
+ };
+ struct std_concept : error
+ {
+ };
+ struct min_concept : std_concept
+ {
+ };
+ struct full_concept : min_concept
+ {
+ };
+
+ // used to delay assert in handle_error() until instantiation
+ template <typename T>
+ struct invalid_allocator_concept
+ {
+ static const bool error = false;
+ };
+
+ //=== allocator_type ===//
+ // if Allocator has a member template `rebind`, use that to rebind to `char`
+ // else if Allocator has a member `value_type`, rebind by changing argument
+ // else does nothing
+ template <class Allocator>
+ auto rebind_impl(int) -> typename Allocator::template rebind<char>::other&;
+
+ template <class Allocator, typename T>
+ struct allocator_rebinder
+ {
+ using type = Allocator&;
+ };
+
+ template <template <typename, typename...> class Alloc, typename U, typename... Args,
+ typename T>
+ struct allocator_rebinder<Alloc<U, Args...>, T>
+ {
+ using type = Alloc<T, Args...>&;
+ };
+
+ template <class Allocator, typename = typename Allocator::value_type>
+ auto rebind_impl(char) -> typename allocator_rebinder<Allocator, char>::type;
+
+ template <class Allocator>
+ auto rebind_impl(...) -> Allocator&;
+
+ template <class Allocator>
+ struct allocator_type_impl // required for MSVC
+ {
+ using type = decltype(rebind_impl<Allocator>(0));
+ };
+
+ template <class Allocator>
+ using allocator_type =
+ typename std::decay<typename allocator_type_impl<Allocator>::type>::type;
+
+ //=== is_stateful ===//
+ // first try to access Allocator::is_stateful,
+ // then use whether or not the type is empty
+ template <class Allocator>
+ auto is_stateful(full_concept) -> decltype(typename Allocator::is_stateful{});
+
+ template <class Allocator, bool IsEmpty>
+ struct is_stateful_impl;
+
+ template <class Allocator>
+ struct is_stateful_impl<Allocator, true>
+ {
+ static_assert(std::is_default_constructible<Allocator>::value,
+ "RawAllocator is empty but not default constructible ."
+ "This means it is not a stateless allocator. "
+ "If this is actually intended provide the appropriate is_stateful "
+ "typedef in your class.");
+ using type = std::false_type;
+ };
+
+ template <class Allocator>
+ struct is_stateful_impl<Allocator, false>
+ {
+ using type = std::true_type;
+ };
+
+ template <class Allocator>
+ auto is_stateful(min_concept) ->
+ typename is_stateful_impl<Allocator, std::is_empty<Allocator>::value>::type;
+
+ //=== allocate_node() ===//
+ // first try Allocator::allocate_node
+ // then assume std_allocator and call Allocator::allocate
+ // then error
+ template <class Allocator>
+ auto allocate_node(full_concept, Allocator& alloc, std::size_t size,
+ std::size_t alignment)
+ -> WPI_AUTO_RETURN_TYPE(alloc.allocate_node(size, alignment), void*)
+
+ template <class Allocator>
+ auto allocate_node(std_concept, Allocator& alloc, std::size_t size, std::size_t)
+ -> WPI_AUTO_RETURN(static_cast<void*>(alloc.allocate(size)))
+
+ template <class Allocator>
+ error allocate_node(error, Allocator&, std::size_t, std::size_t)
+ {
+ static_assert(invalid_allocator_concept<Allocator>::error,
+ "type is not a RawAllocator as it does not provide: void* "
+ "allocate_node(std::size_t, "
+ "std::size_t)");
+ return {};
+ }
+
+ //=== deallocate_node() ===//
+ // first try Allocator::deallocate_node
+ // then assume std_allocator and call Allocator::deallocate
+ // then error
+ template <class Allocator>
+ auto deallocate_node(full_concept, Allocator& alloc, void* ptr, std::size_t size,
+ std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.deallocate_node(ptr, size, alignment), void)
+
+ template <class Allocator>
+ auto deallocate_node(std_concept, Allocator& alloc, void* ptr, std::size_t size,
+ std::size_t) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.deallocate(static_cast<char*>(ptr), size), void)
+
+ template <class Allocator>
+ error deallocate_node(error, Allocator&, void*, std::size_t, std::size_t)
+ {
+ static_assert(invalid_allocator_concept<Allocator>::error,
+ "type is not a RawAllocator as it does not provide: void "
+ "deallocate_node(void*, std::size_t, "
+ "std::size_t)");
+ return error{};
+ }
+
+ //=== allocate_array() ===//
+ // first try Allocator::allocate_array
+ // then forward to allocate_node()
+ template <class Allocator>
+ auto allocate_array(full_concept, Allocator& alloc, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ -> WPI_AUTO_RETURN_TYPE(alloc.allocate_array(count, size, alignment), void*)
+
+ template <class Allocator>
+ void* allocate_array(min_concept, Allocator& alloc, std::size_t count,
+ std::size_t size, std::size_t alignment)
+ {
+ return allocate_node(full_concept{}, alloc, count * size, alignment);
+ }
+
+ //=== deallocate_array() ===//
+ // first try Allocator::deallocate_array
+ // then forward to deallocate_node()
+ template <class Allocator>
+ auto deallocate_array(full_concept, Allocator& alloc, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.deallocate_array(ptr, count, size, alignment),
+ void)
+
+ template <class Allocator>
+ void deallocate_array(min_concept, Allocator& alloc, void* ptr,
+ std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ deallocate_node(full_concept{}, alloc, ptr, count * size, alignment);
+ }
+
+ //=== max_node_size() ===//
+ // first try Allocator::max_node_size()
+ // then return maximum value
+ template <class Allocator>
+ auto max_node_size(full_concept, const Allocator& alloc)
+ -> WPI_AUTO_RETURN_TYPE(alloc.max_node_size(), std::size_t)
+
+ template <class Allocator>
+ std::size_t max_node_size(min_concept, const Allocator&) noexcept
+ {
+ return std::size_t(-1);
+ }
+
+ //=== max_node_size() ===//
+ // first try Allocator::max_array_size()
+ // then forward to max_node_size()
+ template <class Allocator>
+ auto max_array_size(full_concept, const Allocator& alloc)
+ -> WPI_AUTO_RETURN_TYPE(alloc.max_array_size(), std::size_t)
+
+ template <class Allocator>
+ std::size_t max_array_size(min_concept, const Allocator& alloc)
+ {
+ return max_node_size(full_concept{}, alloc);
+ }
+
+ //=== max_alignment() ===//
+ // first try Allocator::max_alignment()
+ // then return detail::max_alignment
+ template <class Allocator>
+ auto max_alignment(full_concept, const Allocator& alloc)
+ -> WPI_AUTO_RETURN_TYPE(alloc.max_alignment(), std::size_t)
+
+ template <class Allocator>
+ std::size_t max_alignment(min_concept, const Allocator&)
+ {
+ return detail::max_alignment;
+ }
+ } // namespace traits_detail
+
+ /// The default specialization of the allocator_traits for a \concept{concept_rawallocator,RawAllocator}.
+ /// See the last link for the requirements on types that do not specialize this class and the interface documentation.
+ /// Any specialization must provide the same interface.
+ /// \ingroup core
+ template <class Allocator>
+ class allocator_traits
+ {
+ public:
+ using allocator_type = traits_detail::allocator_type<Allocator>;
+ using is_stateful =
+ decltype(traits_detail::is_stateful<Allocator>(traits_detail::full_concept{}));
+
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ return traits_detail::allocate_node(traits_detail::full_concept{}, state, size,
+ alignment);
+ }
+
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ return traits_detail::allocate_array(traits_detail::full_concept{}, state, count,
+ size, alignment);
+ }
+
+ static void deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ traits_detail::deallocate_node(traits_detail::full_concept{}, state, node, size,
+ alignment);
+ }
+
+ static void deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ traits_detail::deallocate_array(traits_detail::full_concept{}, state, array, count,
+ size, alignment);
+ }
+
+ static std::size_t max_node_size(const allocator_type& state)
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ return traits_detail::max_node_size(traits_detail::full_concept{}, state);
+ }
+
+ static std::size_t max_array_size(const allocator_type& state)
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ return traits_detail::max_array_size(traits_detail::full_concept{}, state);
+ }
+
+ static std::size_t max_alignment(const allocator_type& state)
+ {
+ static_assert(allocator_is_raw_allocator<Allocator>::value,
+ "Allocator cannot be used as RawAllocator because it provides custom "
+ "construct()/destroy()");
+ return traits_detail::max_alignment(traits_detail::full_concept{}, state);
+ }
+
+#if !defined(DOXYGEN)
+ using foonathan_memory_default_traits = std::true_type;
+#endif
+ };
+
+ namespace detail
+ {
+ template <class RawAllocator>
+ typename allocator_traits<RawAllocator>::foonathan_memory_default_traits
+ alloc_uses_default_traits(RawAllocator&);
+
+ std::false_type alloc_uses_default_traits(...);
+
+ 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>
+ {
+ };
+
+ template <typename T>
+ struct has_invalid_dealloc_function
+ : std::is_same<
+ decltype(traits_detail::deallocate_node(traits_detail::full_concept{},
+ std::declval<typename allocator_traits<
+ T>::allocator_type&>(),
+ nullptr, 0, 0)),
+ traits_detail::error>
+ {
+ };
+
+ template <typename T, class DefaultTraits>
+ struct is_raw_allocator : std::true_type
+ {
+ };
+
+ template <typename T>
+ struct is_raw_allocator<T, std::integral_constant<bool, true>>
+ : std::integral_constant<bool, allocator_is_raw_allocator<T>::value
+ && !(has_invalid_alloc_function<T>::value
+ || has_invalid_dealloc_function<T>::value)>
+ {
+ };
+ } // namespace detail
+
+ /// Traits that check whether a type models concept \concept{concept_rawallocator,RawAllocator}.<br>
+ /// It must either provide the necessary functions for the default traits specialization or has specialized it.
+ /// \ingroup core
+ template <typename T>
+ struct is_raw_allocator
+ : detail::is_raw_allocator<T,
+ decltype(detail::alloc_uses_default_traits(std::declval<T&>()))>
+ {
+ };
+
+ namespace traits_detail
+ {
+ //=== try_allocate_node() ===//
+ // try Allocator::try_allocate_node
+ // otherwise error
+ template <class Allocator>
+ auto try_allocate_node(full_concept, Allocator& alloc, std::size_t size,
+ std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.try_allocate_node(size, alignment), void*)
+
+ template <class Allocator>
+ error try_allocate_node(error, Allocator&, std::size_t, std::size_t)
+ {
+ static_assert(invalid_allocator_concept<Allocator>::error,
+ "type is not a composable RawAllocator as it does not provide: void* "
+ "try_allocate_node(std::size_t, "
+ "std::size_t)");
+ return {};
+ }
+
+ //=== try_deallocate_node() ===//
+ // try Allocator::try_deallocate_node
+ // otherwise error
+ template <class Allocator>
+ auto try_deallocate_node(full_concept, Allocator& alloc, void* ptr, std::size_t size,
+ std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.try_deallocate_node(ptr, size, alignment), bool)
+
+ template <class Allocator>
+ error try_deallocate_node(error, Allocator&, void*, std::size_t, std::size_t)
+ {
+ static_assert(invalid_allocator_concept<Allocator>::error,
+ "type is not a composable RawAllocator as it does not provide: bool "
+ "try_deallocate_node(void*, std::size_t, "
+ "std::size_t)");
+ return error{};
+ }
+
+ //=== try_allocate_array() ===//
+ // first try Allocator::try_allocate_array
+ // then forward to try_allocate_node()
+ template <class Allocator>
+ auto try_allocate_array(full_concept, Allocator& alloc, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.try_allocate_array(count, size, alignment),
+ void*)
+
+ template <class Allocator>
+ void* try_allocate_array(min_concept, Allocator& alloc, std::size_t count,
+ std::size_t size, std::size_t alignment)
+ {
+ return try_allocate_node(full_concept{}, alloc, count * size, alignment);
+ }
+
+ //=== try_deallocate_array() ===//
+ // first try Allocator::try_deallocate_array
+ // then forward to try_deallocate_node()
+ template <class Allocator>
+ auto try_deallocate_array(full_concept, Allocator& alloc, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ -> WPI_AUTO_RETURN_TYPE(alloc.try_deallocate_array(ptr, count, size,
+ alignment),
+ bool)
+
+ template <class Allocator>
+ bool try_deallocate_array(min_concept, Allocator& alloc, void* ptr,
+ std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return try_deallocate_node(full_concept{}, alloc, ptr, count * size, alignment);
+ }
+ } // namespace traits_detail
+
+ /// The default specialization of the composable_allocator_traits for a \concept{concept_composableallocator,ComposableAllocator}.
+ /// See the last link for the requirements on types that do not specialize this class and the interface documentation.
+ /// Any specialization must provide the same interface.
+ /// \ingroup core
+ template <class Allocator>
+ class composable_allocator_traits
+ {
+ public:
+ using allocator_type = typename allocator_traits<Allocator>::allocator_type;
+
+ static void* try_allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ static_assert(is_raw_allocator<Allocator>::value,
+ "ComposableAllocator must be RawAllocator");
+ return traits_detail::try_allocate_node(traits_detail::full_concept{}, state, size,
+ alignment);
+ }
+
+ static void* try_allocate_array(allocator_type& state, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ static_assert(is_raw_allocator<Allocator>::value,
+ "ComposableAllocator must be RawAllocator");
+ return traits_detail::try_allocate_array(traits_detail::full_concept{}, state,
+ count, size, alignment);
+ }
+
+ static bool try_deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ static_assert(is_raw_allocator<Allocator>::value,
+ "ComposableAllocator must be RawAllocator");
+ return traits_detail::try_deallocate_node(traits_detail::full_concept{}, state,
+ node, size, alignment);
+ }
+
+ static bool try_deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ static_assert(is_raw_allocator<Allocator>::value,
+ "ComposableAllocator must be RawAllocator");
+ return traits_detail::try_deallocate_array(traits_detail::full_concept{}, state,
+ array, count, size, alignment);
+ }
+
+#if !defined(DOXYGEN)
+ using foonathan_memory_default_traits = std::true_type;
+#endif
+ };
+
+ namespace detail
+ {
+ template <class RawAllocator>
+ typename composable_allocator_traits<RawAllocator>::foonathan_memory_default_traits
+ composable_alloc_uses_default_traits(RawAllocator&);
+
+ std::false_type composable_alloc_uses_default_traits(...);
+
+ template <typename T>
+ struct has_invalid_try_alloc_function
+ : std::is_same<
+ decltype(traits_detail::try_allocate_node(traits_detail::full_concept{},
+ std::declval<typename allocator_traits<
+ T>::allocator_type&>(),
+ 0, 0)),
+ traits_detail::error>
+ {
+ };
+
+ 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>
+ {
+ };
+
+ template <typename T, class DefaultTraits>
+ struct is_composable_allocator : memory::is_raw_allocator<T>
+ {
+ };
+
+ template <typename T>
+ struct is_composable_allocator<T, std::integral_constant<bool, true>>
+ : std::integral_constant<bool, memory::is_raw_allocator<T>::value
+ && !(has_invalid_try_alloc_function<T>::value
+ || has_invalid_try_dealloc_function<T>::value)>
+ {
+ };
+ } // namespace detail
+
+ /// Traits that check whether a type models concept \concept{concept_rawallocator,ComposableAllocator}.<br>
+ /// It must be a \concept{concept_rawallocator,RawAllocator} and either provide the necessary functions for the default traits specialization or has specialized it.
+ /// \ingroup core
+ template <typename T>
+ struct is_composable_allocator
+ : detail::is_composable_allocator<T, decltype(detail::composable_alloc_uses_default_traits(
+ std::declval<T&>()))>
+ {
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_ALLOCATOR_TRAITS_HPP_INCLUDED
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
new file mode 100644
index 0000000..067ecd2
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config.hpp
@@ -0,0 +1,148 @@
+// 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.
+
+/// \file
+/// Configuration macros.
+
+#ifndef WPI_MEMORY_CONFIG_HPP_INCLUDED
+#define WPI_MEMORY_CONFIG_HPP_INCLUDED
+
+#include <cstddef>
+
+#if !defined(DOXYGEN)
+#define WPI_MEMORY_IMPL_IN_CONFIG_HPP
+#include "config_impl.hpp"
+#undef WPI_MEMORY_IMPL_IN_CONFIG_HPP
+#endif
+
+// exception support
+#ifndef WPI_HAS_EXCEPTION_SUPPORT
+#if defined(__GNUC__) && !defined(__EXCEPTIONS)
+#define WPI_HAS_EXCEPTION_SUPPORT 0
+#elif defined(_MSC_VER) && !_HAS_EXCEPTIONS
+#define WPI_HAS_EXCEPTION_SUPPORT 0
+#else
+#define WPI_HAS_EXCEPTION_SUPPORT 1
+#endif
+#endif
+
+#if WPI_HAS_EXCEPTION_SUPPORT
+#define WPI_THROW(Ex) throw(Ex)
+#else
+#include <cstdlib>
+#define WPI_THROW(Ex) ((Ex), std::abort())
+#endif
+
+// hosted implementation
+#ifndef WPI_HOSTED_IMPLEMENTATION
+#if !_MSC_VER && !__STDC_HOSTED__
+#define WPI_HOSTED_IMPLEMENTATION 0
+#else
+#define WPI_HOSTED_IMPLEMENTATION 1
+#endif
+#endif
+
+// log prefix
+#define WPI_MEMORY_LOG_PREFIX "wpi::memory"
+
+// version
+#define WPI_MEMORY_VERSION \
+ (WPI_MEMORY_VERSION_MAJOR * 100 + WPI_MEMORY_VERSION_MINOR)
+
+// use this macro to mark implementation-defined types
+// gives it more semantics and useful with doxygen
+// add PREDEFINED: WPI_IMPL_DEFINED():=implementation_defined
+#ifndef WPI_IMPL_DEFINED
+#define WPI_IMPL_DEFINED(...) __VA_ARGS__
+#endif
+
+// use this macro to mark base class which only purpose is EBO
+// gives it more semantics and useful with doxygen
+// add PREDEFINED: WPI_EBO():=
+#ifndef WPI_EBO
+#define WPI_EBO(...) __VA_ARGS__
+#endif
+
+#ifndef WPI_ALIAS_TEMPLATE
+// defines a template alias
+// usage:
+// template <typename T>
+// WPI_ALIAS_TEMPLATE(bar, foo<T, int>);
+// useful for doxygen
+#ifdef DOXYGEN
+#define WPI_ALIAS_TEMPLATE(Name, ...) \
+ class Name : public __VA_ARGS__ \
+ { \
+ }
+#else
+#define WPI_ALIAS_TEMPLATE(Name, ...) using Name = __VA_ARGS__
+#endif
+#endif
+
+#ifdef DOXYGEN
+// dummy definitions of config macros for doxygen
+
+/// The major version number.
+/// \ingroup core
+#define WPI_MEMORY_VERSION_MAJOR 1
+
+/// The minor version number.
+/// \ingroup core
+#define WPI_MEMORY_VERSION_MINOR 1
+
+/// The total version number of the form \c Mmm.
+/// \ingroup core
+#define WPI_MEMORY_VERSION \
+ (WPI_MEMORY_VERSION_MAJOR * 100 + WPI_MEMORY_VERSION_MINOR)
+
+/// Whether or not the allocation size will be checked,
+/// i.e. the \ref wpi::memory::bad_allocation_size thrown.
+/// \ingroup core
+#define WPI_MEMORY_CHECK_ALLOCATION_SIZE 1
+
+/// Whether or not internal assertions in the library are enabled.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_ASSERT 1
+
+/// Whether or not allocated memory will be filled with special values.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_FILL 1
+
+/// The size of the fence memory, it has no effect if \ref WPI_MEMORY_DEBUG_FILL is \c false.
+/// \note For most allocators, the actual value doesn't matter and they use appropriate defaults to ensure alignment etc.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_FENCE 1
+
+/// Whether or not leak checking is enabled.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_LEAK_CHECK 1
+
+/// Whether or not the deallocation functions will check for pointers that were never allocated by an allocator.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_POINTER_CHECK 1
+
+/// Whether or not the deallocation functions will check for double free errors.
+/// This option makes no sense if \ref WPI_MEMORY_DEBUG_POINTER_CHECK is \c false.
+/// \ingroup core
+#define WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK 1
+
+/// Whether or not everything is in namespace <tt>wpi::memory</tt>.
+/// If \c false, a namespace alias <tt>namespace memory = wpi::memory</tt> is automatically inserted into each header,
+/// allowing to qualify everything with <tt>wpi::</tt>.
+/// \note This option breaks in combination with using <tt>using namespace wpi;</tt>.
+/// \ingroup core
+#define WPI_MEMORY_NAMESPACE_PREFIX 1
+
+/// The mode of the automatic \ref wpi::memory::temporary_stack creation.
+/// Set to `2` to enable automatic lifetime management of the per-thread stack through nifty counter.
+/// Then all memory will be freed upon program termination automatically.
+/// 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.
+/// \ingroup allocator
+#define WPI_MEMORY_TEMPORARY_STACK_MODE 2
+#endif
+
+#endif // WPI_MEMORY_CONFIG_HPP_INCLUDED
diff --git a/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config_impl.hpp b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config_impl.hpp
new file mode 100644
index 0000000..1f72375
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/config_impl.hpp
@@ -0,0 +1,34 @@
+// 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.
+
+// Copyright (C) 2015-2020 Jonathan 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.
+
+#pragma once
+
+#include <cstddef>
+
+//=== options ===//
+#define WPI_MEMORY_CHECK_ALLOCATION_SIZE 1
+#define WPI_MEMORY_IMPL_DEFAULT_ALLOCATOR heap_allocator
+#ifdef NDEBUG
+#define WPI_MEMORY_DEBUG_ASSERT 0
+#define WPI_MEMORY_DEBUG_FILL 0
+#define WPI_MEMORY_DEBUG_FENCE 0
+#define WPI_MEMORY_DEBUG_LEAK_CHECK 0
+#define WPI_MEMORY_DEBUG_POINTER_CHECK 0
+#define WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK 0
+#else
+#define WPI_MEMORY_DEBUG_ASSERT 1
+#define WPI_MEMORY_DEBUG_FILL 1
+#define WPI_MEMORY_DEBUG_FENCE 8
+#define WPI_MEMORY_DEBUG_LEAK_CHECK 1
+#define WPI_MEMORY_DEBUG_POINTER_CHECK 1
+#define WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK 1
+#endif
+#define WPI_MEMORY_EXTERN_TEMPLATE 1
+#define WPI_MEMORY_TEMPORARY_STACK_MODE 2
+
+#define WPI_MEMORY_NO_NODE_SIZE 1
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
new file mode 100644
index 0000000..fd1547f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/container.hpp
@@ -0,0 +1,362 @@
+// 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.
+
+#ifndef WPI_MEMORY_CONTAINER_HPP_INCLUDED
+#define WPI_MEMORY_CONTAINER_HPP_INCLUDED
+
+/// \file
+/// Aliasas for STL containers using a certain \concept{concept_rawallocator,RawAllocator}.
+/// \note Only available on a hosted implementation.
+
+#include "config.hpp"
+#if !WPI_HOSTED_IMPLEMENTATION
+#error "This header is only available for a hosted implementation."
+#endif
+
+#include <functional>
+#include <utility>
+
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <queue>
+#include <scoped_allocator>
+#include <set>
+#include <stack>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "std_allocator.hpp"
+#include "threading.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// \ingroup adapter
+ /// @{
+
+ /// Alias template for an STL container that uses a certain
+ /// \concept{concept_rawallocator,RawAllocator}. It is just a shorthand for a passing in the \c
+ /// RawAllocator wrapped in a \ref wpi::memory::std_allocator.
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(vector, std::vector<T, std_allocator<T, RawAllocator>>);
+
+ /// Same as above but uses \c std::scoped_allocator_adaptor so the allocator is inherited by all
+ /// nested containers.
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ vector_scoped_alloc,
+ std::vector<T, std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(deque, std::deque<T, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ deque_scoped_alloc,
+ std::deque<T, std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(list, std::list<T, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ list_scoped_alloc,
+ std::list<T, std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(forward_list,
+ std::forward_list<T, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ forward_list_scoped_alloc,
+ std::forward_list<T, std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(set, std::set<T, std::less<T>, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ set_scoped_alloc,
+ std::set<T, std::less<T>,
+ std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(multiset,
+ std::multiset<T, std::less<T>, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ multiset_scoped_alloc,
+ std::multiset<T, std::less<T>,
+ std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ map, std::map<Key, Value, std::less<Key>,
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ map_scoped_alloc,
+ std::map<Key, Value, std::less<Key>,
+ std::scoped_allocator_adaptor<
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ multimap, std::multimap<Key, Value, std::less<Key>,
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ multimap_scoped_alloc,
+ std::multimap<Key, Value, std::less<Key>,
+ std::scoped_allocator_adaptor<
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_set,
+ std::unordered_set<T, std::hash<T>, std::equal_to<T>, std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_set_scoped_alloc,
+ std::unordered_set<T, std::hash<T>, std::equal_to<T>,
+ std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(unordered_multiset,
+ std::unordered_multiset<T, std::hash<T>, std::equal_to<T>,
+ std_allocator<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_multiset_scoped_alloc,
+ std::unordered_multiset<T, std::hash<T>, std::equal_to<T>,
+ std::scoped_allocator_adaptor<std_allocator<T, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_map,
+ std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_map_scoped_alloc,
+ std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ std::scoped_allocator_adaptor<
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_multimap,
+ std::unordered_multimap<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename Key, typename Value, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unordered_multimap_scoped_alloc,
+ std::unordered_multimap<Key, Value, std::hash<Key>, std::equal_to<Key>,
+ std::scoped_allocator_adaptor<
+ std_allocator<std::pair<const Key, Value>, RawAllocator>>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(stack, std::stack<T, deque<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(stack_scoped_alloc,
+ std::stack<T, deque_scoped_alloc<T, RawAllocator>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(queue, std::queue<T, deque<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(queue_scoped_alloc,
+ std::queue<T, deque_scoped_alloc<T, RawAllocator>>);
+
+ /// \copydoc vector
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(priority_queue, std::priority_queue<T, deque<T, RawAllocator>>);
+ /// \copydoc vector_scoped_alloc
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(priority_queue_scoped_alloc,
+ std::priority_queue<T, deque_scoped_alloc<T, RawAllocator>>);
+
+ /// \copydoc vector
+ template <class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ string,
+ std::basic_string<char, std::char_traits<char>, std_allocator<char, RawAllocator>>);
+ /// @}
+
+ /// @{
+ /// Convenience function to create a container adapter using a certain
+ /// \concept{concept_rawallocator,RawAllocator}. \returns An empty adapter with an
+ /// implementation container using a reference to a given allocator. \ingroup adapter
+ template <typename T, class RawAllocator, class Container = deque<T, RawAllocator>>
+ std::stack<T, Container> make_stack(RawAllocator& allocator)
+ {
+ return std::stack<T, Container>{Container(allocator)};
+ }
+
+ /// \copydoc make_stack
+ template <typename T, class RawAllocator, class Container = deque<T, RawAllocator>>
+ std::queue<T, Container> make_queue(RawAllocator& allocator)
+ {
+ return std::queue<T, Container>{Container(allocator)};
+ }
+
+ /// \copydoc make_stack
+ template <typename T, class RawAllocator, class Container = deque<T, RawAllocator>,
+ class Compare = std::less<T>>
+ std::priority_queue<T, Container, Compare> make_priority_queue(RawAllocator& allocator,
+ Compare comp = {})
+ {
+ return std::priority_queue<T, Container, Compare>{detail::move(comp),
+ Container(allocator)};
+ }
+ /// @}
+
+#if !defined(DOXYGEN)
+
+#include "detail/container_node_sizes.hpp"
+
+#if !defined(WPI_MEMORY_NO_NODE_SIZE)
+ /// \exclude
+ namespace detail
+ {
+ template <typename T, class StdAllocator>
+ struct shared_ptr_node_size
+ {
+ static_assert(sizeof(T) != sizeof(T), "unsupported allocator type");
+ };
+
+ template <typename T, class RawAllocator>
+ struct shared_ptr_node_size<T, std_allocator<T, RawAllocator>>
+ : std::conditional<allocator_traits<RawAllocator>::is_stateful::value,
+ memory::shared_ptr_stateful_node_size<T>,
+ memory::shared_ptr_stateless_node_size<T>>::type
+ {
+ static_assert(sizeof(std_allocator<T, RawAllocator>) <= sizeof(void*),
+ "fix node size debugger");
+ };
+
+ } // namespace detail
+
+ template <typename T, class StdAllocator>
+ struct shared_ptr_node_size : detail::shared_ptr_node_size<T, StdAllocator>
+ {
+ };
+#endif
+
+#else
+ /// \ingroup adapter
+ /// @{
+
+ /// 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.
+ template <typename T>
+ struct forward_list_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct list_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct set_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct multiset_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct unordered_set_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct unordered_multiset_node_size
+ : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct map_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct multimap_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct unordered_map_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T>
+ struct unordered_multimap_node_size
+ : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+
+ /// \copydoc forward_list_node_size
+ template <typename T, class StdAllocator>
+ struct shared_ptr_node_size : std::integral_constant<std::size_t, implementation_defined>
+ {
+ };
+/// @}
+#endif
+
+#if !defined(WPI_MEMORY_NO_NODE_SIZE)
+ /// The node size required by \ref allocate_shared.
+ /// \note This is similar to \ref shared_ptr_node_size but takes a
+ /// \concept{concept_rawallocator,RawAllocator} instead.
+ template <typename T, class RawAllocator>
+ struct allocate_shared_node_size : shared_ptr_node_size<T, std_allocator<T, RawAllocator>>
+ {
+ };
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_CONTAINER_HPP_INCLUDED
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
new file mode 100644
index 0000000..b04050f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/debugging.hpp
@@ -0,0 +1,114 @@
+// 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.
+
+#ifndef WPI_MEMORY_DEBUGGING_HPP_INCLUDED
+#define WPI_MEMORY_DEBUGGING_HPP_INCLUDED
+
+/// \file
+/// Debugging facilities.
+
+#include "config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ struct allocator_info;
+
+ /// The magic values that are used for debug filling.
+ /// If \ref WPI_MEMORY_DEBUG_FILL is \c true, memory will be filled to help detect use-after-free or missing initialization errors.
+ /// These are the constants for the different types.
+ /// \ingroup core
+ enum class debug_magic : unsigned char
+ {
+ /// Marks internal memory used by the allocator - "allocated block".
+ internal_memory = 0xAB,
+ /// Marks internal memory currently not used by the allocator - "freed block".
+ internal_freed_memory = 0xFB,
+ /// Marks allocated, but not yet used memory - "clean memory".
+ new_memory = 0xCD,
+ /// Marks freed memory - "dead memory".
+ freed_memory = 0xDD,
+ /// Marks buffer memory used to ensure proper alignment.
+ /// This memory can also serve as \ref debug_magic::fence_memory.
+ alignment_memory = 0xED,
+ /// Marks buffer memory used to protect against overflow - "fence memory".
+ /// The option \ref WPI_MEMORY_DEBUG_FENCE controls the size of a memory fence that will be placed before or after a memory block.
+ /// It helps catching buffer overflows.
+ fence_memory = 0xFD
+ };
+
+ /// The type of the handler called when a memory leak is detected.
+ /// Leak checking can be controlled via the option \ref WPI_MEMORY_DEBUG_LEAK_CHECK
+ /// and only affects calls through the \ref allocator_traits, not direct calls.
+ /// The handler gets the \ref allocator_info and the amount of memory leaked.
+ /// This can also be negative, meaning that more memory has been freed than allocated.
+ /// \requiredbe A leak handler shall log the leak, abort the program, do nothing or anything else that seems appropriate.
+ /// It must not throw any exceptions since it is called in the cleanup process.
+ /// \defaultbe On a hosted implementation it logs the leak to \c stderr and returns, continuing execution.
+ /// On a freestanding implementation it does nothing.
+ /// \ingroup core
+ using leak_handler = void (*)(const allocator_info& info, std::ptrdiff_t amount);
+
+ /// Exchanges the \ref leak_handler.
+ /// \effects Sets \c h as the new \ref leak_handler in an atomic operation.
+ /// A \c nullptr sets the default \ref leak_handler.
+ /// \returns The previous \ref leak_handler. This is never \c nullptr.
+ /// \ingroup core
+ leak_handler set_leak_handler(leak_handler h);
+
+ /// Returns the \ref leak_handler.
+ /// \returns The current \ref leak_handler. This is never \c nullptr.
+ /// \ingroup core
+ leak_handler get_leak_handler();
+
+ /// The type of the handler called when an invalid pointer is passed to a deallocation function.
+ /// Pointer checking can be controlled via the options \ref WPI_MEMORY_DEBUG_POINTER_CHECK and \ref WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK.
+ /// The handler gets the \ref allocator_info and the invalid pointer.
+ /// \requiredbe An invalid pointer handler shall terminate the program.
+ /// It must not throw any exceptions since it might be called in the cleanup process.
+ /// \defaultbe On a hosted implementation it logs the information to \c stderr and calls \c std::abort().
+ /// On a freestanding implementation it only calls \c std::abort().
+ /// \ingroup core
+ using invalid_pointer_handler = void (*)(const allocator_info& info, const void* ptr);
+
+ /// Exchanges the \ref invalid_pointer_handler.
+ /// \effects Sets \c h as the new \ref invalid_pointer_handler in an atomic operation.
+ /// A \c nullptr sets the default \ref invalid_pointer_handler.
+ /// \returns The previous \ref invalid_pointer_handler. This is never \c nullptr.
+ /// \ingroup core
+ invalid_pointer_handler set_invalid_pointer_handler(invalid_pointer_handler h);
+
+ /// Returns the \ref invalid_pointer_handler.
+ /// \returns The current \ref invalid_pointer_handler. This is never \c nullptr.
+ /// \ingroup core
+ invalid_pointer_handler get_invalid_pointer_handler();
+
+ /// The type of the handler called when a buffer under/overflow is detected.
+ /// If \ref WPI_MEMORY_DEBUG_FILL is \c true and \ref WPI_MEMORY_DEBUG_FENCE has a non-zero value
+ /// the allocator classes check if a write into the fence has occured upon deallocation.
+ /// The handler gets the memory block belonging to the corrupted fence, its size and the exact address.
+ /// \requiredbe A buffer overflow handler shall terminate the program.
+ /// It must not throw any exceptions since it me be called in the cleanup process.
+ /// \defaultbe On a hosted implementation it logs the information to \c stderr and calls \c std::abort().
+ /// On a freestanding implementation it only calls \c std::abort().
+ /// \ingroup core
+ using buffer_overflow_handler = void (*)(const void* memory, std::size_t size,
+ const void* write_ptr);
+
+ /// Exchanges the \ref buffer_overflow_handler.
+ /// \effects Sets \c h as the new \ref buffer_overflow_handler in an atomic operation.
+ /// A \c nullptr sets the default \ref buffer_overflow_handler.
+ /// \returns The previous \ref buffer_overflow_handler. This is never \c nullptr.
+ /// \ingroup core
+ buffer_overflow_handler set_buffer_overflow_handler(buffer_overflow_handler h);
+
+ /// Returns the \ref buffer_overflow_handler.
+ /// \returns The current \ref buffer_overflow_handler. This is never \c nullptr.
+ /// \ingroup core
+ buffer_overflow_handler get_buffer_overflow_handler();
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..107a641
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/default_allocator.hpp
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef WPI_MEMORY_DEFAULT_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_DEFAULT_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// The typedef \ref wpi::memory::default_allocator.
+
+#include "config.hpp"
+#include "heap_allocator.hpp"
+#include "new_allocator.hpp"
+#include "static_allocator.hpp"
+#include "virtual_memory.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include "malloc_allocator.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// The default \concept{concept_rawallocator,RawAllocator} that will be used as \concept{concept_blockallocator,BlockAllocator} in memory arenas.
+ /// Arena allocators like \ref memory_stack or \ref memory_pool allocate memory by subdividing a huge block.
+ /// They get a \concept{concept_blockallocator,BlockAllocator} that will be used for their internal allocation,
+ /// this type is the default value.
+ /// \requiredbe Its type can be changed via the CMake option \c WPI_MEMORY_DEFAULT_ALLCOATOR,
+ /// but it must be one of the following: \ref heap_allocator, \ref new_allocator, \ref malloc_allocator, \ref static_allocator, \ref virtual_memory_allocator.
+ /// \defaultbe The default is \ref heap_allocator.
+ /// \ingroup allocator
+ using default_allocator = WPI_IMPL_DEFINED(WPI_MEMORY_IMPL_DEFAULT_ALLOCATOR);
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..01c967c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/deleter.hpp
@@ -0,0 +1,308 @@
+// 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.
+
+#ifndef WPI_MEMORY_DELETER_HPP_INCLUDED
+#define WPI_MEMORY_DELETER_HPP_INCLUDED
+
+/// \file
+/// \c Deleter classes using a \concept{concept_rawallocator,RawAllocator}.
+
+#include <type_traits>
+
+#include "allocator_storage.hpp"
+#include "config.hpp"
+#include "threading.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A deleter class that deallocates the memory through a specified \concept{concept_rawallocator,RawAllocator}.
+ ///
+ /// It deallocates memory for a specified type but does not call its destructors.
+ /// \ingroup adapter
+ template <typename Type, class RawAllocator>
+ class allocator_deallocator : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ static_assert(!std::is_abstract<Type>::value,
+ "use allocator_polymorphic_deallocator for storing base classes");
+
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = Type;
+
+ /// \effects Creates it without any associated allocator.
+ /// The deallocator must not be used if that is the case.
+ /// \notes This functions is useful if you have want to create an empty smart pointer without giving it an allocator.
+ allocator_deallocator() noexcept = default;
+
+ /// \effects Creates it by passing it an \ref allocator_reference.
+ /// It will store the reference to it and uses the referenced allocator object for the deallocation.
+ allocator_deallocator(allocator_reference<RawAllocator> alloc) noexcept
+ : allocator_reference<RawAllocator>(alloc)
+ {
+ }
+
+ /// \effects Deallocates the memory given to it.
+ /// Calls \c deallocate_node(pointer, sizeof(value_type), alignof(value_type)) on the referenced allocator object.
+ /// \requires The deallocator must not have been created by the default constructor.
+ void operator()(value_type* pointer) noexcept
+ {
+ this->deallocate_node(pointer, sizeof(value_type), alignof(value_type));
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ /// \requires The deallocator must not be created by the default constructor.
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+ };
+
+ /// Specialization of \ref allocator_deallocator for array types.
+ /// Otherwise the same behavior.
+ /// \ingroup adapter
+ template <typename Type, class RawAllocator>
+ class allocator_deallocator<Type[], RawAllocator>
+ : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ static_assert(!std::is_abstract<Type>::value, "must not create polymorphic arrays");
+
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = Type;
+
+ /// \effects Creates it without any associated allocator.
+ /// The deallocator must not be used if that is the case.
+ /// \notes This functions is useful if you have want to create an empty smart pointer without giving it an allocator.
+ allocator_deallocator() noexcept : size_(0u) {}
+
+ /// \effects Creates it by passing it an \ref allocator_reference and the size of the array that will be deallocated.
+ /// It will store the reference to the allocator and uses the referenced allocator object for the deallocation.
+ allocator_deallocator(allocator_reference<RawAllocator> alloc,
+ std::size_t size) noexcept
+ : allocator_reference<RawAllocator>(alloc), size_(size)
+ {
+ }
+
+ /// \effects Deallocates the memory given to it.
+ /// Calls \c deallocate_array(pointer, size, sizeof(value_type), alignof(value_type))
+ /// on the referenced allocator object with the size given in the constructor.
+ /// \requires The deallocator must not have been created by the default constructor.
+ void operator()(value_type* pointer) noexcept
+ {
+ this->deallocate_array(pointer, size_, sizeof(value_type), alignof(value_type));
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ /// \requires The deallocator must not have been created by the default constructor.
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+
+ /// \returns The size of the array that will be deallocated.
+ /// This is the same value as passed in the constructor, or `0` if it was created by the default constructor.
+ std::size_t array_size() const noexcept
+ {
+ return size_;
+ }
+
+ private:
+ std::size_t size_;
+ };
+
+ /// A deleter class that deallocates the memory of a derived type through a specified \concept{concept_rawallocator,RawAllocator}.
+ ///
+ /// It can only be created from a \ref allocator_deallocator and thus must only be used for smart pointers initialized by derived-to-base conversion of the pointer.
+ /// \ingroup adapter
+ template <typename BaseType, class RawAllocator>
+ class allocator_polymorphic_deallocator : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = BaseType;
+
+ /// \effects Creates it from a deallocator for a derived type.
+ /// It will deallocate the memory as if done by the derived type.
+ template <typename T, WPI_REQUIRES((std::is_base_of<BaseType, T>::value))>
+ allocator_polymorphic_deallocator(allocator_deallocator<T, RawAllocator> dealloc)
+ : allocator_reference<RawAllocator>(dealloc.get_allocator()),
+ derived_size_(sizeof(T)),
+ derived_alignment_(alignof(T))
+ {
+ }
+
+ /// \effects Deallocates the memory given to it.
+ /// Calls \c deallocate_node(pointer, size, alignment) on the referenced allocator object,
+ /// where \c size and \c alignment are the values of the type it was created with.
+ void operator()(value_type* pointer) noexcept
+ {
+ this->deallocate_node(pointer, derived_size_, derived_alignment_);
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+
+ private:
+ std::size_t derived_size_, derived_alignment_;
+ };
+
+ /// Similar to \ref allocator_deallocator but calls the destructors of the object.
+ /// Otherwise behaves the same.
+ /// \ingroup adapter
+ template <typename Type, class RawAllocator>
+ class allocator_deleter : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ static_assert(!std::is_abstract<Type>::value,
+ "use allocator_polymorphic_deleter for storing base classes");
+
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = Type;
+
+ /// \effects Creates it without any associated allocator.
+ /// The deleter must not be used if that is the case.
+ /// \notes This functions is useful if you have want to create an empty smart pointer without giving it an allocator.
+ allocator_deleter() noexcept = default;
+
+ /// \effects Creates it by passing it an \ref allocator_reference.
+ /// It will store the reference to it and uses the referenced allocator object for the deallocation.
+ allocator_deleter(allocator_reference<RawAllocator> alloc) noexcept
+ : allocator_reference<RawAllocator>(alloc)
+ {
+ }
+
+ /// \effects Calls the destructor and deallocates the memory given to it.
+ /// Calls \c deallocate_node(pointer, sizeof(value_type), alignof(value_type))
+ /// on the referenced allocator object for the deallocation.
+ /// \requires The deleter must not have been created by the default constructor.
+ void operator()(value_type* pointer) noexcept
+ {
+ pointer->~value_type();
+ this->deallocate_node(pointer, sizeof(value_type), alignof(value_type));
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+ };
+
+ /// Specialization of \ref allocator_deleter for array types.
+ /// Otherwise the same behavior.
+ /// \ingroup adapter
+ template <typename Type, class RawAllocator>
+ class allocator_deleter<Type[], RawAllocator>
+ : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ static_assert(!std::is_abstract<Type>::value, "must not create polymorphic arrays");
+
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = Type;
+
+ /// \effects Creates it without any associated allocator.
+ /// The deleter must not be used if that is the case.
+ /// \notes This functions is useful if you have want to create an empty smart pointer without giving it an allocator.
+ allocator_deleter() noexcept : size_(0u) {}
+
+ /// \effects Creates it by passing it an \ref allocator_reference and the size of the array that will be deallocated.
+ /// It will store the reference to the allocator and uses the referenced allocator object for the deallocation.
+ allocator_deleter(allocator_reference<RawAllocator> alloc, std::size_t size) noexcept
+ : allocator_reference<RawAllocator>(alloc), size_(size)
+ {
+ }
+
+ /// \effects Calls the destructors and deallocates the memory given to it.
+ /// Calls \c deallocate_array(pointer, size, sizeof(value_type), alignof(value_type))
+ /// on the referenced allocator object with the size given in the constructor for the deallocation.
+ /// \requires The deleter must not have been created by the default constructor.
+ void operator()(value_type* pointer) noexcept
+ {
+ for (auto cur = pointer; cur != pointer + size_; ++cur)
+ cur->~value_type();
+ this->deallocate_array(pointer, size_, sizeof(value_type), alignof(value_type));
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ /// \requires The deleter must not be created by the default constructor.
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+
+ /// \returns The size of the array that will be deallocated.
+ /// This is the same value as passed in the constructor, or `0` if it was created by the default constructor.
+ std::size_t array_size() const noexcept
+ {
+ return size_;
+ }
+
+ private:
+ std::size_t size_;
+ };
+
+ /// Similar to \ref allocator_polymorphic_deallocator but calls the destructors of the object.
+ /// Otherwise behaves the same.
+ /// \note It has a relatively high space overhead, so only use it if you have to.
+ /// \ingroup adapter
+ template <typename BaseType, class RawAllocator>
+ class allocator_polymorphic_deleter : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ public:
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+ using value_type = BaseType;
+
+ /// \effects Creates it from a deleter for a derived type.
+ /// It will deallocate the memory as if done by the derived type.
+ template <typename T, WPI_REQUIRES((std::is_base_of<BaseType, T>::value))>
+ allocator_polymorphic_deleter(allocator_deleter<T, RawAllocator> deleter)
+ : allocator_reference<RawAllocator>(deleter.get_allocator()),
+ derived_size_(sizeof(T)),
+ derived_alignment_(alignof(T))
+ {
+ WPI_MEMORY_ASSERT(std::size_t(derived_size_) == sizeof(T)
+ && std::size_t(derived_alignment_) == alignof(T));
+ }
+
+ /// \effects Deallocates the memory given to it.
+ /// Calls \c deallocate_node(pointer, size, alignment) on the referenced allocator object,
+ /// where \c size and \c alignment are the values of the type it was created with.
+ void operator()(value_type* pointer) noexcept
+ {
+ pointer->~value_type();
+ this->deallocate_node(pointer, derived_size_, derived_alignment_);
+ }
+
+ /// \returns The reference to the allocator.
+ /// It has the same type as the call to \ref allocator_reference::get_allocator().
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+
+ private:
+ unsigned short derived_size_,
+ derived_alignment_; // use unsigned short here to save space
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..99d6bcc
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/align.hpp
@@ -0,0 +1,52 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_ALIGN_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_ALIGN_HPP_INCLUDED
+
+#include <cstdint>
+
+#include "../config.hpp"
+#include "assert.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // whether or not an alignment is valid, i.e. a power of two not zero
+ constexpr bool is_valid_alignment(std::size_t alignment) noexcept
+ {
+ return alignment && (alignment & (alignment - 1)) == 0u;
+ }
+
+ // returns the offset needed to align ptr for given alignment
+ // alignment must be valid
+ inline std::size_t align_offset(std::uintptr_t address, std::size_t alignment) noexcept
+ {
+ WPI_MEMORY_ASSERT(is_valid_alignment(alignment));
+ auto misaligned = address & (alignment - 1);
+ return misaligned != 0 ? (alignment - misaligned) : 0;
+ }
+ inline std::size_t align_offset(void* ptr, std::size_t alignment) noexcept
+ {
+ return align_offset(reinterpret_cast<std::uintptr_t>(ptr), alignment);
+ }
+
+ // whether or not the pointer is aligned for given alignment
+ // alignment must be valid
+ bool is_aligned(void* ptr, std::size_t alignment) noexcept;
+
+ // maximum alignment value
+ constexpr std::size_t max_alignment = alignof(std::max_align_t);
+ static_assert(is_valid_alignment(max_alignment), "ehm..?");
+
+ // returns the minimum alignment required for a node of given size
+ std::size_t alignment_for(std::size_t size) noexcept;
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..b8a7372
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/assert.hpp
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_ASSERT_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_ASSERT_HPP_INCLUDED
+
+#include <cstdlib>
+
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // handles a failed assertion
+ void handle_failed_assert(const char* msg, const char* file, int line,
+ const char* fnc) noexcept;
+
+ void handle_warning(const char* msg, const char* file, int line,
+ const char* fnc) noexcept;
+
+// note: debug assertion macros don't use fully qualified name
+// because they should only be used in this library, where the whole namespace is available
+// can be override via command line definitions
+#if WPI_MEMORY_DEBUG_ASSERT && !defined(WPI_MEMORY_ASSERT)
+#define WPI_MEMORY_ASSERT(Expr) \
+ static_cast<void>((Expr) \
+ || (detail::handle_failed_assert("Assertion \"" #Expr "\" failed", __FILE__, \
+ __LINE__, __func__), \
+ true))
+
+#define WPI_MEMORY_ASSERT_MSG(Expr, Msg) \
+ static_cast<void>((Expr) \
+ || (detail::handle_failed_assert("Assertion \"" #Expr "\" failed: " Msg, \
+ __FILE__, __LINE__, __func__), \
+ true))
+
+#define WPI_MEMORY_UNREACHABLE(Msg) \
+ detail::handle_failed_assert("Unreachable code reached: " Msg, __FILE__, __LINE__, __func__)
+
+#define WPI_MEMORY_WARNING(Msg) detail::handle_warning(Msg, __FILE__, __LINE__, __func__)
+
+#elif !defined(WPI_MEMORY_ASSERT)
+#define WPI_MEMORY_ASSERT(Expr)
+#define WPI_MEMORY_ASSERT_MSG(Expr, Msg)
+#define WPI_MEMORY_UNREACHABLE(Msg) std::abort()
+#define WPI_MEMORY_WARNING(Msg)
+#endif
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..37949ca
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/container_node_sizes.hpp
@@ -0,0 +1,10 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_CONTAINER_NODE_SIZES_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_CONTAINER_NODE_SIZES_HPP_INCLUDED
+
+#include "container_node_sizes_impl.hpp"
+
+#endif //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
new file mode 100644
index 0000000..3ef2eed
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/debug_helpers.hpp
@@ -0,0 +1,235 @@
+// 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.
+
+#ifndef WPI_MEMORY_DEBUG_HELPERS_HPP_INCLUDED
+#define WPI_MEMORY_DEBUG_HELPERS_HPP_INCLUDED
+
+#include <atomic>
+#include <type_traits>
+
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ enum class debug_magic : unsigned char;
+ struct allocator_info;
+
+ namespace detail
+ {
+ using debug_fill_enabled = std::integral_constant<bool, WPI_MEMORY_DEBUG_FILL>;
+ constexpr std::size_t debug_fence_size =
+ WPI_MEMORY_DEBUG_FILL ? WPI_MEMORY_DEBUG_FENCE : 0u;
+
+#if WPI_MEMORY_DEBUG_FILL
+ // fills size bytes of memory with debug_magic
+ void debug_fill(void* memory, std::size_t size, debug_magic m) noexcept;
+
+ // returns nullptr if memory is filled with debug_magic
+ // else returns pointer to mismatched byte
+ void* debug_is_filled(void* memory, std::size_t size, debug_magic m) noexcept;
+
+ // fills fence, new and fence
+ // returns after fence
+ void* debug_fill_new(void* memory, std::size_t node_size,
+ std::size_t fence_size = debug_fence_size) noexcept;
+
+ // fills free memory and returns memory starting at fence
+ void* debug_fill_free(void* memory, std::size_t node_size,
+ std::size_t fence_size = debug_fence_size) noexcept;
+
+ // fills internal memory
+ void debug_fill_internal(void* memory, std::size_t size, bool free) noexcept;
+#else
+ inline void debug_fill(void*, std::size_t, debug_magic) noexcept {}
+
+ inline void* debug_is_filled(void*, std::size_t, debug_magic) noexcept
+ {
+ return nullptr;
+ }
+
+ inline void* debug_fill_new(void* memory, std::size_t, std::size_t) noexcept
+ {
+ return memory;
+ }
+
+ inline void* debug_fill_free(void* memory, std::size_t, std::size_t) noexcept
+ {
+ return static_cast<char*>(memory);
+ }
+
+ inline void debug_fill_internal(void*, std::size_t, bool) noexcept {}
+#endif
+
+ void debug_handle_invalid_ptr(const allocator_info& info, void* ptr);
+
+ // validates given ptr by evaluating the Functor
+ // if the Functor returns false, calls the debug_leak_checker
+ // note: ptr is just used as the information passed to the invalid ptr handler
+ template <class Functor>
+ void debug_check_pointer(Functor condition, const allocator_info& info, void* ptr)
+ {
+#if WPI_MEMORY_DEBUG_POINTER_CHECK
+ if (!condition())
+ debug_handle_invalid_ptr(info, ptr);
+#else
+ (void)ptr;
+ (void)condition;
+ (void)info;
+#endif
+ }
+
+ // validates ptr by using a more expensive double-dealloc check
+ template <class Functor>
+ void debug_check_double_dealloc(Functor condition, const allocator_info& info,
+ void* ptr)
+ {
+#if WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK
+ debug_check_pointer(condition, info, ptr);
+#else
+ (void)condition;
+ (void)info;
+ (void)ptr;
+#endif
+ }
+
+ void debug_handle_memory_leak(const allocator_info& info, std::ptrdiff_t amount);
+
+ // does no leak checking, null overhead
+ template <class Handler>
+ class no_leak_checker
+ {
+ public:
+ no_leak_checker() noexcept {}
+ no_leak_checker(no_leak_checker&&) noexcept {}
+ ~no_leak_checker() noexcept {}
+
+ no_leak_checker& operator=(no_leak_checker&&) noexcept
+ {
+ return *this;
+ }
+
+ void on_allocate(std::size_t) noexcept {}
+ void on_deallocate(std::size_t) noexcept {}
+ };
+
+ // does leak checking per-object
+ // leak is detected upon destructor
+ template <class Handler>
+ class object_leak_checker : Handler
+ {
+ public:
+ object_leak_checker() noexcept : allocated_(0) {}
+
+ object_leak_checker(object_leak_checker&& other) noexcept
+ : allocated_(other.allocated_)
+ {
+ other.allocated_ = 0;
+ }
+
+ ~object_leak_checker() noexcept
+ {
+ if (allocated_ != 0)
+ this->operator()(allocated_);
+ }
+
+ object_leak_checker& operator=(object_leak_checker&& other) noexcept
+ {
+ allocated_ = other.allocated_;
+ other.allocated_ = 0;
+ return *this;
+ }
+
+ void on_allocate(std::size_t size) noexcept
+ {
+ allocated_ += std::ptrdiff_t(size);
+ }
+
+ void on_deallocate(std::size_t size) noexcept
+ {
+ allocated_ -= std::ptrdiff_t(size);
+ }
+
+ private:
+ std::ptrdiff_t allocated_;
+ };
+
+ // does leak checking on a global basis
+ // call macro WPI_MEMORY_GLOBAL_LEAK_CHECKER(handler, var_name) in the header
+ // when last counter gets destroyed, leak is detected
+ template <class Handler>
+ class global_leak_checker_impl
+ {
+ public:
+ struct counter : Handler
+ {
+ counter()
+ {
+ ++no_counter_objects_;
+ }
+
+ ~counter()
+ {
+ --no_counter_objects_;
+ if (no_counter_objects_ == 0u && allocated_ != 0u)
+ this->operator()(allocated_);
+ }
+ };
+
+ global_leak_checker_impl() noexcept {}
+ global_leak_checker_impl(global_leak_checker_impl&&) noexcept {}
+ ~global_leak_checker_impl() noexcept {}
+
+ global_leak_checker_impl& operator=(global_leak_checker_impl&&) noexcept
+ {
+ return *this;
+ }
+
+ void on_allocate(std::size_t size) noexcept
+ {
+ allocated_ += std::ptrdiff_t(size);
+ }
+
+ void on_deallocate(std::size_t size) noexcept
+ {
+ allocated_ -= std::ptrdiff_t(size);
+ }
+
+ private:
+ static std::atomic<std::size_t> no_counter_objects_;
+ static std::atomic<std::ptrdiff_t> allocated_;
+ };
+
+ template <class Handler>
+ std::atomic<std::size_t> global_leak_checker_impl<Handler>::no_counter_objects_(0u);
+
+ template <class Handler>
+ std::atomic<std::ptrdiff_t> global_leak_checker_impl<Handler>::allocated_(0);
+
+#if WPI_MEMORY_DEBUG_LEAK_CHECK
+ template <class Handler>
+ using global_leak_checker = global_leak_checker_impl<Handler>;
+
+#define WPI_MEMORY_GLOBAL_LEAK_CHECKER(handler, var_name) \
+ static wpi::memory::detail::global_leak_checker<handler>::counter var_name;
+#else
+ template <class Handler>
+ using global_leak_checker = no_leak_checker<int>; // only one instantiation
+
+#define WPI_MEMORY_GLOBAL_LEAK_CHECKER(handler, var_name)
+#endif
+
+#if WPI_MEMORY_DEBUG_LEAK_CHECK
+ template <class Handler>
+ using default_leak_checker = object_leak_checker<Handler>;
+#else
+ template <class Handler>
+ using default_leak_checker = no_leak_checker<Handler>;
+#endif
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..de53f7f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ebo_storage.hpp
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_EBO_STORAGE_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_EBO_STORAGE_HPP_INCLUDED
+
+#include "utility.hpp"
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <int Tag, typename T>
+ class ebo_storage : T
+ {
+ protected:
+ ebo_storage(const T& t) : T(t) {}
+
+ ebo_storage(T&& t) noexcept(std::is_nothrow_move_constructible<T>::value)
+ : T(detail::move(t))
+ {
+ }
+
+ T& get() noexcept
+ {
+ return *this;
+ }
+
+ const T& get() const noexcept
+ {
+ return *this;
+ }
+ };
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..612706d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list.hpp
@@ -0,0 +1,228 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAILL_FREE_LIST_HPP_INCLUDED
+#define WPI_MEMORY_DETAILL_FREE_LIST_HPP_INCLUDED
+
+#include <cstddef>
+#include <cstdint>
+
+#include "align.hpp"
+#include "utility.hpp"
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // stores free blocks for a memory pool
+ // memory blocks are fragmented and stored in a list
+ // debug: fills memory and uses a bigger node_size for fence memory
+ class free_memory_list
+ {
+ public:
+ // minimum element size
+ static constexpr auto min_element_size = sizeof(char*);
+ // alignment
+ static constexpr auto min_element_alignment = alignof(char*);
+
+ // minimal size of the block that needs to be inserted
+ static constexpr std::size_t min_block_size(std::size_t node_size,
+ std::size_t number_of_nodes)
+ {
+ return (node_size < min_element_size ? min_element_size : node_size)
+ * number_of_nodes;
+ }
+
+ //=== constructor ===//
+ free_memory_list(std::size_t node_size) noexcept;
+
+ // calls other constructor plus insert
+ free_memory_list(std::size_t node_size, void* mem, std::size_t size) noexcept;
+
+ free_memory_list(free_memory_list&& other) noexcept;
+ ~free_memory_list() noexcept = default;
+
+ free_memory_list& operator=(free_memory_list&& other) noexcept;
+
+ friend void swap(free_memory_list& a, free_memory_list& b) noexcept;
+
+ //=== insert/allocation/deallocation ===//
+ // inserts a new memory block, by splitting it up and setting the links
+ // does not own memory!
+ // mem must be aligned for alignment()
+ // pre: size != 0
+ void insert(void* mem, std::size_t size) noexcept;
+
+ // returns the usable size
+ // i.e. how many memory will be actually inserted and usable on a call to insert()
+ std::size_t usable_size(std::size_t size) const noexcept
+ {
+ // Round down to next multiple of node size.
+ return (size / node_size_) * node_size_;
+ }
+
+ // returns a single block from the list
+ // pre: !empty()
+ void* allocate() noexcept;
+
+ // returns a memory block big enough for n bytes
+ // might fail even if capacity is sufficient
+ void* allocate(std::size_t n) noexcept;
+
+ // deallocates a single block
+ void deallocate(void* ptr) noexcept;
+
+ // deallocates multiple blocks with n bytes total
+ void deallocate(void* ptr, std::size_t n) noexcept;
+
+ //=== getter ===//
+ std::size_t node_size() const noexcept
+ {
+ return node_size_;
+ }
+
+ // alignment of all nodes
+ std::size_t alignment() const noexcept;
+
+ // number of nodes remaining
+ std::size_t capacity() const noexcept
+ {
+ return capacity_;
+ }
+
+ bool empty() const noexcept
+ {
+ return first_ == nullptr;
+ }
+
+ private:
+ void insert_impl(void* mem, std::size_t size) noexcept;
+
+ char* first_;
+ std::size_t node_size_, capacity_;
+ };
+
+ void swap(free_memory_list& a, free_memory_list& b) noexcept;
+
+ // same as above but keeps the nodes ordered
+ // this allows array allocations, that is, consecutive nodes
+ // debug: fills memory and uses a bigger node_size for fence memory
+ class ordered_free_memory_list
+ {
+ public:
+ // minimum element size
+ static constexpr auto min_element_size = sizeof(char*);
+ // alignment
+ static constexpr auto min_element_alignment = alignof(char*);
+
+ // minimal size of the block that needs to be inserted
+ static constexpr std::size_t min_block_size(std::size_t node_size,
+ std::size_t number_of_nodes)
+ {
+ return (node_size < min_element_size ? min_element_size : node_size)
+ * number_of_nodes;
+ }
+
+ //=== constructor ===//
+ ordered_free_memory_list(std::size_t node_size) noexcept;
+
+ ordered_free_memory_list(std::size_t node_size, void* mem,
+ std::size_t size) noexcept
+ : ordered_free_memory_list(node_size)
+ {
+ insert(mem, size);
+ }
+
+ ordered_free_memory_list(ordered_free_memory_list&& other) noexcept;
+
+ ~ordered_free_memory_list() noexcept = default;
+
+ ordered_free_memory_list& operator=(ordered_free_memory_list&& other) noexcept
+ {
+ ordered_free_memory_list tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+
+ friend void swap(ordered_free_memory_list& a, ordered_free_memory_list& b) noexcept;
+
+ //=== insert/allocation/deallocation ===//
+ // inserts a new memory block, by splitting it up and setting the links
+ // does not own memory!
+ // mem must be aligned for alignment()
+ // pre: size != 0
+ void insert(void* mem, std::size_t size) noexcept;
+
+ // returns the usable size
+ // i.e. how many memory will be actually inserted and usable on a call to insert()
+ std::size_t usable_size(std::size_t size) const noexcept
+ {
+ // Round down to next multiple of node size.
+ return (size / node_size_) * node_size_;
+ }
+
+ // returns a single block from the list
+ // pre: !empty()
+ void* allocate() noexcept;
+
+ // returns a memory block big enough for n bytes (!, not nodes)
+ // might fail even if capacity is sufficient
+ void* allocate(std::size_t n) noexcept;
+
+ // deallocates a single block
+ void deallocate(void* ptr) noexcept;
+
+ // deallocates multiple blocks with n bytes total
+ void deallocate(void* ptr, std::size_t n) noexcept;
+
+ //=== getter ===//
+ std::size_t node_size() const noexcept
+ {
+ return node_size_;
+ }
+
+ // alignment of all nodes
+ std::size_t alignment() const noexcept;
+
+ // number of nodes remaining
+ std::size_t capacity() const noexcept
+ {
+ return capacity_;
+ }
+
+ bool empty() const noexcept
+ {
+ return capacity_ == 0u;
+ }
+
+ private:
+ // returns previous pointer
+ char* insert_impl(void* mem, std::size_t size) noexcept;
+
+ char* begin_node() noexcept;
+ char* end_node() noexcept;
+
+ std::uintptr_t begin_proxy_, end_proxy_;
+ std::size_t node_size_, capacity_;
+ char * last_dealloc_, *last_dealloc_prev_;
+ };
+
+ void swap(ordered_free_memory_list& a, ordered_free_memory_list& b) noexcept;
+
+#if WPI_MEMORY_DEBUG_DOUBLE_DEALLOC_CHECK
+ // use ordered version to allow pointer check
+ using node_free_memory_list = ordered_free_memory_list;
+ using array_free_memory_list = ordered_free_memory_list;
+#else
+ using node_free_memory_list = free_memory_list;
+ using array_free_memory_list = ordered_free_memory_list;
+#endif
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..ec57e1e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/free_list_array.hpp
@@ -0,0 +1,126 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_FREE_LIST_ARRAY_HPP
+#define WPI_MEMORY_DETAIL_FREE_LIST_ARRAY_HPP
+
+#include "align.hpp"
+#include "assert.hpp"
+#include "memory_stack.hpp"
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // an array of free_memory_list types
+ // indexed via size, AccessPolicy does necessary conversions
+ // requires trivial destructible FreeList type
+ template <class FreeList, class AccessPolicy>
+ class free_list_array
+ {
+ // not supported on GCC 4.7
+ //static_assert(std::is_trivially_destructible<FreeList>::value,
+ // "free list must be trivially destructible");
+ public:
+ // creates sufficient elements to support up to given maximum node size
+ // all lists are initially empty
+ // actual number is calculated via policy
+ // memory is taken from fixed_memory_stack, it must be sufficient
+ free_list_array(fixed_memory_stack& stack, const char* end,
+ std::size_t max_node_size) noexcept
+ : no_elements_(AccessPolicy::index_from_size(max_node_size) - min_size_index + 1)
+ {
+ array_ = static_cast<FreeList*>(
+ stack.allocate(end, no_elements_ * sizeof(FreeList), alignof(FreeList)));
+ WPI_MEMORY_ASSERT_MSG(array_, "insufficient memory for free lists");
+ for (std::size_t i = 0u; i != no_elements_; ++i)
+ {
+ auto node_size = AccessPolicy::size_from_index(i + min_size_index);
+ ::new (static_cast<void*>(array_ + i)) FreeList(node_size);
+ }
+ }
+
+ // move constructor, does not actually move the elements, just the pointer
+ free_list_array(free_list_array&& other) noexcept
+ : array_(other.array_), no_elements_(other.no_elements_)
+ {
+ other.array_ = nullptr;
+ other.no_elements_ = 0u;
+ }
+
+ // destructor, does nothing, list must be trivially destructible!
+ ~free_list_array() noexcept = default;
+
+ free_list_array& operator=(free_list_array&& other) noexcept
+ {
+ array_ = other.array_;
+ no_elements_ = other.no_elements_;
+
+ other.array_ = nullptr;
+ other.no_elements_ = 0u;
+ return *this;
+ }
+
+ // access free list for given size
+ FreeList& get(std::size_t node_size) const noexcept
+ {
+ auto i = AccessPolicy::index_from_size(node_size);
+ if (i < min_size_index)
+ i = min_size_index;
+ return array_[i - min_size_index];
+ }
+
+ // number of free lists
+ std::size_t size() const noexcept
+ {
+ return no_elements_;
+ }
+
+ // maximum supported node size
+ std::size_t max_node_size() const noexcept
+ {
+ return AccessPolicy::size_from_index(no_elements_ + min_size_index - 1);
+ }
+
+ private:
+ static const std::size_t min_size_index;
+
+ FreeList* array_;
+ std::size_t no_elements_;
+ };
+
+ template <class FL, class AP>
+ const std::size_t free_list_array<FL, AP>::min_size_index =
+ AP::index_from_size(FL::min_element_size);
+
+ // AccessPolicy that maps size to indices 1:1
+ // creates a free list for each size!
+ struct identity_access_policy
+ {
+ static std::size_t index_from_size(std::size_t size) noexcept
+ {
+ return size;
+ }
+
+ static std::size_t size_from_index(std::size_t index) noexcept
+ {
+ return index;
+ }
+ };
+
+ // AccessPolicy that maps sizes to the integral log2
+ // this creates more nodes and never wastes more than half the size
+ struct log2_access_policy
+ {
+ static std::size_t index_from_size(std::size_t size) noexcept;
+ static std::size_t size_from_index(std::size_t index) noexcept;
+ };
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..5cf125a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/ilog2.hpp
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_ILOG2_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_ILOG2_HPP_INCLUDED
+
+#include <climits>
+#include <cstdint>
+
+#include "../config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // undefined for 0
+ template <typename UInt>
+ constexpr bool is_power_of_two(UInt x)
+ {
+ return (x & (x - 1)) == 0;
+ }
+
+ inline std::size_t ilog2_base(std::uint64_t x)
+ {
+#if defined(__GNUC__)
+ unsigned long long value = x;
+ return sizeof(value) * CHAR_BIT - static_cast<unsigned>(__builtin_clzll(value));
+#else
+ // Adapted from https://stackoverflow.com/a/40943402
+ std::size_t clz = 64;
+ std::size_t c = 32;
+ do
+ {
+ auto tmp = x >> c;
+ if (tmp != 0)
+ {
+ clz -= c;
+ x = tmp;
+ }
+ c = c >> 1;
+ } while (c != 0);
+ clz -= x ? 1 : 0;
+
+ return 64 - clz;
+#endif
+ }
+
+ // ilog2() implementation, cuts part after the comma
+ // e.g. 1 -> 0, 2 -> 1, 3 -> 1, 4 -> 2, 5 -> 2
+ inline std::size_t ilog2(std::uint64_t x)
+ {
+ return ilog2_base(x) - 1;
+ }
+
+ // ceiling ilog2() implementation, adds one if part after comma
+ // e.g. 1 -> 0, 2 -> 1, 3 -> 2, 4 -> 2, 5 -> 3
+ inline std::size_t ilog2_ceil(std::uint64_t x)
+ {
+ // only subtract one if power of two
+ return ilog2_base(x) - std::size_t(is_power_of_two(x));
+ }
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif
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
new file mode 100644
index 0000000..2ac45a5
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/lowlevel_allocator.hpp
@@ -0,0 +1,86 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_LOWLEVEL_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_LOWLEVEL_ALLOCATOR_HPP_INCLUDED
+
+#include <type_traits>
+
+#include "../config.hpp"
+#include "../error.hpp"
+#include "align.hpp"
+#include "debug_helpers.hpp"
+#include "assert.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <class Functor>
+ struct lowlevel_allocator_leak_handler
+ {
+ void operator()(std::ptrdiff_t amount)
+ {
+ debug_handle_memory_leak(Functor::info(), amount);
+ }
+ };
+
+ // Functor controls low-level allocation:
+ // static allocator_info info()
+ // static void* allocate(std::size_t size, std::size_t alignment);
+ // static void deallocate(void *memory, std::size_t size, std::size_t alignment);
+ // static std::size_t max_node_size();
+ template <class Functor>
+ class lowlevel_allocator : global_leak_checker<lowlevel_allocator_leak_handler<Functor>>
+ {
+ public:
+ using is_stateful = std::false_type;
+
+ lowlevel_allocator() noexcept {}
+ lowlevel_allocator(lowlevel_allocator&&) noexcept {}
+ ~lowlevel_allocator() noexcept {}
+
+ lowlevel_allocator& operator=(lowlevel_allocator&&) noexcept
+ {
+ return *this;
+ }
+
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ auto actual_size = size + (debug_fence_size ? 2 * max_alignment : 0u);
+
+ auto memory = Functor::allocate(actual_size, alignment);
+ if (!memory)
+ WPI_THROW(out_of_memory(Functor::info(), actual_size));
+
+ this->on_allocate(actual_size);
+
+ return debug_fill_new(memory, size, max_alignment);
+ }
+
+ void deallocate_node(void* node, std::size_t size, std::size_t alignment) noexcept
+ {
+ auto actual_size = size + (debug_fence_size ? 2 * max_alignment : 0u);
+
+ auto memory = debug_fill_free(node, size, max_alignment);
+ Functor::deallocate(memory, actual_size, alignment);
+
+ this->on_deallocate(actual_size);
+ }
+
+ std::size_t max_node_size() const noexcept
+ {
+ return Functor::max_node_size();
+ }
+ };
+
+#define WPI_MEMORY_LL_ALLOCATOR_LEAK_CHECKER(functor, var_name) \
+ WPI_MEMORY_GLOBAL_LEAK_CHECKER(lowlevel_allocator_leak_handler<functor>, var_name)
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..e49d480
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/memory_stack.hpp
@@ -0,0 +1,120 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_MEMORY_STACK_HPP_INCLUDED
+
+#include <cstddef>
+
+#include "../config.hpp"
+#include "align.hpp"
+#include "debug_helpers.hpp"
+#include "../debugging.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // simple memory stack implementation that does not support growing
+ class fixed_memory_stack
+ {
+ public:
+ fixed_memory_stack() noexcept : fixed_memory_stack(nullptr) {}
+
+ // gives it the current pointer, the end pointer must be maintained seperataly
+ explicit fixed_memory_stack(void* memory) noexcept
+ : cur_(static_cast<char*>(memory))
+ {
+ }
+
+ fixed_memory_stack(fixed_memory_stack&& other) noexcept : cur_(other.cur_)
+ {
+ other.cur_ = nullptr;
+ }
+
+ ~fixed_memory_stack() noexcept = default;
+
+ fixed_memory_stack& operator=(fixed_memory_stack&& other) noexcept
+ {
+ cur_ = other.cur_;
+ other.cur_ = nullptr;
+ return *this;
+ }
+
+ // bumps the top pointer without filling it
+ void bump(std::size_t offset) noexcept
+ {
+ cur_ += offset;
+ }
+
+ // bumps the top pointer by offset and fills
+ void bump(std::size_t offset, debug_magic m) noexcept
+ {
+ detail::debug_fill(cur_, offset, m);
+ bump(offset);
+ }
+
+ // same as bump(offset, m) but returns old value
+ void* bump_return(std::size_t offset,
+ debug_magic m = debug_magic::new_memory) noexcept
+ {
+ auto memory = cur_;
+ detail::debug_fill(memory, offset, m);
+ cur_ += offset;
+ return memory;
+ }
+
+ // allocates memory by advancing the stack, returns nullptr if insufficient
+ // debug: mark memory as new_memory, put fence in front and back
+ void* allocate(const char* end, std::size_t size, std::size_t alignment,
+ std::size_t fence_size = debug_fence_size) noexcept
+ {
+ if (cur_ == nullptr)
+ return nullptr;
+
+ auto remaining = std::size_t(end - cur_);
+ auto offset = align_offset(cur_ + fence_size, alignment);
+ if (fence_size + offset + size + fence_size > remaining)
+ return nullptr;
+
+ return allocate_unchecked(size, offset, fence_size);
+ }
+
+ // same as allocate() but does not check the size
+ // note: pass it the align OFFSET, not the alignment
+ void* allocate_unchecked(std::size_t size, std::size_t align_offset,
+ std::size_t fence_size = debug_fence_size) noexcept
+ {
+ bump(fence_size, debug_magic::fence_memory);
+ bump(align_offset, debug_magic::alignment_memory);
+ auto mem = bump_return(size);
+ bump(fence_size, debug_magic::fence_memory);
+ return mem;
+ }
+
+ // unwindws the stack to a certain older position
+ // debug: marks memory from new top to old top as freed
+ // doesn't check for invalid pointer
+ void unwind(char* top) noexcept
+ {
+ debug_fill(top, std::size_t(cur_ - top), debug_magic::freed_memory);
+ cur_ = top;
+ }
+
+ // returns the current top
+ char* top() const noexcept
+ {
+ return cur_;
+ }
+
+ private:
+ char* cur_;
+ };
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..682417d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/small_free_list.hpp
@@ -0,0 +1,164 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_SMALL_FREE_LIST_HPP_INCLUDED
+#define WPI_MEMORY_DETAIL_SMALL_FREE_LIST_HPP_INCLUDED
+
+#include <cstddef>
+#include <climits>
+
+#include "../config.hpp"
+#include "utility.hpp"
+#include "align.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ struct chunk_base
+ {
+ chunk_base* prev = this;
+ chunk_base* next = this;
+
+ unsigned char first_free = 0; // first free node for the linked list
+ unsigned char capacity = 0; // total number of free nodes available
+ unsigned char no_nodes = 0; // total number of nodes in memory
+
+ chunk_base() noexcept = default;
+
+ chunk_base(unsigned char no) noexcept : capacity(no), no_nodes(no) {}
+ };
+
+ constexpr std::size_t chunk_memory_offset =
+ sizeof(chunk_base) % detail::max_alignment == 0 ?
+ sizeof(chunk_base) :
+ (sizeof(chunk_base) / detail::max_alignment + 1) * detail::max_alignment;
+ constexpr std::size_t chunk_max_nodes = UCHAR_MAX;
+
+ struct chunk;
+
+ // the same as free_memory_list but optimized for small node sizes
+ // it is slower and does not support arrays
+ // but has very small overhead
+ // debug: allocate() and deallocate() mark memory as new and freed, respectively
+ // node_size is increased via two times fence size and fence is put in front and after
+ class small_free_memory_list
+ {
+ static constexpr std::size_t chunk_count(std::size_t number_of_nodes)
+ {
+ return number_of_nodes / chunk_max_nodes
+ + (number_of_nodes % chunk_max_nodes == 0 ? 0 : 1);
+ }
+
+ public:
+ // minimum element size
+ static constexpr std::size_t min_element_size = 1;
+ // alignment
+ static constexpr std::size_t min_element_alignment = 1;
+
+ // minimal size of the block that needs to be inserted
+ static constexpr std::size_t min_block_size(std::size_t node_size,
+ std::size_t number_of_nodes)
+ {
+ return chunk_count(number_of_nodes)
+ * (chunk_memory_offset + chunk_max_nodes * node_size);
+ }
+
+ //=== constructor ===//
+ small_free_memory_list(std::size_t node_size) noexcept;
+
+ // does not own memory!
+ small_free_memory_list(std::size_t node_size, void* mem, std::size_t size) noexcept;
+
+ small_free_memory_list(small_free_memory_list&& other) noexcept;
+
+ ~small_free_memory_list() noexcept = default;
+
+ small_free_memory_list& operator=(small_free_memory_list&& other) noexcept
+ {
+ small_free_memory_list tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+
+ friend void swap(small_free_memory_list& a, small_free_memory_list& b) noexcept;
+
+ //=== insert/alloc/dealloc ===//
+ // inserts new memory of given size into the free list
+ // mem must be aligned for maximum alignment
+ void insert(void* mem, std::size_t size) noexcept;
+
+ // returns the usable size
+ // i.e. how many memory will be actually inserted and usable on a call to insert()
+ std::size_t usable_size(std::size_t size) const noexcept;
+
+ // allocates a node big enough for the node size
+ // pre: !empty()
+ void* allocate() noexcept;
+
+ // always returns nullptr, because array allocations are not supported
+ void* allocate(std::size_t) noexcept
+ {
+ return nullptr;
+ }
+
+ // deallocates the node previously allocated via allocate()
+ void deallocate(void* node) noexcept;
+
+ // forwards to insert()
+ void deallocate(void* mem, std::size_t size) noexcept
+ {
+ insert(mem, size);
+ }
+
+ // hint for allocate() to be prepared to allocate n nodes
+ // it searches for a chunk that has n nodes free
+ // returns false, if there is none like that
+ // never fails for n == 1 if not empty()
+ // pre: capacity() >= n * node_size()
+ bool find_chunk(std::size_t n) noexcept
+ {
+ return find_chunk_impl(n) != nullptr;
+ }
+
+ //=== getter ===//
+ std::size_t node_size() const noexcept
+ {
+ return node_size_;
+ }
+
+ // the alignment of all nodes
+ std::size_t alignment() const noexcept;
+
+ // number of nodes remaining
+ std::size_t capacity() const noexcept
+ {
+ return capacity_;
+ }
+
+ bool empty() const noexcept
+ {
+ return capacity_ == 0u;
+ }
+
+ private:
+ chunk* find_chunk_impl(std::size_t n = 1) noexcept;
+ chunk* find_chunk_impl(unsigned char* node, chunk_base* first,
+ chunk_base* last) noexcept;
+ chunk* find_chunk_impl(unsigned char* node) noexcept;
+
+ chunk_base base_;
+ std::size_t node_size_, capacity_;
+ chunk_base *alloc_chunk_, *dealloc_chunk_;
+ };
+
+ // for some reason, this is required in order to define it
+ void swap(small_free_memory_list& a, small_free_memory_list& b) noexcept;
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..c746fa2
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/detail/utility.hpp
@@ -0,0 +1,118 @@
+// 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.
+
+#ifndef WPI_MEMORY_DETAIL_UTILITY_HPP
+#define WPI_MEMORY_DETAIL_UTILITY_HPP
+
+// implementation of some functions from <utility> to prevent dependencies on it
+
+#include <type_traits>
+
+#include "../config.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <utility>
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ // move - taken from http://stackoverflow.com/a/7518365
+ template <typename T>
+ typename std::remove_reference<T>::type&& move(T&& arg) noexcept
+ {
+ return static_cast<typename std::remove_reference<T>::type&&>(arg);
+ }
+ // forward - taken from http://stackoverflow.com/a/27501759
+ template <class T>
+ T&& forward(typename std::remove_reference<T>::type& t) noexcept
+ {
+ return static_cast<T&&>(t);
+ }
+ template <class T>
+ T&& forward(typename std::remove_reference<T>::type&& t) noexcept
+ {
+ static_assert(!std::is_lvalue_reference<T>::value,
+ "Can not forward an rvalue as an lvalue.");
+ return static_cast<T&&>(t);
+ }
+
+ namespace swap_
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ using std::swap;
+#else
+ template <typename T>
+ void swap(T& a, T& b)
+ {
+ T tmp = move(a);
+ a = move(b);
+ b = move(tmp);
+ }
+#endif
+ } // namespace swap_
+
+ // ADL aware swap
+ template <typename T>
+ void adl_swap(T& a, T& b) noexcept
+ {
+ using swap_::swap;
+ swap(a, b);
+ }
+
+// fancier syntax for enable_if
+// used as (template) parameter
+// also useful for doxygen
+// define PREDEFINED: WPI_REQUIRES(x):=
+#define WPI_REQUIRES(Expr) typename std::enable_if<(Expr), int>::type = 0
+
+// same as above, but as return type
+// also useful for doxygen:
+// defined PREDEFINED: WPI_REQUIRES_RET(x,r):=r
+#define WPI_REQUIRES_RET(Expr, ...) typename std::enable_if<(Expr), __VA_ARGS__>::type
+
+// fancier syntax for enable_if on non-templated member function
+#define WPI_ENABLE_IF(Expr) \
+ template <typename Dummy = std::true_type, WPI_REQUIRES(Dummy::value && (Expr))>
+
+// fancier syntax for general expression SFINAE
+// used as (template) parameter
+// also useful for doxygen:
+// define PREDEFINED: WPI_SFINAE(x):=
+#define WPI_SFINAE(Expr) decltype((Expr), int()) = 0
+
+// avoids code repetition for one-line forwarding functions
+#define WPI_AUTO_RETURN(Expr) \
+ decltype(Expr) \
+ { \
+ return Expr; \
+ }
+
+// same as above, but requires certain type
+#define WPI_AUTO_RETURN_TYPE(Expr, T) \
+ decltype(Expr) \
+ { \
+ static_assert(std::is_same<decltype(Expr), T>::value, \
+ #Expr " does not have the return type " #T); \
+ return Expr; \
+ }
+
+ // whether or not a type is an instantiation of a template
+ template <template <typename...> class Template, typename T>
+ struct is_instantiation_of : std::false_type
+ {
+ };
+
+ template <template <typename...> class Template, typename... Args>
+ struct is_instantiation_of<Template, Template<Args...>> : std::true_type
+ {
+ };
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..5ff99cf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/error.hpp
@@ -0,0 +1,289 @@
+// 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.
+
+/// \file
+/// The exception classes.
+
+#ifndef WPI_MEMORY_ERROR_HPP_INCLUDED
+#define WPI_MEMORY_ERROR_HPP_INCLUDED
+
+#include <cstddef>
+#include <new>
+
+#include "config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// Contains information about an allocator.
+ /// It can be used for logging in the various handler functions.
+ /// \ingroup core
+ struct allocator_info
+ {
+ /// The name of the allocator.
+ /// It is a NTBS whose lifetime is not managed by this object,
+ /// it must be stored elsewhere or be a string literal.
+ const char* name;
+
+ /// A pointer representing an allocator.
+ /// It does not necessarily point to the beginning of the allocator object,
+ /// the only guarantee is that different allocator objects result in a different pointer value.
+ /// For stateless allocators it is sometimes \c nullptr.
+ /// \note The pointer must not be cast back to any allocator type.
+ const void* allocator;
+
+ /// \effects Creates it by giving it the name of the allocator and a pointer.
+ constexpr allocator_info(const char* n, const void* alloc) noexcept
+ : name(n), allocator(alloc)
+ {
+ }
+
+ /// @{
+ /// \effects Compares two \ref allocator_info objects, they are equal, if the \ref allocator is the same.
+ /// \returns The result of the comparision.
+ friend constexpr bool operator==(const allocator_info& a,
+ const allocator_info& b) noexcept
+ {
+ return a.allocator == b.allocator;
+ }
+
+ friend constexpr bool operator!=(const allocator_info& a,
+ const allocator_info& b) noexcept
+ {
+ return a.allocator != b.allocator;
+ }
+ /// @}
+ };
+
+ /// The exception class thrown when a low level allocator runs out of memory.
+ /// It is derived from \c std::bad_alloc.
+ /// This can happen if a low level allocation function like \c std::malloc() runs out of memory.
+ /// Throwing can be prohibited by the handler function.
+ /// \ingroup core
+ class out_of_memory : public std::bad_alloc
+ {
+ public:
+ /// The type of the handler called in the constructor of \ref out_of_memory.
+ /// When an out of memory situation is encountered and the exception class created,
+ /// this handler gets called.
+ /// It is especially useful if exception support is disabled.
+ /// It gets the \ref allocator_info and the amount of memory that was tried to be allocated.
+ /// \requiredbe It can log the error, throw a different exception derived from \c std::bad_alloc or abort the program.
+ /// If it returns, this exception object will be created and thrown.
+ /// \defaultbe On a hosted implementation it logs the error on \c stderr and continues execution,
+ /// leading to this exception being thrown.
+ /// On a freestanding implementation it does nothing.
+ /// \note It is different from \c std::new_handler; it will not be called in a loop trying to allocate memory
+ /// or something like that. Its only job is to report the error.
+ using handler = void (*)(const allocator_info& info, std::size_t amount);
+
+ /// \effects Sets \c h as the new \ref handler in an atomic operation.
+ /// A \c nullptr sets the default \ref handler.
+ /// \returns The previous \ref handler. This is never \c nullptr.
+ static handler set_handler(handler h);
+
+ /// \returns The current \ref handler. This is never \c nullptr.
+ static handler get_handler();
+
+ /// \effects Creates it by passing it the \ref allocator_info and the amount of memory failed to be allocated.
+ /// It also calls the \ref handler to control whether or not it will be thrown.
+ out_of_memory(const allocator_info& info, std::size_t amount);
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+
+ /// \returns The \ref allocator_info passed to it in the constructor.
+ const allocator_info& allocator() const noexcept
+ {
+ return info_;
+ }
+
+ /// \returns The amount of memory that was tried to be allocated.
+ /// This is the value passed in the constructor.
+ std::size_t failed_allocation_size() const noexcept
+ {
+ return amount_;
+ }
+
+ private:
+ allocator_info info_;
+ std::size_t amount_;
+ };
+
+ /// A special case of \ref out_of_memory errors
+ /// thrown when a low-level allocator with a fixed size runs out of memory.
+ /// For example, thrown by \ref fixed_block_allocator or \ref static_allocator.<br>
+ /// It is derived from \ref out_of_memory but does not provide its own handler.
+ /// \ingroup core
+ class out_of_fixed_memory : public out_of_memory
+ {
+ public:
+ /// \effects Just forwards to \ref out_of_memory.
+ out_of_fixed_memory(const allocator_info& info, std::size_t amount)
+ : out_of_memory(info, amount)
+ {
+ }
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+ };
+
+ /// The exception class thrown when an allocation size is bigger than the supported maximum.
+ /// This size is either the node, array or alignment parameter in a call to an allocation function.
+ /// If those exceed the supported maximum returned by \c max_node_size(), \c max_array_size() or \c max_alignment(),
+ /// one of its derived classes will be thrown or this class if in a situation where the type is unknown.
+ /// It is derived from \c std::bad_alloc.
+ /// Throwing can be prohibited by the handler function.
+ /// \note Even if all parameters are less than the maximum, \ref out_of_memory or a similar exception can be thrown,
+ /// because the maximum functions return an upper bound and not the actual supported maximum size,
+ /// since it always depends on fence memory, alignment buffer and the like.
+ /// \note A user should only \c catch for \c bad_allocation_size, not the derived classes.
+ /// \note Most checks will only be done if \ref WPI_MEMORY_CHECK_ALLOCATION_SIZE is \c true.
+ /// \ingroup core
+ class bad_allocation_size : public std::bad_alloc
+ {
+ public:
+ /// The type of the handler called in the constructor of \ref bad_allocation_size.
+ /// When a bad allocation size is detected and the exception object created,
+ /// this handler gets called.
+ /// It is especially useful if exception support is disabled.
+ /// It gets the \ref allocator_info, the size passed to the function and the supported size
+ /// (the latter is still an upper bound).
+ /// \requiredbe It can log the error, throw a different exception derived from \c std::bad_alloc or abort the program.
+ /// If it returns, this exception object will be created and thrown.
+ /// \defaultbe On a hosted implementation it logs the error on \c stderr and continues execution,
+ /// leading to this exception being thrown.
+ /// On a freestanding implementation it does nothing.
+ using handler = void (*)(const allocator_info& info, std::size_t passed,
+ std::size_t supported);
+
+ /// \effects Sets \c h as the new \ref handler in an atomic operation.
+ /// A \c nullptr sets the default \ref handler.
+ /// \returns The previous \ref handler. This is never \c nullptr.
+ static handler set_handler(handler h);
+
+ /// \returns The current \ref handler. This is never \c nullptr.
+ static handler get_handler();
+
+ /// \effects Creates it by passing it the \ref allocator_info, the size passed to the allocation function
+ /// and an upper bound on the supported size.
+ /// It also calls the \ref handler to control whether or not it will be thrown.
+ bad_allocation_size(const allocator_info& info, std::size_t passed,
+ std::size_t supported);
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+
+ /// \returns The \ref allocator_info passed to it in the constructor.
+ const allocator_info& allocator() const noexcept
+ {
+ return info_;
+ }
+
+ /// \returns The size or alignment value that was passed to the allocation function
+ /// which was too big. This is the same value passed to the constructor.
+ std::size_t passed_value() const noexcept
+ {
+ return passed_;
+ }
+
+ /// \returns An upper bound on the maximum supported size/alignment.
+ /// It is only an upper bound, values below can fail, but values above will always fail.
+ std::size_t supported_value() const noexcept
+ {
+ return supported_;
+ }
+
+ private:
+ allocator_info info_;
+ std::size_t passed_, supported_;
+ };
+
+ /// The exception class thrown when the node size exceeds the supported maximum,
+ /// i.e. it is bigger than \c max_node_size().
+ /// It is derived from \ref bad_allocation_size but does not override the handler.
+ /// \ingroup core
+ class bad_node_size : public bad_allocation_size
+ {
+ public:
+ /// \effects Just forwards to \ref bad_allocation_size.
+ bad_node_size(const allocator_info& info, std::size_t passed, std::size_t supported)
+ : bad_allocation_size(info, passed, supported)
+ {
+ }
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+ };
+
+ /// The exception class thrown when the array size exceeds the supported maximum,
+ /// i.e. it is bigger than \c max_array_size().
+ /// It is derived from \ref bad_allocation_size but does not override the handler.
+ /// \ingroup core
+ class bad_array_size : public bad_allocation_size
+ {
+ public:
+ /// \effects Just forwards to \ref bad_allocation_size.
+ bad_array_size(const allocator_info& info, std::size_t passed, std::size_t supported)
+ : bad_allocation_size(info, passed, supported)
+ {
+ }
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+ };
+
+ /// The exception class thrown when the alignment exceeds the supported maximum,
+ /// i.e. it is bigger than \c max_alignment().
+ /// It is derived from \ref bad_allocation_size but does not override the handler.
+ /// \ingroup core
+ class bad_alignment : public bad_allocation_size
+ {
+ public:
+ /// \effects Just forwards to \ref bad_allocation_size.
+ /// \c passed is <tt>count * size</tt>, \c supported the size in bytes.
+ bad_alignment(const allocator_info& info, std::size_t passed, std::size_t supported)
+ : bad_allocation_size(info, passed, supported)
+ {
+ }
+
+ /// \returns A static NTBS that describes the error.
+ /// It does not contain any specific information since there is no memory for formatting.
+ const char* what() const noexcept override;
+ };
+
+ namespace detail
+ {
+ template <class Ex, typename Func>
+ void check_allocation_size(std::size_t passed, Func f, const allocator_info& info)
+ {
+#if WPI_MEMORY_CHECK_ALLOCATION_SIZE
+ auto supported = f();
+ if (passed > supported)
+ WPI_THROW(Ex(info, passed, supported));
+#else
+ (void)passed;
+ (void)f;
+ (void)info;
+#endif
+ }
+
+ template <class Ex>
+ void check_allocation_size(std::size_t passed, std::size_t supported,
+ const allocator_info& info)
+ {
+ check_allocation_size<Ex>(
+ passed, [&] { return supported; }, info);
+ }
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_ERROR_HPP_INCLUDED
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
new file mode 100644
index 0000000..3bf530e
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/fallback_allocator.hpp
@@ -0,0 +1,212 @@
+// 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.
+
+#ifndef WPI_MEMORY_FALLBACK_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_FALLBACK_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+//// Class template \ref wpi::memory::fallback_allocator.
+
+#include "detail/ebo_storage.hpp"
+#include "detail/utility.hpp"
+#include "allocator_traits.hpp"
+#include "config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A \concept{raw_allocator,RawAllocator} with a fallback.
+ /// Allocation first tries `Default`, if it fails,
+ /// it uses `Fallback`.
+ /// \requires `Default` must be a composable \concept{concept_rawallocator,RawAllocator},
+ /// `Fallback` must be a \concept{concept_rawallocator,RawAllocator}.
+ /// \ingroup adapter
+ template <class Default, class Fallback>
+ class fallback_allocator
+ : WPI_EBO(detail::ebo_storage<0, typename allocator_traits<Default>::allocator_type>),
+ WPI_EBO(detail::ebo_storage<1, typename allocator_traits<Fallback>::allocator_type>)
+ {
+ using default_traits = allocator_traits<Default>;
+ using default_composable_traits = composable_allocator_traits<Default>;
+ using fallback_traits = allocator_traits<Fallback>;
+ using fallback_composable_traits = composable_allocator_traits<Fallback>;
+ using fallback_composable =
+ is_composable_allocator<typename fallback_traits::allocator_type>;
+
+ public:
+ using default_allocator_type = typename allocator_traits<Default>::allocator_type;
+ using fallback_allocator_type = typename allocator_traits<Fallback>::allocator_type;
+
+ using is_stateful =
+ std::integral_constant<bool, default_traits::is_stateful::value
+ || fallback_traits::is_stateful::value>;
+
+ /// \effects Default constructs both allocators.
+ /// \notes This function only participates in overload resolution, if both allocators are not stateful.
+ WPI_ENABLE_IF(!is_stateful::value)
+ fallback_allocator()
+ : detail::ebo_storage<0, default_allocator_type>({}),
+ detail::ebo_storage<1, fallback_allocator_type>({})
+ {
+ }
+
+ /// \effects Constructs the allocator by passing in the two allocators it has.
+ explicit fallback_allocator(default_allocator_type&& default_alloc,
+ fallback_allocator_type&& fallback_alloc = {})
+ : detail::ebo_storage<0, default_allocator_type>(detail::move(default_alloc)),
+ detail::ebo_storage<1, fallback_allocator_type>(detail::move(fallback_alloc))
+ {
+ }
+
+ /// @{
+ /// \effects First calls the compositioning (de)allocation function on the `default_allocator_type`.
+ /// If that fails, uses the non-compositioning function of the `fallback_allocator_type`.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ auto ptr = default_composable_traits::try_allocate_node(get_default_allocator(),
+ size, alignment);
+ if (!ptr)
+ ptr = fallback_traits::allocate_node(get_fallback_allocator(), size, alignment);
+ return ptr;
+ }
+
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ auto ptr = default_composable_traits::try_allocate_array(get_default_allocator(),
+ count, size, alignment);
+ if (!ptr)
+ ptr = fallback_traits::allocate_array(get_fallback_allocator(), count, size,
+ alignment);
+ return ptr;
+ }
+
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ auto res = default_composable_traits::try_deallocate_node(get_default_allocator(),
+ ptr, size, alignment);
+ if (!res)
+ fallback_traits::deallocate_node(get_fallback_allocator(), ptr, size,
+ alignment);
+ }
+
+ void deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ auto res =
+ default_composable_traits::try_deallocate_array(get_default_allocator(), ptr,
+ count, size, alignment);
+ if (!res)
+ fallback_traits::deallocate_array(get_fallback_allocator(), ptr, count, size,
+ alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \effects First calls the compositioning (de)allocation function on the `default_allocator_type`.
+ /// If that fails, uses the compositioning function of the `fallback_allocator_type`.
+ /// \requires The `fallback_allocator_type` msut be composable.
+ WPI_ENABLE_IF(fallback_composable::value)
+ void* try_allocate_node(std::size_t size, std::size_t alignment) noexcept
+ {
+ auto ptr = default_composable_traits::try_allocate_node(get_default_allocator(),
+ size, alignment);
+ if (!ptr)
+ ptr = fallback_composable_traits::try_allocate_node(get_fallback_allocator(),
+ size, alignment);
+ return ptr;
+ }
+
+ WPI_ENABLE_IF(fallback_composable::value)
+ void* allocate_array(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ auto ptr = default_composable_traits::try_allocate_array(get_default_allocator(),
+ count, size, alignment);
+ if (!ptr)
+ ptr = fallback_composable_traits::try_allocate_array(get_fallback_allocator(),
+ count, size, alignment);
+ return ptr;
+ }
+
+ WPI_ENABLE_IF(fallback_composable::value)
+ bool try_deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ auto res = default_composable_traits::try_deallocate_node(get_default_allocator(),
+ ptr, size, alignment);
+ if (!res)
+ res = fallback_composable_traits::try_deallocate_node(get_fallback_allocator(),
+ ptr, size, alignment);
+ return res;
+ }
+
+ WPI_ENABLE_IF(fallback_composable::value)
+ bool try_deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ auto res =
+ default_composable_traits::try_deallocate_array(get_default_allocator(), ptr,
+ count, size, alignment);
+ if (!res)
+ res = fallback_composable_traits::try_deallocate_array(get_fallback_allocator(),
+ ptr, count, size,
+ alignment);
+ return res;
+ }
+ /// @}
+
+ /// @{
+ /// \returns The maximum of the two values from both allocators.
+ std::size_t max_node_size() const
+ {
+ auto def = default_traits::max_node_size(get_default_allocator());
+ auto fallback = fallback_traits::max_node_size(get_fallback_allocator());
+ return fallback > def ? fallback : def;
+ }
+
+ std::size_t max_array_size() const
+ {
+ auto def = default_traits::max_array_size(get_default_allocator());
+ auto fallback = fallback_traits::max_array_size(get_fallback_allocator());
+ return fallback > def ? fallback : def;
+ }
+
+ std::size_t max_alignment() const
+ {
+ auto def = default_traits::max_alignment(get_default_allocator());
+ auto fallback = fallback_traits::max_alignment(get_fallback_allocator());
+ return fallback > def ? fallback : def;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (`const`) reference to the default allocator.
+ default_allocator_type& get_default_allocator() noexcept
+ {
+ return detail::ebo_storage<0, default_allocator_type>::get();
+ }
+
+ const default_allocator_type& get_default_allocator() const noexcept
+ {
+ return detail::ebo_storage<0, default_allocator_type>::get();
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (`const`) reference to the fallback allocator.
+ fallback_allocator_type& get_fallback_allocator() noexcept
+ {
+ return detail::ebo_storage<1, fallback_allocator_type>::get();
+ }
+
+ const fallback_allocator_type& get_fallback_allocator() const noexcept
+ {
+ return detail::ebo_storage<1, fallback_allocator_type>::get();
+ }
+ /// @}
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..0724937
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/heap_allocator.hpp
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef WPI_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_HEAP_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::heap_allocator and related functions.
+
+#include "detail/lowlevel_allocator.hpp"
+#include "config.hpp"
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+#include "allocator_traits.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ struct allocator_info;
+
+ /// Allocates heap memory.
+ /// This function is used by the \ref heap_allocator to allocate the heap memory.
+ /// It is not defined on a freestanding implementation, a definition must be provided by the library user.
+ /// \requiredbe This function shall return a block of uninitialized memory that is aligned for \c max_align_t and has the given size.
+ /// The size parameter will not be zero.
+ /// It shall return a \c nullptr if no memory is available.
+ /// It must be thread safe.
+ /// \defaultbe On a hosted implementation this function uses OS specific facilities, \c std::malloc is used as fallback.
+ /// \ingroup allocator
+ void* heap_alloc(std::size_t size) noexcept;
+
+ /// Deallocates heap memory.
+ /// This function is used by the \ref heap_allocator to allocate the heap memory.
+ /// It is not defined on a freestanding implementation, a definition must be provided by the library user.
+ /// \requiredbe This function gets a pointer from a previous call to \ref heap_alloc with the same size.
+ /// It shall free the memory.
+ /// The pointer will not be zero.
+ /// It must be thread safe.
+ /// \defaultbe On a hosted implementation this function uses OS specific facilities, \c std::free is used as fallback.
+ /// \ingroup allocator
+ void heap_dealloc(void* ptr, std::size_t size) noexcept;
+
+ namespace detail
+ {
+ struct heap_allocator_impl
+ {
+ static allocator_info info() noexcept;
+
+ static void* allocate(std::size_t size, std::size_t) noexcept
+ {
+ return heap_alloc(size);
+ }
+
+ static void deallocate(void* ptr, std::size_t size, std::size_t) noexcept
+ {
+ heap_dealloc(ptr, size);
+ }
+
+ static std::size_t max_node_size() noexcept;
+ };
+
+ WPI_MEMORY_LL_ALLOCATOR_LEAK_CHECKER(heap_allocator_impl,
+ heap_alloator_leak_checker)
+ } // namespace detail
+
+ /// A stateless \concept{concept_rawallocator,RawAllocator} that allocates memory from the heap.
+ /// It uses the two functions \ref heap_alloc and \ref heap_dealloc for the allocation,
+ /// which default to \c std::malloc and \c std::free.
+ /// \ingroup allocator
+ using heap_allocator =
+ WPI_IMPL_DEFINED(detail::lowlevel_allocator<detail::heap_allocator_impl>);
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class detail::lowlevel_allocator<detail::heap_allocator_impl>;
+ extern template class allocator_traits<heap_allocator>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..d35a927
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/iteration_allocator.hpp
@@ -0,0 +1,305 @@
+// 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.
+
+#ifndef WPI_MEMORY_ITERATION_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_ITERATION_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class template \ref wpi::memory::iteration_allocator.
+
+#include "detail/debug_helpers.hpp"
+#include "detail/memory_stack.hpp"
+#include "default_allocator.hpp"
+#include "error.hpp"
+#include "memory_arena.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <class BlockOrRawAllocator>
+ using iteration_block_allocator =
+ make_block_allocator_t<BlockOrRawAllocator, fixed_block_allocator>;
+ } // namespace detail
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that is designed for allocations in a loop.
+ /// It uses `N` stacks for the allocation, one of them is always active.
+ /// Allocation uses the currently active stack.
+ /// Calling \ref iteration_allocator::next_iteration() at the end of the loop,
+ /// will make the next stack active for allocation,
+ /// effectively releasing all of its memory.
+ /// Any memory allocated will thus be usable for `N` iterations of the loop.
+ /// This type of allocator is a generalization of the double frame allocator.
+ /// \ingroup allocator
+ template <std::size_t N, class BlockOrRawAllocator = default_allocator>
+ class iteration_allocator
+ : WPI_EBO(detail::iteration_block_allocator<BlockOrRawAllocator>)
+ {
+ public:
+ using allocator_type = detail::iteration_block_allocator<BlockOrRawAllocator>;
+
+ /// \effects Creates it with a given initial block size and and other constructor arguments for the \concept{concept_blockallocator,BlockAllocator}.
+ /// It will allocate the first (and only) block and evenly divide it on all the stacks it uses.
+ template <typename... Args>
+ explicit iteration_allocator(std::size_t block_size, Args&&... args)
+ : allocator_type(block_size, detail::forward<Args>(args)...), cur_(0u)
+ {
+ block_ = get_allocator().allocate_block();
+ auto cur = static_cast<char*>(block_.memory);
+ auto size_each = block_.size / N;
+ for (auto i = 0u; i != N; ++i)
+ {
+ stacks_[i] = detail::fixed_memory_stack(cur);
+ cur += size_each;
+ }
+ }
+
+ iteration_allocator(iteration_allocator&& other) noexcept
+ : allocator_type(detail::move(other)),
+ block_(other.block_),
+ cur_(detail::move(other.cur_))
+ {
+ for (auto i = 0u; i != N; ++i)
+ stacks_[i] = detail::move(other.stacks_[i]);
+
+ other.cur_ = N;
+ }
+
+ ~iteration_allocator() noexcept
+ {
+ if (cur_ < N)
+ get_allocator().deallocate_block(block_);
+ }
+
+ iteration_allocator& operator=(iteration_allocator&& other) noexcept
+ {
+ allocator_type::operator=(detail::move(other));
+ block_ = other.block_;
+ cur_ = other.cur_;
+
+ for (auto i = 0u; i != N; ++i)
+ stacks_[i] = detail::move(other.stacks_[i]);
+
+ other.cur_ = N;
+
+ return *this;
+ }
+
+ /// \effects Allocates a memory block of given size and alignment.
+ /// It simply moves the top marker of the currently active stack.
+ /// \returns A \concept{concept_node,node} with given size and alignment.
+ /// \throws \ref out_of_fixed_memory if the current stack does not have any memory left.
+ /// \requires \c size and \c alignment must be valid.
+ void* allocate(std::size_t size, std::size_t alignment)
+ {
+ auto& stack = stacks_[cur_];
+
+ auto fence = detail::debug_fence_size;
+ auto offset = detail::align_offset(stack.top() + fence, alignment);
+ if (!stack.top()
+ || (fence + offset + size + fence > std::size_t(block_end(cur_) - stack.top())))
+ WPI_THROW(out_of_fixed_memory(info(), size));
+ return stack.allocate_unchecked(size, offset);
+ }
+
+ /// \effects Allocates a memory block of given size and alignment
+ /// similar to \ref allocate().
+ /// \returns A \concept{concept_node,node} with given size and alignment
+ /// or `nullptr` if the current stack does not have any memory left.
+ void* try_allocate(std::size_t size, std::size_t alignment) noexcept
+ {
+ auto& stack = stacks_[cur_];
+ return stack.allocate(block_end(cur_), size, alignment);
+ }
+
+ /// \effects Goes to the next internal stack.
+ /// This will clear the stack whose \ref max_iterations() lifetime has reached,
+ /// and use it for all allocations in this iteration.
+ /// \note This function should be called at the end of the loop.
+ void next_iteration() noexcept
+ {
+ WPI_MEMORY_ASSERT_MSG(cur_ != N, "moved-from allocator");
+ cur_ = (cur_ + 1) % N;
+ stacks_[cur_].unwind(block_start(cur_));
+ }
+
+ /// \returns The number of iteration each allocation will live.
+ /// This is the template parameter `N`.
+ static std::size_t max_iterations() noexcept
+ {
+ return N;
+ }
+
+ /// \returns The index of the current iteration.
+ /// This is modulo \ref max_iterations().
+ std::size_t cur_iteration() const noexcept
+ {
+ return cur_;
+ }
+
+ /// \returns A reference to the \concept{concept_blockallocator,BlockAllocator} used for managing the memory.
+ /// \requires It is undefined behavior to move this allocator out into another object.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ /// \returns The amount of memory remaining in the stack with the given index.
+ /// This is the number of bytes that are available for allocation.
+ std::size_t capacity_left(std::size_t i) const noexcept
+ {
+ return std::size_t(block_end(i) - stacks_[i].top());
+ }
+
+ /// \returns The amount of memory remaining in the currently active stack.
+ std::size_t capacity_left() const noexcept
+ {
+ return capacity_left(cur_iteration());
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::iteration_allocator", this};
+ }
+
+ char* block_start(std::size_t i) const noexcept
+ {
+ WPI_MEMORY_ASSERT_MSG(i <= N, "moved from state");
+ auto ptr = static_cast<char*>(block_.memory);
+ return ptr + (i * block_.size / N);
+ }
+
+ char* block_end(std::size_t i) const noexcept
+ {
+ WPI_MEMORY_ASSERT_MSG(i < N, "moved from state");
+ return block_start(i + 1);
+ }
+
+ detail::fixed_memory_stack stacks_[N];
+ memory_block block_;
+ std::size_t cur_;
+
+ friend allocator_traits<iteration_allocator<N, BlockOrRawAllocator>>;
+ friend composable_allocator_traits<iteration_allocator<N, BlockOrRawAllocator>>;
+ };
+
+ /// An alias for \ref iteration_allocator for two iterations.
+ /// \ingroup allocator
+ template <class BlockOrRawAllocator = default_allocator>
+ WPI_ALIAS_TEMPLATE(double_frame_allocator,
+ iteration_allocator<2, BlockOrRawAllocator>);
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class iteration_allocator<2>;
+#endif
+
+ /// Specialization of the \ref allocator_traits for \ref iteration_allocator.
+ /// \note It is not allowed to mix calls through the specialization and through the member functions,
+ /// i.e. \ref memory_stack::allocate() and this \c allocate_node().
+ /// \ingroup allocator
+ template <std::size_t N, class BlockAllocator>
+ class allocator_traits<iteration_allocator<N, BlockAllocator>>
+ {
+ public:
+ using allocator_type = iteration_allocator<N, BlockAllocator>;
+ using is_stateful = std::true_type;
+
+ /// \returns The result of \ref iteration_allocator::allocate().
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ return state.allocate(size, alignment);
+ }
+
+ /// \returns The result of \ref memory_stack::allocate().
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ return allocate_node(state, count * size, alignment);
+ }
+
+ /// @{
+ /// \effects Does nothing.
+ /// Actual deallocation can only be done via \ref memory_stack::unwind().
+ static void deallocate_node(allocator_type&, void*, std::size_t, std::size_t) noexcept
+ {
+ }
+
+ static void deallocate_array(allocator_type&, void*, std::size_t, std::size_t,
+ std::size_t) noexcept
+ {
+ }
+ /// @}
+
+ /// @{
+ /// \returns The maximum size which is \ref iteration_allocator::capacity_left().
+ static std::size_t max_node_size(const allocator_type& state) noexcept
+ {
+ return state.capacity_left();
+ }
+
+ static std::size_t max_array_size(const allocator_type& state) noexcept
+ {
+ return state.capacity_left();
+ }
+ /// @}
+
+ /// \returns The maximum possible value since there is no alignment restriction
+ /// (except indirectly through \ref memory_stack::next_capacity()).
+ static std::size_t max_alignment(const allocator_type&) noexcept
+ {
+ return std::size_t(-1);
+ }
+ };
+
+ /// Specialization of the \ref composable_allocator_traits for \ref iteration_allocator classes.
+ /// \ingroup allocator
+ template <std::size_t N, class BlockAllocator>
+ class composable_allocator_traits<iteration_allocator<N, BlockAllocator>>
+ {
+ public:
+ using allocator_type = iteration_allocator<N, BlockAllocator>;
+
+ /// \returns The result of \ref memory_stack::try_allocate().
+ static void* try_allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return state.try_allocate(size, alignment);
+ }
+
+ /// \returns The result of \ref memory_stack::try_allocate().
+ static void* try_allocate_array(allocator_type& state, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return state.try_allocate(count * size, alignment);
+ }
+
+ /// @{
+ /// \effects Does nothing.
+ /// \returns Whether the memory will be deallocated by \ref memory_stack::unwind().
+ static bool try_deallocate_node(allocator_type& state, void* ptr, std::size_t,
+ std::size_t) noexcept
+ {
+ return state.block_.contains(ptr);
+ }
+
+ static bool try_deallocate_array(allocator_type& state, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return try_deallocate_node(state, ptr, count * size, alignment);
+ }
+ /// @}
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<iteration_allocator<2>>;
+ extern template class composable_allocator_traits<iteration_allocator<2>>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_ITERATION_ALLOCATOR_HPP_INCLUDED
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
new file mode 100644
index 0000000..db67d46
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/joint_allocator.hpp
@@ -0,0 +1,927 @@
+// 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.
+
+#ifndef WPI_MEMORY_JOINT_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_JOINT_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class template \ref wpi::memory::joint_ptr, \ref wpi::memory::joint_allocator and related.
+
+#include <initializer_list>
+#include <new>
+
+#include "detail/align.hpp"
+#include "detail/memory_stack.hpp"
+#include "detail/utility.hpp"
+#include "allocator_storage.hpp"
+#include "config.hpp"
+#include "default_allocator.hpp"
+#include "error.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ template <typename T, class RawAllocator>
+ class joint_ptr;
+
+ template <typename T>
+ class joint_type;
+
+ namespace detail
+ {
+ // the stack that allocates the joint memory
+ class joint_stack
+ {
+ public:
+ joint_stack(void* mem, std::size_t cap) noexcept
+ : stack_(static_cast<char*>(mem)), end_(static_cast<char*>(mem) + cap)
+ {
+ }
+
+ void* allocate(std::size_t size, std::size_t alignment) noexcept
+ {
+ return stack_.allocate(end_, size, alignment, 0u);
+ }
+
+ bool bump(std::size_t offset) noexcept
+ {
+ if (offset > std::size_t(end_ - stack_.top()))
+ return false;
+ stack_.bump(offset);
+ return true;
+ }
+
+ char* top() noexcept
+ {
+ return stack_.top();
+ }
+
+ const char* top() const noexcept
+ {
+ return stack_.top();
+ }
+
+ void unwind(void* ptr) noexcept
+ {
+ stack_.unwind(static_cast<char*>(ptr));
+ }
+
+ std::size_t capacity(const char* mem) const noexcept
+ {
+ return std::size_t(end_ - mem);
+ }
+
+ std::size_t capacity_left() const noexcept
+ {
+ return std::size_t(end_ - top());
+ }
+
+ std::size_t capacity_used(const char* mem) const noexcept
+ {
+ return std::size_t(top() - mem);
+ }
+
+ private:
+ detail::fixed_memory_stack stack_;
+ char* end_;
+ };
+
+ template <typename T>
+ detail::joint_stack& get_stack(joint_type<T>& obj) noexcept;
+
+ template <typename T>
+ const detail::joint_stack& get_stack(const joint_type<T>& obj) noexcept;
+ } // namespace detail
+
+ /// Tag type that can't be created.
+ ///
+ /// It isued by \ref joint_ptr.
+ /// \ingroup allocator
+ class joint
+ {
+ joint(std::size_t cap) noexcept : capacity(cap) {}
+
+ std::size_t capacity;
+
+ template <typename T, class RawAllocator>
+ friend class joint_ptr;
+ template <typename T>
+ friend class joint_type;
+ };
+
+ /// Tag type to make the joint size more explicit.
+ ///
+ /// It is used by \ref joint_ptr.
+ /// \ingroup allocator
+ struct joint_size
+ {
+ std::size_t size;
+
+ explicit joint_size(std::size_t s) noexcept : size(s) {}
+ };
+
+ /// CRTP base class for all objects that want to use joint memory.
+ ///
+ /// This will disable default copy/move operations
+ /// and inserts additional members for the joint memory management.
+ /// \ingroup allocator
+ template <typename T>
+ class joint_type
+ {
+ protected:
+ /// \effects Creates the base class,
+ /// the tag type cannot be created by the user.
+ /// \note This ensures that you cannot create joint types yourself.
+ joint_type(joint j) noexcept;
+
+ joint_type(const joint_type&) = delete;
+ joint_type(joint_type&&) = delete;
+
+ private:
+ detail::joint_stack stack_;
+
+ template <typename U>
+ friend detail::joint_stack& detail::get_stack(joint_type<U>& obj) noexcept;
+ template <typename U>
+ friend const detail::joint_stack& detail::get_stack(const joint_type<U>& obj) noexcept;
+ };
+
+ namespace detail
+ {
+ template <typename T>
+ detail::joint_stack& get_stack(joint_type<T>& obj) noexcept
+ {
+ return obj.stack_;
+ }
+
+ template <typename T>
+ const detail::joint_stack& get_stack(const joint_type<T>& obj) noexcept
+ {
+ return obj.stack_;
+ }
+
+ template <typename T>
+ char* get_memory(joint_type<T>& obj) noexcept
+ {
+ auto mem = static_cast<void*>(&obj);
+ return static_cast<char*>(mem) + sizeof(T);
+ }
+
+ template <typename T>
+ const char* get_memory(const joint_type<T>& obj) noexcept
+ {
+ auto mem = static_cast<const void*>(&obj);
+ return static_cast<const char*>(mem) + sizeof(T);
+ }
+
+ } // namespace detail
+
+ template <typename T>
+ joint_type<T>::joint_type(joint j) noexcept : stack_(detail::get_memory(*this), j.capacity)
+ {
+ WPI_MEMORY_ASSERT(stack_.top() == detail::get_memory(*this));
+ WPI_MEMORY_ASSERT(stack_.capacity_left() == j.capacity);
+ }
+
+ /// A pointer to an object where all allocations are joint.
+ ///
+ /// It can either own an object or not (be `nullptr`).
+ /// When it owns an object, it points to a memory block.
+ /// This memory block contains both the actual object (of the type `T`)
+ /// and space for allocations of `T`s members.
+ ///
+ /// The type `T` must be derived from \ref joint_type and every constructor must take \ref joint
+ /// as first parameter.
+ /// This prevents that you create joint objects yourself,
+ /// without the additional storage.
+ /// The default copy and move constructors are also deleted,
+ /// you need to write them yourself.
+ ///
+ /// You can only access the object through the pointer,
+ /// use \ref joint_allocator or \ref joint_array as members of `T`,
+ /// to enable the memory sharing.
+ /// If you are using \ref joint_allocator inside STL containers,
+ /// make sure that you do not call their regular copy/move constructors,
+ /// but instead the version where you pass an allocator.
+ ///
+ /// The memory block will be managed by the given \concept{concept_rawallocator,RawAllocator},
+ /// it is stored in an \ref allocator_reference and not owned by the pointer directly.
+ /// \ingroup allocator
+ template <typename T, class RawAllocator>
+ class joint_ptr : WPI_EBO(allocator_reference<RawAllocator>)
+ {
+ static_assert(std::is_base_of<joint_type<T>, T>::value,
+ "T must be derived of joint_type<T>");
+
+ public:
+ using element_type = T;
+ using allocator_type = typename allocator_reference<RawAllocator>::allocator_type;
+
+ //=== constructors/destructor/assignment ===//
+ /// @{
+ /// \effects Creates it with a \concept{concept_rawallocator,RawAllocator}, but does not own a new object.
+ explicit joint_ptr(allocator_type& alloc) noexcept
+ : allocator_reference<RawAllocator>(alloc), ptr_(nullptr)
+ {
+ }
+
+ explicit joint_ptr(const allocator_type& alloc) noexcept
+ : allocator_reference<RawAllocator>(alloc), ptr_(nullptr)
+ {
+ }
+ /// @}
+
+ /// @{
+ /// \effects Reserves memory for the object and the additional size,
+ /// and creates the object by forwarding the arguments to its constructor.
+ /// The \concept{concept_rawallocator,RawAllocator} will be used for the allocation.
+ template <typename... Args>
+ joint_ptr(allocator_type& alloc, joint_size additional_size, Args&&... args)
+ : joint_ptr(alloc)
+ {
+ create(additional_size.size, detail::forward<Args>(args)...);
+ }
+
+ template <typename... Args>
+ joint_ptr(const allocator_type& alloc, joint_size additional_size, Args&&... args)
+ : joint_ptr(alloc)
+ {
+ create(additional_size.size, detail::forward<Args>(args)...);
+ }
+ /// @}
+
+ /// \effects Move-constructs the pointer.
+ /// Ownership will be transferred from `other` to the new object.
+ joint_ptr(joint_ptr&& other) noexcept
+ : allocator_reference<RawAllocator>(detail::move(other)), ptr_(other.ptr_)
+ {
+ other.ptr_ = nullptr;
+ }
+
+ /// \effects Destroys the object and deallocates its storage.
+ ~joint_ptr() noexcept
+ {
+ reset();
+ }
+
+ /// \effects Move-assings the pointer.
+ /// The previously owned object will be destroyed,
+ /// and ownership of `other` transferred.
+ joint_ptr& operator=(joint_ptr&& other) noexcept
+ {
+ joint_ptr tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+
+ /// \effects Same as `reset()`.
+ joint_ptr& operator=(std::nullptr_t) noexcept
+ {
+ reset();
+ return *this;
+ }
+
+ /// \effects Swaps to pointers and their ownership and allocator.
+ friend void swap(joint_ptr& a, joint_ptr& b) noexcept
+ {
+ detail::adl_swap(static_cast<allocator_reference<RawAllocator>&>(a),
+ static_cast<allocator_reference<RawAllocator>&>(b));
+ detail::adl_swap(a.ptr_, b.ptr_);
+ }
+
+ //=== modifiers ===//
+ /// \effects Destroys the object it refers to,
+ /// if there is any.
+ void reset() noexcept
+ {
+ if (ptr_)
+ {
+ (**this).~element_type();
+ this->deallocate_node(ptr_,
+ sizeof(element_type)
+ + detail::get_stack(*ptr_).capacity(
+ detail::get_memory(*ptr_)),
+ alignof(element_type));
+ ptr_ = nullptr;
+ }
+ }
+
+ //=== accessors ===//
+ /// \returns `true` if the pointer does own an object,
+ /// `false` otherwise.
+ explicit operator bool() const noexcept
+ {
+ return ptr_ != nullptr;
+ }
+
+ /// \returns A reference to the object it owns.
+ /// \requires The pointer must own an object,
+ /// i.e. `operator bool()` must return `true`.
+ element_type& operator*() const noexcept
+ {
+ WPI_MEMORY_ASSERT(ptr_);
+ return *get();
+ }
+
+ /// \returns A pointer to the object it owns.
+ /// \requires The pointer must own an object,
+ /// i.e. `operator bool()` must return `true`.
+ element_type* operator->() const noexcept
+ {
+ WPI_MEMORY_ASSERT(ptr_);
+ return get();
+ }
+
+ /// \returns A pointer to the object it owns
+ /// or `nullptr`, if it does not own any object.
+ element_type* get() const noexcept
+ {
+ return static_cast<element_type*>(ptr_);
+ }
+
+ /// \returns A reference to the allocator it will use for the deallocation.
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<allocator_reference<allocator_type>>().get_allocator())
+ {
+ return this->allocator_reference<allocator_type>::get_allocator();
+ }
+
+ private:
+ template <typename... Args>
+ void create(std::size_t additional_size, Args&&... args)
+ {
+ auto mem = this->allocate_node(sizeof(element_type) + additional_size,
+ alignof(element_type));
+
+ element_type* ptr = nullptr;
+#if WPI_HAS_EXCEPTION_SUPPORT
+ try
+ {
+ ptr = ::new (mem)
+ element_type(joint(additional_size), detail::forward<Args>(args)...);
+ }
+ catch (...)
+ {
+ this->deallocate_node(mem, sizeof(element_type) + additional_size,
+ alignof(element_type));
+ throw;
+ }
+#else
+ ptr = ::new (mem)
+ element_type(joint(additional_size), detail::forward<Args>(args)...);
+#endif
+ ptr_ = ptr;
+ }
+
+ joint_type<T>* ptr_;
+
+ friend class joint_allocator;
+ };
+
+ /// @{
+ /// \returns `!ptr`,
+ /// i.e. if `ptr` does not own anything.
+ /// \relates joint_ptr
+ template <typename T, class RawAllocator>
+ bool operator==(const joint_ptr<T, RawAllocator>& ptr, std::nullptr_t)
+ {
+ return !ptr;
+ }
+
+ template <typename T, class RawAllocator>
+ bool operator==(std::nullptr_t, const joint_ptr<T, RawAllocator>& ptr)
+ {
+ return ptr == nullptr;
+ }
+ /// @}
+
+ /// @{
+ /// \returns `ptr.get() == p`,
+ /// i.e. if `ptr` ownws the object referred to by `p`.
+ /// \relates joint_ptr
+ template <typename T, class RawAllocator>
+ bool operator==(const joint_ptr<T, RawAllocator>& ptr, T* p)
+ {
+ return ptr.get() == p;
+ }
+
+ template <typename T, class RawAllocator>
+ bool operator==(T* p, const joint_ptr<T, RawAllocator>& ptr)
+ {
+ return ptr == p;
+ }
+ /// @}
+
+ /// @{
+ /// \returns `!(ptr == nullptr)`,
+ /// i.e. if `ptr` does own something.
+ /// \relates joint_ptr
+ template <typename T, class RawAllocator>
+ bool operator!=(const joint_ptr<T, RawAllocator>& ptr, std::nullptr_t)
+ {
+ return !(ptr == nullptr);
+ }
+
+ template <typename T, class RawAllocator>
+ bool operator!=(std::nullptr_t, const joint_ptr<T, RawAllocator>& ptr)
+ {
+ return ptr != nullptr;
+ }
+ /// @}
+
+ /// @{
+ /// \returns `!(ptr == p)`,
+ /// i.e. if `ptr` does not ownw the object referred to by `p`.
+ /// \relates joint_ptr
+ template <typename T, class RawAllocator>
+ bool operator!=(const joint_ptr<T, RawAllocator>& ptr, T* p)
+ {
+ return !(ptr == p);
+ }
+
+ template <typename T, class RawAllocator>
+ bool operator!=(T* p, const joint_ptr<T, RawAllocator>& ptr)
+ {
+ return ptr != p;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A new \ref joint_ptr as if created with the same arguments passed to the constructor.
+ /// \relatesalso joint_ptr
+ /// \ingroup allocator
+ template <typename T, class RawAllocator, typename... Args>
+ auto allocate_joint(RawAllocator& alloc, joint_size additional_size, Args&&... args)
+ -> joint_ptr<T, RawAllocator>
+ {
+ return joint_ptr<T, RawAllocator>(alloc, additional_size,
+ detail::forward<Args>(args)...);
+ }
+
+ template <typename T, class RawAllocator, typename... Args>
+ auto allocate_joint(const RawAllocator& alloc, joint_size additional_size, Args&&... args)
+ -> joint_ptr<T, RawAllocator>
+ {
+ return joint_ptr<T, RawAllocator>(alloc, additional_size,
+ detail::forward<Args>(args)...);
+ }
+ /// @}
+
+ /// @{
+ /// \returns A new \ref joint_ptr that points to a copy of `joint`.
+ /// It will allocate as much memory as needed and forward to the copy constructor.
+ /// \ingroup allocator
+ template <class RawAllocator, typename T>
+ auto clone_joint(RawAllocator& alloc, const joint_type<T>& joint)
+ -> joint_ptr<T, RawAllocator>
+ {
+ return joint_ptr<T, RawAllocator>(alloc,
+ joint_size(detail::get_stack(joint).capacity_used(
+ detail::get_memory(joint))),
+ static_cast<const T&>(joint));
+ }
+
+ template <class RawAllocator, typename T>
+ auto clone_joint(const RawAllocator& alloc, const joint_type<T>& joint)
+ -> joint_ptr<T, RawAllocator>
+ {
+ return joint_ptr<T, RawAllocator>(alloc,
+ joint_size(detail::get_stack(joint).capacity_used(
+ detail::get_memory(joint))),
+ static_cast<const T&>(joint));
+ }
+ /// @}
+
+ /// A \concept{concept_rawallocator,RawAllocator} that uses the additional joint memory for its allocation.
+ ///
+ /// It is somewhat limited and allows only allocation once.
+ /// All joint allocators for an object share the joint memory and must not be used in multiple threads.
+ /// The memory it returns is owned by a \ref joint_ptr and will be destroyed through it.
+ /// \ingroup allocator
+ class joint_allocator
+ {
+ public:
+#if defined(__GNUC__) && (!defined(_GLIBCXX_USE_CXX11_ABI) || _GLIBCXX_USE_CXX11_ABI == 0)
+ // std::string requires default constructor for the small string optimization when using gcc's old ABI
+ // so add one, but it must never be used for allocation
+ joint_allocator() noexcept : stack_(nullptr) {}
+#endif
+
+ /// \effects Creates it using the joint memory of the given object.
+ template <typename T>
+ joint_allocator(joint_type<T>& j) noexcept : stack_(&detail::get_stack(j))
+ {
+ }
+
+ joint_allocator(const joint_allocator& other) noexcept = default;
+ joint_allocator& operator=(const joint_allocator& other) noexcept = default;
+
+ /// \effects Allocates a node with given properties.
+ /// \returns A pointer to the new node.
+ /// \throws \ref out_of_fixed_memory exception if this function has been called for a second time
+ /// or the joint memory block is exhausted.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ WPI_MEMORY_ASSERT(stack_);
+ auto mem = stack_->allocate(size, alignment);
+ if (!mem)
+ WPI_THROW(out_of_fixed_memory(info(), size));
+ return mem;
+ }
+
+ /// \effects Deallocates the node, if possible.
+ /// \note It is only possible if it was the last allocation.
+ void deallocate_node(void* ptr, std::size_t size, std::size_t) noexcept
+ {
+ WPI_MEMORY_ASSERT(stack_);
+ auto end = static_cast<char*>(ptr) + size;
+ if (end == stack_->top())
+ stack_->unwind(ptr);
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return allocator_info(WPI_MEMORY_LOG_PREFIX "::joint_allocator", this);
+ }
+
+ detail::joint_stack* stack_;
+
+ friend bool operator==(const joint_allocator& lhs, const joint_allocator& rhs) noexcept;
+ };
+
+ /// @{
+ /// \returns Whether `lhs` and `rhs` use the same joint memory for the allocation.
+ /// \relates joint_allocator
+ inline bool operator==(const joint_allocator& lhs, const joint_allocator& rhs) noexcept
+ {
+ return lhs.stack_ == rhs.stack_;
+ }
+
+ inline bool operator!=(const joint_allocator& lhs, const joint_allocator& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+ /// @}
+
+ /// Specialization of \ref is_shared_allocator to mark \ref joint_allocator as shared.
+ /// This allows using it as \ref allocator_reference directly.
+ /// \ingroup allocator
+ template <>
+ struct is_shared_allocator<joint_allocator> : std::true_type
+ {
+ };
+
+ /// Specialization of \ref is_thread_safe_allocator to mark \ref joint_allocator as thread safe.
+ /// This is an optimization to get rid of the mutex in \ref allocator_storage,
+ /// as joint allocator must not be shared between threads.
+ /// \note The allocator is *not* thread safe, it just must not be shared.
+ template <>
+ struct is_thread_safe_allocator<joint_allocator> : std::true_type
+ {
+ };
+
+#if !defined(DOXYGEN)
+ template <class RawAllocator>
+ struct propagation_traits;
+#endif
+
+ /// Specialization of the \ref propagation_traits for the \ref joint_allocator.
+ /// A joint allocator does not propagate on assignment
+ /// and it is not allowed to use the regular copy/move constructor of allocator aware containers,
+ /// instead it needs the copy/move constructor with allocator.
+ /// \note This is required because the container constructor will end up copying/moving the allocator.
+ /// But this is not allowed as you need the allocator with the correct joined memory.
+ /// Copying can be customized (i.e. forbidden), but sadly not move, so keep that in mind.
+ /// \ingroup allocator
+ template <>
+ struct propagation_traits<joint_allocator>
+ {
+ using propagate_on_container_swap = std::false_type;
+ using propagate_on_container_move_assignment = std::false_type;
+ using propagate_on_container_copy_assignment = std::false_type;
+
+ template <class AllocReference>
+ static AllocReference select_on_container_copy_construction(const AllocReference&)
+ {
+ static_assert(always_false<AllocReference>::value,
+ "you must not use the regular copy constructor");
+ }
+
+ private:
+ template <typename T>
+ struct always_false : std::false_type
+ {
+ };
+ };
+
+ /// A zero overhead dynamic array using joint memory.
+ ///
+ /// If you use, e.g. `std::vector` with \ref joint_allocator,
+ /// this has a slight additional overhead.
+ /// This type is joint memory aware and has no overhead.
+ ///
+ /// It has a dynamic, but fixed size,
+ /// it cannot grow after it has been created.
+ /// \ingroup allocator
+ template <typename T>
+ class joint_array
+ {
+ public:
+ using value_type = T;
+ using iterator = value_type*;
+ using const_iterator = const value_type*;
+
+ //=== constructors ===//
+ /// \effects Creates with `size` default-constructed objects using the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if `size` is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename JointType>
+ joint_array(std::size_t size, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), size)
+ {
+ }
+
+ /// \effects Creates with `size` copies of `val` using the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if `size` is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename JointType>
+ joint_array(std::size_t size, const value_type& val, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), size, val)
+ {
+ }
+
+ /// \effects Creates with the copies of the objects in the initializer list using the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if the size is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename JointType>
+ joint_array(std::initializer_list<value_type> ilist, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), ilist)
+ {
+ }
+
+ /// \effects Creates it by forwarding each element of the range to `T`s constructor using the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if the size is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename InIter, typename JointType,
+ typename = decltype(*std::declval<InIter&>()++)>
+ joint_array(InIter begin, InIter end, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), begin, end)
+ {
+ }
+
+ joint_array(const joint_array&) = delete;
+
+ /// \effects Copy constructs each element from `other` into the storage of the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if the size is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename JointType>
+ joint_array(const joint_array& other, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), other)
+ {
+ }
+
+ joint_array(joint_array&&) = delete;
+
+ /// \effects Move constructs each element from `other` into the storage of the specified joint memory.
+ /// \throws \ref out_of_fixed_memory if the size is too big
+ /// and anything thrown by `T`s constructor.
+ /// If an allocation is thrown, the memory will be released directly.
+ template <typename JointType>
+ joint_array(joint_array&& other, joint_type<JointType>& j)
+ : joint_array(detail::get_stack(j), detail::move(other))
+ {
+ }
+
+ /// \effects Destroys all objects,
+ /// but does not release the storage.
+ ~joint_array() noexcept
+ {
+ for (std::size_t i = 0u; i != size_; ++i)
+ ptr_[i].~T();
+ }
+
+ joint_array& operator=(const joint_array&) = delete;
+ joint_array& operator=(joint_array&&) = delete;
+
+ //=== accessors ===//
+ /// @{
+ /// \returns A reference to the `i`th object.
+ /// \requires `i < size()`.
+ value_type& operator[](std::size_t i) noexcept
+ {
+ WPI_MEMORY_ASSERT(i < size_);
+ return ptr_[i];
+ }
+
+ const value_type& operator[](std::size_t i) const noexcept
+ {
+ WPI_MEMORY_ASSERT(i < size_);
+ return ptr_[i];
+ }
+ /// @}
+
+ /// @{
+ /// \returns A pointer to the first object.
+ /// It points to contiguous memory and can be used to access the objects directly.
+ value_type* data() noexcept
+ {
+ return ptr_;
+ }
+
+ const value_type* data() const noexcept
+ {
+ return ptr_;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A random access iterator to the first element.
+ iterator begin() noexcept
+ {
+ return ptr_;
+ }
+
+ const_iterator begin() const noexcept
+ {
+ return ptr_;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A random access iterator one past the last element.
+ iterator end() noexcept
+ {
+ return ptr_ + size_;
+ }
+
+ const_iterator end() const noexcept
+ {
+ return ptr_ + size_;
+ }
+ /// @}
+
+ /// \returns The number of elements in the array.
+ std::size_t size() const noexcept
+ {
+ return size_;
+ }
+
+ /// \returns `true` if the array is empty, `false` otherwise.
+ bool empty() const noexcept
+ {
+ return size_ == 0u;
+ }
+
+ private:
+ // allocate only
+ struct allocate_only
+ {
+ };
+ joint_array(allocate_only, detail::joint_stack& stack, std::size_t size)
+ : ptr_(nullptr), size_(0u)
+ {
+ ptr_ = static_cast<T*>(stack.allocate(size * sizeof(T), alignof(T)));
+ if (!ptr_)
+ WPI_THROW(out_of_fixed_memory(info(), size * sizeof(T)));
+ }
+
+ class builder
+ {
+ public:
+ builder(detail::joint_stack& stack, T* ptr) noexcept
+ : stack_(&stack), objects_(ptr), size_(0u)
+ {
+ }
+
+ ~builder() noexcept
+ {
+ for (std::size_t i = 0u; i != size_; ++i)
+ objects_[i].~T();
+
+ if (size_)
+ stack_->unwind(objects_);
+ }
+
+ builder(builder&&) = delete;
+ builder& operator=(builder&&) = delete;
+
+ template <typename... Args>
+ T* create(Args&&... args)
+ {
+ auto ptr = ::new (static_cast<void*>(&objects_[size_]))
+ T(detail::forward<Args>(args)...);
+ ++size_;
+ return ptr;
+ }
+
+ std::size_t size() const noexcept
+ {
+ return size_;
+ }
+
+ std::size_t release() noexcept
+ {
+ auto res = size_;
+ size_ = 0u;
+ return res;
+ }
+
+ private:
+ detail::joint_stack* stack_;
+ T* objects_;
+ std::size_t size_;
+ };
+
+ joint_array(detail::joint_stack& stack, std::size_t size)
+ : joint_array(allocate_only{}, stack, size)
+ {
+ builder b(stack, ptr_);
+ for (auto i = 0u; i != size; ++i)
+ b.create();
+ size_ = b.release();
+ }
+
+ joint_array(detail::joint_stack& stack, std::size_t size, const value_type& value)
+ : joint_array(allocate_only{}, stack, size)
+ {
+ builder b(stack, ptr_);
+ for (auto i = 0u; i != size; ++i)
+ b.create(value);
+ size_ = b.release();
+ }
+
+ joint_array(detail::joint_stack& stack, std::initializer_list<value_type> ilist)
+ : joint_array(allocate_only{}, stack, ilist.size())
+ {
+ builder b(stack, ptr_);
+ for (auto& elem : ilist)
+ b.create(elem);
+ size_ = b.release();
+ }
+
+ joint_array(detail::joint_stack& stack, const joint_array& other)
+ : joint_array(allocate_only{}, stack, other.size())
+ {
+ builder b(stack, ptr_);
+ for (auto& elem : other)
+ b.create(elem);
+ size_ = b.release();
+ }
+
+ joint_array(detail::joint_stack& stack, joint_array&& other)
+ : joint_array(allocate_only{}, stack, other.size())
+ {
+ builder b(stack, ptr_);
+ for (auto& elem : other)
+ b.create(detail::move(elem));
+ size_ = b.release();
+ }
+
+ template <typename InIter>
+ joint_array(detail::joint_stack& stack, InIter begin, InIter end)
+ : ptr_(nullptr), size_(0u)
+ {
+ if (begin == end)
+ return;
+
+ ptr_ = static_cast<T*>(stack.allocate(sizeof(T), alignof(T)));
+ if (!ptr_)
+ WPI_THROW(out_of_fixed_memory(info(), sizeof(T)));
+
+ builder b(stack, ptr_);
+ b.create(*begin++);
+
+ for (auto last = ptr_; begin != end; ++begin)
+ {
+ // just bump stack to get more memory
+ if (!stack.bump(sizeof(T)))
+ WPI_THROW(out_of_fixed_memory(info(), b.size() * sizeof(T)));
+
+ auto cur = b.create(*begin);
+ WPI_MEMORY_ASSERT(last + 1 == cur);
+ last = cur;
+ }
+
+ size_ = b.release();
+ }
+
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::joint_array", this};
+ }
+
+ value_type* ptr_;
+ std::size_t size_;
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_JOINT_ALLOCATOR_HPP_INCLUDED
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
new file mode 100644
index 0000000..3be9820
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/malloc_allocator.hpp
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef WPI_MEMORY_MALLOC_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_MALLOC_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::malloc_allocator.
+/// \note Only available on a hosted implementation.
+
+#include "config.hpp"
+#if !WPI_HOSTED_IMPLEMENTATION
+#error "This header is only available for a hosted implementation."
+#endif
+
+#include <cstdlib>
+#include <memory>
+
+#include "detail/lowlevel_allocator.hpp"
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+#include "allocator_traits.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ struct allocator_info;
+
+ namespace detail
+ {
+ struct malloc_allocator_impl
+ {
+ static allocator_info info() noexcept;
+
+ static void* allocate(std::size_t size, std::size_t) noexcept
+ {
+ return std::malloc(size);
+ }
+
+ static void deallocate(void* ptr, std::size_t, std::size_t) noexcept
+ {
+ std::free(ptr);
+ }
+
+ static std::size_t max_node_size() noexcept
+ {
+ return std::allocator_traits<std::allocator<char>>::max_size({});
+ }
+ };
+
+ WPI_MEMORY_LL_ALLOCATOR_LEAK_CHECKER(malloc_allocator_impl,
+ malloc_alloator_leak_checker)
+ } // namespace detail
+
+ /// A stateless \concept{concept_rawallocator,RawAllocator} that allocates memory using <tt>std::malloc()</tt>.
+ /// It throws \ref out_of_memory when the allocation fails.
+ /// \ingroup allocator
+ using malloc_allocator =
+ WPI_IMPL_DEFINED(detail::lowlevel_allocator<detail::malloc_allocator_impl>);
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class detail::lowlevel_allocator<detail::malloc_allocator_impl>;
+ extern template class allocator_traits<malloc_allocator>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..a634993
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_arena.hpp
@@ -0,0 +1,693 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::memory_arena and related functionality regarding \concept{concept_blockallocator,BlockAllocators}.
+
+#include <type_traits>
+
+#include "detail/debug_helpers.hpp"
+#include "detail/assert.hpp"
+#include "detail/utility.hpp"
+#include "allocator_traits.hpp"
+#include "config.hpp"
+#include "default_allocator.hpp"
+#include "error.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A memory block.
+ /// It is defined by its starting address and size.
+ /// \ingroup core
+ struct memory_block
+ {
+ void* memory; ///< The address of the memory block (might be \c nullptr).
+ std::size_t size; ///< The size of the memory block (might be \c 0).
+
+ /// \effects Creates an invalid memory block with starting address \c nullptr and size \c 0.
+ memory_block() noexcept : memory_block(nullptr, std::size_t(0)) {}
+
+ /// \effects Creates a memory block from a given starting address and size.
+ memory_block(void* mem, std::size_t s) noexcept : memory(mem), size(s) {}
+
+ /// \effects Creates a memory block from a [begin,end) range.
+ memory_block(void* begin, void* end) noexcept
+ : memory_block(begin, static_cast<std::size_t>(static_cast<char*>(end)
+ - static_cast<char*>(begin)))
+ {
+ }
+
+ /// \returns Whether or not a pointer is inside the memory.
+ bool contains(const void* address) const noexcept
+ {
+ auto mem = static_cast<const char*>(memory);
+ auto addr = static_cast<const char*>(address);
+ return addr >= mem && addr < mem + size;
+ }
+ };
+
+ namespace detail
+ {
+ template <class BlockAllocator>
+ std::true_type is_block_allocator_impl(
+ int,
+ WPI_SFINAE(std::declval<memory_block&>() =
+ std::declval<BlockAllocator&>().allocate_block()),
+ WPI_SFINAE(std::declval<std::size_t&>() =
+ std::declval<BlockAllocator&>().next_block_size()),
+ WPI_SFINAE(std::declval<BlockAllocator>().deallocate_block(memory_block{})));
+
+ template <typename T>
+ std::false_type is_block_allocator_impl(short);
+ } // namespace detail
+
+ /// Traits that check whether a type models concept \concept{concept_blockallocator,BlockAllocator}.
+ /// \ingroup core
+ template <typename T>
+ struct is_block_allocator : decltype(detail::is_block_allocator_impl<T>(0))
+ {
+ };
+
+#if !defined(DOXYGEN)
+ template <class BlockAllocator, bool Cached = true>
+ class memory_arena;
+#endif
+
+ /// @{
+ /// Controls the caching of \ref memory_arena.
+ /// By default, deallocated blocks are put onto a cache, so they can be reused later;
+ /// this tag value enable/disable it..<br>
+ /// This can be useful, e.g. if there will never be blocks available for deallocation.
+ /// The (tiny) overhead for the cache can then be disabled.
+ /// An example is \ref memory_pool.
+ /// \ingroup core
+ constexpr bool cached_arena = true;
+ constexpr bool uncached_arena = false;
+ /// @}
+
+ namespace detail
+ {
+ // stores memory block in an intrusive linked list and allows LIFO access
+ class memory_block_stack
+ {
+ public:
+ memory_block_stack() noexcept : head_(nullptr) {}
+
+ ~memory_block_stack() noexcept {}
+
+ memory_block_stack(memory_block_stack&& other) noexcept : head_(other.head_)
+ {
+ other.head_ = nullptr;
+ }
+
+ memory_block_stack& operator=(memory_block_stack&& other) noexcept
+ {
+ memory_block_stack tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+
+ friend void swap(memory_block_stack& a, memory_block_stack& b) noexcept
+ {
+ detail::adl_swap(a.head_, b.head_);
+ }
+
+ // the raw allocated block returned from an allocator
+ using allocated_mb = memory_block;
+
+ // the inserted block slightly smaller to allow for the fixup value
+ using inserted_mb = memory_block;
+
+ // how much an inserted block is smaller
+ static constexpr std::size_t implementation_offset() noexcept
+ {
+ // node size rounded up to the next multiple of max_alignment.
+ return (sizeof(node) / max_alignment + (sizeof(node) % max_alignment != 0))
+ * max_alignment;
+ }
+
+ // pushes a memory block
+ void push(allocated_mb block) noexcept;
+
+ // pops a memory block and returns the original block
+ allocated_mb pop() noexcept;
+
+ // steals the top block from another stack
+ void steal_top(memory_block_stack& other) noexcept;
+
+ // returns the last pushed() inserted memory block
+ inserted_mb top() const noexcept
+ {
+ WPI_MEMORY_ASSERT(head_);
+ auto mem = static_cast<void*>(head_);
+ return {static_cast<char*>(mem) + implementation_offset(), head_->usable_size};
+ }
+
+ bool empty() const noexcept
+ {
+ return head_ == nullptr;
+ }
+
+ bool owns(const void* ptr) const noexcept;
+
+ // O(n) size
+ std::size_t size() const noexcept;
+
+ private:
+ struct node
+ {
+ node* prev;
+ std::size_t usable_size;
+
+ node(node* p, std::size_t size) noexcept : prev(p), usable_size(size) {}
+ };
+
+ node* head_;
+ };
+
+ template <bool Cached>
+ class memory_arena_cache;
+
+ template <>
+ class memory_arena_cache<cached_arena>
+ {
+ protected:
+ bool cache_empty() const noexcept
+ {
+ return cached_.empty();
+ }
+
+ std::size_t cache_size() const noexcept
+ {
+ return cached_.size();
+ }
+
+ std::size_t cached_block_size() const noexcept
+ {
+ return cached_.top().size;
+ }
+
+ bool take_from_cache(detail::memory_block_stack& used) noexcept
+ {
+ if (cached_.empty())
+ return false;
+ used.steal_top(cached_);
+ return true;
+ }
+
+ template <class BlockAllocator>
+ void do_deallocate_block(BlockAllocator&, detail::memory_block_stack& used) noexcept
+ {
+ cached_.steal_top(used);
+ }
+
+ template <class BlockAllocator>
+ void do_shrink_to_fit(BlockAllocator& alloc) noexcept
+ {
+ detail::memory_block_stack to_dealloc;
+ // pop from cache and push to temporary stack
+ // this revers order
+ while (!cached_.empty())
+ to_dealloc.steal_top(cached_);
+ // now dealloc everything
+ while (!to_dealloc.empty())
+ alloc.deallocate_block(to_dealloc.pop());
+ }
+
+ private:
+ detail::memory_block_stack cached_;
+ };
+
+ template <>
+ class memory_arena_cache<uncached_arena>
+ {
+ protected:
+ bool cache_empty() const noexcept
+ {
+ return true;
+ }
+
+ std::size_t cache_size() const noexcept
+ {
+ return 0u;
+ }
+
+ std::size_t cached_block_size() const noexcept
+ {
+ return 0u;
+ }
+
+ bool take_from_cache(detail::memory_block_stack&) noexcept
+ {
+ return false;
+ }
+
+ template <class BlockAllocator>
+ void do_deallocate_block(BlockAllocator& alloc,
+ detail::memory_block_stack& used) noexcept
+ {
+ alloc.deallocate_block(used.pop());
+ }
+
+ template <class BlockAllocator>
+ void do_shrink_to_fit(BlockAllocator&) noexcept
+ {
+ }
+ };
+ } // namespace detail
+
+ /// A memory arena that manages huge memory blocks for a higher-level allocator.
+ /// Some allocators like \ref memory_stack work on huge memory blocks,
+ /// this class manages them fro those allocators.
+ /// It uses a \concept{concept_blockallocator,BlockAllocator} for the allocation of those blocks.
+ /// The memory blocks in use are put onto a stack like structure, deallocation will pop from the top,
+ /// so it is only possible to deallocate the last allocated block of the arena.
+ /// By default, blocks are not really deallocated but stored in a cache.
+ /// This can be disabled with the second template parameter,
+ /// passing it \ref uncached_arena (or \c false) disables it,
+ /// \ref cached_arena (or \c true) enables it explicitly.
+ /// \ingroup core
+ template <class BlockAllocator, bool Cached /* = true */>
+ class memory_arena : WPI_EBO(BlockAllocator),
+ WPI_EBO(detail::memory_arena_cache<Cached>)
+ {
+ static_assert(is_block_allocator<BlockAllocator>::value,
+ "BlockAllocator is not a BlockAllocator!");
+ using cache = detail::memory_arena_cache<Cached>;
+
+ public:
+ using allocator_type = BlockAllocator;
+ using is_cached = std::integral_constant<bool, Cached>;
+
+ /// \returns The minimum block size required for an arena containing the given amount of memory.
+ /// If an arena is created with the result of `min_block_size(n)`, the resulting capacity will be exactly `n`.
+ /// \requires `byte_size` must be a positive number.
+ static constexpr std::size_t min_block_size(std::size_t byte_size) noexcept
+ {
+ return detail::memory_block_stack::implementation_offset() + byte_size;
+ }
+
+ /// \effects Creates it by giving it the size and other arguments for the \concept{concept_blockallocator,BlockAllocator}.
+ /// It forwards these arguments to its constructor.
+ /// \requires \c block_size must be greater than \c min_block_size(0) and other requirements depending on the \concept{concept_blockallocator,BlockAllocator}.
+ /// \throws Anything thrown by the constructor of the \c BlockAllocator.
+ template <typename... Args>
+ explicit memory_arena(std::size_t block_size, Args&&... args)
+ : allocator_type(block_size, detail::forward<Args>(args)...)
+ {
+ WPI_MEMORY_ASSERT(block_size > min_block_size(0));
+ }
+
+ /// \effects Deallocates all memory blocks that where requested back to the \concept{concept_blockallocator,BlockAllocator}.
+ ~memory_arena() noexcept
+ {
+ // clear cache
+ shrink_to_fit();
+ // now deallocate everything
+ while (!used_.empty())
+ allocator_type::deallocate_block(used_.pop());
+ }
+
+ /// @{
+ /// \effects Moves the arena.
+ /// The new arena takes ownership over all the memory blocks from the other arena object,
+ /// which is empty after that.
+ /// This does not invalidate any memory blocks.
+ memory_arena(memory_arena&& other) noexcept
+ : allocator_type(detail::move(other)),
+ cache(detail::move(other)),
+ used_(detail::move(other.used_))
+ {
+ }
+
+ memory_arena& operator=(memory_arena&& other) noexcept
+ {
+ memory_arena tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+ /// @}
+
+ /// \effects Swaps to memory arena objects.
+ /// This does not invalidate any memory blocks.
+ friend void swap(memory_arena& a, memory_arena& b) noexcept
+ {
+ detail::adl_swap(static_cast<allocator_type&>(a), static_cast<allocator_type&>(b));
+ detail::adl_swap(static_cast<cache&>(a), static_cast<cache&>(b));
+ detail::adl_swap(a.used_, b.used_);
+ }
+
+ /// \effects Allocates a new memory block.
+ /// It first uses a cache of previously deallocated blocks, if caching is enabled,
+ /// if it is empty, allocates a new one.
+ /// \returns The new \ref memory_block.
+ /// \throws Anything thrown by the \concept{concept_blockallocator,BlockAllocator} allocation function.
+ memory_block allocate_block()
+ {
+ if (!this->take_from_cache(used_))
+ used_.push(allocator_type::allocate_block());
+
+ auto block = used_.top();
+ detail::debug_fill_internal(block.memory, block.size, false);
+ return block;
+ }
+
+ /// \returns The current memory block.
+ /// This is the memory block that will be deallocated by the next call to \ref deallocate_block().
+ memory_block current_block() const noexcept
+ {
+ return used_.top();
+ }
+
+ /// \effects Deallocates the current memory block.
+ /// The current memory block is the block on top of the stack of blocks.
+ /// If caching is enabled, it does not really deallocate it but puts it onto a cache for later use,
+ /// use \ref shrink_to_fit() to purge that cache.
+ void deallocate_block() noexcept
+ {
+ auto block = used_.top();
+ detail::debug_fill_internal(block.memory, block.size, true);
+ this->do_deallocate_block(get_allocator(), used_);
+ }
+
+ /// \returns If `ptr` is in memory owned by the arena.
+ bool owns(const void* ptr) const noexcept
+ {
+ return used_.owns(ptr);
+ }
+
+ /// \effects Purges the cache of unused memory blocks by returning them.
+ /// The memory blocks will be deallocated in reversed order of allocation.
+ /// Does nothing if caching is disabled.
+ void shrink_to_fit() noexcept
+ {
+ this->do_shrink_to_fit(get_allocator());
+ }
+
+ /// \returns The capacity of the arena, i.e. how many blocks are used and cached.
+ std::size_t capacity() const noexcept
+ {
+ return size() + cache_size();
+ }
+
+ /// \returns The size of the cache, i.e. how many blocks can be allocated without allocation.
+ std::size_t cache_size() const noexcept
+ {
+ return cache::cache_size();
+ }
+
+ /// \returns The size of the arena, i.e. how many blocks are in use.
+ /// It is always smaller or equal to the \ref capacity().
+ std::size_t size() const noexcept
+ {
+ return used_.size();
+ }
+
+ /// \returns The size of the next memory block,
+ /// i.e. of the next call to \ref allocate_block().
+ /// If there are blocks in the cache, returns size of the next one.
+ /// Otherwise forwards to the \concept{concept_blockallocator,BlockAllocator} and subtracts an implementation offset.
+ std::size_t next_block_size() const noexcept
+ {
+ return this->cache_empty() ?
+ allocator_type::next_block_size()
+ - detail::memory_block_stack::implementation_offset() :
+ this->cached_block_size();
+ }
+
+ /// \returns A reference of the \concept{concept_blockallocator,BlockAllocator} object.
+ /// \requires It is undefined behavior to move this allocator out into another object.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ private:
+ detail::memory_block_stack used_;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class memory_arena<static_block_allocator, true>;
+ extern template class memory_arena<static_block_allocator, false>;
+ extern template class memory_arena<virtual_block_allocator, true>;
+ extern template class memory_arena<virtual_block_allocator, false>;
+#endif
+
+ /// A \concept{concept_blockallocator,BlockAllocator} that uses a given \concept{concept_rawallocator,RawAllocator} for allocating the blocks.
+ /// It calls the \c allocate_array() function with a node of size \c 1 and maximum alignment on the used allocator for the block allocation.
+ /// The size of the next memory block will grow by a given factor after each allocation,
+ /// allowing an amortized constant allocation time in the higher level allocator.
+ /// The factor can be given as rational in the template parameter, default is \c 2.
+ /// \ingroup adapter
+ template <class RawAllocator = default_allocator, unsigned Num = 2, unsigned Den = 1>
+ class growing_block_allocator
+ : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ static_assert(float(Num) / Den >= 1.0, "invalid growth factor");
+
+ using traits = allocator_traits<RawAllocator>;
+
+ public:
+ using allocator_type = typename traits::allocator_type;
+
+ /// \effects Creates it by giving it the initial block size, the allocator object and the growth factor.
+ /// By default, it uses a default-constructed allocator object and a growth factor of \c 2.
+ /// \requires \c block_size must be greater than 0.
+ explicit growing_block_allocator(std::size_t block_size,
+ allocator_type alloc = allocator_type()) noexcept
+ : allocator_type(detail::move(alloc)), block_size_(block_size)
+ {
+ }
+
+ /// \effects Allocates a new memory block and increases the block size for the next allocation.
+ /// \returns The new \ref memory_block.
+ /// \throws Anything thrown by the \c allocate_array() function of the \concept{concept_rawallocator,RawAllocator}.
+ memory_block allocate_block()
+ {
+ auto memory =
+ traits::allocate_array(get_allocator(), block_size_, 1, detail::max_alignment);
+ memory_block block(memory, block_size_);
+ block_size_ = grow_block_size(block_size_);
+ return block;
+ }
+
+ /// \effects Deallocates a previously allocated memory block.
+ /// This does not decrease the block size.
+ /// \requires \c block must be previously returned by a call to \ref allocate_block().
+ void deallocate_block(memory_block block) noexcept
+ {
+ traits::deallocate_array(get_allocator(), block.memory, block.size, 1,
+ detail::max_alignment);
+ }
+
+ /// \returns The size of the memory block returned by the next call to \ref allocate_block().
+ std::size_t next_block_size() const noexcept
+ {
+ return block_size_;
+ }
+
+ /// \returns A reference to the used \concept{concept_rawallocator,RawAllocator} object.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ /// \returns The growth factor.
+ static float growth_factor() noexcept
+ {
+ static constexpr auto factor = float(Num) / Den;
+ return factor;
+ }
+
+ static std::size_t grow_block_size(std::size_t block_size) noexcept
+ {
+ return block_size * Num / Den;
+ }
+
+ private:
+ std::size_t block_size_;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class growing_block_allocator<>;
+ extern template class memory_arena<growing_block_allocator<>, true>;
+ extern template class memory_arena<growing_block_allocator<>, false>;
+#endif
+
+ /// A \concept{concept_blockallocator,BlockAllocator} that allows only one block allocation.
+ /// It can be used to prevent higher-level allocators from expanding.
+ /// The one block allocation is performed through the \c allocate_array() function of the given \concept{concept_rawallocator,RawAllocator}.
+ /// \ingroup adapter
+ template <class RawAllocator = default_allocator>
+ class fixed_block_allocator : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ using traits = allocator_traits<RawAllocator>;
+
+ public:
+ using allocator_type = typename traits::allocator_type;
+
+ /// \effects Creates it by passing it the size of the block and the allocator object.
+ /// \requires \c block_size must be greater than 0,
+ explicit fixed_block_allocator(std::size_t block_size,
+ allocator_type alloc = allocator_type()) noexcept
+ : allocator_type(detail::move(alloc)), block_size_(block_size)
+ {
+ }
+
+ /// \effects Allocates a new memory block or throws an exception if there was already one allocation.
+ /// \returns The new \ref memory_block.
+ /// \throws Anything thrown by the \c allocate_array() function of the \concept{concept_rawallocator,RawAllocator} or \ref out_of_memory if this is not the first call.
+ memory_block allocate_block()
+ {
+ if (block_size_)
+ {
+ auto mem = traits::allocate_array(get_allocator(), block_size_, 1,
+ detail::max_alignment);
+ memory_block block(mem, block_size_);
+ block_size_ = 0u;
+ return block;
+ }
+ WPI_THROW(out_of_fixed_memory(info(), block_size_));
+ }
+
+ /// \effects Deallocates the previously allocated memory block.
+ /// It also resets and allows a new call again.
+ void deallocate_block(memory_block block) noexcept
+ {
+ detail::debug_check_pointer([&] { return block_size_ == 0u; }, info(),
+ block.memory);
+ traits::deallocate_array(get_allocator(), block.memory, block.size, 1,
+ detail::max_alignment);
+ block_size_ = block.size;
+ }
+
+ /// \returns The size of the next block which is either the initial size or \c 0.
+ std::size_t next_block_size() const noexcept
+ {
+ return block_size_;
+ }
+
+ /// \returns A reference to the used \concept{concept_rawallocator,RawAllocator} object.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ private:
+ allocator_info info() noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::fixed_block_allocator", this};
+ }
+
+ std::size_t block_size_;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class fixed_block_allocator<>;
+ extern template class memory_arena<fixed_block_allocator<>, true>;
+ extern template class memory_arena<fixed_block_allocator<>, false>;
+#endif
+
+ namespace detail
+ {
+ template <class RawAlloc>
+ using default_block_wrapper = growing_block_allocator<RawAlloc>;
+
+ template <template <class...> class Wrapper, class BlockAllocator, typename... Args>
+ BlockAllocator make_block_allocator(std::true_type, std::size_t block_size,
+ Args&&... args)
+ {
+ return BlockAllocator(block_size, detail::forward<Args>(args)...);
+ }
+
+ template <template <class...> class Wrapper, class RawAlloc>
+ auto make_block_allocator(std::false_type, std::size_t block_size,
+ RawAlloc alloc = RawAlloc()) -> Wrapper<RawAlloc>
+ {
+ return Wrapper<RawAlloc>(block_size, detail::move(alloc));
+ }
+ } // namespace detail
+
+ /// Takes either a \concept{concept_blockallocator,BlockAllocator} or a \concept{concept_rawallocator,RawAllocator}.
+ /// In the first case simply aliases the type unchanged, in the second to \ref growing_block_allocator (or the template in `BlockAllocator`) with the \concept{concept_rawallocator,RawAllocator}.
+ /// Using this allows passing normal \concept{concept_rawallocator,RawAllocators} as \concept{concept_blockallocator,BlockAllocators}.
+ /// \ingroup core
+ template <class BlockOrRawAllocator,
+ template <typename...> class BlockAllocator = detail::default_block_wrapper>
+ using make_block_allocator_t = WPI_IMPL_DEFINED(
+ typename std::conditional<is_block_allocator<BlockOrRawAllocator>::value,
+ BlockOrRawAllocator,
+ BlockAllocator<BlockOrRawAllocator>>::type);
+
+ /// @{
+ /// Helper function make a \concept{concept_blockallocator,BlockAllocator}.
+ /// \returns A \concept{concept_blockallocator,BlockAllocator} of the given type created with the given arguments.
+ /// \requires Same requirements as the constructor.
+ /// \ingroup core
+ template <class BlockOrRawAllocator, typename... Args>
+ make_block_allocator_t<BlockOrRawAllocator> make_block_allocator(std::size_t block_size,
+ Args&&... args)
+ {
+ return detail::make_block_allocator<
+ detail::default_block_wrapper,
+ BlockOrRawAllocator>(is_block_allocator<BlockOrRawAllocator>{}, block_size,
+ detail::forward<Args>(args)...);
+ }
+
+ template <template <class...> class BlockAllocator, class BlockOrRawAllocator,
+ typename... Args>
+ make_block_allocator_t<BlockOrRawAllocator, BlockAllocator> make_block_allocator(
+ std::size_t block_size, Args&&... args)
+ {
+ return detail::make_block_allocator<
+ BlockAllocator, BlockOrRawAllocator>(is_block_allocator<BlockOrRawAllocator>{},
+ block_size, detail::forward<Args>(args)...);
+ }
+ /// @}
+
+ namespace literals
+ {
+ /// Syntax sugar to express sizes with unit prefixes.
+ /// \returns The number of bytes `value` is in the given unit.
+ /// \ingroup core
+ /// @{
+ constexpr std::size_t operator"" _KiB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1024);
+ }
+
+ constexpr std::size_t operator"" _KB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1000);
+ }
+
+ constexpr std::size_t operator"" _MiB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1024 * 1024);
+ }
+
+ constexpr std::size_t operator"" _MB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1000 * 1000);
+ }
+
+ constexpr std::size_t operator"" _GiB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1024 * 1024 * 1024);
+ }
+
+ constexpr std::size_t operator"" _GB(unsigned long long value) noexcept
+ {
+ return std::size_t(value * 1000 * 1000 * 1000);
+ }
+ } // namespace literals
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_MEMORY_ARENA_HPP_INCLUDED
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
new file mode 100644
index 0000000..09c2b66
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool.hpp
@@ -0,0 +1,433 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_POOL_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_POOL_HPP_INCLUDED
+
+// Inform that wpi::memory::memory_pool::min_block_size API is available
+#define WPI_MEMORY_MEMORY_POOL_HAS_MIN_BLOCK_SIZE
+
+/// \file
+/// Class \ref wpi::memory::memory_pool and its \ref wpi::memory::allocator_traits specialization.
+
+#include <type_traits>
+
+#include "detail/align.hpp"
+#include "detail/debug_helpers.hpp"
+#include "detail/assert.hpp"
+#include "config.hpp"
+#include "error.hpp"
+#include "memory_arena.hpp"
+#include "memory_pool_type.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ struct memory_pool_leak_handler
+ {
+ void operator()(std::ptrdiff_t amount);
+ };
+ } // namespace detail
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that manages \concept{concept_node,nodes} of fixed size.
+ /// It uses a \ref memory_arena with a given \c BlockOrRawAllocator defaulting to \ref growing_block_allocator,
+ /// subdivides them in small nodes of given size and puts them onto a free list.
+ /// Allocation and deallocation simply remove or add nodes from this list and are thus fast.
+ /// The way the list is maintained can be controlled via the \c PoolType
+ /// which is either \ref node_pool, \ref array_pool or \ref small_node_pool.<br>
+ /// This kind of allocator is ideal for fixed size allocations and deallocations in any order,
+ /// for example in a node based container like \c std::list.
+ /// It is not so good for different allocation sizes and has some drawbacks for arrays
+ /// as described in \ref memory_pool_type.hpp.
+ /// \ingroup allocator
+ template <typename PoolType = node_pool, class BlockOrRawAllocator = default_allocator>
+ class memory_pool
+ : WPI_EBO(detail::default_leak_checker<detail::memory_pool_leak_handler>)
+ {
+ using free_list = typename PoolType::type;
+ using leak_checker = detail::default_leak_checker<detail::memory_pool_leak_handler>;
+
+ public:
+ using allocator_type = make_block_allocator_t<BlockOrRawAllocator>;
+ using pool_type = PoolType;
+
+ static constexpr std::size_t min_node_size =
+ WPI_IMPL_DEFINED(free_list::min_element_size);
+
+ /// \returns The minimum block size required for certain number of \concept{concept_node,node}.
+ /// \requires \c node_size must be a valid \concept{concept_node,node size}
+ /// and \c number_of_nodes must be a non-zero value.
+ /// \note MSVC's implementation of \c std::list for example is never empty and always allocates proxy nodes.
+ /// To get enough memory for \c N elements of a list, \c number_of_nodes needs to include the proxy count in addition to \c N.
+ static constexpr std::size_t min_block_size(std::size_t node_size,
+ std::size_t number_of_nodes) noexcept
+ {
+ return detail::memory_block_stack::implementation_offset()
+ + free_list::min_block_size(node_size, number_of_nodes);
+ }
+
+ /// \effects Creates it by specifying the size each \concept{concept_node,node} will have,
+ /// the initial block size for the arena and other constructor arguments for the \concept{concept_blockallocator,BlockAllocator}.
+ /// If the \c node_size is less than the \c min_node_size, the \c min_node_size will be the actual node size.
+ /// It will allocate an initial memory block with given size from the \concept{concept_blockallocator,BlockAllocator}
+ /// and puts it onto the free list.
+ /// \requires \c node_size must be a valid \concept{concept_node,node size}
+ /// and \c block_size must be at least \c min_block_size(node_size, 1).
+ template <typename... Args>
+ memory_pool(std::size_t node_size, std::size_t block_size, Args&&... args)
+ : arena_(block_size, detail::forward<Args>(args)...), free_list_(node_size)
+ {
+ allocate_block();
+ }
+
+ /// \effects Destroys the \ref memory_pool by returning all memory blocks,
+ /// regardless of properly deallocated back to the \concept{concept_blockallocator,BlockAllocator}.
+ ~memory_pool() noexcept {}
+
+ /// @{
+ /// \effects Moving a \ref memory_pool object transfers ownership over the free list,
+ /// i.e. the moved from pool is completely empty and the new one has all its memory.
+ /// That means that it is not allowed to call \ref deallocate_node() on a moved-from allocator
+ /// even when passing it memory that was previously allocated by this object.
+ memory_pool(memory_pool&& other) noexcept
+ : leak_checker(detail::move(other)),
+ arena_(detail::move(other.arena_)),
+ free_list_(detail::move(other.free_list_))
+ {
+ }
+
+ 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_);
+ return *this;
+ }
+ /// @}
+
+ /// \effects Allocates a single \concept{concept_node,node} by removing it from the free list.
+ /// If the free list is empty, a new memory block will be allocated from the arena and put onto it.
+ /// The new block size will be \ref next_capacity() big.
+ /// \returns A node of size \ref node_size() suitable aligned,
+ /// i.e. suitable for any type where <tt>sizeof(T) < node_size()</tt>.
+ /// \throws Anything thrown by the used \concept{concept_blockallocator,BlockAllocator}'s allocation function if a growth is needed.
+ void* allocate_node()
+ {
+ if (free_list_.empty())
+ allocate_block();
+ WPI_MEMORY_ASSERT(!free_list_.empty());
+ return free_list_.allocate();
+ }
+
+ /// \effects Allocates a single \concept{concept_node,node} similar to \ref allocate_node().
+ /// But if the free list is empty, a new block will *not* be allocated.
+ /// \returns A suitable aligned node of size \ref node_size() or `nullptr`.
+ void* try_allocate_node() noexcept
+ {
+ return free_list_.empty() ? nullptr : free_list_.allocate();
+ }
+
+ /// \effects Allocates an \concept{concept_array,array} of nodes by searching for \c n continuous nodes on the list and removing them.
+ /// Depending on the \c PoolType this can be a slow operation or not allowed at all.
+ /// This can sometimes lead to a growth, even if technically there is enough continuous memory on the free list.
+ /// \returns An array of \c n nodes of size \ref node_size() suitable aligned.
+ /// \throws Anything thrown by the used \concept{concept_blockallocator,BlockAllocator}'s allocation function if a growth is needed,
+ /// or \ref bad_array_size if <tt>n * node_size()</tt> is too big.
+ /// \requires \c n must be valid \concept{concept_array,array count}.
+ void* allocate_array(std::size_t n)
+ {
+ detail::check_allocation_size<bad_array_size>(
+ n * node_size(), [&] { return pool_type::value ? next_capacity() : 0; },
+ info());
+ return allocate_array(n, node_size());
+ }
+
+ /// \effects Allocates an \concept{concept_array,array} of nodes similar to \ref allocate_array().
+ /// But it will never allocate a new memory block.
+ /// \returns An array of \c n nodes of size \ref node_size() suitable aligned
+ /// or `nullptr`.
+ void* try_allocate_array(std::size_t n) noexcept
+ {
+ return try_allocate_array(n, node_size());
+ }
+
+ /// \effects Deallocates a single \concept{concept_node,node} by putting it back onto the free list.
+ /// \requires \c ptr must be a result from a previous call to \ref allocate_node() on the same free list,
+ /// i.e. either this allocator object or a new object created by moving this to it.
+ void deallocate_node(void* ptr) noexcept
+ {
+ free_list_.deallocate(ptr);
+ }
+
+ /// \effects Deallocates a single \concept{concept_node,node} but it does not be a result of a previous call to \ref allocate_node().
+ /// \returns `true` if the node could be deallocated, `false` otherwise.
+ /// \note Some free list implementations can deallocate any memory,
+ /// doesn't matter where it is coming from.
+ bool try_deallocate_node(void* ptr) noexcept
+ {
+ if (!arena_.owns(ptr))
+ return false;
+ free_list_.deallocate(ptr);
+ return true;
+ }
+
+ /// \effects Deallocates an \concept{concept_array,array} by putting it back onto the free list.
+ /// \requires \c ptr must be a result from a previous call to \ref allocate_array() with the same \c n on the same free list,
+ /// i.e. either this allocator object or a new object created by moving this to it.
+ void deallocate_array(void* ptr, std::size_t n) noexcept
+ {
+ WPI_MEMORY_ASSERT_MSG(pool_type::value, "does not support array allocations");
+ free_list_.deallocate(ptr, n * node_size());
+ }
+
+ /// \effects Deallocates an \concept{concept_array,array} but it does not be a result of a previous call to \ref allocate_array().
+ /// \returns `true` if the node could be deallocated, `false` otherwise.
+ /// \note Some free list implementations can deallocate any memory,
+ /// doesn't matter where it is coming from.
+ bool try_deallocate_array(void* ptr, std::size_t n) noexcept
+ {
+ return try_deallocate_array(ptr, n, node_size());
+ }
+
+ /// \returns The size of each \concept{concept_node,node} in the pool,
+ /// this is either the same value as in the constructor or \c min_node_size if the value was too small.
+ std::size_t node_size() const noexcept
+ {
+ return free_list_.node_size();
+ }
+
+ /// \effects Returns the total amount of bytes remaining on the free list.
+ /// Divide it by \ref node_size() to get the number of nodes that can be allocated without growing the arena.
+ /// \note Array allocations may lead to a growth even if the capacity_left left is big enough.
+ std::size_t capacity_left() const noexcept
+ {
+ return free_list_.capacity() * node_size();
+ }
+
+ /// \returns The size of the next memory block after the free list gets empty and the arena grows.
+ /// \ref capacity_left() will increase by this amount.
+ /// \note Due to fence memory in debug mode this cannot be just divided by the \ref node_size() to get the number of nodes.
+ std::size_t next_capacity() const noexcept
+ {
+ return free_list_.usable_size(arena_.next_block_size());
+ }
+
+ /// \returns A reference to the \concept{concept_blockallocator,BlockAllocator} used for managing the arena.
+ /// \requires It is undefined behavior to move this allocator out into another object.
+ allocator_type& get_allocator() noexcept
+ {
+ return arena_.get_allocator();
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::memory_pool", this};
+ }
+
+ void allocate_block()
+ {
+ auto mem = arena_.allocate_block();
+ free_list_.insert(static_cast<char*>(mem.memory), mem.size);
+ }
+
+ void* allocate_array(std::size_t n, std::size_t node_size)
+ {
+ auto mem = free_list_.empty() ? nullptr : free_list_.allocate(n * node_size);
+ if (!mem)
+ {
+ allocate_block();
+ mem = free_list_.allocate(n * node_size);
+ if (!mem)
+ WPI_THROW(bad_array_size(info(), n * node_size, capacity_left()));
+ }
+ return mem;
+ }
+
+ void* try_allocate_array(std::size_t n, std::size_t node_size) noexcept
+ {
+ return !pool_type::value || free_list_.empty() ? nullptr :
+ free_list_.allocate(n * node_size);
+ }
+
+ bool try_deallocate_array(void* ptr, std::size_t n, std::size_t node_size) noexcept
+ {
+ if (!pool_type::value || !arena_.owns(ptr))
+ return false;
+ free_list_.deallocate(ptr, n * node_size);
+ return true;
+ }
+
+ memory_arena<allocator_type, false> arena_;
+ free_list free_list_;
+
+ friend allocator_traits<memory_pool<PoolType, BlockOrRawAllocator>>;
+ friend composable_allocator_traits<memory_pool<PoolType, BlockOrRawAllocator>>;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class memory_pool<node_pool>;
+ extern template class memory_pool<array_pool>;
+ extern template class memory_pool<small_node_pool>;
+#endif
+
+ template <class Type, class Alloc>
+ constexpr std::size_t memory_pool<Type, Alloc>::min_node_size;
+
+ /// Specialization of the \ref allocator_traits for \ref memory_pool classes.
+ /// \note It is not allowed to mix calls through the specialization and through the member functions,
+ /// i.e. \ref memory_pool::allocate_node() and this \c allocate_node().
+ /// \ingroup allocator
+ template <typename PoolType, class ImplRawAllocator>
+ class allocator_traits<memory_pool<PoolType, ImplRawAllocator>>
+ {
+ public:
+ using allocator_type = memory_pool<PoolType, ImplRawAllocator>;
+ using is_stateful = std::true_type;
+
+ /// \returns The result of \ref memory_pool::allocate_node().
+ /// \throws Anything thrown by the pool allocation function
+ /// or a \ref bad_allocation_size exception.
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ detail::check_allocation_size<bad_node_size>(size, max_node_size(state),
+ state.info());
+ detail::check_allocation_size<bad_alignment>(
+ alignment, [&] { return max_alignment(state); }, state.info());
+ auto mem = state.allocate_node();
+ state.on_allocate(size);
+ return mem;
+ }
+
+ /// \effects Forwards to \ref memory_pool::allocate_array()
+ /// with the number of nodes adjusted to be the minimum,
+ /// i.e. when the \c size is less than the \ref memory_pool::node_size().
+ /// \returns A \concept{concept_array,array} with specified properties.
+ /// \requires The \ref memory_pool has to support array allocations.
+ /// \throws Anything thrown by the pool allocation function.
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ detail::check_allocation_size<bad_node_size>(size, max_node_size(state),
+ state.info());
+ detail::check_allocation_size<bad_alignment>(
+ alignment, [&] { return max_alignment(state); }, state.info());
+ detail::check_allocation_size<bad_array_size>(count * size, max_array_size(state),
+ state.info());
+ auto mem = state.allocate_array(count, size);
+ state.on_allocate(count * size);
+ return mem;
+ }
+
+ /// \effects Just forwards to \ref memory_pool::deallocate_node().
+ static void deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t) noexcept
+ {
+ state.deallocate_node(node);
+ state.on_deallocate(size);
+ }
+
+ /// \effects Forwards to \ref memory_pool::deallocate_array() with the same size adjustment.
+ static void deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t) noexcept
+ {
+ state.free_list_.deallocate(array, count * size);
+ state.on_deallocate(count * size);
+ }
+
+ /// \returns The maximum size of each node which is \ref memory_pool::node_size().
+ static std::size_t max_node_size(const allocator_type& state) noexcept
+ {
+ return state.node_size();
+ }
+
+ /// \returns An upper bound on the maximum array size which is \ref memory_pool::next_capacity().
+ static std::size_t max_array_size(const allocator_type& state) noexcept
+ {
+ return state.next_capacity();
+ }
+
+ /// \returns The maximum alignment which is the next bigger power of two if less than \c alignof(std::max_align_t)
+ /// or the maximum alignment itself otherwise.
+ static std::size_t max_alignment(const allocator_type& state) noexcept
+ {
+ return state.free_list_.alignment();
+ }
+ };
+
+ /// Specialization of the \ref composable_allocator_traits for \ref memory_pool classes.
+ /// \ingroup allocator
+ template <typename PoolType, class BlockOrRawAllocator>
+ class composable_allocator_traits<memory_pool<PoolType, BlockOrRawAllocator>>
+ {
+ using traits = allocator_traits<memory_pool<PoolType, BlockOrRawAllocator>>;
+
+ public:
+ using allocator_type = memory_pool<PoolType, BlockOrRawAllocator>;
+
+ /// \returns The result of \ref memory_pool::try_allocate_node()
+ /// or `nullptr` if the allocation size was too big.
+ static void* try_allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (size > traits::max_node_size(state) || alignment > traits::max_alignment(state))
+ return nullptr;
+ return state.try_allocate_node();
+ }
+
+ /// \effects Forwards to \ref memory_pool::try_allocate_array()
+ /// with the number of nodes adjusted to be the minimum,
+ /// if the \c size is less than the \ref memory_pool::node_size().
+ /// \returns A \concept{concept_array,array} with specified properties
+ /// or `nullptr` if it was unable to allocate.
+ static void* try_allocate_array(allocator_type& state, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ if (size > traits::max_node_size(state)
+ || count * size > traits::max_array_size(state)
+ || alignment > traits::max_alignment(state))
+ return nullptr;
+ return state.try_allocate_array(count, size);
+ }
+
+ /// \effects Just forwards to \ref memory_pool::try_deallocate_node().
+ /// \returns Whether the deallocation was successful.
+ static bool try_deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (size > traits::max_node_size(state) || alignment > traits::max_alignment(state))
+ return false;
+ return state.try_deallocate_node(node);
+ }
+
+ /// \effects Forwards to \ref memory_pool::deallocate_array() with the same size adjustment.
+ /// \returns Whether the deallocation was successful.
+ static bool try_deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ if (size > traits::max_node_size(state)
+ || count * size > traits::max_array_size(state)
+ || alignment > traits::max_alignment(state))
+ return false;
+ return state.try_deallocate_array(array, count, size);
+ }
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<memory_pool<node_pool>>;
+ extern template class allocator_traits<memory_pool<array_pool>>;
+ extern template class allocator_traits<memory_pool<small_node_pool>>;
+
+ extern template class composable_allocator_traits<memory_pool<node_pool>>;
+ extern template class composable_allocator_traits<memory_pool<array_pool>>;
+ extern template class composable_allocator_traits<memory_pool<small_node_pool>>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_MEMORY_POOL_HPP_INCLUDED
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
new file mode 100644
index 0000000..294dd0a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_collection.hpp
@@ -0,0 +1,569 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_POOL_COLLECTION_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_POOL_COLLECTION_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::memory_pool_collection and related classes.
+
+#include <type_traits>
+
+#include "detail/align.hpp"
+#include "detail/assert.hpp"
+#include "detail/memory_stack.hpp"
+#include "detail/free_list_array.hpp"
+#include "config.hpp"
+#include "debugging.hpp"
+#include "error.hpp"
+#include "memory_arena.hpp"
+#include "memory_pool_type.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ struct memory_pool_collection_leak_handler
+ {
+ void operator()(std::ptrdiff_t amount);
+ };
+ } // namespace detail
+
+ /// A \c BucketDistribution for \ref memory_pool_collection defining that there is a bucket, i.e. pool, for each size.
+ /// That means that for each possible size up to an upper bound there will be a seperate free list.
+ /// Allocating a node will not waste any memory.
+ /// \ingroup allocator
+ struct identity_buckets
+ {
+ using type = detail::identity_access_policy;
+ };
+
+ /// A \c BucketDistribution for \ref memory_pool_collection defining that there is a bucket, i.e. pool, for each power of two.
+ /// That means for each power of two up to an upper bound there will be a separate free list.
+ /// Allocating a node will only waste half of the memory.
+ /// \ingroup allocator
+ struct log2_buckets
+ {
+ using type = detail::log2_access_policy;
+ };
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that behaves as a collection of multiple \ref memory_pool objects.
+ /// It maintains a list of multiple free lists, whose types are controlled via the \c PoolType tags defined in \ref memory_pool_type.hpp,
+ /// each of a different size as defined in the \c BucketDistribution (\ref identity_buckets or \ref log2_buckets).
+ /// Allocating a node of given size will use the appropriate free list.<br>
+ /// This allocator is ideal for \concept{concept_node,node} allocations in any order but with a predefined set of sizes,
+ /// not only one size like \ref memory_pool.
+ /// \ingroup allocator
+ template <class PoolType, class BucketDistribution,
+ class BlockOrRawAllocator = default_allocator>
+ class memory_pool_collection
+ : WPI_EBO(detail::default_leak_checker<detail::memory_pool_collection_leak_handler>)
+ {
+ using free_list_array =
+ detail::free_list_array<typename PoolType::type, typename BucketDistribution::type>;
+ using leak_checker =
+ detail::default_leak_checker<detail::memory_pool_collection_leak_handler>;
+
+ public:
+ using allocator_type = make_block_allocator_t<BlockOrRawAllocator>;
+ using pool_type = PoolType;
+ using bucket_distribution = BucketDistribution;
+
+ /// \effects Creates it by giving it the maximum node size it should be able to allocate,
+ /// 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.
+ template <typename... Args>
+ memory_pool_collection(std::size_t max_node_size, std::size_t block_size,
+ Args&&... args)
+ : arena_(block_size, detail::forward<Args>(args)...),
+ stack_(allocate_block()),
+ pools_(stack_, block_end(), max_node_size)
+ {
+ }
+
+ /// \effects Destroys the \ref memory_pool_collection by returning all memory blocks,
+ /// regardless of properly deallocated back to the \concept{concept_blockallocator,BlockAllocator}.
+ ~memory_pool_collection() noexcept = default;
+
+ /// @{
+ /// \effects Moving a \ref memory_pool_collection object transfers ownership over the free lists,
+ /// i.e. the moved from pool is completely empty and the new one has all its memory.
+ /// That means that it is not allowed to call \ref deallocate_node() on a moved-from allocator
+ /// even when passing it memory that was previously allocated by this object.
+ memory_pool_collection(memory_pool_collection&& other) noexcept
+ : leak_checker(detail::move(other)),
+ arena_(detail::move(other.arena_)),
+ stack_(detail::move(other.stack_)),
+ pools_(detail::move(other.pools_))
+ {
+ }
+
+ 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_);
+ return *this;
+ }
+ /// @}
+
+ /// \effects Allocates a \concept{concept_node,node} of given size.
+ /// It first finds the appropriate free list as defined in the \c BucketDistribution.
+ /// If it is empty, it will use an implementation defined amount of memory from the arena
+ /// and inserts it in it.
+ /// If the arena is empty too, it will request a new memory block from the \concept{concept_blockallocator,BlockAllocator}
+ /// of size \ref next_capacity() and puts part of it onto this free list.
+ /// Then it removes a node from it.
+ /// \returns A \concept{concept_node,node} of given size suitable aligned,
+ /// i.e. suitable for any type where <tt>sizeof(T) < node_size</tt>.
+ /// \throws Anything thrown by the \concept{concept_blockallocator,BlockAllocator} if a growth is needed or a \ref bad_node_size exception if the node size is too big.
+ void* allocate_node(std::size_t node_size)
+ {
+ detail::check_allocation_size<bad_node_size>(
+ node_size, [&] { return max_node_size(); }, info());
+ auto& pool = pools_.get(node_size);
+ if (pool.empty())
+ {
+ auto block = reserve_memory(pool, def_capacity());
+ pool.insert(block.memory, block.size);
+ }
+
+ auto mem = pool.allocate();
+ WPI_MEMORY_ASSERT(mem);
+ return mem;
+ }
+
+ /// \effects Allocates a \concept{concept_node,node} of given size.
+ /// It is similar to \ref allocate_node() but will return `nullptr` on any failure,
+ /// instead of growing the arnea and possibly throwing.
+ /// \returns A \concept{concept_node,node} of given size suitable aligned
+ /// or `nullptr` in case of failure.
+ void* try_allocate_node(std::size_t node_size) noexcept
+ {
+ if (node_size > max_node_size())
+ return nullptr;
+ auto& pool = pools_.get(node_size);
+ if (pool.empty())
+ {
+ try_reserve_memory(pool, def_capacity());
+ return pool.empty() ? nullptr : pool.allocate();
+ }
+ else
+ return pool.allocate();
+ }
+
+ /// \effects Allocates an \concept{concept_array,array} of nodes by searching for \c n continuous nodes on the appropriate free list and removing them.
+ /// Depending on the \c PoolType this can be a slow operation or not allowed at all.
+ /// This can sometimes lead to a growth on the free list, even if technically there is enough continuous memory on the free list.
+ /// Otherwise has the same behavior as \ref allocate_node().
+ /// \returns An array of \c n nodes of size \c node_size suitable aligned.
+ /// \throws Anything thrown by the used \concept{concept_blockallocator,BlockAllocator}'s allocation function if a growth is needed,
+ /// or a \ref bad_allocation_size exception.
+ /// \requires \c count must be valid \concept{concept_array,array count} and
+ /// \c node_size must be valid \concept{concept_node,node size}.
+ void* allocate_array(std::size_t count, std::size_t node_size)
+ {
+ detail::check_allocation_size<bad_node_size>(
+ node_size, [&] { return max_node_size(); }, info());
+
+ auto& pool = pools_.get(node_size);
+
+ // try allocating if not empty
+ // for pools without array allocation support, allocate() will always return nullptr
+ auto mem = pool.empty() ? nullptr : pool.allocate(count * node_size);
+ if (!mem)
+ {
+ // reserve more memory
+ auto block = reserve_memory(pool, def_capacity());
+ pool.insert(block.memory, block.size);
+
+ mem = pool.allocate(count * node_size);
+ if (!mem)
+ {
+ // reserve more then the default capacity if that didn't work either
+ detail::check_allocation_size<bad_array_size>(
+ count * node_size,
+ [&] { return next_capacity() - pool.alignment() + 1; }, info());
+
+ block = reserve_memory(pool, count * node_size);
+ pool.insert(block.memory, block.size);
+
+ mem = pool.allocate(count * node_size);
+ WPI_MEMORY_ASSERT(mem);
+ }
+ }
+
+ return mem;
+ }
+
+ /// \effects Allocates a \concept{concept_array,array} of given size.
+ /// It is similar to \ref allocate_node() but will return `nullptr` on any failure,
+ /// instead of growing the arnea and possibly throwing.
+ /// \returns A \concept{concept_array,array} of given size suitable aligned
+ /// or `nullptr` in case of failure.
+ void* try_allocate_array(std::size_t count, std::size_t node_size) noexcept
+ {
+ if (!pool_type::value || node_size > max_node_size())
+ return nullptr;
+ auto& pool = pools_.get(node_size);
+ if (pool.empty())
+ {
+ try_reserve_memory(pool, def_capacity());
+ return pool.empty() ? nullptr : pool.allocate(count * node_size);
+ }
+ else
+ return pool.allocate(count * node_size);
+ }
+
+ /// \effects Deallocates a \concept{concept_node,node} by putting it back onto the appropriate free list.
+ /// \requires \c ptr must be a result from a previous call to \ref allocate_node() with the same size on the same free list,
+ /// i.e. either this allocator object or a new object created by moving this to it.
+ void deallocate_node(void* ptr, std::size_t node_size) noexcept
+ {
+ pools_.get(node_size).deallocate(ptr);
+ }
+
+ /// \effects Deallocates a \concept{concept_node,node} similar to \ref deallocate_node().
+ /// But it checks if it can deallocate this memory.
+ /// \returns `true` if the node could be deallocated,
+ /// `false` otherwise.
+ bool try_deallocate_node(void* ptr, std::size_t node_size) noexcept
+ {
+ if (node_size > max_node_size() || !arena_.owns(ptr))
+ return false;
+ pools_.get(node_size).deallocate(ptr);
+ return true;
+ }
+
+ /// \effects Deallocates an \concept{concept_array,array} by putting it back onto the free list.
+ /// \requires \c ptr must be a result from a previous call to \ref allocate_array() with the same sizes on the same free list,
+ /// i.e. either this allocator object or a new object created by moving this to it.
+ void deallocate_array(void* ptr, std::size_t count, std::size_t node_size) noexcept
+ {
+ pools_.get(node_size).deallocate(ptr, count * node_size);
+ }
+
+ /// \effects Deallocates a \concept{concept_array,array} similar to \ref deallocate_array().
+ /// But it checks if it can deallocate this memory.
+ /// \returns `true` if the array could be deallocated,
+ /// `false` otherwise.
+ bool try_deallocate_array(void* ptr, std::size_t count, std::size_t node_size) noexcept
+ {
+ if (!pool_type::value || node_size > max_node_size() || !arena_.owns(ptr))
+ return false;
+ pools_.get(node_size).deallocate(ptr, count * node_size);
+ return true;
+ }
+
+ /// \effects Inserts more memory on the free list for nodes of given size.
+ /// It will try to put \c capacity_left bytes from the arena onto the free list defined over the \c BucketDistribution,
+ /// if the arena is empty, a new memory block is requested from the \concept{concept_blockallocator,BlockAllocator}
+ /// and it will be used.
+ /// \throws Anything thrown by the \concept{concept_blockallocator,BlockAllocator} if a growth is needed.
+ /// \requires \c node_size must be valid \concept{concept_node,node size} less than or equal to \ref max_node_size(),
+ /// \c capacity_left must be less than \ref next_capacity().
+ void reserve(std::size_t node_size, std::size_t capacity)
+ {
+ WPI_MEMORY_ASSERT_MSG(node_size <= max_node_size(), "node_size too big");
+ auto& pool = pools_.get(node_size);
+ reserve_memory(pool, capacity);
+ }
+
+ /// \returns The maximum node size for which is a free list.
+ /// This is the value passed to it in the constructor.
+ std::size_t max_node_size() const noexcept
+ {
+ return pools_.max_node_size();
+ }
+
+ /// \returns The amount of nodes available in the free list for nodes of given size
+ /// as defined over the \c BucketDistribution.
+ /// This is the number of nodes that can be allocated without the free list requesting more memory from the arena.
+ /// \note Array allocations may lead to a growth even if the capacity_left is big enough.
+ std::size_t pool_capacity_left(std::size_t node_size) const noexcept
+ {
+ WPI_MEMORY_ASSERT_MSG(node_size <= max_node_size(), "node_size too big");
+ return pools_.get(node_size).capacity();
+ }
+
+ /// \returns The amount of memory available in the arena not inside the free lists.
+ /// This is the number of bytes that can be inserted into the free lists
+ /// without requesting more memory from the \concept{concept_blockallocator,BlockAllocator}.
+ /// \note Array allocations may lead to a growth even if the capacity is big enough.
+ std::size_t capacity_left() const noexcept
+ {
+ return std::size_t(block_end() - stack_.top());
+ }
+
+ /// \returns The size of the next memory block after \ref capacity_left() arena grows.
+ /// This is the amount of memory that can be distributed in the pools.
+ /// \note If the `PoolType` is \ref small_node_pool, the exact usable memory is lower than that.
+ std::size_t next_capacity() const noexcept
+ {
+ return arena_.next_block_size();
+ }
+
+ /// \returns A reference to the \concept{concept_blockallocator,BlockAllocator} used for managing the arena.
+ /// \requires It is undefined behavior to move this allocator out into another object.
+ allocator_type& get_allocator() noexcept
+ {
+ return arena_.get_allocator();
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::memory_pool_collection", this};
+ }
+
+ std::size_t def_capacity() const noexcept
+ {
+ return arena_.next_block_size() / pools_.size();
+ }
+
+ detail::fixed_memory_stack allocate_block()
+ {
+ return detail::fixed_memory_stack(arena_.allocate_block().memory);
+ }
+
+ const char* block_end() const noexcept
+ {
+ auto block = arena_.current_block();
+ return static_cast<const char*>(block.memory) + block.size;
+ }
+
+ bool insert_rest(typename pool_type::type& pool) noexcept
+ {
+ if (auto remaining = std::size_t(block_end() - stack_.top()))
+ {
+ auto offset = detail::align_offset(stack_.top(), detail::max_alignment);
+ if (offset < remaining)
+ {
+ detail::debug_fill(stack_.top(), offset, debug_magic::alignment_memory);
+ pool.insert(stack_.top() + offset, remaining - offset);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void try_reserve_memory(typename pool_type::type& pool, std::size_t capacity) noexcept
+ {
+ auto mem = stack_.allocate(block_end(), capacity, detail::max_alignment);
+ if (!mem)
+ insert_rest(pool);
+ else
+ pool.insert(mem, capacity);
+ }
+
+ memory_block reserve_memory(typename pool_type::type& pool, std::size_t capacity)
+ {
+ auto mem = stack_.allocate(block_end(), capacity, detail::max_alignment);
+ if (!mem)
+ {
+ insert_rest(pool);
+ // get new block
+ stack_ = allocate_block();
+
+ // allocate ensuring alignment
+ mem = stack_.allocate(block_end(), capacity, detail::max_alignment);
+ WPI_MEMORY_ASSERT(mem);
+ }
+ return {mem, capacity};
+ }
+
+ memory_arena<allocator_type, false> arena_;
+ detail::fixed_memory_stack stack_;
+ free_list_array pools_;
+
+ friend allocator_traits<memory_pool_collection>;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class memory_pool_collection<node_pool, identity_buckets>;
+ extern template class memory_pool_collection<array_pool, identity_buckets>;
+ extern template class memory_pool_collection<small_node_pool, identity_buckets>;
+
+ extern template class memory_pool_collection<node_pool, log2_buckets>;
+ extern template class memory_pool_collection<array_pool, log2_buckets>;
+ extern template class memory_pool_collection<small_node_pool, log2_buckets>;
+#endif
+
+ /// An alias for \ref memory_pool_collection using the \ref identity_buckets policy
+ /// and a \c PoolType defaulting to \ref node_pool.
+ /// \ingroup allocator
+ template <class PoolType = node_pool, class ImplAllocator = default_allocator>
+ WPI_ALIAS_TEMPLATE(bucket_allocator,
+ memory_pool_collection<PoolType, identity_buckets, ImplAllocator>);
+
+ template <class Allocator>
+ class allocator_traits;
+
+ /// Specialization of the \ref allocator_traits for \ref memory_pool_collection classes.
+ /// \note It is not allowed to mix calls through the specialization and through the member functions,
+ /// i.e. \ref memory_pool_collection::allocate_node() and this \c allocate_node().
+ /// \ingroup allocator
+ template <class Pool, class BucketDist, class RawAllocator>
+ class allocator_traits<memory_pool_collection<Pool, BucketDist, RawAllocator>>
+ {
+ public:
+ using allocator_type = memory_pool_collection<Pool, BucketDist, RawAllocator>;
+ using is_stateful = std::true_type;
+
+ /// \returns The result of \ref memory_pool_collection::allocate_node().
+ /// \throws Anything thrown by the pool allocation function
+ /// or a \ref bad_allocation_size exception if \c size / \c alignment exceeds \ref max_node_size() / the suitable alignment value,
+ /// i.e. the node is over-aligned.
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ // node already checked
+ detail::check_allocation_size<bad_alignment>(
+ alignment, [&] { return detail::alignment_for(size); }, state.info());
+ auto mem = state.allocate_node(size);
+ state.on_allocate(size);
+ return mem;
+ }
+
+ /// \returns The result of \ref memory_pool_collection::allocate_array().
+ /// \throws Anything thrown by the pool allocation function or a \ref bad_allocation_size exception.
+ /// \requires The \ref memory_pool_collection has to support array allocations.
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ // node and array already checked
+ detail::check_allocation_size<bad_alignment>(
+ alignment, [&] { return detail::alignment_for(size); }, state.info());
+ auto mem = state.allocate_array(count, size);
+ state.on_allocate(count * size);
+ return mem;
+ }
+
+ /// \effects Calls \ref memory_pool_collection::deallocate_node().
+ static void deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t) noexcept
+ {
+ state.deallocate_node(node, size);
+ state.on_deallocate(size);
+ }
+
+ /// \effects Calls \ref memory_pool_collection::deallocate_array().
+ /// \requires The \ref memory_pool_collection has to support array allocations.
+ static void deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t) noexcept
+ {
+ state.deallocate_array(array, count, size);
+ state.on_deallocate(count * size);
+ }
+
+ /// \returns The maximum size of each node which is \ref memory_pool_collection::max_node_size().
+ static std::size_t max_node_size(const allocator_type& state) noexcept
+ {
+ return state.max_node_size();
+ }
+
+ /// \returns An upper bound on the maximum array size which is \ref memory_pool::next_capacity().
+ static std::size_t max_array_size(const allocator_type& state) noexcept
+ {
+ return state.next_capacity();
+ }
+
+ /// \returns Just \c alignof(std::max_align_t) since the actual maximum alignment depends on the node size,
+ /// the nodes must not be over-aligned.
+ static std::size_t max_alignment(const allocator_type&) noexcept
+ {
+ return detail::max_alignment;
+ }
+ };
+
+ /// Specialization of the \ref composable_allocator_traits for \ref memory_pool_collection classes.
+ /// \ingroup allocator
+ template <class Pool, class BucketDist, class RawAllocator>
+ class composable_allocator_traits<memory_pool_collection<Pool, BucketDist, RawAllocator>>
+ {
+ using traits = allocator_traits<memory_pool_collection<Pool, BucketDist, RawAllocator>>;
+
+ public:
+ using allocator_type = memory_pool_collection<Pool, BucketDist, RawAllocator>;
+
+ /// \returns The result of \ref memory_pool_collection::try_allocate_node()
+ /// or `nullptr` if the allocation size was too big.
+ static void* try_allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (alignment > traits::max_alignment(state))
+ return nullptr;
+ return state.try_allocate_node(size);
+ }
+
+ /// \returns The result of \ref memory_pool_collection::try_allocate_array()
+ /// or `nullptr` if the allocation size was too big.
+ static void* try_allocate_array(allocator_type& state, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ if (count * size > traits::max_array_size(state)
+ || alignment > traits::max_alignment(state))
+ return nullptr;
+ return state.try_allocate_array(count, size);
+ }
+
+ /// \effects Just forwards to \ref memory_pool_collection::try_deallocate_node().
+ /// \returns Whether the deallocation was successful.
+ static bool try_deallocate_node(allocator_type& state, void* node, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (alignment > traits::max_alignment(state))
+ return false;
+ return state.try_deallocate_node(node, size);
+ }
+
+ /// \effects Forwards to \ref memory_pool_collection::deallocate_array().
+ /// \returns Whether the deallocation was successful.
+ static bool try_deallocate_array(allocator_type& state, void* array, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ if (count * size > traits::max_array_size(state)
+ || alignment > traits::max_alignment(state))
+ return false;
+ return state.try_deallocate_array(array, count, size);
+ }
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<memory_pool_collection<node_pool, identity_buckets>>;
+ extern template class allocator_traits<
+ memory_pool_collection<array_pool, identity_buckets>>;
+ extern template class allocator_traits<
+ memory_pool_collection<small_node_pool, identity_buckets>>;
+
+ extern template class allocator_traits<memory_pool_collection<node_pool, log2_buckets>>;
+ extern template class allocator_traits<memory_pool_collection<array_pool, log2_buckets>>;
+ extern template class allocator_traits<
+ memory_pool_collection<small_node_pool, log2_buckets>>;
+
+ extern template class composable_allocator_traits<
+ memory_pool_collection<node_pool, identity_buckets>>;
+ extern template class composable_allocator_traits<
+ memory_pool_collection<array_pool, identity_buckets>>;
+ extern template class composable_allocator_traits<
+ memory_pool_collection<small_node_pool, identity_buckets>>;
+
+ extern template class composable_allocator_traits<
+ memory_pool_collection<node_pool, log2_buckets>>;
+ extern template class composable_allocator_traits<
+ memory_pool_collection<array_pool, log2_buckets>>;
+ extern template class composable_allocator_traits<
+ memory_pool_collection<small_node_pool, log2_buckets>>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_MEMORY_POOL_COLLECTION_HPP_INCLUDED
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
new file mode 100644
index 0000000..a7c8ff8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_pool_type.hpp
@@ -0,0 +1,53 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_POOL_TYPE_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_POOL_TYPE_HPP_INCLUDED
+
+/// \file
+/// The \c PoolType tag types.
+
+#include <type_traits>
+
+#include "detail/free_list.hpp"
+#include "detail/small_free_list.hpp"
+#include "config.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// Tag type defining a memory pool optimized for nodes.
+ /// It does not support array allocations that great and may trigger a growth even if there is enough memory.
+ /// But it is the fastest pool type.
+ /// \ingroup allocator
+ struct node_pool : WPI_EBO(std::true_type)
+ {
+ using type = detail::node_free_memory_list;
+ };
+
+ /// 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.
+ /// 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!
+ /// \ingroup allocator
+ struct array_pool : WPI_EBO(std::true_type)
+ {
+ using type = detail::array_free_memory_list;
+ };
+
+ /// Tag type defining a memory pool optimized for small nodes.
+ /// The free list is intrusive and thus requires that each node has at least the size of a pointer.
+ /// This tag type does not have this requirement and thus allows zero-memory-overhead allocations of small nodes.
+ /// It is a little bit slower than \ref node_pool and does not support arrays.
+ /// \ingroup allocator
+ struct small_node_pool : WPI_EBO(std::false_type)
+ {
+ using type = detail::small_free_memory_list;
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_MEMORY_POOL_TYPE_HPP_INCLUDED
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
new file mode 100644
index 0000000..e805f9b
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_resource_adapter.hpp
@@ -0,0 +1,239 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_RESOURCE_ADAPTER_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_RESOURCE_ADAPTER_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::memory_resource_adapter and \ref wpi::memory::memory_resource_allocator to allow usage of PMRs.
+
+#include "detail/assert.hpp"
+#include "detail/utility.hpp"
+#include "config.hpp"
+#include "allocator_traits.hpp"
+
+#if defined(__has_include) && __has_include(<memory_resource>)
+
+#if !defined(__GNUC__) || __cplusplus >= 201703L
+// The experimental/memory_resource header lacks a check for C++17 on older GCC,
+// so we have to do it for them.
+#include <memory_resource>
+#endif
+
+#elif defined(__has_include) && __has_include(<experimental/memory_resource>)
+
+#if !defined(__GNUC__) || __cplusplus >= 201402L
+// The experimental/memory_resource header lacks a check for C++14 on older GCC,
+// so we have to do it for them.
+#include <experimental/memory_resource>
+#endif
+
+#endif
+
+#if defined(__cpp_lib_memory_resource)
+
+// We use std::pmr::memory_resource.
+namespace wpi_memory_pmr = std::pmr;
+
+#elif defined(__cpp_lib_experimental_memory_resources)
+
+// We use std::experimental::pmr::memory_resource.
+namespace wpi_memory_pmr = std::experimental::pmr;
+
+#else
+
+// We use our own implementation.
+namespace wpi_memory_pmr
+{
+ // see N3916 for documentation
+ class memory_resource
+ {
+ static const std::size_t max_alignment = alignof(std::max_align_t);
+
+ public:
+ virtual ~memory_resource() noexcept {}
+ void* allocate(std::size_t bytes, std::size_t alignment = max_alignment)
+ {
+ return do_allocate(bytes, alignment);
+ }
+ void deallocate(void* p, std::size_t bytes, std::size_t alignment = max_alignment)
+ {
+ do_deallocate(p, bytes, alignment);
+ }
+ bool is_equal(const memory_resource& other) const noexcept
+ {
+ return do_is_equal(other);
+ }
+
+ protected:
+ virtual void* do_allocate(std::size_t bytes, std::size_t alignment) = 0;
+ virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) = 0;
+ virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
+ };
+ inline bool operator==(const memory_resource& a, const memory_resource& b) noexcept
+ {
+ return &a == &b || a.is_equal(b);
+ }
+ inline bool operator!=(const memory_resource& a, const memory_resource& b) noexcept
+ {
+ return !(a == b);
+ }
+} // namespace wpi_memory_pmr
+
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// The \c memory_resource abstract base class used in the implementation.
+ /// \ingroup adapter
+ WPI_ALIAS_TEMPLATE(memory_resource, foonathan_memory_pmr::memory_resource);
+
+ /// Wraps a \concept{concept_rawallocator,RawAllocator} and makes it a \ref memory_resource.
+ /// \ingroup adapter
+ template <class RawAllocator>
+ class memory_resource_adapter
+ : public memory_resource,
+ WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+
+ /// \effects Creates the resource by moving in the allocator.
+ memory_resource_adapter(allocator_type&& other) noexcept
+ : allocator_type(detail::move(other))
+ {
+ }
+
+ /// @{
+ /// \returns A reference to the wrapped allocator.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ protected:
+ using traits_type = allocator_traits<RawAllocator>;
+
+ /// \effects Allocates raw memory with given size and alignment.
+ /// It forwards to \c allocate_node() or \c allocate_array() depending on the size.
+ /// \returns The new memory as returned by the \concept{concept_rawallocator,RawAllocator}.
+ /// \throws Anything thrown by the allocation function.
+ void* do_allocate(std::size_t bytes, std::size_t alignment) override
+ {
+ auto max = traits_type::max_node_size(*this);
+ if (bytes <= max)
+ return traits_type::allocate_node(*this, bytes, alignment);
+ auto div = bytes / max;
+ auto mod = bytes % max;
+ auto n = div + (mod != 0);
+ return traits_type::allocate_array(*this, n, max, alignment);
+ }
+
+ /// \effects Deallocates memory previously allocated by \ref do_allocate.
+ /// It forwards to \c deallocate_node() or \c deallocate_array() depending on the size.
+ /// \throws Nothing.
+ void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) override
+ {
+ auto max = traits_type::max_node_size(*this);
+ if (bytes <= max)
+ traits_type::deallocate_node(*this, p, bytes, alignment);
+ else
+ {
+ auto div = bytes / max;
+ auto mod = bytes % max;
+ auto n = div + (mod != 0);
+ traits_type::deallocate_array(*this, p, n, max, alignment);
+ }
+ }
+
+ /// \returns Whether or not \c *this is equal to \c other
+ /// by comparing the addresses.
+ bool do_is_equal(const memory_resource& other) const noexcept override
+ {
+ return this == &other;
+ }
+ };
+
+ /// Wraps a \ref memory_resource and makes it a \concept{concept_rawallocator,RawAllocator}.
+ /// \ingroup adapter
+ class memory_resource_allocator
+ {
+ public:
+ /// \effects Creates it by giving it a pointer to the \ref memory_resource.
+ /// \requires \c ptr must not be \c nullptr.
+ memory_resource_allocator(memory_resource* ptr) noexcept : ptr_(ptr)
+ {
+ WPI_MEMORY_ASSERT(ptr);
+ }
+
+ /// \effects Allocates a node by forwarding to the \c allocate() function.
+ /// \returns The node as returned by the \ref memory_resource.
+ /// \throws Anything thrown by the \c allocate() function.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ return ptr_->allocate(size, alignment);
+ }
+
+ /// \effects Deallocates a node by forwarding to the \c deallocate() function.
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ ptr_->deallocate(ptr, size, alignment);
+ }
+
+ /// \returns The maximum alignment which is the maximum value of type \c std::size_t.
+ std::size_t max_alignment() const noexcept
+ {
+ return std::size_t(-1);
+ }
+
+ /// \returns A pointer to the used \ref memory_resource, this is never \c nullptr.
+ memory_resource* resource() const noexcept
+ {
+ return ptr_;
+ }
+
+ private:
+ memory_resource* ptr_;
+ };
+
+ /// @{
+ /// \returns Whether `lhs` and `rhs` share the same resource.
+ /// \relates memory_resource_allocator
+ inline bool operator==(const memory_resource_allocator& lhs,
+ const memory_resource_allocator& rhs) noexcept
+ {
+ return lhs.resource() == rhs.resource();
+ }
+
+ inline bool operator!=(const memory_resource_allocator& lhs,
+ const memory_resource_allocator& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+ /// @}
+
+#if !defined(DOXYGEN)
+ template <class RawAllocator>
+ struct is_shared_allocator;
+#endif
+
+ /// Specialization of \ref is_shared_allocator to mark \ref memory_resource_allocator as shared.
+ /// This allows using it as \ref allocator_reference directly.
+ /// \ingroup adapter
+ template <>
+ struct is_shared_allocator<memory_resource_allocator> : std::true_type
+ {
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..4c9f524
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/memory_stack.hpp
@@ -0,0 +1,489 @@
+// 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.
+
+#ifndef WPI_MEMORY_MEMORY_STACK_HPP_INCLUDED
+#define WPI_MEMORY_MEMORY_STACK_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::memory_stack and its \ref wpi::memory::allocator_traits specialization.
+
+// Inform that wpi::memory::memory_stack::min_block_size API is available
+#define WPI_MEMORY_MEMORY_STACK_HAS_MIN_BLOCK_SIZE
+
+#include <cstdint>
+#include <type_traits>
+
+#include "detail/assert.hpp"
+#include "detail/memory_stack.hpp"
+#include "config.hpp"
+#include "error.hpp"
+#include "memory_arena.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+#if !defined(DOXYGEN)
+ template <class Impl>
+ class memory_stack;
+#endif
+
+ namespace detail
+ {
+ class stack_marker
+ {
+ std::size_t index;
+ char* top;
+ const char* end;
+
+ stack_marker(std::size_t i, const detail::fixed_memory_stack& s,
+ const char* e) noexcept
+ : index(i), top(s.top()), end(e)
+ {
+ }
+
+ friend bool operator==(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ if (lhs.index != rhs.index)
+ return false;
+ WPI_MEMORY_ASSERT_MSG(lhs.end == rhs.end, "you must not compare two "
+ "stack markers from different "
+ "stacks");
+ return lhs.top == rhs.top;
+ }
+
+ friend bool operator!=(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ return !(rhs == lhs);
+ }
+
+ friend bool operator<(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ if (lhs.index != rhs.index)
+ return lhs.index < rhs.index;
+ WPI_MEMORY_ASSERT_MSG(lhs.end == rhs.end, "you must not compare two "
+ "stack markers from different "
+ "stacks");
+ return lhs.top < rhs.top;
+ }
+
+ friend bool operator>(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ return rhs < lhs;
+ }
+
+ friend bool operator<=(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ return !(rhs < lhs);
+ }
+
+ friend bool operator>=(const stack_marker& lhs, const stack_marker& rhs) noexcept
+ {
+ return !(lhs < rhs);
+ }
+
+ template <class Impl>
+ friend class memory::memory_stack;
+ };
+
+ struct memory_stack_leak_handler
+ {
+ void operator()(std::ptrdiff_t amount);
+ };
+ } // namespace detail
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that provides stack-like (LIFO) allocations.
+ /// It uses a \ref memory_arena with a given \c BlockOrRawAllocator defaulting to \ref growing_block_allocator to allocate huge blocks
+ /// and saves a marker to the current top.
+ /// Allocation simply moves this marker by the appropriate number of bytes and returns the pointer at the old marker position,
+ /// deallocation is not directly supported, only setting the marker to a previously queried position.
+ /// \ingroup allocator
+ template <class BlockOrRawAllocator = default_allocator>
+ class memory_stack
+ : WPI_EBO(detail::default_leak_checker<detail::memory_stack_leak_handler>)
+ {
+ public:
+ using allocator_type = make_block_allocator_t<BlockOrRawAllocator>;
+
+ /// \returns The minimum block size required for a stack containing the given amount of memory.
+ /// If a stack is created with the result of `min_block_size(n)`, the resulting capacity will be exactly `n`.
+ /// \requires `byte_size` must be a positive number.
+ /// \note Due to debug fence sizes, the actual amount of usable memory can vary.
+ /// However, this is impossible to compute without knowing the exact allocation pattern before,
+ /// so this is just a rough estimate.
+ static constexpr std::size_t min_block_size(std::size_t byte_size) noexcept
+ {
+ return detail::memory_block_stack::implementation_offset() + byte_size;
+ }
+
+ /// \effects Creates it with a given initial block size and and other constructor arguments for the \concept{concept_blockallocator,BlockAllocator}.
+ /// It will allocate the first block and sets the top to its beginning.
+ /// \requires \c block_size must be at least \c min_block_size(1).
+ template <typename... Args>
+ explicit memory_stack(std::size_t block_size, Args&&... args)
+ : arena_(block_size, detail::forward<Args>(args)...),
+ stack_(arena_.allocate_block().memory)
+ {
+ }
+
+ /// \effects Allocates a memory block of given size and alignment.
+ /// It simply moves the top marker.
+ /// If there is not enough space on the current memory block,
+ /// a new one will be allocated by the \concept{concept_blockallocator,BlockAllocator} or taken from a cache
+ /// and used for the allocation.
+ /// \returns A \concept{concept_node,node} with given size and alignment.
+ /// \throws Anything thrown by the \concept{concept_blockallocator,BlockAllocator} on growth
+ /// or \ref bad_allocation_size if \c size is too big.
+ /// \requires \c size and \c alignment must be valid.
+ void* allocate(std::size_t size, std::size_t alignment)
+ {
+ auto fence = detail::debug_fence_size;
+ auto offset = detail::align_offset(stack_.top() + fence, alignment);
+
+ if (!stack_.top()
+ || fence + offset + size + fence > std::size_t(block_end() - stack_.top()))
+ {
+ // need to grow
+ auto block = arena_.allocate_block();
+ stack_ = detail::fixed_memory_stack(block.memory);
+
+ // new alignment required for over-aligned types
+ offset = detail::align_offset(stack_.top() + fence, alignment);
+
+ auto needed = fence + offset + size + fence;
+ detail::check_allocation_size<bad_allocation_size>(needed, block.size, info());
+ }
+
+ return stack_.allocate_unchecked(size, offset);
+ }
+
+ /// \effects Allocates a memory block of given size and alignment,
+ /// similar to \ref allocate().
+ /// But it does not attempt a growth if the arena is empty.
+ /// \returns A \concept{concept_node,node} with given size and alignment
+ /// or `nullptr` if there wasn't enough memory available.
+ void* try_allocate(std::size_t size, std::size_t alignment) noexcept
+ {
+ return stack_.allocate(block_end(), size, alignment);
+ }
+
+ /// The marker type that is used for unwinding.
+ /// The exact type is implementation defined,
+ /// it is only required that it is efficiently copyable
+ /// and has all the comparision operators defined for two markers on the same stack.
+ /// Two markers are equal, if they are copies or created from two `top()` calls without a call to `unwind()` or `allocate()`.
+ /// A marker `a` is less than marker `b`, if after `a` was obtained, there was one or more call to `allocate()` and no call to `unwind()`.
+ using marker = WPI_IMPL_DEFINED(detail::stack_marker);
+
+ /// \returns A marker to the current top of the stack.
+ marker top() const noexcept
+ {
+ return {arena_.size() - 1, stack_, block_end()};
+ }
+
+ /// \effects Unwinds the stack to a certain marker position.
+ /// This sets the top pointer of the stack to the position described by the marker
+ /// and has the effect of deallocating all memory allocated since the marker was obtained.
+ /// If any memory blocks are unused after the operation,
+ /// they are not deallocated but put in a cache for later use,
+ /// call \ref shrink_to_fit() to actually deallocate them.
+ /// \requires The marker must point to memory that is still in use and was the whole time,
+ /// i.e. it must have been pointed below the top at all time.
+ void unwind(marker m) noexcept
+ {
+ WPI_MEMORY_ASSERT(m <= top());
+ detail::debug_check_pointer([&] { return m.index <= arena_.size() - 1; }, info(),
+ m.top);
+
+ if (std::size_t to_deallocate = (arena_.size() - 1) - m.index) // different index
+ {
+ arena_.deallocate_block();
+ for (std::size_t i = 1; i != to_deallocate; ++i)
+ arena_.deallocate_block();
+
+ detail::debug_check_pointer(
+ [&] {
+ auto cur = arena_.current_block();
+ return m.end == static_cast<char*>(cur.memory) + cur.size;
+ },
+ info(), m.top);
+
+ // mark memory from new top to end of the block as freed
+ detail::debug_fill_free(m.top, std::size_t(m.end - m.top), 0);
+ stack_ = detail::fixed_memory_stack(m.top);
+ }
+ else // same index
+ {
+ detail::debug_check_pointer([&] { return stack_.top() >= m.top; }, info(),
+ m.top);
+ stack_.unwind(m.top);
+ }
+ }
+
+ /// \effects \ref unwind() does not actually do any deallocation of blocks on the \concept{concept_blockallocator,BlockAllocator},
+ /// unused memory is stored in a cache for later reuse.
+ /// This function clears that cache.
+ void shrink_to_fit() noexcept
+ {
+ arena_.shrink_to_fit();
+ }
+
+ /// \returns The amount of memory remaining in the current block.
+ /// This is the number of bytes that are available for allocation
+ /// before the cache or \concept{concept_blockallocator,BlockAllocator} needs to be used.
+ std::size_t capacity_left() const noexcept
+ {
+ return std::size_t(block_end() - stack_.top());
+ }
+
+ /// \returns The size of the next memory block after the current block is exhausted and the arena grows.
+ /// This function just forwards to the \ref memory_arena.
+ /// \note All of it is available for the stack to use, but due to fences and alignment buffers,
+ /// this may not be the exact amount of memory usable for the user.
+ std::size_t next_capacity() const noexcept
+ {
+ return arena_.next_block_size();
+ }
+
+ /// \returns A reference to the \concept{concept_blockallocator,BlockAllocator} used for managing the arena.
+ /// \requires It is undefined behavior to move this allocator out into another object.
+ allocator_type& get_allocator() noexcept
+ {
+ return arena_.get_allocator();
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::memory_stack", this};
+ }
+
+ const char* block_end() const noexcept
+ {
+ auto block = arena_.current_block();
+ return static_cast<const char*>(block.memory) + block.size;
+ }
+
+ memory_arena<allocator_type> arena_;
+ detail::fixed_memory_stack stack_;
+
+ friend allocator_traits<memory_stack<BlockOrRawAllocator>>;
+ friend composable_allocator_traits<memory_stack<BlockOrRawAllocator>>;
+ };
+
+ /// Simple utility that automatically unwinds a `Stack` to a previously saved location.
+ /// A `Stack` is anything that provides a `marker`, a `top()` function returning a `marker`
+ /// and an `unwind()` function to unwind to a `marker`,
+ /// like a \ref wpi::memory::memory_stack
+ /// \ingroup allocator
+ template <class Stack = memory_stack<>>
+ class memory_stack_raii_unwind
+ {
+ public:
+ using stack_type = Stack;
+ using marker_type = typename stack_type::marker;
+
+ /// \effects Same as `memory_stack_raii_unwind(stack, stack.top())`.
+ explicit memory_stack_raii_unwind(stack_type& stack) noexcept
+ : memory_stack_raii_unwind(stack, stack.top())
+ {
+ }
+
+ /// \effects Creates the unwinder by giving it the stack and the marker.
+ /// \requires The stack must live longer than this object.
+ memory_stack_raii_unwind(stack_type& stack, marker_type marker) noexcept
+ : marker_(marker), stack_(&stack)
+ {
+ }
+
+ /// \effects Move constructs the unwinder by taking the saved position from `other`.
+ /// `other.will_unwind()` will return `false` after it.
+ memory_stack_raii_unwind(memory_stack_raii_unwind&& other) noexcept
+ : marker_(other.marker_), stack_(other.stack_)
+ {
+ other.stack_ = nullptr;
+ }
+
+ /// \effects Unwinds to the previously saved location,
+ /// if there is any, by calling `unwind()`.
+ ~memory_stack_raii_unwind() noexcept
+ {
+ if (stack_)
+ stack_->unwind(marker_);
+ }
+
+ /// \effects Move assigns the unwinder by taking the saved position from `other`.
+ /// `other.will_unwind()` will return `false` after it.
+ memory_stack_raii_unwind& operator=(memory_stack_raii_unwind&& other) noexcept
+ {
+ if (stack_)
+ stack_->unwind(marker_);
+
+ marker_ = other.marker_;
+ stack_ = other.stack_;
+
+ other.stack_ = nullptr;
+
+ return *this;
+ }
+
+ /// \effects Removes the location without unwinding it.
+ /// `will_unwind()` will return `false`.
+ void release() noexcept
+ {
+ stack_ = nullptr;
+ }
+
+ /// \effects Unwinds to the saved location explictly.
+ /// \requires `will_unwind()` must return `true`.
+ void unwind() noexcept
+ {
+ WPI_MEMORY_ASSERT(will_unwind());
+ stack_->unwind(marker_);
+ }
+
+ /// \returns Whether or not the unwinder will actually unwind.
+ /// \note It will not unwind if it is in the moved-from state.
+ bool will_unwind() const noexcept
+ {
+ return stack_ != nullptr;
+ }
+
+ /// \returns The saved marker, if there is any.
+ /// \requires `will_unwind()` must return `true`.
+ marker_type get_marker() const noexcept
+ {
+ WPI_MEMORY_ASSERT(will_unwind());
+ return marker_;
+ }
+
+ /// \returns The stack it will unwind.
+ /// \requires `will_unwind()` must return `true`.
+ stack_type& get_stack() const noexcept
+ {
+ WPI_MEMORY_ASSERT(will_unwind());
+ return *stack_;
+ }
+
+ private:
+ marker_type marker_;
+ stack_type* stack_;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class memory_stack<>;
+ extern template class memory_stack_raii_unwind<memory_stack<>>;
+#endif
+
+ /// Specialization of the \ref allocator_traits for \ref memory_stack classes.
+ /// \note It is not allowed to mix calls through the specialization and through the member functions,
+ /// i.e. \ref memory_stack::allocate() and this \c allocate_node().
+ /// \ingroup allocator
+ template <class BlockAllocator>
+ class allocator_traits<memory_stack<BlockAllocator>>
+ {
+ public:
+ using allocator_type = memory_stack<BlockAllocator>;
+ using is_stateful = std::true_type;
+
+ /// \returns The result of \ref memory_stack::allocate().
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ auto mem = state.allocate(size, alignment);
+ state.on_allocate(size);
+ return mem;
+ }
+
+ /// \returns The result of \ref memory_stack::allocate().
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ return allocate_node(state, count * size, alignment);
+ }
+
+ /// @{
+ /// \effects Does nothing besides bookmarking for leak checking, if that is enabled.
+ /// Actual deallocation can only be done via \ref memory_stack::unwind().
+ static void deallocate_node(allocator_type& state, void*, std::size_t size,
+ std::size_t) noexcept
+ {
+ state.on_deallocate(size);
+ }
+
+ static void deallocate_array(allocator_type& state, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ deallocate_node(state, ptr, count * size, alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \returns The maximum size which is \ref memory_stack::next_capacity().
+ static std::size_t max_node_size(const allocator_type& state) noexcept
+ {
+ return state.next_capacity();
+ }
+
+ static std::size_t max_array_size(const allocator_type& state) noexcept
+ {
+ return state.next_capacity();
+ }
+ /// @}
+
+ /// \returns The maximum possible value since there is no alignment restriction
+ /// (except indirectly through \ref memory_stack::next_capacity()).
+ static std::size_t max_alignment(const allocator_type&) noexcept
+ {
+ return std::size_t(-1);
+ }
+ };
+
+ /// Specialization of the \ref composable_allocator_traits for \ref memory_stack classes.
+ /// \ingroup allocator
+ template <class BlockAllocator>
+ class composable_allocator_traits<memory_stack<BlockAllocator>>
+ {
+ public:
+ using allocator_type = memory_stack<BlockAllocator>;
+
+ /// \returns The result of \ref memory_stack::try_allocate().
+ static void* try_allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ return state.try_allocate(size, alignment);
+ }
+
+ /// \returns The result of \ref memory_stack::try_allocate().
+ static void* try_allocate_array(allocator_type& state, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return state.try_allocate(count * size, alignment);
+ }
+
+ /// @{
+ /// \effects Does nothing.
+ /// \returns Whether the memory will be deallocated by \ref memory_stack::unwind().
+ static bool try_deallocate_node(allocator_type& state, void* ptr, std::size_t,
+ std::size_t) noexcept
+ {
+ return state.arena_.owns(ptr);
+ }
+
+ static bool try_deallocate_array(allocator_type& state, void* ptr, std::size_t count,
+ std::size_t size, std::size_t alignment) noexcept
+ {
+ return try_deallocate_node(state, ptr, count * size, alignment);
+ }
+ /// @}
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<memory_stack<>>;
+ extern template class composable_allocator_traits<memory_stack<>>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_MEMORY_STACK_HPP_INCLUDED
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
new file mode 100644
index 0000000..bf2b95d
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/namespace_alias.hpp
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef WPI_MEMORY_NAMESPACE_ALIAS_HPP_INCLUDED
+#define WPI_MEMORY_NAMESPACE_ALIAS_HPP_INCLUDED
+
+/// \file
+/// Convenient namespace alias.
+
+/// \defgroup core Core components
+
+/// \defgroup allocator Allocator implementations
+
+/// \defgroup adapter Adapters and Wrappers
+
+/// \defgroup storage Allocator storage
+
+/// \namespace wpi
+/// Foonathan namespace.
+
+/// \namespace wpi::memory
+/// Memory namespace.
+
+/// \namespace wpi::memory::literals
+/// Literals namespace.
+
+namespace wpi
+{
+ namespace memory
+ {
+ }
+} // namespace wpi
+
+namespace memory = wpi::memory;
+
+#endif // 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
new file mode 100644
index 0000000..8e24f2f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/new_allocator.hpp
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef WPI_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_NEW_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::new_allocator.
+
+#include "detail/lowlevel_allocator.hpp"
+#include "config.hpp"
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+#include "allocator_traits.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ struct allocator_info;
+
+ namespace detail
+ {
+ struct new_allocator_impl
+ {
+ static allocator_info info() noexcept;
+
+ static void* allocate(std::size_t size, std::size_t) noexcept;
+
+ static void deallocate(void* ptr, std::size_t size, std::size_t) noexcept;
+
+ static std::size_t max_node_size() noexcept;
+ };
+
+ WPI_MEMORY_LL_ALLOCATOR_LEAK_CHECKER(new_allocator_impl,
+ new_alloator_leak_checker)
+ } // namespace detail
+
+ /// A stateless \concept{concept_rawallocator,RawAllocator} that allocates memory using (nothrow) <tt>operator new</tt>.
+ /// If the operator returns \c nullptr, it behaves like \c new and loops calling \c std::new_handler,
+ /// but instead of throwing a \c std::bad_alloc exception, it throws \ref out_of_memory.
+ /// \ingroup allocator
+ using new_allocator =
+ WPI_IMPL_DEFINED(detail::lowlevel_allocator<detail::new_allocator_impl>);
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class detail::lowlevel_allocator<detail::new_allocator_impl>;
+ extern template class allocator_traits<new_allocator>;
+#endif
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..fcd02ac
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/segregator.hpp
@@ -0,0 +1,448 @@
+// 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.
+
+#ifndef WPI_MEMORY_SEGREGATOR_HPP_INCLUDED
+#define WPI_MEMORY_SEGREGATOR_HPP_INCLUDED
+
+/// \file
+/// Class template \ref wpi::memory::segregator and related classes.
+
+#include "detail/ebo_storage.hpp"
+#include "detail/utility.hpp"
+#include "allocator_traits.hpp"
+#include "config.hpp"
+#include "error.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A \concept{concept_segregatable,Segregatable} that allocates until a maximum size.
+ /// \ingroup adapter
+ template <class RawAllocator>
+ class threshold_segregatable : WPI_EBO(allocator_traits<RawAllocator>::allocator_type)
+ {
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+
+ /// \effects Creates it by passing the maximum size it will allocate
+ /// and the allocator it uses.
+ explicit threshold_segregatable(std::size_t max_size,
+ allocator_type alloc = allocator_type())
+ : allocator_type(detail::move(alloc)), max_size_(max_size)
+ {
+ }
+
+ /// \returns `true` if `size` is less then or equal to the maximum size,
+ /// `false` otherwise.
+ /// \note A return value of `true` means that the allocator will be used for the allocation.
+ bool use_allocate_node(std::size_t size, std::size_t) noexcept
+ {
+ return size <= max_size_;
+ }
+
+ /// \returns `true` if `count * size` is less then or equal to the maximum size,
+ /// `false` otherwise.
+ /// \note A return value of `true` means that the allocator will be used for the allocation.
+ bool use_allocate_array(std::size_t count, std::size_t size, std::size_t) noexcept
+ {
+ return count * size <= max_size_;
+ }
+
+ /// @{
+ /// \returns A reference to the allocator it owns.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ private:
+ std::size_t max_size_;
+ };
+
+ /// \returns A \ref threshold_segregatable with the same parameter.
+ template <class RawAllocator>
+ threshold_segregatable<typename std::decay<RawAllocator>::type> threshold(
+ std::size_t max_size, RawAllocator&& alloc)
+ {
+ return threshold_segregatable<
+ typename std::decay<RawAllocator>::type>(max_size,
+ std::forward<RawAllocator>(alloc));
+ }
+
+ /// A composable \concept{concept_rawallocator,RawAllocator} that will always fail.
+ /// This is useful for compositioning or as last resort in \ref binary_segregator.
+ /// \ingroup allocator
+ class null_allocator
+ {
+ public:
+ /// \effects Will always throw.
+ /// \throws A \ref out_of_fixed_memory exception.
+ void* allocate_node(std::size_t size, std::size_t)
+ {
+ throw out_of_fixed_memory(info(), size);
+ }
+
+ /// \requires Must not be called.
+ void deallocate_node(void*, std::size_t, std::size_t) noexcept
+ {
+ WPI_MEMORY_UNREACHABLE("cannot be called with proper values");
+ }
+
+ /// \effects Does nothing.
+ /// \returns Always returns `nullptr`.
+ void* try_allocate_node(std::size_t, std::size_t) noexcept
+ {
+ return nullptr;
+ }
+
+ /// \effects Does nothing.
+ /// \returns Always returns `false`.
+ bool try_deallocate_node(void*, std::size_t, std::size_t) noexcept
+ {
+ return false;
+ }
+
+ private:
+ allocator_info info() const noexcept
+ {
+ return {WPI_MEMORY_LOG_PREFIX "::null_allocator", this};
+ }
+ };
+
+ /// A \concept{concept_rawallocator,RawAllocator} that either uses the \concept{concept_segregatable,Segregatable} or the other `RawAllocator`.
+ /// It is a faster alternative to \ref fallback_allocator that doesn't require a composable allocator
+ /// and decides about the allocator to use purely with the `Segregatable` based on size and alignment.
+ /// \ingroup adapter
+ template <class Segregatable, class RawAllocator>
+ class binary_segregator
+ : WPI_EBO(
+ detail::ebo_storage<1, typename allocator_traits<RawAllocator>::allocator_type>)
+ {
+ using segregatable_traits = allocator_traits<typename Segregatable::allocator_type>;
+ using fallback_traits = allocator_traits<RawAllocator>;
+
+ public:
+ using segregatable = Segregatable;
+ using segregatable_allocator_type = typename segregatable::allocator_type;
+ using fallback_allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+
+ /// \effects Creates it by giving the \concept{concept_segregatable,Segregatable}
+ /// and the \concept{concept_rawallocator,RawAllocator}.
+ explicit binary_segregator(segregatable s,
+ fallback_allocator_type fallback = fallback_allocator_type())
+ : detail::ebo_storage<1, fallback_allocator_type>(detail::move(fallback)),
+ s_(detail::move(s))
+ {
+ }
+
+ /// @{
+ /// \effects Uses the \concept{concept_segregatable,Segregatable} to decide which allocator to use.
+ /// Then forwards to the chosen allocator.
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ if (get_segregatable().use_allocate_node(size, alignment))
+ return segregatable_traits::allocate_node(get_segregatable_allocator(), size,
+ alignment);
+ else
+ return fallback_traits::allocate_node(get_fallback_allocator(), size,
+ alignment);
+ }
+
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ if (get_segregatable().use_allocate_node(size, alignment))
+ segregatable_traits::deallocate_node(get_segregatable_allocator(), ptr, size,
+ alignment);
+ else
+ fallback_traits::deallocate_node(get_fallback_allocator(), ptr, size,
+ alignment);
+ }
+
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ if (get_segregatable().use_allocate_array(count, size, alignment))
+ return segregatable_traits::allocate_array(get_segregatable_allocator(), count,
+ size, alignment);
+ else
+ return fallback_traits::allocate_array(get_fallback_allocator(), count, size,
+ alignment);
+ }
+
+ void deallocate_array(void* array, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ if (get_segregatable().use_allocate_array(count, size, alignment))
+ segregatable_traits::deallocate_array(get_segregatable_allocator(), array,
+ count, size, alignment);
+ else
+ fallback_traits::deallocate_array(get_fallback_allocator(), array, count, size,
+ alignment);
+ }
+ /// @}
+
+ /// @{
+ /// \returns The maximum value of the fallback.
+ /// \note It assumes that the fallback will be used for larger allocations,
+ /// and the `Segregatable` for smaller ones.
+ std::size_t max_node_size() const
+ {
+ return fallback_traits::max_node_size(get_fallback_allocator());
+ }
+
+ std::size_t max_array_size() const
+ {
+ return fallback_traits::max_array_size(get_fallback_allocator());
+ }
+
+ std::size_t max_alignemnt() const
+ {
+ return fallback_traits::max_alignment(get_fallback_allocator());
+ }
+ /// @}
+
+ /// @{
+ /// \returns A reference to the segregatable allocator.
+ /// This is the one primarily used.
+ segregatable_allocator_type& get_segregatable_allocator() noexcept
+ {
+ return get_segregatable().get_allocator();
+ }
+
+ const segregatable_allocator_type& get_segregatable_allocator() const noexcept
+ {
+ return get_segregatable().get_allocator();
+ }
+ /// @}
+
+ /// @{
+ /// \returns A reference to the fallback allocator.
+ /// It will be used if the \concept{concept_segregator,Segregator} doesn't want the alloction.
+ fallback_allocator_type& get_fallback_allocator() noexcept
+ {
+ return detail::ebo_storage<1, fallback_allocator_type>::get();
+ }
+
+ const fallback_allocator_type& get_fallback_allocator() const noexcept
+ {
+ return detail::ebo_storage<1, fallback_allocator_type>::get();
+ }
+ /// @}
+
+ private:
+ segregatable& get_segregatable() noexcept
+ {
+ return s_;
+ }
+
+ segregatable s_;
+ };
+
+ namespace detail
+ {
+ template <class... Segregatables>
+ struct make_segregator_t;
+
+ template <class Segregatable>
+ struct make_segregator_t<Segregatable>
+ {
+ using type = binary_segregator<Segregatable, null_allocator>;
+ };
+
+ template <class Segregatable, class RawAllocator>
+ struct make_segregator_t<Segregatable, RawAllocator>
+ {
+ using type = binary_segregator<Segregatable, RawAllocator>;
+ };
+
+ template <class Segregatable, class... Tail>
+ struct make_segregator_t<Segregatable, Tail...>
+ {
+ using type =
+ binary_segregator<Segregatable, typename make_segregator_t<Tail...>::type>;
+ };
+
+ template <class Segregator, class Fallback = null_allocator>
+ auto make_segregator(Segregator&& seg, Fallback&& f = null_allocator{})
+ -> binary_segregator<typename std::decay<Segregator>::type,
+ typename std::decay<Fallback>::type>
+ {
+ return binary_segregator<
+ typename std::decay<Segregator>::type,
+ typename std::decay<Fallback>::type>(std::forward<Segregator>(seg),
+ std::forward<Fallback>(f));
+ }
+
+ template <class Segregator, typename... Rest>
+ auto make_segregator(Segregator&& seg, Rest&&... rest)
+ -> binary_segregator<typename std::decay<Segregator>::type,
+ decltype(make_segregator(std::forward<Rest>(rest)...))>
+ {
+ return binary_segregator<typename std::decay<Segregator>::type,
+ decltype(make_segregator(std::forward<Rest>(
+ rest)...))>(std::forward<Segregator>(seg),
+ make_segregator(
+ std::forward<Rest>(rest)...));
+ }
+
+ template <std::size_t I, class Segregator>
+ struct segregatable_type;
+
+ template <class Segregator, class Fallback>
+ struct segregatable_type<0, binary_segregator<Segregator, Fallback>>
+ {
+ using type = typename Segregator::allocator_type;
+
+ static type& get(binary_segregator<Segregator, Fallback>& s)
+ {
+ return s.get_segregatable_allocator();
+ }
+
+ static const type& get(const binary_segregator<Segregator, Fallback>& s)
+ {
+ return s.get_segregatable_allocator();
+ }
+ };
+
+ template <std::size_t I, class Segregator, class Fallback>
+ struct segregatable_type<I, binary_segregator<Segregator, Fallback>>
+ {
+ using base = segregatable_type<I - 1, Fallback>;
+ using type = typename base::type;
+
+ static type& get(binary_segregator<Segregator, Fallback>& s)
+ {
+ return base::get(s.get_fallback_allocator());
+ }
+
+ static const type& get(const binary_segregator<Segregator, Fallback>& s)
+ {
+ return base::get(s.get_fallback_allocator());
+ }
+ };
+
+ template <class Fallback>
+ struct fallback_type
+ {
+ using type = Fallback;
+
+ static const std::size_t size = 0u;
+
+ static type& get(Fallback& f)
+ {
+ return f;
+ }
+
+ static const type& get(const Fallback& f)
+ {
+ return f;
+ }
+ };
+
+ template <class Segregator, class Fallback>
+ struct fallback_type<binary_segregator<Segregator, Fallback>>
+ {
+ using base = fallback_type<Fallback>;
+ using type = typename base::type;
+
+ static const std::size_t size = base::size + 1u;
+
+ static type& get(binary_segregator<Segregator, Fallback>& s)
+ {
+ return base::get(s.get_fallback_allocator());
+ }
+
+ static const type& get(const binary_segregator<Segregator, Fallback>& s)
+ {
+ return base::get(s.get_fallback_allocator());
+ }
+ };
+ } // namespace detail
+
+ /// Creates multiple nested \ref binary_segregator.
+ /// If you pass one type, it must be a \concept{concept_segregatable,Segregatable}.
+ /// Then the result is a \ref binary_segregator with that `Segregatable` and \ref null_allocator as fallback.
+ /// If you pass two types, the first one must be a `Segregatable`,
+ /// the second one a \concept{concept_rawallocator,RawAllocator}.
+ /// Then the result is a simple \ref binary_segregator with those arguments.
+ /// If you pass more than one, the last one must be a `RawAllocator` all others `Segregatable`,
+ /// the result is `binary_segregator<Head, segregator<Tail...>>`.
+ /// \note It will result in an allocator that tries each `Segregatable` in the order specified
+ /// using the last parameter as final fallback.
+ /// \ingroup adapter
+ template <class... Allocators>
+ WPI_ALIAS_TEMPLATE(segregator,
+ typename detail::make_segregator_t<Allocators...>::type);
+
+ /// \returns A \ref segregator created from the allocators `args`.
+ /// \relates segregator
+ template <typename... Args>
+ auto make_segregator(Args&&... args) -> segregator<typename std::decay<Args>::type...>
+ {
+ return detail::make_segregator(std::forward<Args>(args)...);
+ }
+
+ /// The number of \concept{concept_segregatable,Segregatable} a \ref segregator has.
+ /// \relates segregator
+ template <class Segregator>
+ struct segregator_size
+ {
+ static const std::size_t value = detail::fallback_type<Segregator>::size;
+ };
+
+ /// The type of the `I`th \concept{concept_segregatable,Segregatable}.
+ /// \relates segregator
+ template <std::size_t I, class Segregator>
+ using segregatable_allocator_type = typename detail::segregatable_type<I, Segregator>::type;
+
+ /// @{
+ /// \returns The `I`th \concept{concept_segregatable,Segregatable}.
+ /// \relates segregrator
+ template <std::size_t I, class Segregator, class Fallback>
+ auto get_segregatable_allocator(binary_segregator<Segregator, Fallback>& s)
+ -> segregatable_allocator_type<I, binary_segregator<Segregator, Fallback>>&
+ {
+ return detail::segregatable_type<I, binary_segregator<Segregator, Fallback>>::get(s);
+ }
+
+ template <std::size_t I, class Segregator, class Fallback>
+ auto get_segregatable_allocator(const binary_segregator<Segregator, Fallback>& s)
+ -> const segregatable_allocator_type<I, binary_segregator<Segregator, Fallback>>
+ {
+ return detail::segregatable_type<I, binary_segregator<Segregator, Fallback>>::get(s);
+ }
+ /// @}
+
+ /// The type of the final fallback \concept{concept_rawallocator,RawAllocator}.
+ /// \relates segregator
+ template <class Segregator>
+ using fallback_allocator_type = typename detail::fallback_type<Segregator>::type;
+
+ /// @{
+ /// \returns The final fallback \concept{concept_rawallocator,RawAllocator}.
+ /// \relates segregator
+ template <class Segregator, class Fallback>
+ auto get_fallback_allocator(binary_segregator<Segregator, Fallback>& s)
+ -> fallback_allocator_type<binary_segregator<Segregator, Fallback>>&
+ {
+ return detail::fallback_type<binary_segregator<Segregator, Fallback>>::get(s);
+ }
+
+ template <class Segregator, class Fallback>
+ auto get_fallback_allocator(const binary_segregator<Segregator, Fallback>& s)
+ -> const fallback_allocator_type<binary_segregator<Segregator, Fallback>>&
+ {
+ return detail::fallback_type<binary_segregator<Segregator, Fallback>>::get(s);
+ }
+ /// @}
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..877efd7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/smart_ptr.hpp
@@ -0,0 +1,210 @@
+// 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.
+
+#ifndef WPI_MEMORY_SMART_PTR_HPP_INCLUDED
+#define WPI_MEMORY_SMART_PTR_HPP_INCLUDED
+
+/// \file
+/// \c std::make_unique() / \c std::make_shared() replacement allocating memory through a \concept{concept_rawallocator,RawAllocator}.
+/// \note Only available on a hosted implementation.
+
+#include "config.hpp"
+#if !WPI_HOSTED_IMPLEMENTATION
+#error "This header is only available for a hosted implementation."
+#endif
+
+#include <memory>
+#include <type_traits>
+
+#include "detail/utility.hpp"
+#include "deleter.hpp"
+#include "std_allocator.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <typename T, class RawAllocator, typename... Args>
+ auto allocate_unique(allocator_reference<RawAllocator> alloc, Args&&... args)
+ -> std::unique_ptr<T, allocator_deleter<T, RawAllocator>>
+ {
+ using raw_ptr = std::unique_ptr<T, allocator_deallocator<T, RawAllocator>>;
+
+ auto memory = alloc.allocate_node(sizeof(T), alignof(T));
+ // raw_ptr deallocates memory in case of constructor exception
+ raw_ptr result(static_cast<T*>(memory), {alloc});
+ // call constructor
+ ::new (memory) T(detail::forward<Args>(args)...);
+ // pass ownership to return value using a deleter that calls destructor
+ return {result.release(), {alloc}};
+ }
+
+ template <typename T, typename... Args>
+ void construct(std::true_type, T* cur, T* end, Args&&... args)
+ {
+ for (; cur != end; ++cur)
+ ::new (static_cast<void*>(cur)) T(detail::forward<Args>(args)...);
+ }
+
+ template <typename T, typename... Args>
+ void construct(std::false_type, T* begin, T* end, Args&&... args)
+ {
+#if WPI_HAS_EXCEPTION_SUPPORT
+ auto cur = begin;
+ try
+ {
+ for (; cur != end; ++cur)
+ ::new (static_cast<void*>(cur)) T(detail::forward<Args>(args)...);
+ }
+ catch (...)
+ {
+ for (auto el = begin; el != cur; ++el)
+ el->~T();
+ throw;
+ }
+#else
+ construct(std::true_type{}, begin, end, detail::forward<Args>(args)...);
+#endif
+ }
+
+ template <typename T, class RawAllocator>
+ auto allocate_array_unique(std::size_t size, allocator_reference<RawAllocator> alloc)
+ -> std::unique_ptr<T[], allocator_deleter<T[], RawAllocator>>
+ {
+ using raw_ptr = std::unique_ptr<T[], allocator_deallocator<T[], RawAllocator>>;
+
+ auto memory = alloc.allocate_array(size, sizeof(T), alignof(T));
+ // raw_ptr deallocates memory in case of constructor exception
+ raw_ptr result(static_cast<T*>(memory), {alloc, size});
+ construct(std::integral_constant<bool, noexcept(T())>{}, result.get(),
+ result.get() + size);
+ // pass ownership to return value using a deleter that calls destructor
+ return {result.release(), {alloc, size}};
+ }
+ } // namespace detail
+
+ /// A \c std::unique_ptr that deletes using a \concept{concept_rawallocator,RawAllocator}.
+ ///
+ /// It is an alias template using \ref allocator_deleter as \c Deleter class.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(unique_ptr,
+ std::unique_ptr<T, allocator_deleter<T, RawAllocator>>);
+
+ /// A \c std::unique_ptr that deletes using a \concept{concept_rawallocator,RawAllocator} and allows polymorphic types.
+ ///
+ /// It can only be created by converting a regular unique pointer to a pointer to a derived class,
+ /// and is meant to be used inside containers.
+ /// It is an alias template using \ref allocator_polymorphic_deleter as \c Deleter class.
+ /// \note It has a relatively high overhead, so only use it if you have to.
+ /// \ingroup adapter
+ template <class BaseType, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ unique_base_ptr,
+ std::unique_ptr<BaseType, allocator_polymorphic_deleter<BaseType, RawAllocator>>);
+
+ /// Creates a \c std::unique_ptr using a \concept{concept_rawallocator,RawAllocator} for the allocation.
+ /// \effects Allocates memory for the given type using the allocator
+ /// and creates a new object inside it passing the given arguments to its constructor.
+ /// \returns A \c std::unique_ptr owning that memory.
+ /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
+ /// the caller has to ensure that the object lives as long as the smart pointer.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator, typename... Args>
+ auto allocate_unique(RawAllocator&& alloc, Args&&... args) -> WPI_REQUIRES_RET(
+ !std::is_array<T>::value,
+ std::unique_ptr<T, allocator_deleter<T, typename std::decay<RawAllocator>::type>>)
+ {
+ return detail::allocate_unique<T>(make_allocator_reference(
+ detail::forward<RawAllocator>(alloc)),
+ detail::forward<Args>(args)...);
+ }
+
+ /// Creates a \c std::unique_ptr using a type-erased \concept{concept_rawallocator,RawAllocator} for the allocation.
+ /// It is the same as the other overload but stores the reference to the allocator type-erased inside the \c std::unique_ptr.
+ /// \effects Allocates memory for the given type using the allocator
+ /// and creates a new object inside it passing the given arguments to its constructor.
+ /// \returns A \c std::unique_ptr with a type-erased allocator reference owning that memory.
+ /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
+ /// the caller has to ensure that the object lives as long as the smart pointer.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator, typename... Args>
+ auto allocate_unique(any_allocator, RawAllocator&& alloc, Args&&... args)
+ -> WPI_REQUIRES_RET(!std::is_array<T>::value,
+ std::unique_ptr<T, allocator_deleter<T, any_allocator>>)
+ {
+ return detail::allocate_unique<T, any_allocator>(make_allocator_reference(
+ detail::forward<RawAllocator>(
+ alloc)),
+ detail::forward<Args>(args)...);
+ }
+
+ /// Creates a \c std::unique_ptr owning an array using a \concept{concept_rawallocator,RawAllocator} for the allocation.
+ /// \effects Allocates memory for an array of given size and value initializes each element inside of it.
+ /// \returns A \c std::unique_ptr owning that array.
+ /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
+ /// the caller has to ensure that the object lives as long as the smart pointer.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator>
+ auto allocate_unique(RawAllocator&& alloc, std::size_t size) -> WPI_REQUIRES_RET(
+ std::is_array<T>::value,
+ std::unique_ptr<T, allocator_deleter<T, typename std::decay<RawAllocator>::type>>)
+ {
+ return detail::allocate_array_unique<
+ typename std::remove_extent<T>::type>(size,
+ make_allocator_reference(
+ detail::forward<RawAllocator>(alloc)));
+ }
+
+ /// Creates a \c std::unique_ptr owning an array using a type-erased \concept{concept_rawallocator,RawAllocator} for the allocation.
+ /// It is the same as the other overload but stores the reference to the allocator type-erased inside the \c std::unique_ptr.
+ /// \effects Allocates memory for an array of given size and value initializes each element inside of it.
+ /// \returns A \c std::unique_ptr with a type-erased allocator reference owning that array.
+ /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
+ /// the caller has to ensure that the object lives as long as the smart pointer.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator>
+ auto allocate_unique(any_allocator, RawAllocator&& alloc, std::size_t size)
+ -> WPI_REQUIRES_RET(std::is_array<T>::value,
+ std::unique_ptr<T, allocator_deleter<T, any_allocator>>)
+ {
+ return detail::allocate_array_unique<typename std::remove_extent<T>::type,
+ any_allocator>(size,
+ make_allocator_reference(
+ detail::forward<RawAllocator>(
+ alloc)));
+ }
+
+ /// Creates a \c std::shared_ptr using a \concept{concept_rawallocator,RawAllocator} for the allocation.
+ /// It is similar to \c std::allocate_shared but uses a \c RawAllocator (and thus also supports any \c Allocator).
+ /// \effects Calls \ref std_allocator::make_std_allocator to wrap the allocator and forwards to \c std::allocate_shared.
+ /// \returns A \c std::shared_ptr created using \c std::allocate_shared.
+ /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the shared pointer,
+ /// the caller has to ensure that the object lives as long as the smart pointer.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator, typename... Args>
+ std::shared_ptr<T> allocate_shared(RawAllocator&& alloc, Args&&... args)
+ {
+ return std::allocate_shared<T>(make_std_allocator<T>(
+ 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
+
+#endif // WPI_MEMORY_SMART_PTR_HPP_INCLUDED
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
new file mode 100644
index 0000000..efbbf73
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/static_allocator.hpp
@@ -0,0 +1,179 @@
+// 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.
+
+#ifndef WPI_MEMORY_STATIC_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_STATIC_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Allocators using a static, fixed-sized storage.
+
+#include <type_traits>
+
+#include "detail/align.hpp"
+#include "detail/assert.hpp"
+#include "detail/memory_stack.hpp"
+#include "detail/utility.hpp"
+#include "config.hpp"
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+#include "allocator_traits.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// Storage for a \ref static_allocator.
+ /// Its constructor will take a reference to it and use it for its allocation.
+ /// The storage type is simply a \c char array aligned for maximum alignment.
+ /// \note It is not allowed to access the memory of the storage.
+ /// \ingroup allocator
+ template <std::size_t Size>
+ struct static_allocator_storage
+ {
+ alignas(detail::max_alignment) char storage[Size];
+ };
+
+ static_assert(sizeof(static_allocator_storage<1024>) == 1024, "");
+ static_assert(alignof(static_allocator_storage<1024>) == detail::max_alignment, "");
+
+ struct allocator_info;
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that uses a fixed sized storage for the allocations.
+ /// It works on a \ref static_allocator_storage and uses its memory for all allocations.
+ /// Deallocations are not supported, memory cannot be marked as freed.<br>
+ /// \note It is not allowed to share an \ref static_allocator_storage between multiple \ref static_allocator objects.
+ /// \ingroup allocator
+ class static_allocator
+ {
+ public:
+ using is_stateful = std::true_type;
+
+ /// \effects Creates it by passing it a \ref static_allocator_storage by reference.
+ /// It will take the address of the storage and use its memory for the allocation.
+ /// \requires The storage object must live as long as the allocator object.
+ /// It must not be shared between multiple allocators,
+ /// i.e. the object must not have been passed to a constructor before.
+ template <std::size_t Size>
+ static_allocator(static_allocator_storage<Size>& storage) noexcept
+ : stack_(&storage), end_(stack_.top() + Size)
+ {
+ }
+
+ /// \effects A \concept{concept_rawallocator,RawAllocator} allocation function.
+ /// It uses the specified \ref static_allocator_storage.
+ /// \returns A pointer to a \concept{concept_node,node}, it will never be \c nullptr.
+ /// \throws An exception of type \ref out_of_memory or whatever is thrown by its handler if the storage is exhausted.
+ void* allocate_node(std::size_t size, std::size_t alignment);
+
+ /// \effects A \concept{concept_rawallocator,RawAllocator} deallocation function.
+ /// It does nothing, deallocation is not supported by this allocator.
+ void deallocate_node(void*, std::size_t, std::size_t) noexcept {}
+
+ /// \returns The maximum node size which is the capacity remaining inside the \ref static_allocator_storage.
+ std::size_t max_node_size() const noexcept
+ {
+ return static_cast<std::size_t>(end_ - stack_.top());
+ }
+
+ /// \returns The maximum possible value since there is no alignment restriction
+ /// (except indirectly through the size of the \ref static_allocator_storage).
+ std::size_t max_alignment() const noexcept
+ {
+ return std::size_t(-1);
+ }
+
+ private:
+ allocator_info info() const noexcept;
+
+ detail::fixed_memory_stack stack_;
+ const char* end_;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<static_allocator>;
+#endif
+
+ struct memory_block;
+
+ /// A \concept{concept_blockallocator,BlockAllocator} that allocates the blocks from a fixed size storage.
+ /// It works on a \ref static_allocator_storage and uses it for all allocations,
+ /// deallocations are only allowed in reversed order which is guaranteed by \ref memory_arena.
+ /// \note It is not allowed to share an \ref static_allocator_storage between multiple \ref static_allocator objects.
+ /// \ingroup allocator
+ class static_block_allocator
+ {
+ public:
+ /// \effects Creates it by passing it the block size and a \ref static_allocator_storage by reference.
+ /// It will take the address of the storage and use it to allocate \c block_size'd blocks.
+ /// \requires The storage object must live as long as the allocator object.
+ /// It must not be shared between multiple allocators,
+ /// i.e. the object must not have been passed to a constructor before.
+ /// The size of the \ref static_allocator_storage must be a multiple of the (non-null) block size.
+ template <std::size_t Size>
+ static_block_allocator(std::size_t block_size,
+ static_allocator_storage<Size>& storage) noexcept
+ : cur_(static_cast<char*>(static_cast<void*>(&storage))),
+ end_(cur_ + Size),
+ block_size_(block_size)
+ {
+ WPI_MEMORY_ASSERT(block_size <= Size);
+ WPI_MEMORY_ASSERT(Size % block_size == 0u);
+ }
+
+ ~static_block_allocator() noexcept = default;
+
+ /// @{
+ /// \effects Moves the block allocator, it transfers ownership over the \ref static_allocator_storage.
+ /// This does not invalidate any memory blocks.
+ static_block_allocator(static_block_allocator&& other) noexcept
+ : cur_(other.cur_), end_(other.end_), block_size_(other.block_size_)
+ {
+ other.cur_ = other.end_ = nullptr;
+ other.block_size_ = 0;
+ }
+
+ static_block_allocator& operator=(static_block_allocator&& other) noexcept
+ {
+ static_block_allocator tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+ /// @}
+
+ /// \effects Swaps the ownership over the \ref static_allocator_storage.
+ /// This does not invalidate any memory blocks.
+ friend void swap(static_block_allocator& a, static_block_allocator& b) noexcept
+ {
+ detail::adl_swap(a.cur_, b.cur_);
+ detail::adl_swap(a.end_, b.end_);
+ detail::adl_swap(a.block_size_, b.block_size_);
+ }
+
+ /// \effects Allocates a new block by returning the \ref next_block_size() bytes.
+ /// \returns The new memory block.
+ memory_block allocate_block();
+
+ /// \effects Deallocates the last memory block by marking the block as free again.
+ /// This block will be returned again by the next call to \ref allocate_block().
+ /// \requires \c block must be the current top block of the memory,
+ /// this is guaranteed by \ref memory_arena.
+ void deallocate_block(memory_block block) noexcept;
+
+ /// \returns The next block size, this is the size passed to the constructor.
+ std::size_t next_block_size() const noexcept
+ {
+ return block_size_;
+ }
+
+ private:
+ allocator_info info() const noexcept;
+
+ char * cur_, *end_;
+ std::size_t block_size_;
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..f727a1c
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/std_allocator.hpp
@@ -0,0 +1,360 @@
+// 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.
+
+#ifndef WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::std_allocator and related classes and functions.
+
+#include <new>
+#include <type_traits>
+
+#include "detail/utility.hpp"
+#include "config.hpp"
+#include "allocator_storage.hpp"
+#include "threading.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace traits_detail
+ {
+ template <class RawAllocator>
+ auto propagate_on_container_swap(std_concept) ->
+ typename RawAllocator::propagate_on_container_swap;
+
+ template <class RawAllocator>
+ auto propagate_on_container_swap(min_concept) -> std::true_type;
+
+ template <class RawAllocator>
+ auto propagate_on_container_move_assignment(std_concept) ->
+ typename RawAllocator::propagate_on_container_move_assignment;
+
+ template <class RawAllocator>
+ auto propagate_on_container_move_assignment(min_concept) -> std::true_type;
+
+ template <class RawAllocator>
+ auto propagate_on_container_copy_assignment(std_concept) ->
+ typename RawAllocator::propagate_on_container_copy_assignment;
+
+ template <class RawAllocator>
+ auto propagate_on_container_copy_assignment(min_concept) -> std::true_type;
+ } // namespace traits_detail
+
+ /// Controls the propagation of a \ref std_allocator for a certain \concept{concept_rawallocator,RawAllocator}.
+ /// \ingroup adapter
+ template <class RawAllocator>
+ struct propagation_traits
+ {
+ using propagate_on_container_swap =
+ decltype(traits_detail::propagate_on_container_swap<RawAllocator>(
+ traits_detail::full_concept{}));
+
+ using propagate_on_container_move_assignment =
+ decltype(traits_detail::propagate_on_container_move_assignment<RawAllocator>(
+ traits_detail::full_concept{}));
+
+ using propagate_on_container_copy_assignment =
+ decltype(traits_detail::propagate_on_container_copy_assignment<RawAllocator>(
+ traits_detail::full_concept{}));
+
+ template <class AllocReference>
+ static AllocReference select_on_container_copy_construction(const AllocReference& alloc)
+ {
+ return alloc;
+ }
+ };
+
+ /// Wraps a \concept{concept_rawallocator,RawAllocator} and makes it a "normal" \c Allocator.
+ /// It allows using a \c RawAllocator anywhere a \c Allocator is required.
+ /// \ingroup adapter
+ template <typename T, class RawAllocator>
+ class std_allocator :
+#if defined _MSC_VER && defined __clang__
+ WPI_EBO(protected allocator_reference<RawAllocator>)
+#else
+ WPI_EBO(allocator_reference<RawAllocator>)
+#endif
+ {
+ using alloc_reference = allocator_reference<RawAllocator>;
+ // if it is any_allocator_reference an optimized implementation can be used
+ using is_any = std::is_same<alloc_reference, any_allocator_reference>;
+
+ using prop_traits = propagation_traits<RawAllocator>;
+
+ public:
+ //=== typedefs ===//
+ using value_type = T;
+ using pointer = T*;
+ using const_pointer = const T*;
+ using reference = T&;
+ using const_reference = const T&;
+ using size_type = std::size_t;
+ using difference_type = std::ptrdiff_t;
+
+ using propagate_on_container_swap = typename prop_traits::propagate_on_container_swap;
+ using propagate_on_container_move_assignment =
+ typename prop_traits::propagate_on_container_move_assignment;
+ using propagate_on_container_copy_assignment =
+ typename prop_traits::propagate_on_container_copy_assignment;
+
+ template <typename U>
+ struct rebind
+ {
+ using other = std_allocator<U, RawAllocator>;
+ };
+
+ using allocator_type = typename alloc_reference::allocator_type;
+
+ //=== constructor ===//
+ /// \effects Default constructs it by storing a default constructed, stateless \c RawAllocator inside the reference.
+ /// \requires The \c RawAllocator type is stateless, otherwise the body of this function will not compile.
+ std_allocator() noexcept : alloc_reference(allocator_type{})
+ {
+#if !defined(__GNUC__) || (defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI != 0)
+ // std::string requires default constructor for the small string optimization when using gcc's old ABI
+ // so don't assert then to allow joint allocator
+ static_assert(!alloc_reference::is_stateful::value,
+ "default constructor must not be used for stateful allocators");
+#endif
+ }
+
+ /// \effects Creates it from a reference to a \c RawAllocator.
+ /// It will store an \ref allocator_reference to it.
+ /// \requires The expression <tt>allocator_reference<RawAllocator>(alloc)</tt> is well-formed,
+ /// that is either \c RawAlloc is the same as \c RawAllocator or \c RawAllocator is the tag type \ref any_allocator.
+ /// If the requirement is not fulfilled this function does not participate in overload resolution.
+ /// \note The caller has to ensure that the lifetime of the \c RawAllocator is at least as long as the lifetime
+ /// of this \ref std_allocator object.
+ template <
+ class RawAlloc,
+ // 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
+ : alloc_reference(alloc)
+ {
+ }
+
+ /// \effects Creates it from a stateless, temporary \c RawAllocator object.
+ /// It will not store a reference but create it on the fly.
+ /// \requires The \c RawAllocator is stateless
+ /// and the expression <tt>allocator_reference<RawAllocator>(alloc)</tt> is well-formed as above,
+ /// otherwise this function does not participate in overload resolution.
+ template <
+ class RawAlloc,
+ // 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
+ : alloc_reference(alloc)
+ {
+ }
+
+ /// \effects Creates it from another \ref allocator_reference using the same allocator type.
+ std_allocator(const alloc_reference& alloc) noexcept : alloc_reference(alloc) {}
+
+ /// \details Implicit conversion from any other \ref allocator_storage is forbidden
+ /// to prevent accidentally wrapping another \ref allocator_storage inside a \ref allocator_reference.
+ template <class StoragePolicy, class OtherMut>
+ std_allocator(const allocator_storage<StoragePolicy, OtherMut>&) = delete;
+
+ /// @{
+ /// \effects Creates it from another \ref std_allocator allocating a different type.
+ /// This is required by the \c Allcoator concept and simply takes the same \ref allocator_reference.
+ template <typename U>
+ std_allocator(const std_allocator<U, RawAllocator>& alloc) noexcept
+ : alloc_reference(alloc)
+ {
+ }
+
+ template <typename U>
+ std_allocator(std_allocator<U, RawAllocator>& alloc) noexcept : alloc_reference(alloc)
+ {
+ }
+ /// @}
+
+ /// \returns A copy of the allocator.
+ /// This is required by the \c Allocator concept and forwards to the \ref propagation_traits.
+ std_allocator<T, RawAllocator> select_on_container_copy_construction() const
+ {
+ return prop_traits::select_on_container_copy_construction(*this);
+ }
+
+ //=== allocation/deallocation ===//
+ /// \effects Allocates memory using the underlying \concept{concept_rawallocator,RawAllocator}.
+ /// If \c n is \c 1, it will call <tt>allocate_node(sizeof(T), alignof(T))</tt>,
+ /// otherwise <tt>allocate_array(n, sizeof(T), alignof(T))</tt>.
+ /// \returns A pointer to a memory block suitable for \c n objects of type \c T.
+ /// \throws Anything thrown by the \c RawAllocator.
+ pointer allocate(size_type n, void* = nullptr)
+ {
+ return static_cast<pointer>(allocate_impl(is_any{}, n));
+ }
+
+ /// \effects Deallcoates memory using the underlying \concept{concept_rawallocator,RawAllocator}.
+ /// It will forward to the deallocation function in the same way as in \ref allocate().
+ /// \requires The pointer must come from a previous call to \ref allocate() with the same \c n on this object or any copy of it.
+ void deallocate(pointer p, size_type n) noexcept
+ {
+ deallocate_impl(is_any{}, p, n);
+ }
+
+ //=== construction/destruction ===//
+ /// \effects Creates an object of type \c U at given address using the passed arguments.
+ template <typename U, typename... Args>
+ void construct(U* p, Args&&... args)
+ {
+ void* mem = p;
+ ::new (mem) U(detail::forward<Args>(args)...);
+ }
+
+ /// \effects Calls the destructor for an object of type \c U at given address.
+ template <typename U>
+ void destroy(U* p) noexcept
+ {
+ // This is to avoid a MSVS 2015 'unreferenced formal parameter' warning
+ (void)p;
+ p->~U();
+ }
+
+ //=== getter ===//
+ /// \returns The maximum size for an allocation which is <tt>max_array_size() / sizeof(value_type)</tt>.
+ /// This is only an upper bound, not the exact maximum.
+ size_type max_size() const noexcept
+ {
+ return this->max_array_size() / sizeof(value_type);
+ }
+
+ /// @{
+ /// \effects Returns a reference to the referenced allocator.
+ /// \returns For stateful allocators: A (\c const) reference to the stored allocator.
+ /// For stateless allocators: A temporary constructed allocator.
+ auto get_allocator() noexcept
+ -> decltype(std::declval<alloc_reference>().get_allocator())
+ {
+ return alloc_reference::get_allocator();
+ }
+
+ auto get_allocator() const noexcept
+ -> decltype(std::declval<const alloc_reference>().get_allocator())
+ {
+ return alloc_reference::get_allocator();
+ }
+ /// @}
+
+ private:
+ // any_allocator_reference: use virtual function which already does a dispatch on node/array
+ void* allocate_impl(std::true_type, size_type n)
+ {
+ return get_allocator().allocate_impl(n, sizeof(T), alignof(T));
+ }
+
+ void deallocate_impl(std::true_type, void* ptr, size_type n)
+ {
+ get_allocator().deallocate_impl(ptr, n, sizeof(T), alignof(T));
+ }
+
+ // alloc_reference: decide between node/array
+ void* allocate_impl(std::false_type, size_type n)
+ {
+ if (n == 1)
+ return this->allocate_node(sizeof(T), alignof(T));
+ else
+ return this->allocate_array(n, sizeof(T), alignof(T));
+ }
+
+ void deallocate_impl(std::false_type, void* ptr, size_type n)
+ {
+ if (n == 1)
+ this->deallocate_node(ptr, sizeof(T), alignof(T));
+ else
+ this->deallocate_array(ptr, n, sizeof(T), alignof(T));
+ }
+
+ template <typename U> // stateful
+ bool equal_to_impl(std::true_type,
+ const std_allocator<U, RawAllocator>& other) const noexcept
+ {
+ return &get_allocator() == &other.get_allocator();
+ }
+
+ template <typename U> // non-stateful
+ bool equal_to_impl(std::false_type,
+ const std_allocator<U, RawAllocator>&) const noexcept
+ {
+ return true;
+ }
+
+ template <typename U> // shared
+ bool equal_to(std::true_type,
+ const std_allocator<U, RawAllocator>& other) const noexcept
+ {
+ return get_allocator() == other.get_allocator();
+ }
+
+ template <typename U> // not shared
+ bool equal_to(std::false_type,
+ const std_allocator<U, RawAllocator>& other) const noexcept
+ {
+ return equal_to_impl(typename allocator_traits<RawAllocator>::is_stateful{}, other);
+ }
+
+ template <typename T1, typename T2, class Impl>
+ friend bool operator==(const std_allocator<T1, Impl>& lhs,
+ const std_allocator<T2, Impl>& rhs) noexcept;
+
+ template <typename U, class OtherRawAllocator>
+ friend class std_allocator;
+ };
+
+ /// \effects Compares two \ref std_allocator object, they are equal if either stateless or reference the same allocator.
+ /// \returns The result of the comparision for equality.
+ /// \relates std_allocator
+ template <typename T, typename U, class Impl>
+ bool operator==(const std_allocator<T, Impl>& lhs,
+ const std_allocator<U, Impl>& rhs) noexcept
+ {
+ return lhs.equal_to(is_shared_allocator<Impl>{}, rhs);
+ }
+
+ /// \effects Compares two \ref std_allocator object, they are equal if either stateless or reference the same allocator.
+ /// \returns The result of the comparision for inequality.
+ /// \relates std_allocator
+ template <typename T, typename U, class Impl>
+ bool operator!=(const std_allocator<T, Impl>& lhs,
+ const std_allocator<U, Impl>& rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ /// \returns A new \ref std_allocator for a given type using a certain allocator object.
+ /// \relates std_allocator
+ template <typename T, class RawAllocator>
+ auto make_std_allocator(RawAllocator&& allocator) noexcept
+ -> std_allocator<T, typename std::decay<RawAllocator>::type>
+ {
+ return {detail::forward<RawAllocator>(allocator)};
+ }
+
+ /// An alias template for \ref std_allocator using a type-erased \concept{concept_rawallocator,RawAllocator}.
+ /// This is the same as using a \ref std_allocator with the tag type \ref any_allocator.
+ /// The implementation is optimized to call fewer virtual functions.
+ /// \ingroup adapter
+ template <typename T>
+ WPI_ALIAS_TEMPLATE(any_std_allocator, std_allocator<T, any_allocator>);
+
+ /// \returns A new \ref any_std_allocator for a given type using a certain allocator object.
+ /// \relates any_std_allocator
+ template <typename T, class RawAllocator>
+ any_std_allocator<T> make_any_std_allocator(RawAllocator&& allocator) noexcept
+ {
+ return {detail::forward<RawAllocator>(allocator)};
+ }
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
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
new file mode 100644
index 0000000..7eba76f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/temporary_allocator.hpp
@@ -0,0 +1,335 @@
+// 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.
+
+#ifndef WPI_MEMORY_TEMPORARY_ALLOCATOR_HPP_INCLUDED
+#define WPI_MEMORY_TEMPORARY_ALLOCATOR_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::temporary_allocator and related functions.
+
+#include "config.hpp"
+#include "memory_stack.hpp"
+
+#if WPI_MEMORY_TEMPORARY_STACK_MODE >= 2
+#include <atomic>
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ class temporary_allocator;
+ class temporary_stack;
+
+ namespace detail
+ {
+ class temporary_block_allocator
+ {
+ public:
+ explicit temporary_block_allocator(std::size_t block_size) noexcept;
+
+ memory_block allocate_block();
+
+ void deallocate_block(memory_block block);
+
+ std::size_t next_block_size() const noexcept
+ {
+ return block_size_;
+ }
+
+ using growth_tracker = void (*)(std::size_t size);
+
+ growth_tracker set_growth_tracker(growth_tracker t) noexcept;
+
+ growth_tracker get_growth_tracker() noexcept;
+
+ private:
+ growth_tracker tracker_;
+ std::size_t block_size_;
+ };
+
+ using temporary_stack_impl = memory_stack<temporary_block_allocator>;
+
+ class temporary_stack_list;
+
+#if WPI_MEMORY_TEMPORARY_STACK_MODE >= 2
+ class temporary_stack_list_node
+ {
+ public:
+ // doesn't add into list
+ temporary_stack_list_node() noexcept : in_use_(true) {}
+
+ temporary_stack_list_node(int) noexcept;
+
+ ~temporary_stack_list_node() noexcept {}
+
+ private:
+ temporary_stack_list_node* next_ = nullptr;
+ std::atomic<bool> in_use_;
+
+ friend temporary_stack_list;
+ };
+
+ static class temporary_allocator_dtor_t
+ {
+ public:
+ temporary_allocator_dtor_t() noexcept;
+ ~temporary_allocator_dtor_t() noexcept;
+ } temporary_allocator_dtor;
+#else
+ class temporary_stack_list_node
+ {
+ protected:
+ temporary_stack_list_node() noexcept {}
+
+ temporary_stack_list_node(int) noexcept {}
+
+ ~temporary_stack_list_node() noexcept {}
+ };
+#endif
+ } // namespace detail
+
+ /// A wrapper around the \ref memory_stack that is used by the \ref temporary_allocator.
+ /// There should be at least one per-thread.
+ /// \ingroup allocator
+ class temporary_stack : WPI_EBO(detail::temporary_stack_list_node)
+ {
+ public:
+ /// The type of the handler called when the internal \ref memory_stack grows.
+ /// It gets the size of the new block that will be allocated.
+ /// \requiredbe The handler shall log the growth, throw an exception or aborts the program.
+ /// If this function does not return, the growth is prevented but the allocator unusable until memory is freed.
+ /// \defaultbe The default handler does nothing.
+ using growth_tracker = detail::temporary_block_allocator::growth_tracker;
+
+ /// \effects Sets \c h as the new \ref growth_tracker.
+ /// A \c nullptr sets the default \ref growth_tracker.
+ /// Each thread has its own, separate tracker.
+ /// \returns The previous \ref growth_tracker. This is never \c nullptr.
+ growth_tracker set_growth_tracker(growth_tracker t) noexcept
+ {
+ return stack_.get_allocator().set_growth_tracker(t);
+ }
+
+ /// \returns The current \ref growth_tracker. This is never \c nullptr.
+ growth_tracker get_growth_tracker() noexcept
+ {
+ return stack_.get_allocator().get_growth_tracker();
+ }
+
+ /// \effects Creates it with a given initial size of the stack.
+ /// It can grow if needed, although that is expensive.
+ /// \requires `initial_size` must be greater than `0`.
+ explicit temporary_stack(std::size_t initial_size) : stack_(initial_size), top_(nullptr)
+ {
+ }
+
+ /// \returns `next_capacity()` of the internal `memory_stack`.
+ std::size_t next_capacity() const noexcept
+ {
+ return stack_.next_capacity();
+ }
+
+ private:
+ temporary_stack(int i, std::size_t initial_size)
+ : detail::temporary_stack_list_node(i), stack_(initial_size), top_(nullptr)
+ {
+ }
+
+ using marker = detail::temporary_stack_impl::marker;
+
+ marker top() const noexcept
+ {
+ return stack_.top();
+ }
+
+ void unwind(marker m) noexcept
+ {
+ stack_.unwind(m);
+ }
+
+ detail::temporary_stack_impl stack_;
+ temporary_allocator* top_;
+
+#if !defined(DOXYGEN)
+ friend temporary_allocator;
+ friend memory_stack_raii_unwind<temporary_stack>;
+ friend detail::temporary_stack_list;
+#endif
+ };
+
+ /// Manually takes care of the lifetime of the per-thread \ref temporary_stack.
+ /// The constructor will create it, if not already done, and the destructor will destroy it, if not already done.
+ /// \note If there are multiple objects in a thread,
+ /// this will lead to unnecessary construction and destruction of the stack.
+ /// It is thus adviced to create one object on the top-level function of the thread, e.g. in `main()`.
+ /// \note If `WPI_MEMORY_TEMPORARY_STACK_MODE == 2`, it is not necessary to use this class,
+ /// the nifty counter will clean everything upon program termination.
+ /// But it can still be used as an optimization if you have a thread that is terminated long before program exit.
+ /// The automatic clean up will only occur much later.
+ /// \note If `WPI_MEMORY_TEMPORARY_STACK_MODE == 0`, the use of this class has no effect,
+ /// because the per-thread stack is disabled.
+ /// \relatesalso temporary_stack
+ class temporary_stack_initializer
+ {
+ public:
+ static constexpr std::size_t default_stack_size = 4096u;
+
+ static const struct defer_create_t
+ {
+ defer_create_t() noexcept {}
+ } defer_create;
+
+ /// \effects Does not create the per-thread stack.
+ /// It will be created by the first call to \ref get_temporary_stack() in the current thread.
+ /// \note If `WPI_MEMORY_TEMPORARY_STACK_MODE == 0`, this function has no effect.
+ temporary_stack_initializer(defer_create_t) noexcept {}
+
+ /// \effects Creates the per-thread stack with the given default size if it wasn't already created.
+ /// \requires `initial_size` must not be `0` if `WPI_MEMORY_TEMPORARY_STACK_MODE != 0`.
+ /// \note If `WPI_MEMORY_TEMPORARY_STACK_MODE == 0`, this function will issue a warning in debug mode.
+ /// This can be disabled by passing `0` as the initial size.
+ temporary_stack_initializer(std::size_t initial_size = default_stack_size);
+
+ /// \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& operator=(temporary_stack_initializer&&) = delete;
+ };
+
+ /// \effects Creates the per-thread \ref temporary_stack with the given initial size,
+ /// if it wasn't already created.
+ /// \returns The per-thread \ref temporary_stack.
+ /// \requires There must be a per-thread temporary stack (\ref WPI_MEMORY_TEMPORARY_STACK_MODE must not be equal to `0`).
+ /// \note If \ref WPI_MEMORY_TEMPORARY_STACK_MODE is equal to `1`,
+ /// this function can create the temporary stack.
+ /// But if there is no \ref temporary_stack_initializer, it won't be destroyed.
+ /// \relatesalso temporary_stack
+ temporary_stack& get_temporary_stack(
+ std::size_t initial_size = temporary_stack_initializer::default_stack_size);
+
+ /// A stateful \concept{concept_rawallocator,RawAllocator} that handles temporary allocations.
+ /// It works similar to \c alloca() but uses a seperate \ref memory_stack for the allocations,
+ /// instead of the actual program stack.
+ /// This avoids the stack overflow error and is portable,
+ /// with a similar speed.
+ /// All allocations done in the scope of the allocator object are automatically freed when the object is destroyed.
+ /// \ingroup allocator
+ class temporary_allocator
+ {
+ public:
+ /// \effects Creates it by using the \ref get_temporary_stack() to get the temporary stack.
+ /// \requires There must be a per-thread temporary stack (\ref WPI_MEMORY_TEMPORARY_STACK_MODE must not be equal to `0`).
+ temporary_allocator();
+
+ /// \effects Creates it by giving it the \ref temporary_stack it uses for allocation.
+ explicit temporary_allocator(temporary_stack& stack);
+
+ ~temporary_allocator() noexcept;
+
+ temporary_allocator(temporary_allocator&&) = delete;
+ temporary_allocator& operator=(temporary_allocator&&) = delete;
+
+ /// \effects Allocates memory from the internal \ref memory_stack by forwarding to it.
+ /// \returns The result of \ref memory_stack::allocate().
+ /// \requires `is_active()` must return `true`.
+ void* allocate(std::size_t size, std::size_t alignment);
+
+ /// \returns Whether or not the allocator object is active.
+ /// \note The active allocator object is the last object created for one stack.
+ /// Moving changes the active allocator.
+ bool is_active() const noexcept;
+
+ /// \effects Instructs it to release unnecessary memory after automatic unwinding occurs.
+ /// This will effectively forward to \ref memory_stack::shrink_to_fit() of the internal stack.
+ /// \note Like the use of the \ref temporary_stack_initializer this can be used as an optimization,
+ /// to tell when the thread's \ref temporary_stack isn't needed anymore and can be destroyed.
+ /// \note It doesn't call shrink to fit immediately, only in the destructor!
+ void shrink_to_fit() noexcept;
+
+ /// \returns The internal stack the temporary allocator is using.
+ /// \requires `is_active()` must return `true`.
+ temporary_stack& get_stack() const noexcept
+ {
+ return unwind_.get_stack();
+ }
+
+ private:
+ memory_stack_raii_unwind<temporary_stack> unwind_;
+ temporary_allocator* prev_;
+ bool shrink_to_fit_;
+ };
+
+ template <class Allocator>
+ class allocator_traits;
+
+ /// Specialization of the \ref allocator_traits for \ref temporary_allocator classes.
+ /// \note It is not allowed to mix calls through the specialization and through the member functions,
+ /// i.e. \ref temporary_allocator::allocate() and this \c allocate_node().
+ /// \ingroup allocator
+ template <>
+ class allocator_traits<temporary_allocator>
+ {
+ public:
+ using allocator_type = temporary_allocator;
+ using is_stateful = std::true_type;
+
+ /// \returns The result of \ref temporary_allocator::allocate().
+ static void* allocate_node(allocator_type& state, std::size_t size,
+ std::size_t alignment)
+ {
+ detail::check_allocation_size<bad_node_size>(size,
+ [&] { return max_node_size(state); },
+ {WPI_MEMORY_LOG_PREFIX
+ "::temporary_allocator",
+ &state});
+ return state.allocate(size, alignment);
+ }
+
+ /// \returns The result of \ref temporary_allocator::allocate().
+ static void* allocate_array(allocator_type& state, std::size_t count, std::size_t size,
+ std::size_t alignment)
+ {
+ return allocate_node(state, count * size, alignment);
+ }
+
+ /// @{
+ /// \effects Does nothing besides bookmarking for leak checking, if that is enabled.
+ /// Actual deallocation will be done automatically if the allocator object goes out of scope.
+ static void deallocate_node(const allocator_type&, void*, std::size_t,
+ std::size_t) noexcept
+ {
+ }
+
+ static void deallocate_array(const allocator_type&, void*, std::size_t, std::size_t,
+ std::size_t) noexcept
+ {
+ }
+ /// @}
+
+ /// @{
+ /// \returns The maximum size which is \ref memory_stack::next_capacity() of the internal stack.
+ static std::size_t max_node_size(const allocator_type& state) noexcept
+ {
+ return state.get_stack().next_capacity();
+ }
+
+ static std::size_t max_array_size(const allocator_type& state) noexcept
+ {
+ return max_node_size(state);
+ }
+ /// @}
+
+ /// \returns The maximum possible value since there is no alignment restriction
+ /// (except indirectly through \ref memory_stack::next_capacity()).
+ static std::size_t max_alignment(const allocator_type&) noexcept
+ {
+ return std::size_t(-1);
+ }
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif // WPI_MEMORY_TEMPORARY_ALLOCATOR_HPP_INCLUDED
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
new file mode 100644
index 0000000..0314ea4
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/threading.hpp
@@ -0,0 +1,155 @@
+// 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.
+
+#ifndef WPI_MEMORY_THREADING_HPP_INCLUDED
+#define WPI_MEMORY_THREADING_HPP_INCLUDED
+
+/// \file
+/// The mutex types.
+
+#include <type_traits>
+
+#include "allocator_traits.hpp"
+#include "config.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <mutex>
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ /// A dummy \c Mutex class that does not lock anything.
+ /// It is a valid \c Mutex and can be used to disable locking anywhere a \c Mutex is requested.
+ /// \ingroup core
+ struct no_mutex
+ {
+ void lock() noexcept {}
+
+ bool try_lock() noexcept
+ {
+ return true;
+ }
+
+ void unlock() noexcept {}
+ };
+
+ /// Specifies whether or not a \concept{concept_rawallocator,RawAllocator} is thread safe as-is.
+ /// This allows to use \ref no_mutex as an optimization.
+ /// Note that stateless allocators are implictly thread-safe.
+ /// Specialize it only for your own stateful allocators.
+ /// \ingroup core
+ template <class RawAllocator>
+ struct is_thread_safe_allocator
+ : std::integral_constant<bool, !allocator_traits<RawAllocator>::is_stateful::value>
+ {
+ };
+
+ namespace detail
+ {
+ // selects a mutex for an Allocator
+ // stateless allocators don't need locking
+ template <class RawAllocator, class Mutex>
+ using mutex_for =
+ typename std::conditional<is_thread_safe_allocator<RawAllocator>::value, no_mutex,
+ Mutex>::type;
+
+ // storage for mutexes to use EBO
+ // it provides const lock/unlock function, inherit from it
+ template <class Mutex>
+ class mutex_storage
+ {
+ public:
+ mutex_storage() noexcept = default;
+ mutex_storage(const mutex_storage&) noexcept {}
+
+ mutex_storage& operator=(const mutex_storage&) noexcept
+ {
+ return *this;
+ }
+
+ void lock() const
+ {
+ mutex_.lock();
+ }
+
+ void unlock() const noexcept
+ {
+ mutex_.unlock();
+ }
+
+ protected:
+ ~mutex_storage() noexcept = default;
+
+ private:
+ mutable Mutex mutex_;
+ };
+
+ template <>
+ class mutex_storage<no_mutex>
+ {
+ public:
+ mutex_storage() noexcept = default;
+
+ void lock() const noexcept {}
+ void unlock() const noexcept {}
+
+ protected:
+ ~mutex_storage() noexcept = default;
+ };
+
+ // non changeable pointer to an Allocator that keeps a lock
+ // I don't think EBO is necessary here...
+ template <class Alloc, class Mutex>
+ class locked_allocator
+ {
+ public:
+ locked_allocator(Alloc& alloc, Mutex& m) noexcept : mutex_(&m), alloc_(&alloc)
+ {
+ mutex_->lock();
+ }
+
+ locked_allocator(locked_allocator&& other) noexcept
+ : mutex_(other.mutex_), alloc_(other.alloc_)
+ {
+ other.mutex_ = nullptr;
+ other.alloc_ = nullptr;
+ }
+
+ ~locked_allocator() noexcept
+ {
+ if (mutex_)
+ mutex_->unlock();
+ }
+
+ locked_allocator& operator=(locked_allocator&& other) noexcept = delete;
+
+ Alloc& operator*() const noexcept
+ {
+ WPI_MEMORY_ASSERT(alloc_);
+ return *alloc_;
+ }
+
+ Alloc* operator->() const noexcept
+ {
+ WPI_MEMORY_ASSERT(alloc_);
+ return alloc_;
+ }
+
+ private:
+ Mutex* mutex_; // don't use unqiue_lock to avoid dependency
+ Alloc* alloc_;
+ };
+
+ template <class Alloc, class Mutex>
+ locked_allocator<Alloc, Mutex> lock_allocator(Alloc& a, Mutex& m)
+ {
+ return {a, m};
+ }
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..ccbc343
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/tracking.hpp
@@ -0,0 +1,430 @@
+// 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.
+
+#ifndef WPI_MEMORY_TRACKING_HPP_INCLUDED
+#define WPI_MEMORY_TRACKING_HPP_INCLUDED
+
+/// \file
+/// Class \ref wpi::memory::tracked_allocator and related classes and functions.
+
+#include "detail/utility.hpp"
+#include "allocator_traits.hpp"
+#include "memory_arena.hpp"
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ template <class Allocator, class Tracker>
+ auto set_tracker(int, Allocator& allocator, Tracker* tracker) noexcept
+ -> decltype(allocator.get_allocator().set_tracker(tracker))
+ {
+ return allocator.get_allocator().set_tracker(tracker);
+ }
+ template <class Allocator, class Tracker>
+ void set_tracker(short, Allocator&, Tracker*) noexcept
+ {
+ }
+
+ // used with deeply_tracked_allocator
+ template <class Tracker, class BlockAllocator>
+ class deeply_tracked_block_allocator : WPI_EBO(BlockAllocator)
+ {
+ public:
+ template <typename... Args>
+ deeply_tracked_block_allocator(std::size_t block_size, Args&&... args)
+ : BlockAllocator(block_size, detail::forward<Args>(args)...), tracker_(nullptr)
+ {
+ }
+
+ memory_block allocate_block()
+ {
+ auto block = BlockAllocator::allocate_block();
+ if (tracker_) // on first call tracker_ is nullptr
+ tracker_->on_allocator_growth(block.memory, block.size);
+ return block;
+ }
+
+ void deallocate_block(memory_block block) noexcept
+ {
+ if (tracker_) // on last call tracker_ is nullptr again
+ tracker_->on_allocator_shrinking(block.memory, block.size);
+ BlockAllocator::deallocate_block(block);
+ }
+
+ std::size_t next_block_size() const noexcept
+ {
+ return BlockAllocator::next_block_size();
+ }
+
+ void set_tracker(Tracker* tracker) noexcept
+ {
+ tracker_ = tracker;
+ }
+
+ private:
+ Tracker* tracker_;
+ };
+ } // namespace detail
+
+ /// A \concept{concept_blockallocator,BlockAllocator} adapter that tracks another allocator using a \concept{concept_tracker,tracker}.
+ /// It wraps another \concept{concept_blockallocator,BlockAllocator} and calls the tracker function before forwarding to it.
+ /// The class can then be used anywhere a \concept{concept_blockallocator,BlockAllocator} is required and the memory usage will be tracked.<br>
+ /// It will only call the <tt>on_allocator_growth()</tt> and <tt>on_allocator_shrinking()</tt> tracking functions,
+ /// since a \concept{concept_blockallocator,BlockAllocator} is normally used inside higher allocators only.
+ /// \ingroup adapter
+ template <class Tracker, class BlockOrRawAllocator>
+ class tracked_block_allocator
+ : WPI_EBO(Tracker, make_block_allocator_t<BlockOrRawAllocator>)
+ {
+ public:
+ using allocator_type = make_block_allocator_t<BlockOrRawAllocator>;
+ using tracker = Tracker;
+
+ /// @{
+ /// \effects Creates it by giving it a \concept{concept_tracker,tracker} and the tracked \concept{concept_rawallocator,RawAllocator}.
+ /// It will embed both objects.
+ explicit tracked_block_allocator(tracker t = {}) noexcept : tracker(detail::move(t)) {}
+
+ tracked_block_allocator(tracker t, allocator_type&& alloc) noexcept
+ : tracker(detail::move(t)), allocator_type(detail::move(alloc))
+ {
+ }
+ /// @}
+
+ /// \effects Creates it in the form required by the concept.
+ /// The allocator will be constructed using \c block_size and \c args.
+ template <typename... Args>
+ tracked_block_allocator(std::size_t block_size, tracker t, Args&&... args)
+ : tracker(detail::move(t)), allocator_type(block_size, detail::forward<Args>(args)...)
+ {
+ }
+
+ /// \effects Calls <tt>Tracker::on_allocator_growth()</tt> after forwarding to the allocator.
+ /// \returns The block as the returned by the allocator.
+ memory_block allocate_block()
+ {
+ auto block = allocator_type::allocate_block();
+ this->on_allocator_growth(block.memory, block.size);
+ return block;
+ }
+
+ /// \effects Calls <tt>Tracker::on_allocator_shrinking()</tt> and forwards to the allocator.
+ void deallocate_block(memory_block block) noexcept
+ {
+ this->on_allocator_shrinking(block.memory, block.size);
+ allocator_type::deallocate_block(block);
+ }
+
+ /// \returns The next block size as returned by the allocator.
+ std::size_t next_block_size() const noexcept
+ {
+ return allocator_type::next_block_size();
+ }
+
+ /// @{
+ /// \returns A (const) reference to the used allocator.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (const) reference to the tracker.
+ tracker& get_tracker() noexcept
+ {
+ return *this;
+ }
+
+ const tracker& get_tracker() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+ };
+
+ /// Similar to \ref tracked_block_allocator, but shares the tracker with the higher level allocator.
+ /// This allows tracking both (de-)allocations and growth with one tracker.
+ /// \note Due to implementation reasons, it cannot track growth and shrinking in the constructor/destructor of the higher level allocator.
+ /// \ingroup adapter
+ template <class Tracker, class BlockOrRawAllocator>
+ using deeply_tracked_block_allocator = WPI_IMPL_DEFINED(
+ detail::deeply_tracked_block_allocator<Tracker,
+ make_block_allocator_t<BlockOrRawAllocator>>);
+
+ /// A \concept{concept_rawallocator,RawAllocator} adapter that tracks another allocator using a \concept{concept_tracker,tracker}.
+ /// It wraps another \concept{concept_rawallocator,RawAllocator} and calls the tracker function before forwarding to it.
+ /// The class can then be used anywhere a \concept{concept_rawallocator,RawAllocator} is required and the memory usage will be tracked.<br>
+ /// If the \concept{concept_rawallocator,RawAllocator} uses \ref deeply_tracked_block_allocator as \concept{concept_blockallocator,BlockAllocator},
+ /// it will also track growth and shrinking of the allocator.
+ /// \ingroup adapter
+ template <class Tracker, class RawAllocator>
+ class tracked_allocator
+ : WPI_EBO(Tracker, allocator_traits<RawAllocator>::allocator_type)
+ {
+ using traits = allocator_traits<RawAllocator>;
+ using composable_traits = composable_allocator_traits<RawAllocator>;
+
+ public:
+ using allocator_type = typename allocator_traits<RawAllocator>::allocator_type;
+ using tracker = Tracker;
+
+ using is_stateful = std::integral_constant<bool, traits::is_stateful::value
+ || !std::is_empty<Tracker>::value>;
+
+ /// @{
+ /// \effects Creates it by giving it a \concept{concept_tracker,tracker} and the tracked \concept{concept_rawallocator,RawAllocator}.
+ /// It will embed both objects.
+ /// \note This will never call the <tt>Tracker::on_allocator_growth()</tt> function.
+ explicit tracked_allocator(tracker t = {}) noexcept
+ : tracked_allocator(detail::move(t), allocator_type{})
+ {
+ }
+
+ tracked_allocator(tracker t, allocator_type&& allocator) noexcept
+ : tracker(detail::move(t)), allocator_type(detail::move(allocator))
+ {
+ detail::set_tracker(0, get_allocator(), &get_tracker());
+ }
+ /// @}
+
+ /// \effects Destroys both tracker and allocator.
+ /// \note This will never call the <tt>Tracker::on_allocator_shrinking()</tt> function.
+ ~tracked_allocator() noexcept
+ {
+ detail::set_tracker(0, get_allocator(), static_cast<tracker*>(nullptr));
+ }
+
+ /// @{
+ /// \effects Moving moves both the tracker and the allocator.
+ tracked_allocator(tracked_allocator&& other) noexcept
+ : tracker(detail::move(other)), allocator_type(detail::move(other))
+ {
+ detail::set_tracker(0, get_allocator(), &get_tracker());
+ }
+
+ tracked_allocator& operator=(tracked_allocator&& other) noexcept
+ {
+ tracker:: operator=(detail::move(other));
+ allocator_type::operator=(detail::move(other));
+ detail::set_tracker(0, get_allocator(), &get_tracker());
+ return *this;
+ }
+ /// @}
+
+ /// \effects Calls <tt>Tracker::on_node_allocation()</tt> and forwards to the allocator.
+ /// If a growth occurs and the allocator is deeply tracked, also calls <tt>Tracker::on_allocator_growth()</tt>.
+ /// \returns The result of <tt>allocate_node()</tt>
+ void* allocate_node(std::size_t size, std::size_t alignment)
+ {
+ auto mem = traits::allocate_node(get_allocator(), size, alignment);
+ this->on_node_allocation(mem, size, alignment);
+ return mem;
+ }
+
+ /// \effects Calls the composable node allocation function.
+ /// If allocation was successful, also calls `Tracker::on_node_allocation()`.
+ /// \returns The result of `try_allocate_node()`.
+ void* try_allocate_node(std::size_t size, std::size_t alignment) noexcept
+ {
+ auto mem = composable_traits::try_allocate_node(get_allocator(), size, alignment);
+ if (mem)
+ this->on_node_allocation(mem, size, alignment);
+ return mem;
+ }
+
+ /// \effects Calls <tt>Tracker::on_array_allocation()</tt> and forwards to the allocator.
+ /// If a growth occurs and the allocator is deeply tracked, also calls <tt>Tracker::on_allocator_growth()</tt>.
+ /// \returns The result of <tt>allocate_array()</tt>
+ void* allocate_array(std::size_t count, std::size_t size, std::size_t alignment)
+ {
+ auto mem = traits::allocate_array(get_allocator(), count, size, alignment);
+ this->on_array_allocation(mem, count, size, alignment);
+ return mem;
+ }
+
+ /// \effects Calls the composable array allocation function.
+ /// If allocation was succesful, also calls `Tracker::on_array_allocation()`.
+ /// \returns The result of `try_allocate_array()`.
+ void* try_allocate_array(std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ auto mem =
+ composable_traits::try_allocate_array(get_allocator(), count, size, alignment);
+ if (mem)
+ this->on_array_allocation(mem, count, size, alignment);
+ return mem;
+ }
+
+ /// \effects Calls <tt>Tracker::on_node_deallocation()</tt> and forwards to the allocator's <tt>deallocate_node()</tt>.
+ /// If shrinking occurs and the allocator is deeply tracked, also calls <tt>Tracker::on_allocator_shrinking()</tt>.
+ void deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ this->on_node_deallocation(ptr, size, alignment);
+ traits::deallocate_node(get_allocator(), ptr, size, alignment);
+ }
+
+ /// \effects Calls the composable node deallocation function.
+ /// If it was succesful, also calls `Tracker::on_node_deallocation()`.
+ /// \returns The result of `try_deallocate_node()`.
+ bool try_deallocate_node(void* ptr, std::size_t size, std::size_t alignment) noexcept
+ {
+ auto res =
+ composable_traits::try_deallocate_node(get_allocator(), ptr, size, alignment);
+ if (res)
+ this->on_node_deallocation(ptr, size, alignment);
+ return res;
+ }
+
+ /// \effects Calls <tt>Tracker::on_array_deallocation()</tt> and forwards to the allocator's <tt>deallocate_array()</tt>.
+ /// If shrinking occurs and the allocator is deeply tracked, also calls <tt>Tracker::on_allocator_shrinking()</tt>.
+ void deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ this->on_array_deallocation(ptr, count, size, alignment);
+ traits::deallocate_array(get_allocator(), ptr, count, size, alignment);
+ }
+
+ /// \effects Calls the composable array deallocation function.
+ /// If it was succesful, also calls `Tracker::on_array_deallocation()`.
+ /// \returns The result of `try_deallocate_array()`.
+ bool try_deallocate_array(void* ptr, std::size_t count, std::size_t size,
+ std::size_t alignment) noexcept
+ {
+ auto res = composable_traits::try_deallocate_array(ptr, count, size, alignment);
+ if (res)
+ this->on_array_deallocation(ptr, count, size, alignment);
+ return res;
+ }
+
+ /// @{
+ /// \returns The result of the corresponding function on the wrapped allocator.
+ std::size_t max_node_size() const
+ {
+ return traits::max_node_size(get_allocator());
+ }
+
+ std::size_t max_array_size() const
+ {
+ return traits::max_array_size(get_allocator());
+ }
+
+ std::size_t max_alignment() const
+ {
+ return traits::max_alignment(get_allocator());
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (\c const) reference to the wrapped allocator.
+ allocator_type& get_allocator() noexcept
+ {
+ return *this;
+ }
+
+ const allocator_type& get_allocator() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+
+ /// @{
+ /// \returns A (\c const) reference to the tracker.
+ tracker& get_tracker() noexcept
+ {
+ return *this;
+ }
+
+ const tracker& get_tracker() const noexcept
+ {
+ return *this;
+ }
+ /// @}
+ };
+
+ /// \effects Takes a \concept{concept_rawallocator,RawAllocator} and wraps it with a \concept{concept_tracker,tracker}.
+ /// \returns A \ref tracked_allocator with the corresponding parameters forwarded to the constructor.
+ /// \relates tracked_allocator
+ template <class Tracker, class RawAllocator>
+ auto make_tracked_allocator(Tracker t, RawAllocator&& alloc)
+ -> tracked_allocator<Tracker, typename std::decay<RawAllocator>::type>
+ {
+ return tracked_allocator<Tracker, typename std::decay<RawAllocator>::type>{detail::move(
+ t),
+ detail::move(
+ alloc)};
+ }
+
+ namespace detail
+ {
+ template <typename T, bool Block>
+ struct is_block_or_raw_allocator_impl : std::true_type
+ {
+ };
+
+ template <typename T>
+ struct is_block_or_raw_allocator_impl<T, false> : memory::is_raw_allocator<T>
+ {
+ };
+
+ template <typename T>
+ struct is_block_or_raw_allocator
+ : is_block_or_raw_allocator_impl<T, memory::is_block_allocator<T>::value>
+ {
+ };
+
+ template <class RawAllocator, class BlockAllocator>
+ struct rebind_block_allocator;
+
+ template <template <typename...> class RawAllocator, typename... Args,
+ class OtherBlockAllocator>
+ struct rebind_block_allocator<RawAllocator<Args...>, OtherBlockAllocator>
+ {
+ using type =
+ RawAllocator<typename std::conditional<is_block_or_raw_allocator<Args>::value,
+ OtherBlockAllocator, Args>::type...>;
+ };
+
+ template <class Tracker, class RawAllocator>
+ using deeply_tracked_block_allocator_for =
+ memory::deeply_tracked_block_allocator<Tracker,
+ typename RawAllocator::allocator_type>;
+
+ template <class Tracker, class RawAllocator>
+ using rebound_allocator = typename rebind_block_allocator<
+ RawAllocator, deeply_tracked_block_allocator_for<Tracker, RawAllocator>>::type;
+ } // namespace detail
+
+ /// A \ref tracked_allocator that has rebound any \concept{concept_blockallocator,BlockAllocator} to the corresponding \ref deeply_tracked_block_allocator.
+ /// This makes it a deeply tracked allocator.<br>
+ /// It replaces each template argument of the given \concept{concept_rawallocator,RawAllocator} for which \ref is_block_allocator or \ref is_raw_allocator is \c true with a \ref deeply_tracked_block_allocator.
+ /// \ingroup adapter
+ template <class Tracker, class RawAllocator>
+ WPI_ALIAS_TEMPLATE(
+ deeply_tracked_allocator,
+ tracked_allocator<Tracker, detail::rebound_allocator<Tracker, RawAllocator>>);
+
+ /// \effects Takes a \concept{concept_rawallocator,RawAllocator} and deeply wraps it with a \concept{concept_tracker,tracker}.
+ /// \returns A \ref deeply_tracked_allocator with the corresponding parameters forwarded to the constructor.
+ /// \relates deeply_tracked_allocator
+ template <class RawAllocator, class Tracker, typename... Args>
+ auto make_deeply_tracked_allocator(Tracker t, Args&&... args)
+ -> deeply_tracked_allocator<Tracker, RawAllocator>
+ {
+ return deeply_tracked_allocator<Tracker, RawAllocator>(detail::move(t),
+ {detail::forward<Args>(
+ args)...});
+ }
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..33d82f7
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/include/wpi/memory/virtual_memory.hpp
@@ -0,0 +1,202 @@
+// 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.
+
+#ifndef WPI_MEMORY_VIRTUAL_MEMORY_HPP_INCLUDED
+#define WPI_MEMORY_VIRTUAL_MEMORY_HPP_INCLUDED
+
+/// \file
+/// Virtual memory api and (low-level) allocator classes.
+
+#include <cstddef>
+#include <type_traits>
+
+#include "detail/debug_helpers.hpp"
+#include "detail/utility.hpp"
+#include "config.hpp"
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+#include "allocator_traits.hpp"
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ struct virtual_memory_allocator_leak_handler
+ {
+ void operator()(std::ptrdiff_t amount);
+ };
+
+ WPI_MEMORY_GLOBAL_LEAK_CHECKER(virtual_memory_allocator_leak_handler,
+ virtual_memory_allocator_leak_checker)
+ } // namespace detail
+
+ /// The page size of the virtual memory.
+ /// All virtual memory allocations must be multiple of this size.
+ /// It is usually 4KiB.
+ /// \ingroup allocator
+ /// \deprecated use \ref get_virtual_memory_page_size instead.
+ extern const std::size_t virtual_memory_page_size;
+
+ /// \returns the page size of the virtual memory.
+ /// All virtual memory allocations must be multiple of this size.
+ /// It is usually 4KiB.
+ /// \ingroup allocator
+ std::size_t get_virtual_memory_page_size() noexcept;
+
+ /// Reserves virtual memory.
+ /// \effects Reserves the given number of pages.
+ /// Each page is \ref virtual_memory_page_size big.
+ /// \returns The address of the first reserved page,
+ /// or \c nullptr in case of error.
+ /// \note The memory may not be used, it must first be commited.
+ /// \ingroup allocator
+ void* virtual_memory_reserve(std::size_t no_pages) noexcept;
+
+ /// Releases reserved virtual memory.
+ /// \effects Returns previously reserved pages to the system.
+ /// \requires \c pages must come from a previous call to \ref virtual_memory_reserve with the same \c calc_no_pages,
+ /// it must not be \c nullptr.
+ /// \ingroup allocator
+ void virtual_memory_release(void* pages, std::size_t no_pages) noexcept;
+
+ /// Commits reserved virtual memory.
+ /// \effects Marks \c calc_no_pages pages starting at the given address available for use.
+ /// \returns The beginning of the committed area, i.e. \c memory, or \c nullptr in case of error.
+ /// \requires The memory must be previously reserved.
+ /// \ingroup allocator
+ void* virtual_memory_commit(void* memory, std::size_t no_pages) noexcept;
+
+ /// Decommits commited virtual memory.
+ /// \effects Puts commited memory back in the reserved state.
+ /// \requires \c memory must come from a previous call to \ref virtual_memory_commit with the same \c calc_no_pages
+ /// it must not be \c nullptr.
+ /// \ingroup allocator
+ void virtual_memory_decommit(void* memory, std::size_t no_pages) noexcept;
+
+ /// A stateless \concept{concept_rawallocator,RawAllocator} that allocates memory using the virtual memory allocation functions.
+ /// It does not prereserve any memory and will always reserve and commit combined.
+ /// \ingroup allocator
+ class virtual_memory_allocator
+ : WPI_EBO(detail::global_leak_checker<detail::virtual_memory_allocator_leak_handler>)
+ {
+ public:
+ using is_stateful = std::false_type;
+
+ virtual_memory_allocator() noexcept = default;
+ virtual_memory_allocator(virtual_memory_allocator&&) noexcept {}
+ ~virtual_memory_allocator() noexcept = default;
+
+ virtual_memory_allocator& operator=(virtual_memory_allocator&&) noexcept
+ {
+ return *this;
+ }
+
+ /// \effects A \concept{concept_rawallocator,RawAllocator} allocation function.
+ /// It uses \ref virtual_memory_reserve followed by \ref virtual_memory_commit for the allocation.
+ /// The number of pages allocated will be the minimum to hold \c size continuous bytes,
+ /// i.e. \c size will be rounded up to the next multiple.
+ /// If debug fences are activated, one additional page before and after the memory will be allocated.
+ /// \returns A pointer to a \concept{concept_node,node}, it will never be \c nullptr.
+ /// It will always be aligned on a fence boundary, regardless of the alignment parameter.
+ /// \throws An exception of type \ref out_of_memory or whatever is thrown by its handler if the allocation fails.
+ void* allocate_node(std::size_t size, std::size_t alignment);
+
+ /// \effects A \concept{concept_rawallocator,RawAllocator} deallocation function.
+ /// It calls \ref virtual_memory_decommit followed by \ref virtual_memory_release for the deallocation.
+ void deallocate_node(void* node, std::size_t size, std::size_t alignment) noexcept;
+
+ /// \returns The maximum node size by returning the maximum value.
+ std::size_t max_node_size() const noexcept;
+
+ /// \returns The maximum alignment which is the same as the \ref virtual_memory_page_size.
+ std::size_t max_alignment() const noexcept;
+ };
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+ extern template class allocator_traits<virtual_memory_allocator>;
+#endif
+
+ struct memory_block;
+ struct allocator_info;
+
+ /// A \concept{concept_blockallocator,BlockAllocator} that reserves virtual memory and commits it part by part.
+ /// It is similar to \ref memory_stack but does not support growing and uses virtual memory,
+ /// also meant for big blocks not small allocations.
+ /// \ingroup allocator
+ class virtual_block_allocator
+ {
+ public:
+ /// \effects Creates it giving it the block size and the total number of blocks it can allocate.
+ /// It reserves enough virtual memory for <tt>block_size * no_blocks</tt>.
+ /// \requires \c block_size must be non-zero and a multiple of the \ref virtual_memory_page_size.
+ /// \c no_blocks must be bigger than \c 1.
+ /// \throws \ref out_of_memory if it cannot reserve the virtual memory.
+ explicit virtual_block_allocator(std::size_t block_size, std::size_t no_blocks);
+
+ /// \effects Releases the reserved virtual memory.
+ ~virtual_block_allocator() noexcept;
+
+ /// @{
+ /// \effects Moves the block allocator, it transfers ownership over the reserved area.
+ /// This does not invalidate any memory blocks.
+ virtual_block_allocator(virtual_block_allocator&& other) noexcept
+ : cur_(other.cur_), end_(other.end_), block_size_(other.block_size_)
+ {
+ other.cur_ = other.end_ = nullptr;
+ other.block_size_ = 0;
+ }
+
+ virtual_block_allocator& operator=(virtual_block_allocator&& other) noexcept
+ {
+ virtual_block_allocator tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+ }
+ /// @}
+
+ /// \effects Swaps the ownership over the reserved memory.
+ /// This does not invalidate any memory blocks.
+ friend void swap(virtual_block_allocator& a, virtual_block_allocator& b) noexcept
+ {
+ detail::adl_swap(a.cur_, b.cur_);
+ detail::adl_swap(a.end_, b.end_);
+ detail::adl_swap(a.block_size_, b.block_size_);
+ }
+
+ /// \effects Allocates a new memory block by committing the next \ref next_block_size() number of bytes.
+ /// \returns The \ref memory_block committed.
+ /// \throws \ref out_of_memory if it cannot commit the memory or the \ref capacity_left() is exhausted.
+ memory_block allocate_block();
+
+ /// \effects Deallocates the last allocated memory block by decommitting it.
+ /// This block will be returned again on the next call to \ref allocate_block().
+ /// \requires \c block must be the current top block of the memory,
+ /// this is guaranteed by \ref memory_arena.
+ void deallocate_block(memory_block block) noexcept;
+
+ /// \returns The next block size, this is the block size of the constructor.
+ std::size_t next_block_size() const noexcept
+ {
+ return block_size_;
+ }
+
+ /// \returns The number of blocks that can be committed until it runs out of memory.
+ std::size_t capacity_left() const noexcept
+ {
+ return static_cast<std::size_t>(end_ - cur_) / block_size_;
+ }
+
+ private:
+ allocator_info info() noexcept;
+
+ char * cur_, *end_;
+ std::size_t block_size_;
+ };
+ } // namespace memory
+} // namespace wpi
+
+#endif //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
new file mode 100644
index 0000000..be1b033
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/debugging.cpp
@@ -0,0 +1,109 @@
+// 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.
+
+#include "wpi/memory/debugging.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <cstdio>
+#endif
+
+#include <atomic>
+#include <cstdlib>
+
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+
+namespace
+{
+ void default_leak_handler(const allocator_info& info, std::ptrdiff_t amount) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ if (amount > 0)
+ std::fprintf(stderr, "[%s] Allocator %s (at %p) leaked %zu bytes.\n",
+ WPI_MEMORY_LOG_PREFIX, info.name, info.allocator,
+ std::size_t(amount));
+ else
+ std::fprintf(stderr,
+ "[%s] Allocator %s (at %p) has deallocated %zu bytes more than "
+ "ever allocated "
+ "(it's amazing you're able to see this message!).\n",
+ WPI_MEMORY_LOG_PREFIX, info.name, info.allocator,
+ std::size_t(-amount));
+#else
+ (void)info;
+ (void)amount;
+#endif
+ }
+
+ std::atomic<leak_handler> leak_h(default_leak_handler);
+} // namespace
+
+leak_handler wpi::memory::set_leak_handler(leak_handler h)
+{
+ return leak_h.exchange(h ? h : default_leak_handler);
+}
+
+leak_handler wpi::memory::get_leak_handler()
+{
+ return leak_h;
+}
+
+namespace
+{
+ void default_invalid_ptr_handler(const allocator_info& info, const void* ptr) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr,
+ "[%s] Deallocation function of allocator %s (at %p) received invalid "
+ "pointer %p\n",
+ WPI_MEMORY_LOG_PREFIX, info.name, info.allocator, ptr);
+#endif
+ (void)info;
+ (void)ptr;
+ std::abort();
+ }
+
+ std::atomic<invalid_pointer_handler> invalid_ptr_h(default_invalid_ptr_handler);
+} // namespace
+
+invalid_pointer_handler wpi::memory::set_invalid_pointer_handler(invalid_pointer_handler h)
+{
+ return invalid_ptr_h.exchange(h ? h : default_invalid_ptr_handler);
+}
+
+invalid_pointer_handler wpi::memory::get_invalid_pointer_handler()
+{
+ return invalid_ptr_h;
+}
+
+namespace
+{
+ void default_buffer_overflow_handler(const void* memory, std::size_t node_size,
+ const void* ptr) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr,
+ "[%s] Buffer overflow at address %p detected, corresponding memory "
+ "block %p has only size %zu.\n",
+ WPI_MEMORY_LOG_PREFIX, ptr, memory, node_size);
+#endif
+ (void)memory;
+ (void)node_size;
+ (void)ptr;
+ std::abort();
+ }
+
+ std::atomic<buffer_overflow_handler> buffer_overflow_h(default_buffer_overflow_handler);
+} // namespace
+
+buffer_overflow_handler wpi::memory::set_buffer_overflow_handler(buffer_overflow_handler h)
+{
+ return buffer_overflow_h.exchange(h ? h : default_buffer_overflow_handler);
+}
+
+buffer_overflow_handler wpi::memory::get_buffer_overflow_handler()
+{
+ return buffer_overflow_h;
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp
new file mode 100644
index 0000000..e1c4f2a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/align.cpp
@@ -0,0 +1,22 @@
+// 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.
+
+#include "wpi/memory/detail/align.hpp"
+
+#include "wpi/memory/detail/ilog2.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+bool wpi::memory::detail::is_aligned(void* ptr, std::size_t alignment) noexcept
+{
+ WPI_MEMORY_ASSERT(is_valid_alignment(alignment));
+ auto address = reinterpret_cast<std::uintptr_t>(ptr);
+ return address % alignment == 0u;
+}
+
+std::size_t wpi::memory::detail::alignment_for(std::size_t size) noexcept
+{
+ return size >= max_alignment ? max_alignment : (std::size_t(1) << ilog2(size));
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp b/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp
new file mode 100644
index 0000000..497f7f8
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/assert.cpp
@@ -0,0 +1,34 @@
+// 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.
+
+#include "wpi/memory/detail/assert.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <cstdio>
+#endif
+
+#include <cstdlib>
+
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+void detail::handle_failed_assert(const char* msg, const char* file, int line,
+ const char* fnc) noexcept
+{
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr, "[%s] Assertion failure in function %s (%s:%d): %s.\n",
+ WPI_MEMORY_LOG_PREFIX, fnc, file, line, msg);
+#endif
+ std::abort();
+}
+
+void detail::handle_warning(const char* msg, const char* file, int line, const char* fnc) noexcept
+{
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr, "[%s] Warning triggered in function %s (%s:%d): %s.\n",
+ WPI_MEMORY_LOG_PREFIX, fnc, file, line, msg);
+#endif
+}
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
new file mode 100644
index 0000000..b5afb20
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/debug_helpers.cpp
@@ -0,0 +1,87 @@
+// 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.
+
+#include "wpi/memory/detail/debug_helpers.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <cstring>
+#endif
+
+#include "wpi/memory/debugging.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+#if WPI_MEMORY_DEBUG_FILL
+void detail::debug_fill(void* memory, std::size_t size, debug_magic m) noexcept
+{
+#if WPI_HOSTED_IMPLEMENTATION
+ std::memset(memory, static_cast<int>(m), size);
+#else
+ // do the naive loop :(
+ auto ptr = static_cast<unsigned char*>(memory);
+ for (std::size_t i = 0u; i != size; ++i)
+ *ptr++ = static_cast<unsigned char>(m);
+#endif
+}
+
+void* detail::debug_is_filled(void* memory, std::size_t size, debug_magic m) noexcept
+{
+ auto byte = static_cast<unsigned char*>(memory);
+ for (auto end = byte + size; byte != end; ++byte)
+ if (*byte != static_cast<unsigned char>(m))
+ return byte;
+ return nullptr;
+}
+
+void* detail::debug_fill_new(void* memory, std::size_t node_size, std::size_t fence_size) noexcept
+{
+ if (!debug_fence_size)
+ fence_size = 0u; // force override of fence_size
+
+ auto mem = static_cast<char*>(memory);
+ debug_fill(mem, fence_size, debug_magic::fence_memory);
+
+ mem += fence_size;
+ debug_fill(mem, node_size, debug_magic::new_memory);
+
+ debug_fill(mem + node_size, fence_size, debug_magic::fence_memory);
+
+ return mem;
+}
+
+void* detail::debug_fill_free(void* memory, std::size_t node_size, std::size_t fence_size) noexcept
+{
+ if (!debug_fence_size)
+ fence_size = 0u; // force override of fence_size
+
+ debug_fill(memory, node_size, debug_magic::freed_memory);
+
+ auto pre_fence = static_cast<unsigned char*>(memory) - fence_size;
+ if (auto pre_dirty = debug_is_filled(pre_fence, fence_size, debug_magic::fence_memory))
+ get_buffer_overflow_handler()(memory, node_size, pre_dirty);
+
+ auto post_mem = static_cast<unsigned char*>(memory) + node_size;
+ if (auto post_dirty = debug_is_filled(post_mem, fence_size, debug_magic::fence_memory))
+ get_buffer_overflow_handler()(memory, node_size, post_dirty);
+
+ return pre_fence;
+}
+
+void detail::debug_fill_internal(void* memory, std::size_t size, bool free) noexcept
+{
+ debug_fill(memory, size,
+ free ? debug_magic::internal_freed_memory : debug_magic::internal_memory);
+}
+#endif
+
+void detail::debug_handle_invalid_ptr(const allocator_info& info, void* ptr)
+{
+ get_invalid_pointer_handler()(info, ptr);
+}
+
+void detail::debug_handle_memory_leak(const allocator_info& info, std::ptrdiff_t amount)
+{
+ get_leak_handler()(info, amount);
+}
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
new file mode 100644
index 0000000..2ca7034
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list.cpp
@@ -0,0 +1,557 @@
+// 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.
+
+#include "wpi/memory/detail/free_list.hpp"
+
+#include "wpi/memory/detail/align.hpp"
+#include "wpi/memory/detail/debug_helpers.hpp"
+#include "wpi/memory/detail/assert.hpp"
+#include "wpi/memory/debugging.hpp"
+#include "wpi/memory/error.hpp"
+
+#include "free_list_utils.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+namespace
+{
+ // i.e. array
+ struct interval
+ {
+ char* prev; // last before
+ char* first; // first in
+ char* last; // last in
+ char* next; // first after
+
+ // number of nodes in the interval
+ std::size_t size(std::size_t node_size) const noexcept
+ {
+ // last is inclusive, so add actual_size to it
+ // note: cannot use next, might not be directly after
+ auto end = last + node_size;
+ WPI_MEMORY_ASSERT(static_cast<std::size_t>(end - first) % node_size == 0u);
+ return static_cast<std::size_t>(end - first) / node_size;
+ }
+ };
+
+ // searches for n consecutive bytes
+ // begin and end are the proxy nodes
+ // assumes list is not empty
+ // similar to list_search_array()
+ interval list_search_array(char* first, std::size_t bytes_needed,
+ std::size_t node_size) noexcept
+ {
+ interval i;
+ i.prev = nullptr;
+ i.first = first;
+ // i.last/next are used as iterator for the end of the interval
+ i.last = first;
+ i.next = list_get_next(first);
+
+ auto bytes_so_far = node_size;
+ while (i.next)
+ {
+ if (i.last + node_size != i.next) // not continous
+ {
+ // restart at next
+ i.prev = i.last;
+ i.first = i.next;
+ i.last = i.next;
+ i.next = list_get_next(i.last);
+
+ bytes_so_far = node_size;
+ }
+ else
+ {
+ // extend interval
+ auto new_next = list_get_next(i.next);
+ i.last = i.next;
+ i.next = new_next;
+
+ bytes_so_far += node_size;
+ if (bytes_so_far >= bytes_needed)
+ return i;
+ }
+ }
+ // not enough continuous space
+ return {nullptr, nullptr, nullptr, nullptr};
+ }
+
+ // similar to list_search_array()
+ // begin/end are proxy nodes
+ interval xor_list_search_array(char* begin, char* end, std::size_t bytes_needed,
+ std::size_t node_size) noexcept
+ {
+ interval i;
+ i.prev = begin;
+ i.first = xor_list_get_other(begin, nullptr);
+ // i.last/next are used as iterator for the end of the interval
+ i.last = i.first;
+ i.next = xor_list_get_other(i.last, i.prev);
+
+ auto bytes_so_far = node_size;
+ while (i.next != end)
+ {
+ if (i.last + node_size != i.next) // not continous
+ {
+ // restart at i.next
+ i.prev = i.last;
+ i.first = i.next;
+ i.last = i.next;
+ i.next = xor_list_get_other(i.first, i.prev);
+
+ bytes_so_far = node_size;
+ }
+ else
+ {
+ // extend interval
+ auto new_next = xor_list_get_other(i.next, i.last);
+ i.last = i.next;
+ i.next = new_next;
+
+ bytes_so_far += node_size;
+ if (bytes_so_far >= bytes_needed)
+ return i;
+ }
+ }
+ // not enough continuous space
+ return {nullptr, nullptr, nullptr, nullptr};
+ }
+} // namespace
+
+constexpr std::size_t free_memory_list::min_element_size;
+constexpr std::size_t free_memory_list::min_element_alignment;
+
+free_memory_list::free_memory_list(std::size_t node_size) noexcept
+: first_(nullptr),
+ node_size_(node_size > min_element_size ? node_size : min_element_size),
+ capacity_(0u)
+{
+}
+
+free_memory_list::free_memory_list(std::size_t node_size, void* mem, std::size_t size) noexcept
+: free_memory_list(node_size)
+{
+ insert(mem, size);
+}
+
+free_memory_list::free_memory_list(free_memory_list&& other) noexcept
+: first_(other.first_), node_size_(other.node_size_), capacity_(other.capacity_)
+{
+ other.first_ = nullptr;
+ other.capacity_ = 0u;
+}
+
+free_memory_list& free_memory_list::operator=(free_memory_list&& other) noexcept
+{
+ free_memory_list tmp(detail::move(other));
+ swap(*this, tmp);
+ return *this;
+}
+
+void wpi::memory::detail::swap(free_memory_list& a, free_memory_list& b) noexcept
+{
+ detail::adl_swap(a.first_, b.first_);
+ detail::adl_swap(a.node_size_, b.node_size_);
+ detail::adl_swap(a.capacity_, b.capacity_);
+}
+
+void free_memory_list::insert(void* mem, std::size_t size) noexcept
+{
+ WPI_MEMORY_ASSERT(mem);
+ WPI_MEMORY_ASSERT(is_aligned(mem, alignment()));
+ detail::debug_fill_internal(mem, size, false);
+
+ insert_impl(mem, size);
+}
+
+void* free_memory_list::allocate() noexcept
+{
+ WPI_MEMORY_ASSERT(!empty());
+ --capacity_;
+
+ auto mem = first_;
+ first_ = list_get_next(first_);
+ return detail::debug_fill_new(mem, node_size_, 0);
+}
+
+void* free_memory_list::allocate(std::size_t n) noexcept
+{
+ WPI_MEMORY_ASSERT(!empty());
+ if (n <= node_size_)
+ return allocate();
+
+ auto i = list_search_array(first_, n, node_size_);
+ if (i.first == nullptr)
+ return nullptr;
+
+ if (i.prev)
+ list_set_next(i.prev, i.next); // change next from previous to first after
+ else
+ first_ = i.next;
+ capacity_ -= i.size(node_size_);
+
+ return detail::debug_fill_new(i.first, n, 0);
+}
+
+void free_memory_list::deallocate(void* ptr) noexcept
+{
+ ++capacity_;
+
+ auto node = static_cast<char*>(detail::debug_fill_free(ptr, node_size_, 0));
+ list_set_next(node, first_);
+ first_ = node;
+}
+
+void free_memory_list::deallocate(void* ptr, std::size_t n) noexcept
+{
+ if (n <= node_size_)
+ deallocate(ptr);
+ else
+ {
+ auto mem = detail::debug_fill_free(ptr, n, 0);
+ insert_impl(mem, n);
+ }
+}
+
+std::size_t free_memory_list::alignment() const noexcept
+{
+ return alignment_for(node_size_);
+}
+
+void free_memory_list::insert_impl(void* mem, std::size_t size) noexcept
+{
+ auto no_nodes = size / node_size_;
+ WPI_MEMORY_ASSERT(no_nodes > 0);
+
+ auto cur = static_cast<char*>(mem);
+ for (std::size_t i = 0u; i != no_nodes - 1; ++i)
+ {
+ list_set_next(cur, cur + node_size_);
+ cur += node_size_;
+ }
+ list_set_next(cur, first_);
+ first_ = static_cast<char*>(mem);
+
+ capacity_ += no_nodes;
+}
+
+namespace
+{
+ // converts a block into a linked list
+ void xor_link_block(void* memory, std::size_t node_size, std::size_t no_nodes, char* prev,
+ char* next) noexcept
+ {
+ auto cur = static_cast<char*>(memory);
+ xor_list_change(prev, next, cur); // change next pointer of prev
+
+ auto last_cur = prev;
+ for (std::size_t i = 0u; i != no_nodes - 1; ++i)
+ {
+ xor_list_set(cur, last_cur,
+ cur + node_size); // cur gets last_cur and next node in continous memory
+ last_cur = cur;
+ cur += node_size;
+ }
+ xor_list_set(cur, last_cur, next); // last memory node gets next as next
+ xor_list_change(next, prev, cur); // change prev pointer of next
+ }
+
+ struct pos
+ {
+ char *prev, *next;
+ };
+
+ // finds position to insert memory to keep list ordered
+ // first_prev -> first -> ... (memory somewhere here) ... -> last -> last_next
+ pos find_pos_interval(const allocator_info& info, char* memory, char* first_prev, char* first,
+ char* last, char* last_next) noexcept
+ {
+ // note: first_prev/last_next can be the proxy nodes, then first_prev isn't necessarily less than first!
+ WPI_MEMORY_ASSERT(less(first, memory) && less(memory, last));
+
+ // need to insert somewhere in the middle
+ // search through the entire list
+ // search from both ends at once
+ auto cur_forward = first;
+ auto prev_forward = first_prev;
+
+ auto cur_backward = last;
+ auto prev_backward = last_next;
+
+ do
+ {
+ if (greater(cur_forward, memory))
+ return {prev_forward, cur_forward};
+ else if (less(cur_backward, memory))
+ // the next position is the previous backwards pointer
+ return {cur_backward, prev_backward};
+ debug_check_double_dealloc([&]
+ { return cur_forward != memory && cur_backward != memory; },
+ info, memory);
+ xor_list_iter_next(cur_forward, prev_forward);
+ xor_list_iter_next(cur_backward, prev_backward);
+ } while (less(prev_forward, prev_backward));
+
+ // ran outside of list
+ debug_check_double_dealloc([] { return false; }, info, memory);
+ return {nullptr, nullptr};
+ }
+
+ // finds the position in the entire list
+ pos find_pos(const allocator_info& info, char* memory, char* begin_node, char* end_node,
+ char* last_dealloc, char* last_dealloc_prev) noexcept
+ {
+ auto first = xor_list_get_other(begin_node, nullptr);
+ auto last = xor_list_get_other(end_node, nullptr);
+
+ if (greater(first, memory))
+ // insert at front
+ return {begin_node, first};
+ else if (less(last, memory))
+ // insert at the end
+ return {last, end_node};
+ else if (less(last_dealloc_prev, memory) && less(memory, last_dealloc))
+ // insert before last_dealloc
+ return {last_dealloc_prev, last_dealloc};
+ else if (less(memory, last_dealloc))
+ // insert into [first, last_dealloc_prev]
+ return find_pos_interval(info, memory, begin_node, first, last_dealloc_prev,
+ last_dealloc);
+ else if (greater(memory, last_dealloc))
+ // insert into (last_dealloc, last]
+ return find_pos_interval(info, memory, last_dealloc_prev, last_dealloc, last, end_node);
+
+ WPI_MEMORY_UNREACHABLE("memory must be in some half or outside");
+ return {nullptr, nullptr};
+ }
+} // namespace
+
+constexpr std::size_t ordered_free_memory_list::min_element_size;
+constexpr std::size_t ordered_free_memory_list::min_element_alignment;
+
+ordered_free_memory_list::ordered_free_memory_list(std::size_t node_size) noexcept
+: node_size_(node_size > min_element_size ? node_size : min_element_size),
+ capacity_(0u),
+ last_dealloc_(end_node()),
+ last_dealloc_prev_(begin_node())
+{
+ xor_list_set(begin_node(), nullptr, end_node());
+ xor_list_set(end_node(), begin_node(), nullptr);
+}
+
+ordered_free_memory_list::ordered_free_memory_list(ordered_free_memory_list&& other) noexcept
+: node_size_(other.node_size_), capacity_(other.capacity_)
+{
+ if (!other.empty())
+ {
+ auto first = xor_list_get_other(other.begin_node(), nullptr);
+ auto last = xor_list_get_other(other.end_node(), nullptr);
+
+ xor_list_set(begin_node(), nullptr, first);
+ xor_list_change(first, other.begin_node(), begin_node());
+ xor_list_change(last, other.end_node(), end_node());
+ xor_list_set(end_node(), last, nullptr);
+
+ other.capacity_ = 0u;
+ xor_list_set(other.begin_node(), nullptr, other.end_node());
+ xor_list_set(other.end_node(), other.begin_node(), nullptr);
+ }
+ else
+ {
+ xor_list_set(begin_node(), nullptr, end_node());
+ xor_list_set(end_node(), begin_node(), nullptr);
+ }
+
+ // for programming convenience, last_dealloc is reset
+ last_dealloc_prev_ = begin_node();
+ last_dealloc_ = xor_list_get_other(last_dealloc_prev_, nullptr);
+}
+
+void wpi::memory::detail::swap(ordered_free_memory_list& a,
+ ordered_free_memory_list& b) noexcept
+{
+ auto a_first = xor_list_get_other(a.begin_node(), nullptr);
+ auto a_last = xor_list_get_other(a.end_node(), nullptr);
+
+ auto b_first = xor_list_get_other(b.begin_node(), nullptr);
+ auto b_last = xor_list_get_other(b.end_node(), nullptr);
+
+ if (!a.empty())
+ {
+ xor_list_set(b.begin_node(), nullptr, a_first);
+ xor_list_change(a_first, a.begin_node(), b.begin_node());
+ xor_list_change(a_last, a.end_node(), b.end_node());
+ xor_list_set(b.end_node(), a_last, nullptr);
+ }
+ else
+ {
+ xor_list_set(b.begin_node(), nullptr, b.end_node());
+ xor_list_set(b.end_node(), b.begin_node(), nullptr);
+ }
+
+ if (!b.empty())
+ {
+ xor_list_set(a.begin_node(), nullptr, b_first);
+ xor_list_change(b_first, b.begin_node(), a.begin_node());
+ xor_list_change(b_last, b.end_node(), a.end_node());
+ xor_list_set(a.end_node(), b_last, nullptr);
+ }
+ else
+ {
+ xor_list_set(a.begin_node(), nullptr, a.end_node());
+ xor_list_set(a.end_node(), a.begin_node(), nullptr);
+ }
+
+ detail::adl_swap(a.node_size_, b.node_size_);
+ detail::adl_swap(a.capacity_, b.capacity_);
+
+ // for programming convenience, last_dealloc is reset
+ a.last_dealloc_prev_ = a.begin_node();
+ a.last_dealloc_ = xor_list_get_other(a.last_dealloc_prev_, nullptr);
+
+ b.last_dealloc_prev_ = b.begin_node();
+ b.last_dealloc_ = xor_list_get_other(b.last_dealloc_prev_, nullptr);
+}
+
+void ordered_free_memory_list::insert(void* mem, std::size_t size) noexcept
+{
+ WPI_MEMORY_ASSERT(mem);
+ WPI_MEMORY_ASSERT(is_aligned(mem, alignment()));
+ detail::debug_fill_internal(mem, size, false);
+
+ insert_impl(mem, size);
+}
+
+void* ordered_free_memory_list::allocate() noexcept
+{
+ WPI_MEMORY_ASSERT(!empty());
+
+ // remove first node
+ auto prev = begin_node();
+ auto node = xor_list_get_other(prev, nullptr);
+ auto next = xor_list_get_other(node, prev);
+
+ xor_list_set(prev, nullptr, next); // link prev to next
+ xor_list_change(next, node, prev); // change prev of next
+ --capacity_;
+
+ if (node == last_dealloc_)
+ {
+ // move last_dealloc_ one further in
+ last_dealloc_ = next;
+ WPI_MEMORY_ASSERT(last_dealloc_prev_ == prev);
+ }
+ else if (node == last_dealloc_prev_)
+ {
+ // now the previous node is the node before ours
+ last_dealloc_prev_ = prev;
+ WPI_MEMORY_ASSERT(last_dealloc_ == next);
+ }
+
+ return detail::debug_fill_new(node, node_size_, 0);
+}
+
+void* ordered_free_memory_list::allocate(std::size_t n) noexcept
+{
+ WPI_MEMORY_ASSERT(!empty());
+
+ if (n <= node_size_)
+ return allocate();
+
+ auto i = xor_list_search_array(begin_node(), end_node(), n, node_size_);
+ if (i.first == nullptr)
+ return nullptr;
+
+ xor_list_change(i.prev, i.first, i.next); // change next pointer from i.prev to i.next
+ xor_list_change(i.next, i.last, i.prev); // change prev pointer from i.next to i.prev
+ capacity_ -= i.size(node_size_);
+
+ // if last_dealloc_ points into the array being removed
+ if ((less_equal(i.first, last_dealloc_) && less_equal(last_dealloc_, i.last)))
+ {
+ // move last_dealloc just outside range
+ last_dealloc_ = i.next;
+ last_dealloc_prev_ = i.prev;
+ }
+ // if the previous deallocation is the last element of the array
+ else if (last_dealloc_prev_ == i.last)
+ {
+ // it is now the last element before the array
+ WPI_MEMORY_ASSERT(last_dealloc_ == i.next);
+ last_dealloc_prev_ = i.prev;
+ }
+
+ return detail::debug_fill_new(i.first, n, 0);
+}
+
+void ordered_free_memory_list::deallocate(void* ptr) noexcept
+{
+ auto node = static_cast<char*>(debug_fill_free(ptr, node_size_, 0));
+
+ auto p =
+ find_pos(allocator_info(WPI_MEMORY_LOG_PREFIX "::detail::ordered_free_memory_list",
+ this),
+ node, begin_node(), end_node(), last_dealloc_, last_dealloc_prev_);
+
+ xor_list_insert(node, p.prev, p.next);
+ ++capacity_;
+
+ last_dealloc_ = node;
+ last_dealloc_prev_ = p.prev;
+}
+
+void ordered_free_memory_list::deallocate(void* ptr, std::size_t n) noexcept
+{
+ if (n <= node_size_)
+ deallocate(ptr);
+ else
+ {
+ auto mem = detail::debug_fill_free(ptr, n, 0);
+ auto prev = insert_impl(mem, n);
+
+ last_dealloc_ = static_cast<char*>(mem);
+ last_dealloc_prev_ = prev;
+ }
+}
+
+std::size_t ordered_free_memory_list::alignment() const noexcept
+{
+ return alignment_for(node_size_);
+}
+
+char* ordered_free_memory_list::insert_impl(void* mem, std::size_t size) noexcept
+{
+ auto no_nodes = size / node_size_;
+ WPI_MEMORY_ASSERT(no_nodes > 0);
+
+ auto p =
+ find_pos(allocator_info(WPI_MEMORY_LOG_PREFIX "::detail::ordered_free_memory_list",
+ this),
+ static_cast<char*>(mem), begin_node(), end_node(), last_dealloc_,
+ last_dealloc_prev_);
+
+ xor_link_block(mem, node_size_, no_nodes, p.prev, p.next);
+ capacity_ += no_nodes;
+
+ if (p.prev == last_dealloc_prev_)
+ {
+ last_dealloc_ = static_cast<char*>(mem);
+ }
+
+ return p.prev;
+}
+
+char* ordered_free_memory_list::begin_node() noexcept
+{
+ void* mem = &begin_proxy_;
+ return static_cast<char*>(mem);
+}
+
+char* ordered_free_memory_list::end_node() noexcept
+{
+ void* mem = &end_proxy_;
+ return static_cast<char*>(mem);
+}
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
new file mode 100644
index 0000000..f4658da
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_array.cpp
@@ -0,0 +1,22 @@
+// 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.
+
+#include "wpi/memory/detail/free_list_array.hpp"
+
+#include "wpi/memory/detail/assert.hpp"
+#include "wpi/memory/detail/ilog2.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+std::size_t log2_access_policy::index_from_size(std::size_t size) noexcept
+{
+ WPI_MEMORY_ASSERT_MSG(size, "size must not be zero");
+ return ilog2_ceil(size);
+}
+
+std::size_t log2_access_policy::size_from_index(std::size_t index) noexcept
+{
+ return std::size_t(1) << index;
+}
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
new file mode 100644
index 0000000..a752837
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/free_list_utils.hpp
@@ -0,0 +1,149 @@
+// 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.
+
+#ifndef WPI_MEMORY_SRC_DETAIL_FREE_LIST_UTILS_HPP_INCLUDED
+#define WPI_MEMORY_SRC_DETAIL_FREE_LIST_UTILS_HPP_INCLUDED
+
+#include <cstdint>
+
+#include "wpi/memory/config.hpp"
+#include "wpi/memory/detail/align.hpp"
+#include "wpi/memory/detail/assert.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <cstring>
+#include <functional>
+#endif
+
+namespace wpi
+{
+ namespace memory
+ {
+ namespace detail
+ {
+ //=== storage ===///
+ // reads stored integer value
+ inline std::uintptr_t get_int(void* address) noexcept
+ {
+ WPI_MEMORY_ASSERT(address);
+ std::uintptr_t res;
+#if WPI_HOSTED_IMPLEMENTATION
+ std::memcpy(&res, address, sizeof(std::uintptr_t));
+#else
+ auto mem = static_cast<char*>(static_cast<void*>(&res));
+ for (auto i = 0u; i != sizeof(std::uintptr_t); ++i)
+ mem[i] = static_cast<char*>(address)[i];
+#endif
+ return res;
+ }
+
+ // sets stored integer value
+ inline void set_int(void* address, std::uintptr_t i) noexcept
+ {
+ WPI_MEMORY_ASSERT(address);
+#if WPI_HOSTED_IMPLEMENTATION
+ std::memcpy(address, &i, sizeof(std::uintptr_t));
+#else
+ auto mem = static_cast<char*>(static_cast<void*>(&i));
+ for (auto i = 0u; i != sizeof(std::uintptr_t); ++i)
+ static_cast<char*>(address)[i] = mem[i];
+#endif
+ }
+
+ // pointer to integer
+ inline std::uintptr_t to_int(char* ptr) noexcept
+ {
+ return reinterpret_cast<std::uintptr_t>(ptr);
+ }
+
+ // integer to pointer
+ inline char* from_int(std::uintptr_t i) noexcept
+ {
+ return reinterpret_cast<char*>(i);
+ }
+
+ //=== intrusive linked list ===//
+ // reads a stored pointer value
+ inline char* list_get_next(void* address) noexcept
+ {
+ return from_int(get_int(address));
+ }
+
+ // stores a pointer value
+ inline void list_set_next(void* address, char* ptr) noexcept
+ {
+ set_int(address, to_int(ptr));
+ }
+
+ //=== intrusive xor linked list ===//
+ // returns the other pointer given one pointer
+ inline char* xor_list_get_other(void* address, char* prev_or_next) noexcept
+ {
+ return from_int(get_int(address) ^ to_int(prev_or_next));
+ }
+
+ // sets the next and previous pointer (order actually does not matter)
+ inline void xor_list_set(void* address, char* prev, char* next) noexcept
+ {
+ set_int(address, to_int(prev) ^ to_int(next));
+ }
+
+ // changes other pointer given one pointer
+ inline void xor_list_change(void* address, char* old_ptr, char* new_ptr) noexcept
+ {
+ WPI_MEMORY_ASSERT(address);
+ auto other = xor_list_get_other(address, old_ptr);
+ xor_list_set(address, other, new_ptr);
+ }
+
+ // advances a pointer pair forward/backward
+ inline void xor_list_iter_next(char*& cur, char*& prev) noexcept
+ {
+ auto next = xor_list_get_other(cur, prev);
+ prev = cur;
+ cur = next;
+ }
+
+ // links new node between prev and next
+ inline void xor_list_insert(char* new_node, char* prev, char* next) noexcept
+ {
+ xor_list_set(new_node, prev, next);
+ xor_list_change(prev, next, new_node); // change prev's next to new_node
+ xor_list_change(next, prev, new_node); // change next's prev to new_node
+ }
+
+ //=== sorted list utils ===//
+ // if std::less/std::greater not available compare integer representation and hope it works
+ inline bool less(void* a, void* b) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ return std::less<void*>()(a, b);
+#else
+ return to_int(a) < to_int(b);
+#endif
+ }
+
+ inline bool less_equal(void* a, void* b) noexcept
+ {
+ return a == b || less(a, b);
+ }
+
+ inline bool greater(void* a, void* b) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ return std::greater<void*>()(a, b);
+#else
+ return to_int(a) < to_int(b);
+#endif
+ }
+
+ inline bool greater_equal(void* a, void* b) noexcept
+ {
+ return a == b || greater(a, b);
+ }
+ } // namespace detail
+ } // namespace memory
+} // namespace wpi
+
+#endif // 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
new file mode 100644
index 0000000..3508daa
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/detail/small_free_list.cpp
@@ -0,0 +1,395 @@
+// 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.
+
+#include "wpi/memory/detail/small_free_list.hpp"
+
+#include <new>
+
+#include "wpi/memory/detail/debug_helpers.hpp"
+#include "wpi/memory/detail/assert.hpp"
+#include "wpi/memory/error.hpp"
+
+#include "free_list_utils.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+struct wpi::memory::detail::chunk : chunk_base
+{
+ // gives it the size of the memory block it is created in and the size of a node
+ chunk(std::size_t total_memory, std::size_t node_size) noexcept
+ : chunk_base(static_cast<unsigned char>((total_memory - chunk_memory_offset) / node_size))
+ {
+ static_assert(sizeof(chunk) == sizeof(chunk_base), "chunk must not have members");
+ WPI_MEMORY_ASSERT((total_memory - chunk_memory_offset) / node_size
+ <= chunk_max_nodes);
+ WPI_MEMORY_ASSERT(capacity > 0);
+ auto p = list_memory();
+ for (unsigned char i = 0u; i != no_nodes; p += node_size)
+ *p = ++i;
+ }
+
+ // returns memory of the free list
+ unsigned char* list_memory() noexcept
+ {
+ auto mem = static_cast<void*>(this);
+ return static_cast<unsigned char*>(mem) + chunk_memory_offset;
+ }
+
+ // returns the nth node
+ unsigned char* node_memory(unsigned char i, std::size_t node_size) noexcept
+ {
+ WPI_MEMORY_ASSERT(i < no_nodes);
+ return list_memory() + i * node_size;
+ }
+
+ // checks whether a node came from this chunk
+ bool from(unsigned char* node, std::size_t node_size) noexcept
+ {
+ auto begin = list_memory();
+ auto end = list_memory() + no_nodes * node_size;
+ return (begin <= node) & (node < end);
+ }
+
+ // checks whether a node is already in this chunk
+ bool contains(unsigned char* node, std::size_t node_size) noexcept
+ {
+ auto cur_index = first_free;
+ while (cur_index != no_nodes)
+ {
+ auto cur_mem = node_memory(cur_index, node_size);
+ if (cur_mem == node)
+ return true;
+ cur_index = *cur_mem;
+ }
+ return false;
+ }
+
+ // allocates a single node
+ // chunk most not be empty
+ unsigned char* allocate(std::size_t node_size) noexcept
+ {
+ --capacity;
+
+ auto node = node_memory(first_free, node_size);
+ first_free = *node;
+ return node;
+ }
+
+ // deallocates a single node given its address and index
+ // it must be from this chunk
+ void deallocate(unsigned char* node, unsigned char node_index) noexcept
+ {
+ ++capacity;
+
+ *node = first_free;
+ first_free = node_index;
+ }
+};
+
+namespace
+{
+ // converts a chunk_base to a chunk (if it is one)
+ chunk* make_chunk(chunk_base* c) noexcept
+ {
+ return static_cast<chunk*>(c);
+ }
+
+ // same as above but also requires a certain size
+ chunk* make_chunk(chunk_base* c, std::size_t size_needed) noexcept
+ {
+ WPI_MEMORY_ASSERT(size_needed <= chunk_max_nodes);
+ return c->capacity >= size_needed ? make_chunk(c) : nullptr;
+ }
+
+ // checks if memory was from a chunk, assumes chunk isn't proxy
+ chunk* from_chunk(chunk_base* c, unsigned char* node, std::size_t node_size) noexcept
+ {
+ auto res = make_chunk(c);
+ return res->from(node, node_size) ? res : nullptr;
+ }
+
+ // inserts already interconnected chunks into the list
+ // list will be kept ordered
+ void insert_chunks(chunk_base* list, chunk_base* begin, chunk_base* end) noexcept
+ {
+ WPI_MEMORY_ASSERT(begin && end);
+
+ if (list->next == list) // empty
+ {
+ begin->prev = list;
+ end->next = list->next;
+ list->next = begin;
+ list->prev = end;
+ }
+ else if (less(list->prev, begin)) // insert at end
+ {
+ list->prev->next = begin;
+ begin->prev = list->prev;
+ end->next = list;
+ list->prev = end;
+ }
+ else
+ {
+ auto prev = list;
+ auto cur = list->next;
+ while (less(cur, begin))
+ {
+ prev = cur;
+ cur = cur->next;
+ }
+ WPI_MEMORY_ASSERT(greater(cur, end));
+ WPI_MEMORY_ASSERT(prev == list || less(prev, begin));
+ prev->next = begin;
+ begin->prev = prev;
+ end->next = cur;
+ cur->prev = end;
+ }
+ }
+} // namespace
+
+constexpr std::size_t small_free_memory_list::min_element_size;
+constexpr std::size_t small_free_memory_list::min_element_alignment;
+
+small_free_memory_list::small_free_memory_list(std::size_t node_size) noexcept
+: node_size_(node_size), capacity_(0u), alloc_chunk_(&base_), dealloc_chunk_(&base_)
+{
+}
+
+small_free_memory_list::small_free_memory_list(std::size_t node_size, void* mem,
+ std::size_t size) noexcept
+: small_free_memory_list(node_size)
+{
+ insert(mem, size);
+}
+
+small_free_memory_list::small_free_memory_list(small_free_memory_list&& other) noexcept
+: node_size_(other.node_size_),
+ capacity_(other.capacity_),
+ // reset markers for simplicity
+ alloc_chunk_(&base_),
+ dealloc_chunk_(&base_)
+{
+ if (!other.empty())
+ {
+ base_.next = other.base_.next;
+ base_.prev = other.base_.prev;
+ other.base_.next->prev = &base_;
+ other.base_.prev->next = &base_;
+
+ other.base_.next = &other.base_;
+ other.base_.prev = &other.base_;
+ other.capacity_ = 0u;
+ }
+ else
+ {
+ base_.next = &base_;
+ base_.prev = &base_;
+ }
+}
+
+void wpi::memory::detail::swap(small_free_memory_list& a, small_free_memory_list& b) noexcept
+{
+ auto b_next = b.base_.next;
+ auto b_prev = b.base_.prev;
+
+ if (!a.empty())
+ {
+ b.base_.next = a.base_.next;
+ b.base_.prev = a.base_.prev;
+ b.base_.next->prev = &b.base_;
+ b.base_.prev->next = &b.base_;
+ }
+ else
+ {
+ b.base_.next = &b.base_;
+ b.base_.prev = &b.base_;
+ }
+
+ if (!b.empty())
+ {
+ a.base_.next = b_next;
+ a.base_.prev = b_prev;
+ a.base_.next->prev = &a.base_;
+ a.base_.prev->next = &a.base_;
+ }
+ else
+ {
+ a.base_.next = &a.base_;
+ a.base_.prev = &a.base_;
+ }
+
+ detail::adl_swap(a.node_size_, b.node_size_);
+ detail::adl_swap(a.capacity_, b.capacity_);
+
+ // reset markers for simplicity
+ a.alloc_chunk_ = a.dealloc_chunk_ = &a.base_;
+ b.alloc_chunk_ = b.dealloc_chunk_ = &b.base_;
+}
+
+void small_free_memory_list::insert(void* mem, std::size_t size) noexcept
+{
+ WPI_MEMORY_ASSERT(mem);
+ WPI_MEMORY_ASSERT(is_aligned(mem, max_alignment));
+ debug_fill_internal(mem, size, false);
+
+ auto total_chunk_size = chunk_memory_offset + node_size_ * chunk_max_nodes;
+ auto align_buffer = align_offset(total_chunk_size, alignof(chunk));
+
+ auto no_chunks = size / (total_chunk_size + align_buffer);
+ auto remainder = size % (total_chunk_size + align_buffer);
+
+ auto memory = static_cast<char*>(mem);
+ auto construct_chunk = [&](std::size_t total_memory, std::size_t node_size)
+ {
+ WPI_MEMORY_ASSERT(align_offset(memory, alignof(chunk)) == 0);
+ return ::new (static_cast<void*>(memory)) chunk(total_memory, node_size);
+ };
+
+ auto prev = static_cast<chunk_base*>(nullptr);
+ for (auto i = std::size_t(0); i != no_chunks; ++i)
+ {
+ auto c = construct_chunk(total_chunk_size, node_size_);
+
+ c->prev = prev;
+ if (prev)
+ prev->next = c;
+ prev = c;
+
+ memory += total_chunk_size;
+ memory += align_buffer;
+ }
+
+ auto new_nodes = no_chunks * chunk_max_nodes;
+ if (remainder >= chunk_memory_offset + node_size_) // at least one node
+ {
+ auto c = construct_chunk(remainder, node_size_);
+
+ c->prev = prev;
+ if (prev)
+ prev->next = c;
+ prev = c;
+
+ new_nodes += c->no_nodes;
+ }
+
+ WPI_MEMORY_ASSERT_MSG(new_nodes > 0, "memory block too small");
+ insert_chunks(&base_, static_cast<chunk_base*>(mem), prev);
+ capacity_ += new_nodes;
+}
+
+std::size_t small_free_memory_list::usable_size(std::size_t size) const noexcept
+{
+ auto total_chunk_size = chunk_memory_offset + node_size_ * chunk_max_nodes;
+ auto no_chunks = size / total_chunk_size;
+ auto remainder = size % total_chunk_size;
+
+ return no_chunks * chunk_max_nodes * node_size_
+ + (remainder > chunk_memory_offset ? remainder - chunk_memory_offset : 0u);
+}
+
+void* small_free_memory_list::allocate() noexcept
+{
+ auto chunk = find_chunk_impl(1);
+ alloc_chunk_ = chunk;
+ WPI_MEMORY_ASSERT(chunk && chunk->capacity >= 1);
+
+ --capacity_;
+
+ auto mem = chunk->allocate(node_size_);
+ WPI_MEMORY_ASSERT(mem);
+ return detail::debug_fill_new(mem, node_size_, 0);
+}
+
+void small_free_memory_list::deallocate(void* mem) noexcept
+{
+ auto info =
+ allocator_info(WPI_MEMORY_LOG_PREFIX "::detail::small_free_memory_list", this);
+
+ auto node = static_cast<unsigned char*>(detail::debug_fill_free(mem, node_size_, 0));
+
+ auto chunk = find_chunk_impl(node);
+ dealloc_chunk_ = chunk;
+ // memory was never allocated from list
+ detail::debug_check_pointer([&] { return chunk != nullptr; }, info, mem);
+
+ auto offset = static_cast<std::size_t>(node - chunk->list_memory());
+ // memory is not at the right position
+ debug_check_pointer([&] { return offset % node_size_ == 0u; }, info, mem);
+ // double-free
+ debug_check_double_dealloc([&] { return !chunk->contains(node, node_size_); }, info, mem);
+
+ auto index = offset / node_size_;
+ WPI_MEMORY_ASSERT(index < chunk->no_nodes);
+ chunk->deallocate(node, static_cast<unsigned char>(index));
+
+ ++capacity_;
+}
+
+std::size_t small_free_memory_list::alignment() const noexcept
+{
+ return alignment_for(node_size_);
+}
+
+chunk* small_free_memory_list::find_chunk_impl(std::size_t n) noexcept
+{
+ if (auto c = make_chunk(alloc_chunk_, n))
+ return c;
+ else if ((c = make_chunk(dealloc_chunk_, n)) != nullptr)
+ return c;
+
+ auto cur_forward = alloc_chunk_->next;
+ auto cur_backward = alloc_chunk_->prev;
+
+ do
+ {
+ if (auto c = make_chunk(cur_forward, n))
+ return c;
+ else if ((c = make_chunk(cur_backward, n)) != nullptr)
+ return c;
+
+ cur_forward = cur_forward->next;
+ cur_backward = cur_backward->prev;
+ WPI_MEMORY_ASSERT(cur_forward != alloc_chunk_);
+ WPI_MEMORY_ASSERT(cur_backward != alloc_chunk_);
+ } while (true);
+ WPI_MEMORY_UNREACHABLE("there is memory available somewhere...");
+ return nullptr;
+}
+
+chunk* small_free_memory_list::find_chunk_impl(unsigned char* node, chunk_base* first,
+ chunk_base* last) noexcept
+{
+ do
+ {
+ if (auto c = from_chunk(first, node, node_size_))
+ return c;
+ else if ((c = from_chunk(last, node, node_size_)) != nullptr)
+ return c;
+
+ first = first->next;
+ last = last->prev;
+ } while (!greater(first, last));
+ return nullptr;
+}
+
+chunk* small_free_memory_list::find_chunk_impl(unsigned char* node) noexcept
+{
+ if (auto c = from_chunk(dealloc_chunk_, node, node_size_))
+ return c;
+ else if ((c = from_chunk(alloc_chunk_, node, node_size_)) != nullptr)
+ return c;
+ else if (less(dealloc_chunk_, node))
+ {
+ // node is in (dealloc_chunk_, base_.prev]
+ return find_chunk_impl(node, dealloc_chunk_->next, base_.prev);
+ }
+ else if (greater(dealloc_chunk_, node))
+ {
+ // node is in [base.next, dealloc_chunk_)
+ return find_chunk_impl(node, base_.next, dealloc_chunk_->prev);
+ }
+ WPI_MEMORY_UNREACHABLE("must be in one half");
+ return nullptr;
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/error.cpp b/wpiutil/src/main/native/thirdparty/memory/src/error.cpp
new file mode 100644
index 0000000..6261819
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/error.cpp
@@ -0,0 +1,106 @@
+// 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.
+
+#include "wpi/memory/error.hpp"
+
+#include <atomic>
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <cstdio>
+#endif
+
+using namespace wpi::memory;
+
+namespace
+{
+ void default_out_of_memory_handler(const allocator_info& info, std::size_t amount) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr,
+ "[%s] Allocator %s (at %p) ran out of memory trying to allocate %zu bytes.\n",
+ WPI_MEMORY_LOG_PREFIX, info.name, info.allocator, amount);
+#endif
+ }
+
+ std::atomic<out_of_memory::handler> out_of_memory_h(default_out_of_memory_handler);
+} // namespace
+
+out_of_memory::handler out_of_memory::set_handler(out_of_memory::handler h)
+{
+ return out_of_memory_h.exchange(h ? h : default_out_of_memory_handler);
+}
+
+out_of_memory::handler out_of_memory::get_handler()
+{
+ return out_of_memory_h;
+}
+
+out_of_memory::out_of_memory(const allocator_info& info, std::size_t amount)
+: info_(info), amount_(amount)
+{
+ out_of_memory_h.load()(info, amount);
+}
+
+const char* out_of_memory::what() const noexcept
+{
+ return "low-level allocator is out of memory";
+}
+
+const char* out_of_fixed_memory::what() const noexcept
+{
+ return "fixed size allocator is out of memory";
+}
+
+namespace
+{
+ void default_bad_alloc_size_handler(const allocator_info& info, std::size_t passed,
+ std::size_t supported) noexcept
+ {
+#if WPI_HOSTED_IMPLEMENTATION
+ std::fprintf(stderr,
+ "[%s] Allocator %s (at %p) received invalid size/alignment %zu, "
+ "max supported is %zu\n",
+ WPI_MEMORY_LOG_PREFIX, info.name, info.allocator, passed, supported);
+#endif
+ }
+
+ std::atomic<bad_allocation_size::handler> bad_alloc_size_h(default_bad_alloc_size_handler);
+} // namespace
+
+bad_allocation_size::handler bad_allocation_size::set_handler(bad_allocation_size::handler h)
+{
+ return bad_alloc_size_h.exchange(h ? h : default_bad_alloc_size_handler);
+}
+
+bad_allocation_size::handler bad_allocation_size::get_handler()
+{
+ return bad_alloc_size_h;
+}
+
+bad_allocation_size::bad_allocation_size(const allocator_info& info, std::size_t passed,
+ std::size_t supported)
+: info_(info), passed_(passed), supported_(supported)
+{
+ bad_alloc_size_h.load()(info_, passed_, supported_);
+}
+
+const char* bad_allocation_size::what() const noexcept
+{
+ return "allocation node size exceeds supported maximum of allocator";
+}
+
+const char* bad_node_size::what() const noexcept
+{
+ return "allocation node size exceeds supported maximum of allocator";
+}
+
+const char* bad_array_size::what() const noexcept
+{
+ return "allocation array size exceeds supported maximum of allocator";
+}
+
+const char* bad_alignment::what() const noexcept
+{
+ return "allocation alignment exceeds supported maximum of allocator";
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp
new file mode 100644
index 0000000..0f559bd
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/heap_allocator.cpp
@@ -0,0 +1,85 @@
+// 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.
+
+#include "wpi/memory/heap_allocator.hpp"
+
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+
+#ifdef _WIN32
+#include <malloc.h>
+#include <windows.h>
+
+namespace
+{
+ HANDLE get_process_heap() noexcept
+ {
+ static auto heap = GetProcessHeap();
+ return heap;
+ }
+
+ std::size_t max_size() noexcept
+ {
+ return _HEAP_MAXREQ;
+ }
+} // namespace
+
+void* wpi::memory::heap_alloc(std::size_t size) noexcept
+{
+ return HeapAlloc(get_process_heap(), 0, size);
+}
+
+void wpi::memory::heap_dealloc(void* ptr, std::size_t) noexcept
+{
+ HeapFree(get_process_heap(), 0, ptr);
+}
+
+#elif WPI_HOSTED_IMPLEMENTATION
+#include <cstdlib>
+#include <memory>
+
+void* wpi::memory::heap_alloc(std::size_t size) noexcept
+{
+ return std::malloc(size);
+}
+
+void wpi::memory::heap_dealloc(void* ptr, std::size_t) noexcept
+{
+ std::free(ptr);
+}
+
+namespace
+{
+ std::size_t max_size() noexcept
+ {
+ return std::allocator_traits<std::allocator<char>>::max_size({});
+ }
+} // namespace
+#else
+// no implementation for heap_alloc/heap_dealloc
+
+namespace
+{
+ std::size_t max_size() noexcept
+ {
+ return std::size_t(-1);
+ }
+} // namespace
+#endif
+
+allocator_info detail::heap_allocator_impl::info() noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::heap_allocator", nullptr};
+}
+
+std::size_t detail::heap_allocator_impl::max_node_size() noexcept
+{
+ return max_size();
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class detail::lowlevel_allocator<detail::heap_allocator_impl>;
+template class wpi::memory::allocator_traits<heap_allocator>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp
new file mode 100644
index 0000000..c174c13
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/iteration_allocator.cpp
@@ -0,0 +1,13 @@
+// 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.
+
+#include "wpi/memory/iteration_allocator.hpp"
+
+using namespace wpi::memory;
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::iteration_allocator<2>;
+template class wpi::memory::allocator_traits<iteration_allocator<2>>;
+template class wpi::memory::composable_allocator_traits<iteration_allocator<2>>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp
new file mode 100644
index 0000000..f54817a
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/malloc_allocator.cpp
@@ -0,0 +1,24 @@
+// 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.
+
+#include "wpi/memory/config.hpp"
+#if WPI_HOSTED_IMPLEMENTATION
+
+#include "wpi/memory/malloc_allocator.hpp"
+
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+
+allocator_info detail::malloc_allocator_impl::info() noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::malloc_allocator", nullptr};
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class detail::lowlevel_allocator<detail::malloc_allocator_impl>;
+template class wpi::memory::allocator_traits<malloc_allocator>;
+#endif
+
+#endif // 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
new file mode 100644
index 0000000..d8454be
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_arena.cpp
@@ -0,0 +1,73 @@
+// 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.
+
+#include "wpi/memory/memory_arena.hpp"
+
+#include <new>
+
+#include "wpi/memory/detail/align.hpp"
+
+using namespace wpi::memory;
+using namespace detail;
+
+void memory_block_stack::push(allocated_mb block) noexcept
+{
+ WPI_MEMORY_ASSERT(block.size >= sizeof(node));
+ WPI_MEMORY_ASSERT(is_aligned(block.memory, max_alignment));
+ auto next = ::new (block.memory) node(head_, block.size - implementation_offset());
+ head_ = next;
+}
+
+memory_block_stack::allocated_mb memory_block_stack::pop() noexcept
+{
+ WPI_MEMORY_ASSERT(head_);
+ auto to_pop = head_;
+ head_ = head_->prev;
+ return {to_pop, to_pop->usable_size + implementation_offset()};
+}
+
+void memory_block_stack::steal_top(memory_block_stack& other) noexcept
+{
+ WPI_MEMORY_ASSERT(other.head_);
+ auto to_steal = other.head_;
+ other.head_ = other.head_->prev;
+
+ to_steal->prev = head_;
+ head_ = to_steal;
+}
+
+bool memory_block_stack::owns(const void* ptr) const noexcept
+{
+ auto address = static_cast<const char*>(ptr);
+ for (auto cur = head_; cur; cur = cur->prev)
+ {
+ auto mem = static_cast<char*>(static_cast<void*>(cur));
+ if (address >= mem && address < mem + cur->usable_size)
+ return true;
+ }
+ return false;
+}
+
+std::size_t memory_block_stack::size() const noexcept
+{
+ std::size_t res = 0u;
+ for (auto cur = head_; cur; cur = cur->prev)
+ ++res;
+ return res;
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::memory_arena<static_block_allocator, true>;
+template class wpi::memory::memory_arena<static_block_allocator, false>;
+template class wpi::memory::memory_arena<virtual_block_allocator, true>;
+template class wpi::memory::memory_arena<virtual_block_allocator, false>;
+
+template class wpi::memory::growing_block_allocator<>;
+template class wpi::memory::memory_arena<growing_block_allocator<>, true>;
+template class wpi::memory::memory_arena<growing_block_allocator<>, false>;
+
+template class wpi::memory::fixed_block_allocator<>;
+template class wpi::memory::memory_arena<fixed_block_allocator<>, true>;
+template class wpi::memory::memory_arena<fixed_block_allocator<>, false>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp
new file mode 100644
index 0000000..5a5e5ab
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool.cpp
@@ -0,0 +1,28 @@
+// 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.
+
+#include "wpi/memory/memory_pool.hpp"
+
+#include "wpi/memory/debugging.hpp"
+
+using namespace wpi::memory;
+
+void detail::memory_pool_leak_handler::operator()(std::ptrdiff_t amount)
+{
+ get_leak_handler()({WPI_MEMORY_LOG_PREFIX "::memory_pool", this}, amount);
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::memory_pool<node_pool>;
+template class wpi::memory::memory_pool<array_pool>;
+template class wpi::memory::memory_pool<small_node_pool>;
+
+template class wpi::memory::allocator_traits<memory_pool<node_pool>>;
+template class wpi::memory::allocator_traits<memory_pool<array_pool>>;
+template class wpi::memory::allocator_traits<memory_pool<small_node_pool>>;
+
+template class wpi::memory::composable_allocator_traits<memory_pool<node_pool>>;
+template class wpi::memory::composable_allocator_traits<memory_pool<array_pool>>;
+template class wpi::memory::composable_allocator_traits<memory_pool<small_node_pool>>;
+#endif
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
new file mode 100644
index 0000000..6366811
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_pool_collection.cpp
@@ -0,0 +1,51 @@
+// 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.
+
+#include "wpi/memory/memory_pool_collection.hpp"
+
+#include "wpi/memory/debugging.hpp"
+
+using namespace wpi::memory;
+
+void detail::memory_pool_collection_leak_handler::operator()(std::ptrdiff_t amount)
+{
+ get_leak_handler()({WPI_MEMORY_LOG_PREFIX "::memory_pool_collection", this}, amount);
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::memory_pool_collection<node_pool, identity_buckets>;
+template class wpi::memory::memory_pool_collection<array_pool, identity_buckets>;
+template class wpi::memory::memory_pool_collection<small_node_pool, identity_buckets>;
+
+template class wpi::memory::memory_pool_collection<node_pool, log2_buckets>;
+template class wpi::memory::memory_pool_collection<array_pool, log2_buckets>;
+template class wpi::memory::memory_pool_collection<small_node_pool, log2_buckets>;
+
+template class wpi::memory::allocator_traits<
+ memory_pool_collection<node_pool, identity_buckets>>;
+template class wpi::memory::allocator_traits<
+ memory_pool_collection<array_pool, identity_buckets>>;
+template class wpi::memory::allocator_traits<
+ memory_pool_collection<small_node_pool, identity_buckets>>;
+
+template class wpi::memory::allocator_traits<memory_pool_collection<node_pool, log2_buckets>>;
+template class wpi::memory::allocator_traits<
+ memory_pool_collection<array_pool, log2_buckets>>;
+template class wpi::memory::allocator_traits<
+ memory_pool_collection<small_node_pool, log2_buckets>>;
+
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<node_pool, identity_buckets>>;
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<array_pool, identity_buckets>>;
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<small_node_pool, identity_buckets>>;
+
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<node_pool, log2_buckets>>;
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<array_pool, log2_buckets>>;
+template class wpi::memory::composable_allocator_traits<
+ memory_pool_collection<small_node_pool, log2_buckets>>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp b/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp
new file mode 100644
index 0000000..8db5728
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/memory_stack.cpp
@@ -0,0 +1,21 @@
+// 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.
+
+#include "wpi/memory/memory_stack.hpp"
+
+#include "wpi/memory/debugging.hpp"
+
+using namespace wpi::memory;
+
+void detail::memory_stack_leak_handler::operator()(std::ptrdiff_t amount)
+{
+ get_leak_handler()({WPI_MEMORY_LOG_PREFIX "::memory_stack", this}, amount);
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::memory_stack<>;
+template class wpi::memory::memory_stack_raii_unwind<memory_stack<>>;
+template class wpi::memory::allocator_traits<memory_stack<>>;
+template class wpi::memory::composable_allocator_traits<memory_stack<>>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp
new file mode 100644
index 0000000..2791182
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/new_allocator.cpp
@@ -0,0 +1,72 @@
+// 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.
+
+#include "wpi/memory/new_allocator.hpp"
+
+#if WPI_HOSTED_IMPLEMENTATION
+#include <memory>
+#endif
+
+#include <new>
+
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+
+allocator_info detail::new_allocator_impl::info() noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::new_allocator", nullptr};
+}
+
+void* detail::new_allocator_impl::allocate(std::size_t size, size_t) noexcept
+{
+ void* memory = nullptr;
+ while (true)
+ {
+ memory = ::operator new(size, std::nothrow);
+ if (memory)
+ break;
+
+ auto handler = std::get_new_handler();
+ if (handler)
+ {
+#if WPI_HAS_EXCEPTION_SUPPORT
+ try
+ {
+ handler();
+ }
+ catch (...)
+ {
+ return nullptr;
+ }
+#else
+ handler();
+#endif
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+ return memory;
+}
+
+void detail::new_allocator_impl::deallocate(void* ptr, std::size_t, size_t) noexcept
+{
+ ::operator delete(ptr);
+}
+
+std::size_t detail::new_allocator_impl::max_node_size() noexcept
+{
+#if WPI_HOSTED_IMPLEMENTATION
+ return std::allocator_traits<std::allocator<char>>::max_size({});
+#else
+ return std::size_t(-1);
+#endif
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class detail::lowlevel_allocator<detail::new_allocator_impl>;
+template class wpi::memory::allocator_traits<new_allocator>;
+#endif
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp
new file mode 100644
index 0000000..15a88bf
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/static_allocator.cpp
@@ -0,0 +1,50 @@
+// 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.
+
+#include "wpi/memory/static_allocator.hpp"
+
+#include "wpi/memory/detail/debug_helpers.hpp"
+#include "wpi/memory/error.hpp"
+#include "wpi/memory/memory_arena.hpp"
+
+using namespace wpi::memory;
+
+void* static_allocator::allocate_node(std::size_t size, std::size_t alignment)
+{
+ auto mem = stack_.allocate(end_, size, alignment);
+ if (!mem)
+ WPI_THROW(out_of_fixed_memory(info(), size));
+ return mem;
+}
+
+allocator_info static_allocator::info() const noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::static_allocator", this};
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::allocator_traits<static_allocator>;
+#endif
+
+memory_block static_block_allocator::allocate_block()
+{
+ if (cur_ + block_size_ > end_)
+ WPI_THROW(out_of_fixed_memory(info(), block_size_));
+ auto mem = cur_;
+ cur_ += block_size_;
+ return {mem, block_size_};
+}
+
+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);
+ cur_ -= block_size_;
+}
+
+allocator_info static_block_allocator::info() const noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::static_block_allocator", this};
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp b/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp
new file mode 100644
index 0000000..fa85e99
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/temporary_allocator.cpp
@@ -0,0 +1,322 @@
+// 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.
+
+#include "wpi/memory/temporary_allocator.hpp"
+
+#include <new>
+#include <type_traits>
+
+#include "wpi/memory/detail/assert.hpp"
+#include "wpi/memory/default_allocator.hpp"
+#include "wpi/memory/error.hpp"
+
+using namespace wpi::memory;
+
+namespace
+{
+ void default_growth_tracker(std::size_t) noexcept {}
+
+ using temporary_impl_allocator = default_allocator;
+ using temporary_impl_allocator_traits = allocator_traits<temporary_impl_allocator>;
+} // namespace
+
+detail::temporary_block_allocator::temporary_block_allocator(std::size_t block_size) noexcept
+: tracker_(default_growth_tracker), block_size_(block_size)
+{
+}
+
+detail::temporary_block_allocator::growth_tracker detail::temporary_block_allocator::
+ set_growth_tracker(growth_tracker t) noexcept
+{
+ auto old = tracker_;
+ tracker_ = t;
+ return old;
+}
+
+detail::temporary_block_allocator::growth_tracker detail::temporary_block_allocator::
+ get_growth_tracker() noexcept
+{
+ return tracker_;
+}
+
+memory_block detail::temporary_block_allocator::allocate_block()
+{
+ auto alloc = temporary_impl_allocator();
+ auto memory = temporary_impl_allocator_traits::allocate_array(alloc, block_size_, 1,
+ detail::max_alignment);
+ auto block = memory_block(memory, block_size_);
+ block_size_ = growing_block_allocator<temporary_impl_allocator>::grow_block_size(block_size_);
+ return block;
+}
+
+void detail::temporary_block_allocator::deallocate_block(memory_block block)
+{
+ auto alloc = temporary_impl_allocator();
+ temporary_impl_allocator_traits::deallocate_array(alloc, block.memory, block.size, 1,
+ detail::max_alignment);
+}
+
+#if WPI_MEMORY_TEMPORARY_STACK_MODE >= 2
+// lifetime managment through the nifty counter and the list
+// note: I could have used a simple `thread_local` variable for the temporary stack
+// but this could lead to issues with destruction order
+// and more importantly I have to support platforms that can't handle non-trivial thread local's
+// hence I need to dynamically allocate the stack's and store them in a container
+// on program exit the container is iterated and all stack's are properly destroyed
+// if a thread exit can be detected, the dynamic memory of the stack is already released,
+// but not the stack itself destroyed
+
+#if !defined(__MINGW64__)
+
+// only use the thread exit detector if we have thread local and are not running on MinGW due to a bug
+// see: https://sourceforge.net/p/mingw-w64/bugs/527/
+#define WPI_MEMORY_THREAD_EXIT_DETECTOR 1
+
+#else
+#define WPI_MEMORY_THREAD_EXIT_DETECTOR 0
+
+#if defined(_MSC_VER)
+#pragma message( \
+ "thread_local doesn't support destructors, need to use the temporary_stack_initializer to ensure proper cleanup of the temporary memory")
+#else
+#warning \
+ "thread_local doesn't support destructors, need to use the temporary_stack_initializer to ensure proper cleanup of the temporary memory"
+#endif
+
+#endif
+
+static class detail::temporary_stack_list
+{
+public:
+ std::atomic<temporary_stack_list_node*> first;
+
+ temporary_stack* create_new(std::size_t size)
+ {
+ auto storage =
+ default_allocator().allocate_node(sizeof(temporary_stack), alignof(temporary_stack));
+ return ::new (storage) temporary_stack(0, size);
+ }
+
+ temporary_stack* find_unused()
+ {
+ for (auto ptr = first.load(); ptr; ptr = ptr->next_)
+ {
+ auto value = false;
+ if (ptr->in_use_.compare_exchange_strong(value, true))
+ return static_cast<temporary_stack*>(ptr);
+ }
+
+ return nullptr;
+ }
+
+ temporary_stack* create(std::size_t size)
+ {
+ if (auto ptr = find_unused())
+ {
+ WPI_MEMORY_ASSERT(ptr->in_use_);
+ ptr->stack_ = detail::temporary_stack_impl(size);
+ return ptr;
+ }
+ return create_new(size);
+ }
+
+ void clear(temporary_stack& stack)
+ {
+ // stack should be empty now, so shrink_to_fit() clears all memory
+ stack.stack_.shrink_to_fit();
+ stack.in_use_ = false; // mark as free
+ }
+
+ void destroy()
+ {
+ for (auto ptr = first.exchange(nullptr); ptr;)
+ {
+ auto stack = static_cast<temporary_stack*>(ptr);
+ auto next = ptr->next_;
+
+ stack->~temporary_stack();
+ default_allocator().deallocate_node(stack, sizeof(temporary_stack),
+ alignof(temporary_stack));
+
+ ptr = next;
+ }
+
+ WPI_MEMORY_ASSERT_MSG(!first.load(),
+ "destroy() called while other threads are still running");
+ }
+} temporary_stack_list_obj;
+
+namespace
+{
+ thread_local std::size_t nifty_counter;
+ thread_local temporary_stack* temp_stack = nullptr;
+
+#if WPI_MEMORY_THREAD_EXIT_DETECTOR
+ // don't use this on a bug
+ thread_local struct thread_exit_detector_t
+ {
+ ~thread_exit_detector_t() noexcept
+ {
+ if (temp_stack)
+ // clear automatically on thread exit, as the initializer's destructor does
+ // note: if another's thread_local variable destructor is called after this one
+ // and that destructor uses the temporary allocator
+ // the stack needs to grow again
+ // but who does temporary allocation in a destructor?!
+ temporary_stack_list_obj.clear(*temp_stack);
+ }
+ } thread_exit_detector;
+#endif
+} // namespace
+
+detail::temporary_stack_list_node::temporary_stack_list_node(int) noexcept : in_use_(true)
+{
+ next_ = temporary_stack_list_obj.first.load();
+ while (!temporary_stack_list_obj.first.compare_exchange_weak(next_, this))
+ ;
+#if WPI_MEMORY_THREAD_EXIT_DETECTOR
+ (void)&thread_exit_detector; // ODR-use it, so it will be created
+#endif
+}
+
+detail::temporary_allocator_dtor_t::temporary_allocator_dtor_t() noexcept
+{
+ ++nifty_counter;
+}
+
+detail::temporary_allocator_dtor_t::~temporary_allocator_dtor_t() noexcept
+{
+ if (--nifty_counter == 0u && temp_stack)
+ temporary_stack_list_obj.destroy();
+}
+
+temporary_stack_initializer::temporary_stack_initializer(std::size_t initial_size)
+{
+ if (!temp_stack)
+ temp_stack = temporary_stack_list_obj.create(initial_size);
+}
+
+temporary_stack_initializer::~temporary_stack_initializer() noexcept
+{
+ // don't destroy, nifty counter does that
+ // but can get rid of all the memory
+ if (temp_stack)
+ temporary_stack_list_obj.clear(*temp_stack);
+}
+
+temporary_stack& wpi::memory::get_temporary_stack(std::size_t initial_size)
+{
+ if (!temp_stack)
+ temp_stack = temporary_stack_list_obj.create(initial_size);
+ return *temp_stack;
+}
+
+#elif WPI_MEMORY_TEMPORARY_STACK_MODE == 1
+
+namespace
+{
+ WPI_THREAD_LOCAL alignas(
+ temporary_stack) char temporary_stack_storage[sizeof(temporary_stack)];
+ WPI_THREAD_LOCAL bool is_created = false;
+
+ temporary_stack& get() noexcept
+ {
+ WPI_MEMORY_ASSERT(is_created);
+ return *static_cast<temporary_stack*>(static_cast<void*>(&temporary_stack_storage));
+ }
+
+ void create(std::size_t initial_size)
+ {
+ if (!is_created)
+ {
+ ::new (static_cast<void*>(&temporary_stack_storage)) temporary_stack(initial_size);
+ is_created = true;
+ }
+ }
+} // namespace
+
+// explicit lifetime managment
+temporary_stack_initializer::temporary_stack_initializer(std::size_t initial_size)
+{
+ create(initial_size);
+}
+
+temporary_stack_initializer::~temporary_stack_initializer()
+{
+ if (is_created)
+ get().~temporary_stack();
+}
+
+temporary_stack& wpi::memory::get_temporary_stack(std::size_t initial_size)
+{
+ create(initial_size);
+ return get();
+}
+
+#else
+
+// no lifetime managment
+
+temporary_stack_initializer::temporary_stack_initializer(std::size_t initial_size)
+{
+ if (initial_size != 0u)
+ WPI_MEMORY_WARNING("temporary_stack_initializer() has no effect if "
+ "WPI_MEMORY_TEMPORARY_STACK == 0 (pass an initial size of 0 "
+ "to disable this message)");
+}
+
+temporary_stack_initializer::~temporary_stack_initializer() {}
+
+temporary_stack& wpi::memory::get_temporary_stack(std::size_t)
+{
+ WPI_MEMORY_UNREACHABLE("get_temporary_stack() called but stack is disabled by "
+ "WPI_MEMORY_TEMPORARY_STACK == 0");
+ std::abort();
+}
+
+#endif
+
+const temporary_stack_initializer::defer_create_t temporary_stack_initializer::defer_create;
+
+temporary_allocator::temporary_allocator() : temporary_allocator(get_temporary_stack()) {}
+
+temporary_allocator::temporary_allocator(temporary_stack& stack)
+: unwind_(stack), prev_(stack.top_), shrink_to_fit_(false)
+{
+ WPI_MEMORY_ASSERT(!prev_ || prev_->is_active());
+ stack.top_ = this;
+}
+
+temporary_allocator::~temporary_allocator() noexcept
+{
+ if (is_active())
+ {
+ auto& stack = unwind_.get_stack();
+ stack.top_ = prev_;
+ unwind_.unwind(); // manually call it now...
+ if (shrink_to_fit_)
+ // to call shrink_to_fit() afterwards
+ stack.stack_.shrink_to_fit();
+ }
+}
+
+void* temporary_allocator::allocate(std::size_t size, std::size_t alignment)
+{
+ WPI_MEMORY_ASSERT_MSG(is_active(), "object isn't the active allocator");
+ return unwind_.get_stack().stack_.allocate(size, alignment);
+}
+
+void temporary_allocator::shrink_to_fit() noexcept
+{
+ shrink_to_fit_ = true;
+}
+
+bool temporary_allocator::is_active() const noexcept
+{
+ WPI_MEMORY_ASSERT(unwind_.will_unwind());
+ auto res = unwind_.get_stack().top_ == this;
+ // check that prev is actually before this
+ WPI_MEMORY_ASSERT(!res || !prev_ || prev_->unwind_.get_marker() <= unwind_.get_marker());
+ return res;
+}
diff --git a/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp b/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp
new file mode 100644
index 0000000..fd7960f
--- /dev/null
+++ b/wpiutil/src/main/native/thirdparty/memory/src/virtual_memory.cpp
@@ -0,0 +1,240 @@
+// 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.
+
+#include "wpi/memory/virtual_memory.hpp"
+
+#include "wpi/memory/detail/debug_helpers.hpp"
+#include "wpi/memory/error.hpp"
+#include "wpi/memory/memory_arena.hpp"
+
+using namespace wpi::memory;
+
+void detail::virtual_memory_allocator_leak_handler::operator()(std::ptrdiff_t amount)
+{
+ detail::debug_handle_memory_leak({WPI_MEMORY_LOG_PREFIX "::virtual_memory_allocator",
+ nullptr},
+ amount);
+}
+
+#if defined(_WIN32)
+#include <windows.h>
+
+namespace
+{
+ std::size_t get_page_size() noexcept
+ {
+ static_assert(sizeof(std::size_t) >= sizeof(DWORD), "possible loss of data");
+
+ SYSTEM_INFO info;
+ GetSystemInfo(&info);
+ return std::size_t(info.dwPageSize);
+ }
+} // namespace
+
+const std::size_t wpi::memory::virtual_memory_page_size = get_page_size();
+
+void* wpi::memory::virtual_memory_reserve(std::size_t no_pages) noexcept
+{
+ auto pages =
+#if (_MSC_VER <= 1900) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ VirtualAlloc(nullptr, no_pages * virtual_memory_page_size, MEM_RESERVE, PAGE_READWRITE);
+#else
+ VirtualAllocFromApp(nullptr, no_pages * virtual_memory_page_size, MEM_RESERVE,
+ PAGE_READWRITE);
+#endif
+ return pages;
+}
+
+void wpi::memory::virtual_memory_release(void* pages, std::size_t) noexcept
+{
+ auto result = VirtualFree(pages, 0u, MEM_RELEASE);
+ WPI_MEMORY_ASSERT_MSG(result, "cannot release pages");
+}
+
+void* wpi::memory::virtual_memory_commit(void* memory, std::size_t no_pages) noexcept
+{
+ auto region =
+#if (_MSC_VER <= 1900) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+ VirtualAlloc(memory, no_pages * virtual_memory_page_size, MEM_COMMIT, PAGE_READWRITE);
+#else
+ VirtualAllocFromApp(memory, no_pages * virtual_memory_page_size, MEM_COMMIT,
+ PAGE_READWRITE);
+#endif
+ if (!region)
+ return nullptr;
+ WPI_MEMORY_ASSERT(region == memory);
+ return region;
+}
+
+void wpi::memory::virtual_memory_decommit(void* memory, std::size_t no_pages) noexcept
+{
+ auto result = VirtualFree(memory, no_pages * virtual_memory_page_size, MEM_DECOMMIT);
+ WPI_MEMORY_ASSERT_MSG(result, "cannot decommit memory");
+}
+#elif defined(__unix__) || defined(__APPLE__) || defined(__VXWORKS__) \
+ || defined(__QNXNTO__) // POSIX systems
+#include <sys/mman.h>
+#include <unistd.h>
+
+#if defined(PAGESIZE)
+const std::size_t wpi::memory::virtual_memory_page_size = PAGESIZE;
+#elif defined(PAGE_SIZE)
+const std::size_t wpi::memory::virtual_memory_page_size = PAGE_SIZE;
+#else
+const std::size_t wpi::memory::virtual_memory_page_size =
+ static_cast<std::size_t>(sysconf(_SC_PAGESIZE));
+#endif
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+void* wpi::memory::virtual_memory_reserve(std::size_t no_pages) noexcept
+{
+ auto pages = mmap(nullptr, no_pages * virtual_memory_page_size, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ return pages == MAP_FAILED ? nullptr : pages;
+}
+
+void wpi::memory::virtual_memory_release(void* pages, std::size_t no_pages) noexcept
+{
+ auto result = munmap(pages, no_pages * virtual_memory_page_size);
+ WPI_MEMORY_ASSERT_MSG(result == 0, "cannot release pages");
+ (void)result;
+}
+
+void* wpi::memory::virtual_memory_commit(void* memory, std::size_t no_pages) noexcept
+{
+ auto size = no_pages * virtual_memory_page_size;
+ auto result = mprotect(memory, size, PROT_WRITE | PROT_READ);
+ if (result != 0)
+ return nullptr;
+
+// advise that the memory will be needed
+#if defined(MADV_WILLNEED)
+ madvise(memory, size, MADV_WILLNEED);
+#elif defined(POSIX_MADV_WILLNEED)
+ posix_madvise(memory, size, POSIX_MADV_WILLNEED);
+#endif
+
+ return memory;
+}
+
+void wpi::memory::virtual_memory_decommit(void* memory, std::size_t no_pages) noexcept
+{
+ auto size = no_pages * virtual_memory_page_size;
+// advise that the memory won't be needed anymore
+#if defined(MADV_FREE)
+ madvise(memory, size, MADV_FREE);
+#elif defined(MADV_DONTNEED)
+ madvise(memory, size, MADV_DONTNEED);
+#elif defined(POSIX_MADV_DONTNEED)
+ posix_madvise(memory, size, POSIX_MADV_DONTNEED);
+#endif
+
+ auto result = mprotect(memory, size, PROT_NONE);
+ WPI_MEMORY_ASSERT_MSG(result == 0, "cannot decommit memory");
+ (void)result;
+}
+#else
+#warning "virtual memory functions not available on your platform, define your own"
+#endif
+
+std::size_t wpi::memory::get_virtual_memory_page_size() noexcept
+{
+ return virtual_memory_page_size;
+}
+
+namespace
+{
+ std::size_t calc_no_pages(std::size_t size) noexcept
+ {
+ auto div = size / virtual_memory_page_size;
+ auto rest = size % virtual_memory_page_size;
+
+ return div + (rest != 0u) + (detail::debug_fence_size ? 2u : 1u);
+ }
+} // namespace
+
+void* virtual_memory_allocator::allocate_node(std::size_t size, std::size_t)
+{
+ auto no_pages = calc_no_pages(size);
+ auto pages = virtual_memory_reserve(no_pages);
+ if (!pages || !virtual_memory_commit(pages, no_pages))
+ WPI_THROW(
+ out_of_memory({WPI_MEMORY_LOG_PREFIX "::virtual_memory_allocator", nullptr},
+ no_pages * virtual_memory_page_size));
+ on_allocate(size);
+
+ return detail::debug_fill_new(pages, size, virtual_memory_page_size);
+}
+
+void virtual_memory_allocator::deallocate_node(void* node, std::size_t size, std::size_t) noexcept
+{
+ auto pages = detail::debug_fill_free(node, size, virtual_memory_page_size);
+
+ on_deallocate(size);
+
+ auto no_pages = calc_no_pages(size);
+ virtual_memory_decommit(pages, no_pages);
+ virtual_memory_release(pages, no_pages);
+}
+
+std::size_t virtual_memory_allocator::max_node_size() const noexcept
+{
+ return std::size_t(-1);
+}
+
+std::size_t virtual_memory_allocator::max_alignment() const noexcept
+{
+ return virtual_memory_page_size;
+}
+
+#if WPI_MEMORY_EXTERN_TEMPLATE
+template class wpi::memory::allocator_traits<virtual_memory_allocator>;
+#endif
+
+virtual_block_allocator::virtual_block_allocator(std::size_t block_size, std::size_t no_blocks)
+: block_size_(block_size)
+{
+ WPI_MEMORY_ASSERT(block_size % virtual_memory_page_size == 0u);
+ WPI_MEMORY_ASSERT(no_blocks > 0);
+ auto total_size = block_size_ * no_blocks;
+ auto no_pages = total_size / virtual_memory_page_size;
+
+ cur_ = static_cast<char*>(virtual_memory_reserve(no_pages));
+ if (!cur_)
+ WPI_THROW(out_of_memory(info(), total_size));
+ end_ = cur_ + total_size;
+}
+
+virtual_block_allocator::~virtual_block_allocator() noexcept
+{
+ virtual_memory_release(cur_, static_cast<std::size_t>(end_ - cur_) / virtual_memory_page_size);
+}
+
+memory_block virtual_block_allocator::allocate_block()
+{
+ if (std::size_t(end_ - cur_) < block_size_)
+ WPI_THROW(out_of_fixed_memory(info(), block_size_));
+ auto mem = virtual_memory_commit(cur_, block_size_ / virtual_memory_page_size);
+ if (!mem)
+ WPI_THROW(out_of_fixed_memory(info(), block_size_));
+ cur_ += block_size_;
+ return {mem, block_size_};
+}
+
+void virtual_block_allocator::deallocate_block(memory_block block) noexcept
+{
+ detail::debug_check_pointer([&]
+ { return static_cast<char*>(block.memory) == cur_ - block_size_; },
+ info(), block.memory);
+ cur_ -= block_size_;
+ virtual_memory_decommit(cur_, block_size_);
+}
+
+allocator_info virtual_block_allocator::info() noexcept
+{
+ return {WPI_MEMORY_LOG_PREFIX "::virtual_block_allocator", this};
+}
diff --git a/wpiutil/src/main/native/include/wpi/mpack.h b/wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
similarity index 100%
rename from wpiutil/src/main/native/include/wpi/mpack.h
rename to wpiutil/src/main/native/thirdparty/mpack/include/wpi/mpack.h
diff --git a/wpiutil/src/main/native/cpp/mpack.cpp b/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
similarity index 99%
rename from wpiutil/src/main/native/cpp/mpack.cpp
rename to wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
index fbcb6a4..af5fbd0 100644
--- a/wpiutil/src/main/native/cpp/mpack.cpp
+++ b/wpiutil/src/main/native/thirdparty/mpack/src/mpack.cpp
@@ -237,6 +237,7 @@
}
#endif
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
/* mpack/mpack-common.c.c */
@@ -246,6 +247,7 @@
/* #include "mpack-common.h" */
MPACK_SILENCE_WARNINGS_BEGIN
+namespace mpack {
const char* mpack_error_to_string(mpack_error_t error) {
#if MPACK_STRINGS
@@ -970,6 +972,7 @@
}
#endif
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
/* mpack/mpack-writer.c.c */
@@ -979,6 +982,7 @@
/* #include "mpack-writer.h" */
MPACK_SILENCE_WARNINGS_BEGIN
+namespace mpack {
#if MPACK_WRITER
@@ -2727,6 +2731,7 @@
#endif // MPACK_BUILDER
#endif // MPACK_WRITER
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
/* mpack/mpack-reader.c.c */
@@ -2736,6 +2741,7 @@
/* #include "mpack-reader.h" */
MPACK_SILENCE_WARNINGS_BEGIN
+namespace mpack {
#if MPACK_READER
@@ -3996,6 +4002,7 @@
#endif
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
/* mpack/mpack-expect.c.c */
@@ -4005,6 +4012,7 @@
/* #include "mpack-expect.h" */
MPACK_SILENCE_WARNINGS_BEGIN
+namespace mpack {
#if MPACK_EXPECT
@@ -4861,6 +4869,7 @@
#endif
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
/* mpack/mpack-node.c.c */
@@ -4870,6 +4879,7 @@
/* #include "mpack-node.h" */
MPACK_SILENCE_WARNINGS_BEGIN
+namespace mpack {
#if MPACK_NODE
@@ -7247,5 +7257,5 @@
#endif
-} // namespace wpi
+} // namespace mpack
MPACK_SILENCE_WARNINGS_END
diff --git a/wpiutil/src/main/native/include/wpi/Signal.h b/wpiutil/src/main/native/thirdparty/sigslot/include/wpi/Signal.h
similarity index 100%
rename from wpiutil/src/main/native/include/wpi/Signal.h
rename to wpiutil/src/main/native/thirdparty/sigslot/include/wpi/Signal.h
diff --git a/wpiutil/src/main/native/windows/Demangle.cpp b/wpiutil/src/main/native/windows/Demangle.cpp
index 1b0a8a7..18be371 100644
--- a/wpiutil/src/main/native/windows/Demangle.cpp
+++ b/wpiutil/src/main/native/windows/Demangle.cpp
@@ -22,8 +22,9 @@
char buffer[256];
DWORD sz = UnDecorateSymbolName(buf.c_str(), buffer, sizeof(buffer),
UNDNAME_COMPLETE);
- if (sz == 0)
+ if (sz == 0) {
return std::string{mangledSymbol};
+ }
return std::string(buffer, sz);
}
diff --git a/wpiutil/src/main/native/windows/DynamicDns.cpp b/wpiutil/src/main/native/windows/DynamicDns.cpp
deleted file mode 100644
index c59d554..0000000
--- a/wpiutil/src/main/native/windows/DynamicDns.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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 "DynamicDns.h"
-
-using namespace wpi;
-
-DynamicDns& DynamicDns::GetDynamicDns() {
- static DynamicDns dns;
- return dns;
-}
-
-DynamicDns::DynamicDns() {
- HMODULE library = LoadLibraryW(L"dnsapi");
-
- if (library == nullptr) {
- return;
- }
-
- DnsServiceFreeInstancePtr = (DnsServiceFreeInstanceFunc)GetProcAddress(
- library, "DnsServiceFreeInstance");
- DnsServiceConstructInstancePtr =
- (DnsServiceConstructInstanceFunc)GetProcAddress(
- library, "DnsServiceConstructInstance");
- DnsServiceRegisterPtr =
- (DnsServiceRegisterFunc)GetProcAddress(library, "DnsServiceRegister");
- DnsServiceDeRegisterPtr =
- (DnsServiceDeRegisterFunc)GetProcAddress(library, "DnsServiceDeRegister");
-
- CanDnsAnnounce = DnsServiceFreeInstancePtr &&
- DnsServiceConstructInstancePtr && DnsServiceRegisterPtr &&
- DnsServiceDeRegisterPtr;
-
- DnsServiceBrowsePtr =
- (DnsServiceBrowseFunc)GetProcAddress(library, "DnsServiceBrowse");
- DnsServiceBrowseCancelPtr = (DnsServiceBrowseCancelFunc)GetProcAddress(
- library, "DnsServiceBrowseCancel");
-
- CanDnsResolve = DnsServiceBrowsePtr && DnsServiceBrowseCancelPtr;
-}
diff --git a/wpiutil/src/main/native/windows/DynamicDns.h b/wpiutil/src/main/native/windows/DynamicDns.h
deleted file mode 100644
index c8bee04..0000000
--- a/wpiutil/src/main/native/windows/DynamicDns.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// 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
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
-#include <windows.h>
-
-#include <WinDNS.h>
-
-namespace wpi {
-class DynamicDns {
- public:
- using DnsServiceFreeInstanceFunc =
- VOID(WINAPI*)(_In_ PDNS_SERVICE_INSTANCE pInstance);
-
- using DnsServiceConstructInstanceFunc = PDNS_SERVICE_INSTANCE(WINAPI*)(
- _In_ PCWSTR pServiceName, _In_ PCWSTR pHostName,
- _In_opt_ PIP4_ADDRESS pIp4, _In_opt_ PIP6_ADDRESS pIp6, _In_ WORD wPort,
- _In_ WORD wPriority, _In_ WORD wWeight, _In_ DWORD dwPropertiesCount,
- _In_reads_(dwPropertiesCount) PCWSTR* keys,
- _In_reads_(dwPropertiesCount) PCWSTR* values);
-
- using DnsServiceRegisterFunc =
- DWORD(WINAPI*)(_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
- _Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
-
- using DnsServiceDeRegisterFunc =
- DWORD(WINAPI*)(_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
- _Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
-
- using DnsServiceBrowseFunc =
- DNS_STATUS(WINAPI*)(_In_ PDNS_SERVICE_BROWSE_REQUEST pRequest,
- _Inout_ PDNS_SERVICE_CANCEL pCancel);
-
- using DnsServiceBrowseCancelFunc =
- DNS_STATUS(WINAPI*)(_In_ PDNS_SERVICE_CANCEL pCancelHandle);
-
- DnsServiceBrowseFunc DnsServiceBrowsePtr{nullptr};
- DnsServiceBrowseCancelFunc DnsServiceBrowseCancelPtr{nullptr};
-
- DnsServiceFreeInstanceFunc DnsServiceFreeInstancePtr{nullptr};
- DnsServiceConstructInstanceFunc DnsServiceConstructInstancePtr{nullptr};
- DnsServiceRegisterFunc DnsServiceRegisterPtr{nullptr};
- DnsServiceDeRegisterFunc DnsServiceDeRegisterPtr{nullptr};
-
- bool CanDnsAnnounce{false};
- bool CanDnsResolve{false};
-
- static DynamicDns& GetDynamicDns();
-
- private:
- DynamicDns();
-};
-} // namespace wpi
diff --git a/wpiutil/src/main/native/windows/MulticastServiceAnnouncer.cpp b/wpiutil/src/main/native/windows/MulticastServiceAnnouncer.cpp
deleted file mode 100644
index 2327b8b..0000000
--- a/wpiutil/src/main/native/windows/MulticastServiceAnnouncer.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-// 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.
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
-#include "wpi/MulticastServiceAnnouncer.h"
-
-#include <string>
-#include <vector>
-
-#include "DynamicDns.h"
-#include "wpi/ConvertUTF.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/StringExtras.h"
-#include "wpi/hostname.h"
-
-using namespace wpi;
-
-struct ImplBase {
- wpi::DynamicDns& dynamicDns = wpi::DynamicDns::GetDynamicDns();
- PDNS_SERVICE_INSTANCE serviceInstance = nullptr;
- HANDLE event = nullptr;
-};
-
-struct MulticastServiceAnnouncer::Impl : ImplBase {
- std::wstring serviceType;
- std::wstring serviceInstanceName;
- std::wstring hostName;
- int port;
- std::vector<std::wstring> keys;
- std::vector<PCWSTR> keyPtrs;
- std::vector<std::wstring> values;
- std::vector<PCWSTR> valuePtrs;
-
- template <typename T>
- Impl(std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<T, T>> txt);
-};
-
-template <typename T>
-MulticastServiceAnnouncer::Impl::Impl(std::string_view serviceName,
- std::string_view serviceType, int port,
- wpi::span<const std::pair<T, T>> txt) {
- if (!dynamicDns.CanDnsAnnounce) {
- return;
- }
-
- this->port = port;
-
- wpi::SmallVector<wchar_t, 128> wideStorage;
- std::string hostName = wpi::GetHostname() + ".local";
-
- for (auto&& i : txt) {
- wideStorage.clear();
- wpi::sys::windows::UTF8ToUTF16(i.first, wideStorage);
- this->keys.emplace_back(
- std::wstring{wideStorage.data(), wideStorage.size()});
- wideStorage.clear();
- wpi::sys::windows::UTF8ToUTF16(i.second, wideStorage);
- this->values.emplace_back(
- std::wstring{wideStorage.data(), wideStorage.size()});
- }
-
- for (size_t i = 0; i < this->keys.size(); i++) {
- this->keyPtrs.emplace_back(this->keys[i].c_str());
- this->valuePtrs.emplace_back(this->values[i].c_str());
- }
-
- wpi::SmallString<128> storage;
-
- wideStorage.clear();
- wpi::sys::windows::UTF8ToUTF16(hostName, wideStorage);
-
- this->hostName = std::wstring{wideStorage.data(), wideStorage.size()};
-
- wideStorage.clear();
- if (wpi::ends_with_lower(serviceType, ".local")) {
- wpi::sys::windows::UTF8ToUTF16(serviceType, wideStorage);
- } else {
- storage.clear();
- storage.append(serviceType);
- storage.append(".local");
- wpi::sys::windows::UTF8ToUTF16(storage.str(), wideStorage);
- }
- this->serviceType = std::wstring{wideStorage.data(), wideStorage.size()};
-
- wideStorage.clear();
- storage.clear();
- storage.append(serviceName);
- storage.append(".");
- storage.append(serviceType);
- if (!wpi::ends_with_lower(serviceType, ".local")) {
- storage.append(".local");
- }
-
- wpi::sys::windows::UTF8ToUTF16(storage.str(), wideStorage);
- this->serviceInstanceName =
- std::wstring{wideStorage.data(), wideStorage.size()};
-}
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string, std::string>> txt) {
- pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
-}
-
-MulticastServiceAnnouncer::MulticastServiceAnnouncer(
- std::string_view serviceName, std::string_view serviceType, int port,
- wpi::span<const std::pair<std::string_view, std::string_view>> txt) {
- pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
-}
-
-MulticastServiceAnnouncer::~MulticastServiceAnnouncer() noexcept {
- Stop();
-}
-
-bool MulticastServiceAnnouncer::HasImplementation() const {
- return pImpl->dynamicDns.CanDnsAnnounce;
-}
-
-static void WINAPI DnsServiceRegisterCallback(DWORD /*Status*/,
- PVOID pQueryContext,
- PDNS_SERVICE_INSTANCE pInstance) {
- ImplBase* impl = reinterpret_cast<ImplBase*>(pQueryContext);
-
- impl->serviceInstance = pInstance;
-
- SetEvent(impl->event);
-}
-
-void MulticastServiceAnnouncer::Start() {
- if (pImpl->serviceInstance) {
- return;
- }
-
- if (!pImpl->dynamicDns.CanDnsAnnounce) {
- return;
- }
-
- PDNS_SERVICE_INSTANCE serviceInst =
- pImpl->dynamicDns.DnsServiceConstructInstancePtr(
- pImpl->serviceInstanceName.c_str(), pImpl->hostName.c_str(), nullptr,
- nullptr, pImpl->port, 0, 0, static_cast<DWORD>(pImpl->keyPtrs.size()),
- pImpl->keyPtrs.data(), pImpl->valuePtrs.data());
- if (serviceInst == nullptr) {
- return;
- }
-
- DNS_SERVICE_REGISTER_REQUEST registerRequest = {};
- registerRequest.pQueryContext = static_cast<ImplBase*>(pImpl.get());
- registerRequest.pRegisterCompletionCallback = DnsServiceRegisterCallback;
- registerRequest.Version = DNS_QUERY_REQUEST_VERSION1;
- registerRequest.unicastEnabled = false;
- registerRequest.pServiceInstance = serviceInst;
- registerRequest.InterfaceIndex = 0;
-
- pImpl->event = CreateEvent(NULL, true, false, NULL);
-
- if (pImpl->dynamicDns.DnsServiceRegisterPtr(®isterRequest, nullptr) ==
- DNS_REQUEST_PENDING) {
- WaitForSingleObject(pImpl->event, INFINITE);
- }
-
- pImpl->dynamicDns.DnsServiceFreeInstancePtr(serviceInst);
- CloseHandle(pImpl->event);
- pImpl->event = nullptr;
-}
-
-static void WINAPI DnsServiceDeRegisterCallback(
- DWORD /*Status*/, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
- ImplBase* impl = reinterpret_cast<ImplBase*>(pQueryContext);
-
- if (pInstance != nullptr) {
- impl->dynamicDns.DnsServiceFreeInstancePtr(pInstance);
- pInstance = nullptr;
- }
-
- SetEvent(impl->event);
-}
-
-void MulticastServiceAnnouncer::Stop() {
- if (!pImpl->dynamicDns.CanDnsAnnounce) {
- return;
- }
-
- if (pImpl->serviceInstance == nullptr) {
- return;
- }
-
- pImpl->event = CreateEvent(NULL, true, false, NULL);
- DNS_SERVICE_REGISTER_REQUEST registerRequest = {};
- registerRequest.pQueryContext = static_cast<ImplBase*>(pImpl.get());
- registerRequest.pRegisterCompletionCallback = DnsServiceDeRegisterCallback;
- registerRequest.Version = DNS_QUERY_REQUEST_VERSION1;
- registerRequest.unicastEnabled = false;
- registerRequest.pServiceInstance = pImpl->serviceInstance;
- registerRequest.InterfaceIndex = 0;
-
- if (pImpl->dynamicDns.DnsServiceDeRegisterPtr(®isterRequest, nullptr) ==
- DNS_REQUEST_PENDING) {
- WaitForSingleObject(pImpl->event, INFINITE);
- }
-
- pImpl->dynamicDns.DnsServiceFreeInstancePtr(pImpl->serviceInstance);
- pImpl->serviceInstance = nullptr;
- CloseHandle(pImpl->event);
- pImpl->event = nullptr;
-}
diff --git a/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp b/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp
deleted file mode 100644
index 115b43f..0000000
--- a/wpiutil/src/main/native/windows/MulticastServiceResolver.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-// 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.
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
-#include "wpi/MulticastServiceResolver.h"
-
-#include <string>
-
-#include "DynamicDns.h"
-#include "wpi/ConvertUTF.h"
-#include "wpi/SmallString.h"
-#include "wpi/SmallVector.h"
-#include "wpi/StringExtras.h"
-
-#pragma comment(lib, "dnsapi")
-
-using namespace wpi;
-
-struct MulticastServiceResolver::Impl {
- wpi::DynamicDns& dynamicDns = wpi::DynamicDns::GetDynamicDns();
- std::wstring serviceType;
- DNS_SERVICE_CANCEL serviceCancel{nullptr};
-
- MulticastServiceResolver* resolver;
-
- void onFound(ServiceData&& data) {
- resolver->PushData(std::forward<ServiceData>(data));
- }
-};
-
-MulticastServiceResolver::MulticastServiceResolver(
- std::string_view serviceType) {
- pImpl = std::make_unique<Impl>();
- pImpl->resolver = this;
-
- if (!pImpl->dynamicDns.CanDnsResolve) {
- return;
- }
-
- wpi::SmallVector<wchar_t, 128> wideStorage;
-
- if (wpi::ends_with_lower(serviceType, ".local")) {
- wpi::sys::windows::UTF8ToUTF16(serviceType, wideStorage);
- } else {
- wpi::SmallString<128> storage;
- storage.append(serviceType);
- storage.append(".local");
- wpi::sys::windows::UTF8ToUTF16(storage.str(), wideStorage);
- }
- pImpl->serviceType = std::wstring{wideStorage.data(), wideStorage.size()};
-}
-
-MulticastServiceResolver::~MulticastServiceResolver() noexcept {
- Stop();
-}
-
-bool MulticastServiceResolver::HasImplementation() const {
- return pImpl->dynamicDns.CanDnsResolve;
-}
-
-static _Function_class_(DNS_QUERY_COMPLETION_ROUTINE) VOID WINAPI
- DnsCompletion(_In_ PVOID pQueryContext,
- _Inout_ PDNS_QUERY_RESULT pQueryResults) {
- MulticastServiceResolver::Impl* impl =
- reinterpret_cast<MulticastServiceResolver::Impl*>(pQueryContext);
-
- wpi::SmallVector<DNS_RECORDW*, 4> PtrRecords;
- wpi::SmallVector<DNS_RECORDW*, 4> SrvRecords;
- wpi::SmallVector<DNS_RECORDW*, 4> TxtRecords;
- wpi::SmallVector<DNS_RECORDW*, 4> ARecords;
-
- {
- DNS_RECORDW* current = pQueryResults->pQueryRecords;
- while (current != nullptr) {
- switch (current->wType) {
- case DNS_TYPE_PTR:
- PtrRecords.push_back(current);
- break;
- case DNS_TYPE_SRV:
- SrvRecords.push_back(current);
- break;
- case DNS_TYPE_TEXT:
- TxtRecords.push_back(current);
- break;
- case DNS_TYPE_A:
- ARecords.push_back(current);
- break;
- }
- current = current->pNext;
- }
- }
-
- for (DNS_RECORDW* Ptr : PtrRecords) {
- if (std::wstring_view{Ptr->pName} != impl->serviceType) {
- continue;
- }
-
- std::wstring_view nameHost = Ptr->Data.Ptr.pNameHost;
- DNS_RECORDW* foundSrv = nullptr;
- for (DNS_RECORDW* Srv : SrvRecords) {
- if (std::wstring_view{Srv->pName} == nameHost) {
- foundSrv = Srv;
- break;
- }
- }
-
- if (!foundSrv) {
- continue;
- }
-
- for (DNS_RECORDW* A : ARecords) {
- if (std::wstring_view{A->pName} ==
- std::wstring_view{foundSrv->Data.Srv.pNameTarget}) {
- MulticastServiceResolver::ServiceData data;
- wpi::SmallString<128> storage;
- for (DNS_RECORDW* Txt : TxtRecords) {
- if (std::wstring_view{Txt->pName} == nameHost) {
- for (DWORD i = 0; i < Txt->Data.Txt.dwStringCount; i++) {
- std::wstring_view wideView = Txt->Data.TXT.pStringArray[i];
- size_t splitIndex = wideView.find(L'=');
- if (splitIndex == wideView.npos) {
- // Todo make this just do key
- continue;
- }
- storage.clear();
- wpi::span<const wpi::UTF16> wideStr{
- reinterpret_cast<const wpi::UTF16*>(wideView.data()),
- splitIndex};
- wpi::convertUTF16ToUTF8String(wideStr, storage);
- auto& pair = data.txt.emplace_back(
- std::pair<std::string, std::string>{storage.string(), {}});
- storage.clear();
- wideStr = wpi::span<const wpi::UTF16>{
- reinterpret_cast<const wpi::UTF16*>(wideView.data() +
- splitIndex + 1),
- wideView.size() - splitIndex - 1};
- wpi::convertUTF16ToUTF8String(wideStr, storage);
- pair.second = storage.string();
- }
- }
- }
-
- storage.clear();
- wpi::span<const wpi::UTF16> wideHostName{
- reinterpret_cast<const wpi::UTF16*>(A->pName), wcslen(A->pName)};
- wpi::convertUTF16ToUTF8String(wideHostName, storage);
- storage.append(".");
-
- data.hostName = storage.string();
- storage.clear();
-
- int len = nameHost.find(impl->serviceType.c_str());
- wpi::span<const wpi::UTF16> wideServiceName{
- reinterpret_cast<const wpi::UTF16*>(nameHost.data()),
- nameHost.size()};
- if (len != nameHost.npos) {
- wideServiceName = wideServiceName.subspan(0, len - 1);
- }
- wpi::convertUTF16ToUTF8String(wideServiceName, storage);
-
- data.serviceName = storage.string();
- data.port = foundSrv->Data.Srv.wPort;
- data.ipv4Address = A->Data.A.IpAddress;
-
- impl->onFound(std::move(data));
- }
- }
- }
- DnsFree(pQueryResults->pQueryRecords, DNS_FREE_TYPE::DnsFreeRecordList);
-}
-
-void MulticastServiceResolver::Start() {
- if (pImpl->serviceCancel.reserved != nullptr) {
- return;
- }
-
- if (!pImpl->dynamicDns.CanDnsResolve) {
- return;
- }
-
- DNS_SERVICE_BROWSE_REQUEST request = {};
- request.InterfaceIndex = 0;
- request.pQueryContext = pImpl.get();
- request.QueryName = pImpl->serviceType.c_str();
- request.Version = 2;
- request.pBrowseCallbackV2 = DnsCompletion;
- pImpl->dynamicDns.DnsServiceBrowsePtr(&request, &pImpl->serviceCancel);
-}
-
-void MulticastServiceResolver::Stop() {
- if (!pImpl->dynamicDns.CanDnsResolve) {
- return;
- }
-
- if (pImpl->serviceCancel.reserved == nullptr) {
- return;
- }
-
- pImpl->dynamicDns.DnsServiceBrowseCancelPtr(&pImpl->serviceCancel);
- pImpl->serviceCancel.reserved = nullptr;
-}
diff --git a/wpiutil/src/main/native/windows/StackTrace.cpp b/wpiutil/src/main/native/windows/StackTrace.cpp
index bab5f83..de31b2a 100644
--- a/wpiutil/src/main/native/windows/StackTrace.cpp
+++ b/wpiutil/src/main/native/windows/StackTrace.cpp
@@ -8,6 +8,8 @@
#include "wpi/ConvertUTF.h"
#include "wpi/SmallString.h"
+#if defined(_MSC_VER)
+
namespace {
class StackTraceWalker : public StackWalker {
public:
@@ -40,3 +42,5 @@
}
} // namespace wpi
+
+#endif // defined(_MSC_VER)
diff --git a/wpiutil/src/main/native/windows/StackWalker.cpp b/wpiutil/src/main/native/windows/StackWalker.cpp
index 237360a..6f0fbf2 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
@@ -485,8 +485,8 @@
if (hToolhelp == NULL)
continue;
createToolhelp32Snapshot = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
- module32First = (tM32F)GetProcAddress(hToolhelp, strModule32First);
- module32Next = (tM32N)GetProcAddress(hToolhelp, strModule32Next);
+ module32First = (tM32F)GetProcAddress(hToolhelp, strModule32First);
+ module32Next = (tM32N)GetProcAddress(hToolhelp, strModule32Next);
if ((createToolhelp32Snapshot != NULL) && (module32First != NULL) && (module32Next != NULL))
break; // found the functions!
FreeLibrary(hToolhelp);
diff --git a/wpiutil/src/main/native/windows/StackWalker.h b/wpiutil/src/main/native/windows/StackWalker.h
index 750de96..89be951 100644
--- a/wpiutil/src/main/native/windows/StackWalker.h
+++ b/wpiutil/src/main/native/windows/StackWalker.h
@@ -1,3 +1,8 @@
+#ifndef __STACKWALKER_H__
+#define __STACKWALKER_H__
+
+#if defined(_MSC_VER)
+
/**********************************************************************
*
* StackWalker.h
@@ -32,6 +37,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* **********************************************************************/
+// #pragma once is supported starting with _MSC_VER 1000,
+// so we need not to check the version (because we only support _MSC_VER >= 1100)!
#pragma once
#include <windows.h>
@@ -105,7 +112,11 @@
BOOL ShowObject(LPVOID pObject);
+#if _MSC_VER >= 1300
+ // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
+ // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
protected:
+#endif
enum
{
STACKWALK_MAX_NAMELEN = 1024
@@ -176,3 +187,7 @@
c.ContextFlags = contextFlags; \
RtlCaptureContext(&c); \
} while (0);
+
+#endif //defined(_MSC_VER)
+
+#endif // __STACKWALKER_H__