mirror of
https://github.com/simplysanatori/KartFrame.git
synced 2026-10-17 11:01:37 +02:00
Compare commits
17
Commits
No files matched your search
@@ -86,3 +86,10 @@ output.txt
|
||||
/android/.runs/
|
||||
# Local patched launcher build, reproducible from integrations/wheelwizard-vr.patch.
|
||||
/integrations/wheelwizard-work/
|
||||
|
||||
# Steam Frame build (steam-frame/build.sh): toolchain downloads, objects, APKs and the signing key
|
||||
/steam-frame/dl/
|
||||
/steam-frame/out/
|
||||
/steam-frame/release/
|
||||
/steam-frame/signing/
|
||||
__pycache__/
|
||||
+2
-1
@@ -41,7 +41,8 @@ That's ok, but rules apply:
|
||||
|
||||
## Bug reports
|
||||
|
||||
See the FAQ in the [README](README.md)
|
||||
For the Steam Frame build, see "Logs and reporting a problem" in the [README](README.md).
|
||||
For the upstream port, see "Troubleshooting" in [README.upstream.md](README.upstream.md).
|
||||
|
||||
## A note on related projects
|
||||
|
||||
|
||||
@@ -1,311 +1,431 @@
|
||||
# Mario Kart Wii VR Port — Wiicompiled VR PLUS
|
||||
# Mario Kart Wii VR on the Steam Frame
|
||||
|
||||
This is the **Wiicompiled VR PLUS** fork of [iChris4/Wiicompiled_VR](https://github.com/iChris4/Wiicompiled_VR). It combines that OpenXR port with the VR gameplay, controller, launcher and packaging work from [heurazy/mario-kart-wii-VR-port](https://github.com/heurazy/mario-kart-wii-VR-port), then adds a standalone Android build for Quest.
|
||||
This is a fork of [heurazy/Wiicompiled_VR-PLUS](https://github.com/heurazy/Wiicompiled_VR-PLUS),
|
||||
the Mario Kart Wii VR port. It runs standalone on Valve's Steam Frame through Lepton, the Frame's
|
||||
Android compatibility tool. No PC is involved.
|
||||
|
||||
On Windows, the game is statically recompiled to native x86-64 and rendered through OpenXR. On Quest standalone, the ARM64 build runs locally with Vulkan and OpenXR. Neither version runs the game through a Wii emulator, interpreter or JIT.
|
||||
Upstream's Quest APK installs on the Frame, but the game crashes as soon as it starts. With the
|
||||
changes here it starts from the Steam library, runs at 90 Hz, and uses a gamepad-style layout on
|
||||
the Frame controllers.
|
||||
|
||||
This repository contains source code, build tools and integration patches. It does **not** contain Nintendo game code, a translated game executable, a ROM or Retro Rewind's game files. You must provide your own clean PAL `RMCP01` disc image and build the game on your own device.
|
||||
The branch is `steam-frame`. The fork's files are in [`steam-frame/`](steam-frame/), plus six
|
||||
commits to `runtime/` and `aurora-main/`. Upstream's README is kept as
|
||||
[README.upstream.md](README.upstream.md). Read it for what the port itself does. This file only
|
||||
covers the Frame.
|
||||
|
||||
[Browse Wiicompiled VR PLUS](https://github.com/heurazy/Wiicompiled_VR-PLUS) · [Release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases) · [Original Mario Kart Wii VR port](https://github.com/heurazy/mario-kart-wii-VR-port)
|
||||
**Status, October 2026.** Release `v1.3.1-frame.3` works on my Steam Frame with SteamOS 0.4.5,
|
||||
Lepton 2.8.14 and SteamVR. Tested: single player, the original and first-person cameras, the
|
||||
menus and the VR settings panel. Read [Known problems](#known-problems) before you start.
|
||||
|
||||
> Download the Windows installer, portable launcher bundle or Quest APK from this fork's [latest release](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases/latest).
|
||||
**AI use.** The code and the docs in this fork were written with Claude Code (Anthropic's Claude
|
||||
Opus 5.5 and Claude Fable 5.1), running on the Frame. I chose what to try, tested every build in
|
||||
the headset and reported what I saw. Nobody from the upstream project has reviewed this fork.
|
||||
Read the diffs before you trust them.
|
||||
|
||||
## What this fork adds
|
||||
## Contents
|
||||
|
||||
Compared with the original Mario Kart Wii VR port, this fork brings together the earlier port's user facing improvements, imports additional OpenXR features from iChris4's branch, and adds the Quest standalone target.
|
||||
- [What the fork changes](#what-the-fork-changes)
|
||||
- [Requirements](#requirements)
|
||||
- [Install](#install)
|
||||
- [First run: import the disc and build the game](#first-run-import-the-disc-and-build-the-game)
|
||||
- [Updating](#updating)
|
||||
- [Controls](#controls)
|
||||
- [Settings](#settings)
|
||||
- [Known problems](#known-problems)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Logs and reporting a problem](#logs-and-reporting-a-problem)
|
||||
- [Building the APK yourself](#building-the-apk-yourself)
|
||||
- [Where things are](#where-things-are)
|
||||
- [How this was made](#how-this-was-made)
|
||||
- [Licence and credits](#licence-and-credits)
|
||||
|
||||
## What the fork changes
|
||||
|
||||
- **Quest Touch Plus controllers:** textured controller models, animated buttons and thumbsticks, pointer interaction in menus and controller specific tutorial diagrams.
|
||||
- **Comfortable driving cameras:** original, first person and diorama views. First person hides the driver's head and adjusts for different character heights. A right stick click changes view. Optional kart movement modes include a smoothed Safe mode that follows sustained slopes and banks.
|
||||
- **Physical driving controls:** tracked hands can grip and turn the kart wheel or motorcycle handlebars. Steering supports one or two hands, passing through the centre, continuous full turns and brief tracking loss. Native vehicle steering animation can be switched off. USB wheels, pedals and paddle buttons can be calibrated; feedback is optional and light.
|
||||
- **Character body IK:** in the first-person cockpit, your selected character's own textured body and hands replace the VR gloves. Shoulders, elbows and wrists follow the tracked controllers; the torso stays stable while legs retain driving and drift movements. Trick and boost celebrations are suppressed. The head is hidden, and arm reach fits human proportions. Toggle **Character body IK** in **VR settings → Cameras**. Hand placement uses fixed built-in calibration profiles for the 24 original characters. See [body IK behavior and current limits](docs/BODY-IK.md).
|
||||
- **Spatial VR UI:** the camera chooser, VR settings, controller tutorials and supported Mario Kart menus sit in VR space and can be selected with a pointer. The first launch explains camera choice and controls; tutorials can be reset in settings.
|
||||
- **VR HUD and visibility fixes:** the circuit map and item panel appear on the left hand, while first person anchors its HUD ahead of the seat. Hand depth, track object culling, race menu rendering, display orientation and the Bullet Bill camera have dedicated VR handling.
|
||||
- **Performance controls:** per eye resolution, sharpening, refresh preference, adaptive resolution, diagnostics and menu shader quality. Frame interpolation is disabled on Quest because it makes the standalone presentation unstable; the game's simulation speed remains unchanged.
|
||||
- **Controller compatibility:** OpenXR action bindings and profiles for Quest, Valve Index, Vive, Windows Mixed Reality and PICO. Stick calibration, headset button shortcuts and the original port's exact controls are documented below.
|
||||
Upstream's design stays the same. The APK carries a "game kit": precompiled runtime objects,
|
||||
headers and a toolchain. The headset translates your own disc and links `libmain.so` against that
|
||||
kit. No Nintendo code is in the APK or in this repository.
|
||||
|
||||
The Steam Frame APK is upstream's v1.3.1 Quest APK with four kit files replaced by ones compiled
|
||||
from this branch, one patched `classes.dex`, and a new kit fingerprint. When the headset builds
|
||||
your game, it links it against the Frame objects.
|
||||
|
||||
The project retains upstream WiiCompiled/OpenXR features as well. The sections below explain the Windows setup, controls, VR settings and build process; the Quest setup is documented separately.
|
||||
1. **The app starts.** Upstream's app registers a clipboard listener at startup. Lepton's Android
|
||||
has no clipboard service, so the app crashed with a `NullPointerException`. That call is
|
||||
replaced with no-ops in `classes.dex` ([`steam-frame/dexpatch.py`](steam-frame/dexpatch.py)).
|
||||
|
||||
## OpenXR integration
|
||||
2. **90 Hz.** Upstream turns VR frame interpolation off on Android. On the Frame that showed as
|
||||
judder and ghosting when turning the head. Interpolation is on again, so the eyes render at the
|
||||
headset's refresh rate with a fresh head pose each frame while the game runs at 60 fps.
|
||||
SteamVR's OpenXR in Lepton lacks `XR_KHR_convert_timespec_time`, so there is a
|
||||
`CLOCK_MONOTONIC` fallback. (`runtime/src/vr/openxr_integration.cpp`)
|
||||
|
||||
The fusion now includes the original controls and SteamVR shortcuts, Index/Vive/WMR/PICO
|
||||
profiles, stick calibration, opt-in adaptive resolution, the legacy Bluetooth scan fix,
|
||||
license renaming without a NAND Mii, and full Wheel Wizard + portable packaging.
|
||||
See [controls and packaging](docs/PORT-CONTROLS-AND-PACKAGING.md) for exact bindings,
|
||||
upgrade behavior and the remaining hardware validation.
|
||||
3. **Frame controller layout.** The game's OpenXR actions were written for Quest Touch
|
||||
controllers. On the Frame, SteamVR mapped A to three actions and left B, X and Y unused. The
|
||||
runtime now also has hand-independent actions (`frame_item`, `frame_drift`,
|
||||
`frame_look_back`, `frame_start`, `frame_back` and four D-pad actions).
|
||||
[`steam-frame/bindings_frame_controller.json`](steam-frame/bindings_frame_controller.json)
|
||||
binds the Frame buttons to them. When SteamVR reports them bound, the game uses the layout in
|
||||
[Controls](#controls) for the rest of the session. (`runtime/src/vr/openxr_input.cpp`)
|
||||
|
||||
## Roadmap
|
||||
- better motorcycle controls : planned
|
||||
- more vehicles visual steering wheel compatibility : planned
|
||||
- more control options : planned
|
||||
- throwing shells and other items option : planned
|
||||
<details>
|
||||
<summary><h2>DONE</h2></summary>
|
||||
4. **Menus at 90 Hz.** Upstream's animated menu background held the menus at 37 to 45 fps. On
|
||||
Android the menus are now always drawn into the eye images, and menu background quality 0
|
||||
gives a plain dark background. (`openxr_integration.cpp`, `menu_shader_quality = 0`)
|
||||
|
||||
- new hand models: selected character's textured hands and body IK, with built-in hand placement profiles
|
||||
- fix character height: cockpit height and steering reach adapt to the selected character
|
||||
- automatic correction of upside-down race output: included in v1.1; feedback from affected headsets welcome
|
||||
- sim racing steering wheels and pedals: included in v1.1; hardware compatibility testing continues
|
||||
- fix low FPS in menu: menus can render above 60 FPS without accelerating the game
|
||||
- fix black hand in front of HUD: corrected hand/HUD depth
|
||||
- VR course object culling based on the player's view rather than the kart's direction: implemented in source; track validation continues
|
||||
- fix Bullet Bill gate vision: temporarily use the original game camera during Bullet Bill
|
||||
- option to move with the kart: configurable movement modes, including the smoothed Safe mode
|
||||
- multiplayer: local-player cockpit and launcher/save fixes included in v1.1; online testing depends on Retro WFC availability
|
||||
- periodic controller-search freezes: legacy Wii Remote scanning is disabled on upgrade in v1.1.1; USB wheel discovery now follows hotplug events
|
||||
5. **Item box (attempted, does not work yet).** The port now skips 2D HUD draws that lie wholly
|
||||
outside the game's scissor rectangle. The empty item box still shows in the headset. The
|
||||
change is harmless and stays in. (`aurora-main/lib/gfx/common.cpp`)
|
||||
|
||||
</details>
|
||||
6. **Frame settings.** The launch wrapper seeds `Config.toml` from
|
||||
[`steam-frame/Config.frame.toml`](steam-frame/Config.frame.toml) on the first launch, and
|
||||
`install.sh` sets per-app SteamVR values. See [Settings](#settings).
|
||||
|
||||
## VR feature details
|
||||
7. **Launch wrapper.** The app's 2D launcher never shows in the headset on the Frame.
|
||||
[`steam-frame/wiicompiled-launch.sh`](steam-frame/wiicompiled-launch.sh) waits for the
|
||||
launcher and starts the game activity itself, once a game built for this APK's kit is
|
||||
installed. A launch from the library reaches the title screen in about ten seconds.
|
||||
|
||||
- Native OpenXR rendering through D3D12 with a desktop mirror and a safe desktop fallback.
|
||||
- Three race cameras: the original game camera, a true first-person cockpit camera, and a distant
|
||||
diorama camera. The right-stick click cycles cameras during a race.
|
||||
- A seated cockpit aligned to the driver's evaluated eye position. Character body IK shows the
|
||||
tracked body and hands with the head hidden; the view adapts to small, tall, and temporarily resized characters.
|
||||
- Physical steering: grab the real kart wheel or motorcycle handlebar with either tracked hand.
|
||||
Native vehicle animation is enabled by default and can be disabled in VR settings.
|
||||
- Two-hand steering with centre-crossing and brief tracking-loss tolerance, adaptive smoothing,
|
||||
full-turn hand continuity, and a left-stick fallback after both hands release the control.
|
||||
- Tracked hands depth-tested against the kart and the track, with SteamVR controller models and
|
||||
per-controller button animations in the VR tutorials and menus.
|
||||
- A left-hand race HUD with the circuit map and item panel. In first person, the HUD is anchored in
|
||||
front of the seat so it stays readable while the head moves.
|
||||
- An anchored, spatial VR presentation for the camera chooser, VR settings, controller guides, and
|
||||
Mario Kart menus. The first launch offers a camera choice through a VR pointer.
|
||||
- A first-race controller tutorial, plus a separate first-person tutorial. Both can be reset from
|
||||
VR settings.
|
||||
- Configurable eye resolution, sharpness, refresh-rate preference, adaptive resolution, world scale,
|
||||
HUD placement, camera trim, steering response, grab assistance, deadzone, haptics, and diagnostics.
|
||||
- Retro Rewind VR support through WheelWizard, with pack updates, patch preparation,
|
||||
compiled-product repair, and access to the VR installation's saves, friends and Miis.
|
||||
See [WheelWizard feature coverage](docs/WHEELWIZARD-VR.md) for the local integration
|
||||
and its limits.
|
||||
8. **Grips in the cockpit.** In the first-person cockpit the grips hold the steering wheel. In
|
||||
the other cameras they drift. The right bumper drifts in every camera.
|
||||
|
||||
9. **Frame controller models.** Inside Lepton the app gets no SteamVR render models, so upstream
|
||||
showed Quest controllers in the menus.
|
||||
[`steam-frame/frame-controller-models.py`](steam-frame/frame-controller-models.py) converts the
|
||||
Frame controller models from your own SteamVR install into the game's format and simplifies
|
||||
them to about 4,000 triangles per hand. `install.sh` runs it, and the launch wrapper copies the
|
||||
result over the Quest files on each launch. Valve's models are never included in the repository
|
||||
or the APK.
|
||||
|
||||
The cameras, hand IK, HUD and Retro Rewind support are upstream's work and are unchanged.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows 10 or 11, 64-bit.
|
||||
- An installed, active OpenXR runtime with the headset connected. The game uses your active runtime
|
||||
by default, including SteamVR or Virtual Desktop's VDXR. F10 → Use SteamVR (next launch)
|
||||
can explicitly select SteamVR for the game without changing the system's active runtime.
|
||||
- A D3D12-capable GPU and a driver accepted by your OpenXR runtime and Dawn. GTX 1650 / RX 6400 /
|
||||
Arc A310 or better is a practical starting point.
|
||||
- About 20 GB free while installing and compiling. The compiled game is about 5 GB, excluding
|
||||
optional Retro Rewind files.
|
||||
- Your own clean, unmodified PAL `RMCP01` disc image. ISO, GCM, GCZ, CISO, WBFS, WIA, and RVZ are
|
||||
accepted. Other regions and modified executables are rejected.
|
||||
- A Steam Frame.
|
||||
- **Lepton**, installed from Steam (Library > Tools).
|
||||
- Your own clean PAL Mario Kart Wii disc image, game ID `RMCP01`. ISO works. Upstream's importer
|
||||
also lists RVZ, WBFS and other formats. Other regions and modified images are rejected.
|
||||
- About 5 GB free.
|
||||
- A terminal on the Frame: Konsole in desktop mode, or SSH from another computer.
|
||||
- Steam running while you install. No root and no `pacman` are needed.
|
||||
|
||||
## Installation
|
||||
## Install
|
||||
|
||||
### Guided installer
|
||||
1. Get the repository:
|
||||
|
||||
1. Download the Windows setup asset from this fork's [release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases).
|
||||
2. Connect your headset through your OpenXR runtime, then run the installer.
|
||||
3. Select your clean PAL `RMCP01` image and choose an installation folder.
|
||||
4. Leave **Download and install Retro Rewind automatically** enabled if you want both games.
|
||||
5. Select **Install**. The setup translates and compiles the game on this PC; the image never leaves
|
||||
the computer.
|
||||
```sh
|
||||
git clone -b steam-frame https://github.com/simplysanatori/Wiicompiled_VR-PLUS-steam-frame.git
|
||||
cd Wiicompiled_VR-PLUS-steam-frame
|
||||
```
|
||||
|
||||
The installer installs WheelWizard in the `WheelWizard` subfolder, creates a **Mario Kart Wii VR
|
||||
Launcher** shortcut on the desktop and in the Start Menu, and opens the launcher when installation
|
||||
finishes. Select **Mario Kart Wii VR** or **Retro Rewind VR** from that launcher.
|
||||
2. Download `WiiCompiled-VR-SteamFrame-*.apk` from the
|
||||
[Releases](https://github.com/simplysanatori/Wiicompiled_VR-PLUS-steam-frame/releases) page.
|
||||
Use `v1.3.1-frame.2` or newer. Each release lists the APK's SHA-256 in `SHA256SUMS.txt`:
|
||||
|
||||
### Portable bundle
|
||||
```sh
|
||||
sha256sum ~/Downloads/WiiCompiled-VR-SteamFrame-*.apk
|
||||
```
|
||||
|
||||
Download this fork's portable archive from its [release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases). Extract the complete folder and run
|
||||
`WiiCompiled-Setup.exe`. Keep **portable installation** enabled and keep the folder together.
|
||||
Start the launcher with `Launch-WiiCompiled-VR.cmd` or `WheelWizard/WheelWizard.exe`. The
|
||||
`UserData` folder keeps configuration, NAND, cache and logs beside the portable installation.
|
||||
Keep the whole folder when moving or updating it so saves and compiled games remain available.
|
||||
You can also build the APK yourself ([Building the APK yourself](#building-the-apk-yourself)).
|
||||
The APK contains no game data.
|
||||
|
||||
No release contains a ROM or a translated game executable. Compilation is intentionally performed
|
||||
locally from the disc image you select.
|
||||
3. Run the installer with Steam running. Use the `install.sh` from the same release tag or newer:
|
||||
|
||||
### Quest standalone
|
||||
```sh
|
||||
steam-frame/install.sh ~/Downloads/WiiCompiled-VR-SteamFrame-*.apk
|
||||
```
|
||||
|
||||
Quest standalone is a separate Android build; the Windows setup and portable archive do not install it. The current preview targets ARM64 and has been tested on Quest 3. For a local build, APK installation, game import and Retro Rewind setup, follow [the Quest 3 preview guide](docs/quest3-preview.md) and [Android build guide](android/README.md). The APK does not bundle your ROM or translated game. Import a `.wcgame` compiled from your own PAL image and keep your game data on the headset. After setup, the game runs without a PC or SteamVR.
|
||||
The installer:
|
||||
|
||||
The current stock Dawn APK does not include fragment density map foveation. See the preview guide for the source build option and exact SDK/toolchain requirements.
|
||||
- copies the APK, the launch wrapper and the seed config to `~/Games/WiiCompiledVR-SteamFrame/`;
|
||||
- converts the Frame controller models from SteamVR;
|
||||
- adds a **Mario Kart Wii VR** entry to the Steam library, set to the Lepton compatibility
|
||||
tool, through Steam's client API;
|
||||
- writes the controller binding and the 90 Hz settings into SteamVR for that entry;
|
||||
- prints the entry's appid. You need it for the first run.
|
||||
|
||||
Frame interpolation is deliberately unavailable on Quest: the runtime forces it off even if an old config requests it, and the Quest settings omit the control. The game's 60 Hz simulation speed remains unchanged while the headset tracks head motion at its selected refresh rate. This Quest only setting does not change Windows interpolation options.
|
||||
Running it again updates the same entry.
|
||||
|
||||
## USB steering wheels and pedals
|
||||
## First run: import the disc and build the game
|
||||
|
||||
Open **VR settings > Hardware wheel** (also available in desktop controller settings).
|
||||
Select the steering device and axis; record full left, full right and center. Select each
|
||||
pedal's device and axis, then record its released and fully pressed positions. Separate USB
|
||||
pedals, inverted axes and combined pedal axes are supported through SDL's raw joystick input;
|
||||
the device does not need an Xbox/gamepad mapping. For a combined axis, select the same axis for
|
||||
both pedals and record their opposite pressed positions.
|
||||
1. Put the disc image in `~/Documents/` on the Frame. Lepton shows that folder to the app as
|
||||
`/sdcard/Documents`.
|
||||
|
||||
Assign the **right paddle to drift** and **left paddle to items**, then enable the physical wheel.
|
||||
Paddle numbers vary by driver, so these assignments require pressing each paddle during setup.
|
||||
Optional hardware buttons provide tricks/wheelies, confirm and pause. The brake pedal brakes,
|
||||
then reverses, in every race camera. It takes priority over acceleration and drift. Mario Kart's
|
||||
acceleration remains a digital game action, even with an analog pedal. VR controllers remain
|
||||
available for menu navigation, camera selection, pause and item aiming. The visible cockpit wheel
|
||||
follows hardware steering. Configuration is saved beside the active config in `PhysicalWheel.toml`.
|
||||
2. Put the headset on and launch **Mario Kart Wii VR** from the library. The first launch takes
|
||||
about a minute while Lepton installs the APK. You will only see SteamVR's empty space. The
|
||||
app's launcher is running but cannot be seen. Leave it running.
|
||||
|
||||
Feedback is **off by default**. Optional light vibration follows the game's original rumble
|
||||
events, including curbs only where the game emits rumble. Effects are short and strength is
|
||||
capped at 15%; no constant torque, spring or centering effect is requested. Rumble support depends
|
||||
on the driver; lack of rumble does not prevent driving. This is not simulated tire-force feedback.
|
||||
An incomplete/disconnected setup gives neutral race input. Close options and release held buttons
|
||||
and pedals before driving. Hardware/driver compatibility needs testing; no universal device support
|
||||
is claimed.
|
||||
3. In the terminal, import the disc. Replace `<appid>` with the number from `install.sh` and
|
||||
`MarioKart.iso` with your file name:
|
||||
|
||||
## Quest and OpenXR controls
|
||||
```sh
|
||||
LEPTON=~/.local/share/Steam/steamapps/common/Lepton/lepton
|
||||
$LEPTON exec steamlaunch-<appid> am start-foreground-service -n org.wiicompiled.quest/.launcher.GameSetupService \
|
||||
-d file:///sdcard/Documents/MarioKart.iso --es task ExtractDisc
|
||||
```
|
||||
|
||||
The runtime uses standard OpenXR actions, so Quest 2, Quest 3, Touch Pro, Valve Index, PICO, Vive,
|
||||
Windows Mixed Reality, Samsung Odyssey, and other advertised profiles use the same in-game actions.
|
||||
Vive trackpads substitute for thumbsticks where necessary. The left menu/system button keeps its
|
||||
headset function; on SteamVR it opens the SteamVR dashboard.
|
||||
This checks the disc and extracts it into the app's data folder. It takes a few minutes.
|
||||
|
||||
| Controller input | Original / diorama camera | First-person cockpit |
|
||||
4. Build the game:
|
||||
|
||||
```sh
|
||||
$LEPTON exec steamlaunch-<appid> am start-foreground-service -n org.wiicompiled.quest/.launcher.GameSetupService \
|
||||
--es task BuildGame
|
||||
```
|
||||
|
||||
The headset translates and compiles the game against the Frame kit. This took about 13
|
||||
minutes on my Frame. Progress goes to
|
||||
`~/.local/share/Steam/steamapps/compatdata/<appid>/external/Android/data/org.wiicompiled.quest/files/WiiCompiledOpenXRVR/Logs/build_*.log`.
|
||||
You can also follow it over adb:
|
||||
|
||||
```sh
|
||||
/usr/lib/android-sdk/platform-tools/adb connect localhost:5555
|
||||
/usr/lib/android-sdk/platform-tools/adb -s localhost:5555 logcat | grep -iE 'GameSetup|DiscExtract|GameBuild|WiiCompiled'
|
||||
```
|
||||
|
||||
5. When the build log says the game is installed, quit the app (Steam button, then exit) and
|
||||
launch it again. From now on every launch goes straight into the game. On the first start the
|
||||
game asks you to pick a camera with the pointer. Your choices are saved to `Config.toml`.
|
||||
|
||||
## Updating
|
||||
|
||||
- **From an older Frame release.** Run the newer `install.sh` with the new APK. It updates the
|
||||
same library entry. Lepton reinstalls the app on the next launch. A new release usually has a
|
||||
new kit fingerprint, so run the `BuildGame` command from the first run again. The disc import,
|
||||
saves and settings are kept. After an update the Frame controller models show from the second
|
||||
launch, because the app unpacks its own files again first.
|
||||
- **From upstream's Quest APK on the Frame.** If your library entry has the same name, `install.sh`
|
||||
points it at the Frame APK. The extracted disc stays, but the old game was built against
|
||||
upstream's kit and will not run. Run `BuildGame` again. The disc import is not needed.
|
||||
- **Newer upstream versions.** This fork is built on upstream v1.3.1. A newer upstream APK has a
|
||||
different kit, and the patches need porting first. `build.sh` stops if the kits do not match.
|
||||
|
||||
## Controls
|
||||
|
||||
`install.sh` installs the binding for the library entry. The game switches to this layout by
|
||||
itself when SteamVR reports the Frame actions as bound. The layout is the same in every camera.
|
||||
|
||||
The Frame's left controller has the D-pad and View button. The right controller has A, B, X, Y
|
||||
and the Menu button.
|
||||
|
||||
| Frame controller | Racing | Game menus |
|
||||
| --- | --- | --- |
|
||||
| Left stick | Steer; navigate menus | Steer after releasing the wheel; navigate menus |
|
||||
| Right trigger | Accelerate | Accelerate |
|
||||
| Left trigger (hold) | Brake, then reverse | Brake, then reverse |
|
||||
| A | Accelerate / confirm | Hop and drift / confirm |
|
||||
| B | Brake / cancel | Brake / cancel |
|
||||
| Y | Use or hold item | Use or hold item |
|
||||
| X | Trick / motorcycle wheelie | Trick / motorcycle wheelie |
|
||||
| Right stick directions | Directional tricks and wheelies | Directional tricks and wheelies |
|
||||
| Left or right grip | Right grip hops/drifts | Grab the wheel or handlebar |
|
||||
| Right stick click | Cycle the three VR cameras | Cycle the three VR cameras |
|
||||
| Left menu/system button | Pause outside SteamVR | Pause outside SteamVR |
|
||||
| X + Y | Open or close VR settings | Open or close VR settings |
|
||||
| Left stick | Steer | Move |
|
||||
| Right trigger | Accelerate | Confirm |
|
||||
| A | Accelerate | Confirm |
|
||||
| B | Brake and reverse | Back |
|
||||
| Left trigger | Brake and reverse (works with accelerate held) | Back |
|
||||
| X | Use item (hold to drag it behind) | |
|
||||
| Left bumper | Use item | |
|
||||
| Y | Look back | |
|
||||
| Right bumper | Hop and drift | |
|
||||
| Grips (either) | Hop and drift. In the first-person cockpit: hold the wheel | |
|
||||
| D-pad | GameCube D-pad. Up does a trick, or a wheelie on a bike | D-pad |
|
||||
| Right stick | Same as the D-pad (push up for a trick) | |
|
||||
| Right stick click | Next camera: original, first person, diorama | |
|
||||
| Menu | Pause (Start) | Start |
|
||||
| View, tap | Back | Back |
|
||||
| View, hold 0.5 s | Open the VR settings panel | Open the VR settings panel |
|
||||
|
||||
On SteamVR, tap X for a trick. Hold X for about 0.65 seconds to send one Mario Kart pause press;
|
||||
the SteamVR system/menu button remains available for the dashboard. X + Y always opens VR settings
|
||||
without forwarding either button to the game. The left trigger always brakes and reverses, including
|
||||
when the wheel is held.
|
||||
Notes:
|
||||
|
||||
In the cockpit, squeeze a grip near the wheel or handlebar to grab it. One or both hands can steer;
|
||||
joining or releasing a hand preserves the current steering target. Releasing both grips returns
|
||||
steering to the left stick. Open **VR settings > Driving** to change native wheel animation,
|
||||
acquisition range, steering response, tracking-loss tolerance, and grab assistance.
|
||||
- The View tap is sent when you let go, so a hold never also goes back.
|
||||
- The right stick click does not change the camera during the race intro. It can be turned off
|
||||
with `first_person_toggle_click = false` under `[vr]` in `Config.toml`.
|
||||
- **Cockpit wheel.** In the first-person camera, reach for the wheel and squeeze a grip to hold
|
||||
it, then turn it to steer. Let go to steer with the stick again. With `hand_steering = false`
|
||||
under `[vr]`, the grips drift in every camera and you always steer with the stick.
|
||||
- **VR settings panel.** Hold View for half a second to open it. Point with a controller. The hand
|
||||
whose trigger you pulled last does the pointing. A trigger or A selects, either stick scrolls,
|
||||
and a press of View closes the panel. While the panel is open the game gets no input.
|
||||
- **Controller models.** The menus show Frame controllers when `install.sh` converted them. The
|
||||
tutorials still name Quest buttons. Use the table above.
|
||||
- To change the layout, use SteamVR's binding UI. The binding is a normal SteamVR binding and shows
|
||||
up under Manage Controller Bindings for the entry.
|
||||
|
||||
## Cameras, HUD, and comfort
|
||||
## Settings
|
||||
|
||||
The first-launch VR panel asks for the default camera with a pointer and trigger. The choice is
|
||||
saved and used at the beginning of every race. Races begin in the selected camera; the original
|
||||
game camera is used for the short race-start launch animation and returns to the selected camera
|
||||
when the animation ends or is skipped.
|
||||
The launch wrapper copies these values into `Config.toml` on the first launch only. The VR
|
||||
settings panel edits the same file. Upstream's README lists all settings under "VR settings".
|
||||
|
||||
The original and diorama cameras show the race HUD, minimap, and item roulette on a panel that can
|
||||
follow the left hand. First person anchors the same HUD in front of the seat. **VR settings >
|
||||
Display** controls panel distance and width; **Camera** controls seat trim and world scale.
|
||||
During a Bullet Bill transformation, the view temporarily switches to the game's original camera
|
||||
so the Bullet Bill model does not block vision; it restores the chosen camera when the item ends.
|
||||
| `Config.toml` | Seed value | What it does |
|
||||
| --- | --- | --- |
|
||||
| `[vr] frame_interpolation_fps` | `1` | Render at the headset's refresh rate (90 Hz), interpolated from the game's 60 fps. |
|
||||
| `[vr] hand_steering` | `true` | Grips hold the wheel in the first-person cockpit. |
|
||||
| `[vr] menu_shader_quality` | `0` | Plain dark menu background. Higher values cost frame rate on the Frame. |
|
||||
| `[vr] render_scale` | `1.0` | Eye render scale. |
|
||||
| `[video] resolution_multiplier` | `1.0` | Game resolution. 1.5 dropped frames on the Frame. |
|
||||
| `[vr] hand_hud` | `false` | Upstream's hand HUD, off. |
|
||||
| `[diagnostics] openxr_logging` | not set (off) | Logs frame timing once a second to `console.log`. Leave it off for play. It caused small hitches. |
|
||||
|
||||
The first-person camera follows the kart in **Safe: large slopes only** mode by default. It ignores small bumps and brief slopes,
|
||||
then gradually follows sustained steep pitch and bank with a limited angle and turning speed.
|
||||
Use **VR settings > Cameras > Follow kart motion in first person** to turn this off or choose another detail level:
|
||||
**Tilt only** follows every track pitch and bank, **Tilt + side-to-side** also moves with the
|
||||
seat's lateral sway, and **All motion** follows the complete vehicle animation, including item
|
||||
hits, banana spins and tricks. Safe and the other comfort modes exclude damage and trick spins.
|
||||
These settings apply immediately and are saved as
|
||||
`first_person_follow_vehicle_motion` and `first_person_motion_level` in `Config.toml`.
|
||||
**Show control tutorials again** resets the first-race and first-person guides.
|
||||
`install.sh` also sets these SteamVR values for the entry: `preferredRefreshRate 90`,
|
||||
`framesToThrottle 0` and `additionalFramesToPredict 0`. They are in the `steam.app.<appid>`
|
||||
section of `~/.config/openvr/config/steamvr.vrsettings`.
|
||||
|
||||
## VR settings
|
||||
Environment variables for the scripts:
|
||||
|
||||
Open VR settings with **X + Y** in the headset or **F10** on the desktop mirror. The menu includes:
|
||||
| Variable | Script | Effect |
|
||||
| --- | --- | --- |
|
||||
| `WCF_FRAME_MODELS=0` | `install.sh` | Keep the Quest controller models. |
|
||||
| `WCF_FRAME_MODEL_TRIANGLES` | `frame-controller-models.py` | Triangle target per hand (default 4000). |
|
||||
| `WCF_SHORTCUT_NAME` | `install.sh` | Library entry name (default `Mario Kart Wii VR`). |
|
||||
| `WCF_STAY_IN_LAUNCHER=1` | `wiicompiled-launch.sh` | Leave the invisible launcher up. Put it before the wrapper in the entry's launch options. |
|
||||
| `WCF_TOOLS` | `build.sh` | Toolchain folder (default `~/.local/opt/android-build`). |
|
||||
| `WCF_SIGNING` | `build.sh` | Signing key folder (default `steam-frame/signing`). |
|
||||
| `WCF_LOG_DIR` | `collect-logs.sh` | Where the log archive goes (default your home folder). |
|
||||
|
||||
- **Graphics:** per-eye resolution, sharp rendering, preferred headset refresh rate, FPS display,
|
||||
adaptive resolution, and menu shader quality (`Off`, `Low`, `Balanced`, `High`).
|
||||
- **Camera and Display:** default camera, first-person head offsets, optional kart motion follow,
|
||||
world scale, HUD width and distance, and seat reset.
|
||||
- **Driving:** native steering-wheel animation, kart and motorcycle steering range, acquisition
|
||||
depth, grab assistance, smoothing, tracking-loss tolerance, and haptics.
|
||||
- **Input:** controller profile diagnostics and stick deadzone calibration.
|
||||
- **Tutorials and Diagnostics:** replay guides and export `VR-diagnostics.txt` beside `Config.toml`.
|
||||
Two Android properties help when testing. Set them over adb before the game starts:
|
||||
`setprop debug.wiicompiled.vr_interp 0|1|72|90|120` overrides the interpolation setting for one
|
||||
launch, and `setprop debug.wiicompiled.fpslog 1` logs the game's frame rate.
|
||||
|
||||
Changes are saved to `Config.toml`. Resolution and some refresh-rate changes take effect after a
|
||||
restart; camera, HUD, steering, shader quality, and diagnostic options apply immediately.
|
||||
## Known problems
|
||||
|
||||
## WheelWizard and Retro Rewind
|
||||
|
||||
WheelWizard is bundled as the launch and mod-selection front end. It has two local VR entries:
|
||||
|
||||
- **Mario Kart Wii VR**, using the base compiled game;
|
||||
- **Retro Rewind VR**, using the separate Retro Rewind static profile.
|
||||
|
||||
The VR integration pins and patches Wheel Wizard to keep its local recompilation paths connected to
|
||||
the correct game data and saves. Its pack updater and mod preparation work with this installation;
|
||||
runtime upgrades can require the original PAL image configured in settings. Retro Rewind is optional
|
||||
during setup and needs its own local compilation from the same clean PAL image. Online rooms and
|
||||
races still depend on Retro WFC service availability, compatible game versions and end to end testing.
|
||||
- **The empty item box stays on screen** after the roulette slides up. Change 5 does not fix it.
|
||||
- **Grip steering in the cockpit is rough.** Grabbing and steering work, but upstream tuned the
|
||||
grab range and steering response for Quest controllers. They have not been adjusted. Set
|
||||
`hand_steering = false` to steer with the stick.
|
||||
- **Small hitches.** Races hold 90 fps on the counter, with brief hitches now and then. The logs
|
||||
do not show a cause yet.
|
||||
- **The 2D launcher is invisible** in the headset, so the disc import and build use the terminal
|
||||
commands above. Upstream's "Select disc image" button needs a file picker Lepton does not have.
|
||||
- **`v1.3.1-frame.1` does not work.** Its game build fails at the final link on the headset. Use
|
||||
`v1.3.1-frame.2` or newer.
|
||||
- **Not tested:** Retro Rewind, online play, the diorama camera for more than a minute, USB wheels,
|
||||
multiplayer, passthrough, hand tracking, Lepton 3.x.
|
||||
- **Not for Quest.** Use upstream's APK on a Quest. The interpolation change is what upstream
|
||||
turned off on Quest, and the Frame layout only works with the SteamVR binding.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **The headset stays on the desktop mirror:** connect the headset, check your active
|
||||
OpenXR runtime, and restart the game. `required = false` falls back to desktop mode when OpenXR
|
||||
cannot create a session.
|
||||
- **The game is not visible in WheelWizard:** run the copied setup from the installation folder,
|
||||
select the clean PAL `RMCP01` image, and let the local compilation finish.
|
||||
- **The wheel is difficult to grab:** use **VR settings > Driving** to increase acquisition depth
|
||||
and grab assistance, then reset the seat position. Both grips can be used independently.
|
||||
- **Tracking or performance problems:** lower eye resolution or menu shader quality, disable
|
||||
adaptive resolution if frame pacing is unstable, and export `VR-diagnostics.txt`.
|
||||
- **Logs:** the runtime writes OpenXR and compilation diagnostics under
|
||||
`%LOCALAPPDATA%\\WiiCompiled\\Logs` (or `UserData\\Logs` in a portable installation).
|
||||
- **`install.sh` says Steam's debugging port is not reachable.** Steam must be running. The script
|
||||
talks to Steam on `127.0.0.1:8080`, which SteamOS enables by default.
|
||||
- **The launch shows only SteamVR's empty space.** No game is built yet, or the built game is for
|
||||
another kit. `/tmp/wiicompiled-launch.log` says which. Run the `BuildGame` command.
|
||||
- **The disc is rejected.** The importer accepts only a clean PAL `RMCP01` image.
|
||||
- **The game build fails at the last step with `undefined symbol: std::__ndk1::__hash_memory`.**
|
||||
You have the `v1.3.1-frame.1` APK. Install `v1.3.1-frame.2` or newer and build again.
|
||||
- **The buttons act like a Quest layout** (A does several things, X and Y do nothing). The SteamVR
|
||||
binding is not applied. Run `install.sh` again, then check Manage Controller Bindings for the
|
||||
entry. The game's `console.log` has the line `Steam Frame button layout active` when the Frame
|
||||
layout is on.
|
||||
- **The menus show Quest controllers.** Launch once more after an update. If they still show,
|
||||
run `install.sh` again and look for a warning about the controller models.
|
||||
- **The menus or races stutter.** Check `Config.toml` for `menu_shader_quality = 0`,
|
||||
`resolution_multiplier = 1.0` and `openxr_logging` off. Higher resolution settings dropped
|
||||
frames on the Frame.
|
||||
- **Settings are not saved after you copied `Config.toml` in by hand.** Run
|
||||
`chmod 664 Config.toml` on it. The app cannot write it otherwise.
|
||||
- **Anything else.** Collect the logs (next section) and look at `console.log` and `lepton.log`.
|
||||
|
||||
## Building from source
|
||||
## Logs and reporting a problem
|
||||
|
||||
For Windows, building requires .NET 8, CMake, Ninja, LLVM-MinGW, and a clean PAL `RMCP01` image.
|
||||
The Windows release uses D3D12 and OpenXR. The main build scripts are:
|
||||
| Log | Where |
|
||||
| --- | --- |
|
||||
| Launch wrapper | `/tmp/wiicompiled-launch.log` |
|
||||
| Lepton | `~/.local/share/Steam/logs/lepton-steamlaunch-<appid>.log` |
|
||||
| Game, one folder per run | `.../WiiCompiledOpenXRVR/Logs/<run>/console.log` |
|
||||
| Disc import and build | `.../WiiCompiledOpenXRVR/Logs/build_*.log` |
|
||||
|
||||
```powershell
|
||||
dotnet build translator/Translator.sln -c Release
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-Installer.ps1
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-WheelWizard.ps1
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-Portable.ps1 `
|
||||
-SetupPath Launcher/dist/WiiCompiled-Setup.exe -Name WiiCompiled-VR-Portable
|
||||
`...` is `~/.local/share/Steam/steamapps/compatdata/<appid>/external/Android/data/org.wiicompiled.quest/files`.
|
||||
|
||||
To report a problem:
|
||||
|
||||
1. Run `steam-frame/collect-logs.sh` (or `steam-frame/collect-logs.sh <appid>`). It writes
|
||||
`~/wiicompiled-frame-logs-<date>.tar.gz` with the logs above, your `Config.toml` and a short
|
||||
summary (SteamOS, Lepton, APK and kit versions). It masks IP and MAC addresses, UUIDs, host
|
||||
names, Wi-Fi names, serial numbers, Steam IDs, email addresses, tokens and certificate blocks.
|
||||
Lepton's log includes the Frame's kernel log, which lists hardware serial numbers. Read the
|
||||
files before you post them. The masking can miss things.
|
||||
2. Open an issue on this repository. Give the release tag, what you did, what happened and what
|
||||
you expected, and attach the archive.
|
||||
3. If the problem also happens with upstream's APK on a Quest, report it upstream instead.
|
||||
|
||||
Pull requests are welcome. Say what you tested and on which headset. Upstream's
|
||||
[CONTRIBUTING.md](CONTRIBUTING.md) rules apply. Never attach game files or disc images.
|
||||
|
||||
## Building the APK yourself
|
||||
|
||||
```sh
|
||||
steam-frame/build.sh # downloads upstream's v1.3.1 APK and checks its SHA-256
|
||||
steam-frame/build.sh path/to/WiiCompiled-VR-Quest3-v1.3.1.apk
|
||||
```
|
||||
|
||||
Quest builds use a separate Android toolchain and `android/Build-Quest.ps1`; see [the Android build guide](android/README.md). Building either target compiles game code locally from your disc. It does not add the game to Git or a release archive.
|
||||
The output is `steam-frame/release/WiiCompiled-VR-SteamFrame-<git tag>.apk`. On the Frame this
|
||||
takes about 20 seconds once the toolchain is downloaded. It needs `curl`, `tar`, `python3` and
|
||||
`openssl`, which SteamOS has. It needs no root.
|
||||
|
||||
The build boundary deliberately excludes translated game code and game data from Git and releases.
|
||||
See [OPENXR.md](OPENXR.md) for the implementation details, configuration keys, controller profiles,
|
||||
and validation notes.
|
||||
1. It downloads Android NDK r29 into `~/.local/opt/android-build/`. Google ships no arm64 Linux
|
||||
NDK, so on the Frame it uses [HomuHomu833's r29 build](https://github.com/HomuHomu833/android-ndk-custom).
|
||||
On x86_64 it uses Google's r29, which is untested. The NDK must be r29, the version the kit
|
||||
was built with. Objects built with r30 fail the final link on the headset.
|
||||
2. It compiles the two runtime unity groups that hold the patched files, and Aurora's
|
||||
`common.cpp`, with upstream's Android flags. The third-party headers they need are in
|
||||
[`steam-frame/build-deps/`](steam-frame/build-deps/) (see its `NOTICE.md`).
|
||||
3. It compares each new object with the original in the upstream kit. The exported symbols must
|
||||
match, and the new object may not import a C++ symbol the original does not. Otherwise it stops.
|
||||
4. [`make-apk.py`](steam-frame/make-apk.py) writes the APK: the four kit files, the new kit
|
||||
fingerprint in `kit.json`, the patched `classes.dex`, zip alignment and an APK Signature
|
||||
Scheme v2 signature made with `openssl`. No Java, apksigner or zipalign is needed.
|
||||
|
||||
## Credits
|
||||
The signing key is created in `steam-frame/signing/` on first use. Keep it. An APK signed with
|
||||
another key will not install over the previous one. `steam-frame/signing/` is ignored by git, so
|
||||
the key never ends up in the repository. `make-apk.py verify file.apk` checks an APK's signature.
|
||||
|
||||
- **[WebXR Input Profiles](https://github.com/immersive-web/webxr-input-profiles)** for the
|
||||
textured Touch Plus controller meshes and button animation transforms used by the Quest
|
||||
standalone version and desktop fallback. SteamVR's device models take priority when available.
|
||||
See [asset provenance and MIT license](runtime/assets/quest_touch_plus/SOURCE.md).
|
||||
- **[Wiicompiled VR](https://github.com/iChris4/Wiicompiled_VR)** by **[iChris4](https://github.com/iChris4)**:
|
||||
This project originated as a fork of iChris4's pioneering OpenXR VR port of WiiCompiled.
|
||||
The core OpenXR integration, stereo rendering pipeline, and initial VR translation hooks
|
||||
were built by iChris4.
|
||||
iChris4 also contributed the native steering-wheel detection fixes integrated in v1.3:
|
||||
[wheel topology handling](https://github.com/iChris4/Wiicompiled_VR/commit/3d48514182f3c055b9614d752edf0896ba190f16)
|
||||
and [node matrix retrieval and topology validation](https://github.com/iChris4/Wiicompiled_VR/commit/f013f9d2f7682802bff576c9c047af49b1fb5ea6).
|
||||
- **[WheelWizard](https://github.com/TeamWheelWizard/WheelWizard)** by Team WheelWizard, integrated
|
||||
as the local launcher and Retro Rewind front end.
|
||||
- **[BigWalkVRInstaller](https://github.com/CircuitLord/BigWalkVRInstaller)** by CircuitLord, whose
|
||||
controller tutorial presentation inspired the attached callouts and pointer flow.
|
||||
- **[@XorDev](https://x.com/XorDev)** for the **Dielectric** shader used as the animated spatial
|
||||
background around the VR menus. This port adapts the shader from the
|
||||
[FragCoord.xyz reference](https://t.co/kdebpbDcaQ) for stereo, translated rendering and exposes
|
||||
quality levels in VR settings. See the [attribution note](licenses/Dielectric-menu-background.md).
|
||||
- **[aurora](https://github.com/encounter/aurora)** for the native GameCube/Wii graphics and windowing
|
||||
layer used by the port.
|
||||
- **[OpenXR](https://www.khronos.org/openxr/)**, **Dawn**, **Dolphin Emulator**, **Pulsar**,
|
||||
**[AnimalCrossing-VR-MR-Standalone](https://github.com/heurazy/AnimalCrossing-VR-MR-Standalone)**,
|
||||
and **[Cyberpunk VR port](https://github.com/dariulone/cyberpunk-vr-port)** for APIs, references,
|
||||
and implementation ideas used during development.
|
||||
The game itself (`libmain.so`) is never built here. The headset builds it from your disc.
|
||||
|
||||
Bundled component licenses are listed in [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md). The
|
||||
controller tutorial notice is in [licenses/BigWalkVR-MIT.txt](licenses/BigWalkVR-MIT.txt).
|
||||
## Where things are
|
||||
|
||||
## License and legal notice
|
||||
- **Library entry:** a non-Steam shortcut whose executable is the APK and whose compatibility tool
|
||||
is `lepton`. Its launch options run `~/Games/WiiCompiledVR-SteamFrame/wiicompiled-launch.sh`.
|
||||
The empty file `lepton-show-flatscreen` next to the APK lets Lepton show the 2D window.
|
||||
- **App data:** `~/.local/share/Steam/steamapps/compatdata/<appid>/`.
|
||||
`external/Android/data/org.wiicompiled.quest/files/WiiCompiledOpenXRVR/` holds `Config.toml`,
|
||||
`DATA` (the extracted disc), saves and `Logs/`.
|
||||
`internal/org.wiicompiled.quest/files/game/base/` holds the built `libmain.so` and `game.json`.
|
||||
- **SteamVR settings:** the `steam.app.<appid>` section of
|
||||
`~/.config/openvr/config/steamvr.vrsettings`. While SteamVR runs, the installer writes them with
|
||||
`/opt/steamvr/bin/linuxarm64/vrcmd --set-settings-int`.
|
||||
- **Shared folders:** Lepton's Android sees `~/Documents`, `~/Downloads` and `~/Videos` as
|
||||
`/sdcard/Documents`, `/sdcard/Download` and `/sdcard/Movies`.
|
||||
- **Shell access:** `lepton exec steamlaunch-<appid> <command>` runs a command in the running
|
||||
container. `adb connect localhost:5555` reaches it too.
|
||||
|
||||
The WiiCompiled source in this repository is licensed under the
|
||||
[GNU General Public License v3](LICENSE). Mario Kart Wii is a trademark of Nintendo. This project
|
||||
is not affiliated with or endorsed by Nintendo and does not contain Nintendo intellectual property.
|
||||
Dump and use your own game disc according to the laws that apply where you live.
|
||||
## How this was made
|
||||
|
||||
The work took about a week in October 2026, in Claude Code sessions on the Frame. I tested each
|
||||
build in the headset and described what I saw. The AI read the logs and the code and made the
|
||||
changes.
|
||||
|
||||
- The first attempt used upstream's v1.3 Quest APK. The clipboard crash showed in logcat and was
|
||||
patched. The game ran, but it flickered and the head tracking was shaky.
|
||||
- Upstream's Windows build under Proton and a native Linux ARM64 build were also tried. The Proton
|
||||
build was too slow under x86 emulation. Both were dropped. This fork is the Android path only.
|
||||
- Turning interpolation back on, with the clock fallback, fixed most of the flicker and judder.
|
||||
The controller layout, the menu change and the item box attempt followed.
|
||||
- The first release was built with NDK r30 and failed to link on the headset. `build.sh` now uses
|
||||
r29 and checks the C++ imports of each object.
|
||||
- A higher resolution for sharper menus caused dropped frames and was rolled back.
|
||||
- After the first releases came the grips change and the Frame controller models. The full
|
||||
models slowed the menus to 45 to 60 fps. With the mesh simplifier the menus hold 90 Hz.
|
||||
|
||||
## Licence and credits
|
||||
|
||||
GPL-3.0, as upstream ([LICENSE](LICENSE)). The fork's additions use the same licence.
|
||||
Third-party headers used for the build are listed with their licences in
|
||||
[`steam-frame/build-deps/NOTICE.md`](steam-frame/build-deps/NOTICE.md). The rest of the
|
||||
third-party code is listed in [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md).
|
||||
|
||||
- The VR port is [heurazy's Wiicompiled VR PLUS](https://github.com/heurazy/Wiicompiled_VR-PLUS),
|
||||
built on [iChris4's Wiicompiled VR](https://github.com/iChris4/Wiicompiled_VR) and the
|
||||
WiiCompiled static recompilation project. It uses
|
||||
[Aurora](https://github.com/encounter/aurora), Dawn, SDL3 and OpenXR. The full credits are in
|
||||
[README.upstream.md](README.upstream.md).
|
||||
- The Android NDK build for arm64 Linux is
|
||||
[HomuHomu833's](https://github.com/HomuHomu833/android-ndk-custom).
|
||||
- Lepton, SteamVR and the Frame controller models are Valve's. The models are read from your own
|
||||
SteamVR install and are not redistributed.
|
||||
- Mario Kart Wii is Nintendo's. Nothing of Nintendo's is in this repository or in the APK. You
|
||||
need your own disc.
|
||||
- Steam Frame port by simplysanatori, written with Claude Code as described above.
|
||||
|
||||
## Support
|
||||
|
||||
If you would like more Steam Frame ports, you can [buy me a coffee](https://ko-fi.com/sana748653). It pays for the Claude API credits these ports are built with, spent as carefully as I can. The credit for the games themselves belongs to the upstream projects named above.
|
||||
@@ -0,0 +1,311 @@
|
||||
# Mario Kart Wii VR Port — Wiicompiled VR PLUS
|
||||
|
||||
This is the **Wiicompiled VR PLUS** fork of [iChris4/Wiicompiled_VR](https://github.com/iChris4/Wiicompiled_VR). It combines that OpenXR port with the VR gameplay, controller, launcher and packaging work from [heurazy/mario-kart-wii-VR-port](https://github.com/heurazy/mario-kart-wii-VR-port), then adds a standalone Android build for Quest.
|
||||
|
||||
On Windows, the game is statically recompiled to native x86-64 and rendered through OpenXR. On Quest standalone, the ARM64 build runs locally with Vulkan and OpenXR. Neither version runs the game through a Wii emulator, interpreter or JIT.
|
||||
|
||||
This repository contains source code, build tools and integration patches. It does **not** contain Nintendo game code, a translated game executable, a ROM or Retro Rewind's game files. You must provide your own clean PAL `RMCP01` disc image and build the game on your own device.
|
||||
|
||||
[Browse Wiicompiled VR PLUS](https://github.com/heurazy/Wiicompiled_VR-PLUS) · [Release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases) · [Original Mario Kart Wii VR port](https://github.com/heurazy/mario-kart-wii-VR-port)
|
||||
|
||||
> Download the Windows installer, portable launcher bundle or Quest APK from this fork's [latest release](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases/latest).
|
||||
|
||||
## What this fork adds
|
||||
|
||||
Compared with the original Mario Kart Wii VR port, this fork brings together the earlier port's user facing improvements, imports additional OpenXR features from iChris4's branch, and adds the Quest standalone target.
|
||||
|
||||
|
||||
- **Quest Touch Plus controllers:** textured controller models, animated buttons and thumbsticks, pointer interaction in menus and controller specific tutorial diagrams.
|
||||
- **Comfortable driving cameras:** original, first person and diorama views. First person hides the driver's head and adjusts for different character heights. A right stick click changes view. Optional kart movement modes include a smoothed Safe mode that follows sustained slopes and banks.
|
||||
- **Physical driving controls:** tracked hands can grip and turn the kart wheel or motorcycle handlebars. Steering supports one or two hands, passing through the centre, continuous full turns and brief tracking loss. Native vehicle steering animation can be switched off. USB wheels, pedals and paddle buttons can be calibrated; feedback is optional and light.
|
||||
- **Character body IK:** in the first-person cockpit, your selected character's own textured body and hands replace the VR gloves. Shoulders, elbows and wrists follow the tracked controllers; the torso stays stable while legs retain driving and drift movements. Trick and boost celebrations are suppressed. The head is hidden, and arm reach fits human proportions. Toggle **Character body IK** in **VR settings → Cameras**. Hand placement uses fixed built-in calibration profiles for the 24 original characters. See [body IK behavior and current limits](docs/BODY-IK.md).
|
||||
- **Spatial VR UI:** the camera chooser, VR settings, controller tutorials and supported Mario Kart menus sit in VR space and can be selected with a pointer. The first launch explains camera choice and controls; tutorials can be reset in settings.
|
||||
- **VR HUD and visibility fixes:** the circuit map and item panel appear on the left hand, while first person anchors its HUD ahead of the seat. Hand depth, track object culling, race menu rendering, display orientation and the Bullet Bill camera have dedicated VR handling.
|
||||
- **Performance controls:** per eye resolution, sharpening, refresh preference, adaptive resolution, diagnostics and menu shader quality. Frame interpolation is disabled on Quest because it makes the standalone presentation unstable; the game's simulation speed remains unchanged.
|
||||
- **Controller compatibility:** OpenXR action bindings and profiles for Quest, Valve Index, Vive, Windows Mixed Reality and PICO. Stick calibration, headset button shortcuts and the original port's exact controls are documented below.
|
||||
|
||||
|
||||
The project retains upstream WiiCompiled/OpenXR features as well. The sections below explain the Windows setup, controls, VR settings and build process; the Quest setup is documented separately.
|
||||
|
||||
## OpenXR integration
|
||||
|
||||
The fusion now includes the original controls and SteamVR shortcuts, Index/Vive/WMR/PICO
|
||||
profiles, stick calibration, opt-in adaptive resolution, the legacy Bluetooth scan fix,
|
||||
license renaming without a NAND Mii, and full Wheel Wizard + portable packaging.
|
||||
See [controls and packaging](docs/PORT-CONTROLS-AND-PACKAGING.md) for exact bindings,
|
||||
upgrade behavior and the remaining hardware validation.
|
||||
|
||||
## Roadmap
|
||||
- better motorcycle controls : planned
|
||||
- more vehicles visual steering wheel compatibility : planned
|
||||
- more control options : planned
|
||||
- throwing shells and other items option : planned
|
||||
<details>
|
||||
<summary><h2>DONE</h2></summary>
|
||||
|
||||
- new hand models: selected character's textured hands and body IK, with built-in hand placement profiles
|
||||
- fix character height: cockpit height and steering reach adapt to the selected character
|
||||
- automatic correction of upside-down race output: included in v1.1; feedback from affected headsets welcome
|
||||
- sim racing steering wheels and pedals: included in v1.1; hardware compatibility testing continues
|
||||
- fix low FPS in menu: menus can render above 60 FPS without accelerating the game
|
||||
- fix black hand in front of HUD: corrected hand/HUD depth
|
||||
- VR course object culling based on the player's view rather than the kart's direction: implemented in source; track validation continues
|
||||
- fix Bullet Bill gate vision: temporarily use the original game camera during Bullet Bill
|
||||
- option to move with the kart: configurable movement modes, including the smoothed Safe mode
|
||||
- multiplayer: local-player cockpit and launcher/save fixes included in v1.1; online testing depends on Retro WFC availability
|
||||
- periodic controller-search freezes: legacy Wii Remote scanning is disabled on upgrade in v1.1.1; USB wheel discovery now follows hotplug events
|
||||
|
||||
</details>
|
||||
|
||||
## VR feature details
|
||||
|
||||
- Native OpenXR rendering through D3D12 with a desktop mirror and a safe desktop fallback.
|
||||
- Three race cameras: the original game camera, a true first-person cockpit camera, and a distant
|
||||
diorama camera. The right-stick click cycles cameras during a race.
|
||||
- A seated cockpit aligned to the driver's evaluated eye position. Character body IK shows the
|
||||
tracked body and hands with the head hidden; the view adapts to small, tall, and temporarily resized characters.
|
||||
- Physical steering: grab the real kart wheel or motorcycle handlebar with either tracked hand.
|
||||
Native vehicle animation is enabled by default and can be disabled in VR settings.
|
||||
- Two-hand steering with centre-crossing and brief tracking-loss tolerance, adaptive smoothing,
|
||||
full-turn hand continuity, and a left-stick fallback after both hands release the control.
|
||||
- Tracked hands depth-tested against the kart and the track, with SteamVR controller models and
|
||||
per-controller button animations in the VR tutorials and menus.
|
||||
- A left-hand race HUD with the circuit map and item panel. In first person, the HUD is anchored in
|
||||
front of the seat so it stays readable while the head moves.
|
||||
- An anchored, spatial VR presentation for the camera chooser, VR settings, controller guides, and
|
||||
Mario Kart menus. The first launch offers a camera choice through a VR pointer.
|
||||
- A first-race controller tutorial, plus a separate first-person tutorial. Both can be reset from
|
||||
VR settings.
|
||||
- Configurable eye resolution, sharpness, refresh-rate preference, adaptive resolution, world scale,
|
||||
HUD placement, camera trim, steering response, grab assistance, deadzone, haptics, and diagnostics.
|
||||
- Retro Rewind VR support through WheelWizard, with pack updates, patch preparation,
|
||||
compiled-product repair, and access to the VR installation's saves, friends and Miis.
|
||||
See [WheelWizard feature coverage](docs/WHEELWIZARD-VR.md) for the local integration
|
||||
and its limits.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Windows 10 or 11, 64-bit.
|
||||
- An installed, active OpenXR runtime with the headset connected. The game uses your active runtime
|
||||
by default, including SteamVR or Virtual Desktop's VDXR. F10 → Use SteamVR (next launch)
|
||||
can explicitly select SteamVR for the game without changing the system's active runtime.
|
||||
- A D3D12-capable GPU and a driver accepted by your OpenXR runtime and Dawn. GTX 1650 / RX 6400 /
|
||||
Arc A310 or better is a practical starting point.
|
||||
- About 20 GB free while installing and compiling. The compiled game is about 5 GB, excluding
|
||||
optional Retro Rewind files.
|
||||
- Your own clean, unmodified PAL `RMCP01` disc image. ISO, GCM, GCZ, CISO, WBFS, WIA, and RVZ are
|
||||
accepted. Other regions and modified executables are rejected.
|
||||
|
||||
## Installation
|
||||
|
||||
### Guided installer
|
||||
|
||||
1. Download the Windows setup asset from this fork's [release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases).
|
||||
2. Connect your headset through your OpenXR runtime, then run the installer.
|
||||
3. Select your clean PAL `RMCP01` image and choose an installation folder.
|
||||
4. Leave **Download and install Retro Rewind automatically** enabled if you want both games.
|
||||
5. Select **Install**. The setup translates and compiles the game on this PC; the image never leaves
|
||||
the computer.
|
||||
|
||||
The installer installs WheelWizard in the `WheelWizard` subfolder, creates a **Mario Kart Wii VR
|
||||
Launcher** shortcut on the desktop and in the Start Menu, and opens the launcher when installation
|
||||
finishes. Select **Mario Kart Wii VR** or **Retro Rewind VR** from that launcher.
|
||||
|
||||
### Portable bundle
|
||||
|
||||
Download this fork's portable archive from its [release page](https://github.com/heurazy/Wiicompiled_VR-PLUS/releases). Extract the complete folder and run
|
||||
`WiiCompiled-Setup.exe`. Keep **portable installation** enabled and keep the folder together.
|
||||
Start the launcher with `Launch-WiiCompiled-VR.cmd` or `WheelWizard/WheelWizard.exe`. The
|
||||
`UserData` folder keeps configuration, NAND, cache and logs beside the portable installation.
|
||||
Keep the whole folder when moving or updating it so saves and compiled games remain available.
|
||||
|
||||
No release contains a ROM or a translated game executable. Compilation is intentionally performed
|
||||
locally from the disc image you select.
|
||||
|
||||
### Quest standalone
|
||||
|
||||
Quest standalone is a separate Android build; the Windows setup and portable archive do not install it. The current preview targets ARM64 and has been tested on Quest 3. For a local build, APK installation, game import and Retro Rewind setup, follow [the Quest 3 preview guide](docs/quest3-preview.md) and [Android build guide](android/README.md). The APK does not bundle your ROM or translated game. Import a `.wcgame` compiled from your own PAL image and keep your game data on the headset. After setup, the game runs without a PC or SteamVR.
|
||||
|
||||
The current stock Dawn APK does not include fragment density map foveation. See the preview guide for the source build option and exact SDK/toolchain requirements.
|
||||
|
||||
Frame interpolation is deliberately unavailable on Quest: the runtime forces it off even if an old config requests it, and the Quest settings omit the control. The game's 60 Hz simulation speed remains unchanged while the headset tracks head motion at its selected refresh rate. This Quest only setting does not change Windows interpolation options.
|
||||
|
||||
## USB steering wheels and pedals
|
||||
|
||||
Open **VR settings > Hardware wheel** (also available in desktop controller settings).
|
||||
Select the steering device and axis; record full left, full right and center. Select each
|
||||
pedal's device and axis, then record its released and fully pressed positions. Separate USB
|
||||
pedals, inverted axes and combined pedal axes are supported through SDL's raw joystick input;
|
||||
the device does not need an Xbox/gamepad mapping. For a combined axis, select the same axis for
|
||||
both pedals and record their opposite pressed positions.
|
||||
|
||||
Assign the **right paddle to drift** and **left paddle to items**, then enable the physical wheel.
|
||||
Paddle numbers vary by driver, so these assignments require pressing each paddle during setup.
|
||||
Optional hardware buttons provide tricks/wheelies, confirm and pause. The brake pedal brakes,
|
||||
then reverses, in every race camera. It takes priority over acceleration and drift. Mario Kart's
|
||||
acceleration remains a digital game action, even with an analog pedal. VR controllers remain
|
||||
available for menu navigation, camera selection, pause and item aiming. The visible cockpit wheel
|
||||
follows hardware steering. Configuration is saved beside the active config in `PhysicalWheel.toml`.
|
||||
|
||||
Feedback is **off by default**. Optional light vibration follows the game's original rumble
|
||||
events, including curbs only where the game emits rumble. Effects are short and strength is
|
||||
capped at 15%; no constant torque, spring or centering effect is requested. Rumble support depends
|
||||
on the driver; lack of rumble does not prevent driving. This is not simulated tire-force feedback.
|
||||
An incomplete/disconnected setup gives neutral race input. Close options and release held buttons
|
||||
and pedals before driving. Hardware/driver compatibility needs testing; no universal device support
|
||||
is claimed.
|
||||
|
||||
## Quest and OpenXR controls
|
||||
|
||||
The runtime uses standard OpenXR actions, so Quest 2, Quest 3, Touch Pro, Valve Index, PICO, Vive,
|
||||
Windows Mixed Reality, Samsung Odyssey, and other advertised profiles use the same in-game actions.
|
||||
Vive trackpads substitute for thumbsticks where necessary. The left menu/system button keeps its
|
||||
headset function; on SteamVR it opens the SteamVR dashboard.
|
||||
|
||||
| Controller input | Original / diorama camera | First-person cockpit |
|
||||
| --- | --- | --- |
|
||||
| Left stick | Steer; navigate menus | Steer after releasing the wheel; navigate menus |
|
||||
| Right trigger | Accelerate | Accelerate |
|
||||
| Left trigger (hold) | Brake, then reverse | Brake, then reverse |
|
||||
| A | Accelerate / confirm | Hop and drift / confirm |
|
||||
| B | Brake / cancel | Brake / cancel |
|
||||
| Y | Use or hold item | Use or hold item |
|
||||
| X | Trick / motorcycle wheelie | Trick / motorcycle wheelie |
|
||||
| Right stick directions | Directional tricks and wheelies | Directional tricks and wheelies |
|
||||
| Left or right grip | Right grip hops/drifts | Grab the wheel or handlebar |
|
||||
| Right stick click | Cycle the three VR cameras | Cycle the three VR cameras |
|
||||
| Left menu/system button | Pause outside SteamVR | Pause outside SteamVR |
|
||||
| X + Y | Open or close VR settings | Open or close VR settings |
|
||||
|
||||
On SteamVR, tap X for a trick. Hold X for about 0.65 seconds to send one Mario Kart pause press;
|
||||
the SteamVR system/menu button remains available for the dashboard. X + Y always opens VR settings
|
||||
without forwarding either button to the game. The left trigger always brakes and reverses, including
|
||||
when the wheel is held.
|
||||
|
||||
In the cockpit, squeeze a grip near the wheel or handlebar to grab it. One or both hands can steer;
|
||||
joining or releasing a hand preserves the current steering target. Releasing both grips returns
|
||||
steering to the left stick. Open **VR settings > Driving** to change native wheel animation,
|
||||
acquisition range, steering response, tracking-loss tolerance, and grab assistance.
|
||||
|
||||
## Cameras, HUD, and comfort
|
||||
|
||||
The first-launch VR panel asks for the default camera with a pointer and trigger. The choice is
|
||||
saved and used at the beginning of every race. Races begin in the selected camera; the original
|
||||
game camera is used for the short race-start launch animation and returns to the selected camera
|
||||
when the animation ends or is skipped.
|
||||
|
||||
The original and diorama cameras show the race HUD, minimap, and item roulette on a panel that can
|
||||
follow the left hand. First person anchors the same HUD in front of the seat. **VR settings >
|
||||
Display** controls panel distance and width; **Camera** controls seat trim and world scale.
|
||||
During a Bullet Bill transformation, the view temporarily switches to the game's original camera
|
||||
so the Bullet Bill model does not block vision; it restores the chosen camera when the item ends.
|
||||
|
||||
The first-person camera follows the kart in **Safe: large slopes only** mode by default. It ignores small bumps and brief slopes,
|
||||
then gradually follows sustained steep pitch and bank with a limited angle and turning speed.
|
||||
Use **VR settings > Cameras > Follow kart motion in first person** to turn this off or choose another detail level:
|
||||
**Tilt only** follows every track pitch and bank, **Tilt + side-to-side** also moves with the
|
||||
seat's lateral sway, and **All motion** follows the complete vehicle animation, including item
|
||||
hits, banana spins and tricks. Safe and the other comfort modes exclude damage and trick spins.
|
||||
These settings apply immediately and are saved as
|
||||
`first_person_follow_vehicle_motion` and `first_person_motion_level` in `Config.toml`.
|
||||
**Show control tutorials again** resets the first-race and first-person guides.
|
||||
|
||||
## VR settings
|
||||
|
||||
Open VR settings with **X + Y** in the headset or **F10** on the desktop mirror. The menu includes:
|
||||
|
||||
- **Graphics:** per-eye resolution, sharp rendering, preferred headset refresh rate, FPS display,
|
||||
adaptive resolution, and menu shader quality (`Off`, `Low`, `Balanced`, `High`).
|
||||
- **Camera and Display:** default camera, first-person head offsets, optional kart motion follow,
|
||||
world scale, HUD width and distance, and seat reset.
|
||||
- **Driving:** native steering-wheel animation, kart and motorcycle steering range, acquisition
|
||||
depth, grab assistance, smoothing, tracking-loss tolerance, and haptics.
|
||||
- **Input:** controller profile diagnostics and stick deadzone calibration.
|
||||
- **Tutorials and Diagnostics:** replay guides and export `VR-diagnostics.txt` beside `Config.toml`.
|
||||
|
||||
Changes are saved to `Config.toml`. Resolution and some refresh-rate changes take effect after a
|
||||
restart; camera, HUD, steering, shader quality, and diagnostic options apply immediately.
|
||||
|
||||
## WheelWizard and Retro Rewind
|
||||
|
||||
WheelWizard is bundled as the launch and mod-selection front end. It has two local VR entries:
|
||||
|
||||
- **Mario Kart Wii VR**, using the base compiled game;
|
||||
- **Retro Rewind VR**, using the separate Retro Rewind static profile.
|
||||
|
||||
The VR integration pins and patches Wheel Wizard to keep its local recompilation paths connected to
|
||||
the correct game data and saves. Its pack updater and mod preparation work with this installation;
|
||||
runtime upgrades can require the original PAL image configured in settings. Retro Rewind is optional
|
||||
during setup and needs its own local compilation from the same clean PAL image. Online rooms and
|
||||
races still depend on Retro WFC service availability, compatible game versions and end to end testing.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
- **The headset stays on the desktop mirror:** connect the headset, check your active
|
||||
OpenXR runtime, and restart the game. `required = false` falls back to desktop mode when OpenXR
|
||||
cannot create a session.
|
||||
- **The game is not visible in WheelWizard:** run the copied setup from the installation folder,
|
||||
select the clean PAL `RMCP01` image, and let the local compilation finish.
|
||||
- **The wheel is difficult to grab:** use **VR settings > Driving** to increase acquisition depth
|
||||
and grab assistance, then reset the seat position. Both grips can be used independently.
|
||||
- **Tracking or performance problems:** lower eye resolution or menu shader quality, disable
|
||||
adaptive resolution if frame pacing is unstable, and export `VR-diagnostics.txt`.
|
||||
- **Logs:** the runtime writes OpenXR and compilation diagnostics under
|
||||
`%LOCALAPPDATA%\\WiiCompiled\\Logs` (or `UserData\\Logs` in a portable installation).
|
||||
|
||||
## Building from source
|
||||
|
||||
For Windows, building requires .NET 8, CMake, Ninja, LLVM-MinGW, and a clean PAL `RMCP01` image.
|
||||
The Windows release uses D3D12 and OpenXR. The main build scripts are:
|
||||
|
||||
```powershell
|
||||
dotnet build translator/Translator.sln -c Release
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-Installer.ps1
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-WheelWizard.ps1
|
||||
powershell -ExecutionPolicy Bypass -File Launcher/Build-Portable.ps1 `
|
||||
-SetupPath Launcher/dist/WiiCompiled-Setup.exe -Name WiiCompiled-VR-Portable
|
||||
```
|
||||
|
||||
Quest builds use a separate Android toolchain and `android/Build-Quest.ps1`; see [the Android build guide](android/README.md). Building either target compiles game code locally from your disc. It does not add the game to Git or a release archive.
|
||||
|
||||
The build boundary deliberately excludes translated game code and game data from Git and releases.
|
||||
See [OPENXR.md](OPENXR.md) for the implementation details, configuration keys, controller profiles,
|
||||
and validation notes.
|
||||
|
||||
## Credits
|
||||
|
||||
- **[WebXR Input Profiles](https://github.com/immersive-web/webxr-input-profiles)** for the
|
||||
textured Touch Plus controller meshes and button animation transforms used by the Quest
|
||||
standalone version and desktop fallback. SteamVR's device models take priority when available.
|
||||
See [asset provenance and MIT license](runtime/assets/quest_touch_plus/SOURCE.md).
|
||||
- **[Wiicompiled VR](https://github.com/iChris4/Wiicompiled_VR)** by **[iChris4](https://github.com/iChris4)**:
|
||||
This project originated as a fork of iChris4's pioneering OpenXR VR port of WiiCompiled.
|
||||
The core OpenXR integration, stereo rendering pipeline, and initial VR translation hooks
|
||||
were built by iChris4.
|
||||
iChris4 also contributed the native steering-wheel detection fixes integrated in v1.3:
|
||||
[wheel topology handling](https://github.com/iChris4/Wiicompiled_VR/commit/3d48514182f3c055b9614d752edf0896ba190f16)
|
||||
and [node matrix retrieval and topology validation](https://github.com/iChris4/Wiicompiled_VR/commit/f013f9d2f7682802bff576c9c047af49b1fb5ea6).
|
||||
- **[WheelWizard](https://github.com/TeamWheelWizard/WheelWizard)** by Team WheelWizard, integrated
|
||||
as the local launcher and Retro Rewind front end.
|
||||
- **[BigWalkVRInstaller](https://github.com/CircuitLord/BigWalkVRInstaller)** by CircuitLord, whose
|
||||
controller tutorial presentation inspired the attached callouts and pointer flow.
|
||||
- **[@XorDev](https://x.com/XorDev)** for the **Dielectric** shader used as the animated spatial
|
||||
background around the VR menus. This port adapts the shader from the
|
||||
[FragCoord.xyz reference](https://t.co/kdebpbDcaQ) for stereo, translated rendering and exposes
|
||||
quality levels in VR settings. See the [attribution note](licenses/Dielectric-menu-background.md).
|
||||
- **[aurora](https://github.com/encounter/aurora)** for the native GameCube/Wii graphics and windowing
|
||||
layer used by the port.
|
||||
- **[OpenXR](https://www.khronos.org/openxr/)**, **Dawn**, **Dolphin Emulator**, **Pulsar**,
|
||||
**[AnimalCrossing-VR-MR-Standalone](https://github.com/heurazy/AnimalCrossing-VR-MR-Standalone)**,
|
||||
and **[Cyberpunk VR port](https://github.com/dariulone/cyberpunk-vr-port)** for APIs, references,
|
||||
and implementation ideas used during development.
|
||||
|
||||
Bundled component licenses are listed in [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md). The
|
||||
controller tutorial notice is in [licenses/BigWalkVR-MIT.txt](licenses/BigWalkVR-MIT.txt).
|
||||
|
||||
## License and legal notice
|
||||
|
||||
The WiiCompiled source in this repository is licensed under the
|
||||
[GNU General Public License v3](LICENSE). Mario Kart Wii is a trademark of Nintendo. This project
|
||||
is not affiliated with or endorsed by Nintendo and does not contain Nintendo intellectual property.
|
||||
Dump and use your own game disc according to the laws that apply where you live.
|
||||
@@ -2742,6 +2742,15 @@ static void render_pass_impl(const wgpu::RenderPassEncoder& pass, const std::vec
|
||||
draw.gx.interpolatedUniformRanges[invocation.interpolatedFrame].size != 0) {
|
||||
uniformOverride = &draw.gx.interpolatedUniformRanges[invocation.interpolatedFrame];
|
||||
}
|
||||
// A virtual-screen draw gets the whole eye (below), so the game's scissor no longer clips
|
||||
// it. An element lying wholly outside a scissor the game narrowed would not have shown on
|
||||
// the flat frame either (Mario Kart's item roulette sliding up after use): skip it.
|
||||
if (virtualScreenDraw && draw.gx.screenRect && recordedScissor != fullTargetScissor &&
|
||||
draw.gx.screenRect->width > 0.f && draw.gx.screenRect->height > 0.f &&
|
||||
sourceScissor.width > 0.f && sourceScissor.height > 0.f &&
|
||||
!stereo_replay::subviews_overlap(*draw.gx.screenRect, sourceScissor)) {
|
||||
break;
|
||||
}
|
||||
// Draw against world depth and mark visible cockpit samples before HUD
|
||||
// depth replaces it. The screen pipelines reject those stencil samples.
|
||||
if (invocation.cockpitFrame != nullptr && overrideTarget) {
|
||||
|
||||
@@ -162,6 +162,20 @@ private:
|
||||
XrAction m_aim_pose = XR_NULL_HANDLE;
|
||||
XrAction m_grip_pose = XR_NULL_HANDLE;
|
||||
XrAction m_haptic = XR_NULL_HANDLE;
|
||||
// Steam Frame layout: hand-independent buttons that the local SteamVR binding assigns
|
||||
// (X / left bumper item, Y look back, grips / right bumper drift, Menu start, View back,
|
||||
// D-pad as the GameCube D-pad). Unbound, and so inactive, on other controllers.
|
||||
XrAction m_frame_item = XR_NULL_HANDLE;
|
||||
XrAction m_frame_look_back = XR_NULL_HANDLE;
|
||||
XrAction m_frame_drift = XR_NULL_HANDLE;
|
||||
XrAction m_frame_start = XR_NULL_HANDLE;
|
||||
XrAction m_frame_back = XR_NULL_HANDLE;
|
||||
std::array<XrAction, 4> m_frame_dpad{}; // up, down, left, right
|
||||
bool m_frame_layout = false;
|
||||
bool m_frame_back_held = false;
|
||||
bool m_frame_back_consumed = false;
|
||||
XrTime m_frame_back_down = 0;
|
||||
XrTime m_frame_back_pulse_until = 0;
|
||||
XrPath m_hand_paths[kHands]{};
|
||||
XrSpace m_aim_spaces[kHands]{};
|
||||
XrSpace m_grip_spaces[kHands]{};
|
||||
|
||||
@@ -333,6 +333,23 @@ bool OpenXRInput::CreateActions() {
|
||||
info.countSubactionPaths=1;info.subactionPaths=m_hand_paths;
|
||||
if(!Check(xrCreateAction(m_action_set,&info,spec.action),spec.name)) return false;
|
||||
}
|
||||
// Steam Frame actions carry no hand: SteamVR may bind them to either controller.
|
||||
for (const Spec& spec : std::array<Spec,9>{{
|
||||
{&m_frame_item,"frame_item","Use item",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_look_back,"frame_look_back","Look back",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_drift,"frame_drift","Drift / hop",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_start,"frame_start","Start / pause",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_back,"frame_back","Back (hold: VR settings)",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_dpad[0],"frame_dpad_up","D-pad up / trick",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_dpad[1],"frame_dpad_down","D-pad down",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_dpad[2],"frame_dpad_left","D-pad left",XR_ACTION_TYPE_BOOLEAN_INPUT},
|
||||
{&m_frame_dpad[3],"frame_dpad_right","D-pad right",XR_ACTION_TYPE_BOOLEAN_INPUT}}}) {
|
||||
XrActionCreateInfo info{XR_TYPE_ACTION_CREATE_INFO};
|
||||
info.actionType=spec.type;
|
||||
std::strncpy(info.actionName,spec.name,XR_MAX_ACTION_NAME_SIZE-1);
|
||||
std::strncpy(info.localizedActionName,spec.localized,XR_MAX_LOCALIZED_ACTION_NAME_SIZE-1);
|
||||
if(!Check(xrCreateAction(m_action_set,&info,spec.action),spec.name)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -607,6 +624,10 @@ void OpenXRInput::Destroy() {
|
||||
m_thumbstick = m_thumbstick_click = m_trigger = m_squeeze = XR_NULL_HANDLE;
|
||||
m_button_primary = m_button_secondary = m_menu = m_haptic = XR_NULL_HANDLE;
|
||||
m_options_x = m_options_y = XR_NULL_HANDLE;
|
||||
m_frame_item = m_frame_look_back = m_frame_drift = m_frame_start = m_frame_back = XR_NULL_HANDLE;
|
||||
m_frame_dpad = {};
|
||||
m_frame_layout = m_frame_back_held = m_frame_back_consumed = false;
|
||||
m_frame_back_down = m_frame_back_pulse_until = 0;
|
||||
m_options_previous=0;
|
||||
m_aim_pose = m_grip_pose = XR_NULL_HANDLE;
|
||||
m_hand_paths[0] = m_hand_paths[1] = XR_NULL_PATH;
|
||||
@@ -756,9 +777,50 @@ void OpenXRInput::Sync(XrTime predicted_display_time, const OpenXRPointerScreen&
|
||||
? static_cast<float>(input_time - m_last_input_time) * 1.0e-9f
|
||||
: 0.0f;
|
||||
m_last_input_time = input_time;
|
||||
// Steam Frame layout (see m_frame_item). An action counts as bound once SteamVR reports it active.
|
||||
bool frame_bound=false;
|
||||
const auto frame_button=[&](XrAction action) {
|
||||
if(action==XR_NULL_HANDLE) return false;
|
||||
XrActionStateGetInfo info{XR_TYPE_ACTION_STATE_GET_INFO};
|
||||
info.action=action;
|
||||
XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN};
|
||||
if(XR_FAILED(xrGetActionStateBoolean(m_runtime->Session(),&info,&state)) || state.isActive!=XR_TRUE) return false;
|
||||
frame_bound=true;
|
||||
return state.currentState==XR_TRUE;
|
||||
};
|
||||
const bool frame_item=frame_button(m_frame_item), frame_look_back=frame_button(m_frame_look_back);
|
||||
const bool frame_drift=frame_button(m_frame_drift), frame_start=frame_button(m_frame_start);
|
||||
const bool frame_back=frame_button(m_frame_back);
|
||||
std::array<bool,4> frame_dpad{};
|
||||
for(size_t i=0;i<frame_dpad.size();++i) frame_dpad[i]=frame_button(m_frame_dpad[i]);
|
||||
// Latched for the session: SteamVR briefly reports the actions inactive (a controller dozing,
|
||||
// focus changes), and the layout must not switch under the player mid-race.
|
||||
if(frame_bound && !m_frame_layout) {
|
||||
m_frame_layout=true;
|
||||
Log(OpenXRLogLevel::Info,"Steam Frame button layout active");
|
||||
}
|
||||
// View: a tap is GameCube B (back), a 0.5 s hold opens the VR settings, and with the settings
|
||||
// open a press closes them. The tap is sent on release so that a hold never also goes back.
|
||||
constexpr XrDuration kFrameBackHoldNs=500'000'000, kFrameBackPulseNs=120'000'000;
|
||||
const bool frame_back_pressed=frame_back && !m_frame_back_held;
|
||||
if(frame_back_pressed) {
|
||||
m_frame_back_down=input_time;
|
||||
m_frame_back_consumed=OpenXRSettingsPanelOpen();
|
||||
}
|
||||
bool frame_back_panel=false;
|
||||
if(frame_back && !m_frame_back_consumed && input_time-m_frame_back_down>=kFrameBackHoldNs) {
|
||||
frame_back_panel=true;
|
||||
m_frame_back_consumed=true;
|
||||
}
|
||||
if(!frame_back && m_frame_back_held && !m_frame_back_consumed) m_frame_back_pulse_until=input_time+kFrameBackPulseNs;
|
||||
m_frame_back_held=frame_back;
|
||||
const bool frame_back_pulse=input_time<m_frame_back_pulse_until;
|
||||
|
||||
std::array<wii_remote::HandInputs, kHands> panel_hands = hands;
|
||||
panel_hands[0].primary |= boolean(m_options_x,0);
|
||||
panel_hands[0].secondary |= boolean(m_options_y,0);
|
||||
if(frame_back_panel) panel_hands[0].primary=panel_hands[0].secondary=true;
|
||||
if(frame_back_pressed && m_frame_back_consumed) panel_hands[0].menu=true;
|
||||
const auto physical=m_runtime->RuntimeInfo().runtime_name.find("SteamVR")!=std::string::npos ?
|
||||
OpenXRReadPhysicalOptionsButtons() : PhysicalOptionsButtons{};
|
||||
if(physical.valid) {
|
||||
@@ -861,6 +923,24 @@ void OpenXRInput::Sync(XrTime predicted_display_time, const OpenXRPointerScreen&
|
||||
port.trick=pause.trick;
|
||||
if(pause.pause && !panel.withheld) OpenXRRequestTutorialPause();
|
||||
} else port.pause=hands[0].menu;
|
||||
if(m_frame_layout) {
|
||||
// A modern gamepad layout over the GameCube pad, the same in both views: A or the right
|
||||
// trigger accelerates, the right bumper drifts (no cockpit A = drift swap), and Menu is
|
||||
// Start. D-pad up goes through the tricks axis, not `trick`, which MapQuestInput reads with
|
||||
// the item as the VR settings chord. Either grip also drifts, except in the cockpit with
|
||||
// hand steering on, where the grips only hold the wheel.
|
||||
const bool grips_hold_wheel=port.cockpit_controls && RuntimeConfigFile::VrHandSteering();
|
||||
port.cockpit_controls=false;
|
||||
port.item=(frame_item || port.item>.5f)?1.f:0.f;
|
||||
port.look_back=frame_look_back;
|
||||
port.drift=std::max(grips_hold_wheel ? 0.f : std::max(ui.buttons[0].squeeze,ui.buttons[1].squeeze),
|
||||
frame_drift?1.f:0.f);
|
||||
port.trick=false;
|
||||
port.tricks_y=std::clamp(port.tricks_y+(frame_dpad[0]?1.f:0.f)-(frame_dpad[1]?1.f:0.f),-1.f,1.f);
|
||||
port.tricks_x=std::clamp(port.tricks_x+(frame_dpad[3]?1.f:0.f)-(frame_dpad[2]?1.f:0.f),-1.f,1.f);
|
||||
port.pause=frame_start;
|
||||
port.brake=port.brake || frame_back_pulse;
|
||||
}
|
||||
if(panel.withheld) {
|
||||
const auto rawX=port.raw_steering_x,rawY=port.raw_steering_y;
|
||||
port=QuestInput{.steamvr=port.steamvr,.active=true};port.raw_steering_x=rawX;port.raw_steering_y=rawY;
|
||||
|
||||
@@ -99,6 +99,17 @@ inline constexpr bool kWindowShapedEyesSupported = true;
|
||||
inline constexpr bool kWindowShapedEyesSupported = false;
|
||||
#endif
|
||||
|
||||
// Whether menus are drawn into the eye images (projection layer) rather than shown on a quad layer.
|
||||
// On Android always: under Lepton, SteamVR turns a quad layer into a slow submission, so quality 0
|
||||
// only swaps Aurora's raymarched menu background for a plain one, which the GPU draws for free.
|
||||
inline bool OpenXRProjectedMenus() noexcept {
|
||||
#if defined(__ANDROID__)
|
||||
return true;
|
||||
#else
|
||||
return RuntimeConfigFile::Get().vrMenuShaderQuality>0 || OpenXRIntroductionActive();
|
||||
#endif
|
||||
}
|
||||
|
||||
struct Quaternion {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
@@ -439,7 +450,15 @@ public:
|
||||
if (has_extension("XR_EXT_performance_settings")) {
|
||||
runtime_->LoadFunction("xrPerfSettingsSetPerformanceLevelEXT", &set_performance_level_);
|
||||
}
|
||||
#if defined(__ANDROID__)
|
||||
// Lepton's SteamVR bridge has no XR_KHR_convert_timespec_time; DisplayTimeNanos falls back
|
||||
// to reading XrTime as CLOCK_MONOTONIC (see MonotonicDisplayDelta).
|
||||
interpolation_available_.store(true, std::memory_order_release);
|
||||
clock_fallback_logged_ = false;
|
||||
clock_offset_valid_ = false;
|
||||
#else
|
||||
interpolation_available_.store(convert_display_time_ != nullptr, std::memory_order_release);
|
||||
#endif
|
||||
if (!backend_->QueryGraphicsRequirements(*runtime_)) {
|
||||
SetError(backend_->LastError());
|
||||
ResetPreparedObjects();
|
||||
@@ -486,7 +505,7 @@ public:
|
||||
WithdrawPublishedFrame();
|
||||
aurora_set_stereo_frame_provider(&OpenXRIntegration::ProvideStereoFrame, this);
|
||||
provider_registered_ = true;
|
||||
if (convert_display_time_ != nullptr) {
|
||||
if (convert_display_time_ != nullptr || interpolation_available_.load(std::memory_order_acquire)) {
|
||||
diagnostics::SetDisplayTimeConverter(
|
||||
[this](int64_t xr_time) { return static_cast<int64_t>(DisplayTimeNanos(xr_time)); });
|
||||
}
|
||||
@@ -566,9 +585,6 @@ public:
|
||||
}
|
||||
|
||||
void SetFrameInterpolationFps(uint32_t target) noexcept {
|
||||
#ifdef __ANDROID__
|
||||
target = 0;
|
||||
#endif
|
||||
frame_interpolation_fps_.store(NormalizeFrameInterpolationFps(target), std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -874,7 +890,7 @@ private:
|
||||
}
|
||||
OpenXRPresentation presentation{};
|
||||
const bool immersive = policy.presentation == VRPresentationMode::ImmersiveRace;
|
||||
presentation.mode = (immersive || RuntimeConfigFile::Get().vrMenuShaderQuality>0 || OpenXRIntroductionActive()) ? OpenXRFrameMode::ImmersiveProjection
|
||||
presentation.mode = (immersive || OpenXRProjectedMenus()) ? OpenXRFrameMode::ImmersiveProjection
|
||||
: OpenXRFrameMode::VirtualScreen;
|
||||
presentation.quad_distance_meters = policy.config.hud_distance_meters;
|
||||
presentation.quad_width_meters = policy.config.hud_width_meters;
|
||||
@@ -1348,7 +1364,7 @@ private:
|
||||
}
|
||||
void BuildMenuUi(const OpenXRBackendFrame& source, AuroraStereoFrame& destination) noexcept {
|
||||
XrPosef panel{};
|
||||
if ((RuntimeConfigFile::Get().vrMenuShaderQuality==0 && !OpenXRIntroductionActive()) || !MenuScreenPose(source,panel)) {
|
||||
if (!OpenXRProjectedMenus() || !MenuScreenPose(source,panel)) {
|
||||
OpenXRPublishHandWorkshopTracking({});return;
|
||||
}
|
||||
destination.ui.anchored=true;
|
||||
@@ -1548,7 +1564,7 @@ private:
|
||||
// pose is captured once, from the first frame whose head pose is good enough
|
||||
// to place it, and released again by a recenter or an origin change.
|
||||
void UpdateVirtualScreenPose(OpenXRBackendFrame& frame) noexcept {
|
||||
if (frame.presentation.mode != OpenXRFrameMode::VirtualScreen && RuntimeConfigFile::Get().vrMenuShaderQuality==0 && !OpenXRIntroductionActive()) {
|
||||
if (frame.presentation.mode != OpenXRFrameMode::VirtualScreen && !OpenXRProjectedMenus()) {
|
||||
return;
|
||||
}
|
||||
constexpr XrViewStateFlags kPoseUsable =
|
||||
@@ -1632,7 +1648,7 @@ private:
|
||||
if (frame.render_width[0] == 0 || frame.render_height[0] == 0 || !MenuScreenPose(frame, screen.pose)) {
|
||||
return screen;
|
||||
}
|
||||
if (RuntimeConfigFile::Get().vrMenuShaderQuality>0 || OpenXRIntroductionActive()) {
|
||||
if (OpenXRProjectedMenus()) {
|
||||
screen.half_width_meters=.5f*frame.presentation.quad_width_meters;
|
||||
screen.half_height_meters=screen.half_width_meters/snapshot_aspect;
|
||||
screen.valid=true;return screen;
|
||||
@@ -1861,9 +1877,6 @@ private:
|
||||
}
|
||||
|
||||
void SetInterpolationActive(bool active) noexcept {
|
||||
#ifdef __ANDROID__
|
||||
active = false;
|
||||
#endif
|
||||
std::lock_guard lock(interpolation_mutex_);
|
||||
aurora_set_stereo_frame_interpolation(active && !interpolation_stopping_);
|
||||
}
|
||||
@@ -1958,6 +1971,17 @@ private:
|
||||
// Converts the compositor's predicted display time onto the runtime's
|
||||
// steady clock, which is what Aurora's interpolation deadlines are paced by.
|
||||
uint64_t DisplayTimeNanos(XrTime display_time) noexcept {
|
||||
#if defined(__ANDROID__)
|
||||
if (convert_display_time_ == nullptr) {
|
||||
timespec now_spec{};
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &now_spec) != 0) return 0;
|
||||
const int64_t monotonic_ns = static_cast<int64_t>(now_spec.tv_sec) * 1'000'000'000ll + now_spec.tv_nsec;
|
||||
const auto steady_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now().time_since_epoch()).count();
|
||||
const int64_t delta = MonotonicDisplayDelta(display_time, monotonic_ns);
|
||||
return steady_ns + delta > 0 ? static_cast<uint64_t>(steady_ns + delta) : 0;
|
||||
}
|
||||
#endif
|
||||
if (convert_display_time_ == nullptr) return 0;
|
||||
const auto now = std::chrono::steady_clock::now();
|
||||
const auto now_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(now.time_since_epoch()).count();
|
||||
@@ -1983,6 +2007,29 @@ private:
|
||||
return now_ns + delta > 0 ? static_cast<uint64_t>(now_ns + delta) : 0;
|
||||
}
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
// SteamVR's XrTime is CLOCK_MONOTONIC in nanoseconds and Waydroid shares the host's clock, so a
|
||||
// predicted display time normally lies a few frames ahead of now. If it does not, the runtime
|
||||
// uses another epoch: anchor it to the first frame seen, assuming that frame shows ~2 frames out.
|
||||
int64_t MonotonicDisplayDelta(XrTime display_time, int64_t monotonic_ns) noexcept {
|
||||
const int64_t raw = static_cast<int64_t>(display_time) - monotonic_ns;
|
||||
const bool same_clock = raw > -100'000'000ll && raw < 500'000'000ll;
|
||||
if (!clock_fallback_logged_) {
|
||||
clock_fallback_logged_ = true;
|
||||
RT_LOG(RT_TAG_RUNTIME) << "OpenXR: no clock conversion; XrTime - CLOCK_MONOTONIC = "
|
||||
<< raw / 1000 << " us, "
|
||||
<< (same_clock ? "reading XrTime as CLOCK_MONOTONIC" : "anchoring to the first frame")
|
||||
<< std::endl;
|
||||
}
|
||||
if (same_clock) return raw;
|
||||
if (!clock_offset_valid_) {
|
||||
clock_offset_valid_ = true;
|
||||
clock_offset_ = raw - 22'000'000ll;
|
||||
}
|
||||
return raw - clock_offset_;
|
||||
}
|
||||
#endif
|
||||
|
||||
void WaitForStopOrDelay(std::chrono::milliseconds delay) {
|
||||
std::unique_lock lock(stop_mutex_);
|
||||
stop_cv_.wait_for(lock, delay,
|
||||
@@ -2027,7 +2074,23 @@ private:
|
||||
std::atomic<float> lean_back_degrees_{RuntimeConfigFile::VrLeanBackDegrees()};
|
||||
std::atomic_bool passthrough_{RuntimeConfigFile::VrPassthrough()};
|
||||
std::atomic_bool immersive_window_{RuntimeConfigFile::VrImmersiveWindow()};
|
||||
#if defined(__ANDROID__)
|
||||
static uint32_t AndroidFrameInterpolationFps() noexcept {
|
||||
// `setprop debug.wiicompiled.vr_interp 0|1|72|90|120` before launch overrides [vr]
|
||||
// frame_interpolation_fps; both default to auto (render every display refresh).
|
||||
char value[PROP_VALUE_MAX] = {};
|
||||
if (__system_property_get("debug.wiicompiled.vr_interp", value) > 0) {
|
||||
return NormalizeFrameInterpolationFps(static_cast<uint32_t>(std::strtoul(value, nullptr, 10)));
|
||||
}
|
||||
return NormalizeFrameInterpolationFps(RuntimeConfigFile::Get().vrFrameInterpolationFps.value_or(1));
|
||||
}
|
||||
std::atomic_uint32_t frame_interpolation_fps_{AndroidFrameInterpolationFps()};
|
||||
bool clock_fallback_logged_ = false;
|
||||
bool clock_offset_valid_ = false;
|
||||
int64_t clock_offset_ = 0;
|
||||
#else
|
||||
std::atomic_uint32_t frame_interpolation_fps_{RuntimeConfigFile::VrFrameInterpolationFps()};
|
||||
#endif
|
||||
std::atomic_bool interpolation_available_{false};
|
||||
std::mutex interpolation_mutex_;
|
||||
bool interpolation_stopping_ = true;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# WiiCompiled Quest configuration. Edit with the launcher or the in-game panel. After an adb push, run chmod 664 on it or the app can no longer save settings.
|
||||
# Seeded by the Steam Frame launch wrapper on the first run; the in-game VR settings panel edits it in place.
|
||||
[paths]
|
||||
dvd_root = "/storage/emulated/0/Android/data/org.wiicompiled.quest/files/WiiCompiledOpenXRVR/DATA"
|
||||
retro_rewind_root = "/storage/emulated/0/Android/data/org.wiicompiled.quest/files/WiiCompiledOpenXRVR/RetroRewind6"
|
||||
|
||||
[video]
|
||||
widescreen = true
|
||||
resolution_multiplier = 1.0
|
||||
|
||||
[vr]
|
||||
enabled = true
|
||||
render_scale = 1.000000
|
||||
# 1 = render at the headset's refresh rate (90 Hz under SteamVR), interpolated from the game's 60 fps.
|
||||
frame_interpolation_fps = 1
|
||||
# Grips hold the wheel in the first-person cockpit (the right bumper drifts there); elsewhere they drift.
|
||||
hand_steering = true
|
||||
# 0 = plain dark background behind the menus; the raymarched one held the menus at 40 fps on the Frame.
|
||||
menu_shader_quality = 0
|
||||
hand_hud = false
|
||||
@@ -0,0 +1,79 @@
|
||||
# Privacy audit of the Steam Frame fork
|
||||
|
||||
Date: 2026-10-11. Branch: `steam-frame`. This file records what was checked for personal data,
|
||||
what was changed, and the commands that repeat the check.
|
||||
|
||||
## What was searched
|
||||
|
||||
All tracked files on `steam-frame`: the READMEs, `DISTRIBUTION.md`, `RELEASE_VALIDATION.md`,
|
||||
`OPENXR.md`, `CONTRIBUTING.md`, `THIRD-PARTY-NOTICES.md`, `docs/`, `.github/` (CI and issue
|
||||
templates), `steam-frame/` (scripts, binding, seed config, generated build files), test fixtures
|
||||
and binary assets (with `strings`). Also the commit messages, author and committer identities
|
||||
and tag identities of the fork's commits, and the history for secrets.
|
||||
|
||||
Categories:
|
||||
|
||||
- Names and old account names of the owner, and school or employer names.
|
||||
- Host names of the owner's computers and client names.
|
||||
- LAN, hotspot, VPN and public IP addresses. MAC addresses.
|
||||
- Wi-Fi network names, including the Frame's own access point name.
|
||||
- UUIDs and IDs tied to the owner's computers, Steam user IDs, device serial numbers, system IDs,
|
||||
headset and Android device IDs in probe dumps, logcat excerpts and validation logs.
|
||||
- GitHub and API tokens, API keys, keystore passwords, paths to a signing key,
|
||||
PEM and certificate material, email addresses.
|
||||
|
||||
The owner's specific strings are kept in a private list outside the repository. They are not
|
||||
written here.
|
||||
|
||||
## Results
|
||||
|
||||
- Tracked files: no personal data found. Email addresses appear only in third-party copyright
|
||||
headers and upstream contributors' co-author lines. `/home/steamos` paths are SteamOS's default
|
||||
user and stay.
|
||||
- Commit and tag identities of the fork use the GitHub noreply address.
|
||||
- History of `steam-frame`: no tokens, private keys, certificates or keystore references.
|
||||
- Release APK `v1.3.1-frame.3`: the v2 signing certificate has a generic subject and no personal
|
||||
fields. Unpacked, the APK contains no personal strings. Two kit objects contain the generic build
|
||||
path under `/home/steamos`. `SHA256SUMS.txt` holds only the hash and file name.
|
||||
|
||||
## Changes
|
||||
|
||||
- `steam-frame/build.sh`: a comment that referred to another project of the owner was made
|
||||
generic.
|
||||
- `steam-frame/collect-logs.sh` (new): gathers the logs for a bug report and masks IP and MAC
|
||||
addresses, UUIDs, host names, Wi-Fi names, serial numbers, Steam IDs, email addresses, tokens,
|
||||
certificate blocks and user names in `/home` paths. Lepton's log contains the Frame's kernel log,
|
||||
which lists hardware serial numbers, so this matters for anyone who posts logs.
|
||||
- `README.md`: rewritten. It tells people to run `collect-logs.sh` and read the result before
|
||||
posting.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Each command must print `0`.
|
||||
|
||||
```sh
|
||||
# The owner's private list: one string per line, kept outside the repository.
|
||||
git grep -IinF -f ~/.config/wcf-private-terms.txt | wc -l
|
||||
git log --all --format='%an %ae %cn %ce %B' | grep -icF -f ~/.config/wcf-private-terms.txt
|
||||
|
||||
# Generic patterns in the fork's own files.
|
||||
FORK="README.md CONTRIBUTING.md .github steam-frame :!steam-frame/build-deps/Dependencies :!steam-frame/build-deps/generated/sdl-build"
|
||||
git grep -IhE '\b(10\.[0-9]+|192\.168|172\.(1[6-9]|2[0-9]|3[01])|100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7]))\.[0-9]+\.[0-9]+\b' -- $FORK | wc -l
|
||||
git grep -IhE '\b([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}\b' -- $FORK | wc -l
|
||||
git grep -IhE '\b[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}\b' -- $FORK | wc -l
|
||||
git grep -IhE '[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+\.[A-Za-z.]{2,}' -- $FORK | wc -l
|
||||
git grep -IhoE '/home/[A-Za-z0-9_.-]+' -- $FORK | sort -u | grep -vxE '/home/steamos' | wc -l
|
||||
|
||||
# Secrets anywhere in the tree and in the branch history.
|
||||
git grep -IhE '\b(ghp|gho|ghu|ghs|github_pat)_[A-Za-z0-9_]{20,}|\bsk-[A-Za-z0-9]{20,}|BEGIN [A-Z ]*(PRIVATE KEY|CERTIFICATE)-----|(store|key)Password' | wc -l
|
||||
git log steam-frame -p -G '(ghp|gho|ghu|ghs|github_pat)_[A-Za-z0-9_]{20,}' -- | wc -l
|
||||
git log steam-frame -p -G 'BEGIN [A-Z ]*(PRIVATE KEY|CERTIFICATE)-----' -- | wc -l
|
||||
git log steam-frame -p -G '[.](jks|keystore)\b|(store|key)Password' -- | wc -l
|
||||
```
|
||||
|
||||
The fork's commit identities can be listed with
|
||||
`git log --format='%ae%n%ce' origin/openxr-work..steam-frame | sort -u`. It must print only the
|
||||
GitHub noreply address.
|
||||
|
||||
To check a release APK's signing certificate without Java, extract the certificate from the APK
|
||||
Signing Block and run `openssl x509 -inform DER -noout -subject -issuer` on it.
|
||||
@@ -0,0 +1,228 @@
|
||||
{
|
||||
"action_manifest_version": 0,
|
||||
"alias_info": {},
|
||||
"app_key": "@APPKEY@",
|
||||
"category": "openxr",
|
||||
"controller_type": "frame_controller",
|
||||
"description": "Left stick steer; RT or A accelerate; LT or B brake/reverse; X or LB item; Y look back; RB drift/hop, grips too except in first person with hand steering (grips hold the wheel there); D-pad = D-pad (up = trick); Menu = Start/pause; View tap = back, hold = VR settings; right stick click = camera",
|
||||
"interaction_profile": "",
|
||||
"name": "WiiCompiled VR - Steam Frame layout (local)",
|
||||
"options": {},
|
||||
"simulated_actions": [],
|
||||
"bindings": {
|
||||
"/actions/mkw_gameplay": {
|
||||
"chords": [],
|
||||
"skeleton": [],
|
||||
"haptics": [
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/out/haptic",
|
||||
"path": "/user/hand/left/output/haptic"
|
||||
},
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/out/haptic",
|
||||
"path": "/user/hand/right/output/haptic"
|
||||
}
|
||||
],
|
||||
"poses": [
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/in/aim_pose",
|
||||
"path": "/user/hand/left/pose/openxr_aim"
|
||||
},
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/in/aim_pose",
|
||||
"path": "/user/hand/right/pose/openxr_aim"
|
||||
},
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/in/grip_pose",
|
||||
"path": "/user/hand/left/pose/openxr_grip"
|
||||
},
|
||||
{
|
||||
"output": "/actions/mkw_gameplay/in/grip_pose",
|
||||
"path": "/user/hand/right/pose/openxr_grip"
|
||||
}
|
||||
],
|
||||
"sources": [
|
||||
{
|
||||
"path": "/user/hand/left/input/thumbstick",
|
||||
"mode": "joystick",
|
||||
"inputs": {
|
||||
"position": {
|
||||
"output": "/actions/mkw_gameplay/in/thumbstick"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/thumbstick",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/thumbstick_click"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/thumbstick",
|
||||
"mode": "joystick",
|
||||
"inputs": {
|
||||
"position": {
|
||||
"output": "/actions/mkw_gameplay/in/thumbstick"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/thumbstick",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/thumbstick_click"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/trigger",
|
||||
"mode": "trigger",
|
||||
"inputs": {
|
||||
"pull": {
|
||||
"output": "/actions/mkw_gameplay/in/trigger"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/trigger",
|
||||
"mode": "trigger",
|
||||
"inputs": {
|
||||
"pull": {
|
||||
"output": "/actions/mkw_gameplay/in/trigger"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/grip",
|
||||
"mode": "trigger",
|
||||
"inputs": {
|
||||
"pull": {
|
||||
"output": "/actions/mkw_gameplay/in/squeeze"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/grip",
|
||||
"mode": "trigger",
|
||||
"inputs": {
|
||||
"pull": {
|
||||
"output": "/actions/mkw_gameplay/in/squeeze"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/a",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/button_primary"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/b",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/button_secondary"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/x",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_item"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/y",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_look_back"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/bumper",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_item"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/bumper",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_drift"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/dpad_up",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_dpad_up"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/dpad_down",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_dpad_down"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/dpad_left",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_dpad_left"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/dpad_right",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_dpad_right"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/right/input/menu",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_start"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "/user/hand/left/input/view",
|
||||
"mode": "button",
|
||||
"inputs": {
|
||||
"click": {
|
||||
"output": "/actions/mkw_gameplay/in/frame_back"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
@@ -0,0 +1,682 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryAtomic
|
||||
*
|
||||
* Atomic operations.
|
||||
*
|
||||
* IMPORTANT: If you are not an expert in concurrent lockless programming, you
|
||||
* should not be using any functions in this file. You should be protecting
|
||||
* your data structures with full mutexes instead.
|
||||
*
|
||||
* ***Seriously, here be dragons!***
|
||||
*
|
||||
* You can find out a little more about lockless programming and the subtle
|
||||
* issues that can arise here:
|
||||
* https://learn.microsoft.com/en-us/windows/win32/dxtecharts/lockless-programming
|
||||
*
|
||||
* There's also lots of good information here:
|
||||
*
|
||||
* - https://www.1024cores.net/home/lock-free-algorithms
|
||||
* - https://preshing.com/
|
||||
*
|
||||
* These operations may or may not actually be implemented using processor
|
||||
* specific atomic operations. When possible they are implemented as true
|
||||
* processor specific atomic operations. When that is not possible the are
|
||||
* implemented using locks that *do* use the available atomic operations.
|
||||
*
|
||||
* All of the atomic operations that modify memory are full memory barriers.
|
||||
*/
|
||||
|
||||
#ifndef SDL_atomic_h_
|
||||
#define SDL_atomic_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_platform_defines.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An atomic spinlock.
|
||||
*
|
||||
* The atomic locks are efficient spinlocks using CPU instructions, but are
|
||||
* vulnerable to starvation and can spin forever if a thread holding a lock
|
||||
* has been terminated. For this reason you should minimize the code executed
|
||||
* inside an atomic lock and never do expensive things like API or system
|
||||
* calls while holding them.
|
||||
*
|
||||
* They are also vulnerable to starvation if the thread holding the lock is
|
||||
* lower priority than other threads and doesn't get scheduled. In general you
|
||||
* should use mutexes instead, since they have better performance and
|
||||
* contention behavior.
|
||||
*
|
||||
* The atomic locks are not safe to lock recursively.
|
||||
*
|
||||
* Porting Note: The spin lock functions and type are required and can not be
|
||||
* emulated because they are used in the atomic emulation code.
|
||||
*/
|
||||
typedef int SDL_SpinLock;
|
||||
|
||||
/**
|
||||
* Try to lock a spin lock by setting it to a non-zero value.
|
||||
*
|
||||
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||
* doing. Please be careful using any sort of spinlock!***
|
||||
*
|
||||
* \param lock a pointer to a lock variable.
|
||||
* \returns true if the lock succeeded, false if the lock is already held.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LockSpinlock
|
||||
* \sa SDL_UnlockSpinlock
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_TryLockSpinlock(SDL_SpinLock *lock);
|
||||
|
||||
/**
|
||||
* Lock a spin lock by setting it to a non-zero value.
|
||||
*
|
||||
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||
* doing. Please be careful using any sort of spinlock!***
|
||||
*
|
||||
* \param lock a pointer to a lock variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_TryLockSpinlock
|
||||
* \sa SDL_UnlockSpinlock
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_LockSpinlock(SDL_SpinLock *lock);
|
||||
|
||||
/**
|
||||
* Unlock a spin lock by setting it to 0.
|
||||
*
|
||||
* Always returns immediately.
|
||||
*
|
||||
* ***Please note that spinlocks are dangerous if you don't know what you're
|
||||
* doing. Please be careful using any sort of spinlock!***
|
||||
*
|
||||
* \param lock a pointer to a lock variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LockSpinlock
|
||||
* \sa SDL_TryLockSpinlock
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_UnlockSpinlock(SDL_SpinLock *lock);
|
||||
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* Mark a compiler barrier.
|
||||
*
|
||||
* A compiler barrier prevents the compiler from reordering reads and writes
|
||||
* to globally visible variables across the call.
|
||||
*
|
||||
* This macro only prevents the compiler from reordering reads and writes, it
|
||||
* does not prevent the CPU from reordering reads and writes. However, all of
|
||||
* the atomic operations that modify memory are full memory barriers.
|
||||
*
|
||||
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||
* time, but if you find yourself needing this, you are probably
|
||||
* dealing with some very sensitive code; be careful!
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_CompilerBarrier() DoCompilerSpecificReadWriteBarrier()
|
||||
|
||||
#elif defined(_MSC_VER) && (_MSC_VER > 1200) && !defined(__clang__)
|
||||
void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
#define SDL_CompilerBarrier() _ReadWriteBarrier()
|
||||
#elif (defined(__GNUC__) && !defined(SDL_PLATFORM_EMSCRIPTEN)) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||
/* This is correct for all CPUs when using GCC or Solaris Studio 12.1+. */
|
||||
#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
|
||||
#elif defined(__WATCOMC__)
|
||||
extern __inline void SDL_CompilerBarrier(void);
|
||||
#pragma aux SDL_CompilerBarrier = "" parm [] modify exact [];
|
||||
#else
|
||||
#define SDL_CompilerBarrier() \
|
||||
{ SDL_SpinLock _tmp = 0; SDL_LockSpinlock(&_tmp); SDL_UnlockSpinlock(&_tmp); }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Insert a memory release barrier (function version).
|
||||
*
|
||||
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||
* version, which might be useful if you need to use this functionality from a
|
||||
* scripting language, etc. Also, some of the macro versions call this
|
||||
* function behind the scenes, where more heavy lifting can happen inside of
|
||||
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||
* version, as it will be more efficient.
|
||||
*
|
||||
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||
* time, but if you find yourself needing this, you are probably
|
||||
* dealing with some very sensitive code; be careful!
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MemoryBarrierRelease
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierReleaseFunction(void);
|
||||
|
||||
/**
|
||||
* Insert a memory acquire barrier (function version).
|
||||
*
|
||||
* Please refer to SDL_MemoryBarrierRelease for details. This is a function
|
||||
* version, which might be useful if you need to use this functionality from a
|
||||
* scripting language, etc. Also, some of the macro versions call this
|
||||
* function behind the scenes, where more heavy lifting can happen inside of
|
||||
* SDL. Generally, though, an app written in C/C++/etc should use the macro
|
||||
* version, as it will be more efficient.
|
||||
*
|
||||
* \threadsafety Obviously this function is safe to use from any thread at any
|
||||
* time, but if you find yourself needing this, you are probably
|
||||
* dealing with some very sensitive code; be careful!
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MemoryBarrierAcquire
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
|
||||
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* Insert a memory release barrier (macro version).
|
||||
*
|
||||
* Memory barriers are designed to prevent reads and writes from being
|
||||
* reordered by the compiler and being seen out of order on multi-core CPUs.
|
||||
*
|
||||
* A typical pattern would be for thread A to write some data and a flag, and
|
||||
* for thread B to read the flag and get the data. In this case you would
|
||||
* insert a release barrier between writing the data and the flag,
|
||||
* guaranteeing that the data write completes no later than the flag is
|
||||
* written, and you would insert an acquire barrier between reading the flag
|
||||
* and reading the data, to ensure that all the reads associated with the flag
|
||||
* have completed.
|
||||
*
|
||||
* In this pattern you should always see a release barrier paired with an
|
||||
* acquire barrier and you should gate the data reads/writes with a single
|
||||
* flag variable.
|
||||
*
|
||||
* For more information on these semantics, take a look at the blog post:
|
||||
* http://preshing.com/20120913/acquire-and-release-semantics
|
||||
*
|
||||
* This is the macro version of this functionality; if possible, SDL will use
|
||||
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||
* call the function version of this, SDL_MemoryBarrierReleaseFunction to do
|
||||
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||
* function.
|
||||
*
|
||||
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||
* time, but if you find yourself needing this, you are probably
|
||||
* dealing with some very sensitive code; be careful!
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MemoryBarrierAcquire
|
||||
* \sa SDL_MemoryBarrierReleaseFunction
|
||||
*/
|
||||
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||
|
||||
/**
|
||||
* Insert a memory acquire barrier (macro version).
|
||||
*
|
||||
* Please see SDL_MemoryBarrierRelease for the details on what memory barriers
|
||||
* are and when to use them.
|
||||
*
|
||||
* This is the macro version of this functionality; if possible, SDL will use
|
||||
* compiler intrinsics or inline assembly, but some platforms might need to
|
||||
* call the function version of this, SDL_MemoryBarrierAcquireFunction, to do
|
||||
* the heavy lifting. Apps that can use the macro should favor it over the
|
||||
* function.
|
||||
*
|
||||
* \threadsafety Obviously this macro is safe to use from any thread at any
|
||||
* time, but if you find yourself needing this, you are probably
|
||||
* dealing with some very sensitive code; be careful!
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_MemoryBarrierRelease
|
||||
* \sa SDL_MemoryBarrierAcquireFunction
|
||||
*/
|
||||
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||
|
||||
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
|
||||
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
|
||||
#elif defined(__GNUC__) && defined(__aarch64__)
|
||||
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||
#elif defined(__GNUC__) && defined(__arm__)
|
||||
#if 0 /* defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_ANDROID) */
|
||||
/* Information from:
|
||||
https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
|
||||
|
||||
The Linux kernel provides a helper function which provides the right code for a memory barrier,
|
||||
hard-coded at address 0xffff0fa0
|
||||
*/
|
||||
typedef void (*SDL_KernelMemoryBarrierFunc)();
|
||||
#define SDL_MemoryBarrierRelease() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||
#define SDL_MemoryBarrierAcquire() ((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
|
||||
#else
|
||||
#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
|
||||
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
|
||||
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
|
||||
#ifdef __thumb__
|
||||
/* The mcr instruction isn't available in thumb mode, use real functions */
|
||||
#define SDL_MEMORY_BARRIER_USES_FUNCTION
|
||||
#define SDL_MemoryBarrierRelease() SDL_MemoryBarrierReleaseFunction()
|
||||
#define SDL_MemoryBarrierAcquire() SDL_MemoryBarrierAcquireFunction()
|
||||
#else
|
||||
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
|
||||
#endif /* __thumb__ */
|
||||
#else
|
||||
#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
|
||||
#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
|
||||
#endif /* SDL_PLATFORM_LINUX || SDL_PLATFORM_ANDROID */
|
||||
#endif /* __GNUC__ && __arm__ */
|
||||
#else
|
||||
#if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))
|
||||
/* This is correct for all CPUs on Solaris when using Solaris Studio 12.1+. */
|
||||
#include <mbarrier.h>
|
||||
#define SDL_MemoryBarrierRelease() __machine_rel_barrier()
|
||||
#define SDL_MemoryBarrierAcquire() __machine_acq_barrier()
|
||||
#else
|
||||
/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
|
||||
#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
|
||||
#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* "REP NOP" is PAUSE, coded for tools that don't know it by that name. */
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A macro to insert a CPU-specific "pause" instruction into the program.
|
||||
*
|
||||
* This can be useful in busy-wait loops, as it serves as a hint to the CPU as
|
||||
* to the program's intent; some CPUs can use this to do more efficient
|
||||
* processing. On some platforms, this doesn't do anything, so using this
|
||||
* macro might just be a harmless no-op.
|
||||
*
|
||||
* Note that if you are busy-waiting, there are often more-efficient
|
||||
* approaches with other synchronization primitives: mutexes, semaphores,
|
||||
* condition variables, etc.
|
||||
*
|
||||
* \threadsafety This macro is safe to use from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_CPUPauseInstruction() DoACPUPauseInACompilerAndArchitectureSpecificWay
|
||||
|
||||
#elif (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define SDL_CPUPauseInstruction() __asm__ __volatile__("pause\n") /* Some assemblers can't do REP NOP, so go with PAUSE. */
|
||||
#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(__aarch64__)
|
||||
#define SDL_CPUPauseInstruction() __asm__ __volatile__("yield" ::: "memory")
|
||||
#elif (defined(__powerpc__) || defined(__powerpc64__))
|
||||
#define SDL_CPUPauseInstruction() __asm__ __volatile__("or 27,27,27");
|
||||
#elif (defined(__riscv) && __riscv_xlen == 64)
|
||||
#define SDL_CPUPauseInstruction() __asm__ __volatile__(".insn i 0x0F, 0, x0, x0, 0x010");
|
||||
#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
|
||||
#define SDL_CPUPauseInstruction() _mm_pause() /* this is actually "rep nop" and not a SIMD instruction. No inline asm in MSVC x86-64! */
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||
#define SDL_CPUPauseInstruction() __yield()
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
extern __inline void SDL_CPUPauseInstruction(void);
|
||||
#pragma aux SDL_CPUPauseInstruction = ".686p" ".xmm2" "pause"
|
||||
#else
|
||||
#define SDL_CPUPauseInstruction()
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* A type representing an atomic integer value.
|
||||
*
|
||||
* This can be used to manage a value that is synchronized across multiple
|
||||
* CPUs without a race condition; when an app sets a value with
|
||||
* SDL_SetAtomicInt all other threads, regardless of the CPU it is running on,
|
||||
* will see that value when retrieved with SDL_GetAtomicInt, regardless of CPU
|
||||
* caches, etc.
|
||||
*
|
||||
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||
* change the value as long as its current value matches expectations. When
|
||||
* done in a loop, one can guarantee data consistency across threads without a
|
||||
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||
* you don't do it carefully, you can confidently cause any number of
|
||||
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||
* this!).
|
||||
*
|
||||
* This is a struct so people don't accidentally use numeric operations on it
|
||||
* directly. You have to use SDL atomic functions.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CompareAndSwapAtomicInt
|
||||
* \sa SDL_GetAtomicInt
|
||||
* \sa SDL_SetAtomicInt
|
||||
* \sa SDL_AddAtomicInt
|
||||
*/
|
||||
typedef struct SDL_AtomicInt { int value; } SDL_AtomicInt;
|
||||
|
||||
/**
|
||||
* Set an atomic variable to a new value if it is currently an old value.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||
* \param oldval the old value.
|
||||
* \param newval the new value.
|
||||
* \returns true if the atomic variable was set, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetAtomicInt
|
||||
* \sa SDL_SetAtomicInt
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicInt(SDL_AtomicInt *a, int oldval, int newval);
|
||||
|
||||
/**
|
||||
* Set an atomic variable to a value.
|
||||
*
|
||||
* This function also acts as a full memory barrier.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||
* \param v the desired value.
|
||||
* \returns the previous value of the atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetAtomicInt
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_SetAtomicInt(SDL_AtomicInt *a, int v);
|
||||
|
||||
/**
|
||||
* Get the value of an atomic variable.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt variable.
|
||||
* \returns the current value of an atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetAtomicInt
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_GetAtomicInt(SDL_AtomicInt *a);
|
||||
|
||||
/**
|
||||
* Add to an atomic variable.
|
||||
*
|
||||
* This function also acts as a full memory barrier.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt variable to be modified.
|
||||
* \param v the desired value to add.
|
||||
* \returns the previous value of the atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AtomicDecRef
|
||||
* \sa SDL_AtomicIncRef
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_AddAtomicInt(SDL_AtomicInt *a, int v);
|
||||
|
||||
#ifndef SDL_AtomicIncRef
|
||||
|
||||
/**
|
||||
* Increment an atomic variable used as a reference count.
|
||||
*
|
||||
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt to increment.
|
||||
* \returns the previous value of the atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AtomicDecRef
|
||||
*/
|
||||
#define SDL_AtomicIncRef(a) SDL_AddAtomicInt(a, 1)
|
||||
#endif
|
||||
|
||||
#ifndef SDL_AtomicDecRef
|
||||
|
||||
/**
|
||||
* Decrement an atomic variable used as a reference count.
|
||||
*
|
||||
* ***Note: If you don't know what this macro is for, you shouldn't use it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicInt to decrement.
|
||||
* \returns true if the variable reached zero after decrementing, false
|
||||
* otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AtomicIncRef
|
||||
*/
|
||||
#define SDL_AtomicDecRef(a) (SDL_AddAtomicInt(a, -1) == 1)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A type representing an atomic unsigned 32-bit value.
|
||||
*
|
||||
* This can be used to manage a value that is synchronized across multiple
|
||||
* CPUs without a race condition; when an app sets a value with
|
||||
* SDL_SetAtomicU32 all other threads, regardless of the CPU it is running on,
|
||||
* will see that value when retrieved with SDL_GetAtomicU32, regardless of CPU
|
||||
* caches, etc.
|
||||
*
|
||||
* This is also useful for atomic compare-and-swap operations: a thread can
|
||||
* change the value as long as its current value matches expectations. When
|
||||
* done in a loop, one can guarantee data consistency across threads without a
|
||||
* lock (but the usual warnings apply: if you don't know what you're doing, or
|
||||
* you don't do it carefully, you can confidently cause any number of
|
||||
* disasters with this, so in most cases, you _should_ use a mutex instead of
|
||||
* this!).
|
||||
*
|
||||
* This is a struct so people don't accidentally use numeric operations on it
|
||||
* directly. You have to use SDL atomic functions.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CompareAndSwapAtomicU32
|
||||
* \sa SDL_GetAtomicU32
|
||||
* \sa SDL_SetAtomicU32
|
||||
*/
|
||||
typedef struct SDL_AtomicU32 { Uint32 value; } SDL_AtomicU32;
|
||||
|
||||
/**
|
||||
* Set an atomic variable to a new value if it is currently an old value.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||
* \param oldval the old value.
|
||||
* \param newval the new value.
|
||||
* \returns true if the atomic variable was set, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetAtomicU32
|
||||
* \sa SDL_SetAtomicU32
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicU32(SDL_AtomicU32 *a, Uint32 oldval, Uint32 newval);
|
||||
|
||||
/**
|
||||
* Set an atomic variable to a value.
|
||||
*
|
||||
* This function also acts as a full memory barrier.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||
* \param v the desired value.
|
||||
* \returns the previous value of the atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetAtomicU32
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint32 SDLCALL SDL_SetAtomicU32(SDL_AtomicU32 *a, Uint32 v);
|
||||
|
||||
/**
|
||||
* Get the value of an atomic variable.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicU32 variable.
|
||||
* \returns the current value of an atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetAtomicU32
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint32 SDLCALL SDL_GetAtomicU32(SDL_AtomicU32 *a);
|
||||
|
||||
/**
|
||||
* Add to an atomic variable.
|
||||
*
|
||||
* This function also acts as a full memory barrier.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to an SDL_AtomicU32 variable to be modified.
|
||||
* \param v the desired value to add or subtract.
|
||||
* \returns the previous value of the atomic variable.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint32 SDLCALL SDL_AddAtomicU32(SDL_AtomicU32 *a, int v);
|
||||
|
||||
/**
|
||||
* Set a pointer to a new value if it is currently an old value.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to a pointer.
|
||||
* \param oldval the old pointer value.
|
||||
* \param newval the new pointer value.
|
||||
* \returns true if the pointer was set, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CompareAndSwapAtomicInt
|
||||
* \sa SDL_GetAtomicPointer
|
||||
* \sa SDL_SetAtomicPointer
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CompareAndSwapAtomicPointer(void **a, void *oldval, void *newval);
|
||||
|
||||
/**
|
||||
* Set a pointer to a value atomically.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to a pointer.
|
||||
* \param v the desired pointer value.
|
||||
* \returns the previous value of the pointer.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CompareAndSwapAtomicPointer
|
||||
* \sa SDL_GetAtomicPointer
|
||||
*/
|
||||
extern SDL_DECLSPEC void * SDLCALL SDL_SetAtomicPointer(void **a, void *v);
|
||||
|
||||
/**
|
||||
* Get the value of a pointer atomically.
|
||||
*
|
||||
* ***Note: If you don't know what this function is for, you shouldn't use
|
||||
* it!***
|
||||
*
|
||||
* \param a a pointer to a pointer.
|
||||
* \returns the current value of a pointer.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CompareAndSwapAtomicPointer
|
||||
* \sa SDL_SetAtomicPointer
|
||||
*/
|
||||
extern SDL_DECLSPEC void * SDLCALL SDL_GetAtomicPointer(void **a);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_atomic_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,553 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* WIKI CATEGORY: BeginCode */
|
||||
|
||||
/**
|
||||
* # CategoryBeginCode
|
||||
*
|
||||
* `SDL_begin_code.h` sets things up for C dynamic library function
|
||||
* definitions, static inlined functions, and structures aligned at 4-byte
|
||||
* alignment. If you don't like ugly C preprocessor code, don't look at this
|
||||
* file. :)
|
||||
*
|
||||
* SDL's headers use this; applications generally should not include this
|
||||
* header directly.
|
||||
*/
|
||||
|
||||
/* This shouldn't be nested -- included it around code only. */
|
||||
#ifdef SDL_begin_code_h
|
||||
#error Nested inclusion of SDL_begin_code.h
|
||||
#endif
|
||||
#define SDL_begin_code_h
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A macro to tag a symbol as deprecated.
|
||||
*
|
||||
* A function is marked deprecated by adding this macro to its declaration:
|
||||
*
|
||||
* ```c
|
||||
* extern SDL_DEPRECATED int ThisFunctionWasABadIdea(void);
|
||||
* ```
|
||||
*
|
||||
* Compilers with deprecation support can give a warning when a deprecated
|
||||
* function is used. This symbol may be used in SDL's headers, but apps are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* SDL, on occasion, might deprecate a function for various reasons. However,
|
||||
* SDL never removes symbols before major versions, so deprecated interfaces
|
||||
* in SDL3 will remain available until SDL4, where it would be expected an app
|
||||
* would have to take steps to migrate anyhow.
|
||||
*
|
||||
* On compilers without a deprecation mechanism, this is defined to nothing,
|
||||
* and using a deprecated function will not generate a warning.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_DEPRECATED __attribute__((deprecated))
|
||||
|
||||
/**
|
||||
* A macro to tag a symbol as a public API.
|
||||
*
|
||||
* SDL uses this macro for all its public functions. On some targets, it is
|
||||
* used to signal to the compiler that this function needs to be exported from
|
||||
* a shared library, but it might have other side effects.
|
||||
*
|
||||
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||
|
||||
/**
|
||||
* A macro to set a function's calling conventions.
|
||||
*
|
||||
* SDL uses this macro for all its public functions, and any callbacks it
|
||||
* defines. This macro guarantees that calling conventions match between SDL
|
||||
* and the app, even if the two were built with different compilers or
|
||||
* optimization settings.
|
||||
*
|
||||
* When writing a callback function, it is very important for it to be
|
||||
* correctly tagged with SDLCALL, as mismatched calling conventions can cause
|
||||
* strange behaviors and can be difficult to diagnose. Plus, on many
|
||||
* platforms, SDLCALL is defined to nothing, so compilers won't be able to
|
||||
* warn that the tag is missing.
|
||||
*
|
||||
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDLCALL __cdecl
|
||||
|
||||
/**
|
||||
* A macro to request a function be inlined.
|
||||
*
|
||||
* This is a hint to the compiler to inline a function. The compiler is free
|
||||
* to ignore this request. On compilers without inline support, this is
|
||||
* defined to nothing.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_INLINE __inline
|
||||
|
||||
/**
|
||||
* A macro to demand a function be inlined.
|
||||
*
|
||||
* This is a command to the compiler to inline a function. SDL uses this macro
|
||||
* in its public headers for a handful of simple functions. On compilers
|
||||
* without forceinline support, this is defined to `static SDL_INLINE`, which
|
||||
* is often good enough.
|
||||
*
|
||||
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_FORCE_INLINE __forceinline
|
||||
|
||||
/**
|
||||
* A macro to tag a function as never-returning.
|
||||
*
|
||||
* This is a hint to the compiler that a function does not return. An example
|
||||
* of a function like this is the C runtime's exit() function.
|
||||
*
|
||||
* This hint can lead to code optimizations, and help analyzers understand
|
||||
* code flow better. On compilers without noreturn support, this is defined to
|
||||
* nothing.
|
||||
*
|
||||
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NORETURN __attribute__((noreturn))
|
||||
|
||||
/**
|
||||
* A macro to tag a function as never-returning (for analysis purposes).
|
||||
*
|
||||
* This is almost identical to SDL_NORETURN, except functions marked with this
|
||||
* _can_ actually return. The difference is that this isn't used for code
|
||||
* generation, but rather static analyzers use this information to assume
|
||||
* truths about program state and available code paths. Specifically, this tag
|
||||
* is useful for writing an assertion mechanism. Indeed, SDL_assert uses this
|
||||
* tag behind the scenes. Generally, apps that don't understand the specific
|
||||
* use-case for this tag should avoid using it directly.
|
||||
*
|
||||
* On compilers without analyzer_noreturn support, this is defined to nothing.
|
||||
*
|
||||
* This symbol is used in SDL's headers, but apps and other libraries are
|
||||
* welcome to use it for their own interfaces as well.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||
|
||||
|
||||
/**
|
||||
* A macro to signal that a case statement without a `break` is intentional.
|
||||
*
|
||||
* C compilers have gotten more aggressive about warning when a switch's
|
||||
* `case` block does not end with a `break` or other flow control statement,
|
||||
* flowing into the next case's code, as this is a common accident that leads
|
||||
* to strange bugs. But sometimes falling through to the next case is the
|
||||
* correct and desired behavior. This symbol lets an app communicate this
|
||||
* intention to the compiler, so it doesn't generate a warning.
|
||||
*
|
||||
* It is used like this:
|
||||
*
|
||||
* ```c
|
||||
* switch (x) {
|
||||
* case 1:
|
||||
* DoSomethingOnlyForOne();
|
||||
* SDL_FALLTHROUGH; // tell the compiler this was intentional.
|
||||
* case 2:
|
||||
* DoSomethingForOneAndTwo();
|
||||
* break;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||
|
||||
/**
|
||||
* A macro to tag a function's return value as critical.
|
||||
*
|
||||
* This is a hint to the compiler that a function's return value should not be
|
||||
* ignored.
|
||||
*
|
||||
* If an NODISCARD function's return value is thrown away (the function is
|
||||
* called as if it returns `void`), the compiler will issue a warning.
|
||||
*
|
||||
* While it's generally good practice to check return values for errors, often
|
||||
* times legitimate programs do not for good reasons. Be careful about what
|
||||
* functions are tagged as NODISCARD. It operates best when used on a function
|
||||
* that's failure is surprising and catastrophic; a good example would be a
|
||||
* program that checks the return values of all its file write function calls
|
||||
* but not the call to close the file, which it assumes incorrectly never
|
||||
* fails.
|
||||
*
|
||||
* Function callers that want to throw away a NODISCARD return value can call
|
||||
* the function with a `(void)` cast, which informs the compiler the act is
|
||||
* intentional.
|
||||
*
|
||||
* On compilers without nodiscard support, this is defined to nothing.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NODISCARD [[nodiscard]]
|
||||
|
||||
/**
|
||||
* A macro to tag a function as an allocator.
|
||||
*
|
||||
* This is a hint to the compiler that a function is an allocator, like
|
||||
* malloc(), with certain rules. A description of how GCC treats this hint is
|
||||
* here:
|
||||
*
|
||||
* https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute
|
||||
*
|
||||
* On compilers without allocator tag support, this is defined to nothing.
|
||||
*
|
||||
* Most apps don't need to, and should not, use this directly.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||
|
||||
/**
|
||||
* A macro to tag a function as returning a certain allocation.
|
||||
*
|
||||
* This is a hint to the compiler that a function allocates and returns a
|
||||
* specific amount of memory based on one of its arguments. For example, the C
|
||||
* runtime's malloc() function could use this macro with an argument of 1
|
||||
* (first argument to malloc is the size of the allocation).
|
||||
*
|
||||
* On compilers without alloc_size support, this is defined to nothing.
|
||||
*
|
||||
* Most apps don't need to, and should not, use this directly.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||
|
||||
/**
|
||||
* A macro to tag a pointer variable, to help with pointer aliasing.
|
||||
*
|
||||
* A good explanation of the restrict keyword is here:
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Restrict
|
||||
*
|
||||
* On compilers without restrict support, this is defined to nothing.
|
||||
*
|
||||
* \since This macro is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_RESTRICT __restrict
|
||||
|
||||
/**
|
||||
* Check if the compiler supports a given builtin functionality.
|
||||
*
|
||||
* This allows preprocessor checks for things that otherwise might fail to
|
||||
* compile.
|
||||
*
|
||||
* Supported by virtually all clang versions and more-recent GCCs. Use this
|
||||
* instead of checking the clang version if possible.
|
||||
*
|
||||
* On compilers without has_builtin support, this is defined to 0 (always
|
||||
* false).
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||
|
||||
/**
|
||||
* A macro to specify data alignment.
|
||||
*
|
||||
* This informs the compiler that a given datatype or variable must be aligned
|
||||
* to a specific byte count.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* ```c
|
||||
* // make sure this is struct is aligned to 16 bytes for SIMD access.
|
||||
* typedef struct {
|
||||
* float x, y, z, w;
|
||||
* } SDL_ALIGNED(16) MySIMDAlignedData;
|
||||
*
|
||||
* // make sure this one field in a struct is aligned to 16 bytes for SIMD access.
|
||||
* typedef struct {
|
||||
* SomeStuff stuff;
|
||||
* float SDL_ALIGNED(16) position[4];
|
||||
* SomeOtherStuff other_stuff;
|
||||
* } MyStruct;
|
||||
*
|
||||
* // make sure this variable is aligned to 32 bytes.
|
||||
* int SDL_ALIGNED(32) myval = 0;
|
||||
* ```
|
||||
*
|
||||
* Alignment is only guaranteed for things the compiler places: local
|
||||
* variables on the stack and global/static variables. To dynamically allocate
|
||||
* something that respects this alignment, use SDL_aligned_alloc() or some
|
||||
* other mechanism.
|
||||
*
|
||||
* On compilers without alignment support, this macro is defined to an invalid
|
||||
* symbol, to make it clear that the current compiler is likely to generate
|
||||
* incorrect code when it sees this macro.
|
||||
*
|
||||
* \param x the byte count to align to, so the data's address will be a
|
||||
* multiple of this value.
|
||||
*
|
||||
* \since This macro is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_ALIGNED(x) __attribute__((aligned(x)))
|
||||
|
||||
/* end of wiki documentation section. */
|
||||
#endif
|
||||
|
||||
/* `restrict` is from C99, but __restrict works with both Visual Studio and GCC. */
|
||||
#ifndef SDL_RESTRICT
|
||||
# if defined(restrict) || ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)))
|
||||
# define SDL_RESTRICT restrict
|
||||
# elif defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__)
|
||||
# define SDL_RESTRICT __restrict
|
||||
# else
|
||||
# define SDL_RESTRICT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_HAS_BUILTIN
|
||||
#ifdef __has_builtin
|
||||
#define SDL_HAS_BUILTIN(x) __has_builtin(x)
|
||||
#else
|
||||
#define SDL_HAS_BUILTIN(x) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_DEPRECATED
|
||||
# if defined(__GNUC__) && (__GNUC__ >= 4) /* technically, this arrived in gcc 3.1, but oh well. */
|
||||
# define SDL_DEPRECATED __attribute__((deprecated))
|
||||
# elif defined(_MSC_VER)
|
||||
# define SDL_DEPRECATED __declspec(deprecated)
|
||||
# else
|
||||
# define SDL_DEPRECATED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_UNUSED
|
||||
# ifdef __GNUC__
|
||||
# define SDL_UNUSED __attribute__((unused))
|
||||
# else
|
||||
# define SDL_UNUSED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Some compilers use a special export keyword */
|
||||
#ifndef SDL_DECLSPEC
|
||||
# if defined(SDL_PLATFORM_WINDOWS)
|
||||
# ifdef DLL_EXPORT
|
||||
# define SDL_DECLSPEC __declspec(dllexport)
|
||||
# else
|
||||
# define SDL_DECLSPEC
|
||||
# endif
|
||||
# else
|
||||
# if defined(__GNUC__) && __GNUC__ >= 4
|
||||
# define SDL_DECLSPEC __attribute__ ((visibility("default")))
|
||||
# else
|
||||
# define SDL_DECLSPEC
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* By default SDL uses the C calling convention */
|
||||
#ifndef SDLCALL
|
||||
#if defined(SDL_PLATFORM_WINDOWS) && !defined(__GNUC__)
|
||||
#define SDLCALL __cdecl
|
||||
#else
|
||||
#define SDLCALL
|
||||
#endif
|
||||
#endif /* SDLCALL */
|
||||
|
||||
/* Force structure packing at 4 byte alignment.
|
||||
This is necessary if the header is included in code which has structure
|
||||
packing set to an alternate value, say for loading structures from disk.
|
||||
The packing is reset to the previous value in SDL_close_code.h
|
||||
*/
|
||||
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4103)
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic ignored "-Wpragma-pack"
|
||||
#endif
|
||||
#ifdef __BORLANDC__
|
||||
#pragma nopackwarning
|
||||
#endif
|
||||
#ifdef _WIN64
|
||||
/* Use 8-byte alignment on 64-bit architectures, so pointers are aligned */
|
||||
#pragma pack(push,8)
|
||||
#else
|
||||
#pragma pack(push,4)
|
||||
#endif
|
||||
#endif /* Compiler needs structure packing set */
|
||||
|
||||
#ifndef SDL_INLINE
|
||||
#ifdef __GNUC__
|
||||
#define SDL_INLINE __inline__
|
||||
#elif defined(_MSC_VER) || defined(__BORLANDC__) || \
|
||||
defined(__DMC__) || defined(__SC__) || \
|
||||
defined(__WATCOMC__) || defined(__LCC__) || \
|
||||
defined(__DECC) || defined(__CC_ARM)
|
||||
#define SDL_INLINE __inline
|
||||
#ifndef __inline__
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
#else
|
||||
#define SDL_INLINE inline
|
||||
#ifndef __inline__
|
||||
#define __inline__ inline
|
||||
#endif
|
||||
#endif
|
||||
#endif /* SDL_INLINE not defined */
|
||||
|
||||
#ifndef SDL_FORCE_INLINE
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
#define SDL_FORCE_INLINE __forceinline
|
||||
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||
#define SDL_FORCE_INLINE __attribute__((always_inline)) static __inline__
|
||||
#else
|
||||
#define SDL_FORCE_INLINE static SDL_INLINE
|
||||
#endif
|
||||
#endif /* SDL_FORCE_INLINE not defined */
|
||||
|
||||
#ifndef SDL_NORETURN
|
||||
#if defined(__GNUC__)
|
||||
#define SDL_NORETURN __attribute__((noreturn))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SDL_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define SDL_NORETURN
|
||||
#endif
|
||||
#endif /* SDL_NORETURN not defined */
|
||||
|
||||
#ifdef __clang__
|
||||
#if __has_feature(attribute_analyzer_noreturn)
|
||||
#define SDL_ANALYZER_NORETURN __attribute__((analyzer_noreturn))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_ANALYZER_NORETURN
|
||||
#define SDL_ANALYZER_NORETURN
|
||||
#endif
|
||||
|
||||
/* Apparently this is needed by several Windows compilers */
|
||||
#ifndef __MACH__
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif /* NULL */
|
||||
#endif /* __MACH__ */
|
||||
|
||||
#ifndef SDL_FALLTHROUGH
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L)
|
||||
#define SDL_FALLTHROUGH [[fallthrough]]
|
||||
#else
|
||||
#if defined(__has_attribute) && !defined(__SUNPRO_C) && !defined(__SUNPRO_CC)
|
||||
#define SDL_HAS_FALLTHROUGH __has_attribute(__fallthrough__)
|
||||
#else
|
||||
#define SDL_HAS_FALLTHROUGH 0
|
||||
#endif /* __has_attribute */
|
||||
#if SDL_HAS_FALLTHROUGH && \
|
||||
((defined(__GNUC__) && __GNUC__ >= 7) || \
|
||||
(defined(__clang_major__) && __clang_major__ >= 10))
|
||||
#define SDL_FALLTHROUGH __attribute__((__fallthrough__))
|
||||
#else
|
||||
#define SDL_FALLTHROUGH do {} while (0) /* fallthrough */
|
||||
#endif /* SDL_HAS_FALLTHROUGH */
|
||||
#undef SDL_HAS_FALLTHROUGH
|
||||
#endif /* C++17 or C2x */
|
||||
#endif /* SDL_FALLTHROUGH not defined */
|
||||
|
||||
#ifndef SDL_NODISCARD
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || \
|
||||
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L)
|
||||
#define SDL_NODISCARD [[nodiscard]]
|
||||
#elif ( (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) )
|
||||
#define SDL_NODISCARD __attribute__((warn_unused_result))
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1700)
|
||||
#define SDL_NODISCARD _Check_return_
|
||||
#else
|
||||
#define SDL_NODISCARD
|
||||
#endif /* C++17 or C23 */
|
||||
#endif /* SDL_NODISCARD not defined */
|
||||
|
||||
#ifndef SDL_MALLOC
|
||||
#if defined(__GNUC__) && (__GNUC__ >= 3)
|
||||
#define SDL_MALLOC __attribute__((malloc))
|
||||
/** FIXME
|
||||
#elif defined(_MSC_VER)
|
||||
#define SDL_MALLOC __declspec(allocator) __desclspec(restrict)
|
||||
**/
|
||||
#else
|
||||
#define SDL_MALLOC
|
||||
#endif
|
||||
#endif /* SDL_MALLOC not defined */
|
||||
|
||||
#ifndef SDL_ALLOC_SIZE
|
||||
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
#define SDL_ALLOC_SIZE(p) __attribute__((alloc_size(p)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SDL_ALLOC_SIZE(p)
|
||||
#else
|
||||
#define SDL_ALLOC_SIZE(p)
|
||||
#endif
|
||||
#endif /* SDL_ALLOC_SIZE not defined */
|
||||
|
||||
#ifndef SDL_ALLOC_SIZE2
|
||||
#if (defined(__clang__) && __clang_major__ >= 4) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)))
|
||||
#define SDL_ALLOC_SIZE2(p1, p2) __attribute__((alloc_size(p1, p2)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||
#else
|
||||
#define SDL_ALLOC_SIZE2(p1, p2)
|
||||
#endif
|
||||
#endif /* SDL_ALLOC_SIZE2 not defined */
|
||||
|
||||
#ifndef SDL_ALIGNED
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define SDL_ALIGNED(x) __attribute__((aligned(x)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define SDL_ALIGNED(x) __declspec(align(x))
|
||||
#elif defined(__cplusplus) && (__cplusplus >= 201103L)
|
||||
#define SDL_ALIGNED(x) alignas(x)
|
||||
#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
|
||||
#define SDL_ALIGNED(x) _Alignas(x)
|
||||
#else
|
||||
#define SDL_ALIGNED(x) PLEASE_DEFINE_SDL_ALIGNED
|
||||
#endif
|
||||
#endif /* SDL_ALIGNED not defined */
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryBlendmode
|
||||
*
|
||||
* Blend modes decide how two colors will mix together. There are both
|
||||
* standard modes for basic needs and a means to create custom modes,
|
||||
* dictating what sort of math to do on what color components.
|
||||
*/
|
||||
|
||||
#ifndef SDL_blendmode_h_
|
||||
#define SDL_blendmode_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A set of blend modes used in drawing operations.
|
||||
*
|
||||
* These predefined blend modes are supported everywhere.
|
||||
*
|
||||
* Additional values may be obtained from SDL_ComposeCustomBlendMode.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ComposeCustomBlendMode
|
||||
*/
|
||||
typedef Uint32 SDL_BlendMode;
|
||||
|
||||
#define SDL_BLENDMODE_NONE 0x00000000u /**< no blending: dstRGBA = srcRGBA */
|
||||
#define SDL_BLENDMODE_BLEND 0x00000001u /**< alpha blending: dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA)), dstA = srcA + (dstA * (1-srcA)) */
|
||||
#define SDL_BLENDMODE_BLEND_PREMULTIPLIED 0x00000010u /**< pre-multiplied alpha blending: dstRGBA = srcRGBA + (dstRGBA * (1-srcA)) */
|
||||
#define SDL_BLENDMODE_ADD 0x00000002u /**< additive blending: dstRGB = (srcRGB * srcA) + dstRGB, dstA = dstA */
|
||||
#define SDL_BLENDMODE_ADD_PREMULTIPLIED 0x00000020u /**< pre-multiplied additive blending: dstRGB = srcRGB + dstRGB, dstA = dstA */
|
||||
#define SDL_BLENDMODE_MOD 0x00000004u /**< color modulate: dstRGB = srcRGB * dstRGB, dstA = dstA */
|
||||
#define SDL_BLENDMODE_MUL 0x00000008u /**< color multiply: dstRGB = (srcRGB * dstRGB) + (dstRGB * (1-srcA)), dstA = dstA */
|
||||
#define SDL_BLENDMODE_INVALID 0x7FFFFFFFu
|
||||
|
||||
/**
|
||||
* The blend operation used when combining source and destination pixel
|
||||
* components.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_BlendOperation
|
||||
{
|
||||
SDL_BLENDOPERATION_ADD = 0x1, /**< dst + src: supported by all renderers */
|
||||
SDL_BLENDOPERATION_SUBTRACT = 0x2, /**< src - dst : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||
SDL_BLENDOPERATION_REV_SUBTRACT = 0x3, /**< dst - src : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||
SDL_BLENDOPERATION_MINIMUM = 0x4, /**< min(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||
SDL_BLENDOPERATION_MAXIMUM = 0x5 /**< max(dst, src) : supported by D3D, OpenGL, OpenGLES, and Vulkan */
|
||||
} SDL_BlendOperation;
|
||||
|
||||
/**
|
||||
* The normalized factor used to multiply pixel components.
|
||||
*
|
||||
* The blend factors are multiplied with the pixels from a drawing operation
|
||||
* (src) and the pixels from the render target (dst) before the blend
|
||||
* operation. The comma-separated factors listed above are always applied in
|
||||
* the component order red, green, blue, and alpha.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_BlendFactor
|
||||
{
|
||||
SDL_BLENDFACTOR_ZERO = 0x1, /**< 0, 0, 0, 0 */
|
||||
SDL_BLENDFACTOR_ONE = 0x2, /**< 1, 1, 1, 1 */
|
||||
SDL_BLENDFACTOR_SRC_COLOR = 0x3, /**< srcR, srcG, srcB, srcA */
|
||||
SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR = 0x4, /**< 1-srcR, 1-srcG, 1-srcB, 1-srcA */
|
||||
SDL_BLENDFACTOR_SRC_ALPHA = 0x5, /**< srcA, srcA, srcA, srcA */
|
||||
SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA = 0x6, /**< 1-srcA, 1-srcA, 1-srcA, 1-srcA */
|
||||
SDL_BLENDFACTOR_DST_COLOR = 0x7, /**< dstR, dstG, dstB, dstA */
|
||||
SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR = 0x8, /**< 1-dstR, 1-dstG, 1-dstB, 1-dstA */
|
||||
SDL_BLENDFACTOR_DST_ALPHA = 0x9, /**< dstA, dstA, dstA, dstA */
|
||||
SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA = 0xA /**< 1-dstA, 1-dstA, 1-dstA, 1-dstA */
|
||||
} SDL_BlendFactor;
|
||||
|
||||
/**
|
||||
* Compose a custom blend mode for renderers.
|
||||
*
|
||||
* The functions SDL_SetRenderDrawBlendMode and SDL_SetTextureBlendMode accept
|
||||
* the SDL_BlendMode returned by this function if the renderer supports it.
|
||||
*
|
||||
* A blend mode controls how the pixels from a drawing operation (source) get
|
||||
* combined with the pixels from the render target (destination). First, the
|
||||
* components of the source and destination pixels get multiplied with their
|
||||
* blend factors. Then, the blend operation takes the two products and
|
||||
* calculates the result that will get stored in the render target.
|
||||
*
|
||||
* Expressed in pseudocode, it would look like this:
|
||||
*
|
||||
* ```c
|
||||
* dstRGB = colorOperation(srcRGB * srcColorFactor, dstRGB * dstColorFactor);
|
||||
* dstA = alphaOperation(srcA * srcAlphaFactor, dstA * dstAlphaFactor);
|
||||
* ```
|
||||
*
|
||||
* Where the functions `colorOperation(src, dst)` and `alphaOperation(src,
|
||||
* dst)` can return one of the following:
|
||||
*
|
||||
* - `src + dst`
|
||||
* - `src - dst`
|
||||
* - `dst - src`
|
||||
* - `min(src, dst)`
|
||||
* - `max(src, dst)`
|
||||
*
|
||||
* The red, green, and blue components are always multiplied with the first,
|
||||
* second, and third components of the SDL_BlendFactor, respectively. The
|
||||
* fourth component is not used.
|
||||
*
|
||||
* The alpha component is always multiplied with the fourth component of the
|
||||
* SDL_BlendFactor. The other components are not used in the alpha
|
||||
* calculation.
|
||||
*
|
||||
* Support for these blend modes varies for each renderer. To check if a
|
||||
* specific SDL_BlendMode is supported, create a renderer and pass it to
|
||||
* either SDL_SetRenderDrawBlendMode or SDL_SetTextureBlendMode. They will
|
||||
* return with an error if the blend mode is not supported.
|
||||
*
|
||||
* This list describes the support of custom blend modes for each renderer.
|
||||
* All renderers support the four blend modes listed in the SDL_BlendMode
|
||||
* enumeration.
|
||||
*
|
||||
* - **direct3d**: Supports all operations with all factors. However, some
|
||||
* factors produce unexpected results with `SDL_BLENDOPERATION_MINIMUM` and
|
||||
* `SDL_BLENDOPERATION_MAXIMUM`.
|
||||
* - **direct3d11**: Same as Direct3D 9.
|
||||
* - **opengl**: Supports the `SDL_BLENDOPERATION_ADD` operation with all
|
||||
* factors. OpenGL versions 1.1, 1.2, and 1.3 do not work correctly here.
|
||||
* - **opengles2**: Supports the `SDL_BLENDOPERATION_ADD`,
|
||||
* `SDL_BLENDOPERATION_SUBTRACT`, `SDL_BLENDOPERATION_REV_SUBTRACT`
|
||||
* operations with all factors.
|
||||
* - **psp**: No custom blend mode support.
|
||||
* - **software**: No custom blend mode support.
|
||||
*
|
||||
* Some renderers do not provide an alpha component for the default render
|
||||
* target. The `SDL_BLENDFACTOR_DST_ALPHA` and
|
||||
* `SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA` factors do not have an effect in this
|
||||
* case.
|
||||
*
|
||||
* \param srcColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||
* blue components of the source pixels.
|
||||
* \param dstColorFactor the SDL_BlendFactor applied to the red, green, and
|
||||
* blue components of the destination pixels.
|
||||
* \param colorOperation the SDL_BlendOperation used to combine the red,
|
||||
* green, and blue components of the source and
|
||||
* destination pixels.
|
||||
* \param srcAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||
* the source pixels.
|
||||
* \param dstAlphaFactor the SDL_BlendFactor applied to the alpha component of
|
||||
* the destination pixels.
|
||||
* \param alphaOperation the SDL_BlendOperation used to combine the alpha
|
||||
* component of the source and destination pixels.
|
||||
* \returns an SDL_BlendMode that represents the chosen factors and
|
||||
* operations.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetRenderDrawBlendMode
|
||||
* \sa SDL_GetRenderDrawBlendMode
|
||||
* \sa SDL_SetTextureBlendMode
|
||||
* \sa SDL_GetTextureBlendMode
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_BlendMode SDLCALL SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor,
|
||||
SDL_BlendFactor dstColorFactor,
|
||||
SDL_BlendOperation colorOperation,
|
||||
SDL_BlendFactor srcAlphaFactor,
|
||||
SDL_BlendFactor dstAlphaFactor,
|
||||
SDL_BlendOperation alphaOperation);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_blendmode_h_ */
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryCamera
|
||||
*
|
||||
* Video capture for the SDL library.
|
||||
*
|
||||
* This API lets apps read input from video sources, like webcams. Camera
|
||||
* devices can be enumerated, queried, and opened. Once opened, it will
|
||||
* provide SDL_Surface objects as new frames of video come in. These surfaces
|
||||
* can be uploaded to an SDL_Texture or processed as pixels in memory.
|
||||
*
|
||||
* Several platforms will alert the user if an app tries to access a camera,
|
||||
* and some will present a UI asking the user if your application should be
|
||||
* allowed to obtain images at all, which they can deny. A successfully opened
|
||||
* camera will not provide images until permission is granted. Applications,
|
||||
* after opening a camera device, can see if they were granted access by
|
||||
* either polling with the SDL_GetCameraPermissionState() function, or waiting
|
||||
* for an SDL_EVENT_CAMERA_DEVICE_APPROVED or SDL_EVENT_CAMERA_DEVICE_DENIED
|
||||
* event. Platforms that don't have any user approval process will report
|
||||
* approval immediately.
|
||||
*
|
||||
* Note that SDL cameras only provide video as individual frames; they will
|
||||
* not provide full-motion video encoded in a movie file format, although an
|
||||
* app is free to encode the acquired frames into any format it likes. It also
|
||||
* does not provide audio from the camera hardware through this API; not only
|
||||
* do many webcams not have microphones at all, many people--from streamers to
|
||||
* people on Zoom calls--will want to use a separate microphone regardless of
|
||||
* the camera. In any case, recorded audio will be available through SDL's
|
||||
* audio API no matter what hardware provides the microphone.
|
||||
*
|
||||
* ## Camera gotchas
|
||||
*
|
||||
* Consumer-level camera hardware tends to take a little while to warm up,
|
||||
* once the device has been opened. Generally most camera apps have some sort
|
||||
* of UI to take a picture (a button to snap a pic while a preview is showing,
|
||||
* some sort of multi-second countdown for the user to pose, like a photo
|
||||
* booth), which puts control in the users' hands, or they are intended to
|
||||
* stay on for long times (Pokemon Go, etc).
|
||||
*
|
||||
* It's not uncommon that a newly-opened camera will provide a couple of
|
||||
* completely black frames, maybe followed by some under-exposed images. If
|
||||
* taking a single frame automatically, or recording video from a camera's
|
||||
* input without the user initiating it from a preview, it could be wise to
|
||||
* drop the first several frames (if not the first several _seconds_ worth of
|
||||
* frames!) before using images from a camera.
|
||||
*/
|
||||
|
||||
#ifndef SDL_camera_h_
|
||||
#define SDL_camera_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_pixels.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL_surface.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is a unique ID for a camera device for the time it is connected to the
|
||||
* system, and is never reused for the lifetime of the application.
|
||||
*
|
||||
* If the device is disconnected and reconnected, it will get a new ID.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameras
|
||||
*/
|
||||
typedef Uint32 SDL_CameraID;
|
||||
|
||||
/**
|
||||
* The opaque structure used to identify an opened SDL camera.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef struct SDL_Camera SDL_Camera;
|
||||
|
||||
/**
|
||||
* The details of an output format for a camera device.
|
||||
*
|
||||
* Cameras often support multiple formats; each one will be encapsulated in
|
||||
* this struct.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameraSupportedFormats
|
||||
* \sa SDL_GetCameraFormat
|
||||
*/
|
||||
typedef struct SDL_CameraSpec
|
||||
{
|
||||
SDL_PixelFormat format; /**< Frame format */
|
||||
SDL_Colorspace colorspace; /**< Frame colorspace */
|
||||
int width; /**< Frame width */
|
||||
int height; /**< Frame height */
|
||||
int framerate_numerator; /**< Frame rate numerator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||
int framerate_denominator; /**< Frame rate denominator ((num / denom) == FPS, (denom / num) == duration in seconds) */
|
||||
} SDL_CameraSpec;
|
||||
|
||||
/**
|
||||
* The position of camera in relation to system device.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameraPosition
|
||||
*/
|
||||
typedef enum SDL_CameraPosition
|
||||
{
|
||||
SDL_CAMERA_POSITION_UNKNOWN,
|
||||
SDL_CAMERA_POSITION_FRONT_FACING,
|
||||
SDL_CAMERA_POSITION_BACK_FACING
|
||||
} SDL_CameraPosition;
|
||||
|
||||
/**
|
||||
* The current state of a request for camera access.
|
||||
*
|
||||
* \since This enum is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_GetCameraPermissionState
|
||||
*/
|
||||
typedef enum SDL_CameraPermissionState
|
||||
{
|
||||
SDL_CAMERA_PERMISSION_STATE_DENIED = -1,
|
||||
SDL_CAMERA_PERMISSION_STATE_PENDING,
|
||||
SDL_CAMERA_PERMISSION_STATE_APPROVED,
|
||||
} SDL_CameraPermissionState;
|
||||
|
||||
|
||||
/**
|
||||
* Use this function to get the number of built-in camera drivers.
|
||||
*
|
||||
* This function returns a hardcoded number. This never returns a negative
|
||||
* value; if there are no drivers compiled into this build of SDL, this
|
||||
* function returns zero. The presence of a driver in this list does not mean
|
||||
* it will function, it just means SDL is capable of interacting with that
|
||||
* interface. For example, a build of SDL might have v4l2 support, but if
|
||||
* there's no kernel support available, SDL's v4l2 driver would fail if used.
|
||||
*
|
||||
* By default, SDL tries all drivers, in its preferred order, until one is
|
||||
* found to be usable.
|
||||
*
|
||||
* \returns the number of built-in camera drivers.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameraDriver
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_GetNumCameraDrivers(void);
|
||||
|
||||
/**
|
||||
* Use this function to get the name of a built in camera driver.
|
||||
*
|
||||
* The list of camera drivers is given in the order that they are normally
|
||||
* initialized by default; the drivers that seem more reasonable to choose
|
||||
* first (as far as the SDL developers believe) are earlier in the list.
|
||||
*
|
||||
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||
* meant to be proper names.
|
||||
*
|
||||
* \param index the index of the camera driver; the value ranges from 0 to
|
||||
* SDL_GetNumCameraDrivers() - 1.
|
||||
* \returns the name of the camera driver at the requested index, or NULL if
|
||||
* an invalid index was specified.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetNumCameraDrivers
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraDriver(int index);
|
||||
|
||||
/**
|
||||
* Get the name of the current camera driver.
|
||||
*
|
||||
* The names of drivers are all simple, low-ASCII identifiers, like "v4l2",
|
||||
* "coremedia" or "android". These never have Unicode characters, and are not
|
||||
* meant to be proper names.
|
||||
*
|
||||
* \returns the name of the current camera driver or NULL if no driver has
|
||||
* been initialized.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCurrentCameraDriver(void);
|
||||
|
||||
/**
|
||||
* Get a list of currently connected camera devices.
|
||||
*
|
||||
* \param count a pointer filled in with the number of cameras returned, may
|
||||
* be NULL.
|
||||
* \returns a 0 terminated array of camera instance IDs or NULL on failure;
|
||||
* call SDL_GetError() for more information. This should be freed
|
||||
* with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_OpenCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_CameraID * SDLCALL SDL_GetCameras(int *count);
|
||||
|
||||
/**
|
||||
* Get the list of native formats/sizes a camera supports.
|
||||
*
|
||||
* This returns a list of all formats and frame sizes that a specific camera
|
||||
* can offer. This is useful if your app can accept a variety of image formats
|
||||
* and sizes and so want to find the optimal spec that doesn't require
|
||||
* conversion.
|
||||
*
|
||||
* This function isn't strictly required; if you call SDL_OpenCamera with a
|
||||
* NULL spec, SDL will choose a native format for you, and if you instead
|
||||
* specify a desired format, it will transparently convert to the requested
|
||||
* format on your behalf.
|
||||
*
|
||||
* If `count` is not NULL, it will be filled with the number of elements in
|
||||
* the returned array.
|
||||
*
|
||||
* Note that it's legal for a camera to supply an empty list. This is what
|
||||
* will happen on Emscripten builds, since that platform won't tell _anything_
|
||||
* about available cameras until you've opened one, and won't even tell if
|
||||
* there _is_ a camera until the user has given you permission to check
|
||||
* through a scary warning popup.
|
||||
*
|
||||
* \param instance_id the camera device instance ID.
|
||||
* \param count a pointer filled in with the number of elements in the list,
|
||||
* may be NULL.
|
||||
* \returns a NULL terminated array of pointers to SDL_CameraSpec or NULL on
|
||||
* failure; call SDL_GetError() for more information. This is a
|
||||
* single allocation that should be freed with SDL_free() when it is
|
||||
* no longer needed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameras
|
||||
* \sa SDL_OpenCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_CameraSpec ** SDLCALL SDL_GetCameraSupportedFormats(SDL_CameraID instance_id, int *count);
|
||||
|
||||
/**
|
||||
* Get the human-readable device name for a camera.
|
||||
*
|
||||
* \param instance_id the camera device instance ID.
|
||||
* \returns a human-readable device name or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameras
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetCameraName(SDL_CameraID instance_id);
|
||||
|
||||
/**
|
||||
* Get the position of the camera in relation to the system.
|
||||
*
|
||||
* Most platforms will report UNKNOWN, but mobile devices, like phones, can
|
||||
* often make a distinction between cameras on the front of the device (that
|
||||
* points towards the user, for taking "selfies") and cameras on the back (for
|
||||
* filming in the direction the user is facing).
|
||||
*
|
||||
* \param instance_id the camera device instance ID.
|
||||
* \returns the position of the camera on the system hardware.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameras
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_CameraPosition SDLCALL SDL_GetCameraPosition(SDL_CameraID instance_id);
|
||||
|
||||
/**
|
||||
* Open a video recording device (a "camera").
|
||||
*
|
||||
* You can open the device with any reasonable spec, and if the hardware can't
|
||||
* directly support it, it will convert data seamlessly to the requested
|
||||
* format. This might incur overhead, including scaling of image data.
|
||||
*
|
||||
* If you would rather accept whatever format the device offers, you can pass
|
||||
* a NULL spec here and it will choose one for you (and you can use
|
||||
* SDL_Surface's conversion/scaling functions directly if necessary).
|
||||
*
|
||||
* You can call SDL_GetCameraFormat() to get the actual data format if passing
|
||||
* a NULL spec here. You can see the exact specs a device can support without
|
||||
* conversion with SDL_GetCameraSupportedFormats().
|
||||
*
|
||||
* SDL will not attempt to emulate framerate; it will try to set the hardware
|
||||
* to the rate closest to the requested speed, but it won't attempt to limit
|
||||
* or duplicate frames artificially; call SDL_GetCameraFormat() to see the
|
||||
* actual framerate of the opened the device, and check your timestamps if
|
||||
* this is crucial to your app!
|
||||
*
|
||||
* Note that the camera is not usable until the user approves its use! On some
|
||||
* platforms, the operating system will prompt the user to permit access to
|
||||
* the camera, and they can choose Yes or No at that point. Until they do, the
|
||||
* camera will not be usable. The app should either wait for an
|
||||
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||
* non-zero. On platforms that don't require explicit user approval (and
|
||||
* perhaps in places where the user previously permitted access), the approval
|
||||
* event might come immediately, but it might come seconds, minutes, or hours
|
||||
* later!
|
||||
*
|
||||
* \param instance_id the camera device instance ID.
|
||||
* \param spec the desired format for data the device will provide. Can be
|
||||
* NULL.
|
||||
* \returns an SDL_Camera object or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCameras
|
||||
* \sa SDL_GetCameraFormat
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Camera * SDLCALL SDL_OpenCamera(SDL_CameraID instance_id, const SDL_CameraSpec *spec);
|
||||
|
||||
/**
|
||||
* Query if camera access has been approved by the user.
|
||||
*
|
||||
* Cameras will not function between when the device is opened by the app and
|
||||
* when the user permits access to the hardware. On some platforms, this
|
||||
* presents as a popup dialog where the user has to explicitly approve access;
|
||||
* on others the approval might be implicit and not alert the user at all.
|
||||
*
|
||||
* This function can be used to check the status of that approval. It will
|
||||
* return SDL_CAMERA_PERMISSION_STATE_PENDING if waiting for user response,
|
||||
* SDL_CAMERA_PERMISSION_STATE_APPROVED if the camera is approved for use, and
|
||||
* SDL_CAMERA_PERMISSION_STATE_DENIED if the user denied access.
|
||||
*
|
||||
* Instead of polling with this function, you can wait for a
|
||||
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event
|
||||
* in the standard SDL event loop, which is guaranteed to be sent once when
|
||||
* permission to use the camera is decided.
|
||||
*
|
||||
* If a camera is declined, there's nothing to be done but call
|
||||
* SDL_CloseCamera() to dispose of it.
|
||||
*
|
||||
* \param camera the opened camera device to query.
|
||||
* \returns an SDL_CameraPermissionState value indicating if access is
|
||||
* granted, or `SDL_CAMERA_PERMISSION_STATE_PENDING` if the decision
|
||||
* is still pending.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_OpenCamera
|
||||
* \sa SDL_CloseCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_CameraPermissionState SDLCALL SDL_GetCameraPermissionState(SDL_Camera *camera);
|
||||
|
||||
/**
|
||||
* Get the instance ID of an opened camera.
|
||||
*
|
||||
* \param camera an SDL_Camera to query.
|
||||
* \returns the instance ID of the specified camera on success or 0 on
|
||||
* failure; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_OpenCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_CameraID SDLCALL SDL_GetCameraID(SDL_Camera *camera);
|
||||
|
||||
/**
|
||||
* Get the properties associated with an opened camera.
|
||||
*
|
||||
* \param camera the SDL_Camera obtained from SDL_OpenCamera().
|
||||
* \returns a valid property ID on success or 0 on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetCameraProperties(SDL_Camera *camera);
|
||||
|
||||
/**
|
||||
* Get the spec that a camera is using when generating images.
|
||||
*
|
||||
* Note that this might not be the native format of the hardware, as SDL might
|
||||
* be converting to this format behind the scenes.
|
||||
*
|
||||
* If the system is waiting for the user to approve access to the camera, as
|
||||
* some platforms require, this will return false, but this isn't necessarily
|
||||
* a fatal error; you should either wait for an
|
||||
* SDL_EVENT_CAMERA_DEVICE_APPROVED (or SDL_EVENT_CAMERA_DEVICE_DENIED) event,
|
||||
* or poll SDL_GetCameraPermissionState() occasionally until it returns
|
||||
* non-zero.
|
||||
*
|
||||
* \param camera opened camera device.
|
||||
* \param spec the SDL_CameraSpec to be initialized by this function.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_OpenCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetCameraFormat(SDL_Camera *camera, SDL_CameraSpec *spec);
|
||||
|
||||
/**
|
||||
* Acquire a frame.
|
||||
*
|
||||
* The frame is a memory pointer to the image data, whose size and format are
|
||||
* given by the spec requested when opening the device.
|
||||
*
|
||||
* This is a non blocking API. If there is a frame available, a non-NULL
|
||||
* surface is returned, and timestampNS will be filled with a non-zero value.
|
||||
*
|
||||
* Note that an error case can also return NULL, but a NULL by itself is
|
||||
* normal and just signifies that a new frame is not yet available. Note that
|
||||
* even if a camera device fails outright (a USB camera is unplugged while in
|
||||
* use, etc), SDL will send an event separately to notify the app, but
|
||||
* continue to provide blank frames at ongoing intervals until
|
||||
* SDL_CloseCamera() is called, so real failure here is almost always an out
|
||||
* of memory condition.
|
||||
*
|
||||
* After use, the frame should be released with SDL_ReleaseCameraFrame(). If
|
||||
* you don't do this, the system may stop providing more video!
|
||||
*
|
||||
* Do not call SDL_DestroySurface() on the returned surface! It must be given
|
||||
* back to the camera subsystem with SDL_ReleaseCameraFrame!
|
||||
*
|
||||
* If the system is waiting for the user to approve access to the camera, as
|
||||
* some platforms require, this will return NULL (no frames available); you
|
||||
* should either wait for an SDL_EVENT_CAMERA_DEVICE_APPROVED (or
|
||||
* SDL_EVENT_CAMERA_DEVICE_DENIED) event, or poll
|
||||
* SDL_GetCameraPermissionState() occasionally until it returns non-zero.
|
||||
*
|
||||
* \param camera opened camera device.
|
||||
* \param timestampNS a pointer filled in with the frame's timestamp, or 0 on
|
||||
* error. Can be NULL.
|
||||
* \returns a new frame of video on success, NULL if none is currently
|
||||
* available.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ReleaseCameraFrame
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_AcquireCameraFrame(SDL_Camera *camera, Uint64 *timestampNS);
|
||||
|
||||
/**
|
||||
* Release a frame of video acquired from a camera.
|
||||
*
|
||||
* Let the back-end re-use the internal buffer for camera.
|
||||
*
|
||||
* This function _must_ be called only on surface objects returned by
|
||||
* SDL_AcquireCameraFrame(). This function should be called as quickly as
|
||||
* possible after acquisition, as SDL keeps a small FIFO queue of surfaces for
|
||||
* video frames; if surfaces aren't released in a timely manner, SDL may drop
|
||||
* upcoming video frames from the camera.
|
||||
*
|
||||
* If the app needs to keep the surface for a significant time, they should
|
||||
* make a copy of it and release the original.
|
||||
*
|
||||
* The app should not use the surface again after calling this function;
|
||||
* assume the surface is freed and the pointer is invalid.
|
||||
*
|
||||
* \param camera opened camera device.
|
||||
* \param frame the video frame surface to release.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AcquireCameraFrame
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ReleaseCameraFrame(SDL_Camera *camera, SDL_Surface *frame);
|
||||
|
||||
/**
|
||||
* Use this function to shut down camera processing and close the camera
|
||||
* device.
|
||||
*
|
||||
* \param camera opened camera device.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, but no
|
||||
* thread may reference `device` once this function is called.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_OpenCamera
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_CloseCamera(SDL_Camera *camera);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_camera_h_ */
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file reverses the effects of SDL_begin_code.h and should be included
|
||||
* after you finish any function and structure declarations in your headers.
|
||||
*
|
||||
* SDL's headers use this; applications generally should not include this
|
||||
* header directly.
|
||||
*/
|
||||
|
||||
#ifndef SDL_begin_code_h
|
||||
#error SDL_close_code.h included without matching SDL_begin_code.h
|
||||
#endif
|
||||
#undef SDL_begin_code_h
|
||||
|
||||
/* Reset structure packing at previous byte alignment */
|
||||
#if defined(_MSC_VER) || defined(__MWERKS__) || defined(__BORLANDC__)
|
||||
#ifdef __BORLANDC__
|
||||
#pragma nopackwarning
|
||||
#endif
|
||||
#pragma pack(pop)
|
||||
#endif /* Compiler needs structure packing set */
|
||||
@@ -0,0 +1,343 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryDialog
|
||||
*
|
||||
* File dialog support.
|
||||
*
|
||||
* SDL offers file dialogs, to let users select files with native GUI
|
||||
* interfaces. There are "open" dialogs, "save" dialogs, and folder selection
|
||||
* dialogs. The app can control some details, such as filtering to specific
|
||||
* files, or whether multiple files can be selected by the user.
|
||||
*
|
||||
* Note that launching a file dialog is a non-blocking operation; control
|
||||
* returns to the app immediately, and a callback is called later (possibly in
|
||||
* another thread) when the user makes a choice.
|
||||
*/
|
||||
|
||||
#ifndef SDL_dialog_h_
|
||||
#define SDL_dialog_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An entry for filters for file dialogs.
|
||||
*
|
||||
* `name` is a user-readable label for the filter (for example, "Office
|
||||
* document").
|
||||
*
|
||||
* `pattern` is a semicolon-separated list of file extensions (for example,
|
||||
* "doc;docx"). File extensions may only contain alphanumeric characters,
|
||||
* hyphens, underscores and periods. Alternatively, the whole string can be a
|
||||
* single asterisk ("*"), which serves as an "All files" filter.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DialogFileCallback
|
||||
* \sa SDL_ShowOpenFileDialog
|
||||
* \sa SDL_ShowSaveFileDialog
|
||||
* \sa SDL_ShowOpenFolderDialog
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
typedef struct SDL_DialogFileFilter
|
||||
{
|
||||
const char *name;
|
||||
const char *pattern;
|
||||
} SDL_DialogFileFilter;
|
||||
|
||||
/**
|
||||
* Callback used by file dialog functions.
|
||||
*
|
||||
* The specific usage is described in each function.
|
||||
*
|
||||
* If `filelist` is:
|
||||
*
|
||||
* - NULL, an error occurred. Details can be obtained with SDL_GetError().
|
||||
* - A pointer to NULL, the user either didn't choose any file or canceled the
|
||||
* dialog.
|
||||
* - A pointer to non-`NULL`, the user chose one or more files. The argument
|
||||
* is a null-terminated array of pointers to UTF-8 encoded strings, each
|
||||
* containing a path.
|
||||
*
|
||||
* The filelist argument should not be freed; it will automatically be freed
|
||||
* when the callback returns.
|
||||
*
|
||||
* The filter argument is the index of the filter that was selected, or -1 if
|
||||
* no filter was selected or if the platform or method doesn't support
|
||||
* fetching the selected filter.
|
||||
*
|
||||
* In Android, the `filelist` are `content://` URIs. They should be opened
|
||||
* using SDL_IOFromFile() with appropriate modes. This applies both to open
|
||||
* and save file dialog.
|
||||
*
|
||||
* \param userdata an app-provided pointer, for the callback's use.
|
||||
* \param filelist the file(s) chosen by the user.
|
||||
* \param filter index of the selected filter.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DialogFileFilter
|
||||
* \sa SDL_ShowOpenFileDialog
|
||||
* \sa SDL_ShowSaveFileDialog
|
||||
* \sa SDL_ShowOpenFolderDialog
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_DialogFileCallback)(void *userdata, const char * const *filelist, int filter);
|
||||
|
||||
/**
|
||||
* Displays a dialog that lets the user select a file on their filesystem.
|
||||
*
|
||||
* This is an asynchronous function; it will return immediately, and the
|
||||
* result will be passed to the callback.
|
||||
*
|
||||
* The callback will be invoked with a null-terminated list of files the user
|
||||
* chose. The list will be empty if the user canceled the dialog, and it will
|
||||
* be NULL if an error occurred.
|
||||
*
|
||||
* Note that the callback may be called from a different thread than the one
|
||||
* the function was invoked on.
|
||||
*
|
||||
* Depending on the platform, the user may be allowed to input paths that
|
||||
* don't yet exist.
|
||||
*
|
||||
* On Linux, dialogs may require XDG Portals, which requires DBus, which
|
||||
* requires an event-handling loop. Apps that do not use SDL to handle events
|
||||
* should add a call to SDL_PumpEvents in their main loop.
|
||||
*
|
||||
* \param callback a function pointer to be invoked when the user selects a
|
||||
* file and accepts, or cancels the dialog, or an error
|
||||
* occurs.
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
* \param window the window that the dialog should be modal for, may be NULL.
|
||||
* Not all platforms support this option.
|
||||
* \param filters a list of filters, may be NULL. See the
|
||||
* [`SDL_DialogFileFilter`](SDL_DialogFileFilter#code-examples)
|
||||
* documentation for examples]. Not all platforms support this
|
||||
* option, and platforms that do support it may allow the user
|
||||
* to ignore the filters. If non-NULL, it must remain valid at
|
||||
* least until the callback is invoked.
|
||||
* \param nfilters the number of filters. Ignored if filters is NULL.
|
||||
* \param default_location the default folder or file to start the dialog at,
|
||||
* may be NULL. Not all platforms support this option.
|
||||
* \param allow_many if non-zero, the user will be allowed to select multiple
|
||||
* entries. Not all platforms support this option.
|
||||
*
|
||||
* \threadsafety This function should be called only from the main thread. The
|
||||
* callback may be invoked from the same thread or from a
|
||||
* different one, depending on the OS's constraints.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DialogFileCallback
|
||||
* \sa SDL_DialogFileFilter
|
||||
* \sa SDL_ShowSaveFileDialog
|
||||
* \sa SDL_ShowOpenFolderDialog
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location, bool allow_many);
|
||||
|
||||
/**
|
||||
* Displays a dialog that lets the user choose a new or existing file on their
|
||||
* filesystem.
|
||||
*
|
||||
* This is an asynchronous function; it will return immediately, and the
|
||||
* result will be passed to the callback.
|
||||
*
|
||||
* The callback will be invoked with a null-terminated list of files the user
|
||||
* chose. The list will be empty if the user canceled the dialog, and it will
|
||||
* be NULL if an error occurred.
|
||||
*
|
||||
* Note that the callback may be called from a different thread than the one
|
||||
* the function was invoked on.
|
||||
*
|
||||
* The chosen file may or may not already exist.
|
||||
*
|
||||
* On Linux, dialogs may require XDG Portals, which requires DBus, which
|
||||
* requires an event-handling loop. Apps that do not use SDL to handle events
|
||||
* should add a call to SDL_PumpEvents in their main loop.
|
||||
*
|
||||
* \param callback a function pointer to be invoked when the user selects a
|
||||
* file and accepts, or cancels the dialog, or an error
|
||||
* occurs.
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
* \param window the window that the dialog should be modal for, may be NULL.
|
||||
* Not all platforms support this option.
|
||||
* \param filters a list of filters, may be NULL. Not all platforms support
|
||||
* this option, and platforms that do support it may allow the
|
||||
* user to ignore the filters. If non-NULL, it must remain
|
||||
* valid at least until the callback is invoked.
|
||||
* \param nfilters the number of filters. Ignored if filters is NULL.
|
||||
* \param default_location the default folder or file to start the dialog at,
|
||||
* may be NULL. Not all platforms support this option.
|
||||
*
|
||||
* \threadsafety This function should be called only from the main thread. The
|
||||
* callback may be invoked from the same thread or from a
|
||||
* different one, depending on the OS's constraints.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DialogFileCallback
|
||||
* \sa SDL_DialogFileFilter
|
||||
* \sa SDL_ShowOpenFileDialog
|
||||
* \sa SDL_ShowOpenFolderDialog
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ShowSaveFileDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const SDL_DialogFileFilter *filters, int nfilters, const char *default_location);
|
||||
|
||||
/**
|
||||
* Displays a dialog that lets the user select a folder on their filesystem.
|
||||
*
|
||||
* This is an asynchronous function; it will return immediately, and the
|
||||
* result will be passed to the callback.
|
||||
*
|
||||
* The callback will be invoked with a null-terminated list of files the user
|
||||
* chose. The list will be empty if the user canceled the dialog, and it will
|
||||
* be NULL if an error occurred.
|
||||
*
|
||||
* Note that the callback may be called from a different thread than the one
|
||||
* the function was invoked on.
|
||||
*
|
||||
* Depending on the platform, the user may be allowed to input paths that
|
||||
* don't yet exist.
|
||||
*
|
||||
* On Linux, dialogs may require XDG Portals, which requires DBus, which
|
||||
* requires an event-handling loop. Apps that do not use SDL to handle events
|
||||
* should add a call to SDL_PumpEvents in their main loop.
|
||||
*
|
||||
* \param callback a function pointer to be invoked when the user selects a
|
||||
* file and accepts, or cancels the dialog, or an error
|
||||
* occurs.
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
* \param window the window that the dialog should be modal for, may be NULL.
|
||||
* Not all platforms support this option.
|
||||
* \param default_location the default folder or file to start the dialog at,
|
||||
* may be NULL. Not all platforms support this option.
|
||||
* \param allow_many if non-zero, the user will be allowed to select multiple
|
||||
* entries. Not all platforms support this option.
|
||||
*
|
||||
* \threadsafety This function should be called only from the main thread. The
|
||||
* callback may be invoked from the same thread or from a
|
||||
* different one, depending on the OS's constraints.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DialogFileCallback
|
||||
* \sa SDL_ShowOpenFileDialog
|
||||
* \sa SDL_ShowSaveFileDialog
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ShowOpenFolderDialog(SDL_DialogFileCallback callback, void *userdata, SDL_Window *window, const char *default_location, bool allow_many);
|
||||
|
||||
/**
|
||||
* Various types of file dialogs.
|
||||
*
|
||||
* This is used by SDL_ShowFileDialogWithProperties() to decide what kind of
|
||||
* dialog to present to the user.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ShowFileDialogWithProperties
|
||||
*/
|
||||
typedef enum SDL_FileDialogType
|
||||
{
|
||||
SDL_FILEDIALOG_OPENFILE,
|
||||
SDL_FILEDIALOG_SAVEFILE,
|
||||
SDL_FILEDIALOG_OPENFOLDER
|
||||
} SDL_FileDialogType;
|
||||
|
||||
/**
|
||||
* Create and launch a file dialog with the specified properties.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_FILE_DIALOG_FILTERS_POINTER`: a pointer to a list of
|
||||
* SDL_DialogFileFilter structs, which will be used as filters for
|
||||
* file-based selections. Ignored if the dialog is an "Open Folder" dialog.
|
||||
* If non-NULL, the array of filters must remain valid at least until the
|
||||
* callback is invoked.
|
||||
* - `SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER`: the number of filters in the
|
||||
* array of filters, if it exists.
|
||||
* - `SDL_PROP_FILE_DIALOG_WINDOW_POINTER`: the window that the dialog should
|
||||
* be modal for.
|
||||
* - `SDL_PROP_FILE_DIALOG_LOCATION_STRING`: the default folder or file to
|
||||
* start the dialog at.
|
||||
* - `SDL_PROP_FILE_DIALOG_MANY_BOOLEAN`: true to allow the user to select
|
||||
* more than one entry.
|
||||
* - `SDL_PROP_FILE_DIALOG_TITLE_STRING`: the title for the dialog.
|
||||
* - `SDL_PROP_FILE_DIALOG_ACCEPT_STRING`: the label that the accept button
|
||||
* should have.
|
||||
* - `SDL_PROP_FILE_DIALOG_CANCEL_STRING`: the label that the cancel button
|
||||
* should have.
|
||||
*
|
||||
* Note that each platform may or may not support any of the properties.
|
||||
*
|
||||
* \param type the type of file dialog.
|
||||
* \param callback a function pointer to be invoked when the user selects a
|
||||
* file and accepts, or cancels the dialog, or an error
|
||||
* occurs.
|
||||
* \param userdata an optional pointer to pass extra data to the callback when
|
||||
* it will be invoked.
|
||||
* \param props the properties to use.
|
||||
*
|
||||
* \threadsafety This function should be called only from the main thread. The
|
||||
* callback may be invoked from the same thread or from a
|
||||
* different one, depending on the OS's constraints.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_FileDialogType
|
||||
* \sa SDL_DialogFileCallback
|
||||
* \sa SDL_DialogFileFilter
|
||||
* \sa SDL_ShowOpenFileDialog
|
||||
* \sa SDL_ShowSaveFileDialog
|
||||
* \sa SDL_ShowOpenFolderDialog
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ShowFileDialogWithProperties(SDL_FileDialogType type, SDL_DialogFileCallback callback, void *userdata, SDL_PropertiesID props);
|
||||
|
||||
#define SDL_PROP_FILE_DIALOG_FILTERS_POINTER "SDL.filedialog.filters"
|
||||
#define SDL_PROP_FILE_DIALOG_NFILTERS_NUMBER "SDL.filedialog.nfilters"
|
||||
#define SDL_PROP_FILE_DIALOG_WINDOW_POINTER "SDL.filedialog.window"
|
||||
#define SDL_PROP_FILE_DIALOG_LOCATION_STRING "SDL.filedialog.location"
|
||||
#define SDL_PROP_FILE_DIALOG_MANY_BOOLEAN "SDL.filedialog.many"
|
||||
#define SDL_PROP_FILE_DIALOG_TITLE_STRING "SDL.filedialog.title"
|
||||
#define SDL_PROP_FILE_DIALOG_ACCEPT_STRING "SDL.filedialog.accept"
|
||||
#define SDL_PROP_FILE_DIALOG_CANCEL_STRING "SDL.filedialog.cancel"
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_dialog_h_ */
|
||||
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryEndian
|
||||
*
|
||||
* Functions converting endian-specific values to different byte orders.
|
||||
*
|
||||
* These functions either unconditionally swap byte order (SDL_Swap16,
|
||||
* SDL_Swap32, SDL_Swap64, SDL_SwapFloat), or they swap to/from the system's
|
||||
* native byte order (SDL_Swap16LE, SDL_Swap16BE, SDL_Swap32LE, SDL_Swap32BE,
|
||||
* SDL_Swap32LE, SDL_Swap32BE, SDL_SwapFloatLE, SDL_SwapFloatBE). In the
|
||||
* latter case, the functionality is provided by macros that become no-ops if
|
||||
* a swap isn't necessary: on an x86 (littleendian) processor, SDL_Swap32LE
|
||||
* does nothing, but SDL_Swap32BE reverses the bytes of the data. On a PowerPC
|
||||
* processor (bigendian), the macros behavior is reversed.
|
||||
*
|
||||
* The swap routines are inline functions, and attempt to use compiler
|
||||
* intrinsics, inline assembly, and other magic to make byteswapping
|
||||
* efficient.
|
||||
*/
|
||||
|
||||
#ifndef SDL_endian_h_
|
||||
#define SDL_endian_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1400)
|
||||
/* As of Clang 11, '_m_prefetchw' is conflicting with the winnt.h's version,
|
||||
so we define the needed '_m_prefetch' here as a pseudo-header, until the issue is fixed. */
|
||||
#if defined(__clang__) && !SDL_HAS_BUILTIN(_m_prefetch)
|
||||
#ifndef __PRFCHWINTRIN_H
|
||||
#define __PRFCHWINTRIN_H
|
||||
static __inline__ void __attribute__((__always_inline__, __nodebug__))
|
||||
_m_prefetch(void *__P)
|
||||
{
|
||||
__builtin_prefetch(__P, 0, 3 /* _MM_HINT_T0 */);
|
||||
}
|
||||
#endif /* __PRFCHWINTRIN_H */
|
||||
#endif /* __clang__ */
|
||||
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \name The two types of endianness
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
|
||||
/**
|
||||
* A value to represent littleendian byteorder.
|
||||
*
|
||||
* This is used with the preprocessor macro SDL_BYTEORDER, to determine a
|
||||
* platform's byte ordering:
|
||||
*
|
||||
* ```c
|
||||
* #if SDL_BYTEORDER == SDL_LIL_ENDIAN
|
||||
* SDL_Log("This system is littleendian.");
|
||||
* #endif
|
||||
* ```
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_BYTEORDER
|
||||
* \sa SDL_BIG_ENDIAN
|
||||
*/
|
||||
#define SDL_LIL_ENDIAN 1234
|
||||
|
||||
/**
|
||||
* A value to represent bigendian byteorder.
|
||||
*
|
||||
* This is used with the preprocessor macro SDL_BYTEORDER, to determine a
|
||||
* platform's byte ordering:
|
||||
*
|
||||
* ```c
|
||||
* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
* SDL_Log("This system is bigendian.");
|
||||
* #endif
|
||||
* ```
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_BYTEORDER
|
||||
* \sa SDL_LIL_ENDIAN
|
||||
*/
|
||||
#define SDL_BIG_ENDIAN 4321
|
||||
|
||||
/* @} */
|
||||
|
||||
#ifndef SDL_BYTEORDER
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A macro that reports the target system's byte order.
|
||||
*
|
||||
* This is set to either SDL_LIL_ENDIAN or SDL_BIG_ENDIAN (and maybe other
|
||||
* values in the future, if something else becomes popular). This can be
|
||||
* tested with the preprocessor, so decisions can be made at compile time.
|
||||
*
|
||||
* ```c
|
||||
* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
* SDL_Log("This system is bigendian.");
|
||||
* #endif
|
||||
* ```
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LIL_ENDIAN
|
||||
* \sa SDL_BIG_ENDIAN
|
||||
*/
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN___or_maybe___SDL_BIG_ENDIAN
|
||||
#elif defined(SDL_PLATFORM_LINUX) || defined(__GLIBC__)
|
||||
#include <endian.h>
|
||||
#define SDL_BYTEORDER __BYTE_ORDER
|
||||
#elif defined(SDL_PLATFORM_SOLARIS)
|
||||
#include <sys/byteorder.h>
|
||||
#if defined(_LITTLE_ENDIAN)
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN
|
||||
#elif defined(_BIG_ENDIAN)
|
||||
#define SDL_BYTEORDER SDL_BIG_ENDIAN
|
||||
#else
|
||||
#error Unsupported endianness
|
||||
#endif
|
||||
#elif defined(SDL_PLATFORM_OPENBSD) || defined(__DragonFly__)
|
||||
#include <endian.h>
|
||||
#define SDL_BYTEORDER BYTE_ORDER
|
||||
#elif defined(SDL_PLATFORM_FREEBSD) || defined(SDL_PLATFORM_NETBSD)
|
||||
#include <sys/endian.h>
|
||||
#define SDL_BYTEORDER BYTE_ORDER
|
||||
/* predefs from newer gcc and clang versions: */
|
||||
#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__BYTE_ORDER__)
|
||||
#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN
|
||||
#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define SDL_BYTEORDER SDL_BIG_ENDIAN
|
||||
#else
|
||||
#error Unsupported endianness
|
||||
#endif /**/
|
||||
#else
|
||||
#if defined(__hppa__) || \
|
||||
defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
|
||||
(defined(__MIPS__) && defined(__MIPSEB__)) || \
|
||||
defined(__ppc__) || defined(__POWERPC__) || defined(__powerpc__) || defined(__PPC__) || \
|
||||
defined(__sparc__) || defined(__sparc)
|
||||
#define SDL_BYTEORDER SDL_BIG_ENDIAN
|
||||
#else
|
||||
#define SDL_BYTEORDER SDL_LIL_ENDIAN
|
||||
#endif
|
||||
#endif /* SDL_PLATFORM_LINUX */
|
||||
#endif /* !SDL_BYTEORDER */
|
||||
|
||||
#ifndef SDL_FLOATWORDORDER
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A macro that reports the target system's floating point word order.
|
||||
*
|
||||
* This is set to either SDL_LIL_ENDIAN or SDL_BIG_ENDIAN (and maybe other
|
||||
* values in the future, if something else becomes popular). This can be
|
||||
* tested with the preprocessor, so decisions can be made at compile time.
|
||||
*
|
||||
* ```c
|
||||
* #if SDL_FLOATWORDORDER == SDL_BIG_ENDIAN
|
||||
* SDL_Log("This system's floats are bigendian.");
|
||||
* #endif
|
||||
* ```
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LIL_ENDIAN
|
||||
* \sa SDL_BIG_ENDIAN
|
||||
*/
|
||||
#define SDL_FLOATWORDORDER SDL_LIL_ENDIAN___or_maybe___SDL_BIG_ENDIAN
|
||||
/* predefs from newer gcc versions: */
|
||||
#elif defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
|
||||
#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define SDL_FLOATWORDORDER SDL_LIL_ENDIAN
|
||||
#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define SDL_FLOATWORDORDER SDL_BIG_ENDIAN
|
||||
#else
|
||||
#error Unsupported endianness
|
||||
#endif /**/
|
||||
#elif defined(__MAVERICK__)
|
||||
/* For Maverick, float words are always little-endian. */
|
||||
#define SDL_FLOATWORDORDER SDL_LIL_ENDIAN
|
||||
#elif (defined(__arm__) || defined(__thumb__)) && !defined(__VFP_FP__) && !defined(__ARM_EABI__)
|
||||
/* For FPA, float words are always big-endian. */
|
||||
#define SDL_FLOATWORDORDER SDL_BIG_ENDIAN
|
||||
#else
|
||||
/* By default, assume that floats words follow the memory system mode. */
|
||||
#define SDL_FLOATWORDORDER SDL_BYTEORDER
|
||||
#endif /* SDL_WIKI_DOCUMENTATION_SECTION */
|
||||
#endif /* !SDL_FLOATWORDORDER */
|
||||
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* various modern compilers may have builtin swap */
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define HAS_BUILTIN_BSWAP16 (SDL_HAS_BUILTIN(__builtin_bswap16)) || \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
||||
# define HAS_BUILTIN_BSWAP32 (SDL_HAS_BUILTIN(__builtin_bswap32)) || \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||
# define HAS_BUILTIN_BSWAP64 (SDL_HAS_BUILTIN(__builtin_bswap64)) || \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
||||
|
||||
/* this one is broken */
|
||||
# define HAS_BROKEN_BSWAP (__GNUC__ == 2 && __GNUC_MINOR__ <= 95)
|
||||
#else
|
||||
# define HAS_BUILTIN_BSWAP16 0
|
||||
# define HAS_BUILTIN_BSWAP32 0
|
||||
# define HAS_BUILTIN_BSWAP64 0
|
||||
# define HAS_BROKEN_BSWAP 0
|
||||
#endif
|
||||
|
||||
/* Byte swap 16-bit integer. */
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
#if HAS_BUILTIN_BSWAP16
|
||||
#define SDL_Swap16(x) __builtin_bswap16(x)
|
||||
#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
|
||||
#pragma intrinsic(_byteswap_ushort)
|
||||
#define SDL_Swap16(x) _byteswap_ushort(x)
|
||||
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0": "=q"(x):"0"(x));
|
||||
return x;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
|
||||
{
|
||||
__asm__("xchgb %b0,%h0": "=abcd"(x):"0"(x));
|
||||
return x;
|
||||
}
|
||||
#elif (defined(__powerpc__) || defined(__ppc__))
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
|
||||
{
|
||||
int result;
|
||||
|
||||
__asm__("rlwimi %0,%2,8,16,23": "=&r"(result):"0"(x >> 8), "r"(x));
|
||||
return (Uint16)result;
|
||||
}
|
||||
#elif (defined(__m68k__) && !defined(__mcoldfire__))
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
|
||||
{
|
||||
__asm__("rorw #8,%0": "=d"(x): "0"(x):"cc");
|
||||
return x;
|
||||
}
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
extern __inline Uint16 SDL_Swap16(Uint16);
|
||||
#pragma aux SDL_Swap16 = \
|
||||
"xchg al, ah" \
|
||||
parm [ax] \
|
||||
modify [ax];
|
||||
#else
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x)
|
||||
{
|
||||
return SDL_static_cast(Uint16, ((x << 8) | (x >> 8)));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Byte swap 32-bit integer. */
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
#if HAS_BUILTIN_BSWAP32
|
||||
#define SDL_Swap32(x) __builtin_bswap32(x)
|
||||
#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
|
||||
#pragma intrinsic(_byteswap_ulong)
|
||||
#define SDL_Swap32(x) _byteswap_ulong(x)
|
||||
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
|
||||
{
|
||||
__asm__("bswap %0": "=r"(x):"0"(x));
|
||||
return x;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
|
||||
{
|
||||
__asm__("bswapl %0": "=r"(x):"0"(x));
|
||||
return x;
|
||||
}
|
||||
#elif (defined(__powerpc__) || defined(__ppc__))
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
|
||||
{
|
||||
Uint32 result;
|
||||
|
||||
__asm__("rlwimi %0,%2,24,16,23": "=&r"(result): "0" (x>>24), "r"(x));
|
||||
__asm__("rlwimi %0,%2,8,8,15" : "=&r"(result): "0" (result), "r"(x));
|
||||
__asm__("rlwimi %0,%2,24,0,7" : "=&r"(result): "0" (result), "r"(x));
|
||||
return result;
|
||||
}
|
||||
#elif (defined(__m68k__) && !defined(__mcoldfire__))
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
|
||||
{
|
||||
__asm__("rorw #8,%0\n\tswap %0\n\trorw #8,%0": "=d"(x): "0"(x):"cc");
|
||||
return x;
|
||||
}
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
extern __inline Uint32 SDL_Swap32(Uint32);
|
||||
#pragma aux SDL_Swap32 = \
|
||||
"bswap eax" \
|
||||
parm [eax] \
|
||||
modify [eax];
|
||||
#else
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x)
|
||||
{
|
||||
return SDL_static_cast(Uint32, ((x << 24) | ((x << 8) & 0x00FF0000) |
|
||||
((x >> 8) & 0x0000FF00) | (x >> 24)));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Byte swap 64-bit integer. */
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
#if HAS_BUILTIN_BSWAP64
|
||||
#define SDL_Swap64(x) __builtin_bswap64(x)
|
||||
#elif (defined(_MSC_VER) && (_MSC_VER >= 1400)) && !defined(__ICL)
|
||||
#pragma intrinsic(_byteswap_uint64)
|
||||
#define SDL_Swap64(x) _byteswap_uint64(x)
|
||||
#elif defined(__i386__) && !HAS_BROKEN_BSWAP
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x)
|
||||
{
|
||||
union {
|
||||
struct {
|
||||
Uint32 a, b;
|
||||
} s;
|
||||
Uint64 u;
|
||||
} v;
|
||||
v.u = x;
|
||||
__asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1"
|
||||
: "=r"(v.s.a), "=r"(v.s.b)
|
||||
: "0" (v.s.a), "1"(v.s.b));
|
||||
return v.u;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x)
|
||||
{
|
||||
__asm__("bswapq %0": "=r"(x):"0"(x));
|
||||
return x;
|
||||
}
|
||||
#elif defined(__WATCOMC__) && defined(__386__)
|
||||
extern __inline Uint64 SDL_Swap64(Uint64);
|
||||
#pragma aux SDL_Swap64 = \
|
||||
"bswap eax" \
|
||||
"bswap edx" \
|
||||
"xchg eax,edx" \
|
||||
parm [eax edx] \
|
||||
modify [eax edx];
|
||||
#else
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x)
|
||||
{
|
||||
Uint32 hi, lo;
|
||||
|
||||
/* Separate into high and low 32-bit values and swap them */
|
||||
lo = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
|
||||
x >>= 32;
|
||||
hi = SDL_static_cast(Uint32, x & 0xFFFFFFFF);
|
||||
x = SDL_Swap32(lo);
|
||||
x <<= 32;
|
||||
x |= SDL_Swap32(hi);
|
||||
return (x);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Byte-swap a floating point number.
|
||||
*
|
||||
* This will always byte-swap the value, whether it's currently in the native
|
||||
* byteorder of the system or not. You should use SDL_SwapFloatLE or
|
||||
* SDL_SwapFloatBE instead, in most cases.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param x the value to byte-swap.
|
||||
* \returns x, with its bytes in the opposite endian order.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE float SDL_SwapFloat(float x)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
Uint32 ui32;
|
||||
} swapper;
|
||||
swapper.f = x;
|
||||
swapper.ui32 = SDL_Swap32(swapper.ui32);
|
||||
return swapper.f;
|
||||
}
|
||||
|
||||
/* remove extra macros */
|
||||
#undef HAS_BROKEN_BSWAP
|
||||
#undef HAS_BUILTIN_BSWAP16
|
||||
#undef HAS_BUILTIN_BSWAP32
|
||||
#undef HAS_BUILTIN_BSWAP64
|
||||
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* Byte-swap an unsigned 16-bit number.
|
||||
*
|
||||
* This will always byte-swap the value, whether it's currently in the native
|
||||
* byteorder of the system or not. You should use SDL_Swap16LE or SDL_Swap16BE
|
||||
* instead, in most cases.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param x the value to byte-swap.
|
||||
* \returns `x`, with its bytes in the opposite endian order.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint16 SDL_Swap16(Uint16 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Byte-swap an unsigned 32-bit number.
|
||||
*
|
||||
* This will always byte-swap the value, whether it's currently in the native
|
||||
* byteorder of the system or not. You should use SDL_Swap32LE or SDL_Swap32BE
|
||||
* instead, in most cases.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param x the value to byte-swap.
|
||||
* \returns `x`, with its bytes in the opposite endian order.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint32 SDL_Swap32(Uint32 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Byte-swap an unsigned 64-bit number.
|
||||
*
|
||||
* This will always byte-swap the value, whether it's currently in the native
|
||||
* byteorder of the system or not. You should use SDL_Swap64LE or SDL_Swap64BE
|
||||
* instead, in most cases.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param x the value to byte-swap.
|
||||
* \returns `x`, with its bytes in the opposite endian order.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE Uint64 SDL_Swap64(Uint64 x) { return x_but_byteswapped; }
|
||||
|
||||
/**
|
||||
* Swap a 16-bit value from littleendian to native byte order.
|
||||
*
|
||||
* If this is running on a littleendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in littleendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap16LE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a 32-bit value from littleendian to native byte order.
|
||||
*
|
||||
* If this is running on a littleendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in littleendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap32LE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a 64-bit value from littleendian to native byte order.
|
||||
*
|
||||
* If this is running on a littleendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in littleendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap64LE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a floating point value from littleendian to native byte order.
|
||||
*
|
||||
* If this is running on a littleendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in littleendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_SwapFloatLE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a 16-bit value from bigendian to native byte order.
|
||||
*
|
||||
* If this is running on a bigendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in bigendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap16BE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a 32-bit value from bigendian to native byte order.
|
||||
*
|
||||
* If this is running on a bigendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in bigendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap32BE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a 64-bit value from bigendian to native byte order.
|
||||
*
|
||||
* If this is running on a bigendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in bigendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Swap64BE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
/**
|
||||
* Swap a floating point value from bigendian to native byte order.
|
||||
*
|
||||
* If this is running on a bigendian system, `x` is returned unchanged.
|
||||
*
|
||||
* This macro never references `x` more than once, avoiding side effects.
|
||||
*
|
||||
* \param x the value to swap, in bigendian byte order.
|
||||
* \returns `x` in native byte order.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_SwapFloatBE(x) SwapOnlyIfNecessary(x)
|
||||
|
||||
#elif SDL_BYTEORDER == SDL_LIL_ENDIAN
|
||||
#define SDL_Swap16LE(x) (x)
|
||||
#define SDL_Swap32LE(x) (x)
|
||||
#define SDL_Swap64LE(x) (x)
|
||||
#define SDL_SwapFloatLE(x) (x)
|
||||
#define SDL_Swap16BE(x) SDL_Swap16(x)
|
||||
#define SDL_Swap32BE(x) SDL_Swap32(x)
|
||||
#define SDL_Swap64BE(x) SDL_Swap64(x)
|
||||
#define SDL_SwapFloatBE(x) SDL_SwapFloat(x)
|
||||
#else
|
||||
#define SDL_Swap16LE(x) SDL_Swap16(x)
|
||||
#define SDL_Swap32LE(x) SDL_Swap32(x)
|
||||
#define SDL_Swap64LE(x) SDL_Swap64(x)
|
||||
#define SDL_SwapFloatLE(x) SDL_SwapFloat(x)
|
||||
#define SDL_Swap16BE(x) (x)
|
||||
#define SDL_Swap32BE(x) (x)
|
||||
#define SDL_Swap64BE(x) (x)
|
||||
#define SDL_SwapFloatBE(x) (x)
|
||||
#endif
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_endian_h_ */
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryError
|
||||
*
|
||||
* Simple error message routines for SDL.
|
||||
*
|
||||
* Most apps will interface with these APIs in exactly one function: when
|
||||
* almost any SDL function call reports failure, you can get a human-readable
|
||||
* string of the problem from SDL_GetError().
|
||||
*
|
||||
* These strings are maintained per-thread, and apps are welcome to set their
|
||||
* own errors, which is popular when building libraries on top of SDL for
|
||||
* other apps to consume. These strings are set by calling SDL_SetError().
|
||||
*
|
||||
* A common usage pattern is to have a function that returns true for success
|
||||
* and false for failure, and do this when something fails:
|
||||
*
|
||||
* ```c
|
||||
* if (something_went_wrong) {
|
||||
* return SDL_SetError("The thing broke in this specific way: %d", errcode);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* It's also common to just return `false` in this case if the failing thing
|
||||
* is known to call SDL_SetError(), so errors simply propagate through.
|
||||
*/
|
||||
|
||||
#ifndef SDL_error_h_
|
||||
#define SDL_error_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Public functions */
|
||||
|
||||
|
||||
/**
|
||||
* Set the SDL error message for the current thread.
|
||||
*
|
||||
* Calling this function will replace any previous error message that was set.
|
||||
*
|
||||
* This function always returns false, since SDL frequently uses false to
|
||||
* signify a failing result, leading to this idiom:
|
||||
*
|
||||
* ```c
|
||||
* if (error_code) {
|
||||
* return SDL_SetError("This operation has failed: %d", error_code);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* \param fmt a printf()-style message format string.
|
||||
* \param ... additional parameters matching % tokens in the `fmt` string, if
|
||||
* any.
|
||||
* \returns false.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ClearError
|
||||
* \sa SDL_GetError
|
||||
* \sa SDL_SetErrorV
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(1);
|
||||
|
||||
/**
|
||||
* Set the SDL error message for the current thread.
|
||||
*
|
||||
* Calling this function will replace any previous error message that was set.
|
||||
*
|
||||
* \param fmt a printf()-style message format string.
|
||||
* \param ap a variable argument list.
|
||||
* \returns false.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ClearError
|
||||
* \sa SDL_GetError
|
||||
* \sa SDL_SetError
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetErrorV(SDL_PRINTF_FORMAT_STRING const char *fmt, va_list ap) SDL_PRINTF_VARARG_FUNCV(1);
|
||||
|
||||
/**
|
||||
* Set an error indicating that memory allocation failed.
|
||||
*
|
||||
* This function does not do any memory allocation.
|
||||
*
|
||||
* \returns false.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_OutOfMemory(void);
|
||||
|
||||
/**
|
||||
* Retrieve a message about the last error that occurred on the current
|
||||
* thread.
|
||||
*
|
||||
* It is possible for multiple errors to occur before calling SDL_GetError().
|
||||
* Only the last error is returned.
|
||||
*
|
||||
* The message is only applicable when an SDL function has signaled an error.
|
||||
* You must check the return values of SDL function calls to determine when to
|
||||
* appropriately call SDL_GetError(). You should *not* use the results of
|
||||
* SDL_GetError() to decide if an error has occurred! Sometimes SDL will set
|
||||
* an error string even when reporting success.
|
||||
*
|
||||
* SDL will *not* clear the error string for successful API calls. You *must*
|
||||
* check return values for failure cases before you can assume the error
|
||||
* string applies.
|
||||
*
|
||||
* Error strings are set per-thread, so an error set in a different thread
|
||||
* will not interfere with the current thread's operation.
|
||||
*
|
||||
* The returned value is a thread-local string which will remain valid until
|
||||
* the current thread's error string is changed. The caller should make a copy
|
||||
* if the value is needed after the next SDL API call.
|
||||
*
|
||||
* \returns a message with information about the specific error that occurred,
|
||||
* or an empty string if there hasn't been an error message set since
|
||||
* the last call to SDL_ClearError().
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ClearError
|
||||
* \sa SDL_SetError
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetError(void);
|
||||
|
||||
/**
|
||||
* Clear any previous error message for this thread.
|
||||
*
|
||||
* \returns true.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetError
|
||||
* \sa SDL_SetError
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearError(void);
|
||||
|
||||
/**
|
||||
* \name Internal error functions
|
||||
*
|
||||
* \internal
|
||||
* Private error reporting function - used internally.
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
/**
|
||||
* A macro to standardize error reporting on unsupported operations.
|
||||
*
|
||||
* This simply calls SDL_SetError() with a standardized error string, for
|
||||
* convenience, consistency, and clarity.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_Unsupported() SDL_SetError("That operation is not supported")
|
||||
|
||||
/**
|
||||
* A macro to standardize error reporting on unsupported operations.
|
||||
*
|
||||
* This simply calls SDL_SetError() with a standardized error string, for
|
||||
* convenience, consistency, and clarity.
|
||||
*
|
||||
* A common usage pattern inside SDL is this:
|
||||
*
|
||||
* ```c
|
||||
* bool MyFunction(const char *str) {
|
||||
* if (!str) {
|
||||
* return SDL_InvalidParamError("str"); // returns false.
|
||||
* }
|
||||
* DoSomething(str);
|
||||
* return true;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_InvalidParamError(param) SDL_SetError("Parameter '%s' is invalid", (param))
|
||||
|
||||
/* @} *//* Internal error functions */
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_error_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryFilesystem
|
||||
*
|
||||
* SDL offers an API for examining and manipulating the system's filesystem.
|
||||
* This covers most things one would need to do with directories, except for
|
||||
* actual file I/O (which is covered by [CategoryIOStream](CategoryIOStream)
|
||||
* and [CategoryAsyncIO](CategoryAsyncIO) instead).
|
||||
*
|
||||
* There are functions to answer necessary path questions:
|
||||
*
|
||||
* - Where is my app's data? SDL_GetBasePath().
|
||||
* - Where can I safely write files? SDL_GetPrefPath().
|
||||
* - Where are paths like Downloads, Desktop, Music? SDL_GetUserFolder().
|
||||
* - What is this thing at this location? SDL_GetPathInfo().
|
||||
* - What items live in this folder? SDL_EnumerateDirectory().
|
||||
* - What items live in this folder by wildcard? SDL_GlobDirectory().
|
||||
* - What is my current working directory? SDL_GetCurrentDirectory().
|
||||
*
|
||||
* SDL also offers functions to manipulate the directory tree: renaming,
|
||||
* removing, copying files.
|
||||
*/
|
||||
|
||||
#ifndef SDL_filesystem_h_
|
||||
#define SDL_filesystem_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get the directory where the application was run from.
|
||||
*
|
||||
* SDL caches the result of this call internally, but the first call to this
|
||||
* function is not necessarily fast, so plan accordingly.
|
||||
*
|
||||
* **macOS and iOS Specific Functionality**: If the application is in a ".app"
|
||||
* bundle, this function returns the Resource directory (e.g.
|
||||
* MyApp.app/Contents/Resources/). This behaviour can be overridden by adding
|
||||
* a property to the Info.plist file. Adding a string key with the name
|
||||
* SDL_FILESYSTEM_BASE_DIR_TYPE with a supported value will change the
|
||||
* behaviour.
|
||||
*
|
||||
* Supported values for the SDL_FILESYSTEM_BASE_DIR_TYPE property (Given an
|
||||
* application in /Applications/SDLApp/MyApp.app):
|
||||
*
|
||||
* - `resource`: bundle resource directory (the default). For example:
|
||||
* `/Applications/SDLApp/MyApp.app/Contents/Resources`
|
||||
* - `bundle`: the Bundle directory. For example:
|
||||
* `/Applications/SDLApp/MyApp.app/`
|
||||
* - `parent`: the containing directory of the bundle. For example:
|
||||
* `/Applications/SDLApp/`
|
||||
*
|
||||
* **Android Specific Functionality**: This function returns "./", which
|
||||
* allows filesystem operations to use internal storage and the asset system.
|
||||
*
|
||||
* **Nintendo 3DS Specific Functionality**: This function returns "romfs"
|
||||
* directory of the application as it is uncommon to store resources outside
|
||||
* the executable. As such it is not a writable directory.
|
||||
*
|
||||
* The returned path is guaranteed to end with a path separator ('\\' on
|
||||
* Windows, '/' on most other platforms).
|
||||
*
|
||||
* \returns an absolute path in UTF-8 encoding to the application data
|
||||
* directory. NULL will be returned on error or when the platform
|
||||
* doesn't implement this functionality, call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPrefPath
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetBasePath(void);
|
||||
|
||||
/**
|
||||
* Get the user-and-app-specific path where files can be written.
|
||||
*
|
||||
* Get the "pref dir". This is meant to be where users can write personal
|
||||
* files (preferences and save games, etc) that are specific to your
|
||||
* application. This directory is unique per user, per application.
|
||||
*
|
||||
* This function will decide the appropriate location in the native
|
||||
* filesystem, create the directory if necessary, and return a string of the
|
||||
* absolute path to the directory in UTF-8 encoding.
|
||||
*
|
||||
* On Windows, the string might look like:
|
||||
*
|
||||
* `C:\\Users\\bob\\AppData\\Roaming\\My Company\\My Program Name\\`
|
||||
*
|
||||
* On Linux, the string might look like:
|
||||
*
|
||||
* `/home/bob/.local/share/My Program Name/`
|
||||
*
|
||||
* On macOS, the string might look like:
|
||||
*
|
||||
* `/Users/bob/Library/Application Support/My Program Name/`
|
||||
*
|
||||
* You should assume the path returned by this function is the only safe place
|
||||
* to write files (and that SDL_GetBasePath(), while it might be writable, or
|
||||
* even the parent of the returned path, isn't where you should be writing
|
||||
* things).
|
||||
*
|
||||
* Both the org and app strings may become part of a directory name, so please
|
||||
* follow these rules:
|
||||
*
|
||||
* - Try to use the same org string (_including case-sensitivity_) for all
|
||||
* your applications that use this function.
|
||||
* - Always use a unique app string for each one, and make sure it never
|
||||
* changes for an app once you've decided on it.
|
||||
* - Unicode characters are legal, as long as they are UTF-8 encoded, but...
|
||||
* - ...only use letters, numbers, and spaces. Avoid punctuation like "Game
|
||||
* Name 2: Bad Guy's Revenge!" ... "Game Name 2" is sufficient.
|
||||
*
|
||||
* Due to historical mistakes, `org` is allowed to be NULL or "". In such
|
||||
* cases, SDL will omit the org subdirectory, including on platforms where it
|
||||
* shouldn't, and including on platforms where this would make your app fail
|
||||
* certification for an app store. New apps should definitely specify a real
|
||||
* string for `org`.
|
||||
*
|
||||
* The returned path is guaranteed to end with a path separator ('\\' on
|
||||
* Windows, '/' on most other platforms).
|
||||
*
|
||||
* \param org the name of your organization.
|
||||
* \param app the name of your application.
|
||||
* \returns a UTF-8 string of the user directory in platform-dependent
|
||||
* notation. NULL if there's a problem (creating directory failed,
|
||||
* etc.). This should be freed with SDL_free() when it is no longer
|
||||
* needed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetBasePath
|
||||
*/
|
||||
extern SDL_DECLSPEC char * SDLCALL SDL_GetPrefPath(const char *org, const char *app);
|
||||
|
||||
/**
|
||||
* The type of the OS-provided default folder for a specific purpose.
|
||||
*
|
||||
* Note that the Trash folder isn't included here, because trashing files
|
||||
* usually involves extra OS-specific functionality to remember the file's
|
||||
* original location.
|
||||
*
|
||||
* The folders supported per platform are:
|
||||
*
|
||||
* | | Windows | macOS/iOS | tvOS | Unix (XDG) | Haiku | Emscripten |
|
||||
* | ----------- | ------- | --------- | ---- | ---------- | ----- | ---------- |
|
||||
* | HOME | X | X | | X | X | X |
|
||||
* | DESKTOP | X | X | | X | X | |
|
||||
* | DOCUMENTS | X | X | | X | | |
|
||||
* | DOWNLOADS | Vista+ | X | | X | | |
|
||||
* | MUSIC | X | X | | X | | |
|
||||
* | PICTURES | X | X | | X | | |
|
||||
* | PUBLICSHARE | | X | | X | | |
|
||||
* | SAVEDGAMES | Vista+ | | | | | |
|
||||
* | SCREENSHOTS | Vista+ | | | | | |
|
||||
* | TEMPLATES | X | X | | X | | |
|
||||
* | VIDEOS | X | X* | | X | | |
|
||||
*
|
||||
* Note that on macOS/iOS, the Videos folder is called "Movies".
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetUserFolder
|
||||
*/
|
||||
typedef enum SDL_Folder
|
||||
{
|
||||
SDL_FOLDER_HOME, /**< The folder which contains all of the current user's data, preferences, and documents. It usually contains most of the other folders. If a requested folder does not exist, the home folder can be considered a safe fallback to store a user's documents. */
|
||||
SDL_FOLDER_DESKTOP, /**< The folder of files that are displayed on the desktop. Note that the existence of a desktop folder does not guarantee that the system does show icons on its desktop; certain GNU/Linux distros with a graphical environment may not have desktop icons. */
|
||||
SDL_FOLDER_DOCUMENTS, /**< User document files, possibly application-specific. This is a good place to save a user's projects. */
|
||||
SDL_FOLDER_DOWNLOADS, /**< Standard folder for user files downloaded from the internet. */
|
||||
SDL_FOLDER_MUSIC, /**< Music files that can be played using a standard music player (mp3, ogg...). */
|
||||
SDL_FOLDER_PICTURES, /**< Image files that can be displayed using a standard viewer (png, jpg...). */
|
||||
SDL_FOLDER_PUBLICSHARE, /**< Files that are meant to be shared with other users on the same computer. */
|
||||
SDL_FOLDER_SAVEDGAMES, /**< Save files for games. */
|
||||
SDL_FOLDER_SCREENSHOTS, /**< Application screenshots. */
|
||||
SDL_FOLDER_TEMPLATES, /**< Template files to be used when the user requests the desktop environment to create a new file in a certain folder, such as "New Text File.txt". Any file in the Templates folder can be used as a starting point for a new file. */
|
||||
SDL_FOLDER_VIDEOS, /**< Video files that can be played using a standard video player (mp4, webm...). */
|
||||
SDL_FOLDER_COUNT /**< Total number of types in this enum, not a folder type by itself. */
|
||||
} SDL_Folder;
|
||||
|
||||
/**
|
||||
* Finds the most suitable user folder for a specific purpose.
|
||||
*
|
||||
* Many OSes provide certain standard folders for certain purposes, such as
|
||||
* storing pictures, music or videos for a certain user. This function gives
|
||||
* the path for many of those special locations.
|
||||
*
|
||||
* This function is specifically for _user_ folders, which are meant for the
|
||||
* user to access and manage. For application-specific folders, meant to hold
|
||||
* data for the application to manage, see SDL_GetBasePath() and
|
||||
* SDL_GetPrefPath().
|
||||
*
|
||||
* The returned path is guaranteed to end with a path separator ('\\' on
|
||||
* Windows, '/' on most other platforms).
|
||||
*
|
||||
* If NULL is returned, the error may be obtained with SDL_GetError().
|
||||
*
|
||||
* \param folder the type of folder to find.
|
||||
* \returns either a null-terminated C string containing the full path to the
|
||||
* folder, or NULL if an error happened.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetUserFolder(SDL_Folder folder);
|
||||
|
||||
|
||||
/* Abstract filesystem interface */
|
||||
|
||||
/**
|
||||
* Types of filesystem entries.
|
||||
*
|
||||
* Note that there may be other sorts of items on a filesystem: devices, named
|
||||
* pipes, etc. They are currently reported as SDL_PATHTYPE_OTHER.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PathInfo
|
||||
*/
|
||||
typedef enum SDL_PathType
|
||||
{
|
||||
SDL_PATHTYPE_NONE, /**< path does not exist */
|
||||
SDL_PATHTYPE_FILE, /**< a normal file */
|
||||
SDL_PATHTYPE_DIRECTORY, /**< a directory */
|
||||
SDL_PATHTYPE_OTHER /**< something completely different like a device node (not a symlink, those are always followed) */
|
||||
} SDL_PathType;
|
||||
|
||||
/**
|
||||
* Information about a path on the filesystem.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPathInfo
|
||||
* \sa SDL_GetStoragePathInfo
|
||||
*/
|
||||
typedef struct SDL_PathInfo
|
||||
{
|
||||
SDL_PathType type; /**< the path type */
|
||||
Uint64 size; /**< the file size in bytes */
|
||||
SDL_Time create_time; /**< the time when the path was created */
|
||||
SDL_Time modify_time; /**< the last time the path was modified */
|
||||
SDL_Time access_time; /**< the last time the path was read */
|
||||
} SDL_PathInfo;
|
||||
|
||||
/**
|
||||
* Flags for path matching.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GlobDirectory
|
||||
* \sa SDL_GlobStorageDirectory
|
||||
*/
|
||||
typedef Uint32 SDL_GlobFlags;
|
||||
|
||||
#define SDL_GLOB_CASEINSENSITIVE (1u << 0)
|
||||
|
||||
/**
|
||||
* Create a directory, and any missing parent directories.
|
||||
*
|
||||
* This reports success if `path` already exists as a directory.
|
||||
*
|
||||
* If parent directories are missing, it will also create them. Note that if
|
||||
* this fails, it will not remove any parent directories it already made.
|
||||
*
|
||||
* \param path the path of the directory to create.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CreateDirectory(const char *path);
|
||||
|
||||
/**
|
||||
* Possible results from an enumeration callback.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_EnumerateDirectoryCallback
|
||||
*/
|
||||
typedef enum SDL_EnumerationResult
|
||||
{
|
||||
SDL_ENUM_CONTINUE, /**< Value that requests that enumeration continue. */
|
||||
SDL_ENUM_SUCCESS, /**< Value that requests that enumeration stop, successfully. */
|
||||
SDL_ENUM_FAILURE /**< Value that requests that enumeration stop, as a failure. */
|
||||
} SDL_EnumerationResult;
|
||||
|
||||
/**
|
||||
* Callback for directory enumeration.
|
||||
*
|
||||
* Enumeration of directory entries will continue until either all entries
|
||||
* have been provided to the callback, or the callback has requested a stop
|
||||
* through its return value.
|
||||
*
|
||||
* Returning SDL_ENUM_CONTINUE will let enumeration proceed, calling the
|
||||
* callback with further entries. SDL_ENUM_SUCCESS and SDL_ENUM_FAILURE will
|
||||
* terminate the enumeration early, and dictate the return value of the
|
||||
* enumeration function itself.
|
||||
*
|
||||
* `dirname` is guaranteed to end with a path separator ('\\' on Windows, '/'
|
||||
* on most other platforms).
|
||||
*
|
||||
* \param userdata an app-controlled pointer that is passed to the callback.
|
||||
* \param dirname the directory that is being enumerated.
|
||||
* \param fname the next entry in the enumeration.
|
||||
* \returns how the enumeration should proceed.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_EnumerateDirectory
|
||||
*/
|
||||
typedef SDL_EnumerationResult (SDLCALL *SDL_EnumerateDirectoryCallback)(void *userdata, const char *dirname, const char *fname);
|
||||
|
||||
/**
|
||||
* Enumerate a directory through a callback function.
|
||||
*
|
||||
* This function provides every directory entry through an app-provided
|
||||
* callback, called once for each directory entry, until all results have been
|
||||
* provided or the callback returns either SDL_ENUM_SUCCESS or
|
||||
* SDL_ENUM_FAILURE.
|
||||
*
|
||||
* This will return false if there was a system problem in general, or if a
|
||||
* callback returns SDL_ENUM_FAILURE. A successful return means a callback
|
||||
* returned SDL_ENUM_SUCCESS to halt enumeration, or all directory entries
|
||||
* were enumerated.
|
||||
*
|
||||
* \param path the path of the directory to enumerate.
|
||||
* \param callback a function that is called for each entry in the directory.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Remove a file or an empty directory.
|
||||
*
|
||||
* Directories that are not empty will fail; this function will not recursely
|
||||
* delete directory trees.
|
||||
*
|
||||
* \param path the path to remove from the filesystem.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_RemovePath(const char *path);
|
||||
|
||||
/**
|
||||
* Rename a file or directory.
|
||||
*
|
||||
* If the file at `newpath` already exists, it will be replaced.
|
||||
*
|
||||
* Note that this will not copy files across filesystems/drives/volumes, as
|
||||
* that is a much more complicated (and possibly time-consuming) operation.
|
||||
*
|
||||
* Which is to say, if this function fails, SDL_CopyFile() to a temporary file
|
||||
* in the same directory as `newpath`, then SDL_RenamePath() from the
|
||||
* temporary file to `newpath` and SDL_RemovePath() on `oldpath` might work
|
||||
* for files. Renaming a non-empty directory across filesystems is
|
||||
* dramatically more complex, however.
|
||||
*
|
||||
* \param oldpath the old path.
|
||||
* \param newpath the new path.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_RenamePath(const char *oldpath, const char *newpath);
|
||||
|
||||
/**
|
||||
* Copy a file.
|
||||
*
|
||||
* If the file at `newpath` already exists, it will be overwritten with the
|
||||
* contents of the file at `oldpath`.
|
||||
*
|
||||
* This function will block until the copy is complete, which might be a
|
||||
* significant time for large files on slow disks. On some platforms, the copy
|
||||
* can be handed off to the OS itself, but on others SDL might just open both
|
||||
* paths, and read from one and write to the other.
|
||||
*
|
||||
* Note that this is not an atomic operation! If something tries to read from
|
||||
* `newpath` while the copy is in progress, it will see an incomplete copy of
|
||||
* the data, and if the calling thread terminates (or the power goes out)
|
||||
* during the copy, `newpath`'s previous contents will be gone, replaced with
|
||||
* an incomplete copy of the data. To avoid this risk, it is recommended that
|
||||
* the app copy to a temporary file in the same directory as `newpath`, and if
|
||||
* the copy is successful, use SDL_RenamePath() to replace `newpath` with the
|
||||
* temporary file. This will ensure that reads of `newpath` will either see a
|
||||
* complete copy of the data, or it will see the pre-copy state of `newpath`.
|
||||
*
|
||||
* This function attempts to synchronize the newly-copied data to disk before
|
||||
* returning, if the platform allows it, so that the renaming trick will not
|
||||
* have a problem in a system crash or power failure, where the file could be
|
||||
* renamed but the contents never made it from the system file cache to the
|
||||
* physical disk.
|
||||
*
|
||||
* If the copy fails for any reason, the state of `newpath` is undefined. It
|
||||
* might be half a copy, it might be the untouched data of what was already
|
||||
* there, or it might be a zero-byte file, etc.
|
||||
*
|
||||
* \param oldpath the old path.
|
||||
* \param newpath the new path.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, but this
|
||||
* operation is not atomic, so the app might need to protect
|
||||
* access to specific paths from other threads if appropriate.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CopyFile(const char *oldpath, const char *newpath);
|
||||
|
||||
/**
|
||||
* Get information about a filesystem path.
|
||||
*
|
||||
* Symlinks, on filesystems that support them, are always followed, so you
|
||||
* will always get information on what the symlink eventually points to, and
|
||||
* not the symlink itself.
|
||||
*
|
||||
* \param path the path to query.
|
||||
* \param info a pointer filled in with information about the path, or NULL to
|
||||
* check for the existence of a file.
|
||||
* \returns true on success or false if the file doesn't exist, or another
|
||||
* failure; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo *info);
|
||||
|
||||
/**
|
||||
* Enumerate a directory tree, filtered by pattern, and return a list.
|
||||
*
|
||||
* Files are filtered out if they don't match the string in `pattern`, which
|
||||
* may contain wildcard characters `*` (match everything) and `?` (match one
|
||||
* character). If pattern is NULL, no filtering is done and all results are
|
||||
* returned. Subdirectories are permitted, and are specified with a path
|
||||
* separator of `/`. Wildcard characters `*` and `?` never match a path
|
||||
* separator.
|
||||
*
|
||||
* `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching
|
||||
* case-insensitive.
|
||||
*
|
||||
* The returned array is always NULL-terminated, for your iterating
|
||||
* convenience, but if `count` is non-NULL, on return it will contain the
|
||||
* number of items in the array, not counting the NULL terminator.
|
||||
*
|
||||
* \param path the path of the directory to enumerate.
|
||||
* \param pattern the pattern that files in the directory must match. Can be
|
||||
* NULL.
|
||||
* \param flags `SDL_GLOB_*` bitflags that affect this search.
|
||||
* \param count on return, will be set to the number of items in the returned
|
||||
* array. Can be NULL.
|
||||
* \returns an array of strings on success or NULL on failure; call
|
||||
* SDL_GetError() for more information. This is a single allocation
|
||||
* that should be freed with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC char ** SDLCALL SDL_GlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count);
|
||||
|
||||
/**
|
||||
* Get what the system believes is the "current working directory."
|
||||
*
|
||||
* For systems without a concept of a current working directory, this will
|
||||
* still attempt to provide something reasonable.
|
||||
*
|
||||
* SDL does not provide a means to _change_ the current working directory; for
|
||||
* platforms without this concept, this would cause surprises with file access
|
||||
* outside of SDL.
|
||||
*
|
||||
* The returned path is guaranteed to end with a path separator ('\\' on
|
||||
* Windows, '/' on most other platforms).
|
||||
*
|
||||
* \returns a UTF-8 string of the current working directory in
|
||||
* platform-dependent notation. NULL if there's a problem. This
|
||||
* should be freed with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC char * SDLCALL SDL_GetCurrentDirectory(void);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_filesystem_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* WIKI CATEGORY: GUID */
|
||||
|
||||
/**
|
||||
* # CategoryGUID
|
||||
*
|
||||
* A GUID is a 128-bit value that represents something that is uniquely
|
||||
* identifiable by this value: "globally unique."
|
||||
*
|
||||
* SDL provides functions to convert a GUID to/from a string.
|
||||
*/
|
||||
|
||||
#ifndef SDL_guid_h_
|
||||
#define SDL_guid_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An SDL_GUID is a 128-bit identifier for an input device that identifies
|
||||
* that device across runs of SDL programs on the same platform.
|
||||
*
|
||||
* If the device is detached and then re-attached to a different port, or if
|
||||
* the base system is rebooted, the device should still report the same GUID.
|
||||
*
|
||||
* GUIDs are as precise as possible but are not guaranteed to distinguish
|
||||
* physically distinct but equivalent devices. For example, two game
|
||||
* controllers from the same vendor with the same product ID and revision may
|
||||
* have the same GUID.
|
||||
*
|
||||
* GUIDs may be platform-dependent (i.e., the same device may report different
|
||||
* GUIDs on different operating systems).
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef struct SDL_GUID {
|
||||
Uint8 data[16];
|
||||
} SDL_GUID;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/**
|
||||
* Get an ASCII string representation for a given SDL_GUID.
|
||||
*
|
||||
* \param guid the SDL_GUID you wish to convert to string.
|
||||
* \param pszGUID buffer in which to write the ASCII string.
|
||||
* \param cbGUID the size of pszGUID, should be at least 33 bytes.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StringToGUID
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_GUIDToString(SDL_GUID guid, char *pszGUID, int cbGUID);
|
||||
|
||||
/**
|
||||
* Convert a GUID string into a SDL_GUID structure.
|
||||
*
|
||||
* Performs no error checking. If this function is given a string containing
|
||||
* an invalid GUID, the function will silently succeed, but the GUID generated
|
||||
* will not be useful.
|
||||
*
|
||||
* \param pchGUID string containing an ASCII representation of a GUID.
|
||||
* \returns a SDL_GUID structure.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GUIDToString
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_GUID SDLCALL SDL_StringToGUID(const char *pchGUID);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_guid_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,507 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryInit
|
||||
*
|
||||
* All SDL programs need to initialize the library before starting to work
|
||||
* with it.
|
||||
*
|
||||
* Almost everything can simply call SDL_Init() near startup, with a handful
|
||||
* of flags to specify subsystems to touch. These are here to make sure SDL
|
||||
* does not even attempt to touch low-level pieces of the operating system
|
||||
* that you don't intend to use. For example, you might be using SDL for video
|
||||
* and input but chose an external library for audio, and in this case you
|
||||
* would just need to leave off the `SDL_INIT_AUDIO` flag to make sure that
|
||||
* external library has complete control.
|
||||
*
|
||||
* Most apps, when terminating, should call SDL_Quit(). This will clean up
|
||||
* (nearly) everything that SDL might have allocated, and crucially, it'll
|
||||
* make sure that the display's resolution is back to what the user expects if
|
||||
* you had previously changed it for your game.
|
||||
*
|
||||
* SDL3 apps are strongly encouraged to call SDL_SetAppMetadata() at startup
|
||||
* to fill in details about the program. This is completely optional, but it
|
||||
* helps in small ways (we can provide an About dialog box for the macOS menu,
|
||||
* we can name the app in the system's audio mixer, etc). Those that want to
|
||||
* provide a _lot_ of information should look at the more-detailed
|
||||
* SDL_SetAppMetadataProperty().
|
||||
*/
|
||||
|
||||
#ifndef SDL_init_h_
|
||||
#define SDL_init_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* As of version 0.5, SDL is loaded dynamically into the application */
|
||||
|
||||
/**
|
||||
* Initialization flags for SDL_Init and/or SDL_InitSubSystem
|
||||
*
|
||||
* These are the flags which may be passed to SDL_Init(). You should specify
|
||||
* the subsystems which you will be using in your application.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Init
|
||||
* \sa SDL_Quit
|
||||
* \sa SDL_InitSubSystem
|
||||
* \sa SDL_QuitSubSystem
|
||||
* \sa SDL_WasInit
|
||||
*/
|
||||
typedef Uint32 SDL_InitFlags;
|
||||
|
||||
#define SDL_INIT_AUDIO 0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_VIDEO 0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
|
||||
#define SDL_INIT_JOYSTICK 0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_HAPTIC 0x00001000u
|
||||
#define SDL_INIT_GAMEPAD 0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
|
||||
#define SDL_INIT_EVENTS 0x00004000u
|
||||
#define SDL_INIT_SENSOR 0x00008000u /**< `SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS` */
|
||||
#define SDL_INIT_CAMERA 0x00010000u /**< `SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS` */
|
||||
|
||||
/**
|
||||
* Return values for optional main callbacks.
|
||||
*
|
||||
* Returning SDL_APP_SUCCESS or SDL_APP_FAILURE from SDL_AppInit,
|
||||
* SDL_AppEvent, or SDL_AppIterate will terminate the program and report
|
||||
* success/failure to the operating system. What that means is
|
||||
* platform-dependent. On Unix, for example, on success, the process error
|
||||
* code will be zero, and on failure it will be 1. This interface doesn't
|
||||
* allow you to return specific exit codes, just whether there was an error
|
||||
* generally or not.
|
||||
*
|
||||
* Returning SDL_APP_CONTINUE from these functions will let the app continue
|
||||
* to run.
|
||||
*
|
||||
* See
|
||||
* [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3)
|
||||
* for complete details.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_AppResult
|
||||
{
|
||||
SDL_APP_CONTINUE, /**< Value that requests that the app continue from the main callbacks. */
|
||||
SDL_APP_SUCCESS, /**< Value that requests termination with success from the main callbacks. */
|
||||
SDL_APP_FAILURE /**< Value that requests termination with error from the main callbacks. */
|
||||
} SDL_AppResult;
|
||||
|
||||
/**
|
||||
* Function pointer typedef for SDL_AppInit.
|
||||
*
|
||||
* These are used by SDL_EnterAppMainCallbacks. This mechanism operates behind
|
||||
* the scenes for apps using the optional main callbacks. Apps that want to
|
||||
* use this should just implement SDL_AppInit directly.
|
||||
*
|
||||
* \param appstate a place where the app can optionally store a pointer for
|
||||
* future use.
|
||||
* \param argc the standard ANSI C main's argc; number of elements in `argv`.
|
||||
* \param argv the standard ANSI C main's argv; array of command line
|
||||
* arguments.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef SDL_AppResult (SDLCALL *SDL_AppInit_func)(void **appstate, int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Function pointer typedef for SDL_AppIterate.
|
||||
*
|
||||
* These are used by SDL_EnterAppMainCallbacks. This mechanism operates behind
|
||||
* the scenes for apps using the optional main callbacks. Apps that want to
|
||||
* use this should just implement SDL_AppIterate directly.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef SDL_AppResult (SDLCALL *SDL_AppIterate_func)(void *appstate);
|
||||
|
||||
/**
|
||||
* Function pointer typedef for SDL_AppEvent.
|
||||
*
|
||||
* These are used by SDL_EnterAppMainCallbacks. This mechanism operates behind
|
||||
* the scenes for apps using the optional main callbacks. Apps that want to
|
||||
* use this should just implement SDL_AppEvent directly.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \param event the new event for the app to examine.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef SDL_AppResult (SDLCALL *SDL_AppEvent_func)(void *appstate, SDL_Event *event);
|
||||
|
||||
/**
|
||||
* Function pointer typedef for SDL_AppQuit.
|
||||
*
|
||||
* These are used by SDL_EnterAppMainCallbacks. This mechanism operates behind
|
||||
* the scenes for apps using the optional main callbacks. Apps that want to
|
||||
* use this should just implement SDL_AppEvent directly.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \param result the result code that terminated the app (success or failure).
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_AppQuit_func)(void *appstate, SDL_AppResult result);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the SDL library.
|
||||
*
|
||||
* SDL_Init() simply forwards to calling SDL_InitSubSystem(). Therefore, the
|
||||
* two may be used interchangeably. Though for readability of your code
|
||||
* SDL_InitSubSystem() might be preferred.
|
||||
*
|
||||
* The file I/O (for example: SDL_IOFromFile) and threading (SDL_CreateThread)
|
||||
* subsystems are initialized by default. Message boxes
|
||||
* (SDL_ShowSimpleMessageBox) also attempt to work without initializing the
|
||||
* video subsystem, in hopes of being useful in showing an error dialog when
|
||||
* SDL_Init fails. You must specifically initialize other subsystems if you
|
||||
* use them in your application.
|
||||
*
|
||||
* Logging (such as SDL_Log) works without initialization, too.
|
||||
*
|
||||
* `flags` may be any of the following OR'd together:
|
||||
*
|
||||
* - `SDL_INIT_AUDIO`: audio subsystem; automatically initializes the events
|
||||
* subsystem
|
||||
* - `SDL_INIT_VIDEO`: video subsystem; automatically initializes the events
|
||||
* subsystem, should be initialized on the main thread.
|
||||
* - `SDL_INIT_JOYSTICK`: joystick subsystem; automatically initializes the
|
||||
* events subsystem
|
||||
* - `SDL_INIT_HAPTIC`: haptic (force feedback) subsystem
|
||||
* - `SDL_INIT_GAMEPAD`: gamepad subsystem; automatically initializes the
|
||||
* joystick subsystem
|
||||
* - `SDL_INIT_EVENTS`: events subsystem
|
||||
* - `SDL_INIT_SENSOR`: sensor subsystem; automatically initializes the events
|
||||
* subsystem
|
||||
* - `SDL_INIT_CAMERA`: camera subsystem; automatically initializes the events
|
||||
* subsystem
|
||||
*
|
||||
* Subsystem initialization is ref-counted, you must call SDL_QuitSubSystem()
|
||||
* for each SDL_InitSubSystem() to correctly shutdown a subsystem manually (or
|
||||
* call SDL_Quit() to force shutdown). If a subsystem is already loaded then
|
||||
* this call will increase the ref-count and return.
|
||||
*
|
||||
* Consider reporting some basic metadata about your application before
|
||||
* calling SDL_Init, using either SDL_SetAppMetadata() or
|
||||
* SDL_SetAppMetadataProperty().
|
||||
*
|
||||
* \param flags subsystem initialization flags.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetAppMetadata
|
||||
* \sa SDL_SetAppMetadataProperty
|
||||
* \sa SDL_InitSubSystem
|
||||
* \sa SDL_Quit
|
||||
* \sa SDL_SetMainReady
|
||||
* \sa SDL_WasInit
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_Init(SDL_InitFlags flags);
|
||||
|
||||
/**
|
||||
* Compatibility function to initialize the SDL library.
|
||||
*
|
||||
* This function and SDL_Init() are interchangeable.
|
||||
*
|
||||
* \param flags any of the flags used by SDL_Init(); see SDL_Init for details.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Init
|
||||
* \sa SDL_Quit
|
||||
* \sa SDL_QuitSubSystem
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_InitSubSystem(SDL_InitFlags flags);
|
||||
|
||||
/**
|
||||
* Shut down specific SDL subsystems.
|
||||
*
|
||||
* You still need to call SDL_Quit() even if you close all open subsystems
|
||||
* with SDL_QuitSubSystem().
|
||||
*
|
||||
* \param flags any of the flags used by SDL_Init(); see SDL_Init for details.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_InitSubSystem
|
||||
* \sa SDL_Quit
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_QuitSubSystem(SDL_InitFlags flags);
|
||||
|
||||
/**
|
||||
* Get a mask of the specified subsystems which are currently initialized.
|
||||
*
|
||||
* \param flags any of the flags used by SDL_Init(); see SDL_Init for details.
|
||||
* \returns a mask of all initialized subsystems if `flags` is 0, otherwise it
|
||||
* returns the initialization status of the specified subsystems.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Init
|
||||
* \sa SDL_InitSubSystem
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_InitFlags SDLCALL SDL_WasInit(SDL_InitFlags flags);
|
||||
|
||||
/**
|
||||
* Clean up all initialized subsystems.
|
||||
*
|
||||
* You should call this function even if you have already shutdown each
|
||||
* initialized subsystem with SDL_QuitSubSystem(). It is safe to call this
|
||||
* function even in the case of errors in initialization.
|
||||
*
|
||||
* You can use this function with atexit() to ensure that it is run when your
|
||||
* application is shutdown, but it is not wise to do this from a library or
|
||||
* other dynamically loaded code.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Init
|
||||
* \sa SDL_QuitSubSystem
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_Quit(void);
|
||||
|
||||
/**
|
||||
* Return whether this is the main thread.
|
||||
*
|
||||
* On Apple platforms, the main thread is the thread that runs your program's
|
||||
* main() entry point. On other platforms, the main thread is the one that
|
||||
* calls SDL_Init(SDL_INIT_VIDEO), which should usually be the one that runs
|
||||
* your program's main() entry point. If you are using the main callbacks,
|
||||
* SDL_AppInit(), SDL_AppIterate(), and SDL_AppQuit() are all called on the
|
||||
* main thread.
|
||||
*
|
||||
* \returns true if this thread is the main thread, or false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RunOnMainThread
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_IsMainThread(void);
|
||||
|
||||
/**
|
||||
* Callback run on the main thread.
|
||||
*
|
||||
* \param userdata an app-controlled pointer that is passed to the callback.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RunOnMainThread
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_MainThreadCallback)(void *userdata);
|
||||
|
||||
/**
|
||||
* Call a function on the main thread during event processing.
|
||||
*
|
||||
* If this is called on the main thread, the callback is executed immediately.
|
||||
* If this is called on another thread, this callback is queued for execution
|
||||
* on the main thread during event processing.
|
||||
*
|
||||
* Be careful of deadlocks when using this functionality. You should not have
|
||||
* the main thread wait for the current thread while this function is being
|
||||
* called with `wait_complete` true.
|
||||
*
|
||||
* \param callback the callback to call on the main thread.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \param wait_complete true to wait for the callback to complete, false to
|
||||
* return immediately.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_IsMainThread
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_RunOnMainThread(SDL_MainThreadCallback callback, void *userdata, bool wait_complete);
|
||||
|
||||
/**
|
||||
* Specify basic metadata about your app.
|
||||
*
|
||||
* You can optionally provide metadata about your app to SDL. This is not
|
||||
* required, but strongly encouraged.
|
||||
*
|
||||
* There are several locations where SDL can make use of metadata (an "About"
|
||||
* box in the macOS menu bar, the name of the app can be shown on some audio
|
||||
* mixers, etc). Any piece of metadata can be left as NULL, if a specific
|
||||
* detail doesn't make sense for the app.
|
||||
*
|
||||
* This function should be called as early as possible, before SDL_Init.
|
||||
* Multiple calls to this function are allowed, but various state might not
|
||||
* change once it has been set up with a previous call to this function.
|
||||
*
|
||||
* Passing a NULL removes any previous metadata.
|
||||
*
|
||||
* This is a simplified interface for the most important information. You can
|
||||
* supply significantly more detailed metadata with
|
||||
* SDL_SetAppMetadataProperty().
|
||||
*
|
||||
* \param appname The name of the application ("My Game 2: Bad Guy's
|
||||
* Revenge!").
|
||||
* \param appversion The version of the application ("1.0.0beta5" or a git
|
||||
* hash, or whatever makes sense).
|
||||
* \param appidentifier A unique string in reverse-domain format that
|
||||
* identifies this app ("com.example.mygame2").
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetAppMetadataProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetAppMetadata(const char *appname, const char *appversion, const char *appidentifier);
|
||||
|
||||
/**
|
||||
* Specify metadata about your app through a set of properties.
|
||||
*
|
||||
* You can optionally provide metadata about your app to SDL. This is not
|
||||
* required, but strongly encouraged.
|
||||
*
|
||||
* There are several locations where SDL can make use of metadata (an "About"
|
||||
* box in the macOS menu bar, the name of the app can be shown on some audio
|
||||
* mixers, etc). Any piece of metadata can be left out, if a specific detail
|
||||
* doesn't make sense for the app.
|
||||
*
|
||||
* This function should be called as early as possible, before SDL_Init.
|
||||
* Multiple calls to this function are allowed, but various state might not
|
||||
* change once it has been set up with a previous call to this function.
|
||||
*
|
||||
* Once set, this metadata can be read using SDL_GetAppMetadataProperty().
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_APP_METADATA_NAME_STRING`: The human-readable name of the
|
||||
* application, like "My Game 2: Bad Guy's Revenge!". This will show up
|
||||
* anywhere the OS shows the name of the application separately from window
|
||||
* titles, such as volume control applets, etc. This defaults to "SDL
|
||||
* Application".
|
||||
* - `SDL_PROP_APP_METADATA_VERSION_STRING`: The version of the app that is
|
||||
* running; there are no rules on format, so "1.0.3beta2" and "April 22nd,
|
||||
* 2024" and a git hash are all valid options. This has no default.
|
||||
* - `SDL_PROP_APP_METADATA_IDENTIFIER_STRING`: A unique string that
|
||||
* identifies this app. This must be in reverse-domain format, like
|
||||
* "com.example.mygame2". This string is used by desktop compositors to
|
||||
* identify and group windows together, as well as match applications with
|
||||
* associated desktop settings and icons. If you plan to package your
|
||||
* application in a container such as Flatpak, the app ID should match the
|
||||
* name of your Flatpak container as well. This has no default.
|
||||
* - `SDL_PROP_APP_METADATA_CREATOR_STRING`: The human-readable name of the
|
||||
* creator/developer/maker of this app, like "MojoWorkshop, LLC"
|
||||
* - `SDL_PROP_APP_METADATA_COPYRIGHT_STRING`: The human-readable copyright
|
||||
* notice, like "Copyright (c) 2024 MojoWorkshop, LLC" or whatnot. Keep this
|
||||
* to one line, don't paste a copy of a whole software license in here. This
|
||||
* has no default.
|
||||
* - `SDL_PROP_APP_METADATA_URL_STRING`: A URL to the app on the web. Maybe a
|
||||
* product page, or a storefront, or even a GitHub repository, for user's
|
||||
* further information This has no default.
|
||||
* - `SDL_PROP_APP_METADATA_TYPE_STRING`: The type of application this is.
|
||||
* Currently this string can be "game" for a video game, "mediaplayer" for a
|
||||
* media player, or generically "application" if nothing else applies.
|
||||
* Future versions of SDL might add new types. This defaults to
|
||||
* "application".
|
||||
*
|
||||
* \param name the name of the metadata property to set.
|
||||
* \param value the value of the property, or NULL to remove that property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetAppMetadataProperty
|
||||
* \sa SDL_SetAppMetadata
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetAppMetadataProperty(const char *name, const char *value);
|
||||
|
||||
#define SDL_PROP_APP_METADATA_NAME_STRING "SDL.app.metadata.name"
|
||||
#define SDL_PROP_APP_METADATA_VERSION_STRING "SDL.app.metadata.version"
|
||||
#define SDL_PROP_APP_METADATA_IDENTIFIER_STRING "SDL.app.metadata.identifier"
|
||||
#define SDL_PROP_APP_METADATA_CREATOR_STRING "SDL.app.metadata.creator"
|
||||
#define SDL_PROP_APP_METADATA_COPYRIGHT_STRING "SDL.app.metadata.copyright"
|
||||
#define SDL_PROP_APP_METADATA_URL_STRING "SDL.app.metadata.url"
|
||||
#define SDL_PROP_APP_METADATA_TYPE_STRING "SDL.app.metadata.type"
|
||||
|
||||
/**
|
||||
* Get metadata about your app.
|
||||
*
|
||||
* This returns metadata previously set using SDL_SetAppMetadata() or
|
||||
* SDL_SetAppMetadataProperty(). See SDL_SetAppMetadataProperty() for the list
|
||||
* of available properties and their meanings.
|
||||
*
|
||||
* \param name the name of the metadata property to get.
|
||||
* \returns the current value of the metadata property, or the default if it
|
||||
* is not set, NULL for properties with no default.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, although
|
||||
* the string returned is not protected and could potentially be
|
||||
* freed if you call SDL_SetAppMetadataProperty() to set that
|
||||
* property from another thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetAppMetadata
|
||||
* \sa SDL_SetAppMetadataProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetAppMetadataProperty(const char *name);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_init_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryKeyboard
|
||||
*
|
||||
* SDL keyboard management.
|
||||
*
|
||||
* Please refer to the Best Keyboard Practices document for details on how
|
||||
* best to accept keyboard input in various types of programs:
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/BestKeyboardPractices
|
||||
*/
|
||||
|
||||
#ifndef SDL_keyboard_h_
|
||||
#define SDL_keyboard_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_keycode.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
#include <SDL3/SDL_rect.h>
|
||||
#include <SDL3/SDL_scancode.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is a unique ID for a keyboard for the time it is connected to the
|
||||
* system, and is never reused for the lifetime of the application.
|
||||
*
|
||||
* If the keyboard is disconnected and reconnected, it will get a new ID.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_KeyboardID;
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/**
|
||||
* Return whether a keyboard is currently connected.
|
||||
*
|
||||
* \returns true if a keyboard is connected, false otherwise.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyboards
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasKeyboard(void);
|
||||
|
||||
/**
|
||||
* Get a list of currently connected keyboards.
|
||||
*
|
||||
* Note that this will include any device or virtual driver that includes
|
||||
* keyboard functionality, including some mice, KVM switches, motherboard
|
||||
* power buttons, etc. You should wait for input from a device before you
|
||||
* consider it actively in use.
|
||||
*
|
||||
* \param count a pointer filled in with the number of keyboards returned, may
|
||||
* be NULL.
|
||||
* \returns a 0 terminated array of keyboards instance IDs or NULL on failure;
|
||||
* call SDL_GetError() for more information. This should be freed
|
||||
* with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyboardNameForID
|
||||
* \sa SDL_HasKeyboard
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_KeyboardID * SDLCALL SDL_GetKeyboards(int *count);
|
||||
|
||||
/**
|
||||
* Get the name of a keyboard.
|
||||
*
|
||||
* This function returns "" if the keyboard doesn't have a name.
|
||||
*
|
||||
* \param instance_id the keyboard instance ID.
|
||||
* \returns the name of the selected keyboard or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyboards
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetKeyboardNameForID(SDL_KeyboardID instance_id);
|
||||
|
||||
/**
|
||||
* Query the window which currently has keyboard focus.
|
||||
*
|
||||
* \returns the window with keyboard focus.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetKeyboardFocus(void);
|
||||
|
||||
/**
|
||||
* Get a snapshot of the current state of the keyboard.
|
||||
*
|
||||
* The pointer returned is a pointer to an internal SDL array. It will be
|
||||
* valid for the whole lifetime of the application and should not be freed by
|
||||
* the caller.
|
||||
*
|
||||
* A array element with a value of true means that the key is pressed and a
|
||||
* value of false means that it is not. Indexes into this array are obtained
|
||||
* by using SDL_Scancode values.
|
||||
*
|
||||
* Use SDL_PumpEvents() to update the state array.
|
||||
*
|
||||
* This function gives you the current state after all events have been
|
||||
* processed, so if a key or button has been pressed and released before you
|
||||
* process events, then the pressed state will never show up in the
|
||||
* SDL_GetKeyboardState() calls.
|
||||
*
|
||||
* Note: This function doesn't take into account whether shift has been
|
||||
* pressed or not.
|
||||
*
|
||||
* \param numkeys if non-NULL, receives the length of the returned array.
|
||||
* \returns a pointer to an array of key states.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PumpEvents
|
||||
* \sa SDL_ResetKeyboard
|
||||
*/
|
||||
extern SDL_DECLSPEC const bool * SDLCALL SDL_GetKeyboardState(int *numkeys);
|
||||
|
||||
/**
|
||||
* Clear the state of the keyboard.
|
||||
*
|
||||
* This function will generate key up events for all pressed keys.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyboardState
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_ResetKeyboard(void);
|
||||
|
||||
/**
|
||||
* Get the current key modifier state for the keyboard.
|
||||
*
|
||||
* \returns an OR'd combination of the modifier keys for the keyboard.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyboardState
|
||||
* \sa SDL_SetModState
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Keymod SDLCALL SDL_GetModState(void);
|
||||
|
||||
/**
|
||||
* Set the current key modifier state for the keyboard.
|
||||
*
|
||||
* The inverse of SDL_GetModState(), SDL_SetModState() allows you to impose
|
||||
* modifier key states on your application. Simply pass your desired modifier
|
||||
* states into `modstate`. This value may be a bitwise, OR'd combination of
|
||||
* SDL_Keymod values.
|
||||
*
|
||||
* This does not change the keyboard state, only the key modifier flags that
|
||||
* SDL reports.
|
||||
*
|
||||
* \param modstate the desired SDL_Keymod for the keyboard.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetModState
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetModState(SDL_Keymod modstate);
|
||||
|
||||
/**
|
||||
* Get the key code corresponding to the given scancode according to the
|
||||
* current keyboard layout.
|
||||
*
|
||||
* If you want to get the keycode as it would be delivered in key events,
|
||||
* including options specified in SDL_HINT_KEYCODE_OPTIONS, then you should
|
||||
* pass `key_event` as true. Otherwise this function simply translates the
|
||||
* scancode based on the given modifier state.
|
||||
*
|
||||
* \param scancode the desired SDL_Scancode to query.
|
||||
* \param modstate the modifier state to use when translating the scancode to
|
||||
* a keycode.
|
||||
* \param key_event true if the keycode will be used in key events.
|
||||
* \returns the SDL_Keycode that corresponds to the given SDL_Scancode.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyName
|
||||
* \sa SDL_GetScancodeFromKey
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromScancode(SDL_Scancode scancode, SDL_Keymod modstate, bool key_event);
|
||||
|
||||
/**
|
||||
* Get the scancode corresponding to the given key code according to the
|
||||
* current keyboard layout.
|
||||
*
|
||||
* Note that there may be multiple scancode+modifier states that can generate
|
||||
* this keycode, this will just return the first one found.
|
||||
*
|
||||
* \param key the desired SDL_Keycode to query.
|
||||
* \param modstate a pointer to the modifier state that would be used when the
|
||||
* scancode generates this key, may be NULL.
|
||||
* \returns the SDL_Scancode that corresponds to the given SDL_Keycode.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyFromScancode
|
||||
* \sa SDL_GetScancodeName
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromKey(SDL_Keycode key, SDL_Keymod *modstate);
|
||||
|
||||
/**
|
||||
* Set a human-readable name for a scancode.
|
||||
*
|
||||
* \param scancode the desired SDL_Scancode.
|
||||
* \param name the name to use for the scancode, encoded as UTF-8. The string
|
||||
* is not copied, so the pointer given to this function must stay
|
||||
* valid while SDL is being used.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetScancodeName
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetScancodeName(SDL_Scancode scancode, const char *name);
|
||||
|
||||
/**
|
||||
* Get a human-readable name for a scancode.
|
||||
*
|
||||
* **Warning**: The returned name is by design not stable across platforms,
|
||||
* e.g. the name for `SDL_SCANCODE_LGUI` is "Left GUI" under Linux but "Left
|
||||
* Windows" under Microsoft Windows, and some scancodes like
|
||||
* `SDL_SCANCODE_NONUSBACKSLASH` don't have any name at all. There are even
|
||||
* scancodes that share names, e.g. `SDL_SCANCODE_RETURN` and
|
||||
* `SDL_SCANCODE_RETURN2` (both called "Return"). This function is therefore
|
||||
* unsuitable for creating a stable cross-platform two-way mapping between
|
||||
* strings and scancodes.
|
||||
*
|
||||
* \param scancode the desired SDL_Scancode to query.
|
||||
* \returns a pointer to the name for the scancode. If the scancode doesn't
|
||||
* have a name this function returns an empty string ("").
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetScancodeFromKey
|
||||
* \sa SDL_GetScancodeFromName
|
||||
* \sa SDL_SetScancodeName
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetScancodeName(SDL_Scancode scancode);
|
||||
|
||||
/**
|
||||
* Get a scancode from a human-readable name.
|
||||
*
|
||||
* \param name the human-readable scancode name.
|
||||
* \returns the SDL_Scancode, or `SDL_SCANCODE_UNKNOWN` if the name wasn't
|
||||
* recognized; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyFromName
|
||||
* \sa SDL_GetScancodeFromKey
|
||||
* \sa SDL_GetScancodeName
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Scancode SDLCALL SDL_GetScancodeFromName(const char *name);
|
||||
|
||||
/**
|
||||
* Get a human-readable name for a key.
|
||||
*
|
||||
* If the key doesn't have a name, this function returns an empty string ("").
|
||||
*
|
||||
* Letters will be presented in their uppercase form, if applicable.
|
||||
*
|
||||
* \param key the desired SDL_Keycode to query.
|
||||
* \returns a UTF-8 encoded string of the key name.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyFromName
|
||||
* \sa SDL_GetKeyFromScancode
|
||||
* \sa SDL_GetScancodeFromKey
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetKeyName(SDL_Keycode key);
|
||||
|
||||
/**
|
||||
* Get a key code from a human-readable name.
|
||||
*
|
||||
* \param name the human-readable key name.
|
||||
* \returns key code, or `SDLK_UNKNOWN` if the name wasn't recognized; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetKeyFromScancode
|
||||
* \sa SDL_GetKeyName
|
||||
* \sa SDL_GetScancodeFromName
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Keycode SDLCALL SDL_GetKeyFromName(const char *name);
|
||||
|
||||
/**
|
||||
* Start accepting Unicode text input events in a window.
|
||||
*
|
||||
* This function will enable text input (SDL_EVENT_TEXT_INPUT and
|
||||
* SDL_EVENT_TEXT_EDITING events) in the specified window. Please use this
|
||||
* function paired with SDL_StopTextInput().
|
||||
*
|
||||
* Text input events are not received by default.
|
||||
*
|
||||
* On some platforms using this function shows the screen keyboard and/or
|
||||
* activates an IME, which can prevent some key press events from being passed
|
||||
* through.
|
||||
*
|
||||
* \param window the window to enable text input.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetTextInputArea
|
||||
* \sa SDL_StartTextInputWithProperties
|
||||
* \sa SDL_StopTextInput
|
||||
* \sa SDL_TextInputActive
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_StartTextInput(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Text input type.
|
||||
*
|
||||
* These are the valid values for SDL_PROP_TEXTINPUT_TYPE_NUMBER. Not every
|
||||
* value is valid on every platform, but where a value isn't supported, a
|
||||
* reasonable fallback will be used.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInputWithProperties
|
||||
*/
|
||||
typedef enum SDL_TextInputType
|
||||
{
|
||||
SDL_TEXTINPUT_TYPE_TEXT, /**< The input is text */
|
||||
SDL_TEXTINPUT_TYPE_TEXT_NAME, /**< The input is a person's name */
|
||||
SDL_TEXTINPUT_TYPE_TEXT_EMAIL, /**< The input is an e-mail address */
|
||||
SDL_TEXTINPUT_TYPE_TEXT_USERNAME, /**< The input is a username */
|
||||
SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_HIDDEN, /**< The input is a secure password that is hidden */
|
||||
SDL_TEXTINPUT_TYPE_TEXT_PASSWORD_VISIBLE, /**< The input is a secure password that is visible */
|
||||
SDL_TEXTINPUT_TYPE_NUMBER, /**< The input is a number */
|
||||
SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_HIDDEN, /**< The input is a secure PIN that is hidden */
|
||||
SDL_TEXTINPUT_TYPE_NUMBER_PASSWORD_VISIBLE /**< The input is a secure PIN that is visible */
|
||||
} SDL_TextInputType;
|
||||
|
||||
/**
|
||||
* Auto capitalization type.
|
||||
*
|
||||
* These are the valid values for SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER.
|
||||
* Not every value is valid on every platform, but where a value isn't
|
||||
* supported, a reasonable fallback will be used.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInputWithProperties
|
||||
*/
|
||||
typedef enum SDL_Capitalization
|
||||
{
|
||||
SDL_CAPITALIZE_NONE, /**< No auto-capitalization will be done */
|
||||
SDL_CAPITALIZE_SENTENCES, /**< The first letter of sentences will be capitalized */
|
||||
SDL_CAPITALIZE_WORDS, /**< The first letter of words will be capitalized */
|
||||
SDL_CAPITALIZE_LETTERS /**< All letters will be capitalized */
|
||||
} SDL_Capitalization;
|
||||
|
||||
/**
|
||||
* Start accepting Unicode text input events in a window, with properties
|
||||
* describing the input.
|
||||
*
|
||||
* This function will enable text input (SDL_EVENT_TEXT_INPUT and
|
||||
* SDL_EVENT_TEXT_EDITING events) in the specified window. Please use this
|
||||
* function paired with SDL_StopTextInput().
|
||||
*
|
||||
* Text input events are not received by default.
|
||||
*
|
||||
* On some platforms using this function shows the screen keyboard and/or
|
||||
* activates an IME, which can prevent some key press events from being passed
|
||||
* through.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_TEXTINPUT_TYPE_NUMBER` - an SDL_TextInputType value that
|
||||
* describes text being input, defaults to SDL_TEXTINPUT_TYPE_TEXT.
|
||||
* - `SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER` - an SDL_Capitalization value
|
||||
* that describes how text should be capitalized, defaults to
|
||||
* SDL_CAPITALIZE_SENTENCES for normal text entry, SDL_CAPITALIZE_WORDS for
|
||||
* SDL_TEXTINPUT_TYPE_TEXT_NAME, and SDL_CAPITALIZE_NONE for e-mail
|
||||
* addresses, usernames, and passwords.
|
||||
* - `SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN` - true to enable auto completion
|
||||
* and auto correction, defaults to true.
|
||||
* - `SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN` - true if multiple lines of text
|
||||
* are allowed. This defaults to true if SDL_HINT_RETURN_KEY_HIDES_IME is
|
||||
* "0" or is not set, and defaults to false if SDL_HINT_RETURN_KEY_HIDES_IME
|
||||
* is "1".
|
||||
*
|
||||
* On Android you can directly specify the input type:
|
||||
*
|
||||
* - `SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER` - the text input type to
|
||||
* use, overriding other properties. This is documented at
|
||||
* https://developer.android.com/reference/android/text/InputType
|
||||
*
|
||||
* \param window the window to enable text input.
|
||||
* \param props the properties to use.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetTextInputArea
|
||||
* \sa SDL_StartTextInput
|
||||
* \sa SDL_StopTextInput
|
||||
* \sa SDL_TextInputActive
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_StartTextInputWithProperties(SDL_Window *window, SDL_PropertiesID props);
|
||||
|
||||
#define SDL_PROP_TEXTINPUT_TYPE_NUMBER "SDL.textinput.type"
|
||||
#define SDL_PROP_TEXTINPUT_CAPITALIZATION_NUMBER "SDL.textinput.capitalization"
|
||||
#define SDL_PROP_TEXTINPUT_AUTOCORRECT_BOOLEAN "SDL.textinput.autocorrect"
|
||||
#define SDL_PROP_TEXTINPUT_MULTILINE_BOOLEAN "SDL.textinput.multiline"
|
||||
#define SDL_PROP_TEXTINPUT_ANDROID_INPUTTYPE_NUMBER "SDL.textinput.android.inputtype"
|
||||
|
||||
/**
|
||||
* Check whether or not Unicode text input events are enabled for a window.
|
||||
*
|
||||
* \param window the window to check.
|
||||
* \returns true if text input events are enabled else false.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInput
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_TextInputActive(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Stop receiving any text input events in a window.
|
||||
*
|
||||
* If SDL_StartTextInput() showed the screen keyboard, this function will hide
|
||||
* it.
|
||||
*
|
||||
* \param window the window to disable text input.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInput
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_StopTextInput(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Dismiss the composition window/IME without disabling the subsystem.
|
||||
*
|
||||
* \param window the window to affect.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInput
|
||||
* \sa SDL_StopTextInput
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearComposition(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Set the area used to type Unicode text input.
|
||||
*
|
||||
* Native input methods may place a window with word suggestions near the
|
||||
* cursor, without covering the text being entered.
|
||||
*
|
||||
* \param window the window for which to set the text input area.
|
||||
* \param rect the SDL_Rect representing the text input area, in window
|
||||
* coordinates, or NULL to clear it.
|
||||
* \param cursor the offset of the current cursor location relative to
|
||||
* `rect->x`, in window coordinates.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetTextInputArea
|
||||
* \sa SDL_StartTextInput
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetTextInputArea(SDL_Window *window, const SDL_Rect *rect, int cursor);
|
||||
|
||||
/**
|
||||
* Get the area used to type Unicode text input.
|
||||
*
|
||||
* This returns the values previously set by SDL_SetTextInputArea().
|
||||
*
|
||||
* \param window the window for which to query the text input area.
|
||||
* \param rect a pointer to an SDL_Rect filled in with the text input area,
|
||||
* may be NULL.
|
||||
* \param cursor a pointer to the offset of the current cursor location
|
||||
* relative to `rect->x`, may be NULL.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetTextInputArea
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetTextInputArea(SDL_Window *window, SDL_Rect *rect, int *cursor);
|
||||
|
||||
/**
|
||||
* Check whether the platform has screen keyboard support.
|
||||
*
|
||||
* \returns true if the platform has some screen keyboard support or false if
|
||||
* not.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_StartTextInput
|
||||
* \sa SDL_ScreenKeyboardShown
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasScreenKeyboardSupport(void);
|
||||
|
||||
/**
|
||||
* Check whether the screen keyboard is shown for given window.
|
||||
*
|
||||
* \param window the window for which screen keyboard should be queried.
|
||||
* \returns true if screen keyboard is shown or false if not.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HasScreenKeyboardSupport
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ScreenKeyboardShown(SDL_Window *window);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_keyboard_h_ */
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryKeycode
|
||||
*
|
||||
* Defines constants which identify keyboard keys and modifiers.
|
||||
*
|
||||
* Please refer to the Best Keyboard Practices document for details on what
|
||||
* this information means and how best to use it.
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/BestKeyboardPractices
|
||||
*/
|
||||
|
||||
#ifndef SDL_keycode_h_
|
||||
#define SDL_keycode_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_scancode.h>
|
||||
|
||||
/**
|
||||
* The SDL virtual key representation.
|
||||
*
|
||||
* Values of this type are used to represent keyboard keys using the current
|
||||
* layout of the keyboard. These values include Unicode values representing
|
||||
* the unmodified character that would be generated by pressing the key, or an
|
||||
* `SDLK_*` constant for those keys that do not generate characters.
|
||||
*
|
||||
* A special exception is the number keys at the top of the keyboard which map
|
||||
* by default to SDLK_0...SDLK_9 on AZERTY layouts.
|
||||
*
|
||||
* Keys with the `SDLK_EXTENDED_MASK` bit set do not map to a scancode or
|
||||
* Unicode code point.
|
||||
*
|
||||
* Many common keycodes are listed below, but this list is not exhaustive.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HINT_KEYCODE_OPTIONS
|
||||
*/
|
||||
typedef Uint32 SDL_Keycode;
|
||||
|
||||
#define SDLK_EXTENDED_MASK (1u << 29)
|
||||
#define SDLK_SCANCODE_MASK (1u << 30)
|
||||
#define SDL_SCANCODE_TO_KEYCODE(X) (X | SDLK_SCANCODE_MASK)
|
||||
#define SDLK_UNKNOWN 0x00000000u /**< 0 */
|
||||
#define SDLK_RETURN 0x0000000du /**< '\r' */
|
||||
#define SDLK_ESCAPE 0x0000001bu /**< '\x1B' */
|
||||
#define SDLK_BACKSPACE 0x00000008u /**< '\b' */
|
||||
#define SDLK_TAB 0x00000009u /**< '\t' */
|
||||
#define SDLK_SPACE 0x00000020u /**< ' ' */
|
||||
#define SDLK_EXCLAIM 0x00000021u /**< '!' */
|
||||
#define SDLK_DBLAPOSTROPHE 0x00000022u /**< '"' */
|
||||
#define SDLK_HASH 0x00000023u /**< '#' */
|
||||
#define SDLK_DOLLAR 0x00000024u /**< '$' */
|
||||
#define SDLK_PERCENT 0x00000025u /**< '%' */
|
||||
#define SDLK_AMPERSAND 0x00000026u /**< '&' */
|
||||
#define SDLK_APOSTROPHE 0x00000027u /**< '\'' */
|
||||
#define SDLK_LEFTPAREN 0x00000028u /**< '(' */
|
||||
#define SDLK_RIGHTPAREN 0x00000029u /**< ')' */
|
||||
#define SDLK_ASTERISK 0x0000002au /**< '*' */
|
||||
#define SDLK_PLUS 0x0000002bu /**< '+' */
|
||||
#define SDLK_COMMA 0x0000002cu /**< ',' */
|
||||
#define SDLK_MINUS 0x0000002du /**< '-' */
|
||||
#define SDLK_PERIOD 0x0000002eu /**< '.' */
|
||||
#define SDLK_SLASH 0x0000002fu /**< '/' */
|
||||
#define SDLK_0 0x00000030u /**< '0' */
|
||||
#define SDLK_1 0x00000031u /**< '1' */
|
||||
#define SDLK_2 0x00000032u /**< '2' */
|
||||
#define SDLK_3 0x00000033u /**< '3' */
|
||||
#define SDLK_4 0x00000034u /**< '4' */
|
||||
#define SDLK_5 0x00000035u /**< '5' */
|
||||
#define SDLK_6 0x00000036u /**< '6' */
|
||||
#define SDLK_7 0x00000037u /**< '7' */
|
||||
#define SDLK_8 0x00000038u /**< '8' */
|
||||
#define SDLK_9 0x00000039u /**< '9' */
|
||||
#define SDLK_COLON 0x0000003au /**< ':' */
|
||||
#define SDLK_SEMICOLON 0x0000003bu /**< ';' */
|
||||
#define SDLK_LESS 0x0000003cu /**< '<' */
|
||||
#define SDLK_EQUALS 0x0000003du /**< '=' */
|
||||
#define SDLK_GREATER 0x0000003eu /**< '>' */
|
||||
#define SDLK_QUESTION 0x0000003fu /**< '?' */
|
||||
#define SDLK_AT 0x00000040u /**< '@' */
|
||||
#define SDLK_LEFTBRACKET 0x0000005bu /**< '[' */
|
||||
#define SDLK_BACKSLASH 0x0000005cu /**< '\\' */
|
||||
#define SDLK_RIGHTBRACKET 0x0000005du /**< ']' */
|
||||
#define SDLK_CARET 0x0000005eu /**< '^' */
|
||||
#define SDLK_UNDERSCORE 0x0000005fu /**< '_' */
|
||||
#define SDLK_GRAVE 0x00000060u /**< '`' */
|
||||
#define SDLK_A 0x00000061u /**< 'a' */
|
||||
#define SDLK_B 0x00000062u /**< 'b' */
|
||||
#define SDLK_C 0x00000063u /**< 'c' */
|
||||
#define SDLK_D 0x00000064u /**< 'd' */
|
||||
#define SDLK_E 0x00000065u /**< 'e' */
|
||||
#define SDLK_F 0x00000066u /**< 'f' */
|
||||
#define SDLK_G 0x00000067u /**< 'g' */
|
||||
#define SDLK_H 0x00000068u /**< 'h' */
|
||||
#define SDLK_I 0x00000069u /**< 'i' */
|
||||
#define SDLK_J 0x0000006au /**< 'j' */
|
||||
#define SDLK_K 0x0000006bu /**< 'k' */
|
||||
#define SDLK_L 0x0000006cu /**< 'l' */
|
||||
#define SDLK_M 0x0000006du /**< 'm' */
|
||||
#define SDLK_N 0x0000006eu /**< 'n' */
|
||||
#define SDLK_O 0x0000006fu /**< 'o' */
|
||||
#define SDLK_P 0x00000070u /**< 'p' */
|
||||
#define SDLK_Q 0x00000071u /**< 'q' */
|
||||
#define SDLK_R 0x00000072u /**< 'r' */
|
||||
#define SDLK_S 0x00000073u /**< 's' */
|
||||
#define SDLK_T 0x00000074u /**< 't' */
|
||||
#define SDLK_U 0x00000075u /**< 'u' */
|
||||
#define SDLK_V 0x00000076u /**< 'v' */
|
||||
#define SDLK_W 0x00000077u /**< 'w' */
|
||||
#define SDLK_X 0x00000078u /**< 'x' */
|
||||
#define SDLK_Y 0x00000079u /**< 'y' */
|
||||
#define SDLK_Z 0x0000007au /**< 'z' */
|
||||
#define SDLK_LEFTBRACE 0x0000007bu /**< '{' */
|
||||
#define SDLK_PIPE 0x0000007cu /**< '|' */
|
||||
#define SDLK_RIGHTBRACE 0x0000007du /**< '}' */
|
||||
#define SDLK_TILDE 0x0000007eu /**< '~' */
|
||||
#define SDLK_DELETE 0x0000007fu /**< '\x7F' */
|
||||
#define SDLK_PLUSMINUS 0x000000b1u /**< '\xB1' */
|
||||
#define SDLK_CAPSLOCK 0x40000039u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK) */
|
||||
#define SDLK_F1 0x4000003au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1) */
|
||||
#define SDLK_F2 0x4000003bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2) */
|
||||
#define SDLK_F3 0x4000003cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F3) */
|
||||
#define SDLK_F4 0x4000003du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F4) */
|
||||
#define SDLK_F5 0x4000003eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F5) */
|
||||
#define SDLK_F6 0x4000003fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F6) */
|
||||
#define SDLK_F7 0x40000040u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F7) */
|
||||
#define SDLK_F8 0x40000041u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F8) */
|
||||
#define SDLK_F9 0x40000042u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F9) */
|
||||
#define SDLK_F10 0x40000043u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F10) */
|
||||
#define SDLK_F11 0x40000044u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F11) */
|
||||
#define SDLK_F12 0x40000045u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F12) */
|
||||
#define SDLK_PRINTSCREEN 0x40000046u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRINTSCREEN) */
|
||||
#define SDLK_SCROLLLOCK 0x40000047u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SCROLLLOCK) */
|
||||
#define SDLK_PAUSE 0x40000048u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAUSE) */
|
||||
#define SDLK_INSERT 0x40000049u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT) */
|
||||
#define SDLK_HOME 0x4000004au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME) */
|
||||
#define SDLK_PAGEUP 0x4000004bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP) */
|
||||
#define SDLK_END 0x4000004du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END) */
|
||||
#define SDLK_PAGEDOWN 0x4000004eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN) */
|
||||
#define SDLK_RIGHT 0x4000004fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT) */
|
||||
#define SDLK_LEFT 0x40000050u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LEFT) */
|
||||
#define SDLK_DOWN 0x40000051u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DOWN) */
|
||||
#define SDLK_UP 0x40000052u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UP) */
|
||||
#define SDLK_NUMLOCKCLEAR 0x40000053u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_NUMLOCKCLEAR) */
|
||||
#define SDLK_KP_DIVIDE 0x40000054u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DIVIDE) */
|
||||
#define SDLK_KP_MULTIPLY 0x40000055u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MULTIPLY) */
|
||||
#define SDLK_KP_MINUS 0x40000056u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MINUS) */
|
||||
#define SDLK_KP_PLUS 0x40000057u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUS) */
|
||||
#define SDLK_KP_ENTER 0x40000058u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_ENTER) */
|
||||
#define SDLK_KP_1 0x40000059u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_1) */
|
||||
#define SDLK_KP_2 0x4000005au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_2) */
|
||||
#define SDLK_KP_3 0x4000005bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_3) */
|
||||
#define SDLK_KP_4 0x4000005cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_4) */
|
||||
#define SDLK_KP_5 0x4000005du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_5) */
|
||||
#define SDLK_KP_6 0x4000005eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_6) */
|
||||
#define SDLK_KP_7 0x4000005fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_7) */
|
||||
#define SDLK_KP_8 0x40000060u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_8) */
|
||||
#define SDLK_KP_9 0x40000061u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_9) */
|
||||
#define SDLK_KP_0 0x40000062u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_0) */
|
||||
#define SDLK_KP_PERIOD 0x40000063u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERIOD) */
|
||||
#define SDLK_APPLICATION 0x40000065u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APPLICATION) */
|
||||
#define SDLK_POWER 0x40000066u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_POWER) */
|
||||
#define SDLK_KP_EQUALS 0x40000067u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALS) */
|
||||
#define SDLK_F13 0x40000068u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F13) */
|
||||
#define SDLK_F14 0x40000069u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F14) */
|
||||
#define SDLK_F15 0x4000006au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F15) */
|
||||
#define SDLK_F16 0x4000006bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F16) */
|
||||
#define SDLK_F17 0x4000006cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F17) */
|
||||
#define SDLK_F18 0x4000006du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F18) */
|
||||
#define SDLK_F19 0x4000006eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F19) */
|
||||
#define SDLK_F20 0x4000006fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F20) */
|
||||
#define SDLK_F21 0x40000070u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F21) */
|
||||
#define SDLK_F22 0x40000071u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F22) */
|
||||
#define SDLK_F23 0x40000072u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F23) */
|
||||
#define SDLK_F24 0x40000073u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F24) */
|
||||
#define SDLK_EXECUTE 0x40000074u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXECUTE) */
|
||||
#define SDLK_HELP 0x40000075u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HELP) */
|
||||
#define SDLK_MENU 0x40000076u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MENU) */
|
||||
#define SDLK_SELECT 0x40000077u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SELECT) */
|
||||
#define SDLK_STOP 0x40000078u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_STOP) */
|
||||
#define SDLK_AGAIN 0x40000079u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AGAIN) */
|
||||
#define SDLK_UNDO 0x4000007au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UNDO) */
|
||||
#define SDLK_CUT 0x4000007bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CUT) */
|
||||
#define SDLK_COPY 0x4000007cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COPY) */
|
||||
#define SDLK_PASTE 0x4000007du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PASTE) */
|
||||
#define SDLK_FIND 0x4000007eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_FIND) */
|
||||
#define SDLK_MUTE 0x4000007fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MUTE) */
|
||||
#define SDLK_VOLUMEUP 0x40000080u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEUP) */
|
||||
#define SDLK_VOLUMEDOWN 0x40000081u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEDOWN) */
|
||||
#define SDLK_KP_COMMA 0x40000085u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COMMA) */
|
||||
#define SDLK_KP_EQUALSAS400 0x40000086u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALSAS400) */
|
||||
#define SDLK_ALTERASE 0x40000099u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ALTERASE) */
|
||||
#define SDLK_SYSREQ 0x4000009au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SYSREQ) */
|
||||
#define SDLK_CANCEL 0x4000009bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CANCEL) */
|
||||
#define SDLK_CLEAR 0x4000009cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEAR) */
|
||||
#define SDLK_PRIOR 0x4000009du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRIOR) */
|
||||
#define SDLK_RETURN2 0x4000009eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RETURN2) */
|
||||
#define SDLK_SEPARATOR 0x4000009fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SEPARATOR) */
|
||||
#define SDLK_OUT 0x400000a0u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OUT) */
|
||||
#define SDLK_OPER 0x400000a1u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OPER) */
|
||||
#define SDLK_CLEARAGAIN 0x400000a2u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEARAGAIN) */
|
||||
#define SDLK_CRSEL 0x400000a3u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CRSEL) */
|
||||
#define SDLK_EXSEL 0x400000a4u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXSEL) */
|
||||
#define SDLK_KP_00 0x400000b0u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_00) */
|
||||
#define SDLK_KP_000 0x400000b1u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_000) */
|
||||
#define SDLK_THOUSANDSSEPARATOR 0x400000b2u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_THOUSANDSSEPARATOR) */
|
||||
#define SDLK_DECIMALSEPARATOR 0x400000b3u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DECIMALSEPARATOR) */
|
||||
#define SDLK_CURRENCYUNIT 0x400000b4u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYUNIT) */
|
||||
#define SDLK_CURRENCYSUBUNIT 0x400000b5u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYSUBUNIT) */
|
||||
#define SDLK_KP_LEFTPAREN 0x400000b6u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTPAREN) */
|
||||
#define SDLK_KP_RIGHTPAREN 0x400000b7u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTPAREN) */
|
||||
#define SDLK_KP_LEFTBRACE 0x400000b8u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTBRACE) */
|
||||
#define SDLK_KP_RIGHTBRACE 0x400000b9u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTBRACE) */
|
||||
#define SDLK_KP_TAB 0x400000bau /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_TAB) */
|
||||
#define SDLK_KP_BACKSPACE 0x400000bbu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BACKSPACE) */
|
||||
#define SDLK_KP_A 0x400000bcu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_A) */
|
||||
#define SDLK_KP_B 0x400000bdu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_B) */
|
||||
#define SDLK_KP_C 0x400000beu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_C) */
|
||||
#define SDLK_KP_D 0x400000bfu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_D) */
|
||||
#define SDLK_KP_E 0x400000c0u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_E) */
|
||||
#define SDLK_KP_F 0x400000c1u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_F) */
|
||||
#define SDLK_KP_XOR 0x400000c2u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_XOR) */
|
||||
#define SDLK_KP_POWER 0x400000c3u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_POWER) */
|
||||
#define SDLK_KP_PERCENT 0x400000c4u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERCENT) */
|
||||
#define SDLK_KP_LESS 0x400000c5u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LESS) */
|
||||
#define SDLK_KP_GREATER 0x400000c6u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_GREATER) */
|
||||
#define SDLK_KP_AMPERSAND 0x400000c7u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AMPERSAND) */
|
||||
#define SDLK_KP_DBLAMPERSAND 0x400000c8u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLAMPERSAND) */
|
||||
#define SDLK_KP_VERTICALBAR 0x400000c9u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_VERTICALBAR) */
|
||||
#define SDLK_KP_DBLVERTICALBAR 0x400000cau /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLVERTICALBAR) */
|
||||
#define SDLK_KP_COLON 0x400000cbu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COLON) */
|
||||
#define SDLK_KP_HASH 0x400000ccu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HASH) */
|
||||
#define SDLK_KP_SPACE 0x400000cdu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_SPACE) */
|
||||
#define SDLK_KP_AT 0x400000ceu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AT) */
|
||||
#define SDLK_KP_EXCLAM 0x400000cfu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EXCLAM) */
|
||||
#define SDLK_KP_MEMSTORE 0x400000d0u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSTORE) */
|
||||
#define SDLK_KP_MEMRECALL 0x400000d1u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMRECALL) */
|
||||
#define SDLK_KP_MEMCLEAR 0x400000d2u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMCLEAR) */
|
||||
#define SDLK_KP_MEMADD 0x400000d3u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMADD) */
|
||||
#define SDLK_KP_MEMSUBTRACT 0x400000d4u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSUBTRACT) */
|
||||
#define SDLK_KP_MEMMULTIPLY 0x400000d5u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMMULTIPLY) */
|
||||
#define SDLK_KP_MEMDIVIDE 0x400000d6u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMDIVIDE) */
|
||||
#define SDLK_KP_PLUSMINUS 0x400000d7u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUSMINUS) */
|
||||
#define SDLK_KP_CLEAR 0x400000d8u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEAR) */
|
||||
#define SDLK_KP_CLEARENTRY 0x400000d9u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEARENTRY) */
|
||||
#define SDLK_KP_BINARY 0x400000dau /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BINARY) */
|
||||
#define SDLK_KP_OCTAL 0x400000dbu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_OCTAL) */
|
||||
#define SDLK_KP_DECIMAL 0x400000dcu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DECIMAL) */
|
||||
#define SDLK_KP_HEXADECIMAL 0x400000ddu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HEXADECIMAL) */
|
||||
#define SDLK_LCTRL 0x400000e0u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LCTRL) */
|
||||
#define SDLK_LSHIFT 0x400000e1u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LSHIFT) */
|
||||
#define SDLK_LALT 0x400000e2u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LALT) */
|
||||
#define SDLK_LGUI 0x400000e3u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LGUI) */
|
||||
#define SDLK_RCTRL 0x400000e4u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RCTRL) */
|
||||
#define SDLK_RSHIFT 0x400000e5u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RSHIFT) */
|
||||
#define SDLK_RALT 0x400000e6u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RALT) */
|
||||
#define SDLK_RGUI 0x400000e7u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RGUI) */
|
||||
#define SDLK_MODE 0x40000101u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MODE) */
|
||||
#define SDLK_SLEEP 0x40000102u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP) */
|
||||
#define SDLK_WAKE 0x40000103u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_WAKE) */
|
||||
#define SDLK_CHANNEL_INCREMENT 0x40000104u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CHANNEL_INCREMENT) */
|
||||
#define SDLK_CHANNEL_DECREMENT 0x40000105u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CHANNEL_DECREMENT) */
|
||||
#define SDLK_MEDIA_PLAY 0x40000106u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_PLAY) */
|
||||
#define SDLK_MEDIA_PAUSE 0x40000107u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_PAUSE) */
|
||||
#define SDLK_MEDIA_RECORD 0x40000108u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_RECORD) */
|
||||
#define SDLK_MEDIA_FAST_FORWARD 0x40000109u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_FAST_FORWARD) */
|
||||
#define SDLK_MEDIA_REWIND 0x4000010au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_REWIND) */
|
||||
#define SDLK_MEDIA_NEXT_TRACK 0x4000010bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_NEXT_TRACK) */
|
||||
#define SDLK_MEDIA_PREVIOUS_TRACK 0x4000010cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_PREVIOUS_TRACK) */
|
||||
#define SDLK_MEDIA_STOP 0x4000010du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_STOP) */
|
||||
#define SDLK_MEDIA_EJECT 0x4000010eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_EJECT) */
|
||||
#define SDLK_MEDIA_PLAY_PAUSE 0x4000010fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_PLAY_PAUSE) */
|
||||
#define SDLK_MEDIA_SELECT 0x40000110u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIA_SELECT) */
|
||||
#define SDLK_AC_NEW 0x40000111u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_NEW) */
|
||||
#define SDLK_AC_OPEN 0x40000112u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_OPEN) */
|
||||
#define SDLK_AC_CLOSE 0x40000113u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_CLOSE) */
|
||||
#define SDLK_AC_EXIT 0x40000114u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_EXIT) */
|
||||
#define SDLK_AC_SAVE 0x40000115u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_SAVE) */
|
||||
#define SDLK_AC_PRINT 0x40000116u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_PRINT) */
|
||||
#define SDLK_AC_PROPERTIES 0x40000117u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_PROPERTIES) */
|
||||
#define SDLK_AC_SEARCH 0x40000118u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_SEARCH) */
|
||||
#define SDLK_AC_HOME 0x40000119u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_HOME) */
|
||||
#define SDLK_AC_BACK 0x4000011au /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BACK) */
|
||||
#define SDLK_AC_FORWARD 0x4000011bu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_FORWARD) */
|
||||
#define SDLK_AC_STOP 0x4000011cu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_STOP) */
|
||||
#define SDLK_AC_REFRESH 0x4000011du /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_REFRESH) */
|
||||
#define SDLK_AC_BOOKMARKS 0x4000011eu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BOOKMARKS) */
|
||||
#define SDLK_SOFTLEFT 0x4000011fu /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTLEFT) */
|
||||
#define SDLK_SOFTRIGHT 0x40000120u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SOFTRIGHT) */
|
||||
#define SDLK_CALL 0x40000121u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALL) */
|
||||
#define SDLK_ENDCALL 0x40000122u /**< SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ENDCALL) */
|
||||
#define SDLK_LEFT_TAB 0x20000001u /**< Extended key Left Tab */
|
||||
#define SDLK_LEVEL5_SHIFT 0x20000002u /**< Extended key Level 5 Shift */
|
||||
#define SDLK_MULTI_KEY_COMPOSE 0x20000003u /**< Extended key Multi-key Compose */
|
||||
#define SDLK_LMETA 0x20000004u /**< Extended key Left Meta */
|
||||
#define SDLK_RMETA 0x20000005u /**< Extended key Right Meta */
|
||||
#define SDLK_LHYPER 0x20000006u /**< Extended key Left Hyper */
|
||||
#define SDLK_RHYPER 0x20000007u /**< Extended key Right Hyper */
|
||||
|
||||
/**
|
||||
* Valid key modifiers (possibly OR'd together).
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint16 SDL_Keymod;
|
||||
|
||||
#define SDL_KMOD_NONE 0x0000u /**< no modifier is applicable. */
|
||||
#define SDL_KMOD_LSHIFT 0x0001u /**< the left Shift key is down. */
|
||||
#define SDL_KMOD_RSHIFT 0x0002u /**< the right Shift key is down. */
|
||||
#define SDL_KMOD_LEVEL5 0x0004u /**< the Level 5 Shift key is down. */
|
||||
#define SDL_KMOD_LCTRL 0x0040u /**< the left Ctrl (Control) key is down. */
|
||||
#define SDL_KMOD_RCTRL 0x0080u /**< the right Ctrl (Control) key is down. */
|
||||
#define SDL_KMOD_LALT 0x0100u /**< the left Alt key is down. */
|
||||
#define SDL_KMOD_RALT 0x0200u /**< the right Alt key is down. */
|
||||
#define SDL_KMOD_LGUI 0x0400u /**< the left GUI key (often the Windows key) is down. */
|
||||
#define SDL_KMOD_RGUI 0x0800u /**< the right GUI key (often the Windows key) is down. */
|
||||
#define SDL_KMOD_NUM 0x1000u /**< the Num Lock key (may be located on an extended keypad) is down. */
|
||||
#define SDL_KMOD_CAPS 0x2000u /**< the Caps Lock key is down. */
|
||||
#define SDL_KMOD_MODE 0x4000u /**< the !AltGr key is down. */
|
||||
#define SDL_KMOD_SCROLL 0x8000u /**< the Scroll Lock key is down. */
|
||||
#define SDL_KMOD_CTRL (SDL_KMOD_LCTRL | SDL_KMOD_RCTRL) /**< Any Ctrl key is down. */
|
||||
#define SDL_KMOD_SHIFT (SDL_KMOD_LSHIFT | SDL_KMOD_RSHIFT) /**< Any Shift key is down. */
|
||||
#define SDL_KMOD_ALT (SDL_KMOD_LALT | SDL_KMOD_RALT) /**< Any Alt key is down. */
|
||||
#define SDL_KMOD_GUI (SDL_KMOD_LGUI | SDL_KMOD_RGUI) /**< Any GUI key is down. */
|
||||
|
||||
#endif /* SDL_keycode_h_ */
|
||||
@@ -0,0 +1,704 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryMain
|
||||
*
|
||||
* Redefine main() if necessary so that it is called by SDL.
|
||||
*
|
||||
* In order to make this consistent on all platforms, the application's main()
|
||||
* should look like this:
|
||||
*
|
||||
* ```c
|
||||
* #include <SDL3/SDL.h>
|
||||
* #include <SDL3/SDL_main.h>
|
||||
*
|
||||
* int main(int argc, char *argv[])
|
||||
* {
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* SDL will take care of platform specific details on how it gets called.
|
||||
*
|
||||
* This is also where an app can be configured to use the main callbacks, via
|
||||
* the SDL_MAIN_USE_CALLBACKS macro.
|
||||
*
|
||||
* SDL_main.h is a "single-header library," which is to say that including
|
||||
* this header inserts code into your program, and you should only include it
|
||||
* once in most cases. SDL.h does not include this header automatically.
|
||||
*
|
||||
* For more information, see:
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/README-main-functions
|
||||
*/
|
||||
|
||||
#ifndef SDL_main_h_
|
||||
#define SDL_main_h_
|
||||
|
||||
#include <SDL3/SDL_platform_defines.h>
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* Inform SDL that the app is providing an entry point instead of SDL.
|
||||
*
|
||||
* SDL does not define this macro, but will check if it is defined when
|
||||
* including `SDL_main.h`. If defined, SDL will expect the app to provide the
|
||||
* proper entry point for the platform, and all the other magic details
|
||||
* needed, like manually calling SDL_SetMainReady.
|
||||
*
|
||||
* Please see [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
* \since This macro is used by the headers since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MAIN_HANDLED 1
|
||||
|
||||
/**
|
||||
* Inform SDL to use the main callbacks instead of main.
|
||||
*
|
||||
* SDL does not define this macro, but will check if it is defined when
|
||||
* including `SDL_main.h`. If defined, SDL will expect the app to provide
|
||||
* several functions: SDL_AppInit, SDL_AppEvent, SDL_AppIterate, and
|
||||
* SDL_AppQuit. The app should not provide a `main` function in this case, and
|
||||
* doing so will likely cause the build to fail.
|
||||
*
|
||||
* Please see [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
* \since This macro is used by the headers since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AppInit
|
||||
* \sa SDL_AppEvent
|
||||
* \sa SDL_AppIterate
|
||||
* \sa SDL_AppQuit
|
||||
*/
|
||||
#define SDL_MAIN_USE_CALLBACKS 1
|
||||
|
||||
/**
|
||||
* Defined if the target platform offers a special mainline through SDL.
|
||||
*
|
||||
* This won't be defined otherwise. If defined, SDL's headers will redefine
|
||||
* `main` to `SDL_main`.
|
||||
*
|
||||
* This macro is defined by `SDL_main.h`, which is not automatically included
|
||||
* by `SDL.h`.
|
||||
*
|
||||
* Even if available, an app can define SDL_MAIN_HANDLED and provide their
|
||||
* own, if they know what they're doing.
|
||||
*
|
||||
* This macro is used internally by SDL, and apps probably shouldn't rely on
|
||||
* it.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
/**
|
||||
* Defined if the target platform _requires_ a special mainline through SDL.
|
||||
*
|
||||
* This won't be defined otherwise. If defined, SDL's headers will redefine
|
||||
* `main` to `SDL_main`.
|
||||
*
|
||||
* This macro is defined by `SDL_main.h`, which is not automatically included
|
||||
* by `SDL.h`.
|
||||
*
|
||||
* Even if required, an app can define SDL_MAIN_HANDLED and provide their own,
|
||||
* if they know what they're doing.
|
||||
*
|
||||
* This macro is used internally by SDL, and apps probably shouldn't rely on
|
||||
* it.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MAIN_NEEDED
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include("SDL_main_private.h") && __has_include("SDL_main_impl_private.h")
|
||||
#define SDL_PLATFORM_PRIVATE_MAIN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_MAIN_HANDLED
|
||||
#if defined(SDL_PLATFORM_PRIVATE_MAIN)
|
||||
/* Private platforms may have their own ideas about entry points. */
|
||||
#include "SDL_main_private.h"
|
||||
|
||||
#elif defined(SDL_PLATFORM_WIN32)
|
||||
/* On Windows SDL provides WinMain(), which parses the command line and passes
|
||||
the arguments to your main function.
|
||||
|
||||
If you provide your own WinMain(), you may define SDL_MAIN_HANDLED
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#elif defined(SDL_PLATFORM_GDK)
|
||||
/* On GDK, SDL provides a main function that initializes the game runtime.
|
||||
|
||||
If you prefer to write your own WinMain-function instead of having SDL
|
||||
provide one that calls your main() function,
|
||||
#define SDL_MAIN_HANDLED before #include'ing SDL_main.h
|
||||
and call the SDL_RunApp function from your entry point.
|
||||
*/
|
||||
#define SDL_MAIN_NEEDED
|
||||
|
||||
#elif defined(SDL_PLATFORM_IOS) || defined(SDL_PLATFORM_TVOS)
|
||||
/* On iOS and tvOS SDL provides a main function that creates an application delegate and starts the application run loop.
|
||||
|
||||
To use it, just #include <SDL3/SDL_main.h> in the source file that contains your main() function.
|
||||
|
||||
See src/video/uikit/SDL_uikitappdelegate.m for more details.
|
||||
*/
|
||||
#define SDL_MAIN_NEEDED
|
||||
|
||||
#elif defined(SDL_PLATFORM_ANDROID)
|
||||
/* On Android SDL provides a Java class in SDLActivity.java that is the
|
||||
main activity entry point.
|
||||
|
||||
See docs/README-android.md for more details on extending that class.
|
||||
*/
|
||||
#define SDL_MAIN_NEEDED
|
||||
|
||||
/* As this is launched from Java, the real entry point (main() function)
|
||||
is outside of the the binary built from this code.
|
||||
This define makes sure that, unlike on other platforms, SDL_main.h
|
||||
and SDL_main_impl.h export an `SDL_main()` function (to be called
|
||||
from Java), but don't implement a native `int main(int argc, char* argv[])`
|
||||
or similar.
|
||||
*/
|
||||
#define SDL_MAIN_EXPORTED
|
||||
|
||||
#elif defined(SDL_PLATFORM_EMSCRIPTEN)
|
||||
/* On Emscripten, SDL provides a main function that converts URL
|
||||
parameters that start with "SDL_" to environment variables, so
|
||||
they can be used as SDL hints, etc.
|
||||
|
||||
This is 100% optional, so if you don't want this to happen, you may
|
||||
define SDL_MAIN_HANDLED
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#elif defined(SDL_PLATFORM_PSP)
|
||||
/* On PSP SDL provides a main function that sets the module info,
|
||||
activates the GPU and starts the thread required to be able to exit
|
||||
the software.
|
||||
|
||||
If you provide this yourself, you may define SDL_MAIN_HANDLED
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#elif defined(SDL_PLATFORM_PS2)
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#define SDL_PS2_SKIP_IOP_RESET() \
|
||||
void reset_IOP(); \
|
||||
void reset_IOP() {}
|
||||
|
||||
#elif defined(SDL_PLATFORM_3DS)
|
||||
/*
|
||||
On N3DS, SDL provides a main function that sets up the screens
|
||||
and storage.
|
||||
|
||||
If you provide this yourself, you may define SDL_MAIN_HANDLED
|
||||
*/
|
||||
#define SDL_MAIN_AVAILABLE
|
||||
|
||||
#endif
|
||||
#endif /* SDL_MAIN_HANDLED */
|
||||
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A macro to tag a main entry point function as exported.
|
||||
*
|
||||
* Most platforms don't need this, and the macro will be defined to nothing.
|
||||
* Some, like Android, keep the entry points in a shared library and need to
|
||||
* explicitly export the symbols.
|
||||
*
|
||||
* External code rarely needs this, and if it needs something, it's almost
|
||||
* always SDL_DECLSPEC instead.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DECLSPEC
|
||||
*/
|
||||
#define SDLMAIN_DECLSPEC
|
||||
|
||||
#elif defined(SDL_MAIN_EXPORTED)
|
||||
/* We need to export SDL_main so it can be launched from external code,
|
||||
like SDLActivity.java on Android */
|
||||
#define SDLMAIN_DECLSPEC SDL_DECLSPEC
|
||||
#else
|
||||
/* usually this is empty */
|
||||
#define SDLMAIN_DECLSPEC
|
||||
#endif /* SDL_WIKI_DOCUMENTATION_SECTION */
|
||||
|
||||
#if defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE) || defined(SDL_MAIN_USE_CALLBACKS)
|
||||
#define main SDL_main
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL_init.h>
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* You can (optionally!) define SDL_MAIN_USE_CALLBACKS before including
|
||||
* SDL_main.h, and then your application will _not_ have a standard
|
||||
* "main" entry point. Instead, it will operate as a collection of
|
||||
* functions that are called as necessary by the system. On some
|
||||
* platforms, this is just a layer where SDL drives your program
|
||||
* instead of your program driving SDL, on other platforms this might
|
||||
* hook into the OS to manage the lifecycle. Programs on most platforms
|
||||
* can use whichever approach they prefer, but the decision boils down
|
||||
* to:
|
||||
*
|
||||
* - Using a standard "main" function: this works like it always has for
|
||||
* the past 50+ years in C programming, and your app is in control.
|
||||
* - Using the callback functions: this might clean up some code,
|
||||
* avoid some #ifdef blocks in your program for some platforms, be more
|
||||
* resource-friendly to the system, and possibly be the primary way to
|
||||
* access some future platforms (but none require this at the moment).
|
||||
*
|
||||
* This is up to the app; both approaches are considered valid and supported
|
||||
* ways to write SDL apps.
|
||||
*
|
||||
* If using the callbacks, don't define a "main" function. Instead, implement
|
||||
* the functions listed below in your program.
|
||||
*/
|
||||
#ifdef SDL_MAIN_USE_CALLBACKS
|
||||
|
||||
/**
|
||||
* App-implemented initial entry point for SDL_MAIN_USE_CALLBACKS apps.
|
||||
*
|
||||
* Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a
|
||||
* standard "main" function, you should not supply this.
|
||||
*
|
||||
* This function is called by SDL once, at startup. The function should
|
||||
* initialize whatever is necessary, possibly create windows and open audio
|
||||
* devices, etc. The `argc` and `argv` parameters work like they would with a
|
||||
* standard "main" function.
|
||||
*
|
||||
* This function should not go into an infinite mainloop; it should do any
|
||||
* one-time setup it requires and then return.
|
||||
*
|
||||
* The app may optionally assign a pointer to `*appstate`. This pointer will
|
||||
* be provided on every future call to the other entry points, to allow
|
||||
* application state to be preserved between functions without the app needing
|
||||
* to use a global variable. If this isn't set, the pointer will be NULL in
|
||||
* future entry points.
|
||||
*
|
||||
* If this function returns SDL_APP_CONTINUE, the app will proceed to normal
|
||||
* operation, and will begin receiving repeated calls to SDL_AppIterate and
|
||||
* SDL_AppEvent for the life of the program. If this function returns
|
||||
* SDL_APP_FAILURE, SDL will call SDL_AppQuit and terminate the process with
|
||||
* an exit code that reports an error to the platform. If it returns
|
||||
* SDL_APP_SUCCESS, SDL calls SDL_AppQuit and terminates with an exit code
|
||||
* that reports success to the platform.
|
||||
*
|
||||
* This function is called by SDL on the main thread.
|
||||
*
|
||||
* \param appstate a place where the app can optionally store a pointer for
|
||||
* future use.
|
||||
* \param argc the standard ANSI C main's argc; number of elements in `argv`.
|
||||
* \param argv the standard ANSI C main's argv; array of command line
|
||||
* arguments.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \threadsafety This function is called once by SDL, at startup, on a single
|
||||
* thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AppIterate
|
||||
* \sa SDL_AppEvent
|
||||
* \sa SDL_AppQuit
|
||||
*/
|
||||
extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* App-implemented iteration entry point for SDL_MAIN_USE_CALLBACKS apps.
|
||||
*
|
||||
* Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a
|
||||
* standard "main" function, you should not supply this.
|
||||
*
|
||||
* This function is called repeatedly by SDL after SDL_AppInit returns
|
||||
* SDL_APP_CONTINUE. The function should operate as a single iteration the
|
||||
* program's primary loop; it should update whatever state it needs and draw a
|
||||
* new frame of video, usually.
|
||||
*
|
||||
* On some platforms, this function will be called at the refresh rate of the
|
||||
* display (which might change during the life of your app!). There are no
|
||||
* promises made about what frequency this function might run at. You should
|
||||
* use SDL's timer functions if you need to see how much time has passed since
|
||||
* the last iteration.
|
||||
*
|
||||
* There is no need to process the SDL event queue during this function; SDL
|
||||
* will send events as they arrive in SDL_AppEvent, and in most cases the
|
||||
* event queue will be empty when this function runs anyhow.
|
||||
*
|
||||
* This function should not go into an infinite mainloop; it should do one
|
||||
* iteration of whatever the program does and return.
|
||||
*
|
||||
* The `appstate` parameter is an optional pointer provided by the app during
|
||||
* SDL_AppInit(). If the app never provided a pointer, this will be NULL.
|
||||
*
|
||||
* If this function returns SDL_APP_CONTINUE, the app will continue normal
|
||||
* operation, receiving repeated calls to SDL_AppIterate and SDL_AppEvent for
|
||||
* the life of the program. If this function returns SDL_APP_FAILURE, SDL will
|
||||
* call SDL_AppQuit and terminate the process with an exit code that reports
|
||||
* an error to the platform. If it returns SDL_APP_SUCCESS, SDL calls
|
||||
* SDL_AppQuit and terminates with an exit code that reports success to the
|
||||
* platform.
|
||||
*
|
||||
* This function is called by SDL on the main thread.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \threadsafety This function may get called concurrently with SDL_AppEvent()
|
||||
* for events not pushed on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AppInit
|
||||
* \sa SDL_AppEvent
|
||||
*/
|
||||
extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppIterate(void *appstate);
|
||||
|
||||
/**
|
||||
* App-implemented event entry point for SDL_MAIN_USE_CALLBACKS apps.
|
||||
*
|
||||
* Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a
|
||||
* standard "main" function, you should not supply this.
|
||||
*
|
||||
* This function is called as needed by SDL after SDL_AppInit returns
|
||||
* SDL_APP_CONTINUE. It is called once for each new event.
|
||||
*
|
||||
* There is (currently) no guarantee about what thread this will be called
|
||||
* from; whatever thread pushes an event onto SDL's queue will trigger this
|
||||
* function. SDL is responsible for pumping the event queue between each call
|
||||
* to SDL_AppIterate, so in normal operation one should only get events in a
|
||||
* serial fashion, but be careful if you have a thread that explicitly calls
|
||||
* SDL_PushEvent. SDL itself will push events to the queue on the main thread.
|
||||
*
|
||||
* Events sent to this function are not owned by the app; if you need to save
|
||||
* the data, you should copy it.
|
||||
*
|
||||
* This function should not go into an infinite mainloop; it should handle the
|
||||
* provided event appropriately and return.
|
||||
*
|
||||
* The `appstate` parameter is an optional pointer provided by the app during
|
||||
* SDL_AppInit(). If the app never provided a pointer, this will be NULL.
|
||||
*
|
||||
* If this function returns SDL_APP_CONTINUE, the app will continue normal
|
||||
* operation, receiving repeated calls to SDL_AppIterate and SDL_AppEvent for
|
||||
* the life of the program. If this function returns SDL_APP_FAILURE, SDL will
|
||||
* call SDL_AppQuit and terminate the process with an exit code that reports
|
||||
* an error to the platform. If it returns SDL_APP_SUCCESS, SDL calls
|
||||
* SDL_AppQuit and terminates with an exit code that reports success to the
|
||||
* platform.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \param event the new event for the app to examine.
|
||||
* \returns SDL_APP_FAILURE to terminate with an error, SDL_APP_SUCCESS to
|
||||
* terminate with success, SDL_APP_CONTINUE to continue.
|
||||
*
|
||||
* \threadsafety This function may get called concurrently with
|
||||
* SDL_AppIterate() or SDL_AppQuit() for events not pushed from
|
||||
* the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AppInit
|
||||
* \sa SDL_AppIterate
|
||||
*/
|
||||
extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppEvent(void *appstate, SDL_Event *event);
|
||||
|
||||
/**
|
||||
* App-implemented deinit entry point for SDL_MAIN_USE_CALLBACKS apps.
|
||||
*
|
||||
* Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a
|
||||
* standard "main" function, you should not supply this.
|
||||
*
|
||||
* This function is called once by SDL before terminating the program.
|
||||
*
|
||||
* This function will be called in all cases, even if SDL_AppInit requests
|
||||
* termination at startup.
|
||||
*
|
||||
* This function should not go into an infinite mainloop; it should
|
||||
* deinitialize any resources necessary, perform whatever shutdown activities,
|
||||
* and return.
|
||||
*
|
||||
* You do not need to call SDL_Quit() in this function, as SDL will call it
|
||||
* after this function returns and before the process terminates, but it is
|
||||
* safe to do so.
|
||||
*
|
||||
* The `appstate` parameter is an optional pointer provided by the app during
|
||||
* SDL_AppInit(). If the app never provided a pointer, this will be NULL. This
|
||||
* function call is the last time this pointer will be provided, so any
|
||||
* resources to it should be cleaned up here.
|
||||
*
|
||||
* This function is called by SDL on the main thread.
|
||||
*
|
||||
* \param appstate an optional pointer, provided by the app in SDL_AppInit.
|
||||
* \param result the result code that terminated the app (success or failure).
|
||||
*
|
||||
* \threadsafety SDL_AppEvent() may get called concurrently with this function
|
||||
* if other threads that push events are still active.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AppInit
|
||||
*/
|
||||
extern SDLMAIN_DECLSPEC void SDLCALL SDL_AppQuit(void *appstate, SDL_AppResult result);
|
||||
|
||||
#endif /* SDL_MAIN_USE_CALLBACKS */
|
||||
|
||||
|
||||
/**
|
||||
* The prototype for the application's main() function
|
||||
*
|
||||
* \param argc an ANSI-C style main function's argc.
|
||||
* \param argv an ANSI-C style main function's argv.
|
||||
* \returns an ANSI-C main return code; generally 0 is considered successful
|
||||
* program completion, and small non-zero values are considered
|
||||
* errors.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef int (SDLCALL *SDL_main_func)(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* An app-supplied function for program entry.
|
||||
*
|
||||
* Apps do not directly create this function; they should create a standard
|
||||
* ANSI-C `main` function instead. If SDL needs to insert some startup code
|
||||
* before `main` runs, or the platform doesn't actually _use_ a function
|
||||
* called "main", SDL will do some macro magic to redefine `main` to
|
||||
* `SDL_main` and provide its own `main`.
|
||||
*
|
||||
* Apps should include `SDL_main.h` in the same file as their `main` function,
|
||||
* and they should not use that symbol for anything else in that file, as it
|
||||
* might get redefined.
|
||||
*
|
||||
* This function is only provided by the app if it isn't using
|
||||
* SDL_MAIN_USE_CALLBACKS.
|
||||
*
|
||||
* Program startup is a surprisingly complex topic. Please see
|
||||
* [README-main-functions](README-main-functions), (or
|
||||
* docs/README-main-functions.md in the source tree) for a more detailed
|
||||
* explanation.
|
||||
*
|
||||
* \param argc an ANSI-C style main function's argc.
|
||||
* \param argv an ANSI-C style main function's argv.
|
||||
* \returns an ANSI-C main return code; generally 0 is considered successful
|
||||
* program completion, and small non-zero values are considered
|
||||
* errors.
|
||||
*
|
||||
* \threadsafety This is the program entry point.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDLMAIN_DECLSPEC int SDLCALL SDL_main(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Circumvent failure of SDL_Init() when not using SDL_main() as an entry
|
||||
* point.
|
||||
*
|
||||
* This function is defined in SDL_main.h, along with the preprocessor rule to
|
||||
* redefine main() as SDL_main(). Thus to ensure that your main() function
|
||||
* will not be changed it is necessary to define SDL_MAIN_HANDLED before
|
||||
* including SDL.h.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Init
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_SetMainReady(void);
|
||||
|
||||
/**
|
||||
* Initializes and launches an SDL application, by doing platform-specific
|
||||
* initialization before calling your mainFunction and cleanups after it
|
||||
* returns, if that is needed for a specific platform, otherwise it just calls
|
||||
* mainFunction.
|
||||
*
|
||||
* You can use this if you want to use your own main() implementation without
|
||||
* using SDL_main (like when using SDL_MAIN_HANDLED). When using this, you do
|
||||
* *not* need SDL_SetMainReady().
|
||||
*
|
||||
* If `argv` is NULL, SDL will provide command line arguments, either by
|
||||
* querying the OS for them if possible, or supplying a filler array if not.
|
||||
*
|
||||
* \param argc the argc parameter from the application's main() function, or 0
|
||||
* if the platform's main-equivalent has no argc.
|
||||
* \param argv the argv parameter from the application's main() function, or
|
||||
* NULL if the platform's main-equivalent has no argv.
|
||||
* \param mainFunction your SDL app's C-style main(). NOT the function you're
|
||||
* calling this from! Its name doesn't matter; it doesn't
|
||||
* literally have to be `main`.
|
||||
* \param reserved should be NULL (reserved for future use, will probably be
|
||||
* platform-specific then).
|
||||
* \returns the return value from mainFunction: 0 on success, otherwise
|
||||
* failure; SDL_GetError() might have more information on the
|
||||
* failure.
|
||||
*
|
||||
* \threadsafety Generally this is called once, near startup, from the
|
||||
* process's initial thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved);
|
||||
|
||||
/**
|
||||
* An entry point for SDL's use in SDL_MAIN_USE_CALLBACKS.
|
||||
*
|
||||
* Generally, you should not call this function directly. This only exists to
|
||||
* hand off work into SDL as soon as possible, where it has a lot more control
|
||||
* and functionality available, and make the inline code in SDL_main.h as
|
||||
* small as possible.
|
||||
*
|
||||
* Not all platforms use this, it's actual use is hidden in a magic
|
||||
* header-only library, and you should not call this directly unless you
|
||||
* _really_ know what you're doing.
|
||||
*
|
||||
* \param argc standard Unix main argc.
|
||||
* \param argv standard Unix main argv.
|
||||
* \param appinit the application's SDL_AppInit function.
|
||||
* \param appiter the application's SDL_AppIterate function.
|
||||
* \param appevent the application's SDL_AppEvent function.
|
||||
* \param appquit the application's SDL_AppQuit function.
|
||||
* \returns standard Unix main return value.
|
||||
*
|
||||
* \threadsafety It is not safe to call this anywhere except as the only
|
||||
* function call in SDL_main.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_EnterAppMainCallbacks(int argc, char *argv[], SDL_AppInit_func appinit, SDL_AppIterate_func appiter, SDL_AppEvent_func appevent, SDL_AppQuit_func appquit);
|
||||
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
/**
|
||||
* Register a win32 window class for SDL's use.
|
||||
*
|
||||
* This can be called to set the application window class at startup. It is
|
||||
* safe to call this multiple times, as long as every call is eventually
|
||||
* paired with a call to SDL_UnregisterApp, but a second registration attempt
|
||||
* while a previous registration is still active will be ignored, other than
|
||||
* to increment a counter.
|
||||
*
|
||||
* Most applications do not need to, and should not, call this directly; SDL
|
||||
* will call it when initializing the video subsystem.
|
||||
*
|
||||
* If `name` is NULL, SDL currently uses `(CS_BYTEALIGNCLIENT | CS_OWNDC)` for
|
||||
* the style, regardless of what is specified here.
|
||||
*
|
||||
* \param name the window class name, in UTF-8 encoding. If NULL, SDL
|
||||
* currently uses "SDL_app" but this isn't guaranteed.
|
||||
* \param style the value to use in WNDCLASSEX::style.
|
||||
* \param hInst the HINSTANCE to use in WNDCLASSEX::hInstance. If zero, SDL
|
||||
* will use `GetModuleHandle(NULL)` instead.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_RegisterApp(const char *name, Uint32 style, void *hInst);
|
||||
|
||||
/**
|
||||
* Deregister the win32 window class from an SDL_RegisterApp call.
|
||||
*
|
||||
* This can be called to undo the effects of SDL_RegisterApp.
|
||||
*
|
||||
* Most applications do not need to, and should not, call this directly; SDL
|
||||
* will call it when deinitializing the video subsystem.
|
||||
*
|
||||
* It is safe to call this multiple times, as long as every call is eventually
|
||||
* paired with a prior call to SDL_RegisterApp. The window class will only be
|
||||
* deregistered when the registration counter in SDL_RegisterApp decrements to
|
||||
* zero through calls to this function.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_UnregisterApp(void);
|
||||
|
||||
#endif /* defined(SDL_PLATFORM_WINDOWS) */
|
||||
|
||||
/**
|
||||
* Callback from the application to let the suspend continue.
|
||||
*
|
||||
* This should be called from an event watch in response to an
|
||||
* `SDL_EVENT_DID_ENTER_BACKGROUND` event.
|
||||
*
|
||||
* When using SDL_Render, your event watch should be added _after_ creating
|
||||
* the `SDL_Renderer`; this allows the timing of the D3D12 command queue
|
||||
* suspension to execute in the correct order.
|
||||
*
|
||||
* When using SDL_GPU, this should be called after calling SDL_GDKSuspendGPU.
|
||||
*
|
||||
* If you're writing your own D3D12 renderer, this should be called after
|
||||
* calling `ID3D12CommandQueue::SuspendX`.
|
||||
*
|
||||
* This function is only needed for Xbox GDK support; all other platforms will
|
||||
* do nothing and set an "unsupported" error message.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddEventWatch
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_GDKSuspendComplete(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#if !defined(SDL_MAIN_HANDLED) && !defined(SDL_MAIN_NOIMPL)
|
||||
/* include header-only SDL_main implementations */
|
||||
#if defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_NEEDED) || defined(SDL_MAIN_AVAILABLE)
|
||||
/* platforms which main (-equivalent) can be implemented in plain C */
|
||||
#include <SDL3/SDL_main_impl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* SDL_main_h_ */
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* WIKI CATEGORY: Main */
|
||||
|
||||
#ifndef SDL_main_impl_h_
|
||||
#define SDL_main_impl_h_
|
||||
|
||||
#ifndef SDL_main_h_
|
||||
#error "This header should not be included directly, but only via SDL_main.h!"
|
||||
#endif
|
||||
|
||||
/* if someone wants to include SDL_main.h but doesn't want the main handing magic,
|
||||
(maybe to call SDL_RegisterApp()) they can #define SDL_MAIN_HANDLED first.
|
||||
SDL_MAIN_NOIMPL is for SDL-internal usage (only affects implementation,
|
||||
not definition of SDL_MAIN_AVAILABLE etc in SDL_main.h) and if the user wants
|
||||
to have the SDL_main implementation (from this header) in another source file
|
||||
than their main() function, for example if SDL_main requires C++
|
||||
and main() is implemented in plain C */
|
||||
#if !defined(SDL_MAIN_HANDLED) && !defined(SDL_MAIN_NOIMPL)
|
||||
|
||||
/* the implementations below must be able to use the implement real main(), nothing renamed
|
||||
(the user's main() will be renamed to SDL_main so it can be called from here) */
|
||||
#ifdef main
|
||||
#undef main
|
||||
#endif
|
||||
|
||||
#ifdef SDL_MAIN_USE_CALLBACKS
|
||||
|
||||
#if 0
|
||||
/* currently there are no platforms that _need_ a magic entry point here
|
||||
for callbacks, but if one shows up, implement it here. */
|
||||
|
||||
#else /* use a standard SDL_main, which the app SHOULD NOT ALSO SUPPLY. */
|
||||
|
||||
/* this define makes the normal SDL_main entry point stuff work...we just provide SDL_main() instead of the app. */
|
||||
#define SDL_MAIN_CALLBACK_STANDARD 1
|
||||
|
||||
int SDL_main(int argc, char **argv)
|
||||
{
|
||||
return SDL_EnterAppMainCallbacks(argc, argv, SDL_AppInit, SDL_AppIterate, SDL_AppEvent, SDL_AppQuit);
|
||||
}
|
||||
|
||||
#endif /* platform-specific tests */
|
||||
|
||||
#endif /* SDL_MAIN_USE_CALLBACKS */
|
||||
|
||||
|
||||
/* set up the usual SDL_main stuff if we're not using callbacks or if we are but need the normal entry point,
|
||||
unless the real entry point needs to be somewhere else entirely, like Android where it's in Java code */
|
||||
#if (!defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_CALLBACK_STANDARD)) && !defined(SDL_MAIN_EXPORTED)
|
||||
|
||||
#if defined(SDL_PLATFORM_PRIVATE_MAIN)
|
||||
/* Private platforms may have their own ideas about entry points. */
|
||||
#include "SDL_main_impl_private.h"
|
||||
|
||||
#elif defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
/* these defines/typedefs are needed for the WinMain() definition */
|
||||
#ifndef WINAPI
|
||||
#define WINAPI __stdcall
|
||||
#endif
|
||||
|
||||
typedef struct HINSTANCE__ * HINSTANCE;
|
||||
typedef char *LPSTR;
|
||||
typedef wchar_t *PWSTR;
|
||||
|
||||
/* The VC++ compiler needs main/wmain defined, but not for GDK */
|
||||
#if defined(_MSC_VER) && !defined(SDL_PLATFORM_GDK)
|
||||
|
||||
/* This is where execution begins [console apps] */
|
||||
#if defined(UNICODE) && UNICODE
|
||||
int wmain(int argc, wchar_t *wargv[], wchar_t *wenvp)
|
||||
{
|
||||
(void)argc;
|
||||
(void)wargv;
|
||||
(void)wenvp;
|
||||
return SDL_RunApp(0, NULL, SDL_main, NULL);
|
||||
}
|
||||
#else /* ANSI */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
return SDL_RunApp(0, NULL, SDL_main, NULL);
|
||||
}
|
||||
#endif /* UNICODE */
|
||||
|
||||
#endif /* _MSC_VER && ! SDL_PLATFORM_GDK */
|
||||
|
||||
/* This is where execution begins [windowed apps and GDK] */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(UNICODE) && UNICODE
|
||||
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrev, PWSTR szCmdLine, int sw)
|
||||
#else /* ANSI */
|
||||
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw)
|
||||
#endif
|
||||
{
|
||||
(void)hInst;
|
||||
(void)hPrev;
|
||||
(void)szCmdLine;
|
||||
(void)sw;
|
||||
return SDL_RunApp(0, NULL, SDL_main, NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
/* end of SDL_PLATFORM_WINDOWS impls */
|
||||
|
||||
#else /* platforms that use a standard main() and just call SDL_RunApp(), like iOS and 3DS */
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return SDL_RunApp(argc, argv, SDL_main, NULL);
|
||||
}
|
||||
|
||||
/* end of impls for standard-conforming platforms */
|
||||
|
||||
#endif /* SDL_PLATFORM_WIN32 etc */
|
||||
|
||||
#endif /* !defined(SDL_MAIN_USE_CALLBACKS) || defined(SDL_MAIN_CALLBACK_STANDARD) */
|
||||
|
||||
/* rename users main() function to SDL_main() so it can be called from the wrappers above */
|
||||
#define main SDL_main
|
||||
|
||||
#endif /* SDL_MAIN_HANDLED */
|
||||
|
||||
#endif /* SDL_main_impl_h_ */
|
||||
@@ -0,0 +1,813 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryMouse
|
||||
*
|
||||
* Any GUI application has to deal with the mouse, and SDL provides functions
|
||||
* to manage mouse input and the displayed cursor.
|
||||
*
|
||||
* Most interactions with the mouse will come through the event subsystem.
|
||||
* Moving a mouse generates an SDL_EVENT_MOUSE_MOTION event, pushing a button
|
||||
* generates SDL_EVENT_MOUSE_BUTTON_DOWN, etc, but one can also query the
|
||||
* current state of the mouse at any time with SDL_GetMouseState().
|
||||
*
|
||||
* For certain games, it's useful to disassociate the mouse cursor from mouse
|
||||
* input. An FPS, for example, would not want the player's motion to stop as
|
||||
* the mouse hits the edge of the window. For these scenarios, use
|
||||
* SDL_SetWindowRelativeMouseMode(), which hides the cursor, grabs mouse input
|
||||
* to the window, and reads mouse input no matter how far it moves.
|
||||
*
|
||||
* Games that want the system to track the mouse but want to draw their own
|
||||
* cursor can use SDL_HideCursor() and SDL_ShowCursor(). It might be more
|
||||
* efficient to let the system manage the cursor, if possible, using
|
||||
* SDL_SetCursor() with a custom image made through SDL_CreateColorCursor(),
|
||||
* or perhaps just a specific system cursor from SDL_CreateSystemCursor().
|
||||
*
|
||||
* SDL can, on many platforms, differentiate between multiple connected mice,
|
||||
* allowing for interesting input scenarios and multiplayer games. They can be
|
||||
* enumerated with SDL_GetMice(), and SDL will send SDL_EVENT_MOUSE_ADDED and
|
||||
* SDL_EVENT_MOUSE_REMOVED events as they are connected and unplugged.
|
||||
*
|
||||
* Since many apps only care about basic mouse input, SDL offers a virtual
|
||||
* mouse device for touch and pen input, which often can make a desktop
|
||||
* application work on a touchscreen phone without any code changes. Apps that
|
||||
* care about touch/pen separately from mouse input should filter out events
|
||||
* with a `which` field of SDL_TOUCH_MOUSEID/SDL_PEN_MOUSEID.
|
||||
*/
|
||||
|
||||
#ifndef SDL_mouse_h_
|
||||
#define SDL_mouse_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_surface.h>
|
||||
#include <SDL3/SDL_video.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is a unique ID for a mouse for the time it is connected to the system,
|
||||
* and is never reused for the lifetime of the application.
|
||||
*
|
||||
* If the mouse is disconnected and reconnected, it will get a new ID.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_MouseID;
|
||||
|
||||
/**
|
||||
* The structure used to identify an SDL cursor.
|
||||
*
|
||||
* This is opaque data.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef struct SDL_Cursor SDL_Cursor;
|
||||
|
||||
/**
|
||||
* Cursor types for SDL_CreateSystemCursor().
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_SystemCursor
|
||||
{
|
||||
SDL_SYSTEM_CURSOR_DEFAULT, /**< Default cursor. Usually an arrow. */
|
||||
SDL_SYSTEM_CURSOR_TEXT, /**< Text selection. Usually an I-beam. */
|
||||
SDL_SYSTEM_CURSOR_WAIT, /**< Wait. Usually an hourglass or watch or spinning ball. */
|
||||
SDL_SYSTEM_CURSOR_CROSSHAIR, /**< Crosshair. */
|
||||
SDL_SYSTEM_CURSOR_PROGRESS, /**< Program is busy but still interactive. Usually it's WAIT with an arrow. */
|
||||
SDL_SYSTEM_CURSOR_NWSE_RESIZE, /**< Double arrow pointing northwest and southeast. */
|
||||
SDL_SYSTEM_CURSOR_NESW_RESIZE, /**< Double arrow pointing northeast and southwest. */
|
||||
SDL_SYSTEM_CURSOR_EW_RESIZE, /**< Double arrow pointing west and east. */
|
||||
SDL_SYSTEM_CURSOR_NS_RESIZE, /**< Double arrow pointing north and south. */
|
||||
SDL_SYSTEM_CURSOR_MOVE, /**< Four pointed arrow pointing north, south, east, and west. */
|
||||
SDL_SYSTEM_CURSOR_NOT_ALLOWED, /**< Not permitted. Usually a slashed circle or crossbones. */
|
||||
SDL_SYSTEM_CURSOR_POINTER, /**< Pointer that indicates a link. Usually a pointing hand. */
|
||||
SDL_SYSTEM_CURSOR_NW_RESIZE, /**< Window resize top-left. This may be a single arrow or a double arrow like NWSE_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_N_RESIZE, /**< Window resize top. May be NS_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_NE_RESIZE, /**< Window resize top-right. May be NESW_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_E_RESIZE, /**< Window resize right. May be EW_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_SE_RESIZE, /**< Window resize bottom-right. May be NWSE_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_S_RESIZE, /**< Window resize bottom. May be NS_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_SW_RESIZE, /**< Window resize bottom-left. May be NESW_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_W_RESIZE, /**< Window resize left. May be EW_RESIZE. */
|
||||
SDL_SYSTEM_CURSOR_COUNT
|
||||
} SDL_SystemCursor;
|
||||
|
||||
/**
|
||||
* Scroll direction types for the Scroll event
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_MouseWheelDirection
|
||||
{
|
||||
SDL_MOUSEWHEEL_NORMAL, /**< The scroll direction is normal */
|
||||
SDL_MOUSEWHEEL_FLIPPED /**< The scroll direction is flipped / natural */
|
||||
} SDL_MouseWheelDirection;
|
||||
|
||||
/**
|
||||
* Animated cursor frame info.
|
||||
*
|
||||
* \since This struct is available since SDL 3.4.0.
|
||||
*/
|
||||
typedef struct SDL_CursorFrameInfo
|
||||
{
|
||||
SDL_Surface *surface; /**< The surface data for this frame */
|
||||
Uint32 duration; /**< The frame duration in milliseconds (a duration of 0 is infinite) */
|
||||
} SDL_CursorFrameInfo;
|
||||
|
||||
/**
|
||||
* A bitmask of pressed mouse buttons, as reported by SDL_GetMouseState, etc.
|
||||
*
|
||||
* - Button 1: Left mouse button
|
||||
* - Button 2: Middle mouse button
|
||||
* - Button 3: Right mouse button
|
||||
* - Button 4: Side mouse button 1
|
||||
* - Button 5: Side mouse button 2
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetMouseState
|
||||
* \sa SDL_GetGlobalMouseState
|
||||
* \sa SDL_GetRelativeMouseState
|
||||
*/
|
||||
typedef Uint32 SDL_MouseButtonFlags;
|
||||
|
||||
#define SDL_BUTTON_LEFT 1
|
||||
#define SDL_BUTTON_MIDDLE 2
|
||||
#define SDL_BUTTON_RIGHT 3
|
||||
#define SDL_BUTTON_X1 4
|
||||
#define SDL_BUTTON_X2 5
|
||||
|
||||
#define SDL_BUTTON_MASK(X) (1u << ((X)-1))
|
||||
#define SDL_BUTTON_LMASK SDL_BUTTON_MASK(SDL_BUTTON_LEFT)
|
||||
#define SDL_BUTTON_MMASK SDL_BUTTON_MASK(SDL_BUTTON_MIDDLE)
|
||||
#define SDL_BUTTON_RMASK SDL_BUTTON_MASK(SDL_BUTTON_RIGHT)
|
||||
#define SDL_BUTTON_X1MASK SDL_BUTTON_MASK(SDL_BUTTON_X1)
|
||||
#define SDL_BUTTON_X2MASK SDL_BUTTON_MASK(SDL_BUTTON_X2)
|
||||
|
||||
/**
|
||||
* A callback used to transform mouse motion delta from raw values.
|
||||
*
|
||||
* This is called during SDL's handling of platform mouse events to scale the
|
||||
* values of the resulting motion delta.
|
||||
*
|
||||
* \param userdata what was passed as `userdata` to
|
||||
* SDL_SetRelativeMouseTransform().
|
||||
* \param timestamp the associated time at which this mouse motion event was
|
||||
* received.
|
||||
* \param window the associated window to which this mouse motion event was
|
||||
* addressed.
|
||||
* \param mouseID the associated mouse from which this mouse motion event was
|
||||
* emitted.
|
||||
* \param x pointer to a variable that will be treated as the resulting x-axis
|
||||
* motion.
|
||||
* \param y pointer to a variable that will be treated as the resulting y-axis
|
||||
* motion.
|
||||
*
|
||||
* \threadsafety This callback is called by SDL's internal mouse input
|
||||
* processing procedure, which may be a thread separate from the
|
||||
* main event loop that is run at realtime priority. Stalling
|
||||
* this thread with too much work in the callback can therefore
|
||||
* potentially freeze the entire system. Care should be taken
|
||||
* with proper synchronization practices when adding other side
|
||||
* effects beyond mutation of the x and y values.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_SetRelativeMouseTransform
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_MouseMotionTransformCallback)(
|
||||
void *userdata,
|
||||
Uint64 timestamp,
|
||||
SDL_Window *window,
|
||||
SDL_MouseID mouseID,
|
||||
float *x, float *y
|
||||
);
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/**
|
||||
* Return whether a mouse is currently connected.
|
||||
*
|
||||
* \returns true if a mouse is connected, false otherwise.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetMice
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasMouse(void);
|
||||
|
||||
/**
|
||||
* Get a list of currently connected mice.
|
||||
*
|
||||
* Note that this will include any device or virtual driver that includes
|
||||
* mouse functionality, including some game controllers, KVM switches, etc.
|
||||
* You should wait for input from a device before you consider it actively in
|
||||
* use.
|
||||
*
|
||||
* \param count a pointer filled in with the number of mice returned, may be
|
||||
* NULL.
|
||||
* \returns a 0 terminated array of mouse instance IDs or NULL on failure;
|
||||
* call SDL_GetError() for more information. This should be freed
|
||||
* with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetMouseNameForID
|
||||
* \sa SDL_HasMouse
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_MouseID * SDLCALL SDL_GetMice(int *count);
|
||||
|
||||
/**
|
||||
* Get the name of a mouse.
|
||||
*
|
||||
* This function returns "" if the mouse doesn't have a name.
|
||||
*
|
||||
* \param instance_id the mouse instance ID.
|
||||
* \returns the name of the selected mouse, or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetMice
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetMouseNameForID(SDL_MouseID instance_id);
|
||||
|
||||
/**
|
||||
* Get the window which currently has mouse focus.
|
||||
*
|
||||
* \returns the window with mouse focus.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetMouseFocus(void);
|
||||
|
||||
/**
|
||||
* Query SDL's cache for the synchronous mouse button state and the
|
||||
* window-relative SDL-cursor position.
|
||||
*
|
||||
* This function returns the cached synchronous state as SDL understands it
|
||||
* from the last pump of the event queue.
|
||||
*
|
||||
* To query the platform for immediate asynchronous state, use
|
||||
* SDL_GetGlobalMouseState.
|
||||
*
|
||||
* Passing non-NULL pointers to `x` or `y` will write the destination with
|
||||
* respective x or y coordinates relative to the focused window.
|
||||
*
|
||||
* In Relative Mode, the SDL-cursor's position usually contradicts the
|
||||
* platform-cursor's position as manually calculated from
|
||||
* SDL_GetGlobalMouseState() and SDL_GetWindowPosition.
|
||||
*
|
||||
* \param x a pointer to receive the SDL-cursor's x-position from the focused
|
||||
* window's top left corner, can be NULL if unused.
|
||||
* \param y a pointer to receive the SDL-cursor's y-position from the focused
|
||||
* window's top left corner, can be NULL if unused.
|
||||
* \returns a 32-bit bitmask of the button state that can be bitwise-compared
|
||||
* against the SDL_BUTTON_MASK(X) macro.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetGlobalMouseState
|
||||
* \sa SDL_GetRelativeMouseState
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_MouseButtonFlags SDLCALL SDL_GetMouseState(float *x, float *y);
|
||||
|
||||
/**
|
||||
* Query the platform for the asynchronous mouse button state and the
|
||||
* desktop-relative platform-cursor position.
|
||||
*
|
||||
* This function immediately queries the platform for the most recent
|
||||
* asynchronous state, more costly than retrieving SDL's cached state in
|
||||
* SDL_GetMouseState().
|
||||
*
|
||||
* Passing non-NULL pointers to `x` or `y` will write the destination with
|
||||
* respective x or y coordinates relative to the desktop.
|
||||
*
|
||||
* In Relative Mode, the platform-cursor's position usually contradicts the
|
||||
* SDL-cursor's position as manually calculated from SDL_GetMouseState() and
|
||||
* SDL_GetWindowPosition.
|
||||
*
|
||||
* This function can be useful if you need to track the mouse outside of a
|
||||
* specific window and SDL_CaptureMouse() doesn't fit your needs. For example,
|
||||
* it could be useful if you need to track the mouse while dragging a window,
|
||||
* where coordinates relative to a window might not be in sync at all times.
|
||||
*
|
||||
* \param x a pointer to receive the platform-cursor's x-position from the
|
||||
* desktop's top left corner, can be NULL if unused.
|
||||
* \param y a pointer to receive the platform-cursor's y-position from the
|
||||
* desktop's top left corner, can be NULL if unused.
|
||||
* \returns a 32-bit bitmask of the button state that can be bitwise-compared
|
||||
* against the SDL_BUTTON_MASK(X) macro.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CaptureMouse
|
||||
* \sa SDL_GetMouseState
|
||||
* \sa SDL_GetGlobalMouseState
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_MouseButtonFlags SDLCALL SDL_GetGlobalMouseState(float *x, float *y);
|
||||
|
||||
/**
|
||||
* Query SDL's cache for the synchronous mouse button state and accumulated
|
||||
* mouse delta since last call.
|
||||
*
|
||||
* This function returns the cached synchronous state as SDL understands it
|
||||
* from the last pump of the event queue.
|
||||
*
|
||||
* To query the platform for immediate asynchronous state, use
|
||||
* SDL_GetGlobalMouseState.
|
||||
*
|
||||
* Passing non-NULL pointers to `x` or `y` will write the destination with
|
||||
* respective x or y deltas accumulated since the last call to this function
|
||||
* (or since event initialization).
|
||||
*
|
||||
* This function is useful for reducing overhead by processing relative mouse
|
||||
* inputs in one go per-frame instead of individually per-event, at the
|
||||
* expense of losing the order between events within the frame (e.g. quickly
|
||||
* pressing and releasing a button within the same frame).
|
||||
*
|
||||
* \param x a pointer to receive the x mouse delta accumulated since last
|
||||
* call, can be NULL if unused.
|
||||
* \param y a pointer to receive the y mouse delta accumulated since last
|
||||
* call, can be NULL if unused.
|
||||
* \returns a 32-bit bitmask of the button state that can be bitwise-compared
|
||||
* against the SDL_BUTTON_MASK(X) macro.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetMouseState
|
||||
* \sa SDL_GetGlobalMouseState
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_MouseButtonFlags SDLCALL SDL_GetRelativeMouseState(float *x, float *y);
|
||||
|
||||
/**
|
||||
* Move the mouse cursor to the given position within the window.
|
||||
*
|
||||
* This function generates a mouse motion event if relative mode is not
|
||||
* enabled. If relative mode is enabled, you can force mouse events for the
|
||||
* warp by setting the SDL_HINT_MOUSE_RELATIVE_WARP_MOTION hint.
|
||||
*
|
||||
* Note that this function will appear to succeed, but not actually move the
|
||||
* mouse when used over Microsoft Remote Desktop.
|
||||
*
|
||||
* \param window the window to move the mouse into, or NULL for the current
|
||||
* mouse focus.
|
||||
* \param x the x coordinate within the window.
|
||||
* \param y the y coordinate within the window.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_WarpMouseGlobal
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window *window,
|
||||
float x, float y);
|
||||
|
||||
/**
|
||||
* Move the mouse to the given position in global screen space.
|
||||
*
|
||||
* This function generates a mouse motion event.
|
||||
*
|
||||
* A failure of this function usually means that it is unsupported by a
|
||||
* platform.
|
||||
*
|
||||
* Note that this function will appear to succeed, but not actually move the
|
||||
* mouse when used over Microsoft Remote Desktop.
|
||||
*
|
||||
* \param x the x coordinate.
|
||||
* \param y the y coordinate.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_WarpMouseInWindow
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_WarpMouseGlobal(float x, float y);
|
||||
|
||||
/**
|
||||
* Set a user-defined function by which to transform relative mouse inputs.
|
||||
*
|
||||
* This overrides the relative system scale and relative speed scale hints.
|
||||
* Should be called prior to enabling relative mouse mode, fails otherwise.
|
||||
*
|
||||
* \param callback a callback used to transform relative mouse motion, or NULL
|
||||
* for default behavior.
|
||||
* \param userdata a pointer that will be passed to `callback`.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetRelativeMouseTransform(SDL_MouseMotionTransformCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Set relative mouse mode for a window.
|
||||
*
|
||||
* While the window has focus and relative mouse mode is enabled, the cursor
|
||||
* is hidden, the mouse position is constrained to the window, and SDL will
|
||||
* report continuous relative mouse motion even if the mouse is at the edge of
|
||||
* the window.
|
||||
*
|
||||
* If you'd like to keep the mouse position fixed while in relative mode you
|
||||
* can use SDL_SetWindowMouseRect(). If you'd like the cursor to be at a
|
||||
* specific location when relative mode ends, you should use
|
||||
* SDL_WarpMouseInWindow() before disabling relative mode.
|
||||
*
|
||||
* This function will flush any pending mouse motion for this window.
|
||||
*
|
||||
* \param window the window to change.
|
||||
* \param enabled true to enable relative mode, false to disable.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetWindowRelativeMouseMode
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetWindowRelativeMouseMode(SDL_Window *window, bool enabled);
|
||||
|
||||
/**
|
||||
* Query whether relative mouse mode is enabled for a window.
|
||||
*
|
||||
* \param window the window to query.
|
||||
* \returns true if relative mode is enabled for a window or false otherwise.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetWindowRelativeMouseMode
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetWindowRelativeMouseMode(SDL_Window *window);
|
||||
|
||||
/**
|
||||
* Capture the mouse and to track input outside an SDL window.
|
||||
*
|
||||
* Capturing enables your app to obtain mouse events globally, instead of just
|
||||
* within your window. Not all video targets support this function. When
|
||||
* capturing is enabled, the current window will get all mouse events, but
|
||||
* unlike relative mode, no change is made to the cursor and it is not
|
||||
* restrained to your window.
|
||||
*
|
||||
* This function may also deny mouse input to other windows--both those in
|
||||
* your application and others on the system--so you should use this function
|
||||
* sparingly, and in small bursts. For example, you might want to track the
|
||||
* mouse while the user is dragging something, until the user releases a mouse
|
||||
* button. It is not recommended that you capture the mouse for long periods
|
||||
* of time, such as the entire time your app is running. For that, you should
|
||||
* probably use SDL_SetWindowRelativeMouseMode() or SDL_SetWindowMouseGrab(),
|
||||
* depending on your goals.
|
||||
*
|
||||
* While captured, mouse events still report coordinates relative to the
|
||||
* current (foreground) window, but those coordinates may be outside the
|
||||
* bounds of the window (including negative values). Capturing is only allowed
|
||||
* for the foreground window. If the window loses focus while capturing, the
|
||||
* capture will be disabled automatically.
|
||||
*
|
||||
* While capturing is enabled, the current window will have the
|
||||
* `SDL_WINDOW_MOUSE_CAPTURE` flag set.
|
||||
*
|
||||
* Please note that SDL will attempt to "auto capture" the mouse while the
|
||||
* user is pressing a button; this is to try and make mouse behavior more
|
||||
* consistent between platforms, and deal with the common case of a user
|
||||
* dragging the mouse outside of the window. This means that if you are
|
||||
* calling SDL_CaptureMouse() only to deal with this situation, you do not
|
||||
* have to (although it is safe to do so). If this causes problems for your
|
||||
* app, you can disable auto capture by setting the
|
||||
* `SDL_HINT_MOUSE_AUTO_CAPTURE` hint to zero.
|
||||
*
|
||||
* \param enabled true to enable capturing, false to disable.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetGlobalMouseState
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CaptureMouse(bool enabled);
|
||||
|
||||
/**
|
||||
* Create a cursor using the specified bitmap data and mask (in MSB format).
|
||||
*
|
||||
* `mask` has to be in MSB (Most Significant Bit) format.
|
||||
*
|
||||
* The cursor width (`w`) must be a multiple of 8 bits.
|
||||
*
|
||||
* The cursor is created in black and white according to the following:
|
||||
*
|
||||
* - data=0, mask=1: white
|
||||
* - data=1, mask=1: black
|
||||
* - data=0, mask=0: transparent
|
||||
* - data=1, mask=0: inverted color if possible, black if not.
|
||||
*
|
||||
* Cursors created with this function must be freed with SDL_DestroyCursor().
|
||||
*
|
||||
* If you want to have a color cursor, or create your cursor from an
|
||||
* SDL_Surface, you should use SDL_CreateColorCursor(). Alternately, you can
|
||||
* hide the cursor and draw your own as part of your game's rendering, but it
|
||||
* will be bound to the framerate.
|
||||
*
|
||||
* Also, SDL_CreateSystemCursor() is available, which provides several
|
||||
* readily-available system cursors to pick from.
|
||||
*
|
||||
* \param data the color value for each pixel of the cursor.
|
||||
* \param mask the mask value for each pixel of the cursor.
|
||||
* \param w the width of the cursor.
|
||||
* \param h the height of the cursor.
|
||||
* \param hot_x the x-axis offset from the left of the cursor image to the
|
||||
* mouse x position, in the range of 0 to `w` - 1.
|
||||
* \param hot_y the y-axis offset from the top of the cursor image to the
|
||||
* mouse y position, in the range of 0 to `h` - 1.
|
||||
* \returns a new cursor with the specified parameters on success or NULL on
|
||||
* failure; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateAnimatedCursor
|
||||
* \sa SDL_CreateColorCursor
|
||||
* \sa SDL_CreateSystemCursor
|
||||
* \sa SDL_DestroyCursor
|
||||
* \sa SDL_SetCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data,
|
||||
const Uint8 *mask,
|
||||
int w, int h, int hot_x,
|
||||
int hot_y);
|
||||
|
||||
/**
|
||||
* Create a color cursor.
|
||||
*
|
||||
* If this function is passed a surface with alternate representations added
|
||||
* with SDL_AddSurfaceAlternateImage(), the surface will be interpreted as the
|
||||
* content to be used for 100% display scale, and the alternate
|
||||
* representations will be used for high DPI situations if
|
||||
* SDL_HINT_MOUSE_DPI_SCALE_CURSORS is enabled. For example, if the original
|
||||
* surface is 32x32, then on a 2x macOS display or 200% display scale on
|
||||
* Windows, a 64x64 version of the image will be used, if available. If a
|
||||
* matching version of the image isn't available, the closest larger size
|
||||
* image will be downscaled to the appropriate size and be used instead, if
|
||||
* available. Otherwise, the closest smaller image will be upscaled and be
|
||||
* used instead.
|
||||
*
|
||||
* \param surface an SDL_Surface structure representing the cursor image.
|
||||
* \param hot_x the x position of the cursor hot spot.
|
||||
* \param hot_y the y position of the cursor hot spot.
|
||||
* \returns the new cursor on success or NULL on failure; call SDL_GetError()
|
||||
* for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
* \sa SDL_CreateAnimatedCursor
|
||||
* \sa SDL_CreateCursor
|
||||
* \sa SDL_CreateSystemCursor
|
||||
* \sa SDL_DestroyCursor
|
||||
* \sa SDL_SetCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateColorCursor(SDL_Surface *surface,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
/**
|
||||
* Create an animated color cursor.
|
||||
*
|
||||
* Animated cursors are composed of a sequential array of frames, specified as
|
||||
* surfaces and durations in an array of SDL_CursorFrameInfo structs. The hot
|
||||
* spot coordinates are universal to all frames, and all frames must have the
|
||||
* same dimensions.
|
||||
*
|
||||
* Frame durations are specified in milliseconds. A duration of 0 implies an
|
||||
* infinite frame time, and the animation will stop on that frame. To create a
|
||||
* one-shot animation, set the duration of the last frame in the sequence to
|
||||
* 0.
|
||||
*
|
||||
* If this function is passed surfaces with alternate representations added
|
||||
* with SDL_AddSurfaceAlternateImage(), the surfaces will be interpreted as
|
||||
* the content to be used for 100% display scale, and the alternate
|
||||
* representations will be used for high DPI situations. For example, if the
|
||||
* original surfaces are 32x32, then on a 2x macOS display or 200% display
|
||||
* scale on Windows, a 64x64 version of the image will be used, if available.
|
||||
* If a matching version of the image isn't available, the closest larger size
|
||||
* image will be downscaled to the appropriate size and be used instead, if
|
||||
* available. Otherwise, the closest smaller image will be upscaled and be
|
||||
* used instead.
|
||||
*
|
||||
* If the underlying platform does not support animated cursors, this function
|
||||
* will fall back to creating a static color cursor using the first frame in
|
||||
* the sequence.
|
||||
*
|
||||
* \param frames an array of cursor images composing the animation.
|
||||
* \param frame_count the number of frames in the sequence.
|
||||
* \param hot_x the x position of the cursor hot spot.
|
||||
* \param hot_y the y position of the cursor hot spot.
|
||||
* \returns the new cursor on success or NULL on failure; call SDL_GetError()
|
||||
* for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*
|
||||
* \sa SDL_AddSurfaceAlternateImage
|
||||
* \sa SDL_CreateCursor
|
||||
* \sa SDL_CreateColorCursor
|
||||
* \sa SDL_CreateSystemCursor
|
||||
* \sa SDL_DestroyCursor
|
||||
* \sa SDL_SetCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor *SDLCALL SDL_CreateAnimatedCursor(SDL_CursorFrameInfo *frames,
|
||||
int frame_count,
|
||||
int hot_x,
|
||||
int hot_y);
|
||||
|
||||
/**
|
||||
* Create a system cursor.
|
||||
*
|
||||
* \param id an SDL_SystemCursor enum value.
|
||||
* \returns a cursor on success or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroyCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateSystemCursor(SDL_SystemCursor id);
|
||||
|
||||
/**
|
||||
* Set the active cursor.
|
||||
*
|
||||
* This function sets the currently active cursor to the specified one. If the
|
||||
* cursor is currently visible, the change will be immediately represented on
|
||||
* the display. SDL_SetCursor(NULL) can be used to force cursor redraw, if
|
||||
* this is desired for any reason.
|
||||
*
|
||||
* \param cursor a cursor to make active.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetCursor(SDL_Cursor *cursor);
|
||||
|
||||
/**
|
||||
* Get the active cursor.
|
||||
*
|
||||
* This function returns a pointer to the current cursor which is owned by the
|
||||
* library. It is not necessary to free the cursor with SDL_DestroyCursor().
|
||||
*
|
||||
* \returns the active cursor or NULL if there is no mouse.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_GetCursor(void);
|
||||
|
||||
/**
|
||||
* Get the default cursor.
|
||||
*
|
||||
* You do not have to call SDL_DestroyCursor() on the return value, but it is
|
||||
* safe to do so.
|
||||
*
|
||||
* \returns the default cursor on success or NULL on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_GetDefaultCursor(void);
|
||||
|
||||
/**
|
||||
* Free a previously-created cursor.
|
||||
*
|
||||
* Use this function to free cursor resources created with SDL_CreateCursor(),
|
||||
* SDL_CreateColorCursor() or SDL_CreateSystemCursor().
|
||||
*
|
||||
* \param cursor the cursor to free.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateAnimatedCursor
|
||||
* \sa SDL_CreateColorCursor
|
||||
* \sa SDL_CreateCursor
|
||||
* \sa SDL_CreateSystemCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DestroyCursor(SDL_Cursor *cursor);
|
||||
|
||||
/**
|
||||
* Show the cursor.
|
||||
*
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CursorVisible
|
||||
* \sa SDL_HideCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ShowCursor(void);
|
||||
|
||||
/**
|
||||
* Hide the cursor.
|
||||
*
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CursorVisible
|
||||
* \sa SDL_ShowCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HideCursor(void);
|
||||
|
||||
/**
|
||||
* Return whether the cursor is currently being shown.
|
||||
*
|
||||
* \returns `true` if the cursor is being shown, or `false` if the cursor is
|
||||
* hidden.
|
||||
*
|
||||
* \threadsafety This function should only be called on the main thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HideCursor
|
||||
* \sa SDL_ShowCursor
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CursorVisible(void);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_mouse_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryPen
|
||||
*
|
||||
* SDL pen event handling.
|
||||
*
|
||||
* SDL provides an API for pressure-sensitive pen (stylus and/or eraser)
|
||||
* handling, e.g., for input and drawing tablets or suitably equipped mobile /
|
||||
* tablet devices.
|
||||
*
|
||||
* To get started with pens, simply handle pen events:
|
||||
*
|
||||
* - SDL_EVENT_PEN_PROXIMITY_IN, SDL_EVENT_PEN_PROXIMITY_OUT
|
||||
* (SDL_PenProximityEvent)
|
||||
* - SDL_EVENT_PEN_DOWN, SDL_EVENT_PEN_UP (SDL_PenTouchEvent)
|
||||
* - SDL_EVENT_PEN_MOTION (SDL_PenMotionEvent)
|
||||
* - SDL_EVENT_PEN_BUTTON_DOWN, SDL_EVENT_PEN_BUTTON_UP (SDL_PenButtonEvent)
|
||||
* - SDL_EVENT_PEN_AXIS (SDL_PenAxisEvent)
|
||||
*
|
||||
* Pens may provide more than simple touch input; they might have other axes,
|
||||
* such as pressure, tilt, rotation, etc.
|
||||
*
|
||||
* When a pen starts providing input, SDL will assign it a unique SDL_PenID,
|
||||
* which will remain for the life of the process, as long as the pen stays
|
||||
* connected. A pen leaving proximity (being taken far enough away from the
|
||||
* digitizer tablet that it no longer reponds) and then coming back should
|
||||
* fire proximity events, but the SDL_PenID should remain consistent.
|
||||
* Unplugging the digitizer and reconnecting may cause future input to have a
|
||||
* new SDL_PenID, as SDL may not know that this is the same hardware.
|
||||
*
|
||||
* Please note that various platforms vary wildly in how (and how well) they
|
||||
* support pen input. If your pen supports some piece of functionality but SDL
|
||||
* doesn't seem to, it might actually be the operating system's fault. For
|
||||
* example, some platforms can manage multiple devices at the same time, but
|
||||
* others will make any connected pens look like a single logical device, much
|
||||
* how all USB mice connected to a computer will move the same system cursor.
|
||||
* Other platforms might not support pen buttons, or the distance axis, etc.
|
||||
* Very few platforms can even report _what_ functionality the pen supports in
|
||||
* the first place, so best practices is to either build UI to let the user
|
||||
* configure their pens, or be prepared to handle new functionality for a pen
|
||||
* the first time an event is reported.
|
||||
*/
|
||||
|
||||
#ifndef SDL_pen_h_
|
||||
#define SDL_pen_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_mouse.h>
|
||||
#include <SDL3/SDL_touch.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SDL pen instance IDs.
|
||||
*
|
||||
* Zero is used to signify an invalid/null device.
|
||||
*
|
||||
* These show up in pen events when SDL sees input from them. They remain
|
||||
* consistent as long as SDL can recognize a tool to be the same pen; but if a
|
||||
* pen's digitizer table is physically detached from the computer, it might
|
||||
* get a new ID when reconnected, as SDL won't know it's the same device.
|
||||
*
|
||||
* These IDs are only stable within a single run of a program; the next time a
|
||||
* program is run, the pen's ID will likely be different, even if the hardware
|
||||
* hasn't been disconnected, etc.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_PenID;
|
||||
|
||||
/**
|
||||
* The SDL_MouseID for mouse events simulated with pen input.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PEN_MOUSEID ((SDL_MouseID)-2)
|
||||
|
||||
/**
|
||||
* The SDL_TouchID for touch events simulated with pen input.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PEN_TOUCHID ((SDL_TouchID)-2)
|
||||
|
||||
/**
|
||||
* Pen input flags, as reported by various pen events' `pen_state` field.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_PenInputFlags;
|
||||
|
||||
#define SDL_PEN_INPUT_DOWN (1u << 0) /**< pen is pressed down */
|
||||
#define SDL_PEN_INPUT_BUTTON_1 (1u << 1) /**< button 1 is pressed */
|
||||
#define SDL_PEN_INPUT_BUTTON_2 (1u << 2) /**< button 2 is pressed */
|
||||
#define SDL_PEN_INPUT_BUTTON_3 (1u << 3) /**< button 3 is pressed */
|
||||
#define SDL_PEN_INPUT_BUTTON_4 (1u << 4) /**< button 4 is pressed */
|
||||
#define SDL_PEN_INPUT_BUTTON_5 (1u << 5) /**< button 5 is pressed */
|
||||
#define SDL_PEN_INPUT_ERASER_TIP (1u << 30) /**< eraser tip is used */
|
||||
#define SDL_PEN_INPUT_IN_PROXIMITY (1u << 31) /**< pen is in proximity (since SDL 3.4.0) */
|
||||
|
||||
/**
|
||||
* Pen axis indices.
|
||||
*
|
||||
* These are the valid values for the `axis` field in SDL_PenAxisEvent. All
|
||||
* axes are either normalised to 0..1 or report a (positive or negative) angle
|
||||
* in degrees, with 0.0 representing the centre. Not all pens/backends support
|
||||
* all axes: unsupported axes are always zero.
|
||||
*
|
||||
* To convert angles for tilt and rotation into vector representation, use
|
||||
* SDL_sinf on the XTILT, YTILT, or ROTATION component, for example:
|
||||
*
|
||||
* `SDL_sinf(xtilt * SDL_PI_F / 180.0)`.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_PenAxis
|
||||
{
|
||||
SDL_PEN_AXIS_PRESSURE, /**< Pen pressure. Unidirectional: 0 to 1.0 */
|
||||
SDL_PEN_AXIS_XTILT, /**< Pen horizontal tilt angle. Bidirectional: -90.0 to 90.0 (left-to-right). */
|
||||
SDL_PEN_AXIS_YTILT, /**< Pen vertical tilt angle. Bidirectional: -90.0 to 90.0 (top-to-down). */
|
||||
SDL_PEN_AXIS_DISTANCE, /**< Pen distance to drawing surface. Unidirectional: 0.0 to 1.0 */
|
||||
SDL_PEN_AXIS_ROTATION, /**< Pen barrel rotation. Bidirectional: -180 to 179.9 (clockwise, 0 is facing up, -180.0 is facing down). */
|
||||
SDL_PEN_AXIS_SLIDER, /**< Pen finger wheel or slider (e.g., Airbrush Pen). Unidirectional: 0 to 1.0 */
|
||||
SDL_PEN_AXIS_TANGENTIAL_PRESSURE, /**< Pressure from squeezing the pen ("barrel pressure"). */
|
||||
SDL_PEN_AXIS_COUNT /**< Total known pen axis types in this version of SDL. This number may grow in future releases! */
|
||||
} SDL_PenAxis;
|
||||
|
||||
/**
|
||||
* An enum that describes the type of a pen device.
|
||||
*
|
||||
* A "direct" device is a pen that touches a graphic display (like an Apple
|
||||
* Pencil on an iPad's screen). "Indirect" devices touch an external tablet
|
||||
* surface that is connected to the machine but is not a display (like a
|
||||
* lower-end Wacom tablet connected over USB).
|
||||
*
|
||||
* Apps may use this information to decide if they should draw a cursor; if
|
||||
* the pen is touching the screen directly, a cursor doesn't make sense and
|
||||
* can be in the way, but becomes necessary for indirect devices to know where
|
||||
* on the display they are interacting.
|
||||
*
|
||||
* \since This enum is available since SDL 3.4.0.
|
||||
*/
|
||||
typedef enum SDL_PenDeviceType
|
||||
{
|
||||
SDL_PEN_DEVICE_TYPE_INVALID = -1, /**< Not a valid pen device. */
|
||||
SDL_PEN_DEVICE_TYPE_UNKNOWN, /**< Don't know specifics of this pen. */
|
||||
SDL_PEN_DEVICE_TYPE_DIRECT, /**< Pen touches display. */
|
||||
SDL_PEN_DEVICE_TYPE_INDIRECT /**< Pen touches something that isn't the display. */
|
||||
} SDL_PenDeviceType;
|
||||
|
||||
/**
|
||||
* Get the device type of the given pen.
|
||||
*
|
||||
* Many platforms do not supply this information, so an app must always be
|
||||
* prepared to get an SDL_PEN_DEVICE_TYPE_UNKNOWN result.
|
||||
*
|
||||
* \param instance_id the pen instance ID.
|
||||
* \returns the device type of the given pen, or SDL_PEN_DEVICE_TYPE_INVALID
|
||||
* on failure; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.4.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PenDeviceType SDLCALL SDL_GetPenDeviceType(SDL_PenID instance_id);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_pen_h_ */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,497 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/* WIKI CATEGORY: Platform */
|
||||
|
||||
/*
|
||||
* SDL_platform_defines.h tries to get a standard set of platform defines.
|
||||
*/
|
||||
|
||||
#ifndef SDL_platform_defines_h_
|
||||
#define SDL_platform_defines_h_
|
||||
|
||||
#ifdef _AIX
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for AIX.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_AIX 1
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Haiku OS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_HAIKU 1
|
||||
#endif
|
||||
|
||||
#if defined(bsdi) || defined(__bsdi) || defined(__bsdi__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for BSDi
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_BSDI 1
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for FreeBSD.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_FREEBSD 1
|
||||
#endif
|
||||
|
||||
#if defined(hpux) || defined(__hpux) || defined(__hpux__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for HP-UX.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_HPUX 1
|
||||
#endif
|
||||
|
||||
#if defined(sgi) || defined(__sgi) || defined(__sgi__) || defined(_SGI_SOURCE)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for IRIX.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_IRIX 1
|
||||
#endif
|
||||
|
||||
#if (defined(linux) || defined(__linux) || defined(__linux__))
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Linux.
|
||||
*
|
||||
* Note that Android, although ostensibly a Linux-based system, will not
|
||||
* define this. It defines SDL_PLATFORM_ANDROID instead.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_LINUX 1
|
||||
#endif
|
||||
|
||||
#if defined(ANDROID) || defined(__ANDROID__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Android.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_ANDROID 1
|
||||
#undef SDL_PLATFORM_LINUX
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) || defined(__unix) || defined(unix)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for a Unix-like
|
||||
* system.
|
||||
*
|
||||
* Other platforms, like Linux, might define this in addition to their primary
|
||||
* define.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_UNIX 1
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Apple platforms.
|
||||
*
|
||||
* iOS, macOS, etc will additionally define a more specific platform macro.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_MACOS
|
||||
* \sa SDL_PLATFORM_IOS
|
||||
* \sa SDL_PLATFORM_TVOS
|
||||
* \sa SDL_PLATFORM_VISIONOS
|
||||
*/
|
||||
#define SDL_PLATFORM_APPLE 1
|
||||
|
||||
/* lets us know what version of macOS we're compiling on */
|
||||
#include <AvailabilityMacros.h>
|
||||
#ifndef __has_extension /* Older compilers don't support this */
|
||||
#define __has_extension(x) 0
|
||||
#include <TargetConditionals.h>
|
||||
#undef __has_extension
|
||||
#else
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
/* Fix building with older SDKs that don't define these
|
||||
See this for more information:
|
||||
https://stackoverflow.com/questions/12132933/preprocessor-macro-for-os-x-targets
|
||||
*/
|
||||
#ifndef TARGET_OS_MACCATALYST
|
||||
#define TARGET_OS_MACCATALYST 0
|
||||
#endif
|
||||
#ifndef TARGET_OS_IOS
|
||||
#define TARGET_OS_IOS 0
|
||||
#endif
|
||||
#ifndef TARGET_OS_IPHONE
|
||||
#define TARGET_OS_IPHONE 0
|
||||
#endif
|
||||
#ifndef TARGET_OS_TV
|
||||
#define TARGET_OS_TV 0
|
||||
#endif
|
||||
#ifndef TARGET_OS_SIMULATOR
|
||||
#define TARGET_OS_SIMULATOR 0
|
||||
#endif
|
||||
#ifndef TARGET_OS_VISION
|
||||
#define TARGET_OS_VISION 0
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_TV
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for tvOS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_APPLE
|
||||
*/
|
||||
#define SDL_PLATFORM_TVOS 1
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_VISION
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for visionOS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_APPLE
|
||||
*/
|
||||
#define SDL_PLATFORM_VISIONOS 1
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for iOS or visionOS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_APPLE
|
||||
*/
|
||||
#define SDL_PLATFORM_IOS 1
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for macOS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_APPLE
|
||||
*/
|
||||
#define SDL_PLATFORM_MACOS 1
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
|
||||
#error SDL for macOS only supports deploying on 10.7 and above.
|
||||
#endif /* MAC_OS_X_VERSION_MIN_REQUIRED < 1070 */
|
||||
#endif /* TARGET_OS_IPHONE */
|
||||
#endif /* defined(__APPLE__) */
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Emscripten.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_EMSCRIPTEN 1
|
||||
#endif
|
||||
|
||||
#ifdef __NetBSD__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for NetBSD.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_NETBSD 1
|
||||
#endif
|
||||
|
||||
#ifdef __OpenBSD__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for OpenBSD.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_OPENBSD 1
|
||||
#endif
|
||||
|
||||
#if defined(__OS2__) || defined(__EMX__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for OS/2.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_OS2 1
|
||||
#endif
|
||||
|
||||
#if defined(osf) || defined(__osf) || defined(__osf__) || defined(_OSF_SOURCE)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Tru64 (OSF/1).
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_OSF 1
|
||||
#endif
|
||||
|
||||
#ifdef __QNXNTO__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for QNX Neutrino.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_QNXNTO 1
|
||||
#endif
|
||||
|
||||
#if defined(riscos) || defined(__riscos) || defined(__riscos__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for RISC OS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_RISCOS 1
|
||||
#endif
|
||||
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for SunOS/Solaris.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_SOLARIS 1
|
||||
#endif
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Cygwin.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_CYGWIN 1
|
||||
#endif
|
||||
|
||||
#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(__NGAGE__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Windows.
|
||||
*
|
||||
* This also covers several other platforms, like Microsoft GDK, Xbox, WinRT,
|
||||
* etc. Each will have their own more-specific platform macros, too.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_PLATFORM_WIN32
|
||||
* \sa SDL_PLATFORM_XBOXONE
|
||||
* \sa SDL_PLATFORM_XBOXSERIES
|
||||
* \sa SDL_PLATFORM_WINGDK
|
||||
* \sa SDL_PLATFORM_GDK
|
||||
*/
|
||||
#define SDL_PLATFORM_WINDOWS 1
|
||||
|
||||
/* Try to find out if we're compiling for WinRT, GDK or non-WinRT/GDK */
|
||||
#if defined(_MSC_VER) && defined(__has_include)
|
||||
#if __has_include(<winapifamily.h>)
|
||||
#define HAVE_WINAPIFAMILY_H 1
|
||||
#else
|
||||
#define HAVE_WINAPIFAMILY_H 0
|
||||
#endif
|
||||
|
||||
/* If _USING_V110_SDK71_ is defined it means we are using the Windows XP toolset. */
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1700 && !_USING_V110_SDK71_) /* _MSC_VER == 1700 for Visual Studio 2012 */
|
||||
#define HAVE_WINAPIFAMILY_H 1
|
||||
#else
|
||||
#define HAVE_WINAPIFAMILY_H 0
|
||||
#endif
|
||||
|
||||
#if HAVE_WINAPIFAMILY_H
|
||||
#include <winapifamily.h>
|
||||
#define WINAPI_FAMILY_WINRT (!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP))
|
||||
#else
|
||||
#define WINAPI_FAMILY_WINRT 0
|
||||
#endif /* HAVE_WINAPIFAMILY_H */
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/**
|
||||
* A preprocessor macro that defined to 1 if compiling for Windows Phone.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||
|
||||
#elif defined(HAVE_WINAPIFAMILY_H) && HAVE_WINAPIFAMILY_H
|
||||
#define SDL_WINAPI_FAMILY_PHONE (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
|
||||
#else
|
||||
#define SDL_WINAPI_FAMILY_PHONE 0
|
||||
#endif
|
||||
|
||||
#if WINAPI_FAMILY_WINRT
|
||||
#error Windows RT/UWP is no longer supported in SDL
|
||||
|
||||
#elif defined(_GAMING_DESKTOP) /* GDK project configuration always defines _GAMING_XXX */
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Microsoft GDK
|
||||
* for Windows.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_WINGDK 1
|
||||
|
||||
#elif defined(_GAMING_XBOX_XBOXONE)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Xbox One.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_XBOXONE 1
|
||||
|
||||
#elif defined(_GAMING_XBOX_SCARLETT)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Xbox Series.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_XBOXSERIES 1
|
||||
|
||||
#else
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for desktop Windows.
|
||||
*
|
||||
* Despite the "32", this also covers 64-bit Windows; as an informal
|
||||
* convention, its system layer tends to still be referred to as "the Win32
|
||||
* API."
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_WIN32 1
|
||||
|
||||
#endif
|
||||
#endif /* defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN) */
|
||||
|
||||
|
||||
/* This is to support generic "any GDK" separate from a platform-specific GDK */
|
||||
#if defined(SDL_PLATFORM_WINGDK) || defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Microsoft GDK on
|
||||
* any platform.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_GDK 1
|
||||
#endif
|
||||
|
||||
#if defined(__PSP__) || defined(__psp__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Sony PSP.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_PSP 1
|
||||
#endif
|
||||
|
||||
#if defined(__PS2__) || defined(PS2)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Sony PlayStation
|
||||
* 2.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_PS2 1
|
||||
#endif
|
||||
|
||||
#if defined(__vita__) || defined(__psp2__)
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Sony Vita.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_VITA 1
|
||||
#endif
|
||||
|
||||
#ifdef __3DS__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for Nintendo 3DS.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_3DS 1
|
||||
#endif
|
||||
|
||||
#ifdef __NGAGE__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for the Nokia
|
||||
* N-Gage.
|
||||
*
|
||||
* \since This macro is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_NGAGE 1
|
||||
#endif
|
||||
|
||||
#ifdef __GNU__
|
||||
|
||||
/**
|
||||
* A preprocessor macro that is only defined if compiling for GNU/Hurd.
|
||||
*
|
||||
* \since This macro is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_PLATFORM_HURD 1
|
||||
#endif
|
||||
|
||||
#endif /* SDL_platform_defines_h_ */
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_power_h_
|
||||
#define SDL_power_h_
|
||||
|
||||
/**
|
||||
* # CategoryPower
|
||||
*
|
||||
* SDL power management routines.
|
||||
*
|
||||
* There is a single function in this category: SDL_GetPowerInfo().
|
||||
*
|
||||
* This function is useful for games on the go. This allows an app to know if
|
||||
* it's running on a draining battery, which can be useful if the app wants to
|
||||
* reduce processing, or perhaps framerate, to extend the duration of the
|
||||
* battery's charge. Perhaps the app just wants to show a battery meter when
|
||||
* fullscreen, or alert the user when the power is getting extremely low, so
|
||||
* they can save their game.
|
||||
*/
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The basic state for the system's power supply.
|
||||
*
|
||||
* These are results returned by SDL_GetPowerInfo().
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_PowerState
|
||||
{
|
||||
SDL_POWERSTATE_ERROR = -1, /**< error determining power status */
|
||||
SDL_POWERSTATE_UNKNOWN, /**< cannot determine power status */
|
||||
SDL_POWERSTATE_ON_BATTERY, /**< Not plugged in, running on the battery */
|
||||
SDL_POWERSTATE_NO_BATTERY, /**< Plugged in, no battery available */
|
||||
SDL_POWERSTATE_CHARGING, /**< Plugged in, charging battery */
|
||||
SDL_POWERSTATE_CHARGED /**< Plugged in, battery charged */
|
||||
} SDL_PowerState;
|
||||
|
||||
/**
|
||||
* Get the current power supply details.
|
||||
*
|
||||
* You should never take a battery status as absolute truth. Batteries
|
||||
* (especially failing batteries) are delicate hardware, and the values
|
||||
* reported here are best estimates based on what that hardware reports. It's
|
||||
* not uncommon for older batteries to lose stored power much faster than it
|
||||
* reports, or completely drain when reporting it has 20 percent left, etc.
|
||||
*
|
||||
* Battery status can change at any time; if you are concerned with power
|
||||
* state, you should call this function frequently, and perhaps ignore changes
|
||||
* until they seem to be stable for a few seconds.
|
||||
*
|
||||
* It's possible a platform can only report battery percentage or time left
|
||||
* but not both.
|
||||
*
|
||||
* On some platforms, retrieving power supply details might be expensive. If
|
||||
* you want to display continuous status you could call this function every
|
||||
* minute or so.
|
||||
*
|
||||
* \param seconds a pointer filled in with the seconds of battery life left,
|
||||
* or NULL to ignore. This will be filled in with -1 if we
|
||||
* can't determine a value or there is no battery.
|
||||
* \param percent a pointer filled in with the percentage of battery life
|
||||
* left, between 0 and 100, or NULL to ignore. This will be
|
||||
* filled in with -1 when we can't determine a value or there
|
||||
* is no battery.
|
||||
* \returns the current battery state or `SDL_POWERSTATE_ERROR` on failure;
|
||||
* call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety This function is not thread safe.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PowerState SDLCALL SDL_GetPowerInfo(int *seconds, int *percent);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_power_h_ */
|
||||
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryProperties
|
||||
*
|
||||
* A property is a variable that can be created and retrieved by name at
|
||||
* runtime.
|
||||
*
|
||||
* All properties are part of a property group (SDL_PropertiesID). A property
|
||||
* group can be created with the SDL_CreateProperties function and destroyed
|
||||
* with the SDL_DestroyProperties function.
|
||||
*
|
||||
* Properties can be added to and retrieved from a property group through the
|
||||
* following functions:
|
||||
*
|
||||
* - SDL_SetPointerProperty and SDL_GetPointerProperty operate on `void*`
|
||||
* pointer types.
|
||||
* - SDL_SetStringProperty and SDL_GetStringProperty operate on string types.
|
||||
* - SDL_SetNumberProperty and SDL_GetNumberProperty operate on signed 64-bit
|
||||
* integer types.
|
||||
* - SDL_SetFloatProperty and SDL_GetFloatProperty operate on floating point
|
||||
* types.
|
||||
* - SDL_SetBooleanProperty and SDL_GetBooleanProperty operate on boolean
|
||||
* types.
|
||||
*
|
||||
* Properties can be removed from a group by using SDL_ClearProperty.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef SDL_properties_h_
|
||||
#define SDL_properties_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* An ID that represents a properties set.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_PropertiesID;
|
||||
|
||||
/**
|
||||
* SDL property type
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_PropertyType
|
||||
{
|
||||
SDL_PROPERTY_TYPE_INVALID,
|
||||
SDL_PROPERTY_TYPE_POINTER,
|
||||
SDL_PROPERTY_TYPE_STRING,
|
||||
SDL_PROPERTY_TYPE_NUMBER,
|
||||
SDL_PROPERTY_TYPE_FLOAT,
|
||||
SDL_PROPERTY_TYPE_BOOLEAN
|
||||
} SDL_PropertyType;
|
||||
|
||||
/**
|
||||
* A generic property for naming things.
|
||||
*
|
||||
* This property is intended to be added to any SDL_PropertiesID that needs a
|
||||
* generic name associated with the property set. It is not guaranteed that
|
||||
* any property set will include this key, but it is convenient to have a
|
||||
* standard key that any piece of code could reasonably agree to use.
|
||||
*
|
||||
* For example, the properties associated with an SDL_Texture might have a
|
||||
* name string of "player sprites", or an SDL_AudioStream might have
|
||||
* "background music", etc. This might also be useful for an SDL_IOStream to
|
||||
* list the path to its asset.
|
||||
*
|
||||
* There is no format for the value set with this key; it is expected to be
|
||||
* human-readable and informational in nature, possibly for logging or
|
||||
* debugging purposes.
|
||||
*
|
||||
* SDL does not currently set this property on any objects it creates, but
|
||||
* this may change in later versions; it is currently expected that apps and
|
||||
* external libraries will take advantage of it, when appropriate.
|
||||
*
|
||||
* \since This macro is available since SDL 3.4.0.
|
||||
*/
|
||||
#define SDL_PROP_NAME_STRING "SDL.name"
|
||||
|
||||
/**
|
||||
* Get the global SDL properties.
|
||||
*
|
||||
* \returns a valid property ID on success or 0 on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGlobalProperties(void);
|
||||
|
||||
/**
|
||||
* Create a group of properties.
|
||||
*
|
||||
* All properties are automatically destroyed when SDL_Quit() is called.
|
||||
*
|
||||
* \returns an ID for a new group of properties, or 0 on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DestroyProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_CreateProperties(void);
|
||||
|
||||
/**
|
||||
* Copy a group of properties.
|
||||
*
|
||||
* Copy all the properties from one group of properties to another, with the
|
||||
* exception of properties requiring cleanup (set using
|
||||
* SDL_SetPointerPropertyWithCleanup()), which will not be copied. Any
|
||||
* property that already exists on `dst` will be overwritten.
|
||||
*
|
||||
* \param src the properties to copy.
|
||||
* \param dst the destination properties.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread. This
|
||||
* function acquires simultaneous mutex locks on both the source
|
||||
* and destination property sets.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_CopyProperties(SDL_PropertiesID src, SDL_PropertiesID dst);
|
||||
|
||||
/**
|
||||
* Lock a group of properties.
|
||||
*
|
||||
* Obtain a multi-threaded lock for these properties. Other threads will wait
|
||||
* while trying to lock these properties until they are unlocked. Properties
|
||||
* must be unlocked before they are destroyed.
|
||||
*
|
||||
* The lock is automatically taken when setting individual properties, this
|
||||
* function is only needed when you want to set several properties atomically
|
||||
* or want to guarantee that properties being queried aren't freed in another
|
||||
* thread.
|
||||
*
|
||||
* \param props the properties to lock.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_UnlockProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_LockProperties(SDL_PropertiesID props);
|
||||
|
||||
/**
|
||||
* Unlock a group of properties.
|
||||
*
|
||||
* \param props the properties to unlock.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_LockProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_UnlockProperties(SDL_PropertiesID props);
|
||||
|
||||
/**
|
||||
* A callback used to free resources when a property is deleted.
|
||||
*
|
||||
* This should release any resources associated with `value` that are no
|
||||
* longer needed.
|
||||
*
|
||||
* This callback is set per-property. Different properties in the same group
|
||||
* can have different cleanup callbacks.
|
||||
*
|
||||
* This callback will be called _during_ SDL_SetPointerPropertyWithCleanup if
|
||||
* the function fails for any reason.
|
||||
*
|
||||
* \param userdata an app-defined pointer passed to the callback.
|
||||
* \param value the pointer assigned to the property to clean up.
|
||||
*
|
||||
* \threadsafety This callback may fire without any locks held; if this is a
|
||||
* concern, the app should provide its own locking.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetPointerPropertyWithCleanup
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_CleanupPropertyCallback)(void *userdata, void *value);
|
||||
|
||||
/**
|
||||
* Set a pointer property in a group of properties with a cleanup function
|
||||
* that is called when the property is deleted.
|
||||
*
|
||||
* The cleanup function is also called if setting the property fails for any
|
||||
* reason.
|
||||
*
|
||||
* For simply setting basic data types, like numbers, bools, or strings, use
|
||||
* SDL_SetNumberProperty, SDL_SetBooleanProperty, or SDL_SetStringProperty
|
||||
* instead, as those functions will handle cleanup on your behalf. This
|
||||
* function is only for more complex, custom data.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property, or NULL to delete the property.
|
||||
* \param cleanup the function to call when this property is deleted, or NULL
|
||||
* if no cleanup is necessary.
|
||||
* \param userdata a pointer that is passed to the cleanup function.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPointerProperty
|
||||
* \sa SDL_SetPointerProperty
|
||||
* \sa SDL_CleanupPropertyCallback
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetPointerPropertyWithCleanup(SDL_PropertiesID props, const char *name, void *value, SDL_CleanupPropertyCallback cleanup, void *userdata);
|
||||
|
||||
/**
|
||||
* Set a pointer property in a group of properties.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property, or NULL to delete the property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPointerProperty
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetBooleanProperty
|
||||
* \sa SDL_SetFloatProperty
|
||||
* \sa SDL_SetNumberProperty
|
||||
* \sa SDL_SetPointerPropertyWithCleanup
|
||||
* \sa SDL_SetStringProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetPointerProperty(SDL_PropertiesID props, const char *name, void *value);
|
||||
|
||||
/**
|
||||
* Set a string property in a group of properties.
|
||||
*
|
||||
* This function makes a copy of the string; the caller does not have to
|
||||
* preserve the data after this call completes.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property, or NULL to delete the property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetStringProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetStringProperty(SDL_PropertiesID props, const char *name, const char *value);
|
||||
|
||||
/**
|
||||
* Set an integer property in a group of properties.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetNumberProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 value);
|
||||
|
||||
/**
|
||||
* Set a floating point property in a group of properties.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetFloatProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetFloatProperty(SDL_PropertiesID props, const char *name, float value);
|
||||
|
||||
/**
|
||||
* Set a boolean property in a group of properties.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to modify.
|
||||
* \param value the new value of the property.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetBooleanProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetBooleanProperty(SDL_PropertiesID props, const char *name, bool value);
|
||||
|
||||
/**
|
||||
* Return whether a property exists in a group of properties.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \returns true if the property exists, or false if it doesn't.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPropertyType
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasProperty(SDL_PropertiesID props, const char *name);
|
||||
|
||||
/**
|
||||
* Get the type of a property in a group of properties.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \returns the type of the property, or SDL_PROPERTY_TYPE_INVALID if it is
|
||||
* not set.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HasProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertyType SDLCALL SDL_GetPropertyType(SDL_PropertiesID props, const char *name);
|
||||
|
||||
/**
|
||||
* Get a pointer property from a group of properties.
|
||||
*
|
||||
* By convention, the names of properties that SDL exposes on objects will
|
||||
* start with "SDL.", and properties that SDL uses internally will start with
|
||||
* "SDL.internal.". These should be considered read-only and should not be
|
||||
* modified by applications.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \param default_value the default value of the property.
|
||||
* \returns the value of the property, or `default_value` if it is not set or
|
||||
* not a pointer property.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, although
|
||||
* the data returned is not protected and could potentially be
|
||||
* freed if you call SDL_SetPointerProperty() or
|
||||
* SDL_ClearProperty() on these properties from another thread.
|
||||
* If you need to avoid this, use SDL_LockProperties() and
|
||||
* SDL_UnlockProperties().
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetBooleanProperty
|
||||
* \sa SDL_GetFloatProperty
|
||||
* \sa SDL_GetNumberProperty
|
||||
* \sa SDL_GetPropertyType
|
||||
* \sa SDL_GetStringProperty
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetPointerProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC void * SDLCALL SDL_GetPointerProperty(SDL_PropertiesID props, const char *name, void *default_value);
|
||||
|
||||
/**
|
||||
* Get a string property from a group of properties.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \param default_value the default value of the property.
|
||||
* \returns the value of the property, or `default_value` if it is not set or
|
||||
* not a string property.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, although
|
||||
* the data returned is not protected and could potentially be
|
||||
* freed if you call SDL_SetStringProperty() or
|
||||
* SDL_ClearProperty() on these properties from another thread.
|
||||
* If you need to avoid this, use SDL_LockProperties() and
|
||||
* SDL_UnlockProperties().
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPropertyType
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetStringProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetStringProperty(SDL_PropertiesID props, const char *name, const char *default_value);
|
||||
|
||||
/**
|
||||
* Get a number property from a group of properties.
|
||||
*
|
||||
* You can use SDL_GetPropertyType() to query whether the property exists and
|
||||
* is a number property.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \param default_value the default value of the property.
|
||||
* \returns the value of the property, or `default_value` if it is not set or
|
||||
* not a number property.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPropertyType
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetNumberProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC Sint64 SDLCALL SDL_GetNumberProperty(SDL_PropertiesID props, const char *name, Sint64 default_value);
|
||||
|
||||
/**
|
||||
* Get a floating point property from a group of properties.
|
||||
*
|
||||
* You can use SDL_GetPropertyType() to query whether the property exists and
|
||||
* is a floating point property.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \param default_value the default value of the property.
|
||||
* \returns the value of the property, or `default_value` if it is not set or
|
||||
* not a float property.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPropertyType
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetFloatProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC float SDLCALL SDL_GetFloatProperty(SDL_PropertiesID props, const char *name, float default_value);
|
||||
|
||||
/**
|
||||
* Get a boolean property from a group of properties.
|
||||
*
|
||||
* You can use SDL_GetPropertyType() to query whether the property exists and
|
||||
* is a boolean property.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param name the name of the property to query.
|
||||
* \param default_value the default value of the property.
|
||||
* \returns the value of the property, or `default_value` if it is not set or
|
||||
* not a boolean property.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPropertyType
|
||||
* \sa SDL_HasProperty
|
||||
* \sa SDL_SetBooleanProperty
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetBooleanProperty(SDL_PropertiesID props, const char *name, bool default_value);
|
||||
|
||||
/**
|
||||
* Clear a property from a group of properties.
|
||||
*
|
||||
* \param props the properties to modify.
|
||||
* \param name the name of the property to clear.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_ClearProperty(SDL_PropertiesID props, const char *name);
|
||||
|
||||
/**
|
||||
* A callback used to enumerate all the properties in a group of properties.
|
||||
*
|
||||
* This callback is called from SDL_EnumerateProperties(), and is called once
|
||||
* per property in the set.
|
||||
*
|
||||
* \param userdata an app-defined pointer passed to the callback.
|
||||
* \param props the SDL_PropertiesID that is being enumerated.
|
||||
* \param name the next property name in the enumeration.
|
||||
*
|
||||
* \threadsafety SDL_EnumerateProperties holds a lock on `props` during this
|
||||
* callback.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_EnumerateProperties
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_EnumeratePropertiesCallback)(void *userdata, SDL_PropertiesID props, const char *name);
|
||||
|
||||
/**
|
||||
* Enumerate the properties contained in a group of properties.
|
||||
*
|
||||
* The callback function is called for each property in the group of
|
||||
* properties. The properties are locked during enumeration.
|
||||
*
|
||||
* \param props the properties to query.
|
||||
* \param callback the function to call for each property.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_EnumerateProperties(SDL_PropertiesID props, SDL_EnumeratePropertiesCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Destroy a group of properties.
|
||||
*
|
||||
* All properties are deleted and their cleanup functions will be called, if
|
||||
* any.
|
||||
*
|
||||
* \param props the properties to destroy.
|
||||
*
|
||||
* \threadsafety This function should not be called while these properties are
|
||||
* locked or other threads might be setting or getting values
|
||||
* from these properties.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateProperties
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DestroyProperties(SDL_PropertiesID props);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_properties_h_ */
|
||||
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryRect
|
||||
*
|
||||
* Some helper functions for managing rectangles and 2D points, in both
|
||||
* integer and floating point versions.
|
||||
*/
|
||||
|
||||
#ifndef SDL_rect_h_
|
||||
#define SDL_rect_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The structure that defines a point (using integers).
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetRectEnclosingPoints
|
||||
* \sa SDL_PointInRect
|
||||
*/
|
||||
typedef struct SDL_Point
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
} SDL_Point;
|
||||
|
||||
/**
|
||||
* The structure that defines a point (using floating point values).
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetRectEnclosingPointsFloat
|
||||
* \sa SDL_PointInRectFloat
|
||||
*/
|
||||
typedef struct SDL_FPoint
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
} SDL_FPoint;
|
||||
|
||||
|
||||
/**
|
||||
* A rectangle, with the origin at the upper left (using integers).
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RectEmpty
|
||||
* \sa SDL_RectsEqual
|
||||
* \sa SDL_HasRectIntersection
|
||||
* \sa SDL_GetRectIntersection
|
||||
* \sa SDL_GetRectAndLineIntersection
|
||||
* \sa SDL_GetRectUnion
|
||||
* \sa SDL_GetRectEnclosingPoints
|
||||
*/
|
||||
typedef struct SDL_Rect
|
||||
{
|
||||
int x, y;
|
||||
int w, h;
|
||||
} SDL_Rect;
|
||||
|
||||
|
||||
/**
|
||||
* A rectangle stored using floating point values.
|
||||
*
|
||||
* The origin of the coordinate space is in the top-left, with increasing
|
||||
* values moving down and right. The properties `x` and `y` represent the
|
||||
* coordinates of the top-left corner of the rectangle.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RectEmptyFloat
|
||||
* \sa SDL_RectsEqualFloat
|
||||
* \sa SDL_RectsEqualEpsilon
|
||||
* \sa SDL_HasRectIntersectionFloat
|
||||
* \sa SDL_GetRectIntersectionFloat
|
||||
* \sa SDL_GetRectAndLineIntersectionFloat
|
||||
* \sa SDL_GetRectUnionFloat
|
||||
* \sa SDL_GetRectEnclosingPointsFloat
|
||||
* \sa SDL_PointInRectFloat
|
||||
*/
|
||||
typedef struct SDL_FRect
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float w;
|
||||
float h;
|
||||
} SDL_FRect;
|
||||
|
||||
|
||||
/**
|
||||
* Convert an SDL_Rect to SDL_FRect
|
||||
*
|
||||
* \param rect a pointer to an SDL_Rect.
|
||||
* \param frect a pointer filled in with the floating point representation of
|
||||
* `rect`.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE void SDL_RectToFRect(const SDL_Rect *rect, SDL_FRect *frect)
|
||||
{
|
||||
frect->x = SDL_static_cast(float, rect->x);
|
||||
frect->y = SDL_static_cast(float, rect->y);
|
||||
frect->w = SDL_static_cast(float, rect->w);
|
||||
frect->h = SDL_static_cast(float, rect->h);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a point resides inside a rectangle.
|
||||
*
|
||||
* A point is considered part of a rectangle if both `p` and `r` are not NULL,
|
||||
* and `p`'s x and y coordinates are >= to the rectangle's top left corner,
|
||||
* and < the rectangle's x+w and y+h. So a 1x1 rectangle considers point (0,0)
|
||||
* as "inside" and (0,1) as not.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param p the point to test.
|
||||
* \param r the rectangle to test.
|
||||
* \returns true if `p` is contained by `r`, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_PointInRect(const SDL_Point *p, const SDL_Rect *r)
|
||||
{
|
||||
return ( p && r && (p->x >= r->x) && (p->x < (r->x + r->w)) &&
|
||||
(p->y >= r->y) && (p->y < (r->y + r->h)) ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a rectangle has no area.
|
||||
*
|
||||
* A rectangle is considered "empty" for this function if `r` is NULL, or if
|
||||
* `r`'s width and/or height are <= 0.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param r the rectangle to test.
|
||||
* \returns true if the rectangle is "empty", false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_RectEmpty(const SDL_Rect *r)
|
||||
{
|
||||
return ((!r) || (r->w <= 0) || (r->h <= 0)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two rectangles are equal.
|
||||
*
|
||||
* Rectangles are considered equal if both are not NULL and each of their x,
|
||||
* y, width and height match.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param a the first rectangle to test.
|
||||
* \param b the second rectangle to test.
|
||||
* \returns true if the rectangles are equal, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_RectsEqual(const SDL_Rect *a, const SDL_Rect *b)
|
||||
{
|
||||
return (a && b && (a->x == b->x) && (a->y == b->y) &&
|
||||
(a->w == b->w) && (a->h == b->h)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two rectangles intersect.
|
||||
*
|
||||
* If either pointer is NULL the function will return false.
|
||||
*
|
||||
* \param A an SDL_Rect structure representing the first rectangle.
|
||||
* \param B an SDL_Rect structure representing the second rectangle.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetRectIntersection
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasRectIntersection(const SDL_Rect *A, const SDL_Rect *B);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two rectangles.
|
||||
*
|
||||
* If `result` is NULL then this function will return false.
|
||||
*
|
||||
* \param A an SDL_Rect structure representing the first rectangle.
|
||||
* \param B an SDL_Rect structure representing the second rectangle.
|
||||
* \param result an SDL_Rect structure filled in with the intersection of
|
||||
* rectangles `A` and `B`.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HasRectIntersection
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectIntersection(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *result);
|
||||
|
||||
/**
|
||||
* Calculate the union of two rectangles.
|
||||
*
|
||||
* \param A an SDL_Rect structure representing the first rectangle.
|
||||
* \param B an SDL_Rect structure representing the second rectangle.
|
||||
* \param result an SDL_Rect structure filled in with the union of rectangles
|
||||
* `A` and `B`.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnion(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *result);
|
||||
|
||||
/**
|
||||
* Calculate a minimal rectangle enclosing a set of points.
|
||||
*
|
||||
* If `clip` is not NULL then only points inside of the clipping rectangle are
|
||||
* considered.
|
||||
*
|
||||
* \param points an array of SDL_Point structures representing points to be
|
||||
* enclosed.
|
||||
* \param count the number of structures in the `points` array.
|
||||
* \param clip an SDL_Rect used for clipping or NULL to enclose all points.
|
||||
* \param result an SDL_Rect structure filled in with the minimal enclosing
|
||||
* rectangle.
|
||||
* \returns true if any points were enclosed or false if all the points were
|
||||
* outside of the clipping rectangle.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPoints(const SDL_Point *points, int count, const SDL_Rect *clip, SDL_Rect *result);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of a rectangle and line segment.
|
||||
*
|
||||
* This function is used to clip a line segment to a rectangle. A line segment
|
||||
* contained entirely within the rectangle or that does not intersect will
|
||||
* remain unchanged. A line segment that crosses the rectangle at either or
|
||||
* both ends will be clipped to the boundary of the rectangle and the new
|
||||
* coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary.
|
||||
*
|
||||
* \param rect an SDL_Rect structure representing the rectangle to intersect.
|
||||
* \param X1 a pointer to the starting X-coordinate of the line.
|
||||
* \param Y1 a pointer to the starting Y-coordinate of the line.
|
||||
* \param X2 a pointer to the ending X-coordinate of the line.
|
||||
* \param Y2 a pointer to the ending Y-coordinate of the line.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectAndLineIntersection(const SDL_Rect *rect, int *X1, int *Y1, int *X2, int *Y2);
|
||||
|
||||
|
||||
/* SDL_FRect versions... */
|
||||
|
||||
/**
|
||||
* Determine whether a point resides inside a floating point rectangle.
|
||||
*
|
||||
* A point is considered part of a rectangle if both `p` and `r` are not NULL,
|
||||
* and `p`'s x and y coordinates are >= to the rectangle's top left corner,
|
||||
* and <= the rectangle's x+w and y+h. So a 1x1 rectangle considers point
|
||||
* (0,0) and (0,1) as "inside" and (0,2) as not.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param p the point to test.
|
||||
* \param r the rectangle to test.
|
||||
* \returns true if `p` is contained by `r`, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_PointInRectFloat(const SDL_FPoint *p, const SDL_FRect *r)
|
||||
{
|
||||
return ( p && r && (p->x >= r->x) && (p->x <= (r->x + r->w)) &&
|
||||
(p->y >= r->y) && (p->y <= (r->y + r->h)) ) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a floating point rectangle takes no space.
|
||||
*
|
||||
* A rectangle is considered "empty" for this function if `r` is NULL, or if
|
||||
* `r`'s width and/or height are < 0.0f.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param r the rectangle to test.
|
||||
* \returns true if the rectangle is "empty", false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_RectEmptyFloat(const SDL_FRect *r)
|
||||
{
|
||||
return ((!r) || (r->w < 0.0f) || (r->h < 0.0f)) ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two floating point rectangles are equal, within some
|
||||
* given epsilon.
|
||||
*
|
||||
* Rectangles are considered equal if both are not NULL and each of their x,
|
||||
* y, width and height are within `epsilon` of each other. If you don't know
|
||||
* what value to use for `epsilon`, you should call the SDL_RectsEqualFloat
|
||||
* function instead.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param a the first rectangle to test.
|
||||
* \param b the second rectangle to test.
|
||||
* \param epsilon the epsilon value for comparison.
|
||||
* \returns true if the rectangles are equal, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RectsEqualFloat
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_RectsEqualEpsilon(const SDL_FRect *a, const SDL_FRect *b, float epsilon)
|
||||
{
|
||||
return (a && b && ((a == b) ||
|
||||
((SDL_fabsf(a->x - b->x) <= epsilon) &&
|
||||
(SDL_fabsf(a->y - b->y) <= epsilon) &&
|
||||
(SDL_fabsf(a->w - b->w) <= epsilon) &&
|
||||
(SDL_fabsf(a->h - b->h) <= epsilon))))
|
||||
? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two floating point rectangles are equal, within a default
|
||||
* epsilon.
|
||||
*
|
||||
* Rectangles are considered equal if both are not NULL and each of their x,
|
||||
* y, width and height are within SDL_FLT_EPSILON of each other. This is often
|
||||
* a reasonable way to compare two floating point rectangles and deal with the
|
||||
* slight precision variations in floating point calculations that tend to pop
|
||||
* up.
|
||||
*
|
||||
* Note that this is a forced-inline function in a header, and not a public
|
||||
* API function available in the SDL library (which is to say, the code is
|
||||
* embedded in the calling program and the linker and dynamic loader will not
|
||||
* be able to find this function inside SDL itself).
|
||||
*
|
||||
* \param a the first rectangle to test.
|
||||
* \param b the second rectangle to test.
|
||||
* \returns true if the rectangles are equal, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_RectsEqualEpsilon
|
||||
*/
|
||||
SDL_FORCE_INLINE bool SDL_RectsEqualFloat(const SDL_FRect *a, const SDL_FRect *b)
|
||||
{
|
||||
return SDL_RectsEqualEpsilon(a, b, SDL_FLT_EPSILON);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether two rectangles intersect with float precision.
|
||||
*
|
||||
* If either pointer is NULL the function will return false.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle.
|
||||
* \param B an SDL_FRect structure representing the second rectangle.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetRectIntersectionFloat
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_HasRectIntersectionFloat(const SDL_FRect *A, const SDL_FRect *B);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of two rectangles with float precision.
|
||||
*
|
||||
* If `result` is NULL then this function will return false.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle.
|
||||
* \param B an SDL_FRect structure representing the second rectangle.
|
||||
* \param result an SDL_FRect structure filled in with the intersection of
|
||||
* rectangles `A` and `B`.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_HasRectIntersectionFloat
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectIntersectionFloat(const SDL_FRect *A, const SDL_FRect *B, SDL_FRect *result);
|
||||
|
||||
/**
|
||||
* Calculate the union of two rectangles with float precision.
|
||||
*
|
||||
* \param A an SDL_FRect structure representing the first rectangle.
|
||||
* \param B an SDL_FRect structure representing the second rectangle.
|
||||
* \param result an SDL_FRect structure filled in with the union of rectangles
|
||||
* `A` and `B`.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectUnionFloat(const SDL_FRect *A, const SDL_FRect *B, SDL_FRect *result);
|
||||
|
||||
/**
|
||||
* Calculate a minimal rectangle enclosing a set of points with float
|
||||
* precision.
|
||||
*
|
||||
* If `clip` is not NULL then only points inside of the clipping rectangle are
|
||||
* considered.
|
||||
*
|
||||
* \param points an array of SDL_FPoint structures representing points to be
|
||||
* enclosed.
|
||||
* \param count the number of structures in the `points` array.
|
||||
* \param clip an SDL_FRect used for clipping or NULL to enclose all points.
|
||||
* \param result an SDL_FRect structure filled in with the minimal enclosing
|
||||
* rectangle.
|
||||
* \returns true if any points were enclosed or false if all the points were
|
||||
* outside of the clipping rectangle.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectEnclosingPointsFloat(const SDL_FPoint *points, int count, const SDL_FRect *clip, SDL_FRect *result);
|
||||
|
||||
/**
|
||||
* Calculate the intersection of a rectangle and line segment with float
|
||||
* precision.
|
||||
*
|
||||
* This function is used to clip a line segment to a rectangle. A line segment
|
||||
* contained entirely within the rectangle or that does not intersect will
|
||||
* remain unchanged. A line segment that crosses the rectangle at either or
|
||||
* both ends will be clipped to the boundary of the rectangle and the new
|
||||
* coordinates saved in `X1`, `Y1`, `X2`, and/or `Y2` as necessary.
|
||||
*
|
||||
* \param rect an SDL_FRect structure representing the rectangle to intersect.
|
||||
* \param X1 a pointer to the starting X-coordinate of the line.
|
||||
* \param Y1 a pointer to the starting Y-coordinate of the line.
|
||||
* \param X2 a pointer to the ending X-coordinate of the line.
|
||||
* \param Y2 a pointer to the ending Y-coordinate of the line.
|
||||
* \returns true if there is an intersection, false otherwise.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetRectAndLineIntersectionFloat(const SDL_FRect *rect, float *X1, float *Y1, float *X2, float *Y2);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_rect_h_ */
|
||||
@@ -0,0 +1,429 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryScancode
|
||||
*
|
||||
* Defines keyboard scancodes.
|
||||
*
|
||||
* Please refer to the Best Keyboard Practices document for details on what
|
||||
* this information means and how best to use it.
|
||||
*
|
||||
* https://wiki.libsdl.org/SDL3/BestKeyboardPractices
|
||||
*/
|
||||
|
||||
#ifndef SDL_scancode_h_
|
||||
#define SDL_scancode_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
|
||||
/**
|
||||
* The SDL keyboard scancode representation.
|
||||
*
|
||||
* An SDL scancode is the physical representation of a key on the keyboard,
|
||||
* independent of language and keyboard mapping.
|
||||
*
|
||||
* Values of this type are used to represent keyboard keys, among other places
|
||||
* in the `scancode` field of the SDL_KeyboardEvent structure.
|
||||
*
|
||||
* The values in this enumeration are based on the USB usage page standard:
|
||||
* https://usb.org/sites/default/files/hut1_5.pdf
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_Scancode
|
||||
{
|
||||
SDL_SCANCODE_UNKNOWN = 0,
|
||||
|
||||
/**
|
||||
* \name Usage page 0x07
|
||||
*
|
||||
* These values are from usage page 0x07 (USB keyboard page).
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
SDL_SCANCODE_A = 4,
|
||||
SDL_SCANCODE_B = 5,
|
||||
SDL_SCANCODE_C = 6,
|
||||
SDL_SCANCODE_D = 7,
|
||||
SDL_SCANCODE_E = 8,
|
||||
SDL_SCANCODE_F = 9,
|
||||
SDL_SCANCODE_G = 10,
|
||||
SDL_SCANCODE_H = 11,
|
||||
SDL_SCANCODE_I = 12,
|
||||
SDL_SCANCODE_J = 13,
|
||||
SDL_SCANCODE_K = 14,
|
||||
SDL_SCANCODE_L = 15,
|
||||
SDL_SCANCODE_M = 16,
|
||||
SDL_SCANCODE_N = 17,
|
||||
SDL_SCANCODE_O = 18,
|
||||
SDL_SCANCODE_P = 19,
|
||||
SDL_SCANCODE_Q = 20,
|
||||
SDL_SCANCODE_R = 21,
|
||||
SDL_SCANCODE_S = 22,
|
||||
SDL_SCANCODE_T = 23,
|
||||
SDL_SCANCODE_U = 24,
|
||||
SDL_SCANCODE_V = 25,
|
||||
SDL_SCANCODE_W = 26,
|
||||
SDL_SCANCODE_X = 27,
|
||||
SDL_SCANCODE_Y = 28,
|
||||
SDL_SCANCODE_Z = 29,
|
||||
|
||||
SDL_SCANCODE_1 = 30,
|
||||
SDL_SCANCODE_2 = 31,
|
||||
SDL_SCANCODE_3 = 32,
|
||||
SDL_SCANCODE_4 = 33,
|
||||
SDL_SCANCODE_5 = 34,
|
||||
SDL_SCANCODE_6 = 35,
|
||||
SDL_SCANCODE_7 = 36,
|
||||
SDL_SCANCODE_8 = 37,
|
||||
SDL_SCANCODE_9 = 38,
|
||||
SDL_SCANCODE_0 = 39,
|
||||
|
||||
SDL_SCANCODE_RETURN = 40,
|
||||
SDL_SCANCODE_ESCAPE = 41,
|
||||
SDL_SCANCODE_BACKSPACE = 42,
|
||||
SDL_SCANCODE_TAB = 43,
|
||||
SDL_SCANCODE_SPACE = 44,
|
||||
|
||||
SDL_SCANCODE_MINUS = 45,
|
||||
SDL_SCANCODE_EQUALS = 46,
|
||||
SDL_SCANCODE_LEFTBRACKET = 47,
|
||||
SDL_SCANCODE_RIGHTBRACKET = 48,
|
||||
SDL_SCANCODE_BACKSLASH = 49, /**< Located at the lower left of the return
|
||||
* key on ISO keyboards and at the right end
|
||||
* of the QWERTY row on ANSI keyboards.
|
||||
* Produces REVERSE SOLIDUS (backslash) and
|
||||
* VERTICAL LINE in a US layout, REVERSE
|
||||
* SOLIDUS and VERTICAL LINE in a UK Mac
|
||||
* layout, NUMBER SIGN and TILDE in a UK
|
||||
* Windows layout, DOLLAR SIGN and POUND SIGN
|
||||
* in a Swiss German layout, NUMBER SIGN and
|
||||
* APOSTROPHE in a German layout, GRAVE
|
||||
* ACCENT and POUND SIGN in a French Mac
|
||||
* layout, and ASTERISK and MICRO SIGN in a
|
||||
* French Windows layout.
|
||||
*/
|
||||
SDL_SCANCODE_NONUSHASH = 50, /**< ISO USB keyboards actually use this code
|
||||
* instead of 49 for the same key, but all
|
||||
* OSes I've seen treat the two codes
|
||||
* identically. So, as an implementor, unless
|
||||
* your keyboard generates both of those
|
||||
* codes and your OS treats them differently,
|
||||
* you should generate SDL_SCANCODE_BACKSLASH
|
||||
* instead of this code. As a user, you
|
||||
* should not rely on this code because SDL
|
||||
* will never generate it with most (all?)
|
||||
* keyboards.
|
||||
*/
|
||||
SDL_SCANCODE_SEMICOLON = 51,
|
||||
SDL_SCANCODE_APOSTROPHE = 52,
|
||||
SDL_SCANCODE_GRAVE = 53, /**< Located in the top left corner (on both ANSI
|
||||
* and ISO keyboards). Produces GRAVE ACCENT and
|
||||
* TILDE in a US Windows layout and in US and UK
|
||||
* Mac layouts on ANSI keyboards, GRAVE ACCENT
|
||||
* and NOT SIGN in a UK Windows layout, SECTION
|
||||
* SIGN and PLUS-MINUS SIGN in US and UK Mac
|
||||
* layouts on ISO keyboards, SECTION SIGN and
|
||||
* DEGREE SIGN in a Swiss German layout (Mac:
|
||||
* only on ISO keyboards), CIRCUMFLEX ACCENT and
|
||||
* DEGREE SIGN in a German layout (Mac: only on
|
||||
* ISO keyboards), SUPERSCRIPT TWO and TILDE in a
|
||||
* French Windows layout, COMMERCIAL AT and
|
||||
* NUMBER SIGN in a French Mac layout on ISO
|
||||
* keyboards, and LESS-THAN SIGN and GREATER-THAN
|
||||
* SIGN in a Swiss German, German, or French Mac
|
||||
* layout on ANSI keyboards.
|
||||
*/
|
||||
SDL_SCANCODE_COMMA = 54,
|
||||
SDL_SCANCODE_PERIOD = 55,
|
||||
SDL_SCANCODE_SLASH = 56,
|
||||
|
||||
SDL_SCANCODE_CAPSLOCK = 57,
|
||||
|
||||
SDL_SCANCODE_F1 = 58,
|
||||
SDL_SCANCODE_F2 = 59,
|
||||
SDL_SCANCODE_F3 = 60,
|
||||
SDL_SCANCODE_F4 = 61,
|
||||
SDL_SCANCODE_F5 = 62,
|
||||
SDL_SCANCODE_F6 = 63,
|
||||
SDL_SCANCODE_F7 = 64,
|
||||
SDL_SCANCODE_F8 = 65,
|
||||
SDL_SCANCODE_F9 = 66,
|
||||
SDL_SCANCODE_F10 = 67,
|
||||
SDL_SCANCODE_F11 = 68,
|
||||
SDL_SCANCODE_F12 = 69,
|
||||
|
||||
SDL_SCANCODE_PRINTSCREEN = 70,
|
||||
SDL_SCANCODE_SCROLLLOCK = 71,
|
||||
SDL_SCANCODE_PAUSE = 72,
|
||||
SDL_SCANCODE_INSERT = 73, /**< insert on PC, help on some Mac keyboards (but
|
||||
does send code 73, not 117) */
|
||||
SDL_SCANCODE_HOME = 74,
|
||||
SDL_SCANCODE_PAGEUP = 75,
|
||||
SDL_SCANCODE_DELETE = 76,
|
||||
SDL_SCANCODE_END = 77,
|
||||
SDL_SCANCODE_PAGEDOWN = 78,
|
||||
SDL_SCANCODE_RIGHT = 79,
|
||||
SDL_SCANCODE_LEFT = 80,
|
||||
SDL_SCANCODE_DOWN = 81,
|
||||
SDL_SCANCODE_UP = 82,
|
||||
|
||||
SDL_SCANCODE_NUMLOCKCLEAR = 83, /**< num lock on PC, clear on Mac keyboards
|
||||
*/
|
||||
SDL_SCANCODE_KP_DIVIDE = 84,
|
||||
SDL_SCANCODE_KP_MULTIPLY = 85,
|
||||
SDL_SCANCODE_KP_MINUS = 86,
|
||||
SDL_SCANCODE_KP_PLUS = 87,
|
||||
SDL_SCANCODE_KP_ENTER = 88,
|
||||
SDL_SCANCODE_KP_1 = 89,
|
||||
SDL_SCANCODE_KP_2 = 90,
|
||||
SDL_SCANCODE_KP_3 = 91,
|
||||
SDL_SCANCODE_KP_4 = 92,
|
||||
SDL_SCANCODE_KP_5 = 93,
|
||||
SDL_SCANCODE_KP_6 = 94,
|
||||
SDL_SCANCODE_KP_7 = 95,
|
||||
SDL_SCANCODE_KP_8 = 96,
|
||||
SDL_SCANCODE_KP_9 = 97,
|
||||
SDL_SCANCODE_KP_0 = 98,
|
||||
SDL_SCANCODE_KP_PERIOD = 99,
|
||||
|
||||
SDL_SCANCODE_NONUSBACKSLASH = 100, /**< This is the additional key that ISO
|
||||
* keyboards have over ANSI ones,
|
||||
* located between left shift and Z.
|
||||
* Produces GRAVE ACCENT and TILDE in a
|
||||
* US or UK Mac layout, REVERSE SOLIDUS
|
||||
* (backslash) and VERTICAL LINE in a
|
||||
* US or UK Windows layout, and
|
||||
* LESS-THAN SIGN and GREATER-THAN SIGN
|
||||
* in a Swiss German, German, or French
|
||||
* layout. */
|
||||
SDL_SCANCODE_APPLICATION = 101, /**< windows contextual menu, compose */
|
||||
SDL_SCANCODE_POWER = 102, /**< The USB document says this is a status flag,
|
||||
* not a physical key - but some Mac keyboards
|
||||
* do have a power key. */
|
||||
SDL_SCANCODE_KP_EQUALS = 103,
|
||||
SDL_SCANCODE_F13 = 104,
|
||||
SDL_SCANCODE_F14 = 105,
|
||||
SDL_SCANCODE_F15 = 106,
|
||||
SDL_SCANCODE_F16 = 107,
|
||||
SDL_SCANCODE_F17 = 108,
|
||||
SDL_SCANCODE_F18 = 109,
|
||||
SDL_SCANCODE_F19 = 110,
|
||||
SDL_SCANCODE_F20 = 111,
|
||||
SDL_SCANCODE_F21 = 112,
|
||||
SDL_SCANCODE_F22 = 113,
|
||||
SDL_SCANCODE_F23 = 114,
|
||||
SDL_SCANCODE_F24 = 115,
|
||||
SDL_SCANCODE_EXECUTE = 116,
|
||||
SDL_SCANCODE_HELP = 117, /**< AL Integrated Help Center */
|
||||
SDL_SCANCODE_MENU = 118, /**< Menu (show menu) */
|
||||
SDL_SCANCODE_SELECT = 119,
|
||||
SDL_SCANCODE_STOP = 120, /**< AC Stop */
|
||||
SDL_SCANCODE_AGAIN = 121, /**< AC Redo/Repeat */
|
||||
SDL_SCANCODE_UNDO = 122, /**< AC Undo */
|
||||
SDL_SCANCODE_CUT = 123, /**< AC Cut */
|
||||
SDL_SCANCODE_COPY = 124, /**< AC Copy */
|
||||
SDL_SCANCODE_PASTE = 125, /**< AC Paste */
|
||||
SDL_SCANCODE_FIND = 126, /**< AC Find */
|
||||
SDL_SCANCODE_MUTE = 127,
|
||||
SDL_SCANCODE_VOLUMEUP = 128,
|
||||
SDL_SCANCODE_VOLUMEDOWN = 129,
|
||||
/* not sure whether there's a reason to enable these */
|
||||
/* SDL_SCANCODE_LOCKINGCAPSLOCK = 130, */
|
||||
/* SDL_SCANCODE_LOCKINGNUMLOCK = 131, */
|
||||
/* SDL_SCANCODE_LOCKINGSCROLLLOCK = 132, */
|
||||
SDL_SCANCODE_KP_COMMA = 133,
|
||||
SDL_SCANCODE_KP_EQUALSAS400 = 134,
|
||||
|
||||
SDL_SCANCODE_INTERNATIONAL1 = 135, /**< used on Asian keyboards, see
|
||||
footnotes in USB doc */
|
||||
SDL_SCANCODE_INTERNATIONAL2 = 136,
|
||||
SDL_SCANCODE_INTERNATIONAL3 = 137, /**< Yen */
|
||||
SDL_SCANCODE_INTERNATIONAL4 = 138,
|
||||
SDL_SCANCODE_INTERNATIONAL5 = 139,
|
||||
SDL_SCANCODE_INTERNATIONAL6 = 140,
|
||||
SDL_SCANCODE_INTERNATIONAL7 = 141,
|
||||
SDL_SCANCODE_INTERNATIONAL8 = 142,
|
||||
SDL_SCANCODE_INTERNATIONAL9 = 143,
|
||||
SDL_SCANCODE_LANG1 = 144, /**< Hangul/English toggle */
|
||||
SDL_SCANCODE_LANG2 = 145, /**< Hanja conversion */
|
||||
SDL_SCANCODE_LANG3 = 146, /**< Katakana */
|
||||
SDL_SCANCODE_LANG4 = 147, /**< Hiragana */
|
||||
SDL_SCANCODE_LANG5 = 148, /**< Zenkaku/Hankaku */
|
||||
SDL_SCANCODE_LANG6 = 149, /**< reserved */
|
||||
SDL_SCANCODE_LANG7 = 150, /**< reserved */
|
||||
SDL_SCANCODE_LANG8 = 151, /**< reserved */
|
||||
SDL_SCANCODE_LANG9 = 152, /**< reserved */
|
||||
|
||||
SDL_SCANCODE_ALTERASE = 153, /**< Erase-Eaze */
|
||||
SDL_SCANCODE_SYSREQ = 154,
|
||||
SDL_SCANCODE_CANCEL = 155, /**< AC Cancel */
|
||||
SDL_SCANCODE_CLEAR = 156,
|
||||
SDL_SCANCODE_PRIOR = 157,
|
||||
SDL_SCANCODE_RETURN2 = 158,
|
||||
SDL_SCANCODE_SEPARATOR = 159,
|
||||
SDL_SCANCODE_OUT = 160,
|
||||
SDL_SCANCODE_OPER = 161,
|
||||
SDL_SCANCODE_CLEARAGAIN = 162,
|
||||
SDL_SCANCODE_CRSEL = 163,
|
||||
SDL_SCANCODE_EXSEL = 164,
|
||||
|
||||
SDL_SCANCODE_KP_00 = 176,
|
||||
SDL_SCANCODE_KP_000 = 177,
|
||||
SDL_SCANCODE_THOUSANDSSEPARATOR = 178,
|
||||
SDL_SCANCODE_DECIMALSEPARATOR = 179,
|
||||
SDL_SCANCODE_CURRENCYUNIT = 180,
|
||||
SDL_SCANCODE_CURRENCYSUBUNIT = 181,
|
||||
SDL_SCANCODE_KP_LEFTPAREN = 182,
|
||||
SDL_SCANCODE_KP_RIGHTPAREN = 183,
|
||||
SDL_SCANCODE_KP_LEFTBRACE = 184,
|
||||
SDL_SCANCODE_KP_RIGHTBRACE = 185,
|
||||
SDL_SCANCODE_KP_TAB = 186,
|
||||
SDL_SCANCODE_KP_BACKSPACE = 187,
|
||||
SDL_SCANCODE_KP_A = 188,
|
||||
SDL_SCANCODE_KP_B = 189,
|
||||
SDL_SCANCODE_KP_C = 190,
|
||||
SDL_SCANCODE_KP_D = 191,
|
||||
SDL_SCANCODE_KP_E = 192,
|
||||
SDL_SCANCODE_KP_F = 193,
|
||||
SDL_SCANCODE_KP_XOR = 194,
|
||||
SDL_SCANCODE_KP_POWER = 195,
|
||||
SDL_SCANCODE_KP_PERCENT = 196,
|
||||
SDL_SCANCODE_KP_LESS = 197,
|
||||
SDL_SCANCODE_KP_GREATER = 198,
|
||||
SDL_SCANCODE_KP_AMPERSAND = 199,
|
||||
SDL_SCANCODE_KP_DBLAMPERSAND = 200,
|
||||
SDL_SCANCODE_KP_VERTICALBAR = 201,
|
||||
SDL_SCANCODE_KP_DBLVERTICALBAR = 202,
|
||||
SDL_SCANCODE_KP_COLON = 203,
|
||||
SDL_SCANCODE_KP_HASH = 204,
|
||||
SDL_SCANCODE_KP_SPACE = 205,
|
||||
SDL_SCANCODE_KP_AT = 206,
|
||||
SDL_SCANCODE_KP_EXCLAM = 207,
|
||||
SDL_SCANCODE_KP_MEMSTORE = 208,
|
||||
SDL_SCANCODE_KP_MEMRECALL = 209,
|
||||
SDL_SCANCODE_KP_MEMCLEAR = 210,
|
||||
SDL_SCANCODE_KP_MEMADD = 211,
|
||||
SDL_SCANCODE_KP_MEMSUBTRACT = 212,
|
||||
SDL_SCANCODE_KP_MEMMULTIPLY = 213,
|
||||
SDL_SCANCODE_KP_MEMDIVIDE = 214,
|
||||
SDL_SCANCODE_KP_PLUSMINUS = 215,
|
||||
SDL_SCANCODE_KP_CLEAR = 216,
|
||||
SDL_SCANCODE_KP_CLEARENTRY = 217,
|
||||
SDL_SCANCODE_KP_BINARY = 218,
|
||||
SDL_SCANCODE_KP_OCTAL = 219,
|
||||
SDL_SCANCODE_KP_DECIMAL = 220,
|
||||
SDL_SCANCODE_KP_HEXADECIMAL = 221,
|
||||
|
||||
SDL_SCANCODE_LCTRL = 224,
|
||||
SDL_SCANCODE_LSHIFT = 225,
|
||||
SDL_SCANCODE_LALT = 226, /**< alt, option */
|
||||
SDL_SCANCODE_LGUI = 227, /**< windows, command (apple), meta */
|
||||
SDL_SCANCODE_RCTRL = 228,
|
||||
SDL_SCANCODE_RSHIFT = 229,
|
||||
SDL_SCANCODE_RALT = 230, /**< alt gr, option */
|
||||
SDL_SCANCODE_RGUI = 231, /**< windows, command (apple), meta */
|
||||
|
||||
SDL_SCANCODE_MODE = 257, /**< I'm not sure if this is really not covered
|
||||
* by any of the above, but since there's a
|
||||
* special SDL_KMOD_MODE for it I'm adding it here
|
||||
*/
|
||||
|
||||
/* @} *//* Usage page 0x07 */
|
||||
|
||||
/**
|
||||
* \name Usage page 0x0C
|
||||
*
|
||||
* These values are mapped from usage page 0x0C (USB consumer page).
|
||||
*
|
||||
* There are way more keys in the spec than we can represent in the
|
||||
* current scancode range, so pick the ones that commonly come up in
|
||||
* real world usage.
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
SDL_SCANCODE_SLEEP = 258, /**< Sleep */
|
||||
SDL_SCANCODE_WAKE = 259, /**< Wake */
|
||||
|
||||
SDL_SCANCODE_CHANNEL_INCREMENT = 260, /**< Channel Increment */
|
||||
SDL_SCANCODE_CHANNEL_DECREMENT = 261, /**< Channel Decrement */
|
||||
|
||||
SDL_SCANCODE_MEDIA_PLAY = 262, /**< Play */
|
||||
SDL_SCANCODE_MEDIA_PAUSE = 263, /**< Pause */
|
||||
SDL_SCANCODE_MEDIA_RECORD = 264, /**< Record */
|
||||
SDL_SCANCODE_MEDIA_FAST_FORWARD = 265, /**< Fast Forward */
|
||||
SDL_SCANCODE_MEDIA_REWIND = 266, /**< Rewind */
|
||||
SDL_SCANCODE_MEDIA_NEXT_TRACK = 267, /**< Next Track */
|
||||
SDL_SCANCODE_MEDIA_PREVIOUS_TRACK = 268, /**< Previous Track */
|
||||
SDL_SCANCODE_MEDIA_STOP = 269, /**< Stop */
|
||||
SDL_SCANCODE_MEDIA_EJECT = 270, /**< Eject */
|
||||
SDL_SCANCODE_MEDIA_PLAY_PAUSE = 271, /**< Play / Pause */
|
||||
SDL_SCANCODE_MEDIA_SELECT = 272, /* Media Select */
|
||||
|
||||
SDL_SCANCODE_AC_NEW = 273, /**< AC New */
|
||||
SDL_SCANCODE_AC_OPEN = 274, /**< AC Open */
|
||||
SDL_SCANCODE_AC_CLOSE = 275, /**< AC Close */
|
||||
SDL_SCANCODE_AC_EXIT = 276, /**< AC Exit */
|
||||
SDL_SCANCODE_AC_SAVE = 277, /**< AC Save */
|
||||
SDL_SCANCODE_AC_PRINT = 278, /**< AC Print */
|
||||
SDL_SCANCODE_AC_PROPERTIES = 279, /**< AC Properties */
|
||||
|
||||
SDL_SCANCODE_AC_SEARCH = 280, /**< AC Search */
|
||||
SDL_SCANCODE_AC_HOME = 281, /**< AC Home */
|
||||
SDL_SCANCODE_AC_BACK = 282, /**< AC Back */
|
||||
SDL_SCANCODE_AC_FORWARD = 283, /**< AC Forward */
|
||||
SDL_SCANCODE_AC_STOP = 284, /**< AC Stop */
|
||||
SDL_SCANCODE_AC_REFRESH = 285, /**< AC Refresh */
|
||||
SDL_SCANCODE_AC_BOOKMARKS = 286, /**< AC Bookmarks */
|
||||
|
||||
/* @} *//* Usage page 0x0C */
|
||||
|
||||
|
||||
/**
|
||||
* \name Mobile keys
|
||||
*
|
||||
* These are values that are often used on mobile phones.
|
||||
*/
|
||||
/* @{ */
|
||||
|
||||
SDL_SCANCODE_SOFTLEFT = 287, /**< Usually situated below the display on phones and
|
||||
used as a multi-function feature key for selecting
|
||||
a software defined function shown on the bottom left
|
||||
of the display. */
|
||||
SDL_SCANCODE_SOFTRIGHT = 288, /**< Usually situated below the display on phones and
|
||||
used as a multi-function feature key for selecting
|
||||
a software defined function shown on the bottom right
|
||||
of the display. */
|
||||
SDL_SCANCODE_CALL = 289, /**< Used for accepting phone calls. */
|
||||
SDL_SCANCODE_ENDCALL = 290, /**< Used for rejecting phone calls. */
|
||||
|
||||
/* @} *//* Mobile keys */
|
||||
|
||||
/* Add any other keys here. */
|
||||
|
||||
SDL_SCANCODE_RESERVED = 400, /**< 400-500 reserved for dynamic keycodes */
|
||||
|
||||
SDL_SCANCODE_COUNT = 512 /**< not a key, just marks the number of scancodes for array bounds */
|
||||
|
||||
} SDL_Scancode;
|
||||
|
||||
#endif /* SDL_scancode_h_ */
|
||||
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategorySensor
|
||||
*
|
||||
* SDL sensor management.
|
||||
*
|
||||
* These APIs grant access to gyros and accelerometers on various platforms.
|
||||
*
|
||||
* In order to use these functions, SDL_Init() must have been called with the
|
||||
* SDL_INIT_SENSOR flag. This causes SDL to scan the system for sensors, and
|
||||
* load appropriate drivers.
|
||||
*/
|
||||
|
||||
#ifndef SDL_sensor_h_
|
||||
#define SDL_sensor_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
extern "C" {
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The opaque structure used to identify an opened SDL sensor.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef struct SDL_Sensor SDL_Sensor;
|
||||
|
||||
/**
|
||||
* This is a unique ID for a sensor for the time it is connected to the
|
||||
* system, and is never reused for the lifetime of the application.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_SensorID;
|
||||
|
||||
/**
|
||||
* A constant to represent standard gravity for accelerometer sensors.
|
||||
*
|
||||
* The accelerometer returns the current acceleration in SI meters per second
|
||||
* squared. This measurement includes the force of gravity, so a device at
|
||||
* rest will have an value of SDL_STANDARD_GRAVITY away from the center of the
|
||||
* earth, which is a positive Y value.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_STANDARD_GRAVITY 9.80665f
|
||||
|
||||
/**
|
||||
* The different sensors defined by SDL.
|
||||
*
|
||||
* Additional sensors may be available, using platform dependent semantics.
|
||||
*
|
||||
* Here are the additional Android sensors:
|
||||
*
|
||||
* https://developer.android.com/reference/android/hardware/SensorEvent.html#values
|
||||
*
|
||||
* Accelerometer sensor notes:
|
||||
*
|
||||
* The accelerometer returns the current acceleration in SI meters per second
|
||||
* squared. This measurement includes the force of gravity, so a device at
|
||||
* rest will have an value of SDL_STANDARD_GRAVITY away from the center of the
|
||||
* earth, which is a positive Y value.
|
||||
*
|
||||
* - `values[0]`: Acceleration on the x axis
|
||||
* - `values[1]`: Acceleration on the y axis
|
||||
* - `values[2]`: Acceleration on the z axis
|
||||
*
|
||||
* For phones and tablets held in natural orientation and game controllers
|
||||
* held in front of you, the axes are defined as follows:
|
||||
*
|
||||
* - -X ... +X : left ... right
|
||||
* - -Y ... +Y : bottom ... top
|
||||
* - -Z ... +Z : farther ... closer
|
||||
*
|
||||
* The accelerometer axis data is not changed when the device is rotated.
|
||||
*
|
||||
* Gyroscope sensor notes:
|
||||
*
|
||||
* The gyroscope returns the current rate of rotation in radians per second.
|
||||
* The rotation is positive in the counter-clockwise direction. That is, an
|
||||
* observer looking from a positive location on one of the axes would see
|
||||
* positive rotation on that axis when it appeared to be rotating
|
||||
* counter-clockwise.
|
||||
*
|
||||
* - `values[0]`: Angular speed around the x axis (pitch)
|
||||
* - `values[1]`: Angular speed around the y axis (yaw)
|
||||
* - `values[2]`: Angular speed around the z axis (roll)
|
||||
*
|
||||
* For phones and tablets held in natural orientation and game controllers
|
||||
* held in front of you, the axes are defined as follows:
|
||||
*
|
||||
* - -X ... +X : left ... right
|
||||
* - -Y ... +Y : bottom ... top
|
||||
* - -Z ... +Z : farther ... closer
|
||||
*
|
||||
* The gyroscope axis data is not changed when the device is rotated.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCurrentDisplayOrientation
|
||||
*/
|
||||
typedef enum SDL_SensorType
|
||||
{
|
||||
SDL_SENSOR_INVALID = -1, /**< Returned for an invalid sensor */
|
||||
SDL_SENSOR_UNKNOWN, /**< Unknown sensor type */
|
||||
SDL_SENSOR_ACCEL, /**< Accelerometer */
|
||||
SDL_SENSOR_GYRO, /**< Gyroscope */
|
||||
SDL_SENSOR_ACCEL_L, /**< Accelerometer for left Joy-Con controller and Wii nunchuk */
|
||||
SDL_SENSOR_GYRO_L, /**< Gyroscope for left Joy-Con controller */
|
||||
SDL_SENSOR_ACCEL_R, /**< Accelerometer for right Joy-Con controller */
|
||||
SDL_SENSOR_GYRO_R, /**< Gyroscope for right Joy-Con controller */
|
||||
SDL_SENSOR_COUNT
|
||||
} SDL_SensorType;
|
||||
|
||||
|
||||
/* Function prototypes */
|
||||
|
||||
/**
|
||||
* Get a list of currently connected sensors.
|
||||
*
|
||||
* \param count a pointer filled in with the number of sensors returned, may
|
||||
* be NULL.
|
||||
* \returns a 0 terminated array of sensor instance IDs or NULL on failure;
|
||||
* call SDL_GetError() for more information. This should be freed
|
||||
* with SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_SensorID * SDLCALL SDL_GetSensors(int *count);
|
||||
|
||||
/**
|
||||
* Get the implementation dependent name of a sensor.
|
||||
*
|
||||
* This can be called before any sensors are opened.
|
||||
*
|
||||
* \param instance_id the sensor instance ID.
|
||||
* \returns the sensor name, or NULL if `instance_id` is not valid.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetSensorNameForID(SDL_SensorID instance_id);
|
||||
|
||||
/**
|
||||
* Get the type of a sensor.
|
||||
*
|
||||
* This can be called before any sensors are opened.
|
||||
*
|
||||
* \param instance_id the sensor instance ID.
|
||||
* \returns the SDL_SensorType, or `SDL_SENSOR_INVALID` if `instance_id` is
|
||||
* not valid.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_SensorType SDLCALL SDL_GetSensorTypeForID(SDL_SensorID instance_id);
|
||||
|
||||
/**
|
||||
* Get the platform dependent type of a sensor.
|
||||
*
|
||||
* This can be called before any sensors are opened.
|
||||
*
|
||||
* \param instance_id the sensor instance ID.
|
||||
* \returns the sensor platform dependent type, or -1 if `instance_id` is not
|
||||
* valid.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_GetSensorNonPortableTypeForID(SDL_SensorID instance_id);
|
||||
|
||||
/**
|
||||
* Open a sensor for use.
|
||||
*
|
||||
* \param instance_id the sensor instance ID.
|
||||
* \returns an SDL_Sensor object or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Sensor * SDLCALL SDL_OpenSensor(SDL_SensorID instance_id);
|
||||
|
||||
/**
|
||||
* Return the SDL_Sensor associated with an instance ID.
|
||||
*
|
||||
* \param instance_id the sensor instance ID.
|
||||
* \returns an SDL_Sensor object or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Sensor * SDLCALL SDL_GetSensorFromID(SDL_SensorID instance_id);
|
||||
|
||||
/**
|
||||
* Get the properties associated with a sensor.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object.
|
||||
* \returns a valid property ID on success or 0 on failure; call
|
||||
* SDL_GetError() for more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetSensorProperties(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Get the implementation dependent name of a sensor.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object.
|
||||
* \returns the sensor name or NULL on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetSensorName(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Get the type of a sensor.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object to inspect.
|
||||
* \returns the SDL_SensorType type, or `SDL_SENSOR_INVALID` if `sensor` is
|
||||
* NULL.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_SensorType SDLCALL SDL_GetSensorType(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Get the platform dependent type of a sensor.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object to inspect.
|
||||
* \returns the sensor platform dependent type, or -1 if `sensor` is NULL.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC int SDLCALL SDL_GetSensorNonPortableType(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Get the instance ID of a sensor.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object to inspect.
|
||||
* \returns the sensor instance ID, or 0 on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_SensorID SDLCALL SDL_GetSensorID(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Get the current state of an opened sensor.
|
||||
*
|
||||
* The number of values and interpretation of the data is sensor dependent.
|
||||
*
|
||||
* \param sensor the SDL_Sensor object to query.
|
||||
* \param data a pointer filled with the current sensor state.
|
||||
* \param num_values the number of values to write to data.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_GetSensorData(SDL_Sensor *sensor, float *data, int num_values);
|
||||
|
||||
/**
|
||||
* Close a sensor previously opened with SDL_OpenSensor().
|
||||
*
|
||||
* \param sensor the SDL_Sensor object to close.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_CloseSensor(SDL_Sensor *sensor);
|
||||
|
||||
/**
|
||||
* Update the current state of the open sensors.
|
||||
*
|
||||
* This is called automatically by the event loop if sensor events are
|
||||
* enabled.
|
||||
*
|
||||
* This needs to be called from the thread that initialized the sensor
|
||||
* subsystem.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_UpdateSensors(void);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
/* *INDENT-OFF* */
|
||||
}
|
||||
/* *INDENT-ON* */
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_sensor_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,602 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_thread_h_
|
||||
#define SDL_thread_h_
|
||||
|
||||
/**
|
||||
* # CategoryThread
|
||||
*
|
||||
* SDL offers cross-platform thread management functions. These are mostly
|
||||
* concerned with starting threads, setting their priority, and dealing with
|
||||
* their termination.
|
||||
*
|
||||
* In addition, there is support for Thread Local Storage (data that is unique
|
||||
* to each thread, but accessed from a single key).
|
||||
*
|
||||
* On platforms without thread support (such as Emscripten when built without
|
||||
* pthreads), these functions still exist, but things like SDL_CreateThread()
|
||||
* will report failure without doing anything.
|
||||
*
|
||||
* If you're going to work with threads, you almost certainly need to have a
|
||||
* good understanding of thread safety measures: locking and synchronization
|
||||
* mechanisms are handled by the functions in SDL_mutex.h.
|
||||
*/
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_properties.h>
|
||||
|
||||
/* Thread synchronization primitives */
|
||||
#include <SDL3/SDL_atomic.h>
|
||||
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
#include <process.h> /* _beginthreadex() and _endthreadex() */
|
||||
#endif
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* The SDL thread object.
|
||||
*
|
||||
* These are opaque data.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateThread
|
||||
* \sa SDL_WaitThread
|
||||
*/
|
||||
typedef struct SDL_Thread SDL_Thread;
|
||||
|
||||
/**
|
||||
* A unique numeric ID that identifies a thread.
|
||||
*
|
||||
* These are different from SDL_Thread objects, which are generally what an
|
||||
* application will operate on, but having a way to uniquely identify a thread
|
||||
* can be useful at times.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetThreadID
|
||||
* \sa SDL_GetCurrentThreadID
|
||||
*/
|
||||
typedef Uint64 SDL_ThreadID;
|
||||
|
||||
/**
|
||||
* Thread local storage ID.
|
||||
*
|
||||
* 0 is the invalid ID. An app can create these and then set data for these
|
||||
* IDs that is unique to each thread.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetTLS
|
||||
* \sa SDL_SetTLS
|
||||
*/
|
||||
typedef SDL_AtomicInt SDL_TLSID;
|
||||
|
||||
/**
|
||||
* The SDL thread priority.
|
||||
*
|
||||
* SDL will make system changes as necessary in order to apply the thread
|
||||
* priority. Code which attempts to control thread state related to priority
|
||||
* should be aware that calling SDL_SetCurrentThreadPriority may alter such
|
||||
* state. SDL_HINT_THREAD_PRIORITY_POLICY can be used to control aspects of
|
||||
* this behavior.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_ThreadPriority {
|
||||
SDL_THREAD_PRIORITY_LOW,
|
||||
SDL_THREAD_PRIORITY_NORMAL,
|
||||
SDL_THREAD_PRIORITY_HIGH,
|
||||
SDL_THREAD_PRIORITY_TIME_CRITICAL
|
||||
} SDL_ThreadPriority;
|
||||
|
||||
/**
|
||||
* The SDL thread state.
|
||||
*
|
||||
* The current state of a thread can be checked by calling SDL_GetThreadState.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetThreadState
|
||||
*/
|
||||
typedef enum SDL_ThreadState
|
||||
{
|
||||
SDL_THREAD_UNKNOWN, /**< The thread is not valid */
|
||||
SDL_THREAD_ALIVE, /**< The thread is currently running */
|
||||
SDL_THREAD_DETACHED, /**< The thread is detached and can't be waited on */
|
||||
SDL_THREAD_COMPLETE /**< The thread has finished and should be cleaned up with SDL_WaitThread() */
|
||||
} SDL_ThreadState;
|
||||
|
||||
/**
|
||||
* The function passed to SDL_CreateThread() as the new thread's entry point.
|
||||
*
|
||||
* \param data what was passed as `data` to SDL_CreateThread().
|
||||
* \returns a value that can be reported through SDL_WaitThread().
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef int (SDLCALL *SDL_ThreadFunction) (void *data);
|
||||
|
||||
|
||||
#ifdef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
|
||||
/*
|
||||
* Note that these aren't the correct function signatures in this block, but
|
||||
* this is what the API reference manual should look like for all intents and
|
||||
* purposes.
|
||||
*
|
||||
* Technical details, not for the wiki (hello, header readers!)...
|
||||
*
|
||||
* On Windows (and maybe other platforms), a program might use a different
|
||||
* C runtime than its libraries. Or, in SDL's case, it might use a C runtime
|
||||
* while SDL uses none at all.
|
||||
*
|
||||
* C runtimes expect to initialize thread-specific details when a new thread
|
||||
* is created, but to do this in SDL_CreateThread would require SDL to know
|
||||
* intimate details about the caller's C runtime, which is not possible.
|
||||
*
|
||||
* So SDL_CreateThread has two extra parameters, which are
|
||||
* hidden at compile time by macros: the C runtime's `_beginthreadex` and
|
||||
* `_endthreadex` entry points. If these are not NULL, they are used to spin
|
||||
* and terminate the new thread; otherwise the standard Win32 `CreateThread`
|
||||
* function is used. When `SDL_CreateThread` is called from a compiler that
|
||||
* needs this C runtime thread init function, macros insert the appropriate
|
||||
* function pointers for SDL_CreateThread's caller (which might be a different
|
||||
* compiler with a different runtime in different calls to SDL_CreateThread!).
|
||||
*
|
||||
* SDL_BeginThreadFunction defaults to `_beginthreadex` on Windows (and NULL
|
||||
* everywhere else), but apps that have extremely specific special needs can
|
||||
* define this to something else and the SDL headers will use it, passing the
|
||||
* app-defined value to SDL_CreateThread calls. Redefine this with caution!
|
||||
*
|
||||
* Platforms that don't need _beginthread stuff (most everything) will fail
|
||||
* SDL_CreateThread with an error if these pointers _aren't_ NULL.
|
||||
*
|
||||
* Unless you are doing something extremely complicated, like perhaps a
|
||||
* language binding, **you should never deal with this directly**. Let SDL's
|
||||
* macros handle this platform-specific detail transparently!
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a new thread with a default stack size.
|
||||
*
|
||||
* This is a convenience function, equivalent to calling
|
||||
* SDL_CreateThreadWithProperties with the following properties set:
|
||||
*
|
||||
* - `SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER`: `fn`
|
||||
* - `SDL_PROP_THREAD_CREATE_NAME_STRING`: `name`
|
||||
* - `SDL_PROP_THREAD_CREATE_USERDATA_POINTER`: `data`
|
||||
*
|
||||
* Note that this "function" is actually a macro that calls an internal
|
||||
* function with two extra parameters not listed here; they are hidden through
|
||||
* preprocessor macros and are needed to support various C runtimes at the
|
||||
* point of the function call. Language bindings that aren't using the C
|
||||
* headers will need to deal with this.
|
||||
*
|
||||
* Usually, apps should just call this function the same way on every platform
|
||||
* and let the macros hide the details.
|
||||
*
|
||||
* \param fn the SDL_ThreadFunction function to call in the new thread.
|
||||
* \param name the name of the thread.
|
||||
* \param data a pointer that is passed to `fn`.
|
||||
* \returns an opaque pointer to the new thread object on success, NULL if the
|
||||
* new thread could not be created; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateThreadWithProperties
|
||||
* \sa SDL_WaitThread
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data);
|
||||
|
||||
/**
|
||||
* Create a new thread with with the specified properties.
|
||||
*
|
||||
* These are the supported properties:
|
||||
*
|
||||
* - `SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER`: an SDL_ThreadFunction
|
||||
* value that will be called at the start of the new thread's life.
|
||||
* Required.
|
||||
* - `SDL_PROP_THREAD_CREATE_NAME_STRING`: the name of the new thread, which
|
||||
* might be available to debuggers. Optional, defaults to NULL.
|
||||
* - `SDL_PROP_THREAD_CREATE_USERDATA_POINTER`: an arbitrary app-defined
|
||||
* pointer, which is passed to the entry function on the new thread, as its
|
||||
* only parameter. Optional, defaults to NULL.
|
||||
* - `SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER`: the size, in bytes, of the new
|
||||
* thread's stack. Optional, defaults to 0 (system-defined default).
|
||||
*
|
||||
* SDL makes an attempt to report `SDL_PROP_THREAD_CREATE_NAME_STRING` to the
|
||||
* system, so that debuggers can display it. Not all platforms support this.
|
||||
*
|
||||
* Thread naming is a little complicated: Most systems have very small limits
|
||||
* for the string length (Haiku has 32 bytes, Linux currently has 16, Visual
|
||||
* C++ 6.0 has _nine_!), and possibly other arbitrary rules. You'll have to
|
||||
* see what happens with your system's debugger. The name should be UTF-8 (but
|
||||
* using the naming limits of C identifiers is a better bet). There are no
|
||||
* requirements for thread naming conventions, so long as the string is
|
||||
* null-terminated UTF-8, but these guidelines are helpful in choosing a name:
|
||||
*
|
||||
* https://stackoverflow.com/questions/149932/naming-conventions-for-threads
|
||||
*
|
||||
* If a system imposes requirements, SDL will try to munge the string for it
|
||||
* (truncate, etc), but the original string contents will be available from
|
||||
* SDL_GetThreadName().
|
||||
*
|
||||
* The size (in bytes) of the new stack can be specified with
|
||||
* `SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER`. Zero means "use the system
|
||||
* default" which might be wildly different between platforms. x86 Linux
|
||||
* generally defaults to eight megabytes, an embedded device might be a few
|
||||
* kilobytes instead. You generally need to specify a stack that is a multiple
|
||||
* of the system's page size (in many cases, this is 4 kilobytes, but check
|
||||
* your system documentation).
|
||||
*
|
||||
* Note that this "function" is actually a macro that calls an internal
|
||||
* function with two extra parameters not listed here; they are hidden through
|
||||
* preprocessor macros and are needed to support various C runtimes at the
|
||||
* point of the function call. Language bindings that aren't using the C
|
||||
* headers will need to deal with this.
|
||||
*
|
||||
* The actual symbol in SDL is `SDL_CreateThreadWithPropertiesRuntime`, so
|
||||
* there is no symbol clash, but trying to load an SDL shared library and look
|
||||
* for "SDL_CreateThreadWithProperties" will fail.
|
||||
*
|
||||
* Usually, apps should just call this function the same way on every platform
|
||||
* and let the macros hide the details.
|
||||
*
|
||||
* \param props the properties to use.
|
||||
* \returns an opaque pointer to the new thread object on success, NULL if the
|
||||
* new thread could not be created; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateThread
|
||||
* \sa SDL_WaitThread
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithProperties(SDL_PropertiesID props);
|
||||
|
||||
#define SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER "SDL.thread.create.entry_function"
|
||||
#define SDL_PROP_THREAD_CREATE_NAME_STRING "SDL.thread.create.name"
|
||||
#define SDL_PROP_THREAD_CREATE_USERDATA_POINTER "SDL.thread.create.userdata"
|
||||
#define SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER "SDL.thread.create.stacksize"
|
||||
|
||||
/* end wiki documentation for macros that are meant to look like functions. */
|
||||
#endif
|
||||
|
||||
|
||||
/* The real implementation, hidden from the wiki, so it can show this as real functions that don't have macro magic. */
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
# if defined(SDL_PLATFORM_WINDOWS)
|
||||
# ifndef SDL_BeginThreadFunction
|
||||
# define SDL_BeginThreadFunction _beginthreadex
|
||||
# endif
|
||||
# ifndef SDL_EndThreadFunction
|
||||
# define SDL_EndThreadFunction _endthreadex
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* currently no other platforms than Windows use _beginthreadex/_endthreadex things. */
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
# ifndef SDL_BeginThreadFunction
|
||||
# define SDL_BeginThreadFunction NULL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
# ifndef SDL_EndThreadFunction
|
||||
# define SDL_EndThreadFunction NULL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef SDL_WIKI_DOCUMENTATION_SECTION
|
||||
/* These are the actual functions exported from SDL! Don't use them directly! Use the SDL_CreateThread and SDL_CreateThreadWithProperties macros! */
|
||||
/**
|
||||
* The actual entry point for SDL_CreateThread.
|
||||
*
|
||||
* \param fn the SDL_ThreadFunction function to call in the new thread
|
||||
* \param name the name of the thread
|
||||
* \param data a pointer that is passed to `fn`
|
||||
* \param pfnBeginThread the C runtime's _beginthreadex (or whatnot). Can be NULL.
|
||||
* \param pfnEndThread the C runtime's _endthreadex (or whatnot). Can be NULL.
|
||||
* \returns an opaque pointer to the new thread object on success, NULL if the
|
||||
* new thread could not be created; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadRuntime(SDL_ThreadFunction fn, const char *name, void *data, SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread);
|
||||
|
||||
/**
|
||||
* The actual entry point for SDL_CreateThreadWithProperties.
|
||||
*
|
||||
* \param props the properties to use
|
||||
* \param pfnBeginThread the C runtime's _beginthreadex (or whatnot). Can be NULL.
|
||||
* \param pfnEndThread the C runtime's _endthreadex (or whatnot). Can be NULL.
|
||||
* \returns an opaque pointer to the new thread object on success, NULL if the
|
||||
* new thread could not be created; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Thread * SDLCALL SDL_CreateThreadWithPropertiesRuntime(SDL_PropertiesID props, SDL_FunctionPointer pfnBeginThread, SDL_FunctionPointer pfnEndThread);
|
||||
|
||||
#define SDL_CreateThread(fn, name, data) SDL_CreateThreadRuntime((fn), (name), (data), (SDL_FunctionPointer) (SDL_BeginThreadFunction), (SDL_FunctionPointer) (SDL_EndThreadFunction))
|
||||
#define SDL_CreateThreadWithProperties(props) SDL_CreateThreadWithPropertiesRuntime((props), (SDL_FunctionPointer) (SDL_BeginThreadFunction), (SDL_FunctionPointer) (SDL_EndThreadFunction))
|
||||
#define SDL_PROP_THREAD_CREATE_ENTRY_FUNCTION_POINTER "SDL.thread.create.entry_function"
|
||||
#define SDL_PROP_THREAD_CREATE_NAME_STRING "SDL.thread.create.name"
|
||||
#define SDL_PROP_THREAD_CREATE_USERDATA_POINTER "SDL.thread.create.userdata"
|
||||
#define SDL_PROP_THREAD_CREATE_STACKSIZE_NUMBER "SDL.thread.create.stacksize"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Get the thread name as it was specified in SDL_CreateThread().
|
||||
*
|
||||
* \param thread the thread to query.
|
||||
* \returns a pointer to a UTF-8 string that names the specified thread, or
|
||||
* NULL if it doesn't have a name.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetThreadName(SDL_Thread *thread);
|
||||
|
||||
/**
|
||||
* Get the thread identifier for the current thread.
|
||||
*
|
||||
* This thread identifier is as reported by the underlying operating system.
|
||||
* If SDL is running on a platform that does not support threads the return
|
||||
* value will always be zero.
|
||||
*
|
||||
* This function also returns a valid thread ID when called from the main
|
||||
* thread.
|
||||
*
|
||||
* \returns the ID of the current thread.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetThreadID
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_ThreadID SDLCALL SDL_GetCurrentThreadID(void);
|
||||
|
||||
/**
|
||||
* Get the thread identifier for the specified thread.
|
||||
*
|
||||
* This thread identifier is as reported by the underlying operating system.
|
||||
* If SDL is running on a platform that does not support threads the return
|
||||
* value will always be zero.
|
||||
*
|
||||
* \param thread the thread to query.
|
||||
* \returns the ID of the specified thread, or the ID of the current thread if
|
||||
* `thread` is NULL.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetCurrentThreadID
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_ThreadID SDLCALL SDL_GetThreadID(SDL_Thread *thread);
|
||||
|
||||
/**
|
||||
* Set the priority for the current thread.
|
||||
*
|
||||
* Note that some platforms will not let you alter the priority (or at least,
|
||||
* promote the thread to a higher priority) at all, and some require you to be
|
||||
* an administrator account. Be prepared for this to fail.
|
||||
*
|
||||
* \param priority the SDL_ThreadPriority to set.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetCurrentThreadPriority(SDL_ThreadPriority priority);
|
||||
|
||||
/**
|
||||
* Wait for a thread to finish.
|
||||
*
|
||||
* Threads that haven't been detached will remain until this function cleans
|
||||
* them up. Not doing so is a resource leak.
|
||||
*
|
||||
* Once a thread has been cleaned up through this function, the SDL_Thread
|
||||
* that references it becomes invalid and should not be referenced again. As
|
||||
* such, only one thread may call SDL_WaitThread() on another.
|
||||
*
|
||||
* The return code from the thread function is placed in the area pointed to
|
||||
* by `status`, if `status` is not NULL.
|
||||
*
|
||||
* You may not wait on a thread that has been used in a call to
|
||||
* SDL_DetachThread(). Use either that function or this one, but not both, or
|
||||
* behavior is undefined.
|
||||
*
|
||||
* It is safe to pass a NULL thread to this function; it is a no-op.
|
||||
*
|
||||
* Note that the thread pointer is freed by this function and is not valid
|
||||
* afterward.
|
||||
*
|
||||
* \param thread the SDL_Thread pointer that was returned from the
|
||||
* SDL_CreateThread() call that started this thread.
|
||||
* \param status a pointer filled in with the value returned from the thread
|
||||
* function by its 'return', or -1 if the thread has been
|
||||
* detached or isn't valid, may be NULL.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread, but only a
|
||||
* single thread can wait any specific thread to finish.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateThread
|
||||
* \sa SDL_DetachThread
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_WaitThread(SDL_Thread *thread, int *status);
|
||||
|
||||
/**
|
||||
* Get the current state of a thread.
|
||||
*
|
||||
* \param thread the thread to query.
|
||||
* \returns the current state of a thread, or SDL_THREAD_UNKNOWN if the thread
|
||||
* isn't valid.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_ThreadState
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_ThreadState SDLCALL SDL_GetThreadState(SDL_Thread *thread);
|
||||
|
||||
/**
|
||||
* Let a thread clean up on exit without intervention.
|
||||
*
|
||||
* A thread may be "detached" to signify that it should not remain until
|
||||
* another thread has called SDL_WaitThread() on it. Detaching a thread is
|
||||
* useful for long-running threads that nothing needs to synchronize with or
|
||||
* further manage. When a detached thread is done, it simply goes away.
|
||||
*
|
||||
* There is no way to recover the return code of a detached thread. If you
|
||||
* need this, don't detach the thread and instead use SDL_WaitThread().
|
||||
*
|
||||
* Once a thread is detached, you should usually assume the SDL_Thread isn't
|
||||
* safe to reference again, as it will become invalid immediately upon the
|
||||
* detached thread's exit, instead of remaining until someone has called
|
||||
* SDL_WaitThread() to finally clean it up. As such, don't detach the same
|
||||
* thread more than once.
|
||||
*
|
||||
* If a thread has already exited when passed to SDL_DetachThread(), it will
|
||||
* stop waiting for a call to SDL_WaitThread() and clean up immediately. It is
|
||||
* not safe to detach a thread that might be used with SDL_WaitThread().
|
||||
*
|
||||
* You may not call SDL_WaitThread() on a thread that has been detached. Use
|
||||
* either that function or this one, but not both, or behavior is undefined.
|
||||
*
|
||||
* It is safe to pass NULL to this function; it is a no-op.
|
||||
*
|
||||
* \param thread the SDL_Thread pointer that was returned from the
|
||||
* SDL_CreateThread() call that started this thread.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_CreateThread
|
||||
* \sa SDL_WaitThread
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DetachThread(SDL_Thread *thread);
|
||||
|
||||
/**
|
||||
* Get the current thread's value associated with a thread local storage ID.
|
||||
*
|
||||
* \param id a pointer to the thread local storage ID, may not be NULL.
|
||||
* \returns the value associated with the ID for the current thread or NULL if
|
||||
* no value has been set; call SDL_GetError() for more information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetTLS
|
||||
*/
|
||||
extern SDL_DECLSPEC void * SDLCALL SDL_GetTLS(SDL_TLSID *id);
|
||||
|
||||
/**
|
||||
* The callback used to cleanup data passed to SDL_SetTLS.
|
||||
*
|
||||
* This is called when a thread exits, to allow an app to free any resources.
|
||||
*
|
||||
* \param value a pointer previously handed to SDL_SetTLS.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_SetTLS
|
||||
*/
|
||||
typedef void (SDLCALL *SDL_TLSDestructorCallback)(void *value);
|
||||
|
||||
/**
|
||||
* Set the current thread's value associated with a thread local storage ID.
|
||||
*
|
||||
* If the thread local storage ID is not initialized (the value is 0), a new
|
||||
* ID will be created in a thread-safe way, so all calls using a pointer to
|
||||
* the same ID will refer to the same local storage.
|
||||
*
|
||||
* Note that replacing a value from a previous call to this function on the
|
||||
* same thread does _not_ call the previous value's destructor!
|
||||
*
|
||||
* `destructor` can be NULL; it is assumed that `value` does not need to be
|
||||
* cleaned up if so.
|
||||
*
|
||||
* \param id a pointer to the thread local storage ID, may not be NULL.
|
||||
* \param value the value to associate with the ID for the current thread.
|
||||
* \param destructor a function called when the thread exits, to free the
|
||||
* value, may be NULL.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetTLS
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_SetTLS(SDL_TLSID *id, const void *value, SDL_TLSDestructorCallback destructor);
|
||||
|
||||
/**
|
||||
* Cleanup all TLS data for this thread.
|
||||
*
|
||||
* If you are creating your threads outside of SDL and then calling SDL
|
||||
* functions, you should call this function before your thread exits, to
|
||||
* properly clean up SDL memory.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_CleanupTLS(void);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_thread_h_ */
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#ifndef SDL_timer_h_
|
||||
#define SDL_timer_h_
|
||||
|
||||
/**
|
||||
* # CategoryTimer
|
||||
*
|
||||
* SDL provides time management functionality. It is useful for dealing with
|
||||
* (usually) small durations of time.
|
||||
*
|
||||
* This is not to be confused with _calendar time_ management, which is
|
||||
* provided by [CategoryTime](CategoryTime).
|
||||
*
|
||||
* This category covers measuring time elapsed (SDL_GetTicks(),
|
||||
* SDL_GetPerformanceCounter()), putting a thread to sleep for a certain
|
||||
* amount of time (SDL_Delay(), SDL_DelayNS(), SDL_DelayPrecise()), and firing
|
||||
* a callback function after a certain amount of time has elapsed
|
||||
* (SDL_AddTimer(), etc).
|
||||
*
|
||||
* There are also useful macros to convert between time units, like
|
||||
* SDL_SECONDS_TO_NS() and such.
|
||||
*/
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* SDL time constants */
|
||||
|
||||
/**
|
||||
* Number of milliseconds in a second.
|
||||
*
|
||||
* This is always 1000.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MS_PER_SECOND 1000
|
||||
|
||||
/**
|
||||
* Number of microseconds in a second.
|
||||
*
|
||||
* This is always 1000000.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_US_PER_SECOND 1000000
|
||||
|
||||
/**
|
||||
* Number of nanoseconds in a second.
|
||||
*
|
||||
* This is always 1000000000.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_PER_SECOND 1000000000LL
|
||||
|
||||
/**
|
||||
* Number of nanoseconds in a millisecond.
|
||||
*
|
||||
* This is always 1000000.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_PER_MS 1000000
|
||||
|
||||
/**
|
||||
* Number of nanoseconds in a microsecond.
|
||||
*
|
||||
* This is always 1000.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_PER_US 1000
|
||||
|
||||
/**
|
||||
* Convert seconds to nanoseconds.
|
||||
*
|
||||
* This only converts whole numbers, not fractional seconds.
|
||||
*
|
||||
* \param S the number of seconds to convert.
|
||||
* \returns S, expressed in nanoseconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_SECONDS_TO_NS(S) (((Uint64)(S)) * SDL_NS_PER_SECOND)
|
||||
|
||||
/**
|
||||
* Convert nanoseconds to seconds.
|
||||
*
|
||||
* This performs a division, so the results can be dramatically different if
|
||||
* `NS` is an integer or floating point value.
|
||||
*
|
||||
* \param NS the number of nanoseconds to convert.
|
||||
* \returns NS, expressed in seconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_TO_SECONDS(NS) ((NS) / SDL_NS_PER_SECOND)
|
||||
|
||||
/**
|
||||
* Convert milliseconds to nanoseconds.
|
||||
*
|
||||
* This only converts whole numbers, not fractional milliseconds.
|
||||
*
|
||||
* \param MS the number of milliseconds to convert.
|
||||
* \returns MS, expressed in nanoseconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MS_TO_NS(MS) (((Uint64)(MS)) * SDL_NS_PER_MS)
|
||||
|
||||
/**
|
||||
* Convert nanoseconds to milliseconds.
|
||||
*
|
||||
* This performs a division, so the results can be dramatically different if
|
||||
* `NS` is an integer or floating point value.
|
||||
*
|
||||
* \param NS the number of nanoseconds to convert.
|
||||
* \returns NS, expressed in milliseconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_TO_MS(NS) ((NS) / SDL_NS_PER_MS)
|
||||
|
||||
/**
|
||||
* Convert microseconds to nanoseconds.
|
||||
*
|
||||
* This only converts whole numbers, not fractional microseconds.
|
||||
*
|
||||
* \param US the number of microseconds to convert.
|
||||
* \returns US, expressed in nanoseconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_US_TO_NS(US) (((Uint64)(US)) * SDL_NS_PER_US)
|
||||
|
||||
/**
|
||||
* Convert nanoseconds to microseconds.
|
||||
*
|
||||
* This performs a division, so the results can be dramatically different if
|
||||
* `NS` is an integer or floating point value.
|
||||
*
|
||||
* \param NS the number of nanoseconds to convert.
|
||||
* \returns NS, expressed in microseconds.
|
||||
*
|
||||
* \threadsafety It is safe to call this macro from any thread.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_NS_TO_US(NS) ((NS) / SDL_NS_PER_US)
|
||||
|
||||
/**
|
||||
* Get the number of milliseconds that have elapsed since the SDL library
|
||||
* initialization.
|
||||
*
|
||||
* \returns an unsigned 64‑bit integer that represents the number of
|
||||
* milliseconds that have elapsed since the SDL library was
|
||||
* initialized (typically via a call to SDL_Init).
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetTicksNS
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetTicks(void);
|
||||
|
||||
/**
|
||||
* Get the number of nanoseconds since SDL library initialization.
|
||||
*
|
||||
* \returns an unsigned 64-bit value representing the number of nanoseconds
|
||||
* since the SDL library initialized.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetTicksNS(void);
|
||||
|
||||
/**
|
||||
* Get the current value of the high resolution counter.
|
||||
*
|
||||
* This function is typically used for profiling.
|
||||
*
|
||||
* The counter values are only meaningful relative to each other. Differences
|
||||
* between values can be converted to times by using
|
||||
* SDL_GetPerformanceFrequency().
|
||||
*
|
||||
* \returns the current counter value.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPerformanceFrequency
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetPerformanceCounter(void);
|
||||
|
||||
/**
|
||||
* Get the count per second of the high resolution counter.
|
||||
*
|
||||
* \returns a platform-specific count per second.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetPerformanceCounter
|
||||
*/
|
||||
extern SDL_DECLSPEC Uint64 SDLCALL SDL_GetPerformanceFrequency(void);
|
||||
|
||||
/**
|
||||
* Wait a specified number of milliseconds before returning.
|
||||
*
|
||||
* This function waits a specified number of milliseconds before returning. It
|
||||
* waits at least the specified time, but possibly longer due to OS
|
||||
* scheduling.
|
||||
*
|
||||
* \param ms the number of milliseconds to delay.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_DelayNS
|
||||
* \sa SDL_DelayPrecise
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_Delay(Uint32 ms);
|
||||
|
||||
/**
|
||||
* Wait a specified number of nanoseconds before returning.
|
||||
*
|
||||
* This function waits a specified number of nanoseconds before returning. It
|
||||
* waits at least the specified time, but possibly longer due to OS
|
||||
* scheduling.
|
||||
*
|
||||
* \param ns the number of nanoseconds to delay.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Delay
|
||||
* \sa SDL_DelayPrecise
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DelayNS(Uint64 ns);
|
||||
|
||||
/**
|
||||
* Wait a specified number of nanoseconds before returning.
|
||||
*
|
||||
* This function waits a specified number of nanoseconds before returning. It
|
||||
* will attempt to wait as close to the requested time as possible, busy
|
||||
* waiting if necessary, but could return later due to OS scheduling.
|
||||
*
|
||||
* \param ns the number of nanoseconds to delay.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_Delay
|
||||
* \sa SDL_DelayNS
|
||||
*/
|
||||
extern SDL_DECLSPEC void SDLCALL SDL_DelayPrecise(Uint64 ns);
|
||||
|
||||
/**
|
||||
* Definition of the timer ID type.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint32 SDL_TimerID;
|
||||
|
||||
/**
|
||||
* Function prototype for the millisecond timer callback function.
|
||||
*
|
||||
* The callback function is passed the current timer interval and returns the
|
||||
* next timer interval, in milliseconds. If the returned value is the same as
|
||||
* the one passed in, the periodic alarm continues, otherwise a new alarm is
|
||||
* scheduled. If the callback returns 0, the periodic alarm is canceled and
|
||||
* will be removed.
|
||||
*
|
||||
* \param userdata an arbitrary pointer provided by the app through
|
||||
* SDL_AddTimer, for its own use.
|
||||
* \param timerID the current timer being processed.
|
||||
* \param interval the current callback time interval.
|
||||
* \returns the new callback time interval, or 0 to disable further runs of
|
||||
* the callback.
|
||||
*
|
||||
* \threadsafety SDL may call this callback at any time from a background
|
||||
* thread; the application is responsible for locking resources
|
||||
* the callback touches that need to be protected.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddTimer
|
||||
*/
|
||||
typedef Uint32 (SDLCALL *SDL_TimerCallback)(void *userdata, SDL_TimerID timerID, Uint32 interval);
|
||||
|
||||
/**
|
||||
* Call a callback function at a future time.
|
||||
*
|
||||
* The callback function is passed the current timer interval and the user
|
||||
* supplied parameter from the SDL_AddTimer() call and should return the next
|
||||
* timer interval. If the value returned from the callback is 0, the timer is
|
||||
* canceled and will be removed.
|
||||
*
|
||||
* The callback is run on a separate thread, and for short timeouts can
|
||||
* potentially be called before this function returns.
|
||||
*
|
||||
* Timers take into account the amount of time it took to execute the
|
||||
* callback. For example, if the callback took 250 ms to execute and returned
|
||||
* 1000 (ms), the timer would only wait another 750 ms before its next
|
||||
* iteration.
|
||||
*
|
||||
* Timing may be inexact due to OS scheduling. Be sure to note the current
|
||||
* time with SDL_GetTicksNS() or SDL_GetPerformanceCounter() in case your
|
||||
* callback needs to adjust for variances.
|
||||
*
|
||||
* \param interval the timer delay, in milliseconds, passed to `callback`.
|
||||
* \param callback the SDL_TimerCallback function to call when the specified
|
||||
* `interval` elapses.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns a timer ID or 0 on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddTimerNS
|
||||
* \sa SDL_RemoveTimer
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Function prototype for the nanosecond timer callback function.
|
||||
*
|
||||
* The callback function is passed the current timer interval and returns the
|
||||
* next timer interval, in nanoseconds. If the returned value is the same as
|
||||
* the one passed in, the periodic alarm continues, otherwise a new alarm is
|
||||
* scheduled. If the callback returns 0, the periodic alarm is canceled and
|
||||
* will be removed.
|
||||
*
|
||||
* \param userdata an arbitrary pointer provided by the app through
|
||||
* SDL_AddTimer, for its own use.
|
||||
* \param timerID the current timer being processed.
|
||||
* \param interval the current callback time interval.
|
||||
* \returns the new callback time interval, or 0 to disable further runs of
|
||||
* the callback.
|
||||
*
|
||||
* \threadsafety SDL may call this callback at any time from a background
|
||||
* thread; the application is responsible for locking resources
|
||||
* the callback touches that need to be protected.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddTimerNS
|
||||
*/
|
||||
typedef Uint64 (SDLCALL *SDL_NSTimerCallback)(void *userdata, SDL_TimerID timerID, Uint64 interval);
|
||||
|
||||
/**
|
||||
* Call a callback function at a future time.
|
||||
*
|
||||
* The callback function is passed the current timer interval and the user
|
||||
* supplied parameter from the SDL_AddTimerNS() call and should return the
|
||||
* next timer interval. If the value returned from the callback is 0, the
|
||||
* timer is canceled and will be removed.
|
||||
*
|
||||
* The callback is run on a separate thread, and for short timeouts can
|
||||
* potentially be called before this function returns.
|
||||
*
|
||||
* Timers take into account the amount of time it took to execute the
|
||||
* callback. For example, if the callback took 250 ns to execute and returned
|
||||
* 1000 (ns), the timer would only wait another 750 ns before its next
|
||||
* iteration.
|
||||
*
|
||||
* Timing may be inexact due to OS scheduling. Be sure to note the current
|
||||
* time with SDL_GetTicksNS() or SDL_GetPerformanceCounter() in case your
|
||||
* callback needs to adjust for variances.
|
||||
*
|
||||
* \param interval the timer delay, in nanoseconds, passed to `callback`.
|
||||
* \param callback the SDL_TimerCallback function to call when the specified
|
||||
* `interval` elapses.
|
||||
* \param userdata a pointer that is passed to `callback`.
|
||||
* \returns a timer ID or 0 on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddTimer
|
||||
* \sa SDL_RemoveTimer
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TimerID SDLCALL SDL_AddTimerNS(Uint64 interval, SDL_NSTimerCallback callback, void *userdata);
|
||||
|
||||
/**
|
||||
* Remove a timer created with SDL_AddTimer().
|
||||
*
|
||||
* \param id the ID of the timer to remove.
|
||||
* \returns true on success or false on failure; call SDL_GetError() for more
|
||||
* information.
|
||||
*
|
||||
* \threadsafety It is safe to call this function from any thread.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_AddTimer
|
||||
*/
|
||||
extern SDL_DECLSPEC bool SDLCALL SDL_RemoveTimer(SDL_TimerID id);
|
||||
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_timer_h_ */
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2026 Sam Lantinga <slouken@libsdl.org>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
/**
|
||||
* # CategoryTouch
|
||||
*
|
||||
* SDL offers touch input, on platforms that support it. It can manage
|
||||
* multiple touch devices and track multiple fingers on those devices.
|
||||
*
|
||||
* Touches are mostly dealt with through the event system, in the
|
||||
* SDL_EVENT_FINGER_DOWN, SDL_EVENT_FINGER_MOTION, and SDL_EVENT_FINGER_UP
|
||||
* events, but there are also functions to query for hardware details, etc.
|
||||
*
|
||||
* The touch system, by default, will also send virtual mouse events; this can
|
||||
* be useful for making a some desktop apps work on a phone without
|
||||
* significant changes. For apps that care about mouse and touch input
|
||||
* separately, they should ignore mouse events that have a `which` field of
|
||||
* SDL_TOUCH_MOUSEID.
|
||||
*/
|
||||
|
||||
#ifndef SDL_touch_h_
|
||||
#define SDL_touch_h_
|
||||
|
||||
#include <SDL3/SDL_stdinc.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_mouse.h>
|
||||
|
||||
#include <SDL3/SDL_begin_code.h>
|
||||
/* Set up for C function definitions, even when using C++ */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A unique ID for a touch device.
|
||||
*
|
||||
* This ID is valid for the time the device is connected to the system, and is
|
||||
* never reused for the lifetime of the application.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint64 SDL_TouchID;
|
||||
|
||||
/**
|
||||
* A unique ID for a single finger on a touch device.
|
||||
*
|
||||
* This ID is valid for the time the finger (stylus, etc) is touching and will
|
||||
* be unique for all fingers currently in contact, so this ID tracks the
|
||||
* lifetime of a single continuous touch. This value may represent an index, a
|
||||
* pointer, or some other unique ID, depending on the platform.
|
||||
*
|
||||
* The value 0 is an invalid ID.
|
||||
*
|
||||
* \since This datatype is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef Uint64 SDL_FingerID;
|
||||
|
||||
/**
|
||||
* An enum that describes the type of a touch device.
|
||||
*
|
||||
* \since This enum is available since SDL 3.2.0.
|
||||
*/
|
||||
typedef enum SDL_TouchDeviceType
|
||||
{
|
||||
SDL_TOUCH_DEVICE_INVALID = -1,
|
||||
SDL_TOUCH_DEVICE_DIRECT, /**< touch screen with window-relative coordinates */
|
||||
SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE, /**< trackpad with absolute device coordinates */
|
||||
SDL_TOUCH_DEVICE_INDIRECT_RELATIVE /**< trackpad with screen cursor-relative coordinates */
|
||||
} SDL_TouchDeviceType;
|
||||
|
||||
/**
|
||||
* Data about a single finger in a multitouch event.
|
||||
*
|
||||
* Each touch event is a collection of fingers that are simultaneously in
|
||||
* contact with the touch device (so a "touch" can be a "multitouch," in
|
||||
* reality), and this struct reports details of the specific fingers.
|
||||
*
|
||||
* \since This struct is available since SDL 3.2.0.
|
||||
*
|
||||
* \sa SDL_GetTouchFingers
|
||||
*/
|
||||
typedef struct SDL_Finger
|
||||
{
|
||||
SDL_FingerID id; /**< the finger ID */
|
||||
float x; /**< the x-axis location of the touch event, normalized (0...1) */
|
||||
float y; /**< the y-axis location of the touch event, normalized (0...1) */
|
||||
float pressure; /**< the quantity of pressure applied, normalized (0...1) */
|
||||
} SDL_Finger;
|
||||
|
||||
/**
|
||||
* The SDL_MouseID for mouse events simulated with touch input.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_TOUCH_MOUSEID ((SDL_MouseID)-1)
|
||||
|
||||
/**
|
||||
* The SDL_TouchID for touch events simulated with mouse input.
|
||||
*
|
||||
* \since This macro is available since SDL 3.2.0.
|
||||
*/
|
||||
#define SDL_MOUSE_TOUCHID ((SDL_TouchID)-1)
|
||||
|
||||
|
||||
/**
|
||||
* Get a list of registered touch devices.
|
||||
*
|
||||
* On some platforms SDL first sees the touch device if it was actually used.
|
||||
* Therefore the returned list might be empty, although devices are available.
|
||||
* After using all devices at least once the number will be correct.
|
||||
*
|
||||
* \param count a pointer filled in with the number of devices returned, may
|
||||
* be NULL.
|
||||
* \returns a 0 terminated array of touch device IDs or NULL on failure; call
|
||||
* SDL_GetError() for more information. This should be freed with
|
||||
* SDL_free() when it is no longer needed.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TouchID * SDLCALL SDL_GetTouchDevices(int *count);
|
||||
|
||||
/**
|
||||
* Get the touch device name as reported from the driver.
|
||||
*
|
||||
* \param touchID the touch device instance ID.
|
||||
* \returns touch device name, or NULL on failure; call SDL_GetError() for
|
||||
* more information.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC const char * SDLCALL SDL_GetTouchDeviceName(SDL_TouchID touchID);
|
||||
|
||||
/**
|
||||
* Get the type of the given touch device.
|
||||
*
|
||||
* \param touchID the ID of a touch device.
|
||||
* \returns touch device type.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_TouchDeviceType SDLCALL SDL_GetTouchDeviceType(SDL_TouchID touchID);
|
||||
|
||||
/**
|
||||
* Get a list of active fingers for a given touch device.
|
||||
*
|
||||
* \param touchID the ID of a touch device.
|
||||
* \param count a pointer filled in with the number of fingers returned, can
|
||||
* be NULL.
|
||||
* \returns a NULL terminated array of SDL_Finger pointers or NULL on failure;
|
||||
* call SDL_GetError() for more information. This is a single
|
||||
* allocation that should be freed with SDL_free() when it is no
|
||||
* longer needed.
|
||||
*
|
||||
* \since This function is available since SDL 3.2.0.
|
||||
*/
|
||||
extern SDL_DECLSPEC SDL_Finger ** SDLCALL SDL_GetTouchFingers(SDL_TouchID touchID, int *count);
|
||||
|
||||
/* Ends C function definitions when using C++ */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#include <SDL3/SDL_close_code.h>
|
||||
|
||||
#endif /* SDL_touch_h_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,203 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
https://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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
|
||||
|
||||
https://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.
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: algorithm.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file contains Google extensions to the standard <algorithm> C++
|
||||
// header.
|
||||
|
||||
#ifndef ABSL_ALGORITHM_ALGORITHM_H_
|
||||
#define ABSL_ALGORITHM_ALGORITHM_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// equal()
|
||||
// rotate()
|
||||
//
|
||||
// Historical note: Abseil once provided implementations of these algorithms
|
||||
// prior to their adoption in C++14. New code should prefer to use the std
|
||||
// variants.
|
||||
//
|
||||
// See the documentation for the STL <algorithm> header for more information:
|
||||
// https://en.cppreference.com/w/cpp/header/algorithm
|
||||
using std::equal;
|
||||
using std::rotate;
|
||||
|
||||
// linear_search()
|
||||
//
|
||||
// Performs a linear search for `value` using the iterator `first` up to
|
||||
// but not including `last`, returning true if [`first`, `last`) contains an
|
||||
// element equal to `value`.
|
||||
//
|
||||
// A linear search is of O(n) complexity which is guaranteed to make at most
|
||||
// n = (`last` - `first`) comparisons. A linear search over short containers
|
||||
// may be faster than a binary search, even when the container is sorted.
|
||||
template <typename InputIterator, typename EqualityComparable>
|
||||
bool linear_search(InputIterator first, InputIterator last,
|
||||
const EqualityComparable& value) {
|
||||
return std::find(first, last, value) != last;
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_ALGORITHM_ALGORITHM_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,958 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// This header file defines macros for declaring attributes for functions,
|
||||
// types, and variables.
|
||||
//
|
||||
// These macros are used within Abseil and allow the compiler to optimize, where
|
||||
// applicable, certain function calls.
|
||||
//
|
||||
// Most macros here are exposing GCC or Clang features, and are stubbed out for
|
||||
// other compilers.
|
||||
//
|
||||
// GCC attributes documentation:
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Variable-Attributes.html
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html
|
||||
//
|
||||
// Most attributes in this file are already supported by GCC 4.7. However, some
|
||||
// of them are not supported in older version of Clang. Thus, we check
|
||||
// `__has_attribute()` first. If the check fails, we check if we are on GCC and
|
||||
// assume the attribute exists on GCC (which is verified on GCC 4.7).
|
||||
|
||||
#ifndef ABSL_BASE_ATTRIBUTES_H_
|
||||
#define ABSL_BASE_ATTRIBUTES_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// ABSL_HAVE_ATTRIBUTE
|
||||
//
|
||||
// A function-like feature checking macro that is a wrapper around
|
||||
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
|
||||
// nonzero constant integer if the attribute is supported or 0 if not.
|
||||
//
|
||||
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
|
||||
//
|
||||
// GCC: https://gcc.gnu.org/gcc-5/changes.html
|
||||
// Clang: https://clang.llvm.org/docs/LanguageExtensions.html
|
||||
#ifdef __has_attribute
|
||||
#define ABSL_HAVE_ATTRIBUTE(x) __has_attribute(x)
|
||||
#else
|
||||
#define ABSL_HAVE_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_CPP_ATTRIBUTE
|
||||
//
|
||||
// A function-like feature checking macro that accepts C++11 style attributes.
|
||||
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
|
||||
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
|
||||
// find `__has_cpp_attribute`, will evaluate to 0.
|
||||
#if defined(__cplusplus) && defined(__has_cpp_attribute)
|
||||
// NOTE: requiring __cplusplus above should not be necessary, but
|
||||
// works around https://bugs.llvm.org/show_bug.cgi?id=23435.
|
||||
#define ABSL_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
|
||||
#else
|
||||
#define ABSL_HAVE_CPP_ATTRIBUTE(x) 0
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Function Attributes
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// GCC: https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
// Clang: https://clang.llvm.org/docs/AttributeReference.html
|
||||
|
||||
// ABSL_PRINTF_ATTRIBUTE
|
||||
// ABSL_SCANF_ATTRIBUTE
|
||||
//
|
||||
// Tells the compiler to perform `printf` format string checking if the
|
||||
// compiler supports it; see the 'format' attribute in
|
||||
// <https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Function-Attributes.html>.
|
||||
//
|
||||
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
||||
// have an implicit 'this' argument, the arguments of such methods
|
||||
// should be counted from two, not one."
|
||||
#if ABSL_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check) \
|
||||
__attribute__((__format__(__printf__, string_index, first_to_check)))
|
||||
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check) \
|
||||
__attribute__((__format__(__scanf__, string_index, first_to_check)))
|
||||
#else
|
||||
#define ABSL_PRINTF_ATTRIBUTE(string_index, first_to_check)
|
||||
#define ABSL_SCANF_ATTRIBUTE(string_index, first_to_check)
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_ALWAYS_INLINE
|
||||
// ABSL_ATTRIBUTE_NOINLINE
|
||||
//
|
||||
// Forces functions to either inline or not inline. Introduced in gcc 3.1.
|
||||
#if ABSL_HAVE_ATTRIBUTE(always_inline) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
|
||||
#define ABSL_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_ALWAYS_INLINE
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_NOINLINE __attribute__((noinline))
|
||||
#define ABSL_HAVE_ATTRIBUTE_NOINLINE 1
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NOINLINE
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_TAIL_CALL
|
||||
//
|
||||
// Prevents the compiler from optimizing away stack frames for functions which
|
||||
// end in a call to another function.
|
||||
#if ABSL_HAVE_ATTRIBUTE(disable_tail_calls)
|
||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
|
||||
#elif defined(__GNUC__) && !defined(__clang__) && !defined(__e2k__)
|
||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
|
||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL \
|
||||
__attribute__((optimize("no-optimize-sibling-calls")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_TAIL_CALL
|
||||
#define ABSL_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_WEAK
|
||||
//
|
||||
// Tags a function as weak for the purposes of compilation and linking.
|
||||
// Weak attributes did not work properly in LLVM's Windows backend before
|
||||
// 9.0.0, so disable them there. See https://bugs.llvm.org/show_bug.cgi?id=37598
|
||||
// for further information.
|
||||
// The MinGW compiler doesn't complain about the weak attribute until the link
|
||||
// step, presumably because Windows doesn't use ELF binaries.
|
||||
#if (ABSL_HAVE_ATTRIBUTE(weak) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))) && \
|
||||
(!defined(_WIN32) || (defined(__clang__) && __clang_major__ >= 9)) && \
|
||||
!defined(__MINGW32__)
|
||||
#undef ABSL_ATTRIBUTE_WEAK
|
||||
#define ABSL_ATTRIBUTE_WEAK __attribute__((weak))
|
||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 1
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_WEAK
|
||||
#define ABSL_HAVE_ATTRIBUTE_WEAK 0
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NONNULL
|
||||
//
|
||||
// Tells the compiler either (a) that a particular function parameter
|
||||
// should be a non-null pointer, or (b) that all pointer arguments should
|
||||
// be non-null.
|
||||
//
|
||||
// Note: As the GCC manual states, "[s]ince non-static C++ methods
|
||||
// have an implicit 'this' argument, the arguments of such methods
|
||||
// should be counted from two, not one."
|
||||
//
|
||||
// Args are indexed starting at 1.
|
||||
//
|
||||
// For non-static class member functions, the implicit `this` argument
|
||||
// is arg 1, and the first explicit argument is arg 2. For static class member
|
||||
// functions, there is no implicit `this`, and the first explicit argument is
|
||||
// arg 1.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// /* arg_a cannot be null, but arg_b can */
|
||||
// void Function(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(1);
|
||||
//
|
||||
// class C {
|
||||
// /* arg_a cannot be null, but arg_b can */
|
||||
// void Method(void* arg_a, void* arg_b) ABSL_ATTRIBUTE_NONNULL(2);
|
||||
//
|
||||
// /* arg_a cannot be null, but arg_b can */
|
||||
// static void StaticMethod(void* arg_a, void* arg_b)
|
||||
// ABSL_ATTRIBUTE_NONNULL(1);
|
||||
// };
|
||||
//
|
||||
// If no arguments are provided, then all pointer arguments should be non-null.
|
||||
//
|
||||
// /* No pointer arguments may be null. */
|
||||
// void Function(void* arg_a, void* arg_b, int arg_c) ABSL_ATTRIBUTE_NONNULL();
|
||||
//
|
||||
// NOTE: The GCC nonnull attribute actually accepts a list of arguments, but
|
||||
// ABSL_ATTRIBUTE_NONNULL does not.
|
||||
#if ABSL_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NONNULL(...)
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NORETURN
|
||||
//
|
||||
// Tells the compiler that a given function never returns.
|
||||
//
|
||||
// Deprecated: Prefer the `[[noreturn]]` attribute standardized by C++11 over
|
||||
// this macro.
|
||||
#if ABSL_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_NORETURN __attribute__((noreturn))
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_ATTRIBUTE_NORETURN __declspec(noreturn)
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NORETURN
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
//
|
||||
// Tells the AddressSanitizer (or other memory testing tools) to ignore a given
|
||||
// function. Useful for cases when a function reads random locations on stack,
|
||||
// calls _exit from a cloned subprocess, deliberately accesses buffer
|
||||
// out of bounds or does other scary things with memory.
|
||||
// NOTE: GCC supports AddressSanitizer(asan) since 4.8.
|
||||
// https://gcc.gnu.org/gcc-4.8/changes.html
|
||||
#if defined(ABSL_HAVE_ADDRESS_SANITIZER) && \
|
||||
ABSL_HAVE_ATTRIBUTE(no_sanitize_address)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
||||
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER) && defined(_MSC_VER) && \
|
||||
_MSC_VER >= 1928
|
||||
// https://docs.microsoft.com/en-us/cpp/cpp/no-sanitize-address
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS __declspec(no_sanitize_address)
|
||||
#elif defined(ABSL_HAVE_HWADDRESS_SANITIZER) && ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||
// HWAddressSanitizer is a sanitizer similar to AddressSanitizer, which uses CPU
|
||||
// features to detect similar bugs with less CPU and memory overhead.
|
||||
// NOTE: GCC supports HWAddressSanitizer(hwasan) since 11.
|
||||
// https://gcc.gnu.org/gcc-11/changes.html
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS \
|
||||
__attribute__((no_sanitize("hwaddress")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
//
|
||||
// Tells the MemorySanitizer to relax the handling of a given function. All "Use
|
||||
// of uninitialized value" warnings from such functions will be suppressed, and
|
||||
// all values loaded from memory will be considered fully initialized. This
|
||||
// attribute is similar to the ABSL_ATTRIBUTE_NO_SANITIZE_ADDRESS attribute
|
||||
// above, but deals with initialized-ness rather than addressability issues.
|
||||
// NOTE: MemorySanitizer(msan) is supported by Clang but not GCC.
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_memory)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
||||
//
|
||||
// Tells the ThreadSanitizer to not instrument a given function.
|
||||
// NOTE: GCC supports ThreadSanitizer(tsan) since 4.8.
|
||||
// https://gcc.gnu.org/gcc-4.8/changes.html
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_thread)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_THREAD
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
//
|
||||
// Tells the UndefinedSanitizer to ignore a given function. Useful for cases
|
||||
// where certain behavior (eg. division by zero) is being used intentionally.
|
||||
// NOTE: GCC supports UndefinedBehaviorSanitizer(ubsan) since 4.9.
|
||||
// https://gcc.gnu.org/gcc-4.9/changes.html
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize_undefined)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
||||
__attribute__((no_sanitize_undefined))
|
||||
#elif ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
|
||||
__attribute__((no_sanitize("undefined")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_UNDEFINED
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||
//
|
||||
// Tells the ControlFlowIntegrity sanitizer to not instrument a given function.
|
||||
// See https://clang.llvm.org/docs/ControlFlowIntegrity.html for details.
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize) && defined(__llvm__)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_CFI
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||
//
|
||||
// Tells the SafeStack to not instrument a given function.
|
||||
// See https://clang.llvm.org/docs/SafeStack.html for details.
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_sanitize)
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
|
||||
__attribute__((no_sanitize("safe-stack")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_SANITIZE_SAFESTACK
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||
//
|
||||
// Tells the compiler that a particular function never returns a null pointer.
|
||||
#if ABSL_HAVE_ATTRIBUTE(returns_nonnull)
|
||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_RETURNS_NONNULL
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_ATTRIBUTE_SECTION
|
||||
//
|
||||
// Indicates whether labeled sections are supported. Weak symbol support is
|
||||
// a prerequisite. Labeled sections are not supported on Darwin/iOS.
|
||||
#ifdef ABSL_HAVE_ATTRIBUTE_SECTION
|
||||
#error ABSL_HAVE_ATTRIBUTE_SECTION cannot be directly set
|
||||
#elif (ABSL_HAVE_ATTRIBUTE(section) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))) && \
|
||||
!defined(__APPLE__) && ABSL_HAVE_ATTRIBUTE_WEAK
|
||||
#define ABSL_HAVE_ATTRIBUTE_SECTION 1
|
||||
|
||||
// ABSL_ATTRIBUTE_SECTION
|
||||
//
|
||||
// Tells the compiler/linker to put a given function into a section and define
|
||||
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
||||
// This functionality is supported by GNU linker. Any function annotated with
|
||||
// `ABSL_ATTRIBUTE_SECTION` must not be inlined, or it will be placed into
|
||||
// whatever section its caller is placed into.
|
||||
//
|
||||
#ifndef ABSL_ATTRIBUTE_SECTION
|
||||
#define ABSL_ATTRIBUTE_SECTION(name) \
|
||||
__attribute__((section(#name))) __attribute__((noinline))
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_SECTION_VARIABLE
|
||||
//
|
||||
// Tells the compiler/linker to put a given variable into a section and define
|
||||
// `__start_ ## name` and `__stop_ ## name` symbols to bracket the section.
|
||||
// This functionality is supported by GNU linker.
|
||||
#ifndef ABSL_ATTRIBUTE_SECTION_VARIABLE
|
||||
#ifdef _AIX
|
||||
// __attribute__((section(#name))) on AIX is achieved by using the `.csect`
|
||||
// psudo op which includes an additional integer as part of its syntax indcating
|
||||
// alignment. If data fall under different alignments then you might get a
|
||||
// compilation error indicating a `Section type conflict`.
|
||||
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
||||
//
|
||||
// A weak section declaration to be used as a global declaration
|
||||
// for ABSL_ATTRIBUTE_SECTION_START|STOP(name) to compile and link
|
||||
// even without functions with ABSL_ATTRIBUTE_SECTION(name).
|
||||
// ABSL_DEFINE_ATTRIBUTE_SECTION should be in the exactly one file; it's
|
||||
// a no-op on ELF but not on Mach-O.
|
||||
//
|
||||
#ifndef ABSL_DECLARE_ATTRIBUTE_SECTION_VARS
|
||||
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
|
||||
extern char __start_##name[] ABSL_ATTRIBUTE_WEAK; \
|
||||
extern char __stop_##name[] ABSL_ATTRIBUTE_WEAK
|
||||
#endif
|
||||
#ifndef ABSL_DEFINE_ATTRIBUTE_SECTION_VARS
|
||||
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
||||
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_SECTION_START
|
||||
//
|
||||
// Returns `void*` pointers to start/end of a section of code with
|
||||
// functions having ABSL_ATTRIBUTE_SECTION(name).
|
||||
// Returns 0 if no such functions exist.
|
||||
// One must ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name) for this to compile and
|
||||
// link.
|
||||
//
|
||||
#define ABSL_ATTRIBUTE_SECTION_START(name) \
|
||||
(reinterpret_cast<void *>(__start_##name))
|
||||
#define ABSL_ATTRIBUTE_SECTION_STOP(name) \
|
||||
(reinterpret_cast<void *>(__stop_##name))
|
||||
|
||||
#else // !ABSL_HAVE_ATTRIBUTE_SECTION
|
||||
|
||||
#define ABSL_HAVE_ATTRIBUTE_SECTION 0
|
||||
|
||||
// provide dummy definitions
|
||||
#define ABSL_ATTRIBUTE_SECTION(name)
|
||||
#define ABSL_ATTRIBUTE_SECTION_VARIABLE(name)
|
||||
#define ABSL_INIT_ATTRIBUTE_SECTION_VARS(name)
|
||||
#define ABSL_DEFINE_ATTRIBUTE_SECTION_VARS(name)
|
||||
#define ABSL_DECLARE_ATTRIBUTE_SECTION_VARS(name)
|
||||
#define ABSL_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
|
||||
#define ABSL_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
|
||||
|
||||
#endif // ABSL_ATTRIBUTE_SECTION
|
||||
|
||||
// ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||
//
|
||||
// Support for aligning the stack on 32-bit x86.
|
||||
#if ABSL_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#if defined(__i386__)
|
||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
|
||||
__attribute__((force_align_arg_pointer))
|
||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||
#elif defined(__x86_64__)
|
||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
|
||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||
#else // !__i386__ && !__x86_64
|
||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||
#endif // __i386__
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
|
||||
#define ABSL_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
|
||||
#endif
|
||||
|
||||
// ABSL_MUST_USE_RESULT
|
||||
//
|
||||
// Tells the compiler to warn about unused results.
|
||||
//
|
||||
// For code or headers that are assured to only build with C++17 and up, prefer
|
||||
// just using the standard `[[nodiscard]]` directly over this macro.
|
||||
//
|
||||
// When annotating a function, it must appear as the first part of the
|
||||
// declaration or definition. The compiler will warn if the return value from
|
||||
// such a function is unused:
|
||||
//
|
||||
// ABSL_MUST_USE_RESULT Sprocket* AllocateSprocket();
|
||||
// AllocateSprocket(); // Triggers a warning.
|
||||
//
|
||||
// When annotating a class, it is equivalent to annotating every function which
|
||||
// returns an instance.
|
||||
//
|
||||
// class ABSL_MUST_USE_RESULT Sprocket {};
|
||||
// Sprocket(); // Triggers a warning.
|
||||
//
|
||||
// Sprocket MakeSprocket();
|
||||
// MakeSprocket(); // Triggers a warning.
|
||||
//
|
||||
// Note that references and pointers are not instances:
|
||||
//
|
||||
// Sprocket* SprocketPointer();
|
||||
// SprocketPointer(); // Does *not* trigger a warning.
|
||||
//
|
||||
// ABSL_MUST_USE_RESULT allows using cast-to-void to suppress the unused result
|
||||
// warning. For that, warn_unused_result is used only for clang but not for gcc.
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425
|
||||
//
|
||||
// Note: past advice was to place the macro after the argument list.
|
||||
//
|
||||
// TODO(b/176172494): Use ABSL_HAVE_CPP_ATTRIBUTE(nodiscard) when all code is
|
||||
// compliant with the stricter [[nodiscard]].
|
||||
#if defined(__clang__) && ABSL_HAVE_ATTRIBUTE(warn_unused_result)
|
||||
#define ABSL_MUST_USE_RESULT __attribute__((warn_unused_result))
|
||||
#else
|
||||
#define ABSL_MUST_USE_RESULT
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_HOT, ABSL_ATTRIBUTE_COLD
|
||||
//
|
||||
// Tells GCC that a function is hot or cold. GCC can use this information to
|
||||
// improve static analysis, i.e. a conditional branch to a cold function
|
||||
// is likely to be not-taken.
|
||||
// This annotation is used for function declarations.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// int foo() ABSL_ATTRIBUTE_HOT;
|
||||
#if ABSL_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_HOT __attribute__((hot))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_HOT
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_COLD __attribute__((cold))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_COLD
|
||||
#endif
|
||||
|
||||
// ABSL_XRAY_ALWAYS_INSTRUMENT, ABSL_XRAY_NEVER_INSTRUMENT, ABSL_XRAY_LOG_ARGS
|
||||
//
|
||||
// We define the ABSL_XRAY_ALWAYS_INSTRUMENT and ABSL_XRAY_NEVER_INSTRUMENT
|
||||
// macro used as an attribute to mark functions that must always or never be
|
||||
// instrumented by XRay. Currently, this is only supported in Clang/LLVM.
|
||||
//
|
||||
// For reference on the LLVM XRay instrumentation, see
|
||||
// http://llvm.org/docs/XRay.html.
|
||||
//
|
||||
// A function with the XRAY_ALWAYS_INSTRUMENT macro attribute in its declaration
|
||||
// will always get the XRay instrumentation sleds. These sleds may introduce
|
||||
// some binary size and runtime overhead and must be used sparingly.
|
||||
//
|
||||
// These attributes only take effect when the following conditions are met:
|
||||
//
|
||||
// * The file/target is built in at least C++11 mode, with a Clang compiler
|
||||
// that supports XRay attributes.
|
||||
// * The file/target is built with the -fxray-instrument flag set for the
|
||||
// Clang/LLVM compiler.
|
||||
// * The function is defined in the translation unit (the compiler honors the
|
||||
// attribute in either the definition or the declaration, and must match).
|
||||
//
|
||||
// There are cases when, even when building with XRay instrumentation, users
|
||||
// might want to control specifically which functions are instrumented for a
|
||||
// particular build using special-case lists provided to the compiler. These
|
||||
// special case lists are provided to Clang via the
|
||||
// -fxray-always-instrument=... and -fxray-never-instrument=... flags. The
|
||||
// attributes in source take precedence over these special-case lists.
|
||||
//
|
||||
// To disable the XRay attributes at build-time, users may define
|
||||
// ABSL_NO_XRAY_ATTRIBUTES. Do NOT define ABSL_NO_XRAY_ATTRIBUTES on specific
|
||||
// packages/targets, as this may lead to conflicting definitions of functions at
|
||||
// link-time.
|
||||
//
|
||||
// XRay isn't currently supported on Android:
|
||||
// https://github.com/android/ndk/issues/368
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_always_instrument) && \
|
||||
!defined(ABSL_NO_XRAY_ATTRIBUTES) && !defined(__ANDROID__)
|
||||
#define ABSL_XRAY_ALWAYS_INSTRUMENT [[clang::xray_always_instrument]]
|
||||
#define ABSL_XRAY_NEVER_INSTRUMENT [[clang::xray_never_instrument]]
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::xray_log_args)
|
||||
#define ABSL_XRAY_LOG_ARGS(N) \
|
||||
[[clang::xray_always_instrument, clang::xray_log_args(N)]]
|
||||
#else
|
||||
#define ABSL_XRAY_LOG_ARGS(N) [[clang::xray_always_instrument]]
|
||||
#endif
|
||||
#else
|
||||
#define ABSL_XRAY_ALWAYS_INSTRUMENT
|
||||
#define ABSL_XRAY_NEVER_INSTRUMENT
|
||||
#define ABSL_XRAY_LOG_ARGS(N)
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_REINITIALIZES
|
||||
//
|
||||
// Indicates that a 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 allows member functions marked
|
||||
// with this attribute to be called on objects that have been moved from;
|
||||
// without the attribute, this would result in a use-after-move warning.
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
|
||||
#define ABSL_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_REINITIALIZES
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Variable Attributes
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ABSL_ATTRIBUTE_UNUSED
|
||||
//
|
||||
// Prevents the compiler from complaining about variables that appear unused.
|
||||
//
|
||||
// For code or headers that are assured to only build with C++17 and up, prefer
|
||||
// just using the standard '[[maybe_unused]]' directly over this macro.
|
||||
//
|
||||
// Due to differences in positioning requirements between the old, compiler
|
||||
// specific __attribute__ syntax and the now standard [[maybe_unused]], this
|
||||
// macro does not attempt to take advantage of '[[maybe_unused]]'.
|
||||
#if ABSL_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#undef ABSL_ATTRIBUTE_UNUSED
|
||||
#define ABSL_ATTRIBUTE_UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_UNUSED
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_INITIAL_EXEC
|
||||
//
|
||||
// Tells the compiler to use "initial-exec" mode for a thread-local variable.
|
||||
// See http://people.redhat.com/drepper/tls.pdf for the gory details.
|
||||
#if ABSL_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_INITIAL_EXEC
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_PACKED
|
||||
//
|
||||
// Instructs the compiler not to use natural alignment for a tagged data
|
||||
// structure, but instead to reduce its alignment to 1.
|
||||
//
|
||||
// Therefore, DO NOT APPLY THIS ATTRIBUTE TO STRUCTS CONTAINING ATOMICS. Doing
|
||||
// so can cause atomic variables to be mis-aligned and silently violate
|
||||
// atomicity on x86.
|
||||
//
|
||||
// This attribute can either be applied to members of a structure or to a
|
||||
// structure in its entirety. Applying this attribute (judiciously) to a
|
||||
// structure in its entirety to optimize the memory footprint of very
|
||||
// commonly-used structs is fine. Do not apply this attribute to a structure in
|
||||
// its entirety if the purpose is to control the offsets of the members in the
|
||||
// structure. Instead, apply this attribute only to structure members that need
|
||||
// it.
|
||||
//
|
||||
// When applying ABSL_ATTRIBUTE_PACKED only to specific structure members the
|
||||
// natural alignment of structure members not annotated is preserved. Aligned
|
||||
// member accesses are faster than non-aligned member accesses even if the
|
||||
// targeted microprocessor supports non-aligned accesses.
|
||||
#if ABSL_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_PACKED __attribute__((__packed__))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_PACKED
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_FUNC_ALIGN
|
||||
//
|
||||
// Tells the compiler to align the function start at least to certain
|
||||
// alignment boundary
|
||||
#if ABSL_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_FUNC_ALIGN(bytes)
|
||||
#endif
|
||||
|
||||
// ABSL_FALLTHROUGH_INTENDED
|
||||
//
|
||||
// Annotates implicit fall-through between switch labels, allowing a case to
|
||||
// indicate intentional fallthrough and turn off warnings about any lack of a
|
||||
// `break` statement. The ABSL_FALLTHROUGH_INTENDED macro should be followed by
|
||||
// a semicolon and can be used in most places where `break` can, provided that
|
||||
// no statements exist between it and the next switch label.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// switch (x) {
|
||||
// case 40:
|
||||
// case 41:
|
||||
// if (truth_is_out_there) {
|
||||
// ++x;
|
||||
// ABSL_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
|
||||
// // in comments
|
||||
// } else {
|
||||
// return x;
|
||||
// }
|
||||
// case 42:
|
||||
// ...
|
||||
//
|
||||
// Notes: When supported, GCC and Clang can issue a warning on switch labels
|
||||
// with unannotated fallthrough using the warning `-Wimplicit-fallthrough`. See
|
||||
// clang documentation on language extensions for details:
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
|
||||
//
|
||||
// When used with unsupported compilers, the ABSL_FALLTHROUGH_INTENDED macro has
|
||||
// no effect on diagnostics. In any case this macro has no effect on runtime
|
||||
// behavior and performance of code.
|
||||
|
||||
#ifdef ABSL_FALLTHROUGH_INTENDED
|
||||
#error "ABSL_FALLTHROUGH_INTENDED should not be defined."
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(fallthrough)
|
||||
#define ABSL_FALLTHROUGH_INTENDED [[fallthrough]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::fallthrough)
|
||||
#define ABSL_FALLTHROUGH_INTENDED [[clang::fallthrough]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::fallthrough)
|
||||
#define ABSL_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
|
||||
#else
|
||||
#define ABSL_FALLTHROUGH_INTENDED \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// ABSL_DEPRECATED()
|
||||
//
|
||||
// Marks a deprecated class, struct, enum, function, method and variable
|
||||
// declarations. The macro argument is used as a custom diagnostic message (e.g.
|
||||
// suggestion of a better alternative).
|
||||
//
|
||||
// For code or headers that are assured to only build with C++14 and up, prefer
|
||||
// just using the standard `[[deprecated("message")]]` directly over this macro.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// class ABSL_DEPRECATED("Use Bar instead") Foo {...};
|
||||
//
|
||||
// ABSL_DEPRECATED("Use Baz() instead") void Bar() {...}
|
||||
//
|
||||
// template <typename T>
|
||||
// ABSL_DEPRECATED("Use DoThat() instead")
|
||||
// void DoThis();
|
||||
//
|
||||
// enum FooEnum {
|
||||
// kBar ABSL_DEPRECATED("Use kBaz instead"),
|
||||
// };
|
||||
//
|
||||
// Every usage of a deprecated entity will trigger a warning when compiled with
|
||||
// GCC/Clang's `-Wdeprecated-declarations` option. Google's production toolchain
|
||||
// turns this warning off by default, instead relying on clang-tidy to report
|
||||
// new uses of deprecated code.
|
||||
#if ABSL_HAVE_ATTRIBUTE(deprecated)
|
||||
#define ABSL_DEPRECATED(message) __attribute__((deprecated(message)))
|
||||
#else
|
||||
#define ABSL_DEPRECATED(message)
|
||||
#endif
|
||||
|
||||
// When deprecating Abseil code, it is sometimes necessary to turn off the
|
||||
// warning within Abseil, until the deprecated code is actually removed. The
|
||||
// deprecated code can be surrounded with these directives to achieve that
|
||||
// result.
|
||||
//
|
||||
// class ABSL_DEPRECATED("Use Bar instead") Foo;
|
||||
//
|
||||
// ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
// Baz ComputeBazFromFoo(Foo f);
|
||||
// ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// Clang also supports these GCC pragmas.
|
||||
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \
|
||||
_Pragma("GCC diagnostic push") \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING \
|
||||
_Pragma("warning(push)") _Pragma("warning(disable: 4996)")
|
||||
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING \
|
||||
_Pragma("warning(pop)")
|
||||
#else
|
||||
#define ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
#define ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
#endif // defined(__GNUC__) || defined(__clang__)
|
||||
|
||||
// ABSL_CONST_INIT
|
||||
//
|
||||
// A variable declaration annotated with the `ABSL_CONST_INIT` attribute will
|
||||
// not compile (on supported platforms) unless the variable has a constant
|
||||
// initializer. This is useful for variables with static and thread storage
|
||||
// duration, because it guarantees that they will not suffer from the so-called
|
||||
// "static init order fiasco".
|
||||
//
|
||||
// This attribute must be placed on the initializing declaration of the
|
||||
// variable. Some compilers will give a -Wmissing-constinit warning when this
|
||||
// attribute is placed on some other declaration but missing from the
|
||||
// initializing declaration.
|
||||
//
|
||||
// In some cases (notably with thread_local variables), `ABSL_CONST_INIT` can
|
||||
// also be used in a non-initializing declaration to tell the compiler that a
|
||||
// variable is already initialized, reducing overhead that would otherwise be
|
||||
// incurred by a hidden guard variable. Thus annotating all declarations with
|
||||
// this attribute is recommended to potentially enhance optimization.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// class MyClass {
|
||||
// public:
|
||||
// ABSL_CONST_INIT static MyType my_var;
|
||||
// };
|
||||
//
|
||||
// ABSL_CONST_INIT MyType MyClass::my_var = MakeMyType(...);
|
||||
//
|
||||
// For code or headers that are assured to only build with C++20 and up, prefer
|
||||
// just using the standard `constinit` keyword directly over this macro.
|
||||
//
|
||||
// Note that this attribute is redundant if the variable is declared constexpr.
|
||||
#if defined(__cpp_constinit) && __cpp_constinit >= 201907L
|
||||
#define ABSL_CONST_INIT constinit
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::require_constant_initialization)
|
||||
#define ABSL_CONST_INIT [[clang::require_constant_initialization]]
|
||||
#else
|
||||
#define ABSL_CONST_INIT
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||
//
|
||||
// ABSL_ATTRIBUTE_PURE_FUNCTION is used to annotate declarations of "pure"
|
||||
// functions. A function is pure if its return value is only a function of its
|
||||
// arguments. The pure attribute prohibits a function from modifying the state
|
||||
// of the program that is observable by means other than inspecting the
|
||||
// function's return value. Declaring such functions with the pure attribute
|
||||
// allows the compiler to avoid emitting some calls in repeated invocations of
|
||||
// the function with the same argument values.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t);
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::pure)
|
||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION [[gnu::pure]]
|
||||
#elif ABSL_HAVE_ATTRIBUTE(pure)
|
||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION __attribute__((pure))
|
||||
#else
|
||||
// If the attribute isn't defined, we'll fallback to ABSL_MUST_USE_RESULT since
|
||||
// pure functions are useless if its return is ignored.
|
||||
#define ABSL_ATTRIBUTE_PURE_FUNCTION ABSL_MUST_USE_RESULT
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_CONST_FUNCTION
|
||||
//
|
||||
// ABSL_ATTRIBUTE_CONST_FUNCTION is used to annotate declarations of "const"
|
||||
// functions. A const function is similar to a pure function, with one
|
||||
// exception: Pure functions may return value that depend on a non-volatile
|
||||
// object that isn't provided as a function argument, while the const function
|
||||
// is guaranteed to return the same result given the same arguments.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Milliseconds(Duration d);
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
// Put the MSVC case first since MSVC seems to parse const as a C++ keyword.
|
||||
#define ABSL_ATTRIBUTE_CONST_FUNCTION ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::const)
|
||||
#define ABSL_ATTRIBUTE_CONST_FUNCTION [[gnu::const]]
|
||||
#elif ABSL_HAVE_ATTRIBUTE(const)
|
||||
#define ABSL_ATTRIBUTE_CONST_FUNCTION __attribute__((const))
|
||||
#else
|
||||
// Since const functions are more restrictive pure function, we'll fallback to a
|
||||
// pure function if the const attribute is not handled.
|
||||
#define ABSL_ATTRIBUTE_CONST_FUNCTION ABSL_ATTRIBUTE_PURE_FUNCTION
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_LIFETIME_BOUND indicates that a resource owned by a function
|
||||
// parameter or implicit object parameter is retained by the return value of the
|
||||
// annotated function (or, for a parameter of a constructor, in the value of the
|
||||
// constructed object). This attribute causes warnings to be produced if a
|
||||
// temporary object does not live long enough.
|
||||
//
|
||||
// When applied to a reference parameter, the referenced object is assumed to be
|
||||
// retained by the return value of the function. When applied to a non-reference
|
||||
// parameter (for example, a pointer or a class type), all temporaries
|
||||
// referenced by the parameter are assumed to be retained by the return value of
|
||||
// the function.
|
||||
//
|
||||
// See also the upstream documentation:
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#lifetimebound
|
||||
// https://learn.microsoft.com/en-us/cpp/code-quality/c26816?view=msvc-170
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::lifetimebound)
|
||||
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[clang::lifetimebound]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(msvc::lifetimebound)
|
||||
#define ABSL_ATTRIBUTE_LIFETIME_BOUND [[msvc::lifetimebound]]
|
||||
#elif ABSL_HAVE_ATTRIBUTE(lifetimebound)
|
||||
#define ABSL_ATTRIBUTE_LIFETIME_BOUND __attribute__((lifetimebound))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_LIFETIME_BOUND
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_ATTRIBUTE_VIEW indicates that a type acts like a view i.e. a
|
||||
// raw (non-owning) pointer. This enables diagnoses similar to those enabled by
|
||||
// ABSL_ATTRIBUTE_LIFETIME_BOUND.
|
||||
//
|
||||
// See the following links for details:
|
||||
// https://reviews.llvm.org/D64448
|
||||
// https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Pointer)
|
||||
#define ABSL_INTERNAL_ATTRIBUTE_VIEW [[gsl::Pointer]]
|
||||
#else
|
||||
#define ABSL_INTERNAL_ATTRIBUTE_VIEW
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_ATTRIBUTE_OWNER indicates that a type acts like a smart
|
||||
// (owning) pointer. This enables diagnoses similar to those enabled by
|
||||
// ABSL_ATTRIBUTE_LIFETIME_BOUND.
|
||||
//
|
||||
// See the following links for details:
|
||||
// https://reviews.llvm.org/D64448
|
||||
// https://lists.llvm.org/pipermail/cfe-dev/2018-November/060355.html
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(gsl::Owner)
|
||||
#define ABSL_INTERNAL_ATTRIBUTE_OWNER [[gsl::Owner]]
|
||||
#else
|
||||
#define ABSL_INTERNAL_ATTRIBUTE_OWNER
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_TRIVIAL_ABI
|
||||
// Indicates that a type is "trivially relocatable" -- meaning it can be
|
||||
// relocated without invoking the constructor/destructor, using a form of move
|
||||
// elision.
|
||||
//
|
||||
// From a memory safety point of view, putting aside destructor ordering, it's
|
||||
// safe to apply ABSL_ATTRIBUTE_TRIVIAL_ABI if an object's location
|
||||
// can change over the course of its lifetime: if a constructor can be run one
|
||||
// place, and then the object magically teleports to another place where some
|
||||
// methods are run, and then the object teleports to yet another place where it
|
||||
// is destroyed. This is notably not true for self-referential types, where the
|
||||
// move-constructor must keep the self-reference up to date. If the type changed
|
||||
// location without invoking the move constructor, it would have a dangling
|
||||
// self-reference.
|
||||
//
|
||||
// The use of this teleporting machinery means that the number of paired
|
||||
// move/destroy operations can change, and so it is a bad idea to apply this to
|
||||
// a type meant to count the number of moves.
|
||||
//
|
||||
// Warning: applying this can, rarely, break callers. Objects passed by value
|
||||
// will be destroyed at the end of the call, instead of the end of the
|
||||
// full-expression containing the call. In addition, it changes the ABI
|
||||
// of functions accepting this type by value (e.g. to pass in registers).
|
||||
//
|
||||
// See also the upstream documentation:
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#trivial-abi
|
||||
//
|
||||
// b/321691395 - This is currently disabled in open-source builds since
|
||||
// compiler support differs. If system libraries compiled with GCC are mixed
|
||||
// with libraries compiled with Clang, types will have different ideas about
|
||||
// their ABI, leading to hard to debug crashes.
|
||||
#define ABSL_ATTRIBUTE_TRIVIAL_ABI
|
||||
|
||||
// ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS
|
||||
//
|
||||
// Indicates a data member can be optimized to occupy no space (if it is empty)
|
||||
// and/or its tail padding can be used for other members.
|
||||
//
|
||||
// For code that is assured to only build with C++20 or later, prefer using
|
||||
// the standard attribute `[[no_unique_address]]` directly instead of this
|
||||
// macro.
|
||||
//
|
||||
// https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/#c20-no_unique_address
|
||||
// Current versions of MSVC have disabled `[[no_unique_address]]` since it
|
||||
// breaks ABI compatibility, but offers `[[msvc::no_unique_address]]` for
|
||||
// situations when it can be assured that it is desired. Since Abseil does not
|
||||
// claim ABI compatibility in mixed builds, we can offer it unconditionally.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1929
|
||||
#define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(no_unique_address)
|
||||
#define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_NO_UNIQUE_ADDRESS
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_UNINITIALIZED
|
||||
//
|
||||
// GCC and Clang support a flag `-ftrivial-auto-var-init=<option>` (<option>
|
||||
// can be "zero" or "pattern") that can be used to initialize automatic stack
|
||||
// variables. Variables with this attribute will be left uninitialized,
|
||||
// overriding the compiler flag.
|
||||
//
|
||||
// See https://clang.llvm.org/docs/AttributeReference.html#uninitialized
|
||||
// and https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-uninitialized-variable-attribute
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::uninitialized)
|
||||
#define ABSL_ATTRIBUTE_UNINITIALIZED [[clang::uninitialized]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(gnu::uninitialized)
|
||||
#define ABSL_ATTRIBUTE_UNINITIALIZED [[gnu::uninitialized]]
|
||||
#elif ABSL_HAVE_ATTRIBUTE(uninitialized)
|
||||
#define ABSL_ATTRIBUTE_UNINITIALIZED __attribute__((uninitialized))
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_UNINITIALIZED
|
||||
#endif
|
||||
|
||||
// ABSL_ATTRIBUTE_WARN_UNUSED
|
||||
//
|
||||
// Compilers routinely warn about trivial variables that are unused. For
|
||||
// non-trivial types, this warning is suppressed since the
|
||||
// constructor/destructor may be intentional and load-bearing, for example, with
|
||||
// a RAII scoped lock.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// class ABSL_ATTRIBUTE_WARN_UNUSED MyType {
|
||||
// public:
|
||||
// MyType();
|
||||
// ~MyType();
|
||||
// };
|
||||
//
|
||||
// void foo() {
|
||||
// // Warns with ABSL_ATTRIBUTE_WARN_UNUSED attribute present.
|
||||
// MyType unused;
|
||||
// }
|
||||
//
|
||||
// See https://clang.llvm.org/docs/AttributeReference.html#warn-unused and
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/C_002b_002b-Attributes.html#index-warn_005funused-type-attribute
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(gnu::warn_unused)
|
||||
#define ABSL_ATTRIBUTE_WARN_UNUSED [[gnu::warn_unused]]
|
||||
#else
|
||||
#define ABSL_ATTRIBUTE_WARN_UNUSED
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_ATTRIBUTES_H_
|
||||
@@ -0,0 +1,180 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: casts.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines casting templates to fit use cases not covered by
|
||||
// the standard casts provided in the C++ standard. As with all cast operations,
|
||||
// use these with caution and only if alternatives do not exist.
|
||||
|
||||
#ifndef ABSL_BASE_CASTS_H_
|
||||
#define ABSL_BASE_CASTS_H_
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
#include <bit> // For std::bit_cast.
|
||||
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
|
||||
#include "absl/base/internal/identity.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// implicit_cast()
|
||||
//
|
||||
// Performs an implicit conversion between types following the language
|
||||
// rules for implicit conversion; if an implicit conversion is otherwise
|
||||
// allowed by the language in the given context, this function performs such an
|
||||
// implicit conversion.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // If the context allows implicit conversion:
|
||||
// From from;
|
||||
// To to = from;
|
||||
//
|
||||
// // Such code can be replaced by:
|
||||
// implicit_cast<To>(from);
|
||||
//
|
||||
// An `implicit_cast()` may also be used to annotate numeric type conversions
|
||||
// that, although safe, may produce compiler warnings (such as `long` to `int`).
|
||||
// Additionally, an `implicit_cast()` is also useful within return statements to
|
||||
// indicate a specific implicit conversion is being undertaken.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// return implicit_cast<double>(size_in_bytes) / capacity_;
|
||||
//
|
||||
// Annotating code with `implicit_cast()` allows you to explicitly select
|
||||
// particular overloads and template instantiations, while providing a safer
|
||||
// cast than `reinterpret_cast()` or `static_cast()`.
|
||||
//
|
||||
// Additionally, an `implicit_cast()` can be used to allow upcasting within a
|
||||
// type hierarchy where incorrect use of `static_cast()` could accidentally
|
||||
// allow downcasting.
|
||||
//
|
||||
// Finally, an `implicit_cast()` can be used to perform implicit conversions
|
||||
// from unrelated types that otherwise couldn't be implicitly cast directly;
|
||||
// C++ will normally only implicitly cast "one step" in such conversions.
|
||||
//
|
||||
// That is, if C is a type which can be implicitly converted to B, with B being
|
||||
// a type that can be implicitly converted to A, an `implicit_cast()` can be
|
||||
// used to convert C to B (which the compiler can then implicitly convert to A
|
||||
// using language rules).
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Assume an object C is convertible to B, which is implicitly convertible
|
||||
// // to A
|
||||
// A a = implicit_cast<B>(C);
|
||||
//
|
||||
// Such implicit cast chaining may be useful within template logic.
|
||||
template <typename To>
|
||||
constexpr To implicit_cast(typename absl::internal::type_identity_t<To> to) {
|
||||
return to;
|
||||
}
|
||||
|
||||
// bit_cast()
|
||||
//
|
||||
// Creates a value of the new type `Dest` whose representation is the same as
|
||||
// that of the argument, which is of (deduced) type `Source` (a "bitwise cast";
|
||||
// every bit in the value representation of the result is equal to the
|
||||
// corresponding bit in the object representation of the source). Source and
|
||||
// destination types must be of the same size, and both types must be trivially
|
||||
// copyable.
|
||||
//
|
||||
// As with most casts, use with caution. A `bit_cast()` might be needed when you
|
||||
// need to treat a value as the value of some other type, for example, to access
|
||||
// the individual bits of an object which are not normally accessible through
|
||||
// the object's type, such as for working with the binary representation of a
|
||||
// floating point value:
|
||||
//
|
||||
// float f = 3.14159265358979;
|
||||
// int i = bit_cast<int>(f);
|
||||
// // i = 0x40490fdb
|
||||
//
|
||||
// Reinterpreting and accessing a value directly as a different type (as shown
|
||||
// below) usually results in undefined behavior.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // WRONG
|
||||
// float f = 3.14159265358979;
|
||||
// int i = reinterpret_cast<int&>(f); // Wrong
|
||||
// int j = *reinterpret_cast<int*>(&f); // Equally wrong
|
||||
// int k = *bit_cast<int*>(&f); // Equally wrong
|
||||
//
|
||||
// Reinterpret-casting results in undefined behavior according to the ISO C++
|
||||
// specification, section [basic.lval]. Roughly, this section says: if an object
|
||||
// in memory has one type, and a program accesses it with a different type, the
|
||||
// result is undefined behavior for most "different type".
|
||||
//
|
||||
// Using bit_cast on a pointer and then dereferencing it is no better than using
|
||||
// reinterpret_cast. You should only use bit_cast on the value itself.
|
||||
//
|
||||
// Such casting results in type punning: holding an object in memory of one type
|
||||
// and reading its bits back using a different type. A `bit_cast()` avoids this
|
||||
// issue by copying the object representation to a new value, which avoids
|
||||
// introducing this undefined behavior (since the original value is never
|
||||
// accessed in the wrong way).
|
||||
//
|
||||
// The requirements of `absl::bit_cast` are more strict than that of
|
||||
// `std::bit_cast` unless compiler support is available. Specifically, without
|
||||
// compiler support, this implementation also requires `Dest` to be
|
||||
// default-constructible. In C++20, `absl::bit_cast` is replaced by
|
||||
// `std::bit_cast`.
|
||||
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
|
||||
using std::bit_cast;
|
||||
|
||||
#else // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
|
||||
template <
|
||||
typename Dest, typename Source,
|
||||
typename std::enable_if<sizeof(Dest) == sizeof(Source) &&
|
||||
std::is_trivially_copyable<Source>::value &&
|
||||
std::is_trivially_copyable<Dest>::value
|
||||
#if !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||
&& std::is_default_constructible<Dest>::value
|
||||
#endif // !ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||
,
|
||||
int>::type = 0>
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||
inline constexpr Dest bit_cast(const Source& source) {
|
||||
return __builtin_bit_cast(Dest, source);
|
||||
}
|
||||
#else // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||
inline Dest bit_cast(const Source& source) {
|
||||
Dest dest;
|
||||
memcpy(static_cast<void*>(std::addressof(dest)),
|
||||
static_cast<const void*>(std::addressof(source)), sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
#endif // ABSL_HAVE_BUILTIN(__builtin_bit_cast)
|
||||
|
||||
#endif // defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_CASTS_H_
|
||||
@@ -0,0 +1,985 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: config.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines a set of macros for checking the presence of
|
||||
// important compiler and platform features. Such macros can be used to
|
||||
// produce portable code by parameterizing compilation based on the presence or
|
||||
// lack of a given feature.
|
||||
//
|
||||
// We define a "feature" as some interface we wish to program to: for example,
|
||||
// a library function or system call. A value of `1` indicates support for
|
||||
// that feature; any other value indicates the feature support is undefined.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Suppose a programmer wants to write a program that uses the 'mmap()' system
|
||||
// call. The Abseil macro for that feature (`ABSL_HAVE_MMAP`) allows you to
|
||||
// selectively include the `mmap.h` header and bracket code using that feature
|
||||
// in the macro:
|
||||
//
|
||||
// #include "absl/base/config.h"
|
||||
//
|
||||
// #ifdef ABSL_HAVE_MMAP
|
||||
// #include "sys/mman.h"
|
||||
// #endif //ABSL_HAVE_MMAP
|
||||
//
|
||||
// ...
|
||||
// #ifdef ABSL_HAVE_MMAP
|
||||
// void *ptr = mmap(...);
|
||||
// ...
|
||||
// #endif // ABSL_HAVE_MMAP
|
||||
|
||||
#ifndef ABSL_BASE_CONFIG_H_
|
||||
#define ABSL_BASE_CONFIG_H_
|
||||
|
||||
// Included for the __GLIBC__ macro (or similar macros on other systems).
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Included for __GLIBCXX__, _LIBCPP_VERSION
|
||||
#include <cstddef>
|
||||
#endif // __cplusplus
|
||||
|
||||
// ABSL_INTERNAL_CPLUSPLUS_LANG
|
||||
//
|
||||
// MSVC does not set the value of __cplusplus correctly, but instead uses
|
||||
// _MSVC_LANG as a stand-in.
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
//
|
||||
// However, there are reports that MSVC even sets _MSVC_LANG incorrectly at
|
||||
// times, for example:
|
||||
// https://github.com/microsoft/vscode-cpptools/issues/1770
|
||||
// https://reviews.llvm.org/D70996
|
||||
//
|
||||
// For this reason, this symbol is considered INTERNAL and code outside of
|
||||
// Abseil must not use it.
|
||||
#if defined(_MSVC_LANG)
|
||||
#define ABSL_INTERNAL_CPLUSPLUS_LANG _MSVC_LANG
|
||||
#elif defined(__cplusplus)
|
||||
#define ABSL_INTERNAL_CPLUSPLUS_LANG __cplusplus
|
||||
#endif
|
||||
|
||||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
|
||||
// Include library feature test macros.
|
||||
#include <version>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
|
||||
// __IPHONE_8_0.
|
||||
#include <Availability.h>
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
|
||||
#include "absl/base/options.h"
|
||||
#include "absl/base/policy_checks.h"
|
||||
|
||||
// Abseil long-term support (LTS) releases will define
|
||||
// `ABSL_LTS_RELEASE_VERSION` to the integer representing the date string of the
|
||||
// LTS release version, and will define `ABSL_LTS_RELEASE_PATCH_LEVEL` to the
|
||||
// integer representing the patch-level for that release.
|
||||
//
|
||||
// For example, for LTS release version "20300401.2", this would give us
|
||||
// ABSL_LTS_RELEASE_VERSION == 20300401 && ABSL_LTS_RELEASE_PATCH_LEVEL == 2
|
||||
//
|
||||
// These symbols will not be defined in non-LTS code.
|
||||
//
|
||||
// Abseil recommends that clients live-at-head. Therefore, if you are using
|
||||
// these symbols to assert a minimum version requirement, we recommend you do it
|
||||
// as
|
||||
//
|
||||
// #if defined(ABSL_LTS_RELEASE_VERSION) && ABSL_LTS_RELEASE_VERSION < 20300401
|
||||
// #error Project foo requires Abseil LTS version >= 20300401
|
||||
// #endif
|
||||
//
|
||||
// The `defined(ABSL_LTS_RELEASE_VERSION)` part of the check excludes
|
||||
// live-at-head clients from the minimum version assertion.
|
||||
//
|
||||
// See https://abseil.io/about/releases for more information on Abseil release
|
||||
// management.
|
||||
//
|
||||
// LTS releases can be obtained from
|
||||
// https://github.com/abseil/abseil-cpp/releases.
|
||||
#define ABSL_LTS_RELEASE_VERSION 20240722
|
||||
#define ABSL_LTS_RELEASE_PATCH_LEVEL 0
|
||||
|
||||
// Helper macro to convert a CPP variable to a string literal.
|
||||
#define ABSL_INTERNAL_DO_TOKEN_STR(x) #x
|
||||
#define ABSL_INTERNAL_TOKEN_STR(x) ABSL_INTERNAL_DO_TOKEN_STR(x)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Abseil namespace annotations
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ABSL_NAMESPACE_BEGIN/ABSL_NAMESPACE_END
|
||||
//
|
||||
// An annotation placed at the beginning/end of each `namespace absl` scope.
|
||||
// This is used to inject an inline namespace.
|
||||
//
|
||||
// The proper way to write Abseil code in the `absl` namespace is:
|
||||
//
|
||||
// namespace absl {
|
||||
// ABSL_NAMESPACE_BEGIN
|
||||
//
|
||||
// void Foo(); // absl::Foo().
|
||||
//
|
||||
// ABSL_NAMESPACE_END
|
||||
// } // namespace absl
|
||||
//
|
||||
// Users of Abseil should not use these macros, because users of Abseil should
|
||||
// not write `namespace absl {` in their own code for any reason. (Abseil does
|
||||
// not support forward declarations of its own types, nor does it support
|
||||
// user-provided specialization of Abseil templates. Code that violates these
|
||||
// rules may be broken without warning.)
|
||||
#if !defined(ABSL_OPTION_USE_INLINE_NAMESPACE) || \
|
||||
!defined(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// Check that ABSL_OPTION_INLINE_NAMESPACE_NAME is neither "head" nor ""
|
||||
#if defined(__cplusplus) && ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||
|
||||
#define ABSL_INTERNAL_INLINE_NAMESPACE_STR \
|
||||
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||
|
||||
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != '\0',
|
||||
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||
"not be empty.");
|
||||
static_assert(ABSL_INTERNAL_INLINE_NAMESPACE_STR[0] != 'h' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[1] != 'e' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[2] != 'a' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[3] != 'd' ||
|
||||
ABSL_INTERNAL_INLINE_NAMESPACE_STR[4] != '\0',
|
||||
"options.h misconfigured: ABSL_OPTION_INLINE_NAMESPACE_NAME must "
|
||||
"be changed to a new, unique identifier name.");
|
||||
|
||||
#endif
|
||||
|
||||
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||
#define ABSL_NAMESPACE_BEGIN
|
||||
#define ABSL_NAMESPACE_END
|
||||
#define ABSL_INTERNAL_C_SYMBOL(x) x
|
||||
#elif ABSL_OPTION_USE_INLINE_NAMESPACE == 1
|
||||
#define ABSL_NAMESPACE_BEGIN \
|
||||
inline namespace ABSL_OPTION_INLINE_NAMESPACE_NAME {
|
||||
#define ABSL_NAMESPACE_END }
|
||||
#define ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v) x##_##v
|
||||
#define ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, v) \
|
||||
ABSL_INTERNAL_C_SYMBOL_HELPER_2(x, v)
|
||||
#define ABSL_INTERNAL_C_SYMBOL(x) \
|
||||
ABSL_INTERNAL_C_SYMBOL_HELPER_1(x, ABSL_OPTION_INLINE_NAMESPACE_NAME)
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Compiler Feature Checks
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ABSL_HAVE_BUILTIN()
|
||||
//
|
||||
// Checks whether the compiler supports a Clang Feature Checking Macro, and if
|
||||
// so, checks whether it supports the provided builtin function "x" where x
|
||||
// is one of the functions noted in
|
||||
// https://clang.llvm.org/docs/LanguageExtensions.html
|
||||
//
|
||||
// Note: Use this macro to avoid an extra level of #ifdef __has_builtin check.
|
||||
// http://releases.llvm.org/3.3/tools/clang/docs/LanguageExtensions.html
|
||||
#ifdef __has_builtin
|
||||
#define ABSL_HAVE_BUILTIN(x) __has_builtin(x)
|
||||
#else
|
||||
#define ABSL_HAVE_BUILTIN(x) 0
|
||||
#endif
|
||||
|
||||
#ifdef __has_feature
|
||||
#define ABSL_HAVE_FEATURE(f) __has_feature(f)
|
||||
#else
|
||||
#define ABSL_HAVE_FEATURE(f) 0
|
||||
#endif
|
||||
|
||||
// Portable check for GCC minimum version:
|
||||
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) \
|
||||
(__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
|
||||
#else
|
||||
#define ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
|
||||
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) \
|
||||
(__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
|
||||
#else
|
||||
#define ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_TLS is defined to 1 when __thread should be supported.
|
||||
// We assume __thread is supported on Linux when compiled with Clang or
|
||||
// compiled against libstdc++ with _GLIBCXX_HAVE_TLS defined.
|
||||
#ifdef ABSL_HAVE_TLS
|
||||
#error ABSL_HAVE_TLS cannot be directly set
|
||||
#elif (defined(__linux__)) && (defined(__clang__) || defined(_GLIBCXX_HAVE_TLS))
|
||||
#define ABSL_HAVE_TLS 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
||||
//
|
||||
// Checks whether `std::is_trivially_destructible<T>` is supported.
|
||||
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
|
||||
#error ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
|
||||
//
|
||||
// Checks whether `std::is_trivially_default_constructible<T>` and
|
||||
// `std::is_trivially_copy_constructible<T>` are supported.
|
||||
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE
|
||||
#error ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
|
||||
#else
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
|
||||
//
|
||||
// Checks whether `std::is_trivially_copy_assignable<T>` is supported.
|
||||
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE
|
||||
#error ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot be directly set
|
||||
#else
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE
|
||||
//
|
||||
// Checks whether `std::is_trivially_copyable<T>` is supported.
|
||||
#ifdef ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE
|
||||
#error ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE cannot be directly set
|
||||
#define ABSL_HAVE_STD_IS_TRIVIALLY_COPYABLE 1
|
||||
#endif
|
||||
|
||||
|
||||
// ABSL_HAVE_THREAD_LOCAL
|
||||
//
|
||||
// DEPRECATED - `thread_local` is available on all supported platforms.
|
||||
// Checks whether C++11's `thread_local` storage duration specifier is
|
||||
// supported.
|
||||
#ifdef ABSL_HAVE_THREAD_LOCAL
|
||||
#error ABSL_HAVE_THREAD_LOCAL cannot be directly set
|
||||
#else
|
||||
#define ABSL_HAVE_THREAD_LOCAL 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_INTRINSIC_INT128
|
||||
//
|
||||
// Checks whether the __int128 compiler extension for a 128-bit integral type is
|
||||
// supported.
|
||||
//
|
||||
// Note: __SIZEOF_INT128__ is defined by Clang and GCC when __int128 is
|
||||
// supported, but we avoid using it in certain cases:
|
||||
// * On Clang:
|
||||
// * Building using Clang for Windows, where the Clang runtime library has
|
||||
// 128-bit support only on LP64 architectures, but Windows is LLP64.
|
||||
// * On Nvidia's nvcc:
|
||||
// * nvcc also defines __GNUC__ and __SIZEOF_INT128__, but not all versions
|
||||
// actually support __int128.
|
||||
#ifdef ABSL_HAVE_INTRINSIC_INT128
|
||||
#error ABSL_HAVE_INTRINSIC_INT128 cannot be directly set
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
#if (defined(__clang__) && !defined(_WIN32)) || \
|
||||
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
|
||||
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
|
||||
#define ABSL_HAVE_INTRINSIC_INT128 1
|
||||
#elif defined(__CUDACC__)
|
||||
// __CUDACC_VER__ is a full version number before CUDA 9, and is defined to a
|
||||
// string explaining that it has been removed starting with CUDA 9. We use
|
||||
// nested #ifs because there is no short-circuiting in the preprocessor.
|
||||
// NOTE: `__CUDACC__` could be undefined while `__CUDACC_VER__` is defined.
|
||||
#if __CUDACC_VER__ >= 70000
|
||||
#define ABSL_HAVE_INTRINSIC_INT128 1
|
||||
#endif // __CUDACC_VER__ >= 70000
|
||||
#endif // defined(__CUDACC__)
|
||||
#endif // ABSL_HAVE_INTRINSIC_INT128
|
||||
|
||||
// ABSL_HAVE_EXCEPTIONS
|
||||
//
|
||||
// Checks whether the compiler both supports and enables exceptions. Many
|
||||
// compilers support a "no exceptions" mode that disables exceptions.
|
||||
//
|
||||
// Generally, when ABSL_HAVE_EXCEPTIONS is not defined:
|
||||
//
|
||||
// * Code using `throw` and `try` may not compile.
|
||||
// * The `noexcept` specifier will still compile and behave as normal.
|
||||
// * The `noexcept` operator may still return `false`.
|
||||
//
|
||||
// For further details, consult the compiler's documentation.
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
#error ABSL_HAVE_EXCEPTIONS cannot be directly set.
|
||||
#elif ABSL_INTERNAL_HAVE_MIN_CLANG_VERSION(3, 6)
|
||||
// Clang >= 3.6
|
||||
#if ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
#elif defined(__clang__)
|
||||
// Clang < 3.6
|
||||
// http://releases.llvm.org/3.6.0/tools/clang/docs/ReleaseNotes.html#the-exceptions-macro
|
||||
#if defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif // defined(__EXCEPTIONS) && ABSL_HAVE_FEATURE(cxx_exceptions)
|
||||
// Handle remaining special cases and default to exceptions being supported.
|
||||
#elif !(defined(__GNUC__) && !defined(__cpp_exceptions)) && \
|
||||
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
|
||||
#define ABSL_HAVE_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Platform Feature Checks
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Currently supported operating systems and associated preprocessor
|
||||
// symbols:
|
||||
//
|
||||
// Linux and Linux-derived __linux__
|
||||
// Android __ANDROID__ (implies __linux__)
|
||||
// Linux (non-Android) __linux__ && !__ANDROID__
|
||||
// Darwin (macOS and iOS) __APPLE__
|
||||
// Akaros (http://akaros.org) __ros__
|
||||
// Windows _WIN32
|
||||
// NaCL __native_client__
|
||||
// AsmJS __asmjs__
|
||||
// WebAssembly (Emscripten) __EMSCRIPTEN__
|
||||
// Fuchsia __Fuchsia__
|
||||
//
|
||||
// Note that since Android defines both __ANDROID__ and __linux__, one
|
||||
// may probe for either Linux or Android by simply testing for __linux__.
|
||||
|
||||
// ABSL_HAVE_MMAP
|
||||
//
|
||||
// Checks whether the platform has an mmap(2) implementation as defined in
|
||||
// POSIX.1-2001.
|
||||
#ifdef ABSL_HAVE_MMAP
|
||||
#error ABSL_HAVE_MMAP cannot be directly set
|
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||
defined(_AIX) || defined(__ros__) || defined(__native_client__) || \
|
||||
defined(__asmjs__) || defined(__EMSCRIPTEN__) || defined(__Fuchsia__) || \
|
||||
defined(__sun) || defined(__myriad2__) || defined(__HAIKU__) || \
|
||||
defined(__OpenBSD__) || defined(__NetBSD__) || defined(__QNX__) || \
|
||||
defined(__VXWORKS__) || defined(__hexagon__)
|
||||
#define ABSL_HAVE_MMAP 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
||||
//
|
||||
// Checks whether the platform implements the pthread_(get|set)schedparam(3)
|
||||
// functions as defined in POSIX.1-2001.
|
||||
#ifdef ABSL_HAVE_PTHREAD_GETSCHEDPARAM
|
||||
#error ABSL_HAVE_PTHREAD_GETSCHEDPARAM cannot be directly set
|
||||
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
|
||||
defined(_AIX) || defined(__ros__) || defined(__OpenBSD__) || \
|
||||
defined(__NetBSD__) || defined(__VXWORKS__)
|
||||
#define ABSL_HAVE_PTHREAD_GETSCHEDPARAM 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_SCHED_GETCPU
|
||||
//
|
||||
// Checks whether sched_getcpu is available.
|
||||
#ifdef ABSL_HAVE_SCHED_GETCPU
|
||||
#error ABSL_HAVE_SCHED_GETCPU cannot be directly set
|
||||
#elif defined(__linux__)
|
||||
#define ABSL_HAVE_SCHED_GETCPU 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_SCHED_YIELD
|
||||
//
|
||||
// Checks whether the platform implements sched_yield(2) as defined in
|
||||
// POSIX.1-2001.
|
||||
#ifdef ABSL_HAVE_SCHED_YIELD
|
||||
#error ABSL_HAVE_SCHED_YIELD cannot be directly set
|
||||
#elif defined(__linux__) || defined(__ros__) || defined(__native_client__) || \
|
||||
defined(__VXWORKS__)
|
||||
#define ABSL_HAVE_SCHED_YIELD 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_SEMAPHORE_H
|
||||
//
|
||||
// Checks whether the platform supports the <semaphore.h> header and sem_init(3)
|
||||
// family of functions as standardized in POSIX.1-2001.
|
||||
//
|
||||
// Note: While Apple provides <semaphore.h> for both iOS and macOS, it is
|
||||
// explicitly deprecated and will cause build failures if enabled for those
|
||||
// platforms. We side-step the issue by not defining it here for Apple
|
||||
// platforms.
|
||||
#ifdef ABSL_HAVE_SEMAPHORE_H
|
||||
#error ABSL_HAVE_SEMAPHORE_H cannot be directly set
|
||||
#elif defined(__linux__) || defined(__ros__) || defined(__VXWORKS__)
|
||||
#define ABSL_HAVE_SEMAPHORE_H 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_ALARM
|
||||
//
|
||||
// Checks whether the platform supports the <signal.h> header and alarm(2)
|
||||
// function as standardized in POSIX.1-2001.
|
||||
#ifdef ABSL_HAVE_ALARM
|
||||
#error ABSL_HAVE_ALARM cannot be directly set
|
||||
#elif defined(__GOOGLE_GRTE_VERSION__)
|
||||
// feature tests for Google's GRTE
|
||||
#define ABSL_HAVE_ALARM 1
|
||||
#elif defined(__GLIBC__)
|
||||
// feature test for glibc
|
||||
#define ABSL_HAVE_ALARM 1
|
||||
#elif defined(_MSC_VER)
|
||||
// feature tests for Microsoft's library
|
||||
#elif defined(__MINGW32__)
|
||||
// mingw32 doesn't provide alarm(2):
|
||||
// https://osdn.net/projects/mingw/scm/git/mingw-org-wsl/blobs/5.2-trunk/mingwrt/include/unistd.h
|
||||
// mingw-w64 provides a no-op implementation:
|
||||
// https://sourceforge.net/p/mingw-w64/mingw-w64/ci/master/tree/mingw-w64-crt/misc/alarm.c
|
||||
#elif defined(__EMSCRIPTEN__)
|
||||
// emscripten doesn't support signals
|
||||
#elif defined(__wasi__)
|
||||
// WASI doesn't support signals
|
||||
#elif defined(__Fuchsia__)
|
||||
// Signals don't exist on fuchsia.
|
||||
#elif defined(__native_client__)
|
||||
// Signals don't exist on hexagon/QuRT
|
||||
#elif defined(__hexagon__)
|
||||
#else
|
||||
// other standard libraries
|
||||
#define ABSL_HAVE_ALARM 1
|
||||
#endif
|
||||
|
||||
// ABSL_IS_LITTLE_ENDIAN
|
||||
// ABSL_IS_BIG_ENDIAN
|
||||
//
|
||||
// Checks the endianness of the platform.
|
||||
//
|
||||
// Notes: uses the built in endian macros provided by GCC (since 4.6) and
|
||||
// Clang (since 3.2); see
|
||||
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html.
|
||||
// Otherwise, if _WIN32, assume little endian. Otherwise, bail with an error.
|
||||
#if defined(ABSL_IS_BIG_ENDIAN)
|
||||
#error "ABSL_IS_BIG_ENDIAN cannot be directly set."
|
||||
#endif
|
||||
#if defined(ABSL_IS_LITTLE_ENDIAN)
|
||||
#error "ABSL_IS_LITTLE_ENDIAN cannot be directly set."
|
||||
#endif
|
||||
|
||||
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
|
||||
#define ABSL_IS_LITTLE_ENDIAN 1
|
||||
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
|
||||
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
#define ABSL_IS_BIG_ENDIAN 1
|
||||
#elif defined(_WIN32)
|
||||
#define ABSL_IS_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#error "absl endian detection needs to be set up for your compiler"
|
||||
#endif
|
||||
|
||||
// macOS < 10.13 and iOS < 12 don't support <any>, <optional>, or <variant>
|
||||
// because the libc++ shared library shipped on the system doesn't have the
|
||||
// requisite exported symbols. See
|
||||
// https://github.com/abseil/abseil-cpp/issues/207 and
|
||||
// https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes
|
||||
//
|
||||
// libc++ spells out the availability requirements in the file
|
||||
// llvm-project/libcxx/include/__config via the #define
|
||||
// _LIBCPP_AVAILABILITY_BAD_OPTIONAL_ACCESS. The set of versions has been
|
||||
// modified a few times, via
|
||||
// https://github.com/llvm/llvm-project/commit/7fb40e1569dd66292b647f4501b85517e9247953
|
||||
// and
|
||||
// https://github.com/llvm/llvm-project/commit/0bc451e7e137c4ccadcd3377250874f641ca514a
|
||||
// The second has the actually correct versions, thus, is what we copy here.
|
||||
#if defined(__APPLE__) && \
|
||||
((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
|
||||
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300) || \
|
||||
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \
|
||||
__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 120000) || \
|
||||
(defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \
|
||||
__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ < 50000) || \
|
||||
(defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \
|
||||
__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 120000))
|
||||
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 1
|
||||
#else
|
||||
#define ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE 0
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_ANY
|
||||
//
|
||||
// Checks whether C++17 std::any is available.
|
||||
#ifdef ABSL_HAVE_STD_ANY
|
||||
#error "ABSL_HAVE_STD_ANY cannot be directly set."
|
||||
#elif defined(__cpp_lib_any) && __cpp_lib_any >= 201606L
|
||||
#define ABSL_HAVE_STD_ANY 1
|
||||
#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_ANY 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_OPTIONAL
|
||||
//
|
||||
// Checks whether C++17 std::optional is available.
|
||||
#ifdef ABSL_HAVE_STD_OPTIONAL
|
||||
#error "ABSL_HAVE_STD_OPTIONAL cannot be directly set."
|
||||
#elif defined(__cpp_lib_optional) && __cpp_lib_optional >= 202106L
|
||||
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||
#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_OPTIONAL 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_VARIANT
|
||||
//
|
||||
// Checks whether C++17 std::variant is available.
|
||||
#ifdef ABSL_HAVE_STD_VARIANT
|
||||
#error "ABSL_HAVE_STD_VARIANT cannot be directly set."
|
||||
#elif defined(__cpp_lib_variant) && __cpp_lib_variant >= 201606L
|
||||
#define ABSL_HAVE_STD_VARIANT 1
|
||||
#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L && \
|
||||
!ABSL_INTERNAL_APPLE_CXX17_TYPES_UNAVAILABLE
|
||||
#define ABSL_HAVE_STD_VARIANT 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_STRING_VIEW
|
||||
//
|
||||
// Checks whether C++17 std::string_view is available.
|
||||
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||
#error "ABSL_HAVE_STD_STRING_VIEW cannot be directly set."
|
||||
#elif defined(__cpp_lib_string_view) && __cpp_lib_string_view >= 201606L
|
||||
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||
#elif defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||
#define ABSL_HAVE_STD_STRING_VIEW 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_STD_ORDERING
|
||||
//
|
||||
// Checks whether C++20 std::{partial,weak,strong}_ordering are available.
|
||||
//
|
||||
// __cpp_lib_three_way_comparison is missing on libc++
|
||||
// (https://github.com/llvm/llvm-project/issues/73953) so treat it as defined
|
||||
// when building in C++20 mode.
|
||||
#ifdef ABSL_HAVE_STD_ORDERING
|
||||
#error "ABSL_HAVE_STD_ORDERING cannot be directly set."
|
||||
#elif (defined(__cpp_lib_three_way_comparison) && \
|
||||
__cpp_lib_three_way_comparison >= 201907L) || \
|
||||
(defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L)
|
||||
#define ABSL_HAVE_STD_ORDERING 1
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_ANY
|
||||
//
|
||||
// Indicates whether absl::any is an alias for std::any.
|
||||
#if !defined(ABSL_OPTION_USE_STD_ANY)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_ANY == 0 || \
|
||||
(ABSL_OPTION_USE_STD_ANY == 2 && !defined(ABSL_HAVE_STD_ANY))
|
||||
#undef ABSL_USES_STD_ANY
|
||||
#elif ABSL_OPTION_USE_STD_ANY == 1 || \
|
||||
(ABSL_OPTION_USE_STD_ANY == 2 && defined(ABSL_HAVE_STD_ANY))
|
||||
#define ABSL_USES_STD_ANY 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_OPTIONAL
|
||||
//
|
||||
// Indicates whether absl::optional is an alias for std::optional.
|
||||
#if !defined(ABSL_OPTION_USE_STD_OPTIONAL)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_OPTIONAL == 0 || \
|
||||
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && !defined(ABSL_HAVE_STD_OPTIONAL))
|
||||
#undef ABSL_USES_STD_OPTIONAL
|
||||
#elif ABSL_OPTION_USE_STD_OPTIONAL == 1 || \
|
||||
(ABSL_OPTION_USE_STD_OPTIONAL == 2 && defined(ABSL_HAVE_STD_OPTIONAL))
|
||||
#define ABSL_USES_STD_OPTIONAL 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_VARIANT
|
||||
//
|
||||
// Indicates whether absl::variant is an alias for std::variant.
|
||||
#if !defined(ABSL_OPTION_USE_STD_VARIANT)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_VARIANT == 0 || \
|
||||
(ABSL_OPTION_USE_STD_VARIANT == 2 && !defined(ABSL_HAVE_STD_VARIANT))
|
||||
#undef ABSL_USES_STD_VARIANT
|
||||
#elif ABSL_OPTION_USE_STD_VARIANT == 1 || \
|
||||
(ABSL_OPTION_USE_STD_VARIANT == 2 && defined(ABSL_HAVE_STD_VARIANT))
|
||||
#define ABSL_USES_STD_VARIANT 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_STRING_VIEW
|
||||
//
|
||||
// Indicates whether absl::string_view is an alias for std::string_view.
|
||||
#if !defined(ABSL_OPTION_USE_STD_STRING_VIEW)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 0 || \
|
||||
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||
!defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||
#undef ABSL_USES_STD_STRING_VIEW
|
||||
#elif ABSL_OPTION_USE_STD_STRING_VIEW == 1 || \
|
||||
(ABSL_OPTION_USE_STD_STRING_VIEW == 2 && \
|
||||
defined(ABSL_HAVE_STD_STRING_VIEW))
|
||||
#define ABSL_USES_STD_STRING_VIEW 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// ABSL_USES_STD_ORDERING
|
||||
//
|
||||
// Indicates whether absl::{partial,weak,strong}_ordering are aliases for the
|
||||
// std:: ordering types.
|
||||
#if !defined(ABSL_OPTION_USE_STD_ORDERING)
|
||||
#error options.h is misconfigured.
|
||||
#elif ABSL_OPTION_USE_STD_ORDERING == 0 || \
|
||||
(ABSL_OPTION_USE_STD_ORDERING == 2 && !defined(ABSL_HAVE_STD_ORDERING))
|
||||
#undef ABSL_USES_STD_ORDERING
|
||||
#elif ABSL_OPTION_USE_STD_ORDERING == 1 || \
|
||||
(ABSL_OPTION_USE_STD_ORDERING == 2 && defined(ABSL_HAVE_STD_ORDERING))
|
||||
#define ABSL_USES_STD_ORDERING 1
|
||||
#else
|
||||
#error options.h is misconfigured.
|
||||
#endif
|
||||
|
||||
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
|
||||
// SEH exception from emplace for variant<SomeStruct> when constructing the
|
||||
// struct can throw. This defeats some of variant_test and
|
||||
// variant_exception_safety_test.
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
|
||||
#define ABSL_INTERNAL_MSVC_2017_DBG_MODE
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_MANGLED_NS
|
||||
// ABSL_INTERNAL_MANGLED_BACKREFERENCE
|
||||
//
|
||||
// Internal macros for building up mangled names in our internal fork of CCTZ.
|
||||
// This implementation detail is only needed and provided for the MSVC build.
|
||||
//
|
||||
// These macros both expand to string literals. ABSL_INTERNAL_MANGLED_NS is
|
||||
// the mangled spelling of the `absl` namespace, and
|
||||
// ABSL_INTERNAL_MANGLED_BACKREFERENCE is a back-reference integer representing
|
||||
// the proper count to skip past the CCTZ fork namespace names. (This number
|
||||
// is one larger when there is an inline namespace name to skip.)
|
||||
#if defined(_MSC_VER)
|
||||
#if ABSL_OPTION_USE_INLINE_NAMESPACE == 0
|
||||
#define ABSL_INTERNAL_MANGLED_NS "absl"
|
||||
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "5"
|
||||
#else
|
||||
#define ABSL_INTERNAL_MANGLED_NS \
|
||||
ABSL_INTERNAL_TOKEN_STR(ABSL_OPTION_INLINE_NAMESPACE_NAME) "@absl"
|
||||
#define ABSL_INTERNAL_MANGLED_BACKREFERENCE "6"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ABSL_DLL
|
||||
//
|
||||
// When building Abseil as a DLL, this macro expands to `__declspec(dllexport)`
|
||||
// so we can annotate symbols appropriately as being exported. When used in
|
||||
// headers consuming a DLL, this macro expands to `__declspec(dllimport)` so
|
||||
// that consumers know the symbol is defined inside the DLL. In all other cases,
|
||||
// the macro expands to nothing.
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(ABSL_BUILD_DLL)
|
||||
#define ABSL_DLL __declspec(dllexport)
|
||||
#elif defined(ABSL_CONSUME_DLL)
|
||||
#define ABSL_DLL __declspec(dllimport)
|
||||
#else
|
||||
#define ABSL_DLL
|
||||
#endif
|
||||
#else
|
||||
#define ABSL_DLL
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(ABSL_BUILD_TEST_DLL)
|
||||
#define ABSL_TEST_DLL __declspec(dllexport)
|
||||
#elif defined(ABSL_CONSUME_TEST_DLL)
|
||||
#define ABSL_TEST_DLL __declspec(dllimport)
|
||||
#else
|
||||
#define ABSL_TEST_DLL
|
||||
#endif
|
||||
#else
|
||||
#define ABSL_TEST_DLL
|
||||
#endif // defined(_MSC_VER)
|
||||
|
||||
// ABSL_HAVE_MEMORY_SANITIZER
|
||||
//
|
||||
// MemorySanitizer (MSan) is a detector of uninitialized reads. It consists of
|
||||
// a compiler instrumentation module and a run-time library.
|
||||
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||
#error "ABSL_HAVE_MEMORY_SANITIZER cannot be directly set."
|
||||
#elif !defined(__native_client__) && ABSL_HAVE_FEATURE(memory_sanitizer)
|
||||
#define ABSL_HAVE_MEMORY_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_THREAD_SANITIZER
|
||||
//
|
||||
// ThreadSanitizer (TSan) is a fast data race detector.
|
||||
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||
#error "ABSL_HAVE_THREAD_SANITIZER cannot be directly set."
|
||||
#elif defined(__SANITIZE_THREAD__)
|
||||
#define ABSL_HAVE_THREAD_SANITIZER 1
|
||||
#elif ABSL_HAVE_FEATURE(thread_sanitizer)
|
||||
#define ABSL_HAVE_THREAD_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_ADDRESS_SANITIZER
|
||||
//
|
||||
// AddressSanitizer (ASan) is a fast memory error detector.
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
#error "ABSL_HAVE_ADDRESS_SANITIZER cannot be directly set."
|
||||
#elif defined(__SANITIZE_ADDRESS__)
|
||||
#define ABSL_HAVE_ADDRESS_SANITIZER 1
|
||||
#elif ABSL_HAVE_FEATURE(address_sanitizer)
|
||||
#define ABSL_HAVE_ADDRESS_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_HWADDRESS_SANITIZER
|
||||
//
|
||||
// Hardware-Assisted AddressSanitizer (or HWASAN) is even faster than asan
|
||||
// memory error detector which can use CPU features like ARM TBI, Intel LAM or
|
||||
// AMD UAI.
|
||||
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
|
||||
#error "ABSL_HAVE_HWADDRESS_SANITIZER cannot be directly set."
|
||||
#elif defined(__SANITIZE_HWADDRESS__)
|
||||
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
|
||||
#elif ABSL_HAVE_FEATURE(hwaddress_sanitizer)
|
||||
#define ABSL_HAVE_HWADDRESS_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_DATAFLOW_SANITIZER
|
||||
//
|
||||
// Dataflow Sanitizer (or DFSAN) is a generalised dynamic data flow analysis.
|
||||
#ifdef ABSL_HAVE_DATAFLOW_SANITIZER
|
||||
#error "ABSL_HAVE_DATAFLOW_SANITIZER cannot be directly set."
|
||||
#elif defined(DATAFLOW_SANITIZER)
|
||||
// GCC provides no method for detecting the presence of the standalone
|
||||
// DataFlowSanitizer (-fsanitize=dataflow), so GCC users of -fsanitize=dataflow
|
||||
// should also use -DDATAFLOW_SANITIZER.
|
||||
#define ABSL_HAVE_DATAFLOW_SANITIZER 1
|
||||
#elif ABSL_HAVE_FEATURE(dataflow_sanitizer)
|
||||
#define ABSL_HAVE_DATAFLOW_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_LEAK_SANITIZER
|
||||
//
|
||||
// LeakSanitizer (or lsan) is a detector of memory leaks.
|
||||
// https://clang.llvm.org/docs/LeakSanitizer.html
|
||||
// https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
|
||||
//
|
||||
// The macro ABSL_HAVE_LEAK_SANITIZER can be used to detect at compile-time
|
||||
// whether the LeakSanitizer is potentially available. However, just because the
|
||||
// LeakSanitizer is available does not mean it is active. Use the
|
||||
// always-available run-time interface in //absl/debugging/leak_check.h for
|
||||
// interacting with LeakSanitizer.
|
||||
#ifdef ABSL_HAVE_LEAK_SANITIZER
|
||||
#error "ABSL_HAVE_LEAK_SANITIZER cannot be directly set."
|
||||
#elif defined(LEAK_SANITIZER)
|
||||
// GCC provides no method for detecting the presence of the standalone
|
||||
// LeakSanitizer (-fsanitize=leak), so GCC users of -fsanitize=leak should also
|
||||
// use -DLEAK_SANITIZER.
|
||||
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||
// Clang standalone LeakSanitizer (-fsanitize=leak)
|
||||
#elif ABSL_HAVE_FEATURE(leak_sanitizer)
|
||||
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||
#elif defined(ABSL_HAVE_ADDRESS_SANITIZER)
|
||||
// GCC or Clang using the LeakSanitizer integrated into AddressSanitizer.
|
||||
#define ABSL_HAVE_LEAK_SANITIZER 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
|
||||
//
|
||||
// Class template argument deduction is a language feature added in C++17.
|
||||
#ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION
|
||||
#error "ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION cannot be directly set."
|
||||
#elif defined(__cpp_deduction_guides)
|
||||
#define ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
//
|
||||
// Prior to C++17, static constexpr variables defined in classes required a
|
||||
// separate definition outside of the class body, for example:
|
||||
//
|
||||
// class Foo {
|
||||
// static constexpr int kBar = 0;
|
||||
// };
|
||||
// constexpr int Foo::kBar;
|
||||
//
|
||||
// In C++17, these variables defined in classes are considered inline variables,
|
||||
// and the extra declaration is redundant. Since some compilers warn on the
|
||||
// extra declarations, ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL can be used
|
||||
// conditionally ignore them:
|
||||
//
|
||||
// #ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
// constexpr int Foo::kBar;
|
||||
// #endif
|
||||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG < 201703L
|
||||
#define ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL 1
|
||||
#endif
|
||||
|
||||
// `ABSL_INTERNAL_HAS_RTTI` determines whether abseil is being compiled with
|
||||
// RTTI support.
|
||||
#ifdef ABSL_INTERNAL_HAS_RTTI
|
||||
#error ABSL_INTERNAL_HAS_RTTI cannot be directly set
|
||||
#elif ABSL_HAVE_FEATURE(cxx_rtti)
|
||||
#define ABSL_INTERNAL_HAS_RTTI 1
|
||||
#elif defined(__GNUC__) && defined(__GXX_RTTI)
|
||||
#define ABSL_INTERNAL_HAS_RTTI 1
|
||||
#elif defined(_MSC_VER) && defined(_CPPRTTI)
|
||||
#define ABSL_INTERNAL_HAS_RTTI 1
|
||||
#elif !defined(__GNUC__) && !defined(_MSC_VER)
|
||||
// Unknown compiler, default to RTTI
|
||||
#define ABSL_INTERNAL_HAS_RTTI 1
|
||||
#endif
|
||||
|
||||
// `ABSL_INTERNAL_HAS_CXA_DEMANGLE` determines whether `abi::__cxa_demangle` is
|
||||
// available.
|
||||
#ifdef ABSL_INTERNAL_HAS_CXA_DEMANGLE
|
||||
#error ABSL_INTERNAL_HAS_CXA_DEMANGLE cannot be directly set
|
||||
#elif defined(OS_ANDROID) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 0
|
||||
#elif defined(__GNUC__)
|
||||
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1
|
||||
#elif defined(__clang__) && !defined(_MSC_VER)
|
||||
#define ABSL_INTERNAL_HAS_CXA_DEMANGLE 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_HAVE_SSE is used for compile-time detection of SSE support.
|
||||
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||
// which architectures support the various x86 instruction sets.
|
||||
#ifdef ABSL_INTERNAL_HAVE_SSE
|
||||
#error ABSL_INTERNAL_HAVE_SSE cannot be directly set
|
||||
#elif defined(__SSE__)
|
||||
#define ABSL_INTERNAL_HAVE_SSE 1
|
||||
#elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) && \
|
||||
!defined(_M_ARM64EC)
|
||||
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 1
|
||||
// indicates that at least SSE was targeted with the /arch:SSE option.
|
||||
// All x86-64 processors support SSE, so support can be assumed.
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
#define ABSL_INTERNAL_HAVE_SSE 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_HAVE_SSE2 is used for compile-time detection of SSE2 support.
|
||||
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||
// which architectures support the various x86 instruction sets.
|
||||
#ifdef ABSL_INTERNAL_HAVE_SSE2
|
||||
#error ABSL_INTERNAL_HAVE_SSE2 cannot be directly set
|
||||
#elif defined(__SSE2__)
|
||||
#define ABSL_INTERNAL_HAVE_SSE2 1
|
||||
#elif (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)) && \
|
||||
!defined(_M_ARM64EC)
|
||||
// MSVC only defines _M_IX86_FP for x86 32-bit code, and _M_IX86_FP >= 2
|
||||
// indicates that at least SSE2 was targeted with the /arch:SSE2 option.
|
||||
// All x86-64 processors support SSE2, so support can be assumed.
|
||||
// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
#define ABSL_INTERNAL_HAVE_SSE2 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_HAVE_SSSE3 is used for compile-time detection of SSSE3 support.
|
||||
// See https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html for an overview of
|
||||
// which architectures support the various x86 instruction sets.
|
||||
//
|
||||
// MSVC does not have a mode that targets SSSE3 at compile-time. To use SSSE3
|
||||
// with MSVC requires either assuming that the code will only every run on CPUs
|
||||
// that support SSSE3, otherwise __cpuid() can be used to detect support at
|
||||
// runtime and fallback to a non-SSSE3 implementation when SSSE3 is unsupported
|
||||
// by the CPU.
|
||||
#ifdef ABSL_INTERNAL_HAVE_SSSE3
|
||||
#error ABSL_INTERNAL_HAVE_SSSE3 cannot be directly set
|
||||
#elif defined(__SSSE3__)
|
||||
#define ABSL_INTERNAL_HAVE_SSSE3 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_HAVE_ARM_NEON is used for compile-time detection of NEON (ARM
|
||||
// SIMD).
|
||||
//
|
||||
// If __CUDA_ARCH__ is defined, then we are compiling CUDA code in device mode.
|
||||
// In device mode, NEON intrinsics are not available, regardless of host
|
||||
// platform.
|
||||
// https://llvm.org/docs/CompileCudaWithLLVM.html#detecting-clang-vs-nvcc-from-code
|
||||
#ifdef ABSL_INTERNAL_HAVE_ARM_NEON
|
||||
#error ABSL_INTERNAL_HAVE_ARM_NEON cannot be directly set
|
||||
#elif defined(__ARM_NEON) && !defined(__CUDA_ARCH__)
|
||||
#define ABSL_INTERNAL_HAVE_ARM_NEON 1
|
||||
#endif
|
||||
|
||||
// ABSL_HAVE_CONSTANT_EVALUATED is used for compile-time detection of
|
||||
// constant evaluation support through `absl::is_constant_evaluated`.
|
||||
#ifdef ABSL_HAVE_CONSTANT_EVALUATED
|
||||
#error ABSL_HAVE_CONSTANT_EVALUATED cannot be directly set
|
||||
#endif
|
||||
#ifdef __cpp_lib_is_constant_evaluated
|
||||
#define ABSL_HAVE_CONSTANT_EVALUATED 1
|
||||
#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated)
|
||||
#define ABSL_HAVE_CONSTANT_EVALUATED 1
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_CONSTEXPR_SINCE_CXXYY is used to conditionally define constexpr
|
||||
// for different C++ versions.
|
||||
//
|
||||
// These macros are an implementation detail and will be unconditionally removed
|
||||
// once the minimum supported C++ version catches up to a given version.
|
||||
//
|
||||
// For this reason, this symbol is considered INTERNAL and code outside of
|
||||
// Abseil must not use it.
|
||||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17 constexpr
|
||||
#else
|
||||
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX17
|
||||
#endif
|
||||
#if defined(ABSL_INTERNAL_CPLUSPLUS_LANG) && \
|
||||
ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
|
||||
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20 constexpr
|
||||
#else
|
||||
#define ABSL_INTERNAL_CONSTEXPR_SINCE_CXX20
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_EMSCRIPTEN_VERSION combines Emscripten's three version macros
|
||||
// into an integer that can be compared against.
|
||||
#ifdef ABSL_INTERNAL_EMSCRIPTEN_VERSION
|
||||
#error ABSL_INTERNAL_EMSCRIPTEN_VERSION cannot be directly set
|
||||
#endif
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/version.h>
|
||||
#ifdef __EMSCRIPTEN_major__
|
||||
#if __EMSCRIPTEN_minor__ >= 1000
|
||||
#error __EMSCRIPTEN_minor__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION
|
||||
#endif
|
||||
#if __EMSCRIPTEN_tiny__ >= 1000
|
||||
#error __EMSCRIPTEN_tiny__ is too big to fit in ABSL_INTERNAL_EMSCRIPTEN_VERSION
|
||||
#endif
|
||||
#define ABSL_INTERNAL_EMSCRIPTEN_VERSION \
|
||||
((__EMSCRIPTEN_major__) * 1000000 + (__EMSCRIPTEN_minor__) * 1000 + \
|
||||
(__EMSCRIPTEN_tiny__))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_CONFIG_H_
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// kConstInit
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// A constructor tag used to mark an object as safe for use as a global
|
||||
// variable, avoiding the usual lifetime issues that can affect globals.
|
||||
|
||||
#ifndef ABSL_BASE_CONST_INIT_H_
|
||||
#define ABSL_BASE_CONST_INIT_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// In general, objects with static storage duration (such as global variables)
|
||||
// can trigger tricky object lifetime situations. Attempting to access them
|
||||
// from the constructors or destructors of other global objects can result in
|
||||
// undefined behavior, unless their constructors and destructors are designed
|
||||
// with this issue in mind.
|
||||
//
|
||||
// The normal way to deal with this issue in C++11 is to use constant
|
||||
// initialization and trivial destructors.
|
||||
//
|
||||
// Constant initialization is guaranteed to occur before any other code
|
||||
// executes. Constructors that are declared 'constexpr' are eligible for
|
||||
// constant initialization. You can annotate a variable declaration with the
|
||||
// ABSL_CONST_INIT macro to express this intent. For compilers that support
|
||||
// it, this annotation will cause a compilation error for declarations that
|
||||
// aren't subject to constant initialization (perhaps because a runtime value
|
||||
// was passed as a constructor argument).
|
||||
//
|
||||
// On program shutdown, lifetime issues can be avoided on global objects by
|
||||
// ensuring that they contain trivial destructors. A class has a trivial
|
||||
// destructor unless it has a user-defined destructor, a virtual method or base
|
||||
// class, or a data member or base class with a non-trivial destructor of its
|
||||
// own. Objects with static storage duration and a trivial destructor are not
|
||||
// cleaned up on program shutdown, and are thus safe to access from other code
|
||||
// running during shutdown.
|
||||
//
|
||||
// For a few core Abseil classes, we make a best effort to allow for safe global
|
||||
// instances, even though these classes have non-trivial destructors. These
|
||||
// objects can be created with the absl::kConstInit tag. For example:
|
||||
// ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
|
||||
//
|
||||
// The line above declares a global variable of type absl::Mutex which can be
|
||||
// accessed at any point during startup or shutdown. global_mutex's destructor
|
||||
// will still run, but will not invalidate the object. Note that C++ specifies
|
||||
// that accessing an object after its destructor has run results in undefined
|
||||
// behavior, but this pattern works on the toolchains we support.
|
||||
//
|
||||
// The absl::kConstInit tag should only be used to define objects with static
|
||||
// or thread_local storage duration.
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
enum ConstInitType {
|
||||
kConstInit,
|
||||
};
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_CONST_INIT_H_
|
||||
@@ -0,0 +1,480 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// This file defines dynamic annotations for use with dynamic analysis tool
|
||||
// such as valgrind, PIN, etc.
|
||||
//
|
||||
// Dynamic annotation is a source code annotation that affects the generated
|
||||
// code (that is, the annotation is not a comment). Each such annotation is
|
||||
// attached to a particular instruction and/or to a particular object (address)
|
||||
// in the program.
|
||||
//
|
||||
// The annotations that should be used by users are macros in all upper-case
|
||||
// (e.g., ABSL_ANNOTATE_THREAD_NAME).
|
||||
//
|
||||
// Actual implementation of these macros may differ depending on the dynamic
|
||||
// analysis tool being used.
|
||||
//
|
||||
// This file supports the following configurations:
|
||||
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
|
||||
// In this case, macros expand to functions implemented by Thread Sanitizer,
|
||||
// when building with TSan. When not provided an external implementation,
|
||||
// dynamic_annotations.cc provides no-op implementations.
|
||||
//
|
||||
// - Static Clang thread-safety warnings enabled.
|
||||
// When building with a Clang compiler that supports thread-safety warnings,
|
||||
// a subset of annotations can be statically-checked at compile-time. We
|
||||
// expand these macros to static-inline functions that can be analyzed for
|
||||
// thread-safety, but afterwards elided when building the final binary.
|
||||
//
|
||||
// - All annotations are disabled.
|
||||
// If neither Dynamic Annotations nor Clang thread-safety warnings are
|
||||
// enabled, then all annotation-macros expand to empty.
|
||||
|
||||
#ifndef ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||
#define ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#ifdef __cplusplus
|
||||
#include "absl/base/macros.h"
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
|
||||
#include <sanitizer/hwasan_interface.h>
|
||||
#endif
|
||||
|
||||
// TODO(rogeeff): Remove after the backward compatibility period.
|
||||
#include "absl/base/internal/dynamic_annotations.h" // IWYU pragma: export
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Decide which features are enabled.
|
||||
|
||||
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||
|
||||
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
|
||||
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
|
||||
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
|
||||
|
||||
// Clang provides limited support for static thread-safety analysis through a
|
||||
// feature called Annotalysis. We configure macro-definitions according to
|
||||
// whether Annotalysis support is available. When running in opt-mode, GCC
|
||||
// will issue a warning, if these attributes are compiled. Only include them
|
||||
// when compiling using Clang.
|
||||
|
||||
#if defined(__clang__)
|
||||
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 1
|
||||
#if !defined(SWIG)
|
||||
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
|
||||
#endif
|
||||
#else
|
||||
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||
#endif
|
||||
|
||||
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
|
||||
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
|
||||
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||
|
||||
#endif // ABSL_HAVE_THREAD_SANITIZER
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
|
||||
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
|
||||
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
|
||||
#define ABSL_INTERNAL_STATIC_INLINE inline
|
||||
#else
|
||||
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
|
||||
#define ABSL_INTERNAL_END_EXTERN_C // empty
|
||||
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
|
||||
#define ABSL_INTERNAL_STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define race annotations.
|
||||
|
||||
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
|
||||
// Some of the symbols used in this section (e.g. AnnotateBenignRaceSized) are
|
||||
// defined by the compiler-based sanitizer implementation, not by the Abseil
|
||||
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations that suppress errors. It is usually better to express the
|
||||
// program's synchronization using the other annotations, but these can be used
|
||||
// when all else fails.
|
||||
|
||||
// Report that we may have a benign race at `pointer`, with size
|
||||
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
|
||||
// point where `pointer` has been allocated, preferably close to the point
|
||||
// where the race happens. See also ABSL_ANNOTATE_BENIGN_RACE_STATIC.
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE(pointer, description) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
|
||||
|
||||
// Same as ABSL_ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
|
||||
// the memory range [`address`, `address`+`size`).
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||
(__FILE__, __LINE__, address, size, description)
|
||||
|
||||
// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
|
||||
// This annotation could be useful if you want to skip expensive race analysis
|
||||
// during some period of program execution, e.g. during initialization.
|
||||
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
|
||||
(__FILE__, __LINE__, enable)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations useful for debugging.
|
||||
|
||||
// Report the current thread `name` to a race detector.
|
||||
#define ABSL_ANNOTATE_THREAD_NAME(name) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations useful when implementing locks. They are not normally needed by
|
||||
// modules that merely use locks. The `lock` argument is a pointer to the lock
|
||||
// object.
|
||||
|
||||
// Report that a lock has been created at address `lock`.
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
|
||||
|
||||
// Report that a linker initialized lock has been created at address `lock`.
|
||||
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
|
||||
(__FILE__, __LINE__, lock)
|
||||
#else
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||
ABSL_ANNOTATE_RWLOCK_CREATE(lock)
|
||||
#endif
|
||||
|
||||
// Report that the lock at address `lock` is about to be destroyed.
|
||||
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
|
||||
|
||||
// Report that the lock at address `lock` has been acquired.
|
||||
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
|
||||
(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
// Report that the lock at address `lock` is about to be released.
|
||||
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
|
||||
(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
// Apply ABSL_ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
|
||||
namespace { \
|
||||
class static_var##_annotator { \
|
||||
public: \
|
||||
static_var##_annotator() { \
|
||||
ABSL_ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
|
||||
#static_var ": " description); \
|
||||
} \
|
||||
}; \
|
||||
static static_var##_annotator the##static_var##_annotator; \
|
||||
} // namespace
|
||||
|
||||
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||
// implementation.
|
||||
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||
void AnnotateRWLockCreate(const char* file, int line,
|
||||
const volatile void* lock);
|
||||
void AnnotateRWLockCreateStatic(const char* file, int line,
|
||||
const volatile void* lock);
|
||||
void AnnotateRWLockDestroy(const char* file, int line,
|
||||
const volatile void* lock);
|
||||
void AnnotateRWLockAcquired(const char* file, int line,
|
||||
const volatile void* lock, long is_w); // NOLINT
|
||||
void AnnotateRWLockReleased(const char* file, int line,
|
||||
const volatile void* lock, long is_w); // NOLINT
|
||||
void AnnotateBenignRace(const char* file, int line,
|
||||
const volatile void* address, const char* description);
|
||||
void AnnotateBenignRaceSized(const char* file, int line,
|
||||
const volatile void* address, size_t size,
|
||||
const char* description);
|
||||
void AnnotateThreadName(const char* file, int line, const char* name);
|
||||
void AnnotateEnableRaceDetection(const char* file, int line, int enable);
|
||||
ABSL_INTERNAL_END_EXTERN_C
|
||||
|
||||
#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
|
||||
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE(lock) // empty
|
||||
#define ABSL_ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
|
||||
#define ABSL_ANNOTATE_RWLOCK_DESTROY(lock) // empty
|
||||
#define ABSL_ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
|
||||
#define ABSL_ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE(address, description) // empty
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
|
||||
#define ABSL_ANNOTATE_THREAD_NAME(name) // empty
|
||||
#define ABSL_ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
|
||||
#define ABSL_ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
|
||||
|
||||
#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define memory annotations.
|
||||
|
||||
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||
__msan_unpoison(address, size)
|
||||
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||
__msan_allocated_memory(address, size)
|
||||
|
||||
#else // !defined(ABSL_HAVE_MEMORY_SANITIZER)
|
||||
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
|
||||
#define ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
|
||||
|
||||
#endif // ABSL_HAVE_MEMORY_SANITIZER
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_READS_BEGIN/_END attributes.
|
||||
|
||||
#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
|
||||
__attribute((exclusive_lock_function("*")))
|
||||
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
|
||||
__attribute((unlock_function("*")))
|
||||
|
||||
#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
|
||||
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
|
||||
|
||||
#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_READS_BEGIN/_END annotations.
|
||||
|
||||
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
|
||||
// Some of the symbols used in this section (e.g. AnnotateIgnoreReadsBegin) are
|
||||
// defined by the compiler-based implementation, not by the Abseil
|
||||
// library. Therefore they do not use ABSL_INTERNAL_C_SYMBOL.
|
||||
|
||||
// Request the analysis tool to ignore all reads in the current thread until
|
||||
// ABSL_ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
|
||||
// reads, while still checking other reads and all writes.
|
||||
// See also ABSL_ANNOTATE_UNPROTECTED_READ.
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin) \
|
||||
(__FILE__, __LINE__)
|
||||
|
||||
// Stop ignoring reads.
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd) \
|
||||
(__FILE__, __LINE__)
|
||||
|
||||
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||
// implementation.
|
||||
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||
void AnnotateIgnoreReadsBegin(const char* file, int line)
|
||||
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE;
|
||||
void AnnotateIgnoreReadsEnd(const char* file,
|
||||
int line) ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE;
|
||||
ABSL_INTERNAL_END_EXTERN_C
|
||||
|
||||
#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
|
||||
|
||||
// When Annotalysis is enabled without Dynamic Annotations, the use of
|
||||
// static-inline functions allows the annotations to be read at compile-time,
|
||||
// while still letting the compiler elide the functions from the final build.
|
||||
//
|
||||
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
|
||||
// allows IGNORE_READS_AND_WRITES to work properly.
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED( \
|
||||
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsBegin)) \
|
||||
()
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED( \
|
||||
ABSL_INTERNAL_C_SYMBOL(AbslInternalAnnotateIgnoreReadsEnd)) \
|
||||
()
|
||||
|
||||
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
|
||||
AbslInternalAnnotateIgnoreReadsBegin)()
|
||||
ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE {}
|
||||
|
||||
ABSL_INTERNAL_STATIC_INLINE void ABSL_INTERNAL_C_SYMBOL(
|
||||
AbslInternalAnnotateIgnoreReadsEnd)()
|
||||
ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE {}
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_BEGIN() // empty
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_END() // empty
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_WRITES_BEGIN/_END annotations.
|
||||
|
||||
#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
|
||||
|
||||
// Similar to ABSL_ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
|
||||
|
||||
// Stop ignoring writes.
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
|
||||
|
||||
// Function prototypes of annotations provided by the compiler-based sanitizer
|
||||
// implementation.
|
||||
ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||
void AnnotateIgnoreWritesBegin(const char* file, int line);
|
||||
void AnnotateIgnoreWritesEnd(const char* file, int line);
|
||||
ABSL_INTERNAL_END_EXTERN_C
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_BEGIN() // empty
|
||||
#define ABSL_ANNOTATE_IGNORE_WRITES_END() // empty
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define the ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
||||
// primitive annotations defined above.
|
||||
//
|
||||
// Instead of doing
|
||||
// ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||
// ... = x;
|
||||
// ABSL_ANNOTATE_IGNORE_READS_END();
|
||||
// one can use
|
||||
// ... = ABSL_ANNOTATE_UNPROTECTED_READ(x);
|
||||
|
||||
#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
|
||||
|
||||
// Start ignoring all memory accesses (both reads and writes).
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||
do { \
|
||||
ABSL_ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||
ABSL_ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||
} while (0)
|
||||
|
||||
// Stop ignoring both reads and writes.
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||
do { \
|
||||
ABSL_ANNOTATE_IGNORE_WRITES_END(); \
|
||||
ABSL_ANNOTATE_IGNORE_READS_END(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
// ABSL_ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
||||
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) \
|
||||
absl::base_internal::AnnotateUnprotectedRead(x)
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
template <typename T>
|
||||
inline T AnnotateUnprotectedRead(const volatile T& x) { // NOLINT
|
||||
ABSL_ANNOTATE_IGNORE_READS_BEGIN();
|
||||
T res = x;
|
||||
ABSL_ANNOTATE_IGNORE_READS_END();
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
|
||||
#define ABSL_ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
|
||||
#define ABSL_ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Address sanitizer annotations
|
||||
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
// Describe the current state of a contiguous container such as e.g.
|
||||
// std::vector or std::string. For more details see
|
||||
// sanitizer/common_interface_defs.h, which is provided by the compiler.
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
|
||||
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
|
||||
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) \
|
||||
struct { \
|
||||
alignas(8) char x[8]; \
|
||||
} name
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) // empty
|
||||
#define ABSL_ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
|
||||
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// HWAddress sanitizer annotations
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace absl {
|
||||
#ifdef ABSL_HAVE_HWADDRESS_SANITIZER
|
||||
// Under HWASAN changes the tag of the pointer.
|
||||
template <typename T>
|
||||
T* HwasanTagPointer(T* ptr, uintptr_t tag) {
|
||||
return reinterpret_cast<T*>(__hwasan_tag_pointer(ptr, tag));
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
T* HwasanTagPointer(T* ptr, uintptr_t) {
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
} // namespace absl
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Undefine the macros intended only for this file.
|
||||
|
||||
#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||
#undef ABSL_INTERNAL_END_EXTERN_C
|
||||
#undef ABSL_INTERNAL_STATIC_INLINE
|
||||
|
||||
#endif // ABSL_BASE_DYNAMIC_ANNOTATIONS_H_
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
#define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
|
||||
#else
|
||||
#define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
|
||||
#else
|
||||
#define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
template <typename T>
|
||||
class AtomicHook;
|
||||
|
||||
// To workaround AtomicHook not being constant-initializable on some platforms,
|
||||
// prefer to annotate instances with `ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES`
|
||||
// instead of `ABSL_CONST_INIT`.
|
||||
#if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
|
||||
#else
|
||||
#define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
|
||||
#endif
|
||||
|
||||
// `AtomicHook` is a helper class, templatized on a raw function pointer type,
|
||||
// for implementing Abseil customization hooks. It is a callable object that
|
||||
// dispatches to the registered hook. Objects of type `AtomicHook` must have
|
||||
// static or thread storage duration.
|
||||
//
|
||||
// A default constructed object performs a no-op (and returns a default
|
||||
// constructed object) if no hook has been registered.
|
||||
//
|
||||
// Hooks can be pre-registered via constant initialization, for example:
|
||||
//
|
||||
// ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES static AtomicHook<void(*)()>
|
||||
// my_hook(DefaultAction);
|
||||
//
|
||||
// and then changed at runtime via a call to `Store()`.
|
||||
//
|
||||
// Reads and writes guarantee memory_order_acquire/memory_order_release
|
||||
// semantics.
|
||||
template <typename ReturnType, typename... Args>
|
||||
class AtomicHook<ReturnType (*)(Args...)> {
|
||||
public:
|
||||
using FnPtr = ReturnType (*)(Args...);
|
||||
|
||||
// Constructs an object that by default performs a no-op (and
|
||||
// returns a default constructed object) when no hook as been registered.
|
||||
constexpr AtomicHook() : AtomicHook(DummyFunction) {}
|
||||
|
||||
// Constructs an object that by default dispatches to/returns the
|
||||
// pre-registered default_fn when no hook has been registered at runtime.
|
||||
#if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: hook_(default_fn), default_fn_(default_fn) {}
|
||||
#elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: hook_(kUninitialized), default_fn_(default_fn) {}
|
||||
#else
|
||||
// As of January 2020, on all known versions of MSVC this constructor runs in
|
||||
// the global constructor sequence. If `Store()` is called by a dynamic
|
||||
// initializer, we want to preserve the value, even if this constructor runs
|
||||
// after the call to `Store()`. If not, `hook_` will be
|
||||
// zero-initialized by the linker and we have no need to set it.
|
||||
// https://developercommunity.visualstudio.com/content/problem/336946/class-with-constexpr-constructor-not-using-static.html
|
||||
explicit constexpr AtomicHook(FnPtr default_fn)
|
||||
: /* hook_(deliberately omitted), */ default_fn_(default_fn) {
|
||||
static_assert(kUninitialized == 0, "here we rely on zero-initialization");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Stores the provided function pointer as the value for this hook.
|
||||
//
|
||||
// This is intended to be called once. Multiple calls are legal only if the
|
||||
// same function pointer is provided for each call. The store is implemented
|
||||
// as a memory_order_release operation, and read accesses are implemented as
|
||||
// memory_order_acquire.
|
||||
void Store(FnPtr fn) {
|
||||
bool success = DoStore(fn);
|
||||
static_cast<void>(success);
|
||||
assert(success);
|
||||
}
|
||||
|
||||
// Invokes the registered callback. If no callback has yet been registered, a
|
||||
// default-constructed object of the appropriate type is returned instead.
|
||||
template <typename... CallArgs>
|
||||
ReturnType operator()(CallArgs&&... args) const {
|
||||
return DoLoad()(std::forward<CallArgs>(args)...);
|
||||
}
|
||||
|
||||
// Returns the registered callback, or nullptr if none has been registered.
|
||||
// Useful if client code needs to conditionalize behavior based on whether a
|
||||
// callback was registered.
|
||||
//
|
||||
// Note that atomic_hook.Load()() and atomic_hook() have different semantics:
|
||||
// operator()() will perform a no-op if no callback was registered, while
|
||||
// Load()() will dereference a null function pointer. Prefer operator()() to
|
||||
// Load()() unless you must conditionalize behavior on whether a hook was
|
||||
// registered.
|
||||
FnPtr Load() const {
|
||||
FnPtr ptr = DoLoad();
|
||||
return (ptr == DummyFunction) ? nullptr : ptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static ReturnType DummyFunction(Args...) {
|
||||
return ReturnType();
|
||||
}
|
||||
|
||||
// Current versions of MSVC (as of September 2017) have a broken
|
||||
// implementation of std::atomic<T*>: Its constructor attempts to do the
|
||||
// equivalent of a reinterpret_cast in a constexpr context, which is not
|
||||
// allowed.
|
||||
//
|
||||
// This causes an issue when building with LLVM under Windows. To avoid this,
|
||||
// we use a less-efficient, intptr_t-based implementation on Windows.
|
||||
#if ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||
// Return the stored value, or DummyFunction if no value has been stored.
|
||||
FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
|
||||
|
||||
// Store the given value. Returns false if a different value was already
|
||||
// stored to this object.
|
||||
bool DoStore(FnPtr fn) {
|
||||
assert(fn);
|
||||
FnPtr expected = default_fn_;
|
||||
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||
expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||
const bool same_value_already_stored = (expected == fn);
|
||||
return store_succeeded || same_value_already_stored;
|
||||
}
|
||||
|
||||
std::atomic<FnPtr> hook_;
|
||||
#else // !ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||
// Use a sentinel value unlikely to be the address of an actual function.
|
||||
static constexpr intptr_t kUninitialized = 0;
|
||||
|
||||
static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
|
||||
"intptr_t can't contain a function pointer");
|
||||
|
||||
FnPtr DoLoad() const {
|
||||
const intptr_t value = hook_.load(std::memory_order_acquire);
|
||||
if (value == kUninitialized) {
|
||||
return default_fn_;
|
||||
}
|
||||
return reinterpret_cast<FnPtr>(value);
|
||||
}
|
||||
|
||||
bool DoStore(FnPtr fn) {
|
||||
assert(fn);
|
||||
const auto value = reinterpret_cast<intptr_t>(fn);
|
||||
intptr_t expected = kUninitialized;
|
||||
const bool store_succeeded = hook_.compare_exchange_strong(
|
||||
expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
|
||||
const bool same_value_already_stored = (expected == value);
|
||||
return store_succeeded || same_value_already_stored;
|
||||
}
|
||||
|
||||
std::atomic<intptr_t> hook_;
|
||||
#endif
|
||||
|
||||
const FnPtr default_fn_;
|
||||
};
|
||||
|
||||
#undef ABSL_HAVE_WORKING_ATOMIC_POINTER
|
||||
#undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
|
||||
// This file defines dynamic annotations for use with dynamic analysis tool
|
||||
// such as valgrind, PIN, etc.
|
||||
//
|
||||
// Dynamic annotation is a source code annotation that affects the generated
|
||||
// code (that is, the annotation is not a comment). Each such annotation is
|
||||
// attached to a particular instruction and/or to a particular object (address)
|
||||
// in the program.
|
||||
//
|
||||
// The annotations that should be used by users are macros in all upper-case
|
||||
// (e.g., ANNOTATE_THREAD_NAME).
|
||||
//
|
||||
// Actual implementation of these macros may differ depending on the dynamic
|
||||
// analysis tool being used.
|
||||
//
|
||||
// This file supports the following configurations:
|
||||
// - Dynamic Annotations enabled (with static thread-safety warnings disabled).
|
||||
// In this case, macros expand to functions implemented by Thread Sanitizer,
|
||||
// when building with TSan. When not provided an external implementation,
|
||||
// dynamic_annotations.cc provides no-op implementations.
|
||||
//
|
||||
// - Static Clang thread-safety warnings enabled.
|
||||
// When building with a Clang compiler that supports thread-safety warnings,
|
||||
// a subset of annotations can be statically-checked at compile-time. We
|
||||
// expand these macros to static-inline functions that can be analyzed for
|
||||
// thread-safety, but afterwards elided when building the final binary.
|
||||
//
|
||||
// - All annotations are disabled.
|
||||
// If neither Dynamic Annotations nor Clang thread-safety warnings are
|
||||
// enabled, then all annotation-macros expand to empty.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||
#define ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Decide which features are enabled
|
||||
|
||||
#ifndef DYNAMIC_ANNOTATIONS_ENABLED
|
||||
#define DYNAMIC_ANNOTATIONS_ENABLED 0
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) && !defined(SWIG)
|
||||
#define ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED 1
|
||||
#endif
|
||||
|
||||
#if DYNAMIC_ANNOTATIONS_ENABLED != 0
|
||||
|
||||
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 1
|
||||
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED 0
|
||||
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED 1
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED 0
|
||||
#define ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED 0
|
||||
#define ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED 0
|
||||
|
||||
// Clang provides limited support for static thread-safety analysis through a
|
||||
// feature called Annotalysis. We configure macro-definitions according to
|
||||
// whether Annotalysis support is available. When running in opt-mode, GCC
|
||||
// will issue a warning, if these attributes are compiled. Only include them
|
||||
// when compiling using Clang.
|
||||
|
||||
// ANNOTALYSIS_ENABLED == 1 when IGNORE_READ_ATTRIBUTE_ENABLED == 1
|
||||
#define ABSL_INTERNAL_ANNOTALYSIS_ENABLED \
|
||||
defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
// Read/write annotations are enabled in Annotalysis mode; disabled otherwise.
|
||||
#define ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED \
|
||||
ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||
#endif
|
||||
|
||||
// Memory annotations are also made available to LLVM's Memory Sanitizer
|
||||
#if defined(ABSL_HAVE_MEMORY_SANITIZER) && !defined(__native_client__)
|
||||
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 1
|
||||
#endif
|
||||
|
||||
#ifndef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||
#define ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED 0
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ABSL_INTERNAL_BEGIN_EXTERN_C extern "C" {
|
||||
#define ABSL_INTERNAL_END_EXTERN_C } // extern "C"
|
||||
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) ::F
|
||||
#define ABSL_INTERNAL_STATIC_INLINE inline
|
||||
#else
|
||||
#define ABSL_INTERNAL_BEGIN_EXTERN_C // empty
|
||||
#define ABSL_INTERNAL_END_EXTERN_C // empty
|
||||
#define ABSL_INTERNAL_GLOBAL_SCOPED(F) F
|
||||
#define ABSL_INTERNAL_STATIC_INLINE static inline
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define race annotations.
|
||||
|
||||
#if ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 1
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations that suppress errors. It is usually better to express the
|
||||
// program's synchronization using the other annotations, but these can be used
|
||||
// when all else fails.
|
||||
|
||||
// Report that we may have a benign race at `pointer`, with size
|
||||
// "sizeof(*(pointer))". `pointer` must be a non-void* pointer. Insert at the
|
||||
// point where `pointer` has been allocated, preferably close to the point
|
||||
// where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC.
|
||||
#define ANNOTATE_BENIGN_RACE(pointer, description) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||
(__FILE__, __LINE__, pointer, sizeof(*(pointer)), description)
|
||||
|
||||
// Same as ANNOTATE_BENIGN_RACE(`address`, `description`), but applies to
|
||||
// the memory range [`address`, `address`+`size`).
|
||||
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateBenignRaceSized) \
|
||||
(__FILE__, __LINE__, address, size, description)
|
||||
|
||||
// Enable (`enable`!=0) or disable (`enable`==0) race detection for all threads.
|
||||
// This annotation could be useful if you want to skip expensive race analysis
|
||||
// during some period of program execution, e.g. during initialization.
|
||||
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateEnableRaceDetection) \
|
||||
(__FILE__, __LINE__, enable)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations useful for debugging.
|
||||
|
||||
// Report the current thread `name` to a race detector.
|
||||
#define ANNOTATE_THREAD_NAME(name) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateThreadName)(__FILE__, __LINE__, name)
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Annotations useful when implementing locks. They are not normally needed by
|
||||
// modules that merely use locks. The `lock` argument is a pointer to the lock
|
||||
// object.
|
||||
|
||||
// Report that a lock has been created at address `lock`.
|
||||
#define ANNOTATE_RWLOCK_CREATE(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
|
||||
|
||||
// Report that a linker initialized lock has been created at address `lock`.
|
||||
#ifdef ABSL_HAVE_THREAD_SANITIZER
|
||||
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockCreateStatic) \
|
||||
(__FILE__, __LINE__, lock)
|
||||
#else
|
||||
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) ANNOTATE_RWLOCK_CREATE(lock)
|
||||
#endif
|
||||
|
||||
// Report that the lock at address `lock` is about to be destroyed.
|
||||
#define ANNOTATE_RWLOCK_DESTROY(lock) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
|
||||
|
||||
// Report that the lock at address `lock` has been acquired.
|
||||
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockAcquired) \
|
||||
(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
// Report that the lock at address `lock` is about to be released.
|
||||
// `is_w`=1 for writer lock, `is_w`=0 for reader lock.
|
||||
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateRWLockReleased) \
|
||||
(__FILE__, __LINE__, lock, is_w)
|
||||
|
||||
// Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable `static_var`.
|
||||
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
|
||||
namespace { \
|
||||
class static_var##_annotator { \
|
||||
public: \
|
||||
static_var##_annotator() { \
|
||||
ANNOTATE_BENIGN_RACE_SIZED(&static_var, sizeof(static_var), \
|
||||
#static_var ": " description); \
|
||||
} \
|
||||
}; \
|
||||
static static_var##_annotator the##static_var##_annotator; \
|
||||
} // namespace
|
||||
|
||||
#else // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED == 0
|
||||
|
||||
#define ANNOTATE_RWLOCK_CREATE(lock) // empty
|
||||
#define ANNOTATE_RWLOCK_CREATE_STATIC(lock) // empty
|
||||
#define ANNOTATE_RWLOCK_DESTROY(lock) // empty
|
||||
#define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) // empty
|
||||
#define ANNOTATE_RWLOCK_RELEASED(lock, is_w) // empty
|
||||
#define ANNOTATE_BENIGN_RACE(address, description) // empty
|
||||
#define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) // empty
|
||||
#define ANNOTATE_THREAD_NAME(name) // empty
|
||||
#define ANNOTATE_ENABLE_RACE_DETECTION(enable) // empty
|
||||
#define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) // empty
|
||||
|
||||
#endif // ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define memory annotations.
|
||||
|
||||
#if ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 1
|
||||
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||
__msan_unpoison(address, size)
|
||||
|
||||
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||
__msan_allocated_memory(address, size)
|
||||
|
||||
#else // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED == 0
|
||||
|
||||
#if DYNAMIC_ANNOTATIONS_ENABLED == 1
|
||||
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) \
|
||||
do { \
|
||||
(void)(address); \
|
||||
(void)(size); \
|
||||
} while (0)
|
||||
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) \
|
||||
do { \
|
||||
(void)(address); \
|
||||
(void)(size); \
|
||||
} while (0)
|
||||
#else
|
||||
#define ANNOTATE_MEMORY_IS_INITIALIZED(address, size) // empty
|
||||
#define ANNOTATE_MEMORY_IS_UNINITIALIZED(address, size) // empty
|
||||
#endif
|
||||
|
||||
#endif // ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_READS_BEGIN/_END attributes.
|
||||
|
||||
#if defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE \
|
||||
__attribute((exclusive_lock_function("*")))
|
||||
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE \
|
||||
__attribute((unlock_function("*")))
|
||||
|
||||
#else // !defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
#define ABSL_INTERNAL_IGNORE_READS_BEGIN_ATTRIBUTE // empty
|
||||
#define ABSL_INTERNAL_IGNORE_READS_END_ATTRIBUTE // empty
|
||||
|
||||
#endif // defined(ABSL_INTERNAL_IGNORE_READS_ATTRIBUTE_ENABLED)
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_READS_BEGIN/_END annotations.
|
||||
|
||||
#if ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED == 1
|
||||
|
||||
// Request the analysis tool to ignore all reads in the current thread until
|
||||
// ANNOTATE_IGNORE_READS_END is called. Useful to ignore intentional racey
|
||||
// reads, while still checking other reads and all writes.
|
||||
// See also ANNOTATE_UNPROTECTED_READ.
|
||||
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
|
||||
|
||||
// Stop ignoring reads.
|
||||
#define ANNOTATE_IGNORE_READS_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
|
||||
|
||||
#elif defined(ABSL_INTERNAL_ANNOTALYSIS_ENABLED)
|
||||
|
||||
// When Annotalysis is enabled without Dynamic Annotations, the use of
|
||||
// static-inline functions allows the annotations to be read at compile-time,
|
||||
// while still letting the compiler elide the functions from the final build.
|
||||
//
|
||||
// TODO(delesley) -- The exclusive lock here ignores writes as well, but
|
||||
// allows IGNORE_READS_AND_WRITES to work properly.
|
||||
|
||||
#define ANNOTATE_IGNORE_READS_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsBegin)()
|
||||
|
||||
#define ANNOTATE_IGNORE_READS_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AbslInternalAnnotateIgnoreReadsEnd)()
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTATE_IGNORE_READS_BEGIN() // empty
|
||||
#define ANNOTATE_IGNORE_READS_END() // empty
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define IGNORE_WRITES_BEGIN/_END annotations.
|
||||
|
||||
#if ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED == 1
|
||||
|
||||
// Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes instead.
|
||||
#define ANNOTATE_IGNORE_WRITES_BEGIN() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
|
||||
|
||||
// Stop ignoring writes.
|
||||
#define ANNOTATE_IGNORE_WRITES_END() \
|
||||
ABSL_INTERNAL_GLOBAL_SCOPED(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTATE_IGNORE_WRITES_BEGIN() // empty
|
||||
#define ANNOTATE_IGNORE_WRITES_END() // empty
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Define the ANNOTATE_IGNORE_READS_AND_WRITES_* annotations using the more
|
||||
// primitive annotations defined above.
|
||||
//
|
||||
// Instead of doing
|
||||
// ANNOTATE_IGNORE_READS_BEGIN();
|
||||
// ... = x;
|
||||
// ANNOTATE_IGNORE_READS_END();
|
||||
// one can use
|
||||
// ... = ANNOTATE_UNPROTECTED_READ(x);
|
||||
|
||||
#if defined(ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED)
|
||||
|
||||
// Start ignoring all memory accesses (both reads and writes).
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_READS_BEGIN(); \
|
||||
ANNOTATE_IGNORE_WRITES_BEGIN(); \
|
||||
} while (0)
|
||||
|
||||
// Stop ignoring both reads and writes.
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
|
||||
do { \
|
||||
ANNOTATE_IGNORE_WRITES_END(); \
|
||||
ANNOTATE_IGNORE_READS_END(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef __cplusplus
|
||||
// ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
|
||||
#define ANNOTATE_UNPROTECTED_READ(x) \
|
||||
absl::base_internal::AnnotateUnprotectedRead(x)
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() // empty
|
||||
#define ANNOTATE_IGNORE_READS_AND_WRITES_END() // empty
|
||||
#define ANNOTATE_UNPROTECTED_READ(x) (x)
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Address sanitizer annotations
|
||||
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
// Describe the current state of a contiguous container such as e.g.
|
||||
// std::vector or std::string. For more details see
|
||||
// sanitizer/common_interface_defs.h, which is provided by the compiler.
|
||||
#include <sanitizer/common_interface_defs.h>
|
||||
|
||||
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid) \
|
||||
__sanitizer_annotate_contiguous_container(beg, end, old_mid, new_mid)
|
||||
#define ADDRESS_SANITIZER_REDZONE(name) \
|
||||
struct { \
|
||||
char x[8] __attribute__((aligned(8))); \
|
||||
} name
|
||||
|
||||
#else
|
||||
|
||||
#define ANNOTATE_CONTIGUOUS_CONTAINER(beg, end, old_mid, new_mid)
|
||||
#define ADDRESS_SANITIZER_REDZONE(name) static_assert(true, "")
|
||||
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Undefine the macros intended only for this file.
|
||||
|
||||
#undef ABSL_INTERNAL_RACE_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_MEMORY_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_READS_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_WRITES_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_ANNOTALYSIS_ENABLED
|
||||
#undef ABSL_INTERNAL_READS_WRITES_ANNOTATIONS_ENABLED
|
||||
#undef ABSL_INTERNAL_BEGIN_EXTERN_C
|
||||
#undef ABSL_INTERNAL_END_EXTERN_C
|
||||
#undef ABSL_INTERNAL_STATIC_INLINE
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_DYNAMIC_ANNOTATIONS_H_
|
||||
@@ -0,0 +1,283 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||
#define ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
|
||||
#include "absl/base/casts.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/unaligned_access.h"
|
||||
#include "absl/base/nullability.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
inline uint64_t gbswap_64(uint64_t host_int) {
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_bswap64) || defined(__GNUC__)
|
||||
return __builtin_bswap64(host_int);
|
||||
#elif defined(_MSC_VER)
|
||||
return _byteswap_uint64(host_int);
|
||||
#else
|
||||
return (((host_int & uint64_t{0xFF}) << 56) |
|
||||
((host_int & uint64_t{0xFF00}) << 40) |
|
||||
((host_int & uint64_t{0xFF0000}) << 24) |
|
||||
((host_int & uint64_t{0xFF000000}) << 8) |
|
||||
((host_int & uint64_t{0xFF00000000}) >> 8) |
|
||||
((host_int & uint64_t{0xFF0000000000}) >> 24) |
|
||||
((host_int & uint64_t{0xFF000000000000}) >> 40) |
|
||||
((host_int & uint64_t{0xFF00000000000000}) >> 56));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint32_t gbswap_32(uint32_t host_int) {
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_bswap32) || defined(__GNUC__)
|
||||
return __builtin_bswap32(host_int);
|
||||
#elif defined(_MSC_VER)
|
||||
return _byteswap_ulong(host_int);
|
||||
#else
|
||||
return (((host_int & uint32_t{0xFF}) << 24) |
|
||||
((host_int & uint32_t{0xFF00}) << 8) |
|
||||
((host_int & uint32_t{0xFF0000}) >> 8) |
|
||||
((host_int & uint32_t{0xFF000000}) >> 24));
|
||||
#endif
|
||||
}
|
||||
|
||||
inline uint16_t gbswap_16(uint16_t host_int) {
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_bswap16) || defined(__GNUC__)
|
||||
return __builtin_bswap16(host_int);
|
||||
#elif defined(_MSC_VER)
|
||||
return _byteswap_ushort(host_int);
|
||||
#else
|
||||
return (((host_int & uint16_t{0xFF}) << 8) |
|
||||
((host_int & uint16_t{0xFF00}) >> 8));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||
|
||||
// Portable definitions for htonl (host-to-network) and friends on little-endian
|
||||
// architectures.
|
||||
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
|
||||
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
|
||||
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
|
||||
|
||||
#elif defined ABSL_IS_BIG_ENDIAN
|
||||
|
||||
// Portable definitions for htonl (host-to-network) etc on big-endian
|
||||
// architectures. These definitions are simpler since the host byte order is the
|
||||
// same as network byte order.
|
||||
inline uint16_t ghtons(uint16_t x) { return x; }
|
||||
inline uint32_t ghtonl(uint32_t x) { return x; }
|
||||
inline uint64_t ghtonll(uint64_t x) { return x; }
|
||||
|
||||
#else
|
||||
#error \
|
||||
"Unsupported byte order: Either ABSL_IS_BIG_ENDIAN or " \
|
||||
"ABSL_IS_LITTLE_ENDIAN must be defined"
|
||||
#endif // byte order
|
||||
|
||||
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
|
||||
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
|
||||
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
|
||||
|
||||
// Utilities to convert numbers between the current hosts's native byte
|
||||
// order and little-endian byte order
|
||||
//
|
||||
// Load/Store methods are alignment safe
|
||||
namespace little_endian {
|
||||
// Conversion functions.
|
||||
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||
|
||||
inline uint16_t FromHost16(uint16_t x) { return x; }
|
||||
inline uint16_t ToHost16(uint16_t x) { return x; }
|
||||
|
||||
inline uint32_t FromHost32(uint32_t x) { return x; }
|
||||
inline uint32_t ToHost32(uint32_t x) { return x; }
|
||||
|
||||
inline uint64_t FromHost64(uint64_t x) { return x; }
|
||||
inline uint64_t ToHost64(uint64_t x) { return x; }
|
||||
|
||||
inline constexpr bool IsLittleEndian() { return true; }
|
||||
|
||||
#elif defined ABSL_IS_BIG_ENDIAN
|
||||
|
||||
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
||||
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
||||
|
||||
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
||||
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
||||
|
||||
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
||||
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
||||
|
||||
inline constexpr bool IsLittleEndian() { return false; }
|
||||
|
||||
#endif /* ENDIAN */
|
||||
|
||||
inline uint8_t FromHost(uint8_t x) { return x; }
|
||||
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
|
||||
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
|
||||
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
|
||||
inline uint8_t ToHost(uint8_t x) { return x; }
|
||||
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
|
||||
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
|
||||
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
|
||||
|
||||
inline int8_t FromHost(int8_t x) { return x; }
|
||||
inline int16_t FromHost(int16_t x) {
|
||||
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
|
||||
}
|
||||
inline int32_t FromHost(int32_t x) {
|
||||
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
|
||||
}
|
||||
inline int64_t FromHost(int64_t x) {
|
||||
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
|
||||
}
|
||||
inline int8_t ToHost(int8_t x) { return x; }
|
||||
inline int16_t ToHost(int16_t x) {
|
||||
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
|
||||
}
|
||||
inline int32_t ToHost(int32_t x) {
|
||||
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
|
||||
}
|
||||
inline int64_t ToHost(int64_t x) {
|
||||
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
|
||||
}
|
||||
|
||||
// Functions to do unaligned loads and stores in little-endian order.
|
||||
inline uint16_t Load16(absl::Nonnull<const void *> p) {
|
||||
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
|
||||
}
|
||||
|
||||
inline void Store16(absl::Nonnull<void *> p, uint16_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
||||
}
|
||||
|
||||
inline uint32_t Load32(absl::Nonnull<const void *> p) {
|
||||
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
inline void Store32(absl::Nonnull<void *> p, uint32_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
||||
}
|
||||
|
||||
inline uint64_t Load64(absl::Nonnull<const void *> p) {
|
||||
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
|
||||
}
|
||||
|
||||
inline void Store64(absl::Nonnull<void *> p, uint64_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
||||
}
|
||||
|
||||
} // namespace little_endian
|
||||
|
||||
// Utilities to convert numbers between the current hosts's native byte
|
||||
// order and big-endian byte order (same as network byte order)
|
||||
//
|
||||
// Load/Store methods are alignment safe
|
||||
namespace big_endian {
|
||||
#ifdef ABSL_IS_LITTLE_ENDIAN
|
||||
|
||||
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
|
||||
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
|
||||
|
||||
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
|
||||
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
|
||||
|
||||
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
|
||||
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
|
||||
|
||||
inline constexpr bool IsLittleEndian() { return true; }
|
||||
|
||||
#elif defined ABSL_IS_BIG_ENDIAN
|
||||
|
||||
inline uint16_t FromHost16(uint16_t x) { return x; }
|
||||
inline uint16_t ToHost16(uint16_t x) { return x; }
|
||||
|
||||
inline uint32_t FromHost32(uint32_t x) { return x; }
|
||||
inline uint32_t ToHost32(uint32_t x) { return x; }
|
||||
|
||||
inline uint64_t FromHost64(uint64_t x) { return x; }
|
||||
inline uint64_t ToHost64(uint64_t x) { return x; }
|
||||
|
||||
inline constexpr bool IsLittleEndian() { return false; }
|
||||
|
||||
#endif /* ENDIAN */
|
||||
|
||||
inline uint8_t FromHost(uint8_t x) { return x; }
|
||||
inline uint16_t FromHost(uint16_t x) { return FromHost16(x); }
|
||||
inline uint32_t FromHost(uint32_t x) { return FromHost32(x); }
|
||||
inline uint64_t FromHost(uint64_t x) { return FromHost64(x); }
|
||||
inline uint8_t ToHost(uint8_t x) { return x; }
|
||||
inline uint16_t ToHost(uint16_t x) { return ToHost16(x); }
|
||||
inline uint32_t ToHost(uint32_t x) { return ToHost32(x); }
|
||||
inline uint64_t ToHost(uint64_t x) { return ToHost64(x); }
|
||||
|
||||
inline int8_t FromHost(int8_t x) { return x; }
|
||||
inline int16_t FromHost(int16_t x) {
|
||||
return bit_cast<int16_t>(FromHost16(bit_cast<uint16_t>(x)));
|
||||
}
|
||||
inline int32_t FromHost(int32_t x) {
|
||||
return bit_cast<int32_t>(FromHost32(bit_cast<uint32_t>(x)));
|
||||
}
|
||||
inline int64_t FromHost(int64_t x) {
|
||||
return bit_cast<int64_t>(FromHost64(bit_cast<uint64_t>(x)));
|
||||
}
|
||||
inline int8_t ToHost(int8_t x) { return x; }
|
||||
inline int16_t ToHost(int16_t x) {
|
||||
return bit_cast<int16_t>(ToHost16(bit_cast<uint16_t>(x)));
|
||||
}
|
||||
inline int32_t ToHost(int32_t x) {
|
||||
return bit_cast<int32_t>(ToHost32(bit_cast<uint32_t>(x)));
|
||||
}
|
||||
inline int64_t ToHost(int64_t x) {
|
||||
return bit_cast<int64_t>(ToHost64(bit_cast<uint64_t>(x)));
|
||||
}
|
||||
|
||||
// Functions to do unaligned loads and stores in big-endian order.
|
||||
inline uint16_t Load16(absl::Nonnull<const void *> p) {
|
||||
return ToHost16(ABSL_INTERNAL_UNALIGNED_LOAD16(p));
|
||||
}
|
||||
|
||||
inline void Store16(absl::Nonnull<void *> p, uint16_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
|
||||
}
|
||||
|
||||
inline uint32_t Load32(absl::Nonnull<const void *> p) {
|
||||
return ToHost32(ABSL_INTERNAL_UNALIGNED_LOAD32(p));
|
||||
}
|
||||
|
||||
inline void Store32(absl::Nonnull<void *>p, uint32_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
|
||||
}
|
||||
|
||||
inline uint64_t Load64(absl::Nonnull<const void *> p) {
|
||||
return ToHost64(ABSL_INTERNAL_UNALIGNED_LOAD64(p));
|
||||
}
|
||||
|
||||
inline void Store64(absl::Nonnull<void *> p, uint64_t v) {
|
||||
ABSL_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
|
||||
}
|
||||
|
||||
} // namespace big_endian
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_ENDIAN_H_
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
#define ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace internal {
|
||||
|
||||
// This is a back-fill of C++20's `std::type_identity`.
|
||||
template <typename T>
|
||||
struct type_identity {
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
// This is a back-fill of C++20's `std::type_identity_t`.
|
||||
template <typename T>
|
||||
using type_identity_t = typename type_identity<T>::type;
|
||||
|
||||
} // namespace internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_IDENTITY_H_
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
|
||||
#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/internal/identity.h"
|
||||
|
||||
// File:
|
||||
// This file define a macro that allows the creation of or emulation of C++17
|
||||
// inline variables based on whether or not the feature is supported.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init)
|
||||
//
|
||||
// Description:
|
||||
// Expands to the equivalent of an inline constexpr instance of the specified
|
||||
// `type` and `name`, initialized to the value `init`. If the compiler being
|
||||
// used is detected as supporting actual inline variables as a language
|
||||
// feature, then the macro expands to an actual inline variable definition.
|
||||
//
|
||||
// Requires:
|
||||
// `type` is a type that is usable in an extern variable declaration.
|
||||
//
|
||||
// Requires: `name` is a valid identifier
|
||||
//
|
||||
// Requires:
|
||||
// `init` is an expression that can be used in the following definition:
|
||||
// constexpr type name = init;
|
||||
//
|
||||
// Usage:
|
||||
//
|
||||
// // Equivalent to: `inline constexpr size_t variant_npos = -1;`
|
||||
// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1);
|
||||
//
|
||||
// Differences in implementation:
|
||||
// For a direct, language-level inline variable, decltype(name) will be the
|
||||
// type that was specified along with const qualification, whereas for
|
||||
// emulated inline variables, decltype(name) may be different (in practice
|
||||
// it will likely be a reference type).
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __cpp_inline_variables
|
||||
|
||||
// Clang's -Wmissing-variable-declarations option erroneously warned that
|
||||
// inline constexpr objects need to be pre-declared. This has now been fixed,
|
||||
// but we will need to support this workaround for people building with older
|
||||
// versions of clang.
|
||||
//
|
||||
// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862
|
||||
//
|
||||
// Note:
|
||||
// type_identity_t is used here so that the const and name are in the
|
||||
// appropriate place for pointer types, reference types, function pointer
|
||||
// types, etc..
|
||||
#if defined(__clang__)
|
||||
#define ABSL_INTERNAL_EXTERN_DECL(type, name) \
|
||||
extern const ::absl::internal::type_identity_t<type> name;
|
||||
#else // Otherwise, just define the macro to do nothing.
|
||||
#define ABSL_INTERNAL_EXTERN_DECL(type, name)
|
||||
#endif // defined(__clang__)
|
||||
|
||||
// See above comment at top of file for details.
|
||||
#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \
|
||||
ABSL_INTERNAL_EXTERN_DECL(type, name) \
|
||||
inline constexpr ::absl::internal::type_identity_t<type> name = init
|
||||
|
||||
#else
|
||||
|
||||
// See above comment at top of file for details.
|
||||
//
|
||||
// Note:
|
||||
// type_identity_t is used here so that the const and name are in the
|
||||
// appropriate place for pointer types, reference types, function pointer
|
||||
// types, etc..
|
||||
#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \
|
||||
template <class /*AbslInternalDummy*/ = void> \
|
||||
struct AbslInternalInlineVariableHolder##name { \
|
||||
static constexpr ::absl::internal::type_identity_t<var_type> kInstance = \
|
||||
init; \
|
||||
}; \
|
||||
\
|
||||
template <class AbslInternalDummy> \
|
||||
constexpr ::absl::internal::type_identity_t<var_type> \
|
||||
AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \
|
||||
\
|
||||
static constexpr const ::absl::internal::type_identity_t<var_type>& \
|
||||
name = /* NOLINT */ \
|
||||
AbslInternalInlineVariableHolder##name<>::kInstance; \
|
||||
static_assert(sizeof(void (*)(decltype(name))) != 0, \
|
||||
"Silence unused variable warnings.")
|
||||
|
||||
#endif // __cpp_inline_variables
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_H_
|
||||
@@ -0,0 +1,241 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// absl::base_internal::invoke(f, args...) is an implementation of
|
||||
// INVOKE(f, args...) from section [func.require] of the C++ standard.
|
||||
// When compiled as C++17 and later versions, it is implemented as an alias of
|
||||
// std::invoke.
|
||||
//
|
||||
// [func.require]
|
||||
// Define INVOKE (f, t1, t2, ..., tN) as follows:
|
||||
// 1. (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
|
||||
// and t1 is an object of type T or a reference to an object of type T or a
|
||||
// reference to an object of a type derived from T;
|
||||
// 2. ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
|
||||
// class T and t1 is not one of the types described in the previous item;
|
||||
// 3. t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
|
||||
// an object of type T or a reference to an object of type T or a reference
|
||||
// to an object of a type derived from T;
|
||||
// 4. (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
|
||||
// is not one of the types described in the previous item;
|
||||
// 5. f(t1, t2, ..., tN) in all other cases.
|
||||
//
|
||||
// The implementation is SFINAE-friendly: substitution failure within invoke()
|
||||
// isn't an error.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_INVOKE_H_
|
||||
#define ABSL_BASE_INTERNAL_INVOKE_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#if ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
using std::invoke;
|
||||
using std::invoke_result_t;
|
||||
using std::is_invocable_r;
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#else // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
// The following code is internal implementation detail. See the comment at the
|
||||
// top of this file for the API documentation.
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// The five classes below each implement one of the clauses from the definition
|
||||
// of INVOKE. The inner class template Accept<F, Args...> checks whether the
|
||||
// clause is applicable; static function template Invoke(f, args...) does the
|
||||
// invocation.
|
||||
//
|
||||
// By separating the clause selection logic from invocation we make sure that
|
||||
// Invoke() does exactly what the standard says.
|
||||
|
||||
template <typename Derived>
|
||||
struct StrippedAccept {
|
||||
template <typename... Args>
|
||||
struct Accept : Derived::template AcceptImpl<typename std::remove_cv<
|
||||
typename std::remove_reference<Args>::type>::type...> {};
|
||||
};
|
||||
|
||||
// (t1.*f)(t2, ..., tN) when f is a pointer to a member function of a class T
|
||||
// and t1 is an object of type T or a reference to an object of type T or a
|
||||
// reference to an object of a type derived from T.
|
||||
struct MemFunAndRef : StrippedAccept<MemFunAndRef> {
|
||||
template <typename... Args>
|
||||
struct AcceptImpl : std::false_type {};
|
||||
|
||||
template <typename MemFunType, typename C, typename Obj, typename... Args>
|
||||
struct AcceptImpl<MemFunType C::*, Obj, Args...>
|
||||
: std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
|
||||
absl::is_function<MemFunType>::value> {
|
||||
};
|
||||
|
||||
template <typename MemFun, typename Obj, typename... Args>
|
||||
static decltype((std::declval<Obj>().*
|
||||
std::declval<MemFun>())(std::declval<Args>()...))
|
||||
Invoke(MemFun&& mem_fun, Obj&& obj, Args&&... args) {
|
||||
// Ignore bogus GCC warnings on this line.
|
||||
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101436 for similar example.
|
||||
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
return (std::forward<Obj>(obj).*
|
||||
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
|
||||
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(11, 0)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// ((*t1).*f)(t2, ..., tN) when f is a pointer to a member function of a
|
||||
// class T and t1 is not one of the types described in the previous item.
|
||||
struct MemFunAndPtr : StrippedAccept<MemFunAndPtr> {
|
||||
template <typename... Args>
|
||||
struct AcceptImpl : std::false_type {};
|
||||
|
||||
template <typename MemFunType, typename C, typename Ptr, typename... Args>
|
||||
struct AcceptImpl<MemFunType C::*, Ptr, Args...>
|
||||
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
|
||||
absl::is_function<MemFunType>::value> {
|
||||
};
|
||||
|
||||
template <typename MemFun, typename Ptr, typename... Args>
|
||||
static decltype(((*std::declval<Ptr>()).*
|
||||
std::declval<MemFun>())(std::declval<Args>()...))
|
||||
Invoke(MemFun&& mem_fun, Ptr&& ptr, Args&&... args) {
|
||||
return ((*std::forward<Ptr>(ptr)).*
|
||||
std::forward<MemFun>(mem_fun))(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// t1.*f when N == 1 and f is a pointer to member data of a class T and t1 is
|
||||
// an object of type T or a reference to an object of type T or a reference
|
||||
// to an object of a type derived from T.
|
||||
struct DataMemAndRef : StrippedAccept<DataMemAndRef> {
|
||||
template <typename... Args>
|
||||
struct AcceptImpl : std::false_type {};
|
||||
|
||||
template <typename R, typename C, typename Obj>
|
||||
struct AcceptImpl<R C::*, Obj>
|
||||
: std::integral_constant<bool, std::is_base_of<C, Obj>::value &&
|
||||
!absl::is_function<R>::value> {};
|
||||
|
||||
template <typename DataMem, typename Ref>
|
||||
static decltype(std::declval<Ref>().*std::declval<DataMem>()) Invoke(
|
||||
DataMem&& data_mem, Ref&& ref) {
|
||||
return std::forward<Ref>(ref).*std::forward<DataMem>(data_mem);
|
||||
}
|
||||
};
|
||||
|
||||
// (*t1).*f when N == 1 and f is a pointer to member data of a class T and t1
|
||||
// is not one of the types described in the previous item.
|
||||
struct DataMemAndPtr : StrippedAccept<DataMemAndPtr> {
|
||||
template <typename... Args>
|
||||
struct AcceptImpl : std::false_type {};
|
||||
|
||||
template <typename R, typename C, typename Ptr>
|
||||
struct AcceptImpl<R C::*, Ptr>
|
||||
: std::integral_constant<bool, !std::is_base_of<C, Ptr>::value &&
|
||||
!absl::is_function<R>::value> {};
|
||||
|
||||
template <typename DataMem, typename Ptr>
|
||||
static decltype((*std::declval<Ptr>()).*std::declval<DataMem>()) Invoke(
|
||||
DataMem&& data_mem, Ptr&& ptr) {
|
||||
return (*std::forward<Ptr>(ptr)).*std::forward<DataMem>(data_mem);
|
||||
}
|
||||
};
|
||||
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
struct Callable {
|
||||
// Callable doesn't have Accept because it's the last clause that gets picked
|
||||
// when none of the previous clauses are applicable.
|
||||
template <typename F, typename... Args>
|
||||
static decltype(std::declval<F>()(std::declval<Args>()...)) Invoke(
|
||||
F&& f, Args&&... args) {
|
||||
return std::forward<F>(f)(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Resolves to the first matching clause.
|
||||
template <typename... Args>
|
||||
struct Invoker {
|
||||
typedef typename std::conditional<
|
||||
MemFunAndRef::Accept<Args...>::value, MemFunAndRef,
|
||||
typename std::conditional<
|
||||
MemFunAndPtr::Accept<Args...>::value, MemFunAndPtr,
|
||||
typename std::conditional<
|
||||
DataMemAndRef::Accept<Args...>::value, DataMemAndRef,
|
||||
typename std::conditional<DataMemAndPtr::Accept<Args...>::value,
|
||||
DataMemAndPtr, Callable>::type>::type>::
|
||||
type>::type type;
|
||||
};
|
||||
|
||||
// The result type of Invoke<F, Args...>.
|
||||
template <typename F, typename... Args>
|
||||
using invoke_result_t = decltype(Invoker<F, Args...>::type::Invoke(
|
||||
std::declval<F>(), std::declval<Args>()...));
|
||||
|
||||
// Invoke(f, args...) is an implementation of INVOKE(f, args...) from section
|
||||
// [func.require] of the C++ standard.
|
||||
template <typename F, typename... Args>
|
||||
invoke_result_t<F, Args...> invoke(F&& f, Args&&... args) {
|
||||
return Invoker<F, Args...>::type::Invoke(std::forward<F>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename AlwaysVoid, typename, typename, typename...>
|
||||
struct IsInvocableRImpl : std::false_type {};
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
struct IsInvocableRImpl<
|
||||
absl::void_t<absl::base_internal::invoke_result_t<F, Args...> >, R, F,
|
||||
Args...>
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
std::is_convertible<absl::base_internal::invoke_result_t<F, Args...>,
|
||||
R>::value ||
|
||||
std::is_void<R>::value> {};
|
||||
|
||||
// Type trait whose member `value` is true if invoking `F` with `Args` is valid,
|
||||
// and either the return type is convertible to `R`, or `R` is void.
|
||||
// C++11-compatible version of `std::is_invocable_r`.
|
||||
template <typename R, typename F, typename... Args>
|
||||
using is_invocable_r = IsInvocableRImpl<void, R, F, Args...>;
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_INTERNAL_CPLUSPLUS_LANG >= 201703L
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_INVOKE_H_
|
||||
@@ -0,0 +1,127 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||
#define ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||
|
||||
// A simple thread-safe memory allocator that does not depend on
|
||||
// mutexes or thread-specific data. It is intended to be used
|
||||
// sparingly, and only when malloc() would introduce an unwanted
|
||||
// dependency, such as inside the heap-checker, or the Mutex
|
||||
// implementation.
|
||||
|
||||
// IWYU pragma: private, include "base/low_level_alloc.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// LowLevelAlloc requires that the platform support low-level
|
||||
// allocation of virtual memory. Platforms lacking this cannot use
|
||||
// LowLevelAlloc.
|
||||
#ifdef ABSL_LOW_LEVEL_ALLOC_MISSING
|
||||
#error ABSL_LOW_LEVEL_ALLOC_MISSING cannot be directly set
|
||||
#elif !defined(ABSL_HAVE_MMAP) && !defined(_WIN32)
|
||||
#define ABSL_LOW_LEVEL_ALLOC_MISSING 1
|
||||
#endif
|
||||
|
||||
// Using LowLevelAlloc with kAsyncSignalSafe isn't supported on Windows or
|
||||
// asm.js / WebAssembly.
|
||||
// See https://kripken.github.io/emscripten-site/docs/porting/pthreads.html
|
||||
// for more information.
|
||||
#ifdef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||
#error ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING cannot be directly set
|
||||
#elif defined(_WIN32) || defined(__asmjs__) || defined(__wasm__) || \
|
||||
defined(__hexagon__)
|
||||
#define ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING 1
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "absl/base/port.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class LowLevelAlloc {
|
||||
public:
|
||||
struct Arena; // an arena from which memory may be allocated
|
||||
|
||||
// Returns a pointer to a block of at least "request" bytes
|
||||
// that have been newly allocated from the specific arena.
|
||||
// for Alloc() call the DefaultArena() is used.
|
||||
// Returns 0 if passed request==0.
|
||||
// Does not return 0 under other circumstances; it crashes if memory
|
||||
// is not available.
|
||||
static void *Alloc(size_t request) ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||
static void *AllocWithArena(size_t request, Arena *arena)
|
||||
ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||
|
||||
// Deallocates a region of memory that was previously allocated with
|
||||
// Alloc(). Does nothing if passed 0. "s" must be either 0,
|
||||
// or must have been returned from a call to Alloc() and not yet passed to
|
||||
// Free() since that call to Alloc(). The space is returned to the arena
|
||||
// from which it was allocated.
|
||||
static void Free(void *s) ABSL_ATTRIBUTE_SECTION(malloc_hook);
|
||||
|
||||
// ABSL_ATTRIBUTE_SECTION(malloc_hook) for Alloc* and Free
|
||||
// are to put all callers of MallocHook::Invoke* in this module
|
||||
// into special section,
|
||||
// so that MallocHook::GetCallerStackTrace can function accurately.
|
||||
|
||||
// Create a new arena.
|
||||
// The root metadata for the new arena is allocated in the
|
||||
// meta_data_arena; the DefaultArena() can be passed for meta_data_arena.
|
||||
// These values may be ored into flags:
|
||||
enum {
|
||||
// Report calls to Alloc() and Free() via the MallocHook interface.
|
||||
// Set in the DefaultArena.
|
||||
kCallMallocHook = 0x0001,
|
||||
|
||||
#ifndef ABSL_LOW_LEVEL_ALLOC_ASYNC_SIGNAL_SAFE_MISSING
|
||||
// Make calls to Alloc(), Free() be async-signal-safe. Not set in
|
||||
// DefaultArena(). Not supported on all platforms.
|
||||
kAsyncSignalSafe = 0x0002,
|
||||
#endif
|
||||
};
|
||||
// Construct a new arena. The allocation of the underlying metadata honors
|
||||
// the provided flags. For example, the call NewArena(kAsyncSignalSafe)
|
||||
// is itself async-signal-safe, as well as generatating an arena that provides
|
||||
// async-signal-safe Alloc/Free.
|
||||
static Arena *NewArena(uint32_t flags);
|
||||
|
||||
// Destroys an arena allocated by NewArena and returns true,
|
||||
// provided no allocated blocks remain in the arena.
|
||||
// If allocated blocks remain in the arena, does nothing and
|
||||
// returns false.
|
||||
// It is illegal to attempt to destroy the DefaultArena().
|
||||
static bool DeleteArena(Arena *arena);
|
||||
|
||||
// The default arena that always exists.
|
||||
static Arena *DefaultArena();
|
||||
|
||||
private:
|
||||
LowLevelAlloc(); // no instances
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_ALLOC_H_
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Core interfaces and definitions used by by low-level interfaces such as
|
||||
// SpinLock.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
#define ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
#include "absl/base/macros.h"
|
||||
|
||||
// The following two declarations exist so SchedulingGuard may friend them with
|
||||
// the appropriate language linkage. These callbacks allow libc internals, such
|
||||
// as function level statics, to schedule cooperatively when locking.
|
||||
extern "C" bool __google_disable_rescheduling(void);
|
||||
extern "C" void __google_enable_rescheduling(bool disable_result);
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
class CondVar;
|
||||
class Mutex;
|
||||
|
||||
namespace synchronization_internal {
|
||||
int MutexDelay(int32_t c, int mode);
|
||||
} // namespace synchronization_internal
|
||||
|
||||
namespace base_internal {
|
||||
|
||||
class SchedulingHelper; // To allow use of SchedulingGuard.
|
||||
class SpinLock; // To allow use of SchedulingGuard.
|
||||
|
||||
// SchedulingGuard
|
||||
// Provides guard semantics that may be used to disable cooperative rescheduling
|
||||
// of the calling thread within specific program blocks. This is used to
|
||||
// protect resources (e.g. low-level SpinLocks or Domain code) that cooperative
|
||||
// scheduling depends on.
|
||||
//
|
||||
// Domain implementations capable of rescheduling in reaction to involuntary
|
||||
// kernel thread actions (e.g blocking due to a pagefault or syscall) must
|
||||
// guarantee that an annotated thread is not allowed to (cooperatively)
|
||||
// reschedule until the annotated region is complete.
|
||||
//
|
||||
// It is an error to attempt to use a cooperatively scheduled resource (e.g.
|
||||
// Mutex) within a rescheduling-disabled region.
|
||||
//
|
||||
// All methods are async-signal safe.
|
||||
class SchedulingGuard {
|
||||
public:
|
||||
// Returns true iff the calling thread may be cooperatively rescheduled.
|
||||
static bool ReschedulingIsAllowed();
|
||||
SchedulingGuard(const SchedulingGuard&) = delete;
|
||||
SchedulingGuard& operator=(const SchedulingGuard&) = delete;
|
||||
|
||||
private:
|
||||
// Disable cooperative rescheduling of the calling thread. It may still
|
||||
// initiate scheduling operations (e.g. wake-ups), however, it may not itself
|
||||
// reschedule. Nestable. The returned result is opaque, clients should not
|
||||
// attempt to interpret it.
|
||||
// REQUIRES: Result must be passed to a pairing EnableScheduling().
|
||||
static bool DisableRescheduling();
|
||||
|
||||
// Marks the end of a rescheduling disabled region, previously started by
|
||||
// DisableRescheduling().
|
||||
// REQUIRES: Pairs with innermost call (and result) of DisableRescheduling().
|
||||
static void EnableRescheduling(bool disable_result);
|
||||
|
||||
// A scoped helper for {Disable, Enable}Rescheduling().
|
||||
// REQUIRES: destructor must run in same thread as constructor.
|
||||
struct ScopedDisable {
|
||||
ScopedDisable() { disabled = SchedulingGuard::DisableRescheduling(); }
|
||||
~ScopedDisable() { SchedulingGuard::EnableRescheduling(disabled); }
|
||||
|
||||
bool disabled;
|
||||
};
|
||||
|
||||
// A scoped helper to enable rescheduling temporarily.
|
||||
// REQUIRES: destructor must run in same thread as constructor.
|
||||
class ScopedEnable {
|
||||
public:
|
||||
ScopedEnable();
|
||||
~ScopedEnable();
|
||||
|
||||
private:
|
||||
int scheduling_disabled_depth_;
|
||||
};
|
||||
|
||||
// Access to SchedulingGuard is explicitly permitted.
|
||||
friend class absl::CondVar;
|
||||
friend class absl::Mutex;
|
||||
friend class SchedulingHelper;
|
||||
friend class SpinLock;
|
||||
friend int absl::synchronization_internal::MutexDelay(int32_t c, int mode);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// End of public interfaces.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline bool SchedulingGuard::ReschedulingIsAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool SchedulingGuard::DisableRescheduling() {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SchedulingGuard::EnableRescheduling(bool /* disable_result */) {
|
||||
return;
|
||||
}
|
||||
|
||||
inline SchedulingGuard::ScopedEnable::ScopedEnable()
|
||||
: scheduling_disabled_depth_(0) {}
|
||||
inline SchedulingGuard::ScopedEnable::~ScopedEnable() {
|
||||
ABSL_RAW_CHECK(scheduling_disabled_depth_ == 0, "disable unused warning");
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_LOW_LEVEL_SCHEDULING_H_
|
||||
@@ -0,0 +1,108 @@
|
||||
// Copyright 2023 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
|
||||
#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace nullability_internal {
|
||||
|
||||
// `IsNullabilityCompatible` checks whether its first argument is a class
|
||||
// explicitly tagged as supporting nullability annotations. The tag is the type
|
||||
// declaration `absl_nullability_compatible`.
|
||||
template <typename, typename = void>
|
||||
struct IsNullabilityCompatible : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsNullabilityCompatible<
|
||||
T, absl::void_t<typename T::absl_nullability_compatible>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsSupportedType = IsNullabilityCompatible<T>::value;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsSupportedType<T*> = true;
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool IsSupportedType<T U::*> = true;
|
||||
|
||||
template <typename T, typename... Deleter>
|
||||
constexpr bool IsSupportedType<std::unique_ptr<T, Deleter...>> = true;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool IsSupportedType<std::shared_ptr<T>> = true;
|
||||
|
||||
template <typename T>
|
||||
struct EnableNullable {
|
||||
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
|
||||
"Template argument must be a raw or supported smart pointer "
|
||||
"type. See absl/base/nullability.h.");
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EnableNonnull {
|
||||
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
|
||||
"Template argument must be a raw or supported smart pointer "
|
||||
"type. See absl/base/nullability.h.");
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct EnableNullabilityUnknown {
|
||||
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
|
||||
"Template argument must be a raw or supported smart pointer "
|
||||
"type. See absl/base/nullability.h.");
|
||||
using type = T;
|
||||
};
|
||||
|
||||
// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These
|
||||
// only support raw pointers, and conditionally enabling them only for raw
|
||||
// pointers inhibits template arg deduction. Ideally, they would support all
|
||||
// pointer-like types.
|
||||
template <typename T, typename = typename EnableNullable<T>::type>
|
||||
using NullableImpl
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
|
||||
[[clang::annotate("Nullable")]]
|
||||
#endif
|
||||
= T;
|
||||
|
||||
template <typename T, typename = typename EnableNonnull<T>::type>
|
||||
using NonnullImpl
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
|
||||
[[clang::annotate("Nonnull")]]
|
||||
#endif
|
||||
= T;
|
||||
|
||||
template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
|
||||
using NullabilityUnknownImpl
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
|
||||
[[clang::annotate("Nullability_Unspecified")]]
|
||||
#endif
|
||||
= T;
|
||||
|
||||
} // namespace nullability_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||
#define ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||
|
||||
// This header defines two macros:
|
||||
//
|
||||
// If the platform supports thread-local storage:
|
||||
//
|
||||
// * ABSL_PER_THREAD_TLS_KEYWORD is the C keyword needed to declare a
|
||||
// thread-local variable
|
||||
// * ABSL_PER_THREAD_TLS is 1
|
||||
//
|
||||
// Otherwise:
|
||||
//
|
||||
// * ABSL_PER_THREAD_TLS_KEYWORD is empty
|
||||
// * ABSL_PER_THREAD_TLS is 0
|
||||
//
|
||||
// Microsoft C supports thread-local storage.
|
||||
// GCC supports it if the appropriate version of glibc is available,
|
||||
// which the programmer can indicate by defining ABSL_HAVE_TLS
|
||||
|
||||
#include "absl/base/port.h" // For ABSL_HAVE_TLS
|
||||
|
||||
#if defined(ABSL_PER_THREAD_TLS)
|
||||
#error ABSL_PER_THREAD_TLS cannot be directly set
|
||||
#elif defined(ABSL_PER_THREAD_TLS_KEYWORD)
|
||||
#error ABSL_PER_THREAD_TLS_KEYWORD cannot be directly set
|
||||
#elif defined(ABSL_HAVE_TLS)
|
||||
#define ABSL_PER_THREAD_TLS_KEYWORD __thread
|
||||
#define ABSL_PER_THREAD_TLS 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_PER_THREAD_TLS_KEYWORD __declspec(thread)
|
||||
#define ABSL_PER_THREAD_TLS 1
|
||||
#else
|
||||
#define ABSL_PER_THREAD_TLS_KEYWORD
|
||||
#define ABSL_PER_THREAD_TLS 0
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_PER_THREAD_TLS_H_
|
||||
@@ -0,0 +1,217 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Thread-safe logging routines that do not allocate any memory or
|
||||
// acquire any locks, and can therefore be used by low-level memory
|
||||
// allocation, synchronization, and signal-handling code.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||
#define ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/atomic_hook.h"
|
||||
#include "absl/base/log_severity.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
// This is similar to LOG(severity) << format..., but
|
||||
// * it is to be used ONLY by low-level modules that can't use normal LOG()
|
||||
// * it is designed to be a low-level logger that does not allocate any
|
||||
// memory and does not need any locks, hence:
|
||||
// * it logs straight and ONLY to STDERR w/o buffering
|
||||
// * it uses an explicit printf-format and arguments list
|
||||
// * it will silently chop off really long message strings
|
||||
// Usage example:
|
||||
// ABSL_RAW_LOG(ERROR, "Failed foo with %i: %s", status, error);
|
||||
// This will print an almost standard log line like this to stderr only:
|
||||
// E0821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
|
||||
|
||||
#define ABSL_RAW_LOG(severity, ...) \
|
||||
do { \
|
||||
constexpr const char* absl_raw_log_internal_basename = \
|
||||
::absl::raw_log_internal::Basename(__FILE__, sizeof(__FILE__) - 1); \
|
||||
::absl::raw_log_internal::RawLog(ABSL_RAW_LOG_INTERNAL_##severity, \
|
||||
absl_raw_log_internal_basename, __LINE__, \
|
||||
__VA_ARGS__); \
|
||||
ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \
|
||||
} while (0)
|
||||
|
||||
// Similar to CHECK(condition) << message, but for low-level modules:
|
||||
// we use only ABSL_RAW_LOG that does not allocate memory.
|
||||
// We do not want to provide args list here to encourage this usage:
|
||||
// if (!cond) ABSL_RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
|
||||
// so that the args are not computed when not needed.
|
||||
#define ABSL_RAW_CHECK(condition, message) \
|
||||
do { \
|
||||
if (ABSL_PREDICT_FALSE(!(condition))) { \
|
||||
ABSL_RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// ABSL_INTERNAL_LOG and ABSL_INTERNAL_CHECK work like the RAW variants above,
|
||||
// except that if the richer log library is linked into the binary, we dispatch
|
||||
// to that instead. This is potentially useful for internal logging and
|
||||
// assertions, where we are using RAW_LOG neither for its async-signal-safety
|
||||
// nor for its non-allocating nature, but rather because raw logging has very
|
||||
// few other dependencies.
|
||||
//
|
||||
// The API is a subset of the above: each macro only takes two arguments. Use
|
||||
// StrCat if you need to build a richer message.
|
||||
#define ABSL_INTERNAL_LOG(severity, message) \
|
||||
do { \
|
||||
constexpr const char* absl_raw_log_internal_filename = __FILE__; \
|
||||
::absl::raw_log_internal::internal_log_function( \
|
||||
ABSL_RAW_LOG_INTERNAL_##severity, absl_raw_log_internal_filename, \
|
||||
__LINE__, message); \
|
||||
ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_##severity; \
|
||||
} while (0)
|
||||
|
||||
#define ABSL_INTERNAL_CHECK(condition, message) \
|
||||
do { \
|
||||
if (ABSL_PREDICT_FALSE(!(condition))) { \
|
||||
std::string death_message = "Check " #condition " failed: "; \
|
||||
death_message += std::string(message); \
|
||||
ABSL_INTERNAL_LOG(FATAL, death_message); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
#define ABSL_RAW_DLOG(severity, ...) ABSL_RAW_LOG(severity, __VA_ARGS__)
|
||||
#define ABSL_RAW_DCHECK(condition, message) ABSL_RAW_CHECK(condition, message)
|
||||
|
||||
#else // NDEBUG
|
||||
|
||||
#define ABSL_RAW_DLOG(severity, ...) \
|
||||
while (false) ABSL_RAW_LOG(severity, __VA_ARGS__)
|
||||
#define ABSL_RAW_DCHECK(condition, message) \
|
||||
while (false) ABSL_RAW_CHECK(condition, message)
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
#define ABSL_RAW_LOG_INTERNAL_INFO ::absl::LogSeverity::kInfo
|
||||
#define ABSL_RAW_LOG_INTERNAL_WARNING ::absl::LogSeverity::kWarning
|
||||
#define ABSL_RAW_LOG_INTERNAL_ERROR ::absl::LogSeverity::kError
|
||||
#define ABSL_RAW_LOG_INTERNAL_FATAL ::absl::LogSeverity::kFatal
|
||||
#define ABSL_RAW_LOG_INTERNAL_DFATAL ::absl::kLogDebugFatal
|
||||
#define ABSL_RAW_LOG_INTERNAL_LEVEL(severity) \
|
||||
::absl::NormalizeLogSeverity(severity)
|
||||
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_INFO
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_WARNING
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_ERROR
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_FATAL ABSL_UNREACHABLE()
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_DFATAL
|
||||
#define ABSL_RAW_LOG_INTERNAL_MAYBE_UNREACHABLE_LEVEL(severity)
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace raw_log_internal {
|
||||
|
||||
// Helper function to implement ABSL_RAW_LOG
|
||||
// Logs format... at "severity" level, reporting it
|
||||
// as called from file:line.
|
||||
// This does not allocate memory or acquire locks.
|
||||
void RawLog(absl::LogSeverity severity, const char* file, int line,
|
||||
const char* format, ...) ABSL_PRINTF_ATTRIBUTE(4, 5);
|
||||
|
||||
// Writes the provided buffer directly to stderr, in a signal-safe, low-level
|
||||
// manner. Preserves errno.
|
||||
void AsyncSignalSafeWriteError(const char* s, size_t len);
|
||||
|
||||
// compile-time function to get the "base" filename, that is, the part of
|
||||
// a filename after the last "/" or "\" path separator. The search starts at
|
||||
// the end of the string; the second parameter is the length of the string.
|
||||
constexpr const char* Basename(const char* fname, int offset) {
|
||||
return offset == 0 || fname[offset - 1] == '/' || fname[offset - 1] == '\\'
|
||||
? fname + offset
|
||||
: Basename(fname, offset - 1);
|
||||
}
|
||||
|
||||
// For testing only.
|
||||
// Returns true if raw logging is fully supported. When it is not
|
||||
// fully supported, no messages will be emitted, but a log at FATAL
|
||||
// severity will cause an abort.
|
||||
//
|
||||
// TODO(gfalcon): Come up with a better name for this method.
|
||||
bool RawLoggingFullySupported();
|
||||
|
||||
// Function type for a raw_log customization hook for suppressing messages
|
||||
// by severity, and for writing custom prefixes on non-suppressed messages.
|
||||
//
|
||||
// The installed hook is called for every raw log invocation. The message will
|
||||
// be logged to stderr only if the hook returns true. FATAL errors will cause
|
||||
// the process to abort, even if writing to stderr is suppressed. The hook is
|
||||
// also provided with an output buffer, where it can write a custom log message
|
||||
// prefix.
|
||||
//
|
||||
// The raw_log system does not allocate memory or grab locks. User-provided
|
||||
// hooks must avoid these operations, and must not throw exceptions.
|
||||
//
|
||||
// 'severity' is the severity level of the message being written.
|
||||
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
|
||||
// was located.
|
||||
// 'buf' and 'buf_size' are pointers to the buffer and buffer size. If the
|
||||
// hook writes a prefix, it must increment *buf and decrement *buf_size
|
||||
// accordingly.
|
||||
using LogFilterAndPrefixHook = bool (*)(absl::LogSeverity severity,
|
||||
const char* file, int line, char** buf,
|
||||
int* buf_size);
|
||||
|
||||
// Function type for a raw_log customization hook called to abort a process
|
||||
// when a FATAL message is logged. If the provided AbortHook() returns, the
|
||||
// logging system will call abort().
|
||||
//
|
||||
// 'file' and 'line' are the file and line number where the ABSL_RAW_LOG macro
|
||||
// was located.
|
||||
// The NUL-terminated logged message lives in the buffer between 'buf_start'
|
||||
// and 'buf_end'. 'prefix_end' points to the first non-prefix character of the
|
||||
// buffer (as written by the LogFilterAndPrefixHook.)
|
||||
//
|
||||
// The lifetime of the filename and message buffers will not end while the
|
||||
// process remains alive.
|
||||
using AbortHook = void (*)(const char* file, int line, const char* buf_start,
|
||||
const char* prefix_end, const char* buf_end);
|
||||
|
||||
// Internal logging function for ABSL_INTERNAL_LOG to dispatch to.
|
||||
//
|
||||
// TODO(gfalcon): When string_view no longer depends on base, change this
|
||||
// interface to take its message as a string_view instead.
|
||||
using InternalLogFunction = void (*)(absl::LogSeverity severity,
|
||||
const char* file, int line,
|
||||
const std::string& message);
|
||||
|
||||
ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_DLL extern base_internal::AtomicHook<
|
||||
InternalLogFunction>
|
||||
internal_log_function;
|
||||
|
||||
// Registers hooks of the above types. Only a single hook of each type may be
|
||||
// registered. It is an error to call these functions multiple times with
|
||||
// different input arguments.
|
||||
//
|
||||
// These functions are safe to call at any point during initialization; they do
|
||||
// not block or malloc, and are async-signal safe.
|
||||
void RegisterLogFilterAndPrefixHook(LogFilterAndPrefixHook func);
|
||||
void RegisterAbortHook(AbortHook func);
|
||||
void RegisterInternalLogFunction(InternalLogFunction func);
|
||||
|
||||
} // namespace raw_log_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_RAW_LOGGING_H_
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Core interfaces and definitions used by by low-level interfaces such as
|
||||
// SpinLock.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
#define ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Used to describe how a thread may be scheduled. Typically associated with
|
||||
// the declaration of a resource supporting synchronized access.
|
||||
//
|
||||
// SCHEDULE_COOPERATIVE_AND_KERNEL:
|
||||
// Specifies that when waiting, a cooperative thread (e.g. a Fiber) may
|
||||
// reschedule (using base::scheduling semantics); allowing other cooperative
|
||||
// threads to proceed.
|
||||
//
|
||||
// SCHEDULE_KERNEL_ONLY: (Also described as "non-cooperative")
|
||||
// Specifies that no cooperative scheduling semantics may be used, even if the
|
||||
// current thread is itself cooperatively scheduled. This means that
|
||||
// cooperative threads will NOT allow other cooperative threads to execute in
|
||||
// their place while waiting for a resource of this type. Host operating system
|
||||
// semantics (e.g. a futex) may still be used.
|
||||
//
|
||||
// When optional, clients should strongly prefer SCHEDULE_COOPERATIVE_AND_KERNEL
|
||||
// by default. SCHEDULE_KERNEL_ONLY should only be used for resources on which
|
||||
// base::scheduling (e.g. the implementation of a Scheduler) may depend.
|
||||
//
|
||||
// NOTE: Cooperative resources may not be nested below non-cooperative ones.
|
||||
// This means that it is invalid to to acquire a SCHEDULE_COOPERATIVE_AND_KERNEL
|
||||
// resource if a SCHEDULE_KERNEL_ONLY resource is already held.
|
||||
enum SchedulingMode {
|
||||
SCHEDULE_KERNEL_ONLY = 0, // Allow scheduling only the host OS.
|
||||
SCHEDULE_COOPERATIVE_AND_KERNEL, // Also allow cooperative scheduling.
|
||||
};
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SCHEDULING_MODE_H_
|
||||
@@ -0,0 +1,275 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
|
||||
// Most users requiring mutual exclusion should use Mutex.
|
||||
// SpinLock is provided for use in two situations:
|
||||
// - for use by Abseil internal code that Mutex itself depends on
|
||||
// - for async signal safety (see below)
|
||||
|
||||
// SpinLock with a base_internal::SchedulingMode::SCHEDULE_KERNEL_ONLY is async
|
||||
// signal safe. If a spinlock is used within a signal handler, all code that
|
||||
// acquires the lock must ensure that the signal cannot arrive while they are
|
||||
// holding the lock. Typically, this is done by blocking the signal.
|
||||
//
|
||||
// Threads waiting on a SpinLock may be woken in an arbitrary order.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||
#define ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/const_init.h"
|
||||
#include "absl/base/dynamic_annotations.h"
|
||||
#include "absl/base/internal/low_level_scheduling.h"
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
#include "absl/base/internal/scheduling_mode.h"
|
||||
#include "absl/base/internal/tsan_mutex_interface.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace tcmalloc {
|
||||
namespace tcmalloc_internal {
|
||||
|
||||
class AllocationGuardSpinLockHolder;
|
||||
|
||||
} // namespace tcmalloc_internal
|
||||
} // namespace tcmalloc
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
class ABSL_LOCKABLE ABSL_ATTRIBUTE_WARN_UNUSED SpinLock {
|
||||
public:
|
||||
SpinLock() : lockword_(kSpinLockCooperative) {
|
||||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||
}
|
||||
|
||||
// Constructors that allow non-cooperative spinlocks to be created for use
|
||||
// inside thread schedulers. Normal clients should not use these.
|
||||
explicit SpinLock(base_internal::SchedulingMode mode);
|
||||
|
||||
// Constructor for global SpinLock instances. See absl/base/const_init.h.
|
||||
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
|
||||
: lockword_(IsCooperative(mode) ? kSpinLockCooperative : 0) {}
|
||||
|
||||
// For global SpinLock instances prefer trivial destructor when possible.
|
||||
// Default but non-trivial destructor in some build configurations causes an
|
||||
// extra static initializer.
|
||||
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||
~SpinLock() { ABSL_TSAN_MUTEX_DESTROY(this, __tsan_mutex_not_static); }
|
||||
#else
|
||||
~SpinLock() = default;
|
||||
#endif
|
||||
|
||||
// Acquire this SpinLock.
|
||||
inline void Lock() ABSL_EXCLUSIVE_LOCK_FUNCTION() {
|
||||
ABSL_TSAN_MUTEX_PRE_LOCK(this, 0);
|
||||
if (!TryLockImpl()) {
|
||||
SlowLock();
|
||||
}
|
||||
ABSL_TSAN_MUTEX_POST_LOCK(this, 0, 0);
|
||||
}
|
||||
|
||||
// Try to acquire this SpinLock without blocking and return true if the
|
||||
// acquisition was successful. If the lock was not acquired, false is
|
||||
// returned. If this SpinLock is free at the time of the call, TryLock
|
||||
// will return true with high probability.
|
||||
ABSL_MUST_USE_RESULT inline bool TryLock()
|
||||
ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
|
||||
ABSL_TSAN_MUTEX_PRE_LOCK(this, __tsan_mutex_try_lock);
|
||||
bool res = TryLockImpl();
|
||||
ABSL_TSAN_MUTEX_POST_LOCK(
|
||||
this, __tsan_mutex_try_lock | (res ? 0 : __tsan_mutex_try_lock_failed),
|
||||
0);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Release this SpinLock, which must be held by the calling thread.
|
||||
inline void Unlock() ABSL_UNLOCK_FUNCTION() {
|
||||
ABSL_TSAN_MUTEX_PRE_UNLOCK(this, 0);
|
||||
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
|
||||
lock_value = lockword_.exchange(lock_value & kSpinLockCooperative,
|
||||
std::memory_order_release);
|
||||
|
||||
if ((lock_value & kSpinLockDisabledScheduling) != 0) {
|
||||
base_internal::SchedulingGuard::EnableRescheduling(true);
|
||||
}
|
||||
if ((lock_value & kWaitTimeMask) != 0) {
|
||||
// Collect contentionz profile info, and speed the wakeup of any waiter.
|
||||
// The wait_cycles value indicates how long this thread spent waiting
|
||||
// for the lock.
|
||||
SlowUnlock(lock_value);
|
||||
}
|
||||
ABSL_TSAN_MUTEX_POST_UNLOCK(this, 0);
|
||||
}
|
||||
|
||||
// Determine if the lock is held. When the lock is held by the invoking
|
||||
// thread, true will always be returned. Intended to be used as
|
||||
// CHECK(lock.IsHeld()).
|
||||
ABSL_MUST_USE_RESULT inline bool IsHeld() const {
|
||||
return (lockword_.load(std::memory_order_relaxed) & kSpinLockHeld) != 0;
|
||||
}
|
||||
|
||||
// Return immediately if this thread holds the SpinLock exclusively.
|
||||
// Otherwise, report an error by crashing with a diagnostic.
|
||||
inline void AssertHeld() const ABSL_ASSERT_EXCLUSIVE_LOCK() {
|
||||
if (!IsHeld()) {
|
||||
ABSL_RAW_LOG(FATAL, "thread should hold the lock on SpinLock");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// These should not be exported except for testing.
|
||||
|
||||
// Store number of cycles between wait_start_time and wait_end_time in a
|
||||
// lock value.
|
||||
static uint32_t EncodeWaitCycles(int64_t wait_start_time,
|
||||
int64_t wait_end_time);
|
||||
|
||||
// Extract number of wait cycles in a lock value.
|
||||
static int64_t DecodeWaitCycles(uint32_t lock_value);
|
||||
|
||||
// Provide access to protected method above. Use for testing only.
|
||||
friend struct SpinLockTest;
|
||||
friend class tcmalloc::tcmalloc_internal::AllocationGuardSpinLockHolder;
|
||||
|
||||
private:
|
||||
// lockword_ is used to store the following:
|
||||
//
|
||||
// bit[0] encodes whether a lock is being held.
|
||||
// bit[1] encodes whether a lock uses cooperative scheduling.
|
||||
// bit[2] encodes whether the current lock holder disabled scheduling when
|
||||
// acquiring the lock. Only set when kSpinLockHeld is also set.
|
||||
// bit[3:31] encodes time a lock spent on waiting as a 29-bit unsigned int.
|
||||
// This is set by the lock holder to indicate how long it waited on
|
||||
// the lock before eventually acquiring it. The number of cycles is
|
||||
// encoded as a 29-bit unsigned int, or in the case that the current
|
||||
// holder did not wait but another waiter is queued, the LSB
|
||||
// (kSpinLockSleeper) is set. The implementation does not explicitly
|
||||
// track the number of queued waiters beyond this. It must always be
|
||||
// assumed that waiters may exist if the current holder was required to
|
||||
// queue.
|
||||
//
|
||||
// Invariant: if the lock is not held, the value is either 0 or
|
||||
// kSpinLockCooperative.
|
||||
static constexpr uint32_t kSpinLockHeld = 1;
|
||||
static constexpr uint32_t kSpinLockCooperative = 2;
|
||||
static constexpr uint32_t kSpinLockDisabledScheduling = 4;
|
||||
static constexpr uint32_t kSpinLockSleeper = 8;
|
||||
// Includes kSpinLockSleeper.
|
||||
static constexpr uint32_t kWaitTimeMask =
|
||||
~(kSpinLockHeld | kSpinLockCooperative | kSpinLockDisabledScheduling);
|
||||
|
||||
// Returns true if the provided scheduling mode is cooperative.
|
||||
static constexpr bool IsCooperative(
|
||||
base_internal::SchedulingMode scheduling_mode) {
|
||||
return scheduling_mode == base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
||||
}
|
||||
|
||||
bool IsCooperative() const {
|
||||
return lockword_.load(std::memory_order_relaxed) & kSpinLockCooperative;
|
||||
}
|
||||
|
||||
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
|
||||
void SlowLock() ABSL_ATTRIBUTE_COLD;
|
||||
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
|
||||
uint32_t SpinLoop();
|
||||
|
||||
inline bool TryLockImpl() {
|
||||
uint32_t lock_value = lockword_.load(std::memory_order_relaxed);
|
||||
return (TryLockInternal(lock_value, 0) & kSpinLockHeld) == 0;
|
||||
}
|
||||
|
||||
std::atomic<uint32_t> lockword_;
|
||||
|
||||
SpinLock(const SpinLock&) = delete;
|
||||
SpinLock& operator=(const SpinLock&) = delete;
|
||||
};
|
||||
|
||||
// Corresponding locker object that arranges to acquire a spinlock for
|
||||
// the duration of a C++ scope.
|
||||
//
|
||||
// TODO(b/176172494): Use only [[nodiscard]] when baseline is raised.
|
||||
// TODO(b/6695610): Remove forward declaration when #ifdef is no longer needed.
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(nodiscard)
|
||||
class [[nodiscard]] SpinLockHolder;
|
||||
#else
|
||||
class ABSL_MUST_USE_RESULT ABSL_ATTRIBUTE_TRIVIAL_ABI SpinLockHolder;
|
||||
#endif
|
||||
|
||||
class ABSL_SCOPED_LOCKABLE SpinLockHolder {
|
||||
public:
|
||||
inline explicit SpinLockHolder(SpinLock* l) ABSL_EXCLUSIVE_LOCK_FUNCTION(l)
|
||||
: lock_(l) {
|
||||
l->Lock();
|
||||
}
|
||||
inline ~SpinLockHolder() ABSL_UNLOCK_FUNCTION() { lock_->Unlock(); }
|
||||
|
||||
SpinLockHolder(const SpinLockHolder&) = delete;
|
||||
SpinLockHolder& operator=(const SpinLockHolder&) = delete;
|
||||
|
||||
private:
|
||||
SpinLock* lock_;
|
||||
};
|
||||
|
||||
// Register a hook for profiling support.
|
||||
//
|
||||
// The function pointer registered here will be called whenever a spinlock is
|
||||
// contended. The callback is given an opaque handle to the contended spinlock
|
||||
// and the number of wait cycles. This is thread-safe, but only a single
|
||||
// profiler can be registered. It is an error to call this function multiple
|
||||
// times with different arguments.
|
||||
void RegisterSpinLockProfiler(void (*fn)(const void* lock,
|
||||
int64_t wait_cycles));
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Public interface ends here.
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// If (result & kSpinLockHeld) == 0, then *this was successfully locked.
|
||||
// Otherwise, returns last observed value for lockword_.
|
||||
inline uint32_t SpinLock::TryLockInternal(uint32_t lock_value,
|
||||
uint32_t wait_cycles) {
|
||||
if ((lock_value & kSpinLockHeld) != 0) {
|
||||
return lock_value;
|
||||
}
|
||||
|
||||
uint32_t sched_disabled_bit = 0;
|
||||
if ((lock_value & kSpinLockCooperative) == 0) {
|
||||
// For non-cooperative locks we must make sure we mark ourselves as
|
||||
// non-reschedulable before we attempt to CompareAndSwap.
|
||||
if (base_internal::SchedulingGuard::DisableRescheduling()) {
|
||||
sched_disabled_bit = kSpinLockDisabledScheduling;
|
||||
}
|
||||
}
|
||||
|
||||
if (!lockword_.compare_exchange_strong(
|
||||
lock_value,
|
||||
kSpinLockHeld | lock_value | wait_cycles | sched_disabled_bit,
|
||||
std::memory_order_acquire, std::memory_order_relaxed)) {
|
||||
base_internal::SchedulingGuard::EnableRescheduling(sched_disabled_bit != 0);
|
||||
}
|
||||
|
||||
return lock_value;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_SPINLOCK_H_
|
||||
@@ -0,0 +1,269 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Each active thread has an ThreadIdentity that may represent the thread in
|
||||
// various level interfaces. ThreadIdentity objects are never deallocated.
|
||||
// When a thread terminates, its ThreadIdentity object may be reused for a
|
||||
// thread created later.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||
#define ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <pthread.h>
|
||||
// Defines __GOOGLE_GRTE_VERSION__ (via glibc-specific features.h) when
|
||||
// supported.
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
struct SynchLocksHeld;
|
||||
struct SynchWaitParams;
|
||||
|
||||
namespace base_internal {
|
||||
|
||||
class SpinLock;
|
||||
struct ThreadIdentity;
|
||||
|
||||
// Used by the implementation of absl::Mutex and absl::CondVar.
|
||||
struct PerThreadSynch {
|
||||
// The internal representation of absl::Mutex and absl::CondVar rely
|
||||
// on the alignment of PerThreadSynch. Both store the address of the
|
||||
// PerThreadSynch in the high-order bits of their internal state,
|
||||
// which means the low kLowZeroBits of the address of PerThreadSynch
|
||||
// must be zero.
|
||||
static constexpr int kLowZeroBits = 8;
|
||||
static constexpr int kAlignment = 1 << kLowZeroBits;
|
||||
|
||||
// Returns the associated ThreadIdentity.
|
||||
// This can be implemented as a cast because we guarantee
|
||||
// PerThreadSynch is the first element of ThreadIdentity.
|
||||
ThreadIdentity* thread_identity() {
|
||||
return reinterpret_cast<ThreadIdentity*>(this);
|
||||
}
|
||||
|
||||
PerThreadSynch* next; // Circular waiter queue; initialized to 0.
|
||||
PerThreadSynch* skip; // If non-zero, all entries in Mutex queue
|
||||
// up to and including "skip" have same
|
||||
// condition as this, and will be woken later
|
||||
bool may_skip; // if false while on mutex queue, a mutex unlocker
|
||||
// is using this PerThreadSynch as a terminator. Its
|
||||
// skip field must not be filled in because the loop
|
||||
// might then skip over the terminator.
|
||||
bool wake; // This thread is to be woken from a Mutex.
|
||||
// If "x" is on a waiter list for a mutex, "x->cond_waiter" is true iff the
|
||||
// waiter is waiting on the mutex as part of a CV Wait or Mutex Await.
|
||||
//
|
||||
// The value of "x->cond_waiter" is meaningless if "x" is not on a
|
||||
// Mutex waiter list.
|
||||
bool cond_waiter;
|
||||
bool maybe_unlocking; // Valid at head of Mutex waiter queue;
|
||||
// true if UnlockSlow could be searching
|
||||
// for a waiter to wake. Used for an optimization
|
||||
// in Enqueue(). true is always a valid value.
|
||||
// Can be reset to false when the unlocker or any
|
||||
// writer releases the lock, or a reader fully
|
||||
// releases the lock. It may not be set to false
|
||||
// by a reader that decrements the count to
|
||||
// non-zero. protected by mutex spinlock
|
||||
bool suppress_fatal_errors; // If true, try to proceed even in the face
|
||||
// of broken invariants. This is used within
|
||||
// fatal signal handlers to improve the
|
||||
// chances of debug logging information being
|
||||
// output successfully.
|
||||
int priority; // Priority of thread (updated every so often).
|
||||
|
||||
// State values:
|
||||
// kAvailable: This PerThreadSynch is available.
|
||||
// kQueued: This PerThreadSynch is unavailable, it's currently queued on a
|
||||
// Mutex or CondVar waistlist.
|
||||
//
|
||||
// Transitions from kQueued to kAvailable require a release
|
||||
// barrier. This is needed as a waiter may use "state" to
|
||||
// independently observe that it's no longer queued.
|
||||
//
|
||||
// Transitions from kAvailable to kQueued require no barrier, they
|
||||
// are externally ordered by the Mutex.
|
||||
enum State { kAvailable, kQueued };
|
||||
std::atomic<State> state;
|
||||
|
||||
// The wait parameters of the current wait. waitp is null if the
|
||||
// thread is not waiting. Transitions from null to non-null must
|
||||
// occur before the enqueue commit point (state = kQueued in
|
||||
// Enqueue() and CondVarEnqueue()). Transitions from non-null to
|
||||
// null must occur after the wait is finished (state = kAvailable in
|
||||
// Mutex::Block() and CondVar::WaitCommon()). This field may be
|
||||
// changed only by the thread that describes this PerThreadSynch. A
|
||||
// special case is Fer(), which calls Enqueue() on another thread,
|
||||
// but with an identical SynchWaitParams pointer, thus leaving the
|
||||
// pointer unchanged.
|
||||
SynchWaitParams* waitp;
|
||||
|
||||
intptr_t readers; // Number of readers in mutex.
|
||||
|
||||
// When priority will next be read (cycles).
|
||||
int64_t next_priority_read_cycles;
|
||||
|
||||
// Locks held; used during deadlock detection.
|
||||
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
|
||||
SynchLocksHeld* all_locks;
|
||||
};
|
||||
|
||||
// The instances of this class are allocated in NewThreadIdentity() with an
|
||||
// alignment of PerThreadSynch::kAlignment.
|
||||
//
|
||||
// NOTE: The layout of fields in this structure is critical, please do not
|
||||
// add, remove, or modify the field placements without fully auditing the
|
||||
// layout.
|
||||
struct ThreadIdentity {
|
||||
// Must be the first member. The Mutex implementation requires that
|
||||
// the PerThreadSynch object associated with each thread is
|
||||
// PerThreadSynch::kAlignment aligned. We provide this alignment on
|
||||
// ThreadIdentity itself.
|
||||
PerThreadSynch per_thread_synch;
|
||||
|
||||
// Private: Reserved for absl::synchronization_internal::Waiter.
|
||||
struct WaiterState {
|
||||
alignas(void*) char data[256];
|
||||
} waiter_state;
|
||||
|
||||
// Used by PerThreadSem::{Get,Set}ThreadBlockedCounter().
|
||||
std::atomic<int>* blocked_count_ptr;
|
||||
|
||||
// The following variables are mostly read/written just by the
|
||||
// thread itself. The only exception is that these are read by
|
||||
// a ticker thread as a hint.
|
||||
std::atomic<int> ticker; // Tick counter, incremented once per second.
|
||||
std::atomic<int> wait_start; // Ticker value when thread started waiting.
|
||||
std::atomic<bool> is_idle; // Has thread become idle yet?
|
||||
|
||||
ThreadIdentity* next;
|
||||
};
|
||||
|
||||
// Returns the ThreadIdentity object representing the calling thread; guaranteed
|
||||
// to be unique for its lifetime. The returned object will remain valid for the
|
||||
// program's lifetime; although it may be re-assigned to a subsequent thread.
|
||||
// If one does not exist, return nullptr instead.
|
||||
//
|
||||
// Does not malloc(*), and is async-signal safe.
|
||||
// [*] Technically pthread_setspecific() does malloc on first use; however this
|
||||
// is handled internally within tcmalloc's initialization already. Note that
|
||||
// darwin does *not* use tcmalloc, so this can catch you if using MallocHooks
|
||||
// on Apple platforms. Whatever function is calling your MallocHooks will need
|
||||
// to watch for recursion on Apple platforms.
|
||||
//
|
||||
// New ThreadIdentity objects can be constructed and associated with a thread
|
||||
// by calling GetOrCreateCurrentThreadIdentity() in per-thread-sem.h.
|
||||
ThreadIdentity* CurrentThreadIdentityIfPresent();
|
||||
|
||||
using ThreadIdentityReclaimerFunction = void (*)(void*);
|
||||
|
||||
// Sets the current thread identity to the given value. 'reclaimer' is a
|
||||
// pointer to the global function for cleaning up instances on thread
|
||||
// destruction.
|
||||
void SetCurrentThreadIdentity(ThreadIdentity* identity,
|
||||
ThreadIdentityReclaimerFunction reclaimer);
|
||||
|
||||
// Removes the currently associated ThreadIdentity from the running thread.
|
||||
// This must be called from inside the ThreadIdentityReclaimerFunction, and only
|
||||
// from that function.
|
||||
void ClearCurrentThreadIdentity();
|
||||
|
||||
// May be chosen at compile time via: -DABSL_FORCE_THREAD_IDENTITY_MODE=<mode
|
||||
// index>
|
||||
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||
#error ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC cannot be directly set
|
||||
#else
|
||||
#define ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC 0
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||
#error ABSL_THREAD_IDENTITY_MODE_USE_TLS cannot be directly set
|
||||
#else
|
||||
#define ABSL_THREAD_IDENTITY_MODE_USE_TLS 1
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
#error ABSL_THREAD_IDENTITY_MODE_USE_CPP11 cannot be directly set
|
||||
#else
|
||||
#define ABSL_THREAD_IDENTITY_MODE_USE_CPP11 2
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_THREAD_IDENTITY_MODE
|
||||
#error ABSL_THREAD_IDENTITY_MODE cannot be directly set
|
||||
#elif defined(ABSL_FORCE_THREAD_IDENTITY_MODE)
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_FORCE_THREAD_IDENTITY_MODE
|
||||
#elif defined(_WIN32) && !defined(__MINGW32__)
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
|
||||
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
|
||||
// Support for async-safe TLS was specifically added in GRTEv4. It's not
|
||||
// present in the upstream eglibc.
|
||||
// Note: Current default for production systems.
|
||||
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_TLS
|
||||
#else
|
||||
#define ABSL_THREAD_IDENTITY_MODE \
|
||||
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||
#endif
|
||||
|
||||
#if ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_TLS || \
|
||||
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
|
||||
|
||||
#if ABSL_PER_THREAD_TLS
|
||||
ABSL_CONST_INIT extern ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity*
|
||||
thread_identity_ptr;
|
||||
#elif defined(ABSL_HAVE_THREAD_LOCAL)
|
||||
ABSL_CONST_INIT extern thread_local ThreadIdentity* thread_identity_ptr;
|
||||
#else
|
||||
#error Thread-local storage not detected on this platform
|
||||
#endif
|
||||
|
||||
// thread_local variables cannot be in headers exposed by DLLs or in certain
|
||||
// build configurations on Apple platforms. However, it is important for
|
||||
// performance reasons in general that `CurrentThreadIdentityIfPresent` be
|
||||
// inlined. In the other cases we opt to have the function not be inlined. Note
|
||||
// that `CurrentThreadIdentityIfPresent` is declared above so we can exclude
|
||||
// this entire inline definition.
|
||||
#if !defined(__APPLE__) && !defined(ABSL_BUILD_DLL) && \
|
||||
!defined(ABSL_CONSUME_DLL)
|
||||
#define ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT 1
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_INTERNAL_INLINE_CURRENT_THREAD_IDENTITY_IF_PRESENT
|
||||
inline ThreadIdentity* CurrentThreadIdentityIfPresent() {
|
||||
return thread_identity_ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif ABSL_THREAD_IDENTITY_MODE != \
|
||||
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
|
||||
#error Unknown ABSL_THREAD_IDENTITY_MODE
|
||||
#endif
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_THREAD_IDENTITY_H_
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||
#define ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Helper functions that allow throwing exceptions consistently from anywhere.
|
||||
// The main use case is for header-based libraries (eg templates), as they will
|
||||
// be built by many different targets with their own compiler options.
|
||||
// In particular, this will allow a safe way to throw exceptions even if the
|
||||
// caller is compiled with -fno-exceptions. This is intended for implementing
|
||||
// things like map<>::at(), which the standard documents as throwing an
|
||||
// exception on error.
|
||||
//
|
||||
// Using other techniques like #if tricks could lead to ODR violations.
|
||||
//
|
||||
// You shouldn't use it unless you're writing code that you know will be built
|
||||
// both with and without exceptions and you need to conform to an interface
|
||||
// that uses exceptions.
|
||||
|
||||
[[noreturn]] void ThrowStdLogicError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdLogicError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdInvalidArgument(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdInvalidArgument(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdDomainError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdDomainError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdLengthError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdLengthError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdOutOfRange(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdOutOfRange(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdRuntimeError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdRuntimeError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdRangeError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdRangeError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdOverflowError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdOverflowError(const char* what_arg);
|
||||
[[noreturn]] void ThrowStdUnderflowError(const std::string& what_arg);
|
||||
[[noreturn]] void ThrowStdUnderflowError(const char* what_arg);
|
||||
|
||||
[[noreturn]] void ThrowStdBadFunctionCall();
|
||||
[[noreturn]] void ThrowStdBadAlloc();
|
||||
|
||||
// ThrowStdBadArrayNewLength() cannot be consistently supported because
|
||||
// std::bad_array_new_length is missing in libstdc++ until 4.9.0.
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.8.3/libstdc++/api/a01379_source.html
|
||||
// https://gcc.gnu.org/onlinedocs/gcc-4.9.0/libstdc++/api/a01327_source.html
|
||||
// libcxx (as of 3.2) and msvc (as of 2015) both have it.
|
||||
// [[noreturn]] void ThrowStdBadArrayNewLength();
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_THROW_DELEGATE_H_
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// This file is intended solely for spinlock.h.
|
||||
// It provides ThreadSanitizer annotations for custom mutexes.
|
||||
// See <sanitizer/tsan_interface.h> for meaning of these annotations.
|
||||
|
||||
#ifndef ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||
#define ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||
// Macro intended only for internal use.
|
||||
//
|
||||
// Checks whether LLVM Thread Sanitizer interfaces are available.
|
||||
// First made available in LLVM 5.0 (Sep 2017).
|
||||
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||
#error "ABSL_INTERNAL_HAVE_TSAN_INTERFACE cannot be directly set."
|
||||
#endif
|
||||
|
||||
#if defined(ABSL_HAVE_THREAD_SANITIZER) && defined(__has_include)
|
||||
#if __has_include(<sanitizer/tsan_interface.h>)
|
||||
#define ABSL_INTERNAL_HAVE_TSAN_INTERFACE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_INTERNAL_HAVE_TSAN_INTERFACE
|
||||
#include <sanitizer/tsan_interface.h>
|
||||
|
||||
#define ABSL_TSAN_MUTEX_CREATE __tsan_mutex_create
|
||||
#define ABSL_TSAN_MUTEX_DESTROY __tsan_mutex_destroy
|
||||
#define ABSL_TSAN_MUTEX_PRE_LOCK __tsan_mutex_pre_lock
|
||||
#define ABSL_TSAN_MUTEX_POST_LOCK __tsan_mutex_post_lock
|
||||
#define ABSL_TSAN_MUTEX_PRE_UNLOCK __tsan_mutex_pre_unlock
|
||||
#define ABSL_TSAN_MUTEX_POST_UNLOCK __tsan_mutex_post_unlock
|
||||
#define ABSL_TSAN_MUTEX_PRE_SIGNAL __tsan_mutex_pre_signal
|
||||
#define ABSL_TSAN_MUTEX_POST_SIGNAL __tsan_mutex_post_signal
|
||||
#define ABSL_TSAN_MUTEX_PRE_DIVERT __tsan_mutex_pre_divert
|
||||
#define ABSL_TSAN_MUTEX_POST_DIVERT __tsan_mutex_post_divert
|
||||
|
||||
#else
|
||||
|
||||
#define ABSL_TSAN_MUTEX_CREATE(...)
|
||||
#define ABSL_TSAN_MUTEX_DESTROY(...)
|
||||
#define ABSL_TSAN_MUTEX_PRE_LOCK(...)
|
||||
#define ABSL_TSAN_MUTEX_POST_LOCK(...)
|
||||
#define ABSL_TSAN_MUTEX_PRE_UNLOCK(...)
|
||||
#define ABSL_TSAN_MUTEX_POST_UNLOCK(...)
|
||||
#define ABSL_TSAN_MUTEX_PRE_SIGNAL(...)
|
||||
#define ABSL_TSAN_MUTEX_POST_SIGNAL(...)
|
||||
#define ABSL_TSAN_MUTEX_PRE_DIVERT(...)
|
||||
#define ABSL_TSAN_MUTEX_POST_DIVERT(...)
|
||||
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_TSAN_MUTEX_INTERFACE_H_
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||
#define ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/nullability.h"
|
||||
|
||||
// unaligned APIs
|
||||
|
||||
// Portable handling of unaligned loads, stores, and copies.
|
||||
|
||||
// The unaligned API is C++ only. The declarations use C++ features
|
||||
// (namespaces, inline) which are absent or incompatible in C.
|
||||
#if defined(__cplusplus)
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
inline uint16_t UnalignedLoad16(absl::Nonnull<const void *> p) {
|
||||
uint16_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint32_t UnalignedLoad32(absl::Nonnull<const void *> p) {
|
||||
uint32_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline uint64_t UnalignedLoad64(absl::Nonnull<const void *> p) {
|
||||
uint64_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
|
||||
inline void UnalignedStore16(absl::Nonnull<void *> p, uint16_t v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UnalignedStore32(absl::Nonnull<void *> p, uint32_t v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
inline void UnalignedStore64(absl::Nonnull<void *> p, uint64_t v) {
|
||||
memcpy(p, &v, sizeof v);
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#define ABSL_INTERNAL_UNALIGNED_LOAD16(_p) \
|
||||
(absl::base_internal::UnalignedLoad16(_p))
|
||||
#define ABSL_INTERNAL_UNALIGNED_LOAD32(_p) \
|
||||
(absl::base_internal::UnalignedLoad32(_p))
|
||||
#define ABSL_INTERNAL_UNALIGNED_LOAD64(_p) \
|
||||
(absl::base_internal::UnalignedLoad64(_p))
|
||||
|
||||
#define ABSL_INTERNAL_UNALIGNED_STORE16(_p, _val) \
|
||||
(absl::base_internal::UnalignedStore16(_p, _val))
|
||||
#define ABSL_INTERNAL_UNALIGNED_STORE32(_p, _val) \
|
||||
(absl::base_internal::UnalignedStore32(_p, _val))
|
||||
#define ABSL_INTERNAL_UNALIGNED_STORE64(_p, _val) \
|
||||
(absl::base_internal::UnalignedStore64(_p, _val))
|
||||
|
||||
#endif // defined(__cplusplus), end of unaligned API
|
||||
|
||||
#endif // ABSL_BASE_INTERNAL_UNALIGNED_ACCESS_H_
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_BASE_LOG_SEVERITY_H_
|
||||
#define ABSL_BASE_LOG_SEVERITY_H_
|
||||
|
||||
#include <array>
|
||||
#include <ostream>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// absl::LogSeverity
|
||||
//
|
||||
// Four severity levels are defined. Logging APIs should terminate the program
|
||||
// when a message is logged at severity `kFatal`; the other levels have no
|
||||
// special semantics.
|
||||
//
|
||||
// Values other than the four defined levels (e.g. produced by `static_cast`)
|
||||
// are valid, but their semantics when passed to a function, macro, or flag
|
||||
// depend on the function, macro, or flag. The usual behavior is to normalize
|
||||
// such values to a defined severity level, however in some cases values other
|
||||
// than the defined levels are useful for comparison.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Effectively disables all logging:
|
||||
// SetMinLogLevel(static_cast<absl::LogSeverity>(100));
|
||||
//
|
||||
// Abseil flags may be defined with type `LogSeverity`. Dependency layering
|
||||
// constraints require that the `AbslParseFlag()` overload be declared and
|
||||
// defined in the flags library itself rather than here. The `AbslUnparseFlag()`
|
||||
// overload is defined there as well for consistency.
|
||||
//
|
||||
// absl::LogSeverity Flag String Representation
|
||||
//
|
||||
// An `absl::LogSeverity` has a string representation used for parsing
|
||||
// command-line flags based on the enumerator name (e.g. `kFatal`) or
|
||||
// its unprefixed name (without the `k`) in any case-insensitive form. (E.g.
|
||||
// "FATAL", "fatal" or "Fatal" are all valid.) Unparsing such flags produces an
|
||||
// unprefixed string representation in all caps (e.g. "FATAL") or an integer.
|
||||
//
|
||||
// Additionally, the parser accepts arbitrary integers (as if the type were
|
||||
// `int`).
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// --my_log_level=kInfo
|
||||
// --my_log_level=INFO
|
||||
// --my_log_level=info
|
||||
// --my_log_level=0
|
||||
//
|
||||
// `DFATAL` and `kLogDebugFatal` are similarly accepted.
|
||||
//
|
||||
// Unparsing a flag produces the same result as `absl::LogSeverityName()` for
|
||||
// the standard levels and a base-ten integer otherwise.
|
||||
enum class LogSeverity : int {
|
||||
kInfo = 0,
|
||||
kWarning = 1,
|
||||
kError = 2,
|
||||
kFatal = 3,
|
||||
};
|
||||
|
||||
// LogSeverities()
|
||||
//
|
||||
// Returns an iterable of all standard `absl::LogSeverity` values, ordered from
|
||||
// least to most severe.
|
||||
constexpr std::array<absl::LogSeverity, 4> LogSeverities() {
|
||||
return {{absl::LogSeverity::kInfo, absl::LogSeverity::kWarning,
|
||||
absl::LogSeverity::kError, absl::LogSeverity::kFatal}};
|
||||
}
|
||||
|
||||
// `absl::kLogDebugFatal` equals `absl::LogSeverity::kFatal` in debug builds
|
||||
// (i.e. when `NDEBUG` is not defined) and `absl::LogSeverity::kError`
|
||||
// otherwise. Avoid ODR-using this variable as it has internal linkage and thus
|
||||
// distinct storage in different TUs.
|
||||
#ifdef NDEBUG
|
||||
static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kError;
|
||||
#else
|
||||
static constexpr absl::LogSeverity kLogDebugFatal = absl::LogSeverity::kFatal;
|
||||
#endif
|
||||
|
||||
// LogSeverityName()
|
||||
//
|
||||
// Returns the all-caps string representation (e.g. "INFO") of the specified
|
||||
// severity level if it is one of the standard levels and "UNKNOWN" otherwise.
|
||||
constexpr const char* LogSeverityName(absl::LogSeverity s) {
|
||||
switch (s) {
|
||||
case absl::LogSeverity::kInfo: return "INFO";
|
||||
case absl::LogSeverity::kWarning: return "WARNING";
|
||||
case absl::LogSeverity::kError: return "ERROR";
|
||||
case absl::LogSeverity::kFatal: return "FATAL";
|
||||
}
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
// NormalizeLogSeverity()
|
||||
//
|
||||
// Values less than `kInfo` normalize to `kInfo`; values greater than `kFatal`
|
||||
// normalize to `kError` (**NOT** `kFatal`).
|
||||
constexpr absl::LogSeverity NormalizeLogSeverity(absl::LogSeverity s) {
|
||||
absl::LogSeverity n = s;
|
||||
if (n < absl::LogSeverity::kInfo) n = absl::LogSeverity::kInfo;
|
||||
if (n > absl::LogSeverity::kFatal) n = absl::LogSeverity::kError;
|
||||
return n;
|
||||
}
|
||||
constexpr absl::LogSeverity NormalizeLogSeverity(int s) {
|
||||
return absl::NormalizeLogSeverity(static_cast<absl::LogSeverity>(s));
|
||||
}
|
||||
|
||||
// operator<<
|
||||
//
|
||||
// The exact representation of a streamed `absl::LogSeverity` is deliberately
|
||||
// unspecified; do not rely on it.
|
||||
std::ostream& operator<<(std::ostream& os, absl::LogSeverity s);
|
||||
|
||||
// Enums representing a lower bound for LogSeverity. APIs that only operate on
|
||||
// messages of at least a certain level (for example, `SetMinLogLevel()`) use
|
||||
// this type to specify that level. absl::LogSeverityAtLeast::kInfinity is
|
||||
// a level above all threshold levels and therefore no log message will
|
||||
// ever meet this threshold.
|
||||
enum class LogSeverityAtLeast : int {
|
||||
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
|
||||
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
|
||||
kError = static_cast<int>(absl::LogSeverity::kError),
|
||||
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
|
||||
kInfinity = 1000,
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtLeast s);
|
||||
|
||||
// Enums representing an upper bound for LogSeverity. APIs that only operate on
|
||||
// messages of at most a certain level (for example, buffer all messages at or
|
||||
// below a certain level) use this type to specify that level.
|
||||
// absl::LogSeverityAtMost::kNegativeInfinity is a level below all threshold
|
||||
// levels and therefore will exclude all log messages.
|
||||
enum class LogSeverityAtMost : int {
|
||||
kNegativeInfinity = -1000,
|
||||
kInfo = static_cast<int>(absl::LogSeverity::kInfo),
|
||||
kWarning = static_cast<int>(absl::LogSeverity::kWarning),
|
||||
kError = static_cast<int>(absl::LogSeverity::kError),
|
||||
kFatal = static_cast<int>(absl::LogSeverity::kFatal),
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, absl::LogSeverityAtMost s);
|
||||
|
||||
#define COMPOP(op1, op2, T) \
|
||||
constexpr bool operator op1(absl::T lhs, absl::LogSeverity rhs) { \
|
||||
return static_cast<absl::LogSeverity>(lhs) op1 rhs; \
|
||||
} \
|
||||
constexpr bool operator op2(absl::LogSeverity lhs, absl::T rhs) { \
|
||||
return lhs op2 static_cast<absl::LogSeverity>(rhs); \
|
||||
}
|
||||
|
||||
// Comparisons between `LogSeverity` and `LogSeverityAtLeast`/
|
||||
// `LogSeverityAtMost` are only supported in one direction.
|
||||
// Valid checks are:
|
||||
// LogSeverity >= LogSeverityAtLeast
|
||||
// LogSeverity < LogSeverityAtLeast
|
||||
// LogSeverity <= LogSeverityAtMost
|
||||
// LogSeverity > LogSeverityAtMost
|
||||
COMPOP(>, <, LogSeverityAtLeast)
|
||||
COMPOP(<=, >=, LogSeverityAtLeast)
|
||||
COMPOP(<, >, LogSeverityAtMost)
|
||||
COMPOP(>=, <=, LogSeverityAtMost)
|
||||
#undef COMPOP
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_LOG_SEVERITY_H_
|
||||
@@ -0,0 +1,189 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: macros.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the set of language macros used within Abseil code.
|
||||
// For the set of macros used to determine supported compilers and platforms,
|
||||
// see absl/base/config.h instead.
|
||||
//
|
||||
// This code is compiled directly on many platforms, including client
|
||||
// platforms like Windows, Mac, and embedded systems. Before making
|
||||
// any changes here, make sure that you're not breaking any platforms.
|
||||
|
||||
#ifndef ABSL_BASE_MACROS_H_
|
||||
#define ABSL_BASE_MACROS_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
|
||||
// ABSL_ARRAYSIZE()
|
||||
//
|
||||
// Returns the number of elements in an array as a compile-time constant, which
|
||||
// can be used in defining new arrays. If you use this macro on a pointer by
|
||||
// mistake, you will get a compile-time error.
|
||||
#define ABSL_ARRAYSIZE(array) \
|
||||
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace macros_internal {
|
||||
// Note: this internal template function declaration is used by ABSL_ARRAYSIZE.
|
||||
// The function doesn't need a definition, as we only use its type.
|
||||
template <typename T, size_t N>
|
||||
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
||||
} // namespace macros_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// ABSL_BAD_CALL_IF()
|
||||
//
|
||||
// Used on a function overload to trap bad calls: any call that matches the
|
||||
// overload will cause a compile-time error. This macro uses a clang-specific
|
||||
// "enable_if" attribute, as described at
|
||||
// https://clang.llvm.org/docs/AttributeReference.html#enable-if
|
||||
//
|
||||
// Overloads which use this macro should be bracketed by
|
||||
// `#ifdef ABSL_BAD_CALL_IF`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// int isdigit(int c);
|
||||
// #ifdef ABSL_BAD_CALL_IF
|
||||
// int isdigit(int c)
|
||||
// ABSL_BAD_CALL_IF(c <= -1 || c > 255,
|
||||
// "'c' must have the value of an unsigned char or EOF");
|
||||
// #endif // ABSL_BAD_CALL_IF
|
||||
#if ABSL_HAVE_ATTRIBUTE(enable_if)
|
||||
#define ABSL_BAD_CALL_IF(expr, msg) \
|
||||
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
|
||||
#endif
|
||||
|
||||
// ABSL_ASSERT()
|
||||
//
|
||||
// In C++11, `assert` can't be used portably within constexpr functions.
|
||||
// ABSL_ASSERT functions as a runtime assert but works in C++11 constexpr
|
||||
// functions. Example:
|
||||
//
|
||||
// constexpr double Divide(double a, double b) {
|
||||
// return ABSL_ASSERT(b != 0), a / b;
|
||||
// }
|
||||
//
|
||||
// This macro is inspired by
|
||||
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
|
||||
#if defined(NDEBUG)
|
||||
#define ABSL_ASSERT(expr) \
|
||||
(false ? static_cast<void>(expr) : static_cast<void>(0))
|
||||
#else
|
||||
#define ABSL_ASSERT(expr) \
|
||||
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
|
||||
: [] { assert(false && #expr); }()) // NOLINT
|
||||
#endif
|
||||
|
||||
// `ABSL_INTERNAL_HARDENING_ABORT()` controls how `ABSL_HARDENING_ASSERT()`
|
||||
// aborts the program in release mode (when NDEBUG is defined). The
|
||||
// implementation should abort the program as quickly as possible and ideally it
|
||||
// should not be possible to ignore the abort request.
|
||||
#define ABSL_INTERNAL_HARDENING_ABORT() \
|
||||
do { \
|
||||
ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
|
||||
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
|
||||
} while (false)
|
||||
|
||||
// ABSL_HARDENING_ASSERT()
|
||||
//
|
||||
// `ABSL_HARDENING_ASSERT()` is like `ABSL_ASSERT()`, but used to implement
|
||||
// runtime assertions that should be enabled in hardened builds even when
|
||||
// `NDEBUG` is defined.
|
||||
//
|
||||
// When `NDEBUG` is not defined, `ABSL_HARDENING_ASSERT()` is identical to
|
||||
// `ABSL_ASSERT()`.
|
||||
//
|
||||
// See `ABSL_OPTION_HARDENED` in `absl/base/options.h` for more information on
|
||||
// hardened mode.
|
||||
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
|
||||
#define ABSL_HARDENING_ASSERT(expr) \
|
||||
(ABSL_PREDICT_TRUE((expr)) ? static_cast<void>(0) \
|
||||
: [] { ABSL_INTERNAL_HARDENING_ABORT(); }())
|
||||
#else
|
||||
#define ABSL_HARDENING_ASSERT(expr) ABSL_ASSERT(expr)
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_HAVE_EXCEPTIONS
|
||||
#define ABSL_INTERNAL_TRY try
|
||||
#define ABSL_INTERNAL_CATCH_ANY catch (...)
|
||||
#define ABSL_INTERNAL_RETHROW do { throw; } while (false)
|
||||
#else // ABSL_HAVE_EXCEPTIONS
|
||||
#define ABSL_INTERNAL_TRY if (true)
|
||||
#define ABSL_INTERNAL_CATCH_ANY else if (false)
|
||||
#define ABSL_INTERNAL_RETHROW do {} while (false)
|
||||
#endif // ABSL_HAVE_EXCEPTIONS
|
||||
|
||||
// ABSL_DEPRECATE_AND_INLINE()
|
||||
//
|
||||
// Marks a function or type alias as deprecated and tags it to be picked up for
|
||||
// automated refactoring by go/cpp-inliner. It can added to inline function
|
||||
// definitions or type aliases. It should only be used within a header file. It
|
||||
// differs from `ABSL_DEPRECATED` in the following ways:
|
||||
//
|
||||
// 1. New uses of the function or type will be discouraged via Tricorder
|
||||
// warnings.
|
||||
// 2. If enabled via `METADATA`, automated changes will be sent out inlining the
|
||||
// functions's body or replacing the type where it is used.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// ABSL_DEPRECATE_AND_INLINE() inline int OldFunc(int x) {
|
||||
// return NewFunc(x, 0);
|
||||
// }
|
||||
//
|
||||
// will mark `OldFunc` as deprecated, and the go/cpp-inliner service will
|
||||
// replace calls to `OldFunc(x)` with calls to `NewFunc(x, 0)`. Once all calls
|
||||
// to `OldFunc` have been replaced, `OldFunc` can be deleted.
|
||||
//
|
||||
// See go/cpp-inliner for more information.
|
||||
//
|
||||
// Note: go/cpp-inliner is Google-internal service for automated refactoring.
|
||||
// While open-source users do not have access to this service, the macro is
|
||||
// provided for compatibility, and so that users receive deprecation warnings.
|
||||
#if ABSL_HAVE_CPP_ATTRIBUTE(deprecated) && \
|
||||
ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
|
||||
#define ABSL_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]]
|
||||
#elif ABSL_HAVE_CPP_ATTRIBUTE(deprecated)
|
||||
#define ABSL_DEPRECATE_AND_INLINE() [[deprecated]]
|
||||
#else
|
||||
#define ABSL_DEPRECATE_AND_INLINE()
|
||||
#endif
|
||||
|
||||
// Requires the compiler to prove that the size of the given object is at least
|
||||
// the expected amount.
|
||||
#if ABSL_HAVE_ATTRIBUTE(diagnose_if) && ABSL_HAVE_BUILTIN(__builtin_object_size)
|
||||
#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N) \
|
||||
__attribute__((diagnose_if(__builtin_object_size(Obj, 0) < N, \
|
||||
"object size provably too small " \
|
||||
"(this would corrupt memory)", \
|
||||
"error")))
|
||||
#else
|
||||
#define ABSL_INTERNAL_NEED_MIN_SIZE(Obj, N)
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_MACROS_H_
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright 2023 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: nullability.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines a set of "templated annotations" for designating the
|
||||
// expected nullability of pointers. These annotations allow you to designate
|
||||
// pointers in one of three classification states:
|
||||
//
|
||||
// * "Non-null" (for pointers annotated `Nonnull<T>`), indicating that it is
|
||||
// invalid for the given pointer to ever be null.
|
||||
// * "Nullable" (for pointers annotated `Nullable<T>`), indicating that it is
|
||||
// valid for the given pointer to be null.
|
||||
// * "Unknown" (for pointers annotated `NullabilityUnknown<T>`), indicating
|
||||
// that the given pointer has not been yet classified as either nullable or
|
||||
// non-null. This is the default state of unannotated pointers.
|
||||
//
|
||||
// NOTE: unannotated pointers implicitly bear the annotation
|
||||
// `NullabilityUnknown<T>`; you should rarely, if ever, see this annotation used
|
||||
// in the codebase explicitly.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Nullability and Contracts
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// These nullability annotations allow you to more clearly specify contracts on
|
||||
// software components by narrowing the *preconditions*, *postconditions*, and
|
||||
// *invariants* of pointer state(s) in any given interface. It then depends on
|
||||
// context who is responsible for fulfilling the annotation's requirements.
|
||||
//
|
||||
// For example, a function may receive a pointer argument. Designating that
|
||||
// pointer argument as "non-null" tightens the precondition of the contract of
|
||||
// that function. It is then the responsibility of anyone calling such a
|
||||
// function to ensure that the passed pointer is not null.
|
||||
//
|
||||
// Similarly, a function may have a pointer as a return value. Designating that
|
||||
// return value as "non-null" tightens the postcondition of the contract of that
|
||||
// function. In this case, however, it is the responsibility of the function
|
||||
// itself to ensure that the returned pointer is not null.
|
||||
//
|
||||
// Clearly defining these contracts allows providers (and consumers) of such
|
||||
// pointers to have more confidence in their null state. If a function declares
|
||||
// a return value as "non-null", for example, the caller should not need to
|
||||
// check whether the returned value is `nullptr`; it can simply assume the
|
||||
// pointer is valid.
|
||||
//
|
||||
// Of course most interfaces already have expectations on the nullability state
|
||||
// of pointers, and these expectations are, in effect, a contract; often,
|
||||
// however, those contracts are either poorly or partially specified, assumed,
|
||||
// or misunderstood. These nullability annotations are designed to allow you to
|
||||
// formalize those contracts within the codebase.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Using Nullability Annotations
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// It is important to note that these annotations are not distinct strong
|
||||
// *types*. They are alias templates defined to be equal to the underlying
|
||||
// pointer type. A pointer annotated `Nonnull<T*>`, for example, is simply a
|
||||
// pointer of type `T*`. Each annotation acts as a form of documentation about
|
||||
// the contract for the given pointer. Each annotation requires providers or
|
||||
// consumers of these pointers across API boundaries to take appropriate steps
|
||||
// when setting or using these pointers:
|
||||
//
|
||||
// * "Non-null" pointers should never be null. It is the responsibility of the
|
||||
// provider of this pointer to ensure that the pointer may never be set to
|
||||
// null. Consumers of such pointers can treat such pointers as non-null.
|
||||
// * "Nullable" pointers may or may not be null. Consumers of such pointers
|
||||
// should precede any usage of that pointer (e.g. a dereference operation)
|
||||
// with a a `nullptr` check.
|
||||
// * "Unknown" pointers may be either "non-null" or "nullable" but have not been
|
||||
// definitively determined to be in either classification state. Providers of
|
||||
// such pointers across API boundaries should determine -- over time -- to
|
||||
// annotate the pointer in either of the above two states. Consumers of such
|
||||
// pointers across an API boundary should continue to treat such pointers as
|
||||
// they currently do.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // PaySalary() requires the passed pointer to an `Employee` to be non-null.
|
||||
// void PaySalary(absl::Nonnull<Employee *> e) {
|
||||
// pay(e->salary); // OK to dereference
|
||||
// }
|
||||
//
|
||||
// // CompleteTransaction() guarantees the returned pointer to an `Account` to
|
||||
// // be non-null.
|
||||
// absl::Nonnull<Account *> balance CompleteTransaction(double fee) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// // Note that specifying a nullability annotation does not prevent someone
|
||||
// // from violating the contract:
|
||||
//
|
||||
// Nullable<Employee *> find(Map& employees, std::string_view name);
|
||||
//
|
||||
// void g(Map& employees) {
|
||||
// Employee *e = find(employees, "Pat");
|
||||
// // `e` can now be null.
|
||||
// PaySalary(e); // Violates contract, but compiles!
|
||||
// }
|
||||
//
|
||||
// Nullability annotations, in other words, are useful for defining and
|
||||
// narrowing contracts; *enforcement* of those contracts depends on use and any
|
||||
// additional (static or dynamic analysis) tooling.
|
||||
//
|
||||
// NOTE: The "unknown" annotation state indicates that a pointer's contract has
|
||||
// not yet been positively identified. The unknown state therefore acts as a
|
||||
// form of documentation of your technical debt, and a codebase that adopts
|
||||
// nullability annotations should aspire to annotate every pointer as either
|
||||
// "non-null" or "nullable".
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Applicability of Nullability Annotations
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// By default, nullability annotations are applicable to raw and smart
|
||||
// pointers. User-defined types can indicate compatibility with nullability
|
||||
// annotations by adding the ABSL_NULLABILITY_COMPATIBLE attribute.
|
||||
//
|
||||
// // Example:
|
||||
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// Note: For the time being, nullability-compatible classes should additionally
|
||||
// be marked with an `absl_nullability_compatible` nested type (this will soon
|
||||
// be deprecated). The actual definition of this inner type is not relevant as
|
||||
// it is used merely as a marker. It is common to use a using declaration of
|
||||
// `absl_nullability_compatible` set to void.
|
||||
//
|
||||
// // Example:
|
||||
// struct MyPtr {
|
||||
// using absl_nullability_compatible = void;
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// DISCLAIMER:
|
||||
// ===========================================================================
|
||||
// These nullability annotations are primarily a human readable signal about the
|
||||
// intended contract of the pointer. They are not *types* and do not currently
|
||||
// provide any correctness guarantees. For example, a pointer annotated as
|
||||
// `Nonnull<T*>` is *not guaranteed* to be non-null, and the compiler won't
|
||||
// alert or prevent assignment of a `Nullable<T*>` to a `Nonnull<T*>`.
|
||||
// ===========================================================================
|
||||
#ifndef ABSL_BASE_NULLABILITY_H_
|
||||
#define ABSL_BASE_NULLABILITY_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/nullability_impl.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// absl::Nonnull
|
||||
//
|
||||
// The indicated pointer is never null. It is the responsibility of the provider
|
||||
// of this pointer across an API boundary to ensure that the pointer is never
|
||||
// set to null. Consumers of this pointer across an API boundary may safely
|
||||
// dereference the pointer.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // `employee` is designated as not null.
|
||||
// void PaySalary(absl::Nonnull<Employee *> employee) {
|
||||
// pay(*employee); // OK to dereference
|
||||
// }
|
||||
template <typename T>
|
||||
using Nonnull = nullability_internal::NonnullImpl<T>;
|
||||
|
||||
// absl::Nullable
|
||||
//
|
||||
// The indicated pointer may, by design, be either null or non-null. Consumers
|
||||
// of this pointer across an API boundary should perform a `nullptr` check
|
||||
// before performing any operation using the pointer.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // `employee` may be null.
|
||||
// void PaySalary(absl::Nullable<Employee *> employee) {
|
||||
// if (employee != nullptr) {
|
||||
// Pay(*employee); // OK to dereference
|
||||
// }
|
||||
// }
|
||||
template <typename T>
|
||||
using Nullable = nullability_internal::NullableImpl<T>;
|
||||
|
||||
// absl::NullabilityUnknown (default)
|
||||
//
|
||||
// The indicated pointer has not yet been determined to be definitively
|
||||
// "non-null" or "nullable." Providers of such pointers across API boundaries
|
||||
// should, over time, annotate such pointers as either "non-null" or "nullable."
|
||||
// Consumers of these pointers across an API boundary should treat such pointers
|
||||
// with the same caution they treat currently unannotated pointers. Most
|
||||
// existing code will have "unknown" pointers, which should eventually be
|
||||
// migrated into one of the above two nullability states: `Nonnull<T>` or
|
||||
// `Nullable<T>`.
|
||||
//
|
||||
// NOTE: Because this annotation is the global default state, unannotated
|
||||
// pointers are assumed to have "unknown" semantics. This assumption is designed
|
||||
// to minimize churn and reduce clutter within the codebase.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // `employee`s nullability state is unknown.
|
||||
// void PaySalary(absl::NullabilityUnknown<Employee *> employee) {
|
||||
// Pay(*employee); // Potentially dangerous. API provider should investigate.
|
||||
// }
|
||||
//
|
||||
// Note that a pointer without an annotation, by default, is assumed to have the
|
||||
// annotation `NullabilityUnknown`.
|
||||
//
|
||||
// // `employee`s nullability state is unknown.
|
||||
// void PaySalary(Employee* employee) {
|
||||
// Pay(*employee); // Potentially dangerous. API provider should investigate.
|
||||
// }
|
||||
template <typename T>
|
||||
using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl<T>;
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// ABSL_NULLABILITY_COMPATIBLE
|
||||
//
|
||||
// Indicates that a class is compatible with nullability annotations.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// struct ABSL_NULLABILITY_COMPATIBLE MyPtr {
|
||||
// ...
|
||||
// };
|
||||
#if ABSL_HAVE_FEATURE(nullability_on_classes)
|
||||
#define ABSL_NULLABILITY_COMPATIBLE _Nullable
|
||||
#else
|
||||
#define ABSL_NULLABILITY_COMPATIBLE
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_NULLABILITY_H_
|
||||
@@ -0,0 +1,316 @@
|
||||
//
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: optimization.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines portable macros for performance optimization.
|
||||
//
|
||||
// This header is included in both C++ code and legacy C code and thus must
|
||||
// remain compatible with both C and C++. C compatibility will be removed if
|
||||
// the legacy code is removed or converted to C++. Do not include this header in
|
||||
// new code that requires C compatibility or assume C compatibility will remain
|
||||
// indefinitely.
|
||||
|
||||
#ifndef ABSL_BASE_OPTIMIZATION_H_
|
||||
#define ABSL_BASE_OPTIMIZATION_H_
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Included for std::unreachable()
|
||||
#include <utility>
|
||||
#endif // __cplusplus
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/options.h"
|
||||
|
||||
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION
|
||||
//
|
||||
// Instructs the compiler to avoid optimizing tail-call recursion. This macro is
|
||||
// useful when you wish to preserve the existing function order within a stack
|
||||
// trace for logging, debugging, or profiling purposes.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// int f() {
|
||||
// int result = g();
|
||||
// ABSL_BLOCK_TAIL_CALL_OPTIMIZATION();
|
||||
// return result;
|
||||
// }
|
||||
#if defined(__pnacl__)
|
||||
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
||||
#elif defined(__clang__)
|
||||
// Clang will not tail call given inline volatile assembly.
|
||||
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
||||
#elif defined(__GNUC__)
|
||||
// GCC will not tail call given inline volatile assembly.
|
||||
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
|
||||
#elif defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
// The __nop() intrinsic blocks the optimisation.
|
||||
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
|
||||
#else
|
||||
#define ABSL_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
|
||||
#endif
|
||||
|
||||
// ABSL_CACHELINE_SIZE
|
||||
//
|
||||
// Explicitly defines the size of the L1 cache for purposes of alignment.
|
||||
// Setting the cacheline size allows you to specify that certain objects be
|
||||
// aligned on a cacheline boundary with `ABSL_CACHELINE_ALIGNED` declarations.
|
||||
// (See below.)
|
||||
//
|
||||
// NOTE: this macro should be replaced with the following C++17 features, when
|
||||
// those are generally available:
|
||||
//
|
||||
// * `std::hardware_constructive_interference_size`
|
||||
// * `std::hardware_destructive_interference_size`
|
||||
//
|
||||
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
||||
// for more information.
|
||||
#if defined(__GNUC__)
|
||||
// Cache line alignment
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#define ABSL_CACHELINE_SIZE 64
|
||||
#elif defined(__powerpc64__)
|
||||
#define ABSL_CACHELINE_SIZE 128
|
||||
#elif defined(__aarch64__)
|
||||
// We would need to read special register ctr_el0 to find out L1 dcache size.
|
||||
// This value is a good estimate based on a real aarch64 machine.
|
||||
#define ABSL_CACHELINE_SIZE 64
|
||||
#elif defined(__arm__)
|
||||
// Cache line sizes for ARM: These values are not strictly correct since
|
||||
// cache line sizes depend on implementations, not architectures. There
|
||||
// are even implementations with cache line sizes configurable at boot
|
||||
// time.
|
||||
#if defined(__ARM_ARCH_5T__)
|
||||
#define ABSL_CACHELINE_SIZE 32
|
||||
#elif defined(__ARM_ARCH_7A__)
|
||||
#define ABSL_CACHELINE_SIZE 64
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ABSL_CACHELINE_SIZE
|
||||
// A reasonable default guess. Note that overestimates tend to waste more
|
||||
// space, while underestimates tend to waste more time.
|
||||
#define ABSL_CACHELINE_SIZE 64
|
||||
#endif
|
||||
|
||||
// ABSL_CACHELINE_ALIGNED
|
||||
//
|
||||
// Indicates that the declared object be cache aligned using
|
||||
// `ABSL_CACHELINE_SIZE` (see above). Cacheline aligning objects allows you to
|
||||
// load a set of related objects in the L1 cache for performance improvements.
|
||||
// Cacheline aligning objects properly allows constructive memory sharing and
|
||||
// prevents destructive (or "false") memory sharing.
|
||||
//
|
||||
// NOTE: callers should replace uses of this macro with `alignas()` using
|
||||
// `std::hardware_constructive_interference_size` and/or
|
||||
// `std::hardware_destructive_interference_size` when C++17 becomes available to
|
||||
// them.
|
||||
//
|
||||
// See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0154r1.html
|
||||
// for more information.
|
||||
//
|
||||
// On some compilers, `ABSL_CACHELINE_ALIGNED` expands to an `__attribute__`
|
||||
// or `__declspec` attribute. For compilers where this is not known to work,
|
||||
// the macro expands to nothing.
|
||||
//
|
||||
// No further guarantees are made here. The result of applying the macro
|
||||
// to variables and types is always implementation-defined.
|
||||
//
|
||||
// WARNING: It is easy to use this attribute incorrectly, even to the point
|
||||
// of causing bugs that are difficult to diagnose, crash, etc. It does not
|
||||
// of itself guarantee that objects are aligned to a cache line.
|
||||
//
|
||||
// NOTE: Some compilers are picky about the locations of annotations such as
|
||||
// this attribute, so prefer to put it at the beginning of your declaration.
|
||||
// For example,
|
||||
//
|
||||
// ABSL_CACHELINE_ALIGNED static Foo* foo = ...
|
||||
//
|
||||
// class ABSL_CACHELINE_ALIGNED Bar { ...
|
||||
//
|
||||
// Recommendations:
|
||||
//
|
||||
// 1) Consult compiler documentation; this comment is not kept in sync as
|
||||
// toolchains evolve.
|
||||
// 2) Verify your use has the intended effect. This often requires inspecting
|
||||
// the generated machine code.
|
||||
// 3) Prefer applying this attribute to individual variables. Avoid
|
||||
// applying it to types. This tends to localize the effect.
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define ABSL_CACHELINE_ALIGNED __attribute__((aligned(ABSL_CACHELINE_SIZE)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_CACHELINE_ALIGNED __declspec(align(ABSL_CACHELINE_SIZE))
|
||||
#else
|
||||
#define ABSL_CACHELINE_ALIGNED
|
||||
#endif
|
||||
|
||||
// ABSL_PREDICT_TRUE, ABSL_PREDICT_FALSE
|
||||
//
|
||||
// Enables the compiler to prioritize compilation using static analysis for
|
||||
// likely paths within a boolean branch.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// if (ABSL_PREDICT_TRUE(expression)) {
|
||||
// return result; // Faster if more likely
|
||||
// } else {
|
||||
// return 0;
|
||||
// }
|
||||
//
|
||||
// Compilers can use the information that a certain branch is not likely to be
|
||||
// taken (for instance, a CHECK failure) to optimize for the common case in
|
||||
// the absence of better information (ie. compiling gcc with `-fprofile-arcs`).
|
||||
//
|
||||
// Recommendation: Modern CPUs dynamically predict branch execution paths,
|
||||
// typically with accuracy greater than 97%. As a result, annotating every
|
||||
// branch in a codebase is likely counterproductive; however, annotating
|
||||
// specific branches that are both hot and consistently mispredicted is likely
|
||||
// to yield performance improvements.
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_expect) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_PREDICT_FALSE(x) (__builtin_expect(false || (x), false))
|
||||
#define ABSL_PREDICT_TRUE(x) (__builtin_expect(false || (x), true))
|
||||
#else
|
||||
#define ABSL_PREDICT_FALSE(x) (x)
|
||||
#define ABSL_PREDICT_TRUE(x) (x)
|
||||
#endif
|
||||
|
||||
// `ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL()` aborts the program in the fastest
|
||||
// possible way, with no attempt at logging. One use is to implement hardening
|
||||
// aborts with ABSL_OPTION_HARDENED. Since this is an internal symbol, it
|
||||
// should not be used directly outside of Abseil.
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_trap) || \
|
||||
(defined(__GNUC__) && !defined(__clang__))
|
||||
#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() __builtin_trap()
|
||||
#else
|
||||
#define ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL() abort()
|
||||
#endif
|
||||
|
||||
// `ABSL_INTERNAL_UNREACHABLE_IMPL()` is the platform specific directive to
|
||||
// indicate that a statement is unreachable, and to allow the compiler to
|
||||
// optimize accordingly. Clients should use `ABSL_UNREACHABLE()`, which is
|
||||
// defined below.
|
||||
#if defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
|
||||
#define ABSL_INTERNAL_UNREACHABLE_IMPL() std::unreachable()
|
||||
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
|
||||
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_unreachable()
|
||||
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
|
||||
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __builtin_assume(false)
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_INTERNAL_UNREACHABLE_IMPL() __assume(false)
|
||||
#else
|
||||
#define ABSL_INTERNAL_UNREACHABLE_IMPL()
|
||||
#endif
|
||||
|
||||
// `ABSL_UNREACHABLE()` is an unreachable statement. A program which reaches
|
||||
// one has undefined behavior, and the compiler may optimize accordingly.
|
||||
#if ABSL_OPTION_HARDENED == 1 && defined(NDEBUG)
|
||||
// Abort in hardened mode to avoid dangerous undefined behavior.
|
||||
#define ABSL_UNREACHABLE() \
|
||||
do { \
|
||||
ABSL_INTERNAL_IMMEDIATE_ABORT_IMPL(); \
|
||||
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
|
||||
} while (false)
|
||||
#else
|
||||
// The assert only fires in debug mode to aid in debugging.
|
||||
// When NDEBUG is defined, reaching ABSL_UNREACHABLE() is undefined behavior.
|
||||
#define ABSL_UNREACHABLE() \
|
||||
do { \
|
||||
/* NOLINTNEXTLINE: misc-static-assert */ \
|
||||
assert(false && "ABSL_UNREACHABLE reached"); \
|
||||
ABSL_INTERNAL_UNREACHABLE_IMPL(); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
// ABSL_ASSUME(cond)
|
||||
//
|
||||
// Informs the compiler that a condition is always true and that it can assume
|
||||
// it to be true for optimization purposes.
|
||||
//
|
||||
// WARNING: If the condition is false, the program can produce undefined and
|
||||
// potentially dangerous behavior.
|
||||
//
|
||||
// In !NDEBUG mode, the condition is checked with an assert().
|
||||
//
|
||||
// NOTE: The expression must not have side effects, as it may only be evaluated
|
||||
// in some compilation modes and not others. Some compilers may issue a warning
|
||||
// if the compiler cannot prove the expression has no side effects. For example,
|
||||
// the expression should not use a function call since the compiler cannot prove
|
||||
// that a function call does not have side effects.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// int x = ...;
|
||||
// ABSL_ASSUME(x >= 0);
|
||||
// // The compiler can optimize the division to a simple right shift using the
|
||||
// // assumption specified above.
|
||||
// int y = x / 16;
|
||||
//
|
||||
#if !defined(NDEBUG)
|
||||
#define ABSL_ASSUME(cond) assert(cond)
|
||||
#elif ABSL_HAVE_BUILTIN(__builtin_assume)
|
||||
#define ABSL_ASSUME(cond) __builtin_assume(cond)
|
||||
#elif defined(_MSC_VER)
|
||||
#define ABSL_ASSUME(cond) __assume(cond)
|
||||
#elif defined(__cpp_lib_unreachable) && __cpp_lib_unreachable >= 202202L
|
||||
#define ABSL_ASSUME(cond) \
|
||||
do { \
|
||||
if (!(cond)) std::unreachable(); \
|
||||
} while (false)
|
||||
#elif defined(__GNUC__) || ABSL_HAVE_BUILTIN(__builtin_unreachable)
|
||||
#define ABSL_ASSUME(cond) \
|
||||
do { \
|
||||
if (!(cond)) __builtin_unreachable(); \
|
||||
} while (false)
|
||||
#else
|
||||
#define ABSL_ASSUME(cond) \
|
||||
do { \
|
||||
static_cast<void>(false && (cond)); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
// ABSL_INTERNAL_UNIQUE_SMALL_NAME(cond)
|
||||
// This macro forces small unique name on a static file level symbols like
|
||||
// static local variables or static functions. This is intended to be used in
|
||||
// macro definitions to optimize the cost of generated code. Do NOT use it on
|
||||
// symbols exported from translation unit since it may cause a link time
|
||||
// conflict.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// #define MY_MACRO(txt)
|
||||
// namespace {
|
||||
// char VeryVeryLongVarName[] ABSL_INTERNAL_UNIQUE_SMALL_NAME() = txt;
|
||||
// const char* VeryVeryLongFuncName() ABSL_INTERNAL_UNIQUE_SMALL_NAME();
|
||||
// const char* VeryVeryLongFuncName() { return txt; }
|
||||
// }
|
||||
//
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x) #x
|
||||
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME1(x) ABSL_INTERNAL_UNIQUE_SMALL_NAME2(x)
|
||||
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME() \
|
||||
asm(ABSL_INTERNAL_UNIQUE_SMALL_NAME1(.absl.__COUNTER__))
|
||||
#else
|
||||
#define ABSL_INTERNAL_UNIQUE_SMALL_NAME()
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_OPTIMIZATION_H_
|
||||
@@ -0,0 +1,258 @@
|
||||
// Copyright 2019 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: options.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This file contains Abseil configuration options for setting specific
|
||||
// implementations instead of letting Abseil determine which implementation to
|
||||
// use at compile-time. Setting these options may be useful for package or build
|
||||
// managers who wish to guarantee ABI stability within binary builds (which are
|
||||
// otherwise difficult to enforce).
|
||||
//
|
||||
// *** IMPORTANT NOTICE FOR PACKAGE MANAGERS: It is important that
|
||||
// maintainers of package managers who wish to package Abseil read and
|
||||
// understand this file! ***
|
||||
//
|
||||
// Abseil contains a number of possible configuration endpoints, based on
|
||||
// parameters such as the detected platform, language version, or command-line
|
||||
// flags used to invoke the underlying binary. As is the case with all
|
||||
// libraries, binaries which contain Abseil code must ensure that separate
|
||||
// packages use the same compiled copy of Abseil to avoid a diamond dependency
|
||||
// problem, which can occur if two packages built with different Abseil
|
||||
// configuration settings are linked together. Diamond dependency problems in
|
||||
// C++ may manifest as violations to the One Definition Rule (ODR) (resulting in
|
||||
// linker errors), or undefined behavior (resulting in crashes).
|
||||
//
|
||||
// Diamond dependency problems can be avoided if all packages utilize the same
|
||||
// exact version of Abseil. Building from source code with the same compilation
|
||||
// parameters is the easiest way to avoid such dependency problems. However, for
|
||||
// package managers who cannot control such compilation parameters, we are
|
||||
// providing the file to allow you to inject ABI (Application Binary Interface)
|
||||
// stability across builds. Settings options in this file will neither change
|
||||
// API nor ABI, providing a stable copy of Abseil between packages.
|
||||
//
|
||||
// Care must be taken to keep options within these configurations isolated
|
||||
// from any other dynamic settings, such as command-line flags which could alter
|
||||
// these options. This file is provided specifically to help build and package
|
||||
// managers provide a stable copy of Abseil within their libraries and binaries;
|
||||
// other developers should not have need to alter the contents of this file.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// Usage
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// For any particular package release, set the appropriate definitions within
|
||||
// this file to whatever value makes the most sense for your package(s). Note
|
||||
// that, by default, most of these options, at the moment, affect the
|
||||
// implementation of types; future options may affect other implementation
|
||||
// details.
|
||||
//
|
||||
// NOTE: the defaults within this file all assume that Abseil can select the
|
||||
// proper Abseil implementation at compile-time, which will not be sufficient
|
||||
// to guarantee ABI stability to package managers.
|
||||
|
||||
#ifndef ABSL_BASE_OPTIONS_H_
|
||||
#define ABSL_BASE_OPTIONS_H_
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Type Compatibility Options
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// ABSL_OPTION_USE_STD_ANY
|
||||
//
|
||||
// This option controls whether absl::any is implemented as an alias to
|
||||
// std::any, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::any. This requires that all code
|
||||
// using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::any is available. This option is
|
||||
// useful when you are building your entire program, including all of its
|
||||
// dependencies, from source. It should not be used otherwise -- for example,
|
||||
// if you are distributing Abseil in a binary package manager -- since in
|
||||
// mode 2, absl::any will name a different type, with a different mangled name
|
||||
// and binary layout, depending on the compiler flags passed by the end user.
|
||||
// For more info, see https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::any is a typedef of std::any, use the feature macro ABSL_USES_STD_ANY.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_ANY 2
|
||||
|
||||
|
||||
// ABSL_OPTION_USE_STD_OPTIONAL
|
||||
//
|
||||
// This option controls whether absl::optional is implemented as an alias to
|
||||
// std::optional, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::optional. This requires that all
|
||||
// code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::optional is available. This option
|
||||
// is useful when you are building your program from source. It should not be
|
||||
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||
// package manager -- since in mode 2, absl::optional will name a different
|
||||
// type, with a different mangled name and binary layout, depending on the
|
||||
// compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::optional is a typedef of std::optional, use the feature macro
|
||||
// ABSL_USES_STD_OPTIONAL.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_OPTIONAL 2
|
||||
|
||||
|
||||
// ABSL_OPTION_USE_STD_STRING_VIEW
|
||||
//
|
||||
// This option controls whether absl::string_view is implemented as an alias to
|
||||
// std::string_view, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::string_view. This requires that
|
||||
// all code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::string_view is available. This
|
||||
// option is useful when you are building your program from source. It should
|
||||
// not be used otherwise -- for example, if you are distributing Abseil in a
|
||||
// binary package manager -- since in mode 2, absl::string_view will name a
|
||||
// different type, with a different mangled name and binary layout, depending on
|
||||
// the compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::string_view is a typedef of std::string_view, use the feature macro
|
||||
// ABSL_USES_STD_STRING_VIEW.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_STRING_VIEW 2
|
||||
|
||||
// ABSL_OPTION_USE_STD_VARIANT
|
||||
//
|
||||
// This option controls whether absl::variant is implemented as an alias to
|
||||
// std::variant, or as an independent implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use an alias to std::variant. This requires that all
|
||||
// code using Abseil is built in C++17 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if a working std::variant is available. This option
|
||||
// is useful when you are building your program from source. It should not be
|
||||
// used otherwise -- for example, if you are distributing Abseil in a binary
|
||||
// package manager -- since in mode 2, absl::variant will name a different
|
||||
// type, with a different mangled name and binary layout, depending on the
|
||||
// compiler flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// absl::variant is a typedef of std::variant, use the feature macro
|
||||
// ABSL_USES_STD_VARIANT.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_VARIANT 2
|
||||
|
||||
// ABSL_OPTION_USE_STD_ORDERING
|
||||
//
|
||||
// This option controls whether absl::{partial,weak,strong}_ordering are
|
||||
// implemented as aliases to the std:: ordering types, or as an independent
|
||||
// implementation.
|
||||
//
|
||||
// A value of 0 means to use Abseil's implementation. This requires only C++11
|
||||
// support, and is expected to work on every toolchain we support.
|
||||
//
|
||||
// A value of 1 means to use aliases. This requires that all code using Abseil
|
||||
// is built in C++20 mode or later.
|
||||
//
|
||||
// A value of 2 means to detect the C++ version being used to compile Abseil,
|
||||
// and use an alias only if working std:: ordering types are available. This
|
||||
// option is useful when you are building your program from source. It should
|
||||
// not be used otherwise -- for example, if you are distributing Abseil in a
|
||||
// binary package manager -- since in mode 2, they will name different types,
|
||||
// with different mangled names and binary layout, depending on the compiler
|
||||
// flags passed by the end user. For more info, see
|
||||
// https://abseil.io/about/design/dropin-types.
|
||||
//
|
||||
// User code should not inspect this macro. To check in the preprocessor if
|
||||
// the ordering types are aliases of std:: ordering types, use the feature macro
|
||||
// ABSL_USES_STD_ORDERING.
|
||||
|
||||
#define ABSL_OPTION_USE_STD_ORDERING 2
|
||||
|
||||
// ABSL_OPTION_USE_INLINE_NAMESPACE
|
||||
// ABSL_OPTION_INLINE_NAMESPACE_NAME
|
||||
//
|
||||
// These options controls whether all entities in the absl namespace are
|
||||
// contained within an inner inline namespace. This does not affect the
|
||||
// user-visible API of Abseil, but it changes the mangled names of all symbols.
|
||||
//
|
||||
// This can be useful as a version tag if you are distributing Abseil in
|
||||
// precompiled form. This will prevent a binary library build of Abseil with
|
||||
// one inline namespace being used with headers configured with a different
|
||||
// inline namespace name. Binary packagers are reminded that Abseil does not
|
||||
// guarantee any ABI stability in Abseil, so any update of Abseil or
|
||||
// configuration change in such a binary package should be combined with a
|
||||
// new, unique value for the inline namespace name.
|
||||
//
|
||||
// A value of 0 means not to use inline namespaces.
|
||||
//
|
||||
// A value of 1 means to use an inline namespace with the given name inside
|
||||
// namespace absl. If this is set, ABSL_OPTION_INLINE_NAMESPACE_NAME must also
|
||||
// be changed to a new, unique identifier name. In particular "head" is not
|
||||
// allowed.
|
||||
|
||||
#define ABSL_OPTION_USE_INLINE_NAMESPACE 1
|
||||
#define ABSL_OPTION_INLINE_NAMESPACE_NAME lts_20240722
|
||||
|
||||
// ABSL_OPTION_HARDENED
|
||||
//
|
||||
// This option enables a "hardened" build in release mode (in this context,
|
||||
// release mode is defined as a build where the `NDEBUG` macro is defined).
|
||||
//
|
||||
// A value of 0 means that "hardened" mode is not enabled.
|
||||
//
|
||||
// A value of 1 means that "hardened" mode is enabled.
|
||||
//
|
||||
// Hardened builds have additional security checks enabled when `NDEBUG` is
|
||||
// defined. Defining `NDEBUG` is normally used to turn `assert()` macro into a
|
||||
// no-op, as well as disabling other bespoke program consistency checks. By
|
||||
// defining ABSL_OPTION_HARDENED to 1, a select set of checks remain enabled in
|
||||
// release mode. These checks guard against programming errors that may lead to
|
||||
// security vulnerabilities. In release mode, when one of these programming
|
||||
// errors is encountered, the program will immediately abort, possibly without
|
||||
// any attempt at logging.
|
||||
//
|
||||
// The checks enabled by this option are not free; they do incur runtime cost.
|
||||
//
|
||||
// The checks enabled by this option are always active when `NDEBUG` is not
|
||||
// defined, even in the case when ABSL_OPTION_HARDENED is defined to 0. The
|
||||
// checks enabled by this option may abort the program in a different way and
|
||||
// log additional information when `NDEBUG` is not defined.
|
||||
|
||||
#define ABSL_OPTION_HARDENED 0
|
||||
|
||||
#endif // ABSL_BASE_OPTIONS_H_
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: policy_checks.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header enforces a minimum set of policies at build time, such as the
|
||||
// supported compiler and library versions. Unsupported configurations are
|
||||
// reported with `#error`. This enforcement is best effort, so successfully
|
||||
// compiling this header does not guarantee a supported configuration.
|
||||
|
||||
#ifndef ABSL_BASE_POLICY_CHECKS_H_
|
||||
#define ABSL_BASE_POLICY_CHECKS_H_
|
||||
|
||||
// Included for the __GLIBC_PREREQ macro used below.
|
||||
#include <limits.h>
|
||||
|
||||
// Included for the _STLPORT_VERSION macro used below.
|
||||
#if defined(__cplusplus)
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Operating System Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if defined(__CYGWIN__)
|
||||
#error "Cygwin is not supported."
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Toolchain Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// We support Visual Studio 2019 (MSVC++ 16.0) and later.
|
||||
// This minimum will go up.
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
|
||||
#error "This package requires Visual Studio 2019 (MSVC++ 16.0) or higher."
|
||||
#endif
|
||||
|
||||
// We support GCC 7 and later.
|
||||
// This minimum will go up.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#if __GNUC__ < 7
|
||||
#error "This package requires GCC 7 or higher."
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
|
||||
// This corresponds to Apple Xcode version 4.5.
|
||||
// This minimum will go up.
|
||||
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
|
||||
#error "This package requires __apple_build_version__ of 4211165 or higher."
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// C++ Version Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Enforce C++14 as the minimum.
|
||||
#if defined(_MSVC_LANG)
|
||||
#if _MSVC_LANG < 201402L
|
||||
#error "C++ versions less than C++14 are not supported."
|
||||
#endif // _MSVC_LANG < 201402L
|
||||
#elif defined(__cplusplus)
|
||||
#if __cplusplus < 201402L
|
||||
#error "C++ versions less than C++14 are not supported."
|
||||
#endif // __cplusplus < 201402L
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Standard Library Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if defined(_STLPORT_VERSION)
|
||||
#error "STLPort is not supported."
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// `char` Size Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Abseil currently assumes CHAR_BIT == 8. If you would like to use Abseil on a
|
||||
// platform where this is not the case, please provide us with the details about
|
||||
// your platform so we can consider relaxing this requirement.
|
||||
#if CHAR_BIT != 8
|
||||
#error "Abseil assumes CHAR_BIT == 8."
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// `int` Size Check
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Abseil currently assumes that an int is 4 bytes. If you would like to use
|
||||
// Abseil on a platform where this is not the case, please provide us with the
|
||||
// details about your platform so we can consider relaxing this requirement.
|
||||
#if INT_MAX < 2147483647
|
||||
#error "Abseil assumes that int is at least 4 bytes. "
|
||||
#endif
|
||||
|
||||
#endif // ABSL_BASE_POLICY_CHECKS_H_
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// This files is a forwarding header for other headers containing various
|
||||
// portability macros and functions.
|
||||
|
||||
#ifndef ABSL_BASE_PORT_H_
|
||||
#define ABSL_BASE_PORT_H_
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
#endif // ABSL_BASE_PORT_H_
|
||||
@@ -0,0 +1,209 @@
|
||||
// Copyright 2023 The Abseil Authors
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: prefetch.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines prefetch functions to prefetch memory contents
|
||||
// into the first level cache (L1) for the current CPU. The prefetch logic
|
||||
// offered in this header is limited to prefetching first level cachelines
|
||||
// only, and is aimed at relatively 'simple' prefetching logic.
|
||||
//
|
||||
#ifndef ABSL_BASE_PREFETCH_H_
|
||||
#define ABSL_BASE_PREFETCH_H_
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
#if defined(ABSL_INTERNAL_HAVE_SSE)
|
||||
#include <xmmintrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#if defined(ABSL_INTERNAL_HAVE_SSE)
|
||||
#pragma intrinsic(_mm_prefetch)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// Moves data into the L1 cache before it is read, or "prefetches" it.
|
||||
//
|
||||
// The value of `addr` is the address of the memory to prefetch. If
|
||||
// the target and compiler support it, data prefetch instructions are
|
||||
// generated. If the prefetch is done some time before the memory is
|
||||
// read, it may be in the cache by the time the read occurs.
|
||||
//
|
||||
// This method prefetches data with the highest degree of temporal locality;
|
||||
// data is prefetched where possible into all levels of the cache.
|
||||
//
|
||||
// Incorrect or gratuitous use of this function can degrade performance.
|
||||
// Use this function only when representative benchmarks show an improvement.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Computes incremental checksum for `data`.
|
||||
// int ComputeChecksum(int sum, absl::string_view data);
|
||||
//
|
||||
// // Computes cumulative checksum for all values in `data`
|
||||
// int ComputeChecksum(absl::Span<const std::string> data) {
|
||||
// int sum = 0;
|
||||
// auto it = data.begin();
|
||||
// auto pit = data.begin();
|
||||
// auto end = data.end();
|
||||
// for (int dist = 8; dist > 0 && pit != data.end(); --dist, ++pit) {
|
||||
// absl::PrefetchToLocalCache(pit->data());
|
||||
// }
|
||||
// for (; pit != end; ++pit, ++it) {
|
||||
// sum = ComputeChecksum(sum, *it);
|
||||
// absl::PrefetchToLocalCache(pit->data());
|
||||
// }
|
||||
// for (; it != end; ++it) {
|
||||
// sum = ComputeChecksum(sum, *it);
|
||||
// }
|
||||
// return sum;
|
||||
// }
|
||||
//
|
||||
void PrefetchToLocalCache(const void* addr);
|
||||
|
||||
// Moves data into the L1 cache before it is read, or "prefetches" it.
|
||||
//
|
||||
// This function is identical to `PrefetchToLocalCache()` except that it has
|
||||
// non-temporal locality: the fetched data should not be left in any of the
|
||||
// cache tiers. This is useful for cases where the data is used only once /
|
||||
// short term, for example, invoking a destructor on an object.
|
||||
//
|
||||
// Incorrect or gratuitous use of this function can degrade performance.
|
||||
// Use this function only when representative benchmarks show an improvement.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// template <typename Iterator>
|
||||
// void DestroyPointers(Iterator begin, Iterator end) {
|
||||
// size_t distance = std::min(8U, bars.size());
|
||||
//
|
||||
// int dist = 8;
|
||||
// auto prefetch_it = begin;
|
||||
// while (prefetch_it != end && --dist;) {
|
||||
// absl::PrefetchToLocalCacheNta(*prefetch_it++);
|
||||
// }
|
||||
// while (prefetch_it != end) {
|
||||
// delete *begin++;
|
||||
// absl::PrefetchToLocalCacheNta(*prefetch_it++);
|
||||
// }
|
||||
// while (begin != end) {
|
||||
// delete *begin++;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
void PrefetchToLocalCacheNta(const void* addr);
|
||||
|
||||
// Moves data into the L1 cache with the intent to modify it.
|
||||
//
|
||||
// This function is similar to `PrefetchToLocalCache()` except that it
|
||||
// prefetches cachelines with an 'intent to modify' This typically includes
|
||||
// invalidating cache entries for this address in all other cache tiers, and an
|
||||
// exclusive access intent.
|
||||
//
|
||||
// Incorrect or gratuitous use of this function can degrade performance. As this
|
||||
// function can invalidate cached cachelines on other caches and computer cores,
|
||||
// incorrect usage of this function can have an even greater negative impact
|
||||
// than incorrect regular prefetches.
|
||||
// Use this function only when representative benchmarks show an improvement.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// void* Arena::Allocate(size_t size) {
|
||||
// void* ptr = AllocateBlock(size);
|
||||
// absl::PrefetchToLocalCacheForWrite(ptr);
|
||||
// return ptr;
|
||||
// }
|
||||
//
|
||||
void PrefetchToLocalCacheForWrite(const void* addr);
|
||||
|
||||
#if ABSL_HAVE_BUILTIN(__builtin_prefetch) || defined(__GNUC__)
|
||||
|
||||
#define ABSL_HAVE_PREFETCH 1
|
||||
|
||||
// See __builtin_prefetch:
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html.
|
||||
//
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
|
||||
const void* addr) {
|
||||
__builtin_prefetch(addr, 0, 3);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
|
||||
const void* addr) {
|
||||
__builtin_prefetch(addr, 0, 0);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
|
||||
const void* addr) {
|
||||
// [x86] gcc/clang don't generate PREFETCHW for __builtin_prefetch(.., 1)
|
||||
// unless -march=broadwell or newer; this is not generally the default, so we
|
||||
// manually emit prefetchw. PREFETCHW is recognized as a no-op on older Intel
|
||||
// processors and has been present on AMD processors since the K6-2.
|
||||
#if defined(__x86_64__) && !defined(__PRFCHW__)
|
||||
asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr)));
|
||||
#else
|
||||
__builtin_prefetch(addr, 1, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
#elif defined(ABSL_INTERNAL_HAVE_SSE)
|
||||
|
||||
#define ABSL_HAVE_PREFETCH 1
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
|
||||
const void* addr) {
|
||||
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_T0);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
|
||||
const void* addr) {
|
||||
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_NTA);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
|
||||
const void* addr) {
|
||||
#if defined(_MM_HINT_ET0)
|
||||
_mm_prefetch(reinterpret_cast<const char*>(addr), _MM_HINT_ET0);
|
||||
#elif !defined(_MSC_VER) && defined(__x86_64__)
|
||||
// _MM_HINT_ET0 is not universally supported. As we commented further
|
||||
// up, PREFETCHW is recognized as a no-op on older Intel processors
|
||||
// and has been present on AMD processors since the K6-2. We have this
|
||||
// disabled for MSVC compilers as this miscompiles on older MSVC compilers.
|
||||
asm("prefetchw %0" : : "m"(*reinterpret_cast<const char*>(addr)));
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCache(
|
||||
const void* addr) {}
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheNta(
|
||||
const void* addr) {}
|
||||
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void PrefetchToLocalCacheForWrite(
|
||||
const void* addr) {}
|
||||
|
||||
#endif
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_PREFETCH_H_
|
||||
@@ -0,0 +1,333 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: thread_annotations.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file contains macro definitions for thread safety annotations
|
||||
// that allow developers to document the locking policies of multi-threaded
|
||||
// code. The annotations can also help program analysis tools to identify
|
||||
// potential thread safety issues.
|
||||
//
|
||||
// These annotations are implemented using compiler attributes. Using the macros
|
||||
// defined here instead of raw attributes allow for portability and future
|
||||
// compatibility.
|
||||
//
|
||||
// When referring to mutexes in the arguments of the attributes, you should
|
||||
// use variable names or more complex expressions (e.g. my_object->mutex_)
|
||||
// that evaluate to a concrete mutex object whenever possible. If the mutex
|
||||
// you want to refer to is not in scope, you may use a member pointer
|
||||
// (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object.
|
||||
|
||||
#ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
#define ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// ABSL_GUARDED_BY()
|
||||
//
|
||||
// Documents if a shared field or global variable needs to be protected by a
|
||||
// mutex. ABSL_GUARDED_BY() allows the user to specify a particular mutex that
|
||||
// should be held when accessing the annotated variable.
|
||||
//
|
||||
// Although this annotation (and ABSL_PT_GUARDED_BY, below) cannot be applied to
|
||||
// local variables, a local variable and its associated mutex can often be
|
||||
// combined into a small class or struct, thereby allowing the annotation.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// class Foo {
|
||||
// Mutex mu_;
|
||||
// int p1_ ABSL_GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
#if ABSL_HAVE_ATTRIBUTE(guarded_by)
|
||||
#define ABSL_GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||
#else
|
||||
#define ABSL_GUARDED_BY(x)
|
||||
#endif
|
||||
|
||||
// ABSL_PT_GUARDED_BY()
|
||||
//
|
||||
// Documents if the memory location pointed to by a pointer should be guarded
|
||||
// by a mutex when dereferencing the pointer.
|
||||
//
|
||||
// Example:
|
||||
// class Foo {
|
||||
// Mutex mu_;
|
||||
// int *p1_ ABSL_PT_GUARDED_BY(mu_);
|
||||
// ...
|
||||
// };
|
||||
//
|
||||
// Note that a pointer variable to a shared memory location could itself be a
|
||||
// shared variable.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // `q_`, guarded by `mu1_`, points to a shared memory location that is
|
||||
// // guarded by `mu2_`:
|
||||
// int *q_ ABSL_GUARDED_BY(mu1_) ABSL_PT_GUARDED_BY(mu2_);
|
||||
#if ABSL_HAVE_ATTRIBUTE(pt_guarded_by)
|
||||
#define ABSL_PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x)))
|
||||
#else
|
||||
#define ABSL_PT_GUARDED_BY(x)
|
||||
#endif
|
||||
|
||||
// ABSL_ACQUIRED_AFTER() / ABSL_ACQUIRED_BEFORE()
|
||||
//
|
||||
// Documents the acquisition order between locks that can be held
|
||||
// simultaneously by a thread. For any two locks that need to be annotated
|
||||
// to establish an acquisition order, only one of them needs the annotation.
|
||||
// (i.e. You don't have to annotate both locks with both ABSL_ACQUIRED_AFTER
|
||||
// and ABSL_ACQUIRED_BEFORE.)
|
||||
//
|
||||
// As with ABSL_GUARDED_BY, this is only applicable to mutexes that are shared
|
||||
// fields or global variables.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Mutex m1_;
|
||||
// Mutex m2_ ABSL_ACQUIRED_AFTER(m1_);
|
||||
#if ABSL_HAVE_ATTRIBUTE(acquired_after)
|
||||
#define ABSL_ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ACQUIRED_AFTER(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(acquired_before)
|
||||
#define ABSL_ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ACQUIRED_BEFORE(...)
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_LOCKS_REQUIRED() / ABSL_SHARED_LOCKS_REQUIRED()
|
||||
//
|
||||
// Documents a function that expects a mutex to be held prior to entry.
|
||||
// The mutex is expected to be held both on entry to, and exit from, the
|
||||
// function.
|
||||
//
|
||||
// An exclusive lock allows read-write access to the guarded data member(s), and
|
||||
// only one thread can acquire a lock exclusively at any one time. A shared lock
|
||||
// allows read-only access, and any number of threads can acquire a shared lock
|
||||
// concurrently.
|
||||
//
|
||||
// Generally, non-const methods should be annotated with
|
||||
// ABSL_EXCLUSIVE_LOCKS_REQUIRED, while const methods should be annotated with
|
||||
// ABSL_SHARED_LOCKS_REQUIRED.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// Mutex mu1, mu2;
|
||||
// int a ABSL_GUARDED_BY(mu1);
|
||||
// int b ABSL_GUARDED_BY(mu2);
|
||||
//
|
||||
// void foo() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
// void bar() const ABSL_SHARED_LOCKS_REQUIRED(mu1, mu2) { ... }
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_locks_required)
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
__attribute__((exclusive_locks_required(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_LOCKS_REQUIRED(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_locks_required)
|
||||
#define ABSL_SHARED_LOCKS_REQUIRED(...) \
|
||||
__attribute__((shared_locks_required(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_LOCKS_REQUIRED(...)
|
||||
#endif
|
||||
|
||||
// ABSL_LOCKS_EXCLUDED()
|
||||
//
|
||||
// Documents the locks that cannot be held by callers of this function, as they
|
||||
// might be acquired by this function (Abseil's `Mutex` locks are
|
||||
// non-reentrant).
|
||||
#if ABSL_HAVE_ATTRIBUTE(locks_excluded)
|
||||
#define ABSL_LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_LOCKS_EXCLUDED(...)
|
||||
#endif
|
||||
|
||||
// ABSL_LOCK_RETURNED()
|
||||
//
|
||||
// Documents a function that returns a mutex without acquiring it. For example,
|
||||
// a public getter method that returns a pointer to a private mutex should
|
||||
// be annotated with ABSL_LOCK_RETURNED.
|
||||
#if ABSL_HAVE_ATTRIBUTE(lock_returned)
|
||||
#define ABSL_LOCK_RETURNED(x) __attribute__((lock_returned(x)))
|
||||
#else
|
||||
#define ABSL_LOCK_RETURNED(x)
|
||||
#endif
|
||||
|
||||
// ABSL_LOCKABLE
|
||||
//
|
||||
// Documents if a class/type is a lockable type (such as the `Mutex` class).
|
||||
#if ABSL_HAVE_ATTRIBUTE(lockable)
|
||||
#define ABSL_LOCKABLE __attribute__((lockable))
|
||||
#else
|
||||
#define ABSL_LOCKABLE
|
||||
#endif
|
||||
|
||||
// ABSL_SCOPED_LOCKABLE
|
||||
//
|
||||
// Documents if a class does RAII locking (such as the `MutexLock` class).
|
||||
// The constructor should use `LOCK_FUNCTION()` to specify the mutex that is
|
||||
// acquired, and the destructor should use `UNLOCK_FUNCTION()` with no
|
||||
// arguments; the analysis will assume that the destructor unlocks whatever the
|
||||
// constructor locked.
|
||||
#if ABSL_HAVE_ATTRIBUTE(scoped_lockable)
|
||||
#define ABSL_SCOPED_LOCKABLE __attribute__((scoped_lockable))
|
||||
#else
|
||||
#define ABSL_SCOPED_LOCKABLE
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_LOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that acquire a lock in the body of a function, and do
|
||||
// not release it.
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_lock_function)
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
__attribute__((exclusive_lock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_LOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_SHARED_LOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that acquire a shared (reader) lock in the body of a
|
||||
// function, and do not release it.
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_lock_function)
|
||||
#define ABSL_SHARED_LOCK_FUNCTION(...) \
|
||||
__attribute__((shared_lock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_LOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_UNLOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that expect a lock to be held on entry to the function,
|
||||
// and release it in the body of the function.
|
||||
#if ABSL_HAVE_ATTRIBUTE(unlock_function)
|
||||
#define ABSL_UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_UNLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_EXCLUSIVE_TRYLOCK_FUNCTION() / ABSL_SHARED_TRYLOCK_FUNCTION()
|
||||
//
|
||||
// Documents functions that try to acquire a lock, and return success or failure
|
||||
// (or a non-boolean value that can be interpreted as a boolean).
|
||||
// The first argument should be `true` for functions that return `true` on
|
||||
// success, or `false` for functions that return `false` on success. The second
|
||||
// argument specifies the mutex that is locked on success. If unspecified, this
|
||||
// mutex is assumed to be `this`.
|
||||
#if ABSL_HAVE_ATTRIBUTE(exclusive_trylock_function)
|
||||
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||
__attribute__((exclusive_trylock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_EXCLUSIVE_TRYLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(shared_trylock_function)
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
__attribute__((shared_trylock_function(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_SHARED_TRYLOCK_FUNCTION(...)
|
||||
#endif
|
||||
|
||||
// ABSL_ASSERT_EXCLUSIVE_LOCK() / ABSL_ASSERT_SHARED_LOCK()
|
||||
//
|
||||
// Documents functions that dynamically check to see if a lock is held, and fail
|
||||
// if it is not held.
|
||||
#if ABSL_HAVE_ATTRIBUTE(assert_exclusive_lock)
|
||||
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...) \
|
||||
__attribute__((assert_exclusive_lock(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ASSERT_EXCLUSIVE_LOCK(...)
|
||||
#endif
|
||||
|
||||
#if ABSL_HAVE_ATTRIBUTE(assert_shared_lock)
|
||||
#define ABSL_ASSERT_SHARED_LOCK(...) \
|
||||
__attribute__((assert_shared_lock(__VA_ARGS__)))
|
||||
#else
|
||||
#define ABSL_ASSERT_SHARED_LOCK(...)
|
||||
#endif
|
||||
|
||||
// ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
//
|
||||
// Turns off thread safety checking within the body of a particular function.
|
||||
// This annotation is used to mark functions that are known to be correct, but
|
||||
// the locking behavior is more complicated than the analyzer can handle.
|
||||
#if ABSL_HAVE_ATTRIBUTE(no_thread_safety_analysis)
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS \
|
||||
__attribute__((no_thread_safety_analysis))
|
||||
#else
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Tool-Supplied Annotations
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// ABSL_TS_UNCHECKED should be placed around lock expressions that are not valid
|
||||
// C++ syntax, but which are present for documentation purposes. These
|
||||
// annotations will be ignored by the analysis.
|
||||
#define ABSL_TS_UNCHECKED(x) ""
|
||||
|
||||
// ABSL_TS_FIXME is used to mark lock expressions that are not valid C++ syntax.
|
||||
// It is used by automated tools to mark and disable invalid expressions.
|
||||
// The annotation should either be fixed, or changed to ABSL_TS_UNCHECKED.
|
||||
#define ABSL_TS_FIXME(x) ""
|
||||
|
||||
// Like ABSL_NO_THREAD_SAFETY_ANALYSIS, this turns off checking within the body
|
||||
// of a particular function. However, this attribute is used to mark functions
|
||||
// that are incorrect and need to be fixed. It is used by automated tools to
|
||||
// avoid breaking the build when the analysis is updated.
|
||||
// Code owners are expected to eventually fix the routine.
|
||||
#define ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME ABSL_NO_THREAD_SAFETY_ANALYSIS
|
||||
|
||||
// Similar to ABSL_NO_THREAD_SAFETY_ANALYSIS_FIXME, this macro marks a
|
||||
// ABSL_GUARDED_BY annotation that needs to be fixed, because it is producing
|
||||
// thread safety warning. It disables the ABSL_GUARDED_BY.
|
||||
#define ABSL_GUARDED_BY_FIXME(x)
|
||||
|
||||
// Disables warnings for a single read operation. This can be used to avoid
|
||||
// warnings when it is known that the read is not actually involved in a race,
|
||||
// but the compiler cannot confirm that.
|
||||
#define ABSL_TS_UNCHECKED_READ(x) absl::base_internal::ts_unchecked_read(x)
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace base_internal {
|
||||
|
||||
// Takes a reference to a guarded data member, and returns an unguarded
|
||||
// reference.
|
||||
// Do not use this function directly, use ABSL_TS_UNCHECKED_READ instead.
|
||||
template <typename T>
|
||||
inline const T& ts_unchecked_read(const T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T& ts_unchecked_read(T& v) ABSL_NO_THREAD_SAFETY_ANALYSIS {
|
||||
return v;
|
||||
}
|
||||
|
||||
} // namespace base_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_BASE_THREAD_ANNOTATIONS_H_
|
||||
@@ -0,0 +1,556 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: fixed_array.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// A `FixedArray<T>` represents a non-resizable array of `T` where the length of
|
||||
// the array can be determined at run-time. It is a good replacement for
|
||||
// non-standard and deprecated uses of `alloca()` and variable length arrays
|
||||
// within the GCC extension. (See
|
||||
// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html).
|
||||
//
|
||||
// `FixedArray` allocates small arrays inline, keeping performance fast by
|
||||
// avoiding heap operations. It also helps reduce the chances of
|
||||
// accidentally overflowing your stack if large input is passed to
|
||||
// your function.
|
||||
|
||||
#ifndef ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||
#define ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/algorithm/algorithm.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/dynamic_annotations.h"
|
||||
#include "absl/base/internal/throw_delegate.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/container/internal/compressed_tuple.h"
|
||||
#include "absl/memory/memory.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
constexpr static auto kFixedArrayUseDefault = static_cast<size_t>(-1);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// FixedArray
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// A `FixedArray` provides a run-time fixed-size array, allocating a small array
|
||||
// inline for efficiency.
|
||||
//
|
||||
// Most users should not specify the `N` template parameter and let `FixedArray`
|
||||
// automatically determine the number of elements to store inline based on
|
||||
// `sizeof(T)`. If `N` is specified, the `FixedArray` implementation will use
|
||||
// inline storage for arrays with a length <= `N`.
|
||||
//
|
||||
// Note that a `FixedArray` constructed with a `size_type` argument will
|
||||
// default-initialize its values by leaving trivially constructible types
|
||||
// uninitialized (e.g. int, int[4], double), and others default-constructed.
|
||||
// This matches the behavior of c-style arrays and `std::array`, but not
|
||||
// `std::vector`.
|
||||
template <typename T, size_t N = kFixedArrayUseDefault,
|
||||
typename A = std::allocator<T>>
|
||||
class FixedArray {
|
||||
static_assert(!std::is_array<T>::value || std::extent<T>::value > 0,
|
||||
"Arrays with unknown bounds cannot be used with FixedArray.");
|
||||
|
||||
static constexpr size_t kInlineBytesDefault = 256;
|
||||
|
||||
using AllocatorTraits = std::allocator_traits<A>;
|
||||
// std::iterator_traits isn't guaranteed to be SFINAE-friendly until C++17,
|
||||
// but this seems to be mostly pedantic.
|
||||
template <typename Iterator>
|
||||
using EnableIfForwardIterator = absl::enable_if_t<std::is_convertible<
|
||||
typename std::iterator_traits<Iterator>::iterator_category,
|
||||
std::forward_iterator_tag>::value>;
|
||||
static constexpr bool NoexceptCopyable() {
|
||||
return std::is_nothrow_copy_constructible<StorageElement>::value &&
|
||||
absl::allocator_is_nothrow<allocator_type>::value;
|
||||
}
|
||||
static constexpr bool NoexceptMovable() {
|
||||
return std::is_nothrow_move_constructible<StorageElement>::value &&
|
||||
absl::allocator_is_nothrow<allocator_type>::value;
|
||||
}
|
||||
static constexpr bool DefaultConstructorIsNonTrivial() {
|
||||
return !absl::is_trivially_default_constructible<StorageElement>::value;
|
||||
}
|
||||
|
||||
public:
|
||||
using allocator_type = typename AllocatorTraits::allocator_type;
|
||||
using value_type = typename AllocatorTraits::value_type;
|
||||
using pointer = typename AllocatorTraits::pointer;
|
||||
using const_pointer = typename AllocatorTraits::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = typename AllocatorTraits::size_type;
|
||||
using difference_type = typename AllocatorTraits::difference_type;
|
||||
using iterator = pointer;
|
||||
using const_iterator = const_pointer;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
|
||||
static constexpr size_type inline_elements =
|
||||
(N == kFixedArrayUseDefault ? kInlineBytesDefault / sizeof(value_type)
|
||||
: static_cast<size_type>(N));
|
||||
|
||||
FixedArray(const FixedArray& other) noexcept(NoexceptCopyable())
|
||||
: FixedArray(other,
|
||||
AllocatorTraits::select_on_container_copy_construction(
|
||||
other.storage_.alloc())) {}
|
||||
|
||||
FixedArray(const FixedArray& other,
|
||||
const allocator_type& a) noexcept(NoexceptCopyable())
|
||||
: FixedArray(other.begin(), other.end(), a) {}
|
||||
|
||||
FixedArray(FixedArray&& other) noexcept(NoexceptMovable())
|
||||
: FixedArray(std::move(other), other.storage_.alloc()) {}
|
||||
|
||||
FixedArray(FixedArray&& other,
|
||||
const allocator_type& a) noexcept(NoexceptMovable())
|
||||
: FixedArray(std::make_move_iterator(other.begin()),
|
||||
std::make_move_iterator(other.end()), a) {}
|
||||
|
||||
// Creates an array object that can store `n` elements.
|
||||
// Note that trivially constructible elements will be uninitialized.
|
||||
explicit FixedArray(size_type n, const allocator_type& a = allocator_type())
|
||||
: storage_(n, a) {
|
||||
if (DefaultConstructorIsNonTrivial()) {
|
||||
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
|
||||
storage_.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Creates an array initialized with `n` copies of `val`.
|
||||
FixedArray(size_type n, const value_type& val,
|
||||
const allocator_type& a = allocator_type())
|
||||
: storage_(n, a) {
|
||||
memory_internal::ConstructRange(storage_.alloc(), storage_.begin(),
|
||||
storage_.end(), val);
|
||||
}
|
||||
|
||||
// Creates an array initialized with the size and contents of `init_list`.
|
||||
FixedArray(std::initializer_list<value_type> init_list,
|
||||
const allocator_type& a = allocator_type())
|
||||
: FixedArray(init_list.begin(), init_list.end(), a) {}
|
||||
|
||||
// Creates an array initialized with the elements from the input
|
||||
// range. The array's size will always be `std::distance(first, last)`.
|
||||
// REQUIRES: Iterator must be a forward_iterator or better.
|
||||
template <typename Iterator, EnableIfForwardIterator<Iterator>* = nullptr>
|
||||
FixedArray(Iterator first, Iterator last,
|
||||
const allocator_type& a = allocator_type())
|
||||
: storage_(std::distance(first, last), a) {
|
||||
memory_internal::CopyRange(storage_.alloc(), storage_.begin(), first, last);
|
||||
}
|
||||
|
||||
~FixedArray() noexcept {
|
||||
for (auto* cur = storage_.begin(); cur != storage_.end(); ++cur) {
|
||||
AllocatorTraits::destroy(storage_.alloc(), cur);
|
||||
}
|
||||
}
|
||||
|
||||
// Assignments are deleted because they break the invariant that the size of a
|
||||
// `FixedArray` never changes.
|
||||
void operator=(FixedArray&&) = delete;
|
||||
void operator=(const FixedArray&) = delete;
|
||||
|
||||
// FixedArray::size()
|
||||
//
|
||||
// Returns the length of the fixed array.
|
||||
size_type size() const { return storage_.size(); }
|
||||
|
||||
// FixedArray::max_size()
|
||||
//
|
||||
// Returns the largest possible value of `std::distance(begin(), end())` for a
|
||||
// `FixedArray<T>`. This is equivalent to the most possible addressable bytes
|
||||
// over the number of bytes taken by T.
|
||||
constexpr size_type max_size() const {
|
||||
return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
|
||||
}
|
||||
|
||||
// FixedArray::empty()
|
||||
//
|
||||
// Returns whether or not the fixed array is empty.
|
||||
bool empty() const { return size() == 0; }
|
||||
|
||||
// FixedArray::memsize()
|
||||
//
|
||||
// Returns the memory size of the fixed array in bytes.
|
||||
size_t memsize() const { return size() * sizeof(value_type); }
|
||||
|
||||
// FixedArray::data()
|
||||
//
|
||||
// Returns a const T* pointer to elements of the `FixedArray`. This pointer
|
||||
// can be used to access (but not modify) the contained elements.
|
||||
const_pointer data() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return AsValueType(storage_.begin());
|
||||
}
|
||||
|
||||
// Overload of FixedArray::data() to return a T* pointer to elements of the
|
||||
// fixed array. This pointer can be used to access and modify the contained
|
||||
// elements.
|
||||
pointer data() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return AsValueType(storage_.begin());
|
||||
}
|
||||
|
||||
// FixedArray::operator[]
|
||||
//
|
||||
// Returns a reference the ith element of the fixed array.
|
||||
// REQUIRES: 0 <= i < size()
|
||||
reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::operator()[] to return a const reference to the
|
||||
// ith element of the fixed array.
|
||||
// REQUIRES: 0 <= i < size()
|
||||
const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(i < size());
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
// FixedArray::at
|
||||
//
|
||||
// Bounds-checked access. Returns a reference to the ith element of the fixed
|
||||
// array, or throws std::out_of_range
|
||||
reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
|
||||
}
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::at() to return a const reference to the ith element
|
||||
// of the fixed array.
|
||||
const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
if (ABSL_PREDICT_FALSE(i >= size())) {
|
||||
base_internal::ThrowStdOutOfRange("FixedArray::at failed bounds check");
|
||||
}
|
||||
return data()[i];
|
||||
}
|
||||
|
||||
// FixedArray::front()
|
||||
//
|
||||
// Returns a reference to the first element of the fixed array.
|
||||
reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::front() to return a reference to the first element
|
||||
// of a fixed array of const values.
|
||||
const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[0];
|
||||
}
|
||||
|
||||
// FixedArray::back()
|
||||
//
|
||||
// Returns a reference to the last element of the fixed array.
|
||||
reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
// Overload of FixedArray::back() to return a reference to the last element
|
||||
// of a fixed array of const values.
|
||||
const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
ABSL_HARDENING_ASSERT(!empty());
|
||||
return data()[size() - 1];
|
||||
}
|
||||
|
||||
// FixedArray::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the fixed array.
|
||||
iterator begin() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
|
||||
|
||||
// Overload of FixedArray::begin() to return a const iterator to the
|
||||
// beginning of the fixed array.
|
||||
const_iterator begin() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
|
||||
|
||||
// FixedArray::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the fixed array.
|
||||
const_iterator cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return begin();
|
||||
}
|
||||
|
||||
// FixedArray::end()
|
||||
//
|
||||
// Returns an iterator to the end of the fixed array.
|
||||
iterator end() ABSL_ATTRIBUTE_LIFETIME_BOUND { return data() + size(); }
|
||||
|
||||
// Overload of FixedArray::end() to return a const iterator to the end of the
|
||||
// fixed array.
|
||||
const_iterator end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return data() + size();
|
||||
}
|
||||
|
||||
// FixedArray::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the fixed array.
|
||||
const_iterator cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return end(); }
|
||||
|
||||
// FixedArray::rbegin()
|
||||
//
|
||||
// Returns a reverse iterator from the end of the fixed array.
|
||||
reverse_iterator rbegin() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
|
||||
// Overload of FixedArray::rbegin() to return a const reverse iterator from
|
||||
// the end of the fixed array.
|
||||
const_reverse_iterator rbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return const_reverse_iterator(end());
|
||||
}
|
||||
|
||||
// FixedArray::crbegin()
|
||||
//
|
||||
// Returns a const reverse iterator from the end of the fixed array.
|
||||
const_reverse_iterator crbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return rbegin();
|
||||
}
|
||||
|
||||
// FixedArray::rend()
|
||||
//
|
||||
// Returns a reverse iterator from the beginning of the fixed array.
|
||||
reverse_iterator rend() ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
// Overload of FixedArray::rend() for returning a const reverse iterator
|
||||
// from the beginning of the fixed array.
|
||||
const_reverse_iterator rend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return const_reverse_iterator(begin());
|
||||
}
|
||||
|
||||
// FixedArray::crend()
|
||||
//
|
||||
// Returns a reverse iterator from the beginning of the fixed array.
|
||||
const_reverse_iterator crend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return rend();
|
||||
}
|
||||
|
||||
// FixedArray::fill()
|
||||
//
|
||||
// Assigns the given `value` to all elements in the fixed array.
|
||||
void fill(const value_type& val) { std::fill(begin(), end(), val); }
|
||||
|
||||
// Relational operators. Equality operators are elementwise using
|
||||
// `operator==`, while order operators order FixedArrays lexicographically.
|
||||
friend bool operator==(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
|
||||
}
|
||||
|
||||
friend bool operator!=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
friend bool operator<(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
|
||||
rhs.end());
|
||||
}
|
||||
|
||||
friend bool operator>(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
|
||||
friend bool operator<=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
friend bool operator>=(const FixedArray& lhs, const FixedArray& rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, const FixedArray& v) {
|
||||
return H::combine(H::combine_contiguous(std::move(h), v.data(), v.size()),
|
||||
v.size());
|
||||
}
|
||||
|
||||
private:
|
||||
// StorageElement
|
||||
//
|
||||
// For FixedArrays with a C-style-array value_type, StorageElement is a POD
|
||||
// wrapper struct called StorageElementWrapper that holds the value_type
|
||||
// instance inside. This is needed for construction and destruction of the
|
||||
// entire array regardless of how many dimensions it has. For all other cases,
|
||||
// StorageElement is just an alias of value_type.
|
||||
//
|
||||
// Maintainer's Note: The simpler solution would be to simply wrap value_type
|
||||
// in a struct whether it's an array or not. That causes some paranoid
|
||||
// diagnostics to misfire, believing that 'data()' returns a pointer to a
|
||||
// single element, rather than the packed array that it really is.
|
||||
// e.g.:
|
||||
//
|
||||
// FixedArray<char> buf(1);
|
||||
// sprintf(buf.data(), "foo");
|
||||
//
|
||||
// error: call to int __builtin___sprintf_chk(etc...)
|
||||
// will always overflow destination buffer [-Werror]
|
||||
//
|
||||
template <typename OuterT, typename InnerT = absl::remove_extent_t<OuterT>,
|
||||
size_t InnerN = std::extent<OuterT>::value>
|
||||
struct StorageElementWrapper {
|
||||
InnerT array[InnerN];
|
||||
};
|
||||
|
||||
using StorageElement =
|
||||
absl::conditional_t<std::is_array<value_type>::value,
|
||||
StorageElementWrapper<value_type>, value_type>;
|
||||
|
||||
static pointer AsValueType(pointer ptr) { return ptr; }
|
||||
static pointer AsValueType(StorageElementWrapper<value_type>* ptr) {
|
||||
return std::addressof(ptr->array);
|
||||
}
|
||||
|
||||
static_assert(sizeof(StorageElement) == sizeof(value_type), "");
|
||||
static_assert(alignof(StorageElement) == alignof(value_type), "");
|
||||
|
||||
class NonEmptyInlinedStorage {
|
||||
public:
|
||||
StorageElement* data() { return reinterpret_cast<StorageElement*>(buff_); }
|
||||
void AnnotateConstruct(size_type n);
|
||||
void AnnotateDestruct(size_type n);
|
||||
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
void* RedzoneBegin() { return &redzone_begin_; }
|
||||
void* RedzoneEnd() { return &redzone_end_ + 1; }
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
|
||||
private:
|
||||
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_begin_);
|
||||
alignas(StorageElement) char buff_[sizeof(StorageElement[inline_elements])];
|
||||
ABSL_ADDRESS_SANITIZER_REDZONE(redzone_end_);
|
||||
};
|
||||
|
||||
class EmptyInlinedStorage {
|
||||
public:
|
||||
StorageElement* data() { return nullptr; }
|
||||
void AnnotateConstruct(size_type) {}
|
||||
void AnnotateDestruct(size_type) {}
|
||||
};
|
||||
|
||||
using InlinedStorage =
|
||||
absl::conditional_t<inline_elements == 0, EmptyInlinedStorage,
|
||||
NonEmptyInlinedStorage>;
|
||||
|
||||
// Storage
|
||||
//
|
||||
// An instance of Storage manages the inline and out-of-line memory for
|
||||
// instances of FixedArray. This guarantees that even when construction of
|
||||
// individual elements fails in the FixedArray constructor body, the
|
||||
// destructor for Storage will still be called and out-of-line memory will be
|
||||
// properly deallocated.
|
||||
//
|
||||
class Storage : public InlinedStorage {
|
||||
public:
|
||||
Storage(size_type n, const allocator_type& a)
|
||||
: size_alloc_(n, a), data_(InitializeData()) {}
|
||||
|
||||
~Storage() noexcept {
|
||||
if (UsingInlinedStorage(size())) {
|
||||
InlinedStorage::AnnotateDestruct(size());
|
||||
} else {
|
||||
AllocatorTraits::deallocate(alloc(), AsValueType(begin()), size());
|
||||
}
|
||||
}
|
||||
|
||||
size_type size() const { return size_alloc_.template get<0>(); }
|
||||
StorageElement* begin() const { return data_; }
|
||||
StorageElement* end() const { return begin() + size(); }
|
||||
allocator_type& alloc() { return size_alloc_.template get<1>(); }
|
||||
const allocator_type& alloc() const {
|
||||
return size_alloc_.template get<1>();
|
||||
}
|
||||
|
||||
private:
|
||||
static bool UsingInlinedStorage(size_type n) {
|
||||
return n <= inline_elements;
|
||||
}
|
||||
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
ABSL_ATTRIBUTE_NOINLINE
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
StorageElement* InitializeData() {
|
||||
if (UsingInlinedStorage(size())) {
|
||||
InlinedStorage::AnnotateConstruct(size());
|
||||
return InlinedStorage::data();
|
||||
} else {
|
||||
return reinterpret_cast<StorageElement*>(
|
||||
AllocatorTraits::allocate(alloc(), size()));
|
||||
}
|
||||
}
|
||||
|
||||
// `CompressedTuple` takes advantage of EBCO for stateless `allocator_type`s
|
||||
container_internal::CompressedTuple<size_type, allocator_type> size_alloc_;
|
||||
StorageElement* data_;
|
||||
};
|
||||
|
||||
Storage storage_;
|
||||
};
|
||||
|
||||
#ifdef ABSL_INTERNAL_NEED_REDUNDANT_CONSTEXPR_DECL
|
||||
template <typename T, size_t N, typename A>
|
||||
constexpr size_t FixedArray<T, N, A>::kInlineBytesDefault;
|
||||
|
||||
template <typename T, size_t N, typename A>
|
||||
constexpr typename FixedArray<T, N, A>::size_type
|
||||
FixedArray<T, N, A>::inline_elements;
|
||||
#endif
|
||||
|
||||
template <typename T, size_t N, typename A>
|
||||
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateConstruct(
|
||||
typename FixedArray<T, N, A>::size_type n) {
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
if (!n) return;
|
||||
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), RedzoneEnd(),
|
||||
data() + n);
|
||||
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), data(),
|
||||
RedzoneBegin());
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
static_cast<void>(n); // Mark used when not in asan mode
|
||||
}
|
||||
|
||||
template <typename T, size_t N, typename A>
|
||||
void FixedArray<T, N, A>::NonEmptyInlinedStorage::AnnotateDestruct(
|
||||
typename FixedArray<T, N, A>::size_type n) {
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
if (!n) return;
|
||||
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(data(), RedzoneEnd(), data() + n,
|
||||
RedzoneEnd());
|
||||
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(RedzoneBegin(), data(), RedzoneBegin(),
|
||||
data());
|
||||
#endif // ABSL_HAVE_ADDRESS_SANITIZER
|
||||
static_cast<void>(n); // Mark used when not in asan mode
|
||||
}
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_FIXED_ARRAY_H_
|
||||
@@ -0,0 +1,673 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: flat_hash_map.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::flat_hash_map<K, V>` is an unordered associative container of
|
||||
// unique keys and associated values designed to be a more efficient replacement
|
||||
// for `std::unordered_map`. Like `unordered_map`, search, insertion, and
|
||||
// deletion of map elements can be done as an `O(1)` operation. However,
|
||||
// `flat_hash_map` (and other unordered associative containers known as the
|
||||
// collection of Abseil "Swiss tables") contain other optimizations that result
|
||||
// in both memory and computation advantages.
|
||||
//
|
||||
// In most cases, your default choice for a hash map should be a map of type
|
||||
// `flat_hash_map`.
|
||||
//
|
||||
// `flat_hash_map` is not exception-safe.
|
||||
|
||||
#ifndef ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||
#define ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/algorithm/container.h"
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/container/hash_container_defaults.h"
|
||||
#include "absl/container/internal/container_memory.h"
|
||||
#include "absl/container/internal/raw_hash_map.h" // IWYU pragma: export
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
template <class K, class V>
|
||||
struct FlatHashMapPolicy;
|
||||
} // namespace container_internal
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// absl::flat_hash_map
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// An `absl::flat_hash_map<K, V>` is an unordered associative container which
|
||||
// has been optimized for both speed and memory footprint in most common use
|
||||
// cases. Its interface is similar to that of `std::unordered_map<K, V>` with
|
||||
// the following notable differences:
|
||||
//
|
||||
// * Requires keys that are CopyConstructible
|
||||
// * Requires values that are MoveConstructible
|
||||
// * Supports heterogeneous lookup, through `find()`, `operator[]()` and
|
||||
// `insert()`, provided that the map is provided a compatible heterogeneous
|
||||
// hashing function and equality operator. See below for details.
|
||||
// * Invalidates any references and pointers to elements within the table after
|
||||
// `rehash()` and when the table is moved.
|
||||
// * Contains a `capacity()` member function indicating the number of element
|
||||
// slots (open, deleted, and empty) within the hash map.
|
||||
// * Returns `void` from the `erase(iterator)` overload.
|
||||
//
|
||||
// By default, `flat_hash_map` uses the `absl::Hash` hashing framework.
|
||||
// All fundamental and Abseil types that support the `absl::Hash` framework have
|
||||
// a compatible equality operator for comparing insertions into `flat_hash_map`.
|
||||
// If your type is not yet supported by the `absl::Hash` framework, see
|
||||
// absl/hash/hash.h for information on extending Abseil hashing to user-defined
|
||||
// types.
|
||||
//
|
||||
// Using `absl::flat_hash_map` at interface boundaries in dynamically loaded
|
||||
// libraries (e.g. .dll, .so) is unsupported due to way `absl::Hash` values may
|
||||
// be randomized across dynamically loaded libraries.
|
||||
//
|
||||
// To achieve heterogeneous lookup for custom types either `Hash` and `Eq` type
|
||||
// parameters can be used or `T` should have public inner types
|
||||
// `absl_container_hash` and (optionally) `absl_container_eq`. In either case,
|
||||
// `typename Hash::is_transparent` and `typename Eq::is_transparent` should be
|
||||
// well-formed. Both types are basically functors:
|
||||
// * `Hash` should support `size_t operator()(U val) const` that returns a hash
|
||||
// for the given `val`.
|
||||
// * `Eq` should support `bool operator()(U lhs, V rhs) const` that returns true
|
||||
// if `lhs` is equal to `rhs`.
|
||||
//
|
||||
// In most cases `T` needs only to provide the `absl_container_hash`. In this
|
||||
// case `std::equal_to<void>` will be used instead of `eq` part.
|
||||
//
|
||||
// NOTE: A `flat_hash_map` stores its value types directly inside its
|
||||
// implementation array to avoid memory indirection. Because a `flat_hash_map`
|
||||
// is designed to move data when rehashed, map values will not retain pointer
|
||||
// stability. If you require pointer stability, or if your values are large,
|
||||
// consider using `absl::flat_hash_map<Key, std::unique_ptr<Value>>` instead.
|
||||
// If your types are not moveable or you require pointer stability for keys,
|
||||
// consider `absl::node_hash_map`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Create a flat hash map of three strings (that map to strings)
|
||||
// absl::flat_hash_map<std::string, std::string> ducks =
|
||||
// {{"a", "huey"}, {"b", "dewey"}, {"c", "louie"}};
|
||||
//
|
||||
// // Insert a new element into the flat hash map
|
||||
// ducks.insert({"d", "donald"});
|
||||
//
|
||||
// // Force a rehash of the flat hash map
|
||||
// ducks.rehash(0);
|
||||
//
|
||||
// // Find the element with the key "b"
|
||||
// std::string search_key = "b";
|
||||
// auto result = ducks.find(search_key);
|
||||
// if (result != ducks.end()) {
|
||||
// std::cout << "Result: " << result->second << std::endl;
|
||||
// }
|
||||
template <class K, class V, class Hash = DefaultHashContainerHash<K>,
|
||||
class Eq = DefaultHashContainerEq<K>,
|
||||
class Allocator = std::allocator<std::pair<const K, V>>>
|
||||
class ABSL_INTERNAL_ATTRIBUTE_OWNER flat_hash_map
|
||||
: public absl::container_internal::raw_hash_map<
|
||||
absl::container_internal::FlatHashMapPolicy<K, V>, Hash, Eq,
|
||||
Allocator> {
|
||||
using Base = typename flat_hash_map::raw_hash_map;
|
||||
|
||||
public:
|
||||
// Constructors and Assignment Operators
|
||||
//
|
||||
// A flat_hash_map supports the same overload set as `std::unordered_map`
|
||||
// for construction and assignment:
|
||||
//
|
||||
// * Default constructor
|
||||
//
|
||||
// // No allocation for the table's elements is made.
|
||||
// absl::flat_hash_map<int, std::string> map1;
|
||||
//
|
||||
// * Initializer List constructor
|
||||
//
|
||||
// absl::flat_hash_map<int, std::string> map2 =
|
||||
// {{1, "huey"}, {2, "dewey"}, {3, "louie"},};
|
||||
//
|
||||
// * Copy constructor
|
||||
//
|
||||
// absl::flat_hash_map<int, std::string> map3(map2);
|
||||
//
|
||||
// * Copy assignment operator
|
||||
//
|
||||
// // Hash functor and Comparator are copied as well
|
||||
// absl::flat_hash_map<int, std::string> map4;
|
||||
// map4 = map3;
|
||||
//
|
||||
// * Move constructor
|
||||
//
|
||||
// // Move is guaranteed efficient
|
||||
// absl::flat_hash_map<int, std::string> map5(std::move(map4));
|
||||
//
|
||||
// * Move assignment operator
|
||||
//
|
||||
// // May be efficient if allocators are compatible
|
||||
// absl::flat_hash_map<int, std::string> map6;
|
||||
// map6 = std::move(map5);
|
||||
//
|
||||
// * Range constructor
|
||||
//
|
||||
// std::vector<std::pair<int, std::string>> v = {{1, "a"}, {2, "b"}};
|
||||
// absl::flat_hash_map<int, std::string> map7(v.begin(), v.end());
|
||||
flat_hash_map() {}
|
||||
using Base::Base;
|
||||
|
||||
// flat_hash_map::begin()
|
||||
//
|
||||
// Returns an iterator to the beginning of the `flat_hash_map`.
|
||||
using Base::begin;
|
||||
|
||||
// flat_hash_map::cbegin()
|
||||
//
|
||||
// Returns a const iterator to the beginning of the `flat_hash_map`.
|
||||
using Base::cbegin;
|
||||
|
||||
// flat_hash_map::cend()
|
||||
//
|
||||
// Returns a const iterator to the end of the `flat_hash_map`.
|
||||
using Base::cend;
|
||||
|
||||
// flat_hash_map::end()
|
||||
//
|
||||
// Returns an iterator to the end of the `flat_hash_map`.
|
||||
using Base::end;
|
||||
|
||||
// flat_hash_map::capacity()
|
||||
//
|
||||
// Returns the number of element slots (assigned, deleted, and empty)
|
||||
// available within the `flat_hash_map`.
|
||||
//
|
||||
// NOTE: this member function is particular to `absl::flat_hash_map` and is
|
||||
// not provided in the `std::unordered_map` API.
|
||||
using Base::capacity;
|
||||
|
||||
// flat_hash_map::empty()
|
||||
//
|
||||
// Returns whether or not the `flat_hash_map` is empty.
|
||||
using Base::empty;
|
||||
|
||||
// flat_hash_map::max_size()
|
||||
//
|
||||
// Returns the largest theoretical possible number of elements within a
|
||||
// `flat_hash_map` under current memory constraints. This value can be thought
|
||||
// of the largest value of `std::distance(begin(), end())` for a
|
||||
// `flat_hash_map<K, V>`.
|
||||
using Base::max_size;
|
||||
|
||||
// flat_hash_map::size()
|
||||
//
|
||||
// Returns the number of elements currently within the `flat_hash_map`.
|
||||
using Base::size;
|
||||
|
||||
// flat_hash_map::clear()
|
||||
//
|
||||
// Removes all elements from the `flat_hash_map`. Invalidates any references,
|
||||
// pointers, or iterators referring to contained elements.
|
||||
//
|
||||
// NOTE: this operation may shrink the underlying buffer. To avoid shrinking
|
||||
// the underlying buffer call `erase(begin(), end())`.
|
||||
using Base::clear;
|
||||
|
||||
// flat_hash_map::erase()
|
||||
//
|
||||
// Erases elements within the `flat_hash_map`. Erasing does not trigger a
|
||||
// rehash. Overloads are listed below.
|
||||
//
|
||||
// void erase(const_iterator pos):
|
||||
//
|
||||
// Erases the element at `position` of the `flat_hash_map`, returning
|
||||
// `void`.
|
||||
//
|
||||
// NOTE: returning `void` in this case is different than that of STL
|
||||
// containers in general and `std::unordered_map` in particular (which
|
||||
// return an iterator to the element following the erased element). If that
|
||||
// iterator is needed, simply post increment the iterator:
|
||||
//
|
||||
// map.erase(it++);
|
||||
//
|
||||
// iterator erase(const_iterator first, const_iterator last):
|
||||
//
|
||||
// Erases the elements in the open interval [`first`, `last`), returning an
|
||||
// iterator pointing to `last`. The special case of calling
|
||||
// `erase(begin(), end())` resets the reserved growth such that if
|
||||
// `reserve(N)` has previously been called and there has been no intervening
|
||||
// call to `clear()`, then after calling `erase(begin(), end())`, it is safe
|
||||
// to assume that inserting N elements will not cause a rehash.
|
||||
//
|
||||
// size_type erase(const key_type& key):
|
||||
//
|
||||
// Erases the element with the matching key, if it exists, returning the
|
||||
// number of elements erased (0 or 1).
|
||||
using Base::erase;
|
||||
|
||||
// flat_hash_map::insert()
|
||||
//
|
||||
// Inserts an element of the specified value into the `flat_hash_map`,
|
||||
// returning an iterator pointing to the newly inserted element, provided that
|
||||
// an element with the given key does not already exist. If rehashing occurs
|
||||
// due to the insertion, all iterators are invalidated. Overloads are listed
|
||||
// below.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(const init_type& value):
|
||||
//
|
||||
// Inserts a value into the `flat_hash_map`. Returns a pair consisting of an
|
||||
// iterator to the inserted element (or to the element that prevented the
|
||||
// insertion) and a bool denoting whether the insertion took place.
|
||||
//
|
||||
// std::pair<iterator,bool> insert(T&& value):
|
||||
// std::pair<iterator,bool> insert(init_type&& value):
|
||||
//
|
||||
// Inserts a moveable value into the `flat_hash_map`. Returns a pair
|
||||
// consisting of an iterator to the inserted element (or to the element that
|
||||
// prevented the insertion) and a bool denoting whether the insertion took
|
||||
// place.
|
||||
//
|
||||
// iterator insert(const_iterator hint, const init_type& value):
|
||||
// iterator insert(const_iterator hint, T&& value):
|
||||
// iterator insert(const_iterator hint, init_type&& value);
|
||||
//
|
||||
// Inserts a value, using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search. Returns an iterator to the
|
||||
// inserted element, or to the existing element that prevented the
|
||||
// insertion.
|
||||
//
|
||||
// void insert(InputIterator first, InputIterator last):
|
||||
//
|
||||
// Inserts a range of values [`first`, `last`).
|
||||
//
|
||||
// NOTE: Although the STL does not specify which element may be inserted if
|
||||
// multiple keys compare equivalently, for `flat_hash_map` we guarantee the
|
||||
// first match is inserted.
|
||||
//
|
||||
// void insert(std::initializer_list<init_type> ilist):
|
||||
//
|
||||
// Inserts the elements within the initializer list `ilist`.
|
||||
//
|
||||
// NOTE: Although the STL does not specify which element may be inserted if
|
||||
// multiple keys compare equivalently within the initializer list, for
|
||||
// `flat_hash_map` we guarantee the first match is inserted.
|
||||
using Base::insert;
|
||||
|
||||
// flat_hash_map::insert_or_assign()
|
||||
//
|
||||
// Inserts an element of the specified value into the `flat_hash_map` provided
|
||||
// that a value with the given key does not already exist, or replaces it with
|
||||
// the element value if a key for that value already exists, returning an
|
||||
// iterator pointing to the newly inserted element. If rehashing occurs due
|
||||
// to the insertion, all existing iterators are invalidated. Overloads are
|
||||
// listed below.
|
||||
//
|
||||
// pair<iterator, bool> insert_or_assign(const init_type& k, T&& obj):
|
||||
// pair<iterator, bool> insert_or_assign(init_type&& k, T&& obj):
|
||||
//
|
||||
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||
// `flat_hash_map`.
|
||||
//
|
||||
// iterator insert_or_assign(const_iterator hint,
|
||||
// const init_type& k, T&& obj):
|
||||
// iterator insert_or_assign(const_iterator hint, init_type&& k, T&& obj):
|
||||
//
|
||||
// Inserts/Assigns (or moves) the element of the specified key into the
|
||||
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search.
|
||||
using Base::insert_or_assign;
|
||||
|
||||
// flat_hash_map::emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `flat_hash_map`, provided that no element with the given key
|
||||
// already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||
// copyable or moveable.
|
||||
//
|
||||
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||
using Base::emplace;
|
||||
|
||||
// flat_hash_map::emplace_hint()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `flat_hash_map`, using the position of `hint` as a non-binding
|
||||
// suggestion for where to begin the insertion search, and only inserts
|
||||
// provided that no element with the given key already exists.
|
||||
//
|
||||
// The element may be constructed even if there already is an element with the
|
||||
// key in the container, in which case the newly constructed element will be
|
||||
// destroyed immediately. Prefer `try_emplace()` unless your key is not
|
||||
// copyable or moveable.
|
||||
//
|
||||
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||
using Base::emplace_hint;
|
||||
|
||||
// flat_hash_map::try_emplace()
|
||||
//
|
||||
// Inserts an element of the specified value by constructing it in-place
|
||||
// within the `flat_hash_map`, provided that no element with the given key
|
||||
// already exists. Unlike `emplace()`, if an element with the given key
|
||||
// already exists, we guarantee that no element is constructed.
|
||||
//
|
||||
// If rehashing occurs due to the insertion, all iterators are invalidated.
|
||||
// Overloads are listed below.
|
||||
//
|
||||
// pair<iterator, bool> try_emplace(const key_type& k, Args&&... args):
|
||||
// pair<iterator, bool> try_emplace(key_type&& k, Args&&... args):
|
||||
//
|
||||
// Inserts (via copy or move) the element of the specified key into the
|
||||
// `flat_hash_map`.
|
||||
//
|
||||
// iterator try_emplace(const_iterator hint,
|
||||
// const key_type& k, Args&&... args):
|
||||
// iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args):
|
||||
//
|
||||
// Inserts (via copy or move) the element of the specified key into the
|
||||
// `flat_hash_map` using the position of `hint` as a non-binding suggestion
|
||||
// for where to begin the insertion search.
|
||||
//
|
||||
// All `try_emplace()` overloads make the same guarantees regarding rvalue
|
||||
// arguments as `std::unordered_map::try_emplace()`, namely that these
|
||||
// functions will not move from rvalue arguments if insertions do not happen.
|
||||
using Base::try_emplace;
|
||||
|
||||
// flat_hash_map::extract()
|
||||
//
|
||||
// Extracts the indicated element, erasing it in the process, and returns it
|
||||
// as a C++17-compatible node handle. Overloads are listed below.
|
||||
//
|
||||
// node_type extract(const_iterator position):
|
||||
//
|
||||
// Extracts the key,value pair of the element at the indicated position and
|
||||
// returns a node handle owning that extracted data.
|
||||
//
|
||||
// node_type extract(const key_type& x):
|
||||
//
|
||||
// Extracts the key,value pair of the element with a key matching the passed
|
||||
// key value and returns a node handle owning that extracted data. If the
|
||||
// `flat_hash_map` does not contain an element with a matching key, this
|
||||
// function returns an empty node handle.
|
||||
//
|
||||
// NOTE: when compiled in an earlier version of C++ than C++17,
|
||||
// `node_type::key()` returns a const reference to the key instead of a
|
||||
// mutable reference. We cannot safely return a mutable reference without
|
||||
// std::launder (which is not available before C++17).
|
||||
using Base::extract;
|
||||
|
||||
// flat_hash_map::merge()
|
||||
//
|
||||
// Extracts elements from a given `source` flat hash map into this
|
||||
// `flat_hash_map`. If the destination `flat_hash_map` already contains an
|
||||
// element with an equivalent key, that element is not extracted.
|
||||
using Base::merge;
|
||||
|
||||
// flat_hash_map::swap(flat_hash_map& other)
|
||||
//
|
||||
// Exchanges the contents of this `flat_hash_map` with those of the `other`
|
||||
// flat hash map, avoiding invocation of any move, copy, or swap operations on
|
||||
// individual elements.
|
||||
//
|
||||
// All iterators and references on the `flat_hash_map` remain valid, excepting
|
||||
// for the past-the-end iterator, which is invalidated.
|
||||
//
|
||||
// `swap()` requires that the flat hash map's hashing and key equivalence
|
||||
// functions be Swappable, and are exchanged using unqualified calls to
|
||||
// non-member `swap()`. If the map's allocator has
|
||||
// `std::allocator_traits<allocator_type>::propagate_on_container_swap::value`
|
||||
// set to `true`, the allocators are also exchanged using an unqualified call
|
||||
// to non-member `swap()`; otherwise, the allocators are not swapped.
|
||||
using Base::swap;
|
||||
|
||||
// flat_hash_map::rehash(count)
|
||||
//
|
||||
// Rehashes the `flat_hash_map`, setting the number of slots to be at least
|
||||
// the passed value. If the new number of slots increases the load factor more
|
||||
// than the current maximum load factor
|
||||
// (`count` < `size()` / `max_load_factor()`), then the new number of slots
|
||||
// will be at least `size()` / `max_load_factor()`.
|
||||
//
|
||||
// To force a rehash, pass rehash(0).
|
||||
//
|
||||
// NOTE: unlike behavior in `std::unordered_map`, references are also
|
||||
// invalidated upon a `rehash()`.
|
||||
using Base::rehash;
|
||||
|
||||
// flat_hash_map::reserve(count)
|
||||
//
|
||||
// Sets the number of slots in the `flat_hash_map` to the number needed to
|
||||
// accommodate at least `count` total elements without exceeding the current
|
||||
// maximum load factor, and may rehash the container if needed.
|
||||
using Base::reserve;
|
||||
|
||||
// flat_hash_map::at()
|
||||
//
|
||||
// Returns a reference to the mapped value of the element with key equivalent
|
||||
// to the passed key.
|
||||
using Base::at;
|
||||
|
||||
// flat_hash_map::contains()
|
||||
//
|
||||
// Determines whether an element with a key comparing equal to the given `key`
|
||||
// exists within the `flat_hash_map`, returning `true` if so or `false`
|
||||
// otherwise.
|
||||
using Base::contains;
|
||||
|
||||
// flat_hash_map::count(const Key& key) const
|
||||
//
|
||||
// Returns the number of elements with a key comparing equal to the given
|
||||
// `key` within the `flat_hash_map`. note that this function will return
|
||||
// either `1` or `0` since duplicate keys are not allowed within a
|
||||
// `flat_hash_map`.
|
||||
using Base::count;
|
||||
|
||||
// flat_hash_map::equal_range()
|
||||
//
|
||||
// Returns a closed range [first, last], defined by a `std::pair` of two
|
||||
// iterators, containing all elements with the passed key in the
|
||||
// `flat_hash_map`.
|
||||
using Base::equal_range;
|
||||
|
||||
// flat_hash_map::find()
|
||||
//
|
||||
// Finds an element with the passed `key` within the `flat_hash_map`.
|
||||
using Base::find;
|
||||
|
||||
// flat_hash_map::operator[]()
|
||||
//
|
||||
// Returns a reference to the value mapped to the passed key within the
|
||||
// `flat_hash_map`, performing an `insert()` if the key does not already
|
||||
// exist.
|
||||
//
|
||||
// If an insertion occurs and results in a rehashing of the container, all
|
||||
// iterators are invalidated. Otherwise iterators are not affected and
|
||||
// references are not invalidated. Overloads are listed below.
|
||||
//
|
||||
// T& operator[](const Key& key):
|
||||
//
|
||||
// Inserts an init_type object constructed in-place if the element with the
|
||||
// given key does not exist.
|
||||
//
|
||||
// T& operator[](Key&& key):
|
||||
//
|
||||
// Inserts an init_type object constructed in-place provided that an element
|
||||
// with the given key does not exist.
|
||||
using Base::operator[];
|
||||
|
||||
// flat_hash_map::bucket_count()
|
||||
//
|
||||
// Returns the number of "buckets" within the `flat_hash_map`. Note that
|
||||
// because a flat hash map contains all elements within its internal storage,
|
||||
// this value simply equals the current capacity of the `flat_hash_map`.
|
||||
using Base::bucket_count;
|
||||
|
||||
// flat_hash_map::load_factor()
|
||||
//
|
||||
// Returns the current load factor of the `flat_hash_map` (the average number
|
||||
// of slots occupied with a value within the hash map).
|
||||
using Base::load_factor;
|
||||
|
||||
// flat_hash_map::max_load_factor()
|
||||
//
|
||||
// Manages the maximum load factor of the `flat_hash_map`. Overloads are
|
||||
// listed below.
|
||||
//
|
||||
// float flat_hash_map::max_load_factor()
|
||||
//
|
||||
// Returns the current maximum load factor of the `flat_hash_map`.
|
||||
//
|
||||
// void flat_hash_map::max_load_factor(float ml)
|
||||
//
|
||||
// Sets the maximum load factor of the `flat_hash_map` to the passed value.
|
||||
//
|
||||
// NOTE: This overload is provided only for API compatibility with the STL;
|
||||
// `flat_hash_map` will ignore any set load factor and manage its rehashing
|
||||
// internally as an implementation detail.
|
||||
using Base::max_load_factor;
|
||||
|
||||
// flat_hash_map::get_allocator()
|
||||
//
|
||||
// Returns the allocator function associated with this `flat_hash_map`.
|
||||
using Base::get_allocator;
|
||||
|
||||
// flat_hash_map::hash_function()
|
||||
//
|
||||
// Returns the hashing function used to hash the keys within this
|
||||
// `flat_hash_map`.
|
||||
using Base::hash_function;
|
||||
|
||||
// flat_hash_map::key_eq()
|
||||
//
|
||||
// Returns the function used for comparing keys equality.
|
||||
using Base::key_eq;
|
||||
};
|
||||
|
||||
// erase_if(flat_hash_map<>, Pred)
|
||||
//
|
||||
// Erases all elements that satisfy the predicate `pred` from the container `c`.
|
||||
// Returns the number of erased elements.
|
||||
template <typename K, typename V, typename H, typename E, typename A,
|
||||
typename Predicate>
|
||||
typename flat_hash_map<K, V, H, E, A>::size_type erase_if(
|
||||
flat_hash_map<K, V, H, E, A>& c, Predicate pred) {
|
||||
return container_internal::EraseIf(pred, &c);
|
||||
}
|
||||
|
||||
namespace container_internal {
|
||||
|
||||
// c_for_each_fast(flat_hash_map<>, Function)
|
||||
//
|
||||
// Container-based version of the <algorithm> `std::for_each()` function to
|
||||
// apply a function to a container's elements.
|
||||
// There is no guarantees on the order of the function calls.
|
||||
// Erasure and/or insertion of elements in the function is not allowed.
|
||||
template <typename K, typename V, typename H, typename E, typename A,
|
||||
typename Function>
|
||||
decay_t<Function> c_for_each_fast(const flat_hash_map<K, V, H, E, A>& c,
|
||||
Function&& f) {
|
||||
container_internal::ForEach(f, &c);
|
||||
return f;
|
||||
}
|
||||
template <typename K, typename V, typename H, typename E, typename A,
|
||||
typename Function>
|
||||
decay_t<Function> c_for_each_fast(flat_hash_map<K, V, H, E, A>& c,
|
||||
Function&& f) {
|
||||
container_internal::ForEach(f, &c);
|
||||
return f;
|
||||
}
|
||||
template <typename K, typename V, typename H, typename E, typename A,
|
||||
typename Function>
|
||||
decay_t<Function> c_for_each_fast(flat_hash_map<K, V, H, E, A>&& c,
|
||||
Function&& f) {
|
||||
container_internal::ForEach(f, &c);
|
||||
return f;
|
||||
}
|
||||
|
||||
} // namespace container_internal
|
||||
|
||||
namespace container_internal {
|
||||
|
||||
template <class K, class V>
|
||||
struct FlatHashMapPolicy {
|
||||
using slot_policy = container_internal::map_slot_policy<K, V>;
|
||||
using slot_type = typename slot_policy::slot_type;
|
||||
using key_type = K;
|
||||
using mapped_type = V;
|
||||
using init_type = std::pair</*non const*/ key_type, mapped_type>;
|
||||
|
||||
template <class Allocator, class... Args>
|
||||
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
|
||||
slot_policy::construct(alloc, slot, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Returns std::true_type in case destroy is trivial.
|
||||
template <class Allocator>
|
||||
static auto destroy(Allocator* alloc, slot_type* slot) {
|
||||
return slot_policy::destroy(alloc, slot);
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
static auto transfer(Allocator* alloc, slot_type* new_slot,
|
||||
slot_type* old_slot) {
|
||||
return slot_policy::transfer(alloc, new_slot, old_slot);
|
||||
}
|
||||
|
||||
template <class F, class... Args>
|
||||
static decltype(absl::container_internal::DecomposePair(
|
||||
std::declval<F>(), std::declval<Args>()...))
|
||||
apply(F&& f, Args&&... args) {
|
||||
return absl::container_internal::DecomposePair(std::forward<F>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Hash>
|
||||
static constexpr HashSlotFn get_hash_slot_fn() {
|
||||
return memory_internal::IsLayoutCompatible<K, V>::value
|
||||
? &TypeErasedApplyToSlotFn<Hash, K>
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
static size_t space_used(const slot_type*) { return 0; }
|
||||
|
||||
static std::pair<const K, V>& element(slot_type* slot) { return slot->value; }
|
||||
|
||||
static V& value(std::pair<const K, V>* kv) { return kv->second; }
|
||||
static const V& value(const std::pair<const K, V>* kv) { return kv->second; }
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
|
||||
namespace container_algorithm_internal {
|
||||
|
||||
// Specialization of trait in absl/algorithm/container.h
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
struct IsUnorderedContainer<
|
||||
absl::flat_hash_map<Key, T, Hash, KeyEqual, Allocator>> : std::true_type {};
|
||||
|
||||
} // namespace container_algorithm_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_FLAT_HASH_MAP_H_
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2024 The Abseil Authors
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
|
||||
#define ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/container/internal/hash_function_defaults.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// DefaultHashContainerHash is a convenience alias for the functor that is used
|
||||
// by default by Abseil hash-based (unordered) containers for hashing when
|
||||
// `Hash` type argument is not explicitly specified.
|
||||
//
|
||||
// This type alias can be used by generic code that wants to provide more
|
||||
// flexibility for defining underlying containers.
|
||||
template <typename T>
|
||||
using DefaultHashContainerHash = absl::container_internal::hash_default_hash<T>;
|
||||
|
||||
// DefaultHashContainerEq is a convenience alias for the functor that is used by
|
||||
// default by Abseil hash-based (unordered) containers for equality check when
|
||||
// `Eq` type argument is not explicitly specified.
|
||||
//
|
||||
// This type alias can be used by generic code that wants to provide more
|
||||
// flexibility for defining underlying containers.
|
||||
template <typename T>
|
||||
using DefaultHashContainerEq = absl::container_internal::hash_default_eq<T>;
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_HASH_CONTAINER_DEFAULTS_H_
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,207 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_INTERNAL_COMMON_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_COMMON_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/types/optional.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
template <class, class = void>
|
||||
struct IsTransparent : std::false_type {};
|
||||
template <class T>
|
||||
struct IsTransparent<T, absl::void_t<typename T::is_transparent>>
|
||||
: std::true_type {};
|
||||
|
||||
template <bool is_transparent>
|
||||
struct KeyArg {
|
||||
// Transparent. Forward `K`.
|
||||
template <typename K, typename key_type>
|
||||
using type = K;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct KeyArg<false> {
|
||||
// Not transparent. Always use `key_type`.
|
||||
template <typename K, typename key_type>
|
||||
using type = key_type;
|
||||
};
|
||||
|
||||
// The node_handle concept from C++17.
|
||||
// We specialize node_handle for sets and maps. node_handle_base holds the
|
||||
// common API of both.
|
||||
template <typename PolicyTraits, typename Alloc>
|
||||
class node_handle_base {
|
||||
protected:
|
||||
using slot_type = typename PolicyTraits::slot_type;
|
||||
|
||||
public:
|
||||
using allocator_type = Alloc;
|
||||
|
||||
constexpr node_handle_base() = default;
|
||||
node_handle_base(node_handle_base&& other) noexcept {
|
||||
*this = std::move(other);
|
||||
}
|
||||
~node_handle_base() { destroy(); }
|
||||
node_handle_base& operator=(node_handle_base&& other) noexcept {
|
||||
destroy();
|
||||
if (!other.empty()) {
|
||||
alloc_ = other.alloc_;
|
||||
PolicyTraits::transfer(alloc(), slot(), other.slot());
|
||||
other.reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const noexcept { return !alloc_; }
|
||||
explicit operator bool() const noexcept { return !empty(); }
|
||||
allocator_type get_allocator() const { return *alloc_; }
|
||||
|
||||
protected:
|
||||
friend struct CommonAccess;
|
||||
|
||||
struct transfer_tag_t {};
|
||||
node_handle_base(transfer_tag_t, const allocator_type& a, slot_type* s)
|
||||
: alloc_(a) {
|
||||
PolicyTraits::transfer(alloc(), slot(), s);
|
||||
}
|
||||
|
||||
struct construct_tag_t {};
|
||||
template <typename... Args>
|
||||
node_handle_base(construct_tag_t, const allocator_type& a, Args&&... args)
|
||||
: alloc_(a) {
|
||||
PolicyTraits::construct(alloc(), slot(), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (!empty()) {
|
||||
PolicyTraits::destroy(alloc(), slot());
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(alloc_.has_value());
|
||||
alloc_ = absl::nullopt;
|
||||
}
|
||||
|
||||
slot_type* slot() const {
|
||||
assert(!empty());
|
||||
return reinterpret_cast<slot_type*>(std::addressof(slot_space_));
|
||||
}
|
||||
allocator_type* alloc() { return std::addressof(*alloc_); }
|
||||
|
||||
private:
|
||||
absl::optional<allocator_type> alloc_ = {};
|
||||
alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {};
|
||||
};
|
||||
|
||||
// For sets.
|
||||
template <typename Policy, typename PolicyTraits, typename Alloc,
|
||||
typename = void>
|
||||
class node_handle : public node_handle_base<PolicyTraits, Alloc> {
|
||||
using Base = node_handle_base<PolicyTraits, Alloc>;
|
||||
|
||||
public:
|
||||
using value_type = typename PolicyTraits::value_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
value_type& value() const { return PolicyTraits::element(this->slot()); }
|
||||
|
||||
private:
|
||||
friend struct CommonAccess;
|
||||
|
||||
using Base::Base;
|
||||
};
|
||||
|
||||
// For maps.
|
||||
template <typename Policy, typename PolicyTraits, typename Alloc>
|
||||
class node_handle<Policy, PolicyTraits, Alloc,
|
||||
absl::void_t<typename Policy::mapped_type>>
|
||||
: public node_handle_base<PolicyTraits, Alloc> {
|
||||
using Base = node_handle_base<PolicyTraits, Alloc>;
|
||||
using slot_type = typename PolicyTraits::slot_type;
|
||||
|
||||
public:
|
||||
using key_type = typename Policy::key_type;
|
||||
using mapped_type = typename Policy::mapped_type;
|
||||
|
||||
constexpr node_handle() {}
|
||||
|
||||
// When C++17 is available, we can use std::launder to provide mutable
|
||||
// access to the key. Otherwise, we provide const access.
|
||||
auto key() const
|
||||
-> decltype(PolicyTraits::mutable_key(std::declval<slot_type*>())) {
|
||||
return PolicyTraits::mutable_key(this->slot());
|
||||
}
|
||||
|
||||
mapped_type& mapped() const {
|
||||
return PolicyTraits::value(&PolicyTraits::element(this->slot()));
|
||||
}
|
||||
|
||||
private:
|
||||
friend struct CommonAccess;
|
||||
|
||||
using Base::Base;
|
||||
};
|
||||
|
||||
// Provide access to non-public node-handle functions.
|
||||
struct CommonAccess {
|
||||
template <typename Node>
|
||||
static auto GetSlot(const Node& node) -> decltype(node.slot()) {
|
||||
return node.slot();
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
static void Destroy(Node* node) {
|
||||
node->destroy();
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
static void Reset(Node* node) {
|
||||
node->reset();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T Transfer(Args&&... args) {
|
||||
return T(typename T::transfer_tag_t{}, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T Construct(Args&&... args) {
|
||||
return T(typename T::construct_tag_t{}, std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
// Implement the insert_return_type<> concept of C++17.
|
||||
template <class Iterator, class NodeType>
|
||||
struct InsertReturnType {
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_COMMON_H_
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
// Copyright 2022 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
// Defines how slots are initialized/destroyed/moved.
|
||||
template <class Policy, class = void>
|
||||
struct common_policy_traits {
|
||||
// The actual object stored in the container.
|
||||
using slot_type = typename Policy::slot_type;
|
||||
using reference = decltype(Policy::element(std::declval<slot_type*>()));
|
||||
using value_type = typename std::remove_reference<reference>::type;
|
||||
|
||||
// PRECONDITION: `slot` is UNINITIALIZED
|
||||
// POSTCONDITION: `slot` is INITIALIZED
|
||||
template <class Alloc, class... Args>
|
||||
static void construct(Alloc* alloc, slot_type* slot, Args&&... args) {
|
||||
Policy::construct(alloc, slot, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// PRECONDITION: `slot` is INITIALIZED
|
||||
// POSTCONDITION: `slot` is UNINITIALIZED
|
||||
// Returns std::true_type in case destroy is trivial.
|
||||
template <class Alloc>
|
||||
static auto destroy(Alloc* alloc, slot_type* slot) {
|
||||
return Policy::destroy(alloc, slot);
|
||||
}
|
||||
|
||||
// Transfers the `old_slot` to `new_slot`. Any memory allocated by the
|
||||
// allocator inside `old_slot` to `new_slot` can be transferred.
|
||||
//
|
||||
// OPTIONAL: defaults to:
|
||||
//
|
||||
// clone(new_slot, std::move(*old_slot));
|
||||
// destroy(old_slot);
|
||||
//
|
||||
// PRECONDITION: `new_slot` is UNINITIALIZED and `old_slot` is INITIALIZED
|
||||
// POSTCONDITION: `new_slot` is INITIALIZED and `old_slot` is
|
||||
// UNINITIALIZED
|
||||
template <class Alloc>
|
||||
static void transfer(Alloc* alloc, slot_type* new_slot, slot_type* old_slot) {
|
||||
transfer_impl(alloc, new_slot, old_slot, Rank2{});
|
||||
}
|
||||
|
||||
// PRECONDITION: `slot` is INITIALIZED
|
||||
// POSTCONDITION: `slot` is INITIALIZED
|
||||
// Note: we use remove_const_t so that the two overloads have different args
|
||||
// in the case of sets with explicitly const value_types.
|
||||
template <class P = Policy>
|
||||
static auto element(absl::remove_const_t<slot_type>* slot)
|
||||
-> decltype(P::element(slot)) {
|
||||
return P::element(slot);
|
||||
}
|
||||
template <class P = Policy>
|
||||
static auto element(const slot_type* slot) -> decltype(P::element(slot)) {
|
||||
return P::element(slot);
|
||||
}
|
||||
|
||||
static constexpr bool transfer_uses_memcpy() {
|
||||
return std::is_same<decltype(transfer_impl<std::allocator<char>>(
|
||||
nullptr, nullptr, nullptr, Rank2{})),
|
||||
std::true_type>::value;
|
||||
}
|
||||
|
||||
// Returns true if destroy is trivial and can be omitted.
|
||||
template <class Alloc>
|
||||
static constexpr bool destroy_is_trivial() {
|
||||
return std::is_same<decltype(destroy<Alloc>(nullptr, nullptr)),
|
||||
std::true_type>::value;
|
||||
}
|
||||
|
||||
private:
|
||||
// Use go/ranked-overloads for dispatching.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
struct Rank2 : Rank1 {};
|
||||
|
||||
// Use auto -> decltype as an enabler.
|
||||
// P::transfer returns std::true_type if transfer uses memcpy (e.g. in
|
||||
// node_slot_policy).
|
||||
template <class Alloc, class P = Policy>
|
||||
static auto transfer_impl(Alloc* alloc, slot_type* new_slot,
|
||||
slot_type* old_slot,
|
||||
Rank2) -> decltype(P::transfer(alloc, new_slot,
|
||||
old_slot)) {
|
||||
return P::transfer(alloc, new_slot, old_slot);
|
||||
}
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
// This overload returns true_type for the trait below.
|
||||
// The conditional_t is to make the enabler type dependent.
|
||||
template <class Alloc,
|
||||
typename = std::enable_if_t<absl::is_trivially_relocatable<
|
||||
std::conditional_t<false, Alloc, value_type>>::value>>
|
||||
static std::true_type transfer_impl(Alloc*, slot_type* new_slot,
|
||||
slot_type* old_slot, Rank1) {
|
||||
// TODO(b/247130232): remove casts after fixing warnings.
|
||||
// TODO(b/251814870): remove casts after fixing warnings.
|
||||
std::memcpy(
|
||||
static_cast<void*>(std::launder(
|
||||
const_cast<std::remove_const_t<value_type>*>(&element(new_slot)))),
|
||||
static_cast<const void*>(&element(old_slot)), sizeof(value_type));
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Alloc>
|
||||
static void transfer_impl(Alloc* alloc, slot_type* new_slot,
|
||||
slot_type* old_slot, Rank0) {
|
||||
construct(alloc, new_slot, std::move(element(old_slot)));
|
||||
destroy(alloc, old_slot);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_COMMON_POLICY_TRAITS_H_
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Helper class to perform the Empty Base Optimization.
|
||||
// Ts can contain classes and non-classes, empty or not. For the ones that
|
||||
// are empty classes, we perform the optimization. If all types in Ts are empty
|
||||
// classes, then CompressedTuple<Ts...> is itself an empty class.
|
||||
//
|
||||
// To access the members, use member get<N>() function.
|
||||
//
|
||||
// Eg:
|
||||
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
|
||||
// t3);
|
||||
// assert(value.get<0>() == 7);
|
||||
// T1& t1 = value.get<1>();
|
||||
// const T2& t2 = value.get<2>();
|
||||
// ...
|
||||
//
|
||||
// https://en.cppreference.com/w/cpp/language/ebo
|
||||
|
||||
#ifndef ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|
||||
|
||||
#include <initializer_list>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__NVCC__)
|
||||
// We need to mark these classes with this declspec to ensure that
|
||||
// CompressedTuple happens.
|
||||
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC __declspec(empty_bases)
|
||||
#else
|
||||
#define ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
template <typename... Ts>
|
||||
class CompressedTuple;
|
||||
|
||||
namespace internal_compressed_tuple {
|
||||
|
||||
template <typename D, size_t I>
|
||||
struct Elem;
|
||||
template <typename... B, size_t I>
|
||||
struct Elem<CompressedTuple<B...>, I>
|
||||
: std::tuple_element<I, std::tuple<B...>> {};
|
||||
template <typename D, size_t I>
|
||||
using ElemT = typename Elem<D, I>::type;
|
||||
|
||||
// We can't use EBCO on other CompressedTuples because that would mean that we
|
||||
// derive from multiple Storage<> instantiations with the same I parameter,
|
||||
// and potentially from multiple identical Storage<> instantiations. So anytime
|
||||
// we use type inheritance rather than encapsulation, we mark
|
||||
// CompressedTupleImpl, to make this easy to detect.
|
||||
struct uses_inheritance {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool ShouldUseBase() {
|
||||
return std::is_class<T>::value && std::is_empty<T>::value &&
|
||||
!std::is_final<T>::value &&
|
||||
!std::is_base_of<uses_inheritance, T>::value;
|
||||
}
|
||||
|
||||
// The storage class provides two specializations:
|
||||
// - For empty classes, it stores T as a base class.
|
||||
// - For everything else, it stores T as a member.
|
||||
template <typename T, size_t I, bool UseBase = ShouldUseBase<T>()>
|
||||
struct Storage {
|
||||
T value;
|
||||
constexpr Storage() = default;
|
||||
template <typename V>
|
||||
explicit constexpr Storage(absl::in_place_t, V&& v)
|
||||
: value(std::forward<V>(v)) {}
|
||||
constexpr const T& get() const& { return value; }
|
||||
constexpr T& get() & { return value; }
|
||||
constexpr const T&& get() const&& { return std::move(*this).value; }
|
||||
constexpr T&& get() && { return std::move(*this).value; }
|
||||
};
|
||||
|
||||
template <typename T, size_t I>
|
||||
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<T, I, true> : T {
|
||||
constexpr Storage() = default;
|
||||
|
||||
template <typename V>
|
||||
explicit constexpr Storage(absl::in_place_t, V&& v) : T(std::forward<V>(v)) {}
|
||||
|
||||
constexpr const T& get() const& { return *this; }
|
||||
constexpr T& get() & { return *this; }
|
||||
constexpr const T&& get() const&& { return std::move(*this); }
|
||||
constexpr T&& get() && { return std::move(*this); }
|
||||
};
|
||||
|
||||
template <typename D, typename I, bool ShouldAnyUseBase>
|
||||
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl;
|
||||
|
||||
template <typename... Ts, size_t... I, bool ShouldAnyUseBase>
|
||||
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
|
||||
CompressedTuple<Ts...>, absl::index_sequence<I...>, ShouldAnyUseBase>
|
||||
// We use the dummy identity function through std::integral_constant to
|
||||
// convince MSVC of accepting and expanding I in that context. Without it
|
||||
// you would get:
|
||||
// error C3548: 'I': parameter pack cannot be used in this context
|
||||
: uses_inheritance,
|
||||
Storage<Ts, std::integral_constant<size_t, I>::value>... {
|
||||
constexpr CompressedTupleImpl() = default;
|
||||
template <typename... Vs>
|
||||
explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
|
||||
: Storage<Ts, I>(absl::in_place, std::forward<Vs>(args))... {}
|
||||
friend CompressedTuple<Ts...>;
|
||||
};
|
||||
|
||||
template <typename... Ts, size_t... I>
|
||||
struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTupleImpl<
|
||||
CompressedTuple<Ts...>, absl::index_sequence<I...>, false>
|
||||
// We use the dummy identity function as above...
|
||||
: Storage<Ts, std::integral_constant<size_t, I>::value, false>... {
|
||||
constexpr CompressedTupleImpl() = default;
|
||||
template <typename... Vs>
|
||||
explicit constexpr CompressedTupleImpl(absl::in_place_t, Vs&&... args)
|
||||
: Storage<Ts, I, false>(absl::in_place, std::forward<Vs>(args))... {}
|
||||
friend CompressedTuple<Ts...>;
|
||||
};
|
||||
|
||||
std::false_type Or(std::initializer_list<std::false_type>);
|
||||
std::true_type Or(std::initializer_list<bool>);
|
||||
|
||||
// MSVC requires this to be done separately rather than within the declaration
|
||||
// of CompressedTuple below.
|
||||
template <typename... Ts>
|
||||
constexpr bool ShouldAnyUseBase() {
|
||||
return decltype(
|
||||
Or({std::integral_constant<bool, ShouldUseBase<Ts>()>()...})){};
|
||||
}
|
||||
|
||||
template <typename T, typename V>
|
||||
using TupleElementMoveConstructible =
|
||||
typename std::conditional<std::is_reference<T>::value,
|
||||
std::is_convertible<V, T>,
|
||||
std::is_constructible<T, V&&>>::type;
|
||||
|
||||
template <bool SizeMatches, class T, class... Vs>
|
||||
struct TupleMoveConstructible : std::false_type {};
|
||||
|
||||
template <class... Ts, class... Vs>
|
||||
struct TupleMoveConstructible<true, CompressedTuple<Ts...>, Vs...>
|
||||
: std::integral_constant<
|
||||
bool, absl::conjunction<
|
||||
TupleElementMoveConstructible<Ts, Vs&&>...>::value> {};
|
||||
|
||||
template <typename T>
|
||||
struct compressed_tuple_size;
|
||||
|
||||
template <typename... Es>
|
||||
struct compressed_tuple_size<CompressedTuple<Es...>>
|
||||
: public std::integral_constant<std::size_t, sizeof...(Es)> {};
|
||||
|
||||
template <class T, class... Vs>
|
||||
struct TupleItemsMoveConstructible
|
||||
: std::integral_constant<
|
||||
bool, TupleMoveConstructible<compressed_tuple_size<T>::value ==
|
||||
sizeof...(Vs),
|
||||
T, Vs...>::value> {};
|
||||
|
||||
} // namespace internal_compressed_tuple
|
||||
|
||||
// Helper class to perform the Empty Base Class Optimization.
|
||||
// Ts can contain classes and non-classes, empty or not. For the ones that
|
||||
// are empty classes, we perform the CompressedTuple. If all types in Ts are
|
||||
// empty classes, then CompressedTuple<Ts...> is itself an empty class. (This
|
||||
// does not apply when one or more of those empty classes is itself an empty
|
||||
// CompressedTuple.)
|
||||
//
|
||||
// To access the members, use member .get<N>() function.
|
||||
//
|
||||
// Eg:
|
||||
// absl::container_internal::CompressedTuple<int, T1, T2, T3> value(7, t1, t2,
|
||||
// t3);
|
||||
// assert(value.get<0>() == 7);
|
||||
// T1& t1 = value.get<1>();
|
||||
// const T2& t2 = value.get<2>();
|
||||
// ...
|
||||
//
|
||||
// https://en.cppreference.com/w/cpp/language/ebo
|
||||
template <typename... Ts>
|
||||
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
|
||||
: private internal_compressed_tuple::CompressedTupleImpl<
|
||||
CompressedTuple<Ts...>, absl::index_sequence_for<Ts...>,
|
||||
internal_compressed_tuple::ShouldAnyUseBase<Ts...>()> {
|
||||
private:
|
||||
template <int I>
|
||||
using ElemT = internal_compressed_tuple::ElemT<CompressedTuple, I>;
|
||||
|
||||
template <int I>
|
||||
using StorageT = internal_compressed_tuple::Storage<ElemT<I>, I>;
|
||||
|
||||
public:
|
||||
// There seems to be a bug in MSVC dealing in which using '=default' here will
|
||||
// cause the compiler to ignore the body of other constructors. The work-
|
||||
// around is to explicitly implement the default constructor.
|
||||
#if defined(_MSC_VER)
|
||||
constexpr CompressedTuple() : CompressedTuple::CompressedTupleImpl() {}
|
||||
#else
|
||||
constexpr CompressedTuple() = default;
|
||||
#endif
|
||||
explicit constexpr CompressedTuple(const Ts&... base)
|
||||
: CompressedTuple::CompressedTupleImpl(absl::in_place, base...) {}
|
||||
|
||||
template <typename First, typename... Vs,
|
||||
absl::enable_if_t<
|
||||
absl::conjunction<
|
||||
// Ensure we are not hiding default copy/move constructors.
|
||||
absl::negation<std::is_same<void(CompressedTuple),
|
||||
void(absl::decay_t<First>)>>,
|
||||
internal_compressed_tuple::TupleItemsMoveConstructible<
|
||||
CompressedTuple<Ts...>, First, Vs...>>::value,
|
||||
bool> = true>
|
||||
explicit constexpr CompressedTuple(First&& first, Vs&&... base)
|
||||
: CompressedTuple::CompressedTupleImpl(absl::in_place,
|
||||
std::forward<First>(first),
|
||||
std::forward<Vs>(base)...) {}
|
||||
|
||||
template <int I>
|
||||
constexpr ElemT<I>& get() & {
|
||||
return StorageT<I>::get();
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr const ElemT<I>& get() const& {
|
||||
return StorageT<I>::get();
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr ElemT<I>&& get() && {
|
||||
return std::move(*this).StorageT<I>::get();
|
||||
}
|
||||
|
||||
template <int I>
|
||||
constexpr const ElemT<I>&& get() const&& {
|
||||
return std::move(*this).StorageT<I>::get();
|
||||
}
|
||||
};
|
||||
|
||||
// Explicit specialization for a zero-element tuple
|
||||
// (needed to avoid ambiguous overloads for the default constructor).
|
||||
template <>
|
||||
class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple<> {};
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#undef ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_COMPRESSED_TUPLE_H_
|
||||
+491
@@ -0,0 +1,491 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/memory/memory.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#endif
|
||||
|
||||
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||
#include <sanitizer/msan_interface.h>
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
template <size_t Alignment>
|
||||
struct alignas(Alignment) AlignedType {};
|
||||
|
||||
// Allocates at least n bytes aligned to the specified alignment.
|
||||
// Alignment must be a power of 2. It must be positive.
|
||||
//
|
||||
// Note that many allocators don't honor alignment requirements above certain
|
||||
// threshold (usually either alignof(std::max_align_t) or alignof(void*)).
|
||||
// Allocate() doesn't apply alignment corrections. If the underlying allocator
|
||||
// returns insufficiently alignment pointer, that's what you are going to get.
|
||||
template <size_t Alignment, class Alloc>
|
||||
void* Allocate(Alloc* alloc, size_t n) {
|
||||
static_assert(Alignment > 0, "");
|
||||
assert(n && "n must be positive");
|
||||
using M = AlignedType<Alignment>;
|
||||
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
|
||||
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
|
||||
// On macOS, "mem_alloc" is a #define with one argument defined in
|
||||
// rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
|
||||
// with the "foo(bar)" syntax.
|
||||
A my_mem_alloc(*alloc);
|
||||
void* p = AT::allocate(my_mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
|
||||
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
|
||||
"allocator does not respect alignment");
|
||||
return p;
|
||||
}
|
||||
|
||||
// Returns true if the destruction of the value with given Allocator will be
|
||||
// trivial.
|
||||
template <class Allocator, class ValueType>
|
||||
constexpr auto IsDestructionTrivial() {
|
||||
constexpr bool result =
|
||||
std::is_trivially_destructible<ValueType>::value &&
|
||||
std::is_same<typename absl::allocator_traits<
|
||||
Allocator>::template rebind_alloc<char>,
|
||||
std::allocator<char>>::value;
|
||||
return std::integral_constant<bool, result>();
|
||||
}
|
||||
|
||||
// The pointer must have been previously obtained by calling
|
||||
// Allocate<Alignment>(alloc, n).
|
||||
template <size_t Alignment, class Alloc>
|
||||
void Deallocate(Alloc* alloc, void* p, size_t n) {
|
||||
static_assert(Alignment > 0, "");
|
||||
assert(n && "n must be positive");
|
||||
using M = AlignedType<Alignment>;
|
||||
using A = typename absl::allocator_traits<Alloc>::template rebind_alloc<M>;
|
||||
using AT = typename absl::allocator_traits<Alloc>::template rebind_traits<M>;
|
||||
// On macOS, "mem_alloc" is a #define with one argument defined in
|
||||
// rpc/types.h, so we can't name the variable "mem_alloc" and initialize it
|
||||
// with the "foo(bar)" syntax.
|
||||
A my_mem_alloc(*alloc);
|
||||
AT::deallocate(my_mem_alloc, static_cast<M*>(p),
|
||||
(n + sizeof(M) - 1) / sizeof(M));
|
||||
}
|
||||
|
||||
namespace memory_internal {
|
||||
|
||||
// Constructs T into uninitialized storage pointed by `ptr` using the args
|
||||
// specified in the tuple.
|
||||
template <class Alloc, class T, class Tuple, size_t... I>
|
||||
void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
|
||||
absl::index_sequence<I...>) {
|
||||
absl::allocator_traits<Alloc>::construct(
|
||||
*alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
template <class T, class F>
|
||||
struct WithConstructedImplF {
|
||||
template <class... Args>
|
||||
decltype(std::declval<F>()(std::declval<T>())) operator()(
|
||||
Args&&... args) const {
|
||||
return std::forward<F>(f)(T(std::forward<Args>(args)...));
|
||||
}
|
||||
F&& f;
|
||||
};
|
||||
|
||||
template <class T, class Tuple, size_t... Is, class F>
|
||||
decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
|
||||
Tuple&& t, absl::index_sequence<Is...>, F&& f) {
|
||||
return WithConstructedImplF<T, F>{std::forward<F>(f)}(
|
||||
std::get<Is>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
|
||||
template <class T, size_t... Is>
|
||||
auto TupleRefImpl(T&& t, absl::index_sequence<Is...>)
|
||||
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
|
||||
return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
|
||||
}
|
||||
|
||||
// Returns a tuple of references to the elements of the input tuple. T must be a
|
||||
// tuple.
|
||||
template <class T>
|
||||
auto TupleRef(T&& t) -> decltype(TupleRefImpl(
|
||||
std::forward<T>(t),
|
||||
absl::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<T>::type>::value>())) {
|
||||
return TupleRefImpl(
|
||||
std::forward<T>(t),
|
||||
absl::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<T>::type>::value>());
|
||||
}
|
||||
|
||||
template <class F, class K, class V>
|
||||
decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
|
||||
std::declval<std::tuple<K>>(), std::declval<V>()))
|
||||
DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
|
||||
const auto& key = std::get<0>(p.first);
|
||||
return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
|
||||
std::move(p.second));
|
||||
}
|
||||
|
||||
} // namespace memory_internal
|
||||
|
||||
// Constructs T into uninitialized storage pointed by `ptr` using the args
|
||||
// specified in the tuple.
|
||||
template <class Alloc, class T, class Tuple>
|
||||
void ConstructFromTuple(Alloc* alloc, T* ptr, Tuple&& t) {
|
||||
memory_internal::ConstructFromTupleImpl(
|
||||
alloc, ptr, std::forward<Tuple>(t),
|
||||
absl::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<Tuple>::type>::value>());
|
||||
}
|
||||
|
||||
// Constructs T using the args specified in the tuple and calls F with the
|
||||
// constructed value.
|
||||
template <class T, class Tuple, class F>
|
||||
decltype(std::declval<F>()(std::declval<T>())) WithConstructed(Tuple&& t,
|
||||
F&& f) {
|
||||
return memory_internal::WithConstructedImpl<T>(
|
||||
std::forward<Tuple>(t),
|
||||
absl::make_index_sequence<
|
||||
std::tuple_size<typename std::decay<Tuple>::type>::value>(),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
// Given arguments of an std::pair's constructor, PairArgs() returns a pair of
|
||||
// tuples with references to the passed arguments. The tuples contain
|
||||
// constructor arguments for the first and the second elements of the pair.
|
||||
//
|
||||
// The following two snippets are equivalent.
|
||||
//
|
||||
// 1. std::pair<F, S> p(args...);
|
||||
//
|
||||
// 2. auto a = PairArgs(args...);
|
||||
// std::pair<F, S> p(std::piecewise_construct,
|
||||
// std::move(a.first), std::move(a.second));
|
||||
inline std::pair<std::tuple<>, std::tuple<>> PairArgs() { return {}; }
|
||||
template <class F, class S>
|
||||
std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(F&& f, S&& s) {
|
||||
return {std::piecewise_construct, std::forward_as_tuple(std::forward<F>(f)),
|
||||
std::forward_as_tuple(std::forward<S>(s))};
|
||||
}
|
||||
template <class F, class S>
|
||||
std::pair<std::tuple<const F&>, std::tuple<const S&>> PairArgs(
|
||||
const std::pair<F, S>& p) {
|
||||
return PairArgs(p.first, p.second);
|
||||
}
|
||||
template <class F, class S>
|
||||
std::pair<std::tuple<F&&>, std::tuple<S&&>> PairArgs(std::pair<F, S>&& p) {
|
||||
return PairArgs(std::forward<F>(p.first), std::forward<S>(p.second));
|
||||
}
|
||||
template <class F, class S>
|
||||
auto PairArgs(std::piecewise_construct_t, F&& f, S&& s)
|
||||
-> decltype(std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
|
||||
memory_internal::TupleRef(std::forward<S>(s)))) {
|
||||
return std::make_pair(memory_internal::TupleRef(std::forward<F>(f)),
|
||||
memory_internal::TupleRef(std::forward<S>(s)));
|
||||
}
|
||||
|
||||
// A helper function for implementing apply() in map policies.
|
||||
template <class F, class... Args>
|
||||
auto DecomposePair(F&& f, Args&&... args)
|
||||
-> decltype(memory_internal::DecomposePairImpl(
|
||||
std::forward<F>(f), PairArgs(std::forward<Args>(args)...))) {
|
||||
return memory_internal::DecomposePairImpl(
|
||||
std::forward<F>(f), PairArgs(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// A helper function for implementing apply() in set policies.
|
||||
template <class F, class Arg>
|
||||
decltype(std::declval<F>()(std::declval<const Arg&>(), std::declval<Arg>()))
|
||||
DecomposeValue(F&& f, Arg&& arg) {
|
||||
const auto& key = arg;
|
||||
return std::forward<F>(f)(key, std::forward<Arg>(arg));
|
||||
}
|
||||
|
||||
// Helper functions for asan and msan.
|
||||
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
ASAN_POISON_MEMORY_REGION(m, s);
|
||||
#endif
|
||||
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||
__msan_poison(m, s);
|
||||
#endif
|
||||
(void)m;
|
||||
(void)s;
|
||||
}
|
||||
|
||||
inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
|
||||
#ifdef ABSL_HAVE_ADDRESS_SANITIZER
|
||||
ASAN_UNPOISON_MEMORY_REGION(m, s);
|
||||
#endif
|
||||
#ifdef ABSL_HAVE_MEMORY_SANITIZER
|
||||
__msan_unpoison(m, s);
|
||||
#endif
|
||||
(void)m;
|
||||
(void)s;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SanitizerPoisonObject(const T* object) {
|
||||
SanitizerPoisonMemoryRegion(object, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SanitizerUnpoisonObject(const T* object) {
|
||||
SanitizerUnpoisonMemoryRegion(object, sizeof(T));
|
||||
}
|
||||
|
||||
namespace memory_internal {
|
||||
|
||||
// If Pair is a standard-layout type, OffsetOf<Pair>::kFirst and
|
||||
// OffsetOf<Pair>::kSecond are equivalent to offsetof(Pair, first) and
|
||||
// offsetof(Pair, second) respectively. Otherwise they are -1.
|
||||
//
|
||||
// The purpose of OffsetOf is to avoid calling offsetof() on non-standard-layout
|
||||
// type, which is non-portable.
|
||||
template <class Pair, class = std::true_type>
|
||||
struct OffsetOf {
|
||||
static constexpr size_t kFirst = static_cast<size_t>(-1);
|
||||
static constexpr size_t kSecond = static_cast<size_t>(-1);
|
||||
};
|
||||
|
||||
template <class Pair>
|
||||
struct OffsetOf<Pair, typename std::is_standard_layout<Pair>::type> {
|
||||
static constexpr size_t kFirst = offsetof(Pair, first);
|
||||
static constexpr size_t kSecond = offsetof(Pair, second);
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
struct IsLayoutCompatible {
|
||||
private:
|
||||
struct Pair {
|
||||
K first;
|
||||
V second;
|
||||
};
|
||||
|
||||
// Is P layout-compatible with Pair?
|
||||
template <class P>
|
||||
static constexpr bool LayoutCompatible() {
|
||||
return std::is_standard_layout<P>() && sizeof(P) == sizeof(Pair) &&
|
||||
alignof(P) == alignof(Pair) &&
|
||||
memory_internal::OffsetOf<P>::kFirst ==
|
||||
memory_internal::OffsetOf<Pair>::kFirst &&
|
||||
memory_internal::OffsetOf<P>::kSecond ==
|
||||
memory_internal::OffsetOf<Pair>::kSecond;
|
||||
}
|
||||
|
||||
public:
|
||||
// Whether pair<const K, V> and pair<K, V> are layout-compatible. If they are,
|
||||
// then it is safe to store them in a union and read from either.
|
||||
static constexpr bool value = std::is_standard_layout<K>() &&
|
||||
std::is_standard_layout<Pair>() &&
|
||||
memory_internal::OffsetOf<Pair>::kFirst == 0 &&
|
||||
LayoutCompatible<std::pair<K, V>>() &&
|
||||
LayoutCompatible<std::pair<const K, V>>();
|
||||
};
|
||||
|
||||
} // namespace memory_internal
|
||||
|
||||
// The internal storage type for key-value containers like flat_hash_map.
|
||||
//
|
||||
// It is convenient for the value_type of a flat_hash_map<K, V> to be
|
||||
// pair<const K, V>; the "const K" prevents accidental modification of the key
|
||||
// when dealing with the reference returned from find() and similar methods.
|
||||
// However, this creates other problems; we want to be able to emplace(K, V)
|
||||
// efficiently with move operations, and similarly be able to move a
|
||||
// pair<K, V> in insert().
|
||||
//
|
||||
// The solution is this union, which aliases the const and non-const versions
|
||||
// of the pair. This also allows flat_hash_map<const K, V> to work, even though
|
||||
// that has the same efficiency issues with move in emplace() and insert() -
|
||||
// but people do it anyway.
|
||||
//
|
||||
// If kMutableKeys is false, only the value member can be accessed.
|
||||
//
|
||||
// If kMutableKeys is true, key can be accessed through all slots while value
|
||||
// and mutable_value must be accessed only via INITIALIZED slots. Slots are
|
||||
// created and destroyed via mutable_value so that the key can be moved later.
|
||||
//
|
||||
// Accessing one of the union fields while the other is active is safe as
|
||||
// long as they are layout-compatible, which is guaranteed by the definition of
|
||||
// kMutableKeys. For C++11, the relevant section of the standard is
|
||||
// https://timsong-cpp.github.io/cppwp/n3337/class.mem#19 (9.2.19)
|
||||
template <class K, class V>
|
||||
union map_slot_type {
|
||||
map_slot_type() {}
|
||||
~map_slot_type() = delete;
|
||||
using value_type = std::pair<const K, V>;
|
||||
using mutable_value_type =
|
||||
std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
|
||||
|
||||
value_type value;
|
||||
mutable_value_type mutable_value;
|
||||
absl::remove_const_t<K> key;
|
||||
};
|
||||
|
||||
template <class K, class V>
|
||||
struct map_slot_policy {
|
||||
using slot_type = map_slot_type<K, V>;
|
||||
using value_type = std::pair<const K, V>;
|
||||
using mutable_value_type =
|
||||
std::pair<absl::remove_const_t<K>, absl::remove_const_t<V>>;
|
||||
|
||||
private:
|
||||
static void emplace(slot_type* slot) {
|
||||
// The construction of union doesn't do anything at runtime but it allows us
|
||||
// to access its members without violating aliasing rules.
|
||||
new (slot) slot_type;
|
||||
}
|
||||
// If pair<const K, V> and pair<K, V> are layout-compatible, we can accept one
|
||||
// or the other via slot_type. We are also free to access the key via
|
||||
// slot_type::key in this case.
|
||||
using kMutableKeys = memory_internal::IsLayoutCompatible<K, V>;
|
||||
|
||||
public:
|
||||
static value_type& element(slot_type* slot) { return slot->value; }
|
||||
static const value_type& element(const slot_type* slot) {
|
||||
return slot->value;
|
||||
}
|
||||
|
||||
// When C++17 is available, we can use std::launder to provide mutable
|
||||
// access to the key for use in node handle.
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
static K& mutable_key(slot_type* slot) {
|
||||
// Still check for kMutableKeys so that we can avoid calling std::launder
|
||||
// unless necessary because it can interfere with optimizations.
|
||||
return kMutableKeys::value ? slot->key
|
||||
: *std::launder(const_cast<K*>(
|
||||
std::addressof(slot->value.first)));
|
||||
}
|
||||
#else // !(defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606)
|
||||
static const K& mutable_key(slot_type* slot) { return key(slot); }
|
||||
#endif
|
||||
|
||||
static const K& key(const slot_type* slot) {
|
||||
return kMutableKeys::value ? slot->key : slot->value.first;
|
||||
}
|
||||
|
||||
template <class Allocator, class... Args>
|
||||
static void construct(Allocator* alloc, slot_type* slot, Args&&... args) {
|
||||
emplace(slot);
|
||||
if (kMutableKeys::value) {
|
||||
absl::allocator_traits<Allocator>::construct(*alloc, &slot->mutable_value,
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct this slot by moving from another slot.
|
||||
template <class Allocator>
|
||||
static void construct(Allocator* alloc, slot_type* slot, slot_type* other) {
|
||||
emplace(slot);
|
||||
if (kMutableKeys::value) {
|
||||
absl::allocator_traits<Allocator>::construct(
|
||||
*alloc, &slot->mutable_value, std::move(other->mutable_value));
|
||||
} else {
|
||||
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
|
||||
std::move(other->value));
|
||||
}
|
||||
}
|
||||
|
||||
// Construct this slot by copying from another slot.
|
||||
template <class Allocator>
|
||||
static void construct(Allocator* alloc, slot_type* slot,
|
||||
const slot_type* other) {
|
||||
emplace(slot);
|
||||
absl::allocator_traits<Allocator>::construct(*alloc, &slot->value,
|
||||
other->value);
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
static auto destroy(Allocator* alloc, slot_type* slot) {
|
||||
if (kMutableKeys::value) {
|
||||
absl::allocator_traits<Allocator>::destroy(*alloc, &slot->mutable_value);
|
||||
} else {
|
||||
absl::allocator_traits<Allocator>::destroy(*alloc, &slot->value);
|
||||
}
|
||||
return IsDestructionTrivial<Allocator, value_type>();
|
||||
}
|
||||
|
||||
template <class Allocator>
|
||||
static auto transfer(Allocator* alloc, slot_type* new_slot,
|
||||
slot_type* old_slot) {
|
||||
auto is_relocatable =
|
||||
typename absl::is_trivially_relocatable<value_type>::type();
|
||||
|
||||
emplace(new_slot);
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
if (is_relocatable) {
|
||||
// TODO(b/247130232,b/251814870): remove casts after fixing warnings.
|
||||
std::memcpy(static_cast<void*>(std::launder(&new_slot->value)),
|
||||
static_cast<const void*>(&old_slot->value),
|
||||
sizeof(value_type));
|
||||
return is_relocatable;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (kMutableKeys::value) {
|
||||
absl::allocator_traits<Allocator>::construct(
|
||||
*alloc, &new_slot->mutable_value, std::move(old_slot->mutable_value));
|
||||
} else {
|
||||
absl::allocator_traits<Allocator>::construct(*alloc, &new_slot->value,
|
||||
std::move(old_slot->value));
|
||||
}
|
||||
destroy(alloc, old_slot);
|
||||
return is_relocatable;
|
||||
}
|
||||
};
|
||||
|
||||
// Type erased function for computing hash of the slot.
|
||||
using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
|
||||
|
||||
// Type erased function to apply `Fn` to data inside of the `slot`.
|
||||
// The data is expected to have type `T`.
|
||||
template <class Fn, class T>
|
||||
size_t TypeErasedApplyToSlotFn(const void* fn, void* slot) {
|
||||
const auto* f = static_cast<const Fn*>(fn);
|
||||
return (*f)(*static_cast<const T*>(slot));
|
||||
}
|
||||
|
||||
// Type erased function to apply `Fn` to data inside of the `*slot_ptr`.
|
||||
// The data is expected to have type `T`.
|
||||
template <class Fn, class T>
|
||||
size_t TypeErasedDerefAndApplyToSlotFn(const void* fn, void* slot_ptr) {
|
||||
const auto* f = static_cast<const Fn*>(fn);
|
||||
const T* slot = *static_cast<const T**>(slot_ptr);
|
||||
return (*f)(*slot);
|
||||
}
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_CONTAINER_MEMORY_H_
|
||||
+276
@@ -0,0 +1,276 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Define the default Hash and Eq functions for SwissTable containers.
|
||||
//
|
||||
// std::hash<T> and std::equal_to<T> are not appropriate hash and equal
|
||||
// functions for SwissTable containers. There are two reasons for this.
|
||||
//
|
||||
// SwissTable containers are power of 2 sized containers:
|
||||
//
|
||||
// This means they use the lower bits of the hash value to find the slot for
|
||||
// each entry. The typical hash function for integral types is the identity.
|
||||
// This is a very weak hash function for SwissTable and any power of 2 sized
|
||||
// hashtable implementation which will lead to excessive collisions. For
|
||||
// SwissTable we use murmur3 style mixing to reduce collisions to a minimum.
|
||||
//
|
||||
// SwissTable containers support heterogeneous lookup:
|
||||
//
|
||||
// In order to make heterogeneous lookup work, hash and equal functions must be
|
||||
// polymorphic. At the same time they have to satisfy the same requirements the
|
||||
// C++ standard imposes on hash functions and equality operators. That is:
|
||||
//
|
||||
// if hash_default_eq<T>(a, b) returns true for any a and b of type T, then
|
||||
// hash_default_hash<T>(a) must equal hash_default_hash<T>(b)
|
||||
//
|
||||
// For SwissTable containers this requirement is relaxed to allow a and b of
|
||||
// any and possibly different types. Note that like the standard the hash and
|
||||
// equal functions are still bound to T. This is important because some type U
|
||||
// can be hashed by/tested for equality differently depending on T. A notable
|
||||
// example is `const char*`. `const char*` is treated as a c-style string when
|
||||
// the hash function is hash<std::string> but as a pointer when the hash
|
||||
// function is hash<void*>.
|
||||
//
|
||||
#ifndef ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/container/internal/common.h"
|
||||
#include "absl/hash/hash.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
#include "absl/strings/cord.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
// The hash of an object of type T is computed by using absl::Hash.
|
||||
template <class T, class E = void>
|
||||
struct HashEq {
|
||||
using Hash = absl::Hash<T>;
|
||||
using Eq = std::equal_to<T>;
|
||||
};
|
||||
|
||||
struct StringHash {
|
||||
using is_transparent = void;
|
||||
|
||||
size_t operator()(absl::string_view v) const {
|
||||
return absl::Hash<absl::string_view>{}(v);
|
||||
}
|
||||
size_t operator()(const absl::Cord& v) const {
|
||||
return absl::Hash<absl::Cord>{}(v);
|
||||
}
|
||||
};
|
||||
|
||||
struct StringEq {
|
||||
using is_transparent = void;
|
||||
bool operator()(absl::string_view lhs, absl::string_view rhs) const {
|
||||
return lhs == rhs;
|
||||
}
|
||||
bool operator()(const absl::Cord& lhs, const absl::Cord& rhs) const {
|
||||
return lhs == rhs;
|
||||
}
|
||||
bool operator()(const absl::Cord& lhs, absl::string_view rhs) const {
|
||||
return lhs == rhs;
|
||||
}
|
||||
bool operator()(absl::string_view lhs, const absl::Cord& rhs) const {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
// Supports heterogeneous lookup for string-like elements.
|
||||
struct StringHashEq {
|
||||
using Hash = StringHash;
|
||||
using Eq = StringEq;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashEq<std::string> : StringHashEq {};
|
||||
template <>
|
||||
struct HashEq<absl::string_view> : StringHashEq {};
|
||||
template <>
|
||||
struct HashEq<absl::Cord> : StringHashEq {};
|
||||
|
||||
#ifdef ABSL_HAVE_STD_STRING_VIEW
|
||||
|
||||
template <typename TChar>
|
||||
struct BasicStringHash {
|
||||
using is_transparent = void;
|
||||
|
||||
size_t operator()(std::basic_string_view<TChar> v) const {
|
||||
return absl::Hash<std::basic_string_view<TChar>>{}(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename TChar>
|
||||
struct BasicStringEq {
|
||||
using is_transparent = void;
|
||||
bool operator()(std::basic_string_view<TChar> lhs,
|
||||
std::basic_string_view<TChar> rhs) const {
|
||||
return lhs == rhs;
|
||||
}
|
||||
};
|
||||
|
||||
// Supports heterogeneous lookup for w/u16/u32 string + string_view + char*.
|
||||
template <typename TChar>
|
||||
struct BasicStringHashEq {
|
||||
using Hash = BasicStringHash<TChar>;
|
||||
using Eq = BasicStringEq<TChar>;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashEq<std::wstring> : BasicStringHashEq<wchar_t> {};
|
||||
template <>
|
||||
struct HashEq<std::wstring_view> : BasicStringHashEq<wchar_t> {};
|
||||
template <>
|
||||
struct HashEq<std::u16string> : BasicStringHashEq<char16_t> {};
|
||||
template <>
|
||||
struct HashEq<std::u16string_view> : BasicStringHashEq<char16_t> {};
|
||||
template <>
|
||||
struct HashEq<std::u32string> : BasicStringHashEq<char32_t> {};
|
||||
template <>
|
||||
struct HashEq<std::u32string_view> : BasicStringHashEq<char32_t> {};
|
||||
|
||||
#endif // ABSL_HAVE_STD_STRING_VIEW
|
||||
|
||||
// Supports heterogeneous lookup for pointers and smart pointers.
|
||||
template <class T>
|
||||
struct HashEq<T*> {
|
||||
struct Hash {
|
||||
using is_transparent = void;
|
||||
template <class U>
|
||||
size_t operator()(const U& ptr) const {
|
||||
return absl::Hash<const T*>{}(HashEq::ToPtr(ptr));
|
||||
}
|
||||
};
|
||||
struct Eq {
|
||||
using is_transparent = void;
|
||||
template <class A, class B>
|
||||
bool operator()(const A& a, const B& b) const {
|
||||
return HashEq::ToPtr(a) == HashEq::ToPtr(b);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
static const T* ToPtr(const T* ptr) { return ptr; }
|
||||
template <class U, class D>
|
||||
static const T* ToPtr(const std::unique_ptr<U, D>& ptr) {
|
||||
return ptr.get();
|
||||
}
|
||||
template <class U>
|
||||
static const T* ToPtr(const std::shared_ptr<U>& ptr) {
|
||||
return ptr.get();
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, class D>
|
||||
struct HashEq<std::unique_ptr<T, D>> : HashEq<T*> {};
|
||||
template <class T>
|
||||
struct HashEq<std::shared_ptr<T>> : HashEq<T*> {};
|
||||
|
||||
template <typename T, typename E = void>
|
||||
struct HasAbslContainerHash : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasAbslContainerHash<T, absl::void_t<typename T::absl_container_hash>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename E = void>
|
||||
struct HasAbslContainerEq : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct HasAbslContainerEq<T, absl::void_t<typename T::absl_container_eq>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename E = void>
|
||||
struct AbslContainerEq {
|
||||
using type = std::equal_to<>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct AbslContainerEq<
|
||||
T, typename std::enable_if_t<HasAbslContainerEq<T>::value>> {
|
||||
using type = typename T::absl_container_eq;
|
||||
};
|
||||
|
||||
template <typename T, typename E = void>
|
||||
struct AbslContainerHash {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct AbslContainerHash<
|
||||
T, typename std::enable_if_t<HasAbslContainerHash<T>::value>> {
|
||||
using type = typename T::absl_container_hash;
|
||||
};
|
||||
|
||||
// HashEq specialization for user types that provide `absl_container_hash` and
|
||||
// (optionally) `absl_container_eq`. This specialization allows user types to
|
||||
// provide heterogeneous lookup without requiring to explicitly specify Hash/Eq
|
||||
// type arguments in unordered Abseil containers.
|
||||
//
|
||||
// Both `absl_container_hash` and `absl_container_eq` should be transparent
|
||||
// (have inner is_transparent type). While there is no technical reason to
|
||||
// restrict to transparent-only types, there is also no feasible use case when
|
||||
// it shouldn't be transparent - it is easier to relax the requirement later if
|
||||
// such a case arises rather than restricting it.
|
||||
//
|
||||
// If type provides only `absl_container_hash` then `eq` part will be
|
||||
// `std::equal_to<void>`.
|
||||
//
|
||||
// User types are not allowed to provide only a `Eq` part as there is no
|
||||
// feasible use case for this behavior - if Hash should be a default one then Eq
|
||||
// should be an equivalent to the `std::equal_to<T>`.
|
||||
template <typename T>
|
||||
struct HashEq<T, typename std::enable_if_t<HasAbslContainerHash<T>::value>> {
|
||||
using Hash = typename AbslContainerHash<T>::type;
|
||||
using Eq = typename AbslContainerEq<T>::type;
|
||||
static_assert(IsTransparent<Hash>::value,
|
||||
"absl_container_hash must be transparent. To achieve it add a "
|
||||
"`using is_transparent = void;` clause to this type.");
|
||||
static_assert(IsTransparent<Eq>::value,
|
||||
"absl_container_eq must be transparent. To achieve it add a "
|
||||
"`using is_transparent = void;` clause to this type.");
|
||||
};
|
||||
|
||||
// This header's visibility is restricted. If you need to access the default
|
||||
// hasher please use the container's ::hasher alias instead.
|
||||
//
|
||||
// Example: typename Hash = typename absl::flat_hash_map<K, V>::hasher
|
||||
template <class T>
|
||||
using hash_default_hash = typename container_internal::HashEq<T>::Hash;
|
||||
|
||||
// This header's visibility is restricted. If you need to access the default
|
||||
// key equal please use the container's ::key_equal alias instead.
|
||||
//
|
||||
// Example: typename Eq = typename absl::flat_hash_map<K, V, Hash>::key_equal
|
||||
template <class T>
|
||||
using hash_default_eq = typename container_internal::HashEq<T>::Eq;
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_HASH_FUNCTION_DEFAULTS_H_
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/container/internal/common_policy_traits.h"
|
||||
#include "absl/meta/type_traits.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
// Defines how slots are initialized/destroyed/moved.
|
||||
template <class Policy, class = void>
|
||||
struct hash_policy_traits : common_policy_traits<Policy> {
|
||||
// The type of the keys stored in the hashtable.
|
||||
using key_type = typename Policy::key_type;
|
||||
|
||||
private:
|
||||
struct ReturnKey {
|
||||
// When C++17 is available, we can use std::launder to provide mutable
|
||||
// access to the key for use in node handle.
|
||||
#if defined(__cpp_lib_launder) && __cpp_lib_launder >= 201606
|
||||
template <class Key,
|
||||
absl::enable_if_t<std::is_lvalue_reference<Key>::value, int> = 0>
|
||||
static key_type& Impl(Key&& k, int) {
|
||||
return *std::launder(
|
||||
const_cast<key_type*>(std::addressof(std::forward<Key>(k))));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class Key>
|
||||
static Key Impl(Key&& k, char) {
|
||||
return std::forward<Key>(k);
|
||||
}
|
||||
|
||||
// When Key=T&, we forward the lvalue reference.
|
||||
// When Key=T, we return by value to avoid a dangling reference.
|
||||
// eg, for string_hash_map.
|
||||
template <class Key, class... Args>
|
||||
auto operator()(Key&& k, const Args&...) const
|
||||
-> decltype(Impl(std::forward<Key>(k), 0)) {
|
||||
return Impl(std::forward<Key>(k), 0);
|
||||
}
|
||||
};
|
||||
|
||||
template <class P = Policy, class = void>
|
||||
struct ConstantIteratorsImpl : std::false_type {};
|
||||
|
||||
template <class P>
|
||||
struct ConstantIteratorsImpl<P, absl::void_t<typename P::constant_iterators>>
|
||||
: P::constant_iterators {};
|
||||
|
||||
public:
|
||||
// The actual object stored in the hash table.
|
||||
using slot_type = typename Policy::slot_type;
|
||||
|
||||
// The argument type for insertions into the hashtable. This is different
|
||||
// from value_type for increased performance. See initializer_list constructor
|
||||
// and insert() member functions for more details.
|
||||
using init_type = typename Policy::init_type;
|
||||
|
||||
using reference = decltype(Policy::element(std::declval<slot_type*>()));
|
||||
using pointer = typename std::remove_reference<reference>::type*;
|
||||
using value_type = typename std::remove_reference<reference>::type;
|
||||
|
||||
// Policies can set this variable to tell raw_hash_set that all iterators
|
||||
// should be constant, even `iterator`. This is useful for set-like
|
||||
// containers.
|
||||
// Defaults to false if not provided by the policy.
|
||||
using constant_iterators = ConstantIteratorsImpl<>;
|
||||
|
||||
// Returns the amount of memory owned by `slot`, exclusive of `sizeof(*slot)`.
|
||||
//
|
||||
// If `slot` is nullptr, returns the constant amount of memory owned by any
|
||||
// full slot or -1 if slots own variable amounts of memory.
|
||||
//
|
||||
// PRECONDITION: `slot` is INITIALIZED or nullptr
|
||||
template <class P = Policy>
|
||||
static size_t space_used(const slot_type* slot) {
|
||||
return P::space_used(slot);
|
||||
}
|
||||
|
||||
// Provides generalized access to the key for elements, both for elements in
|
||||
// the table and for elements that have not yet been inserted (or even
|
||||
// constructed). We would like an API that allows us to say: `key(args...)`
|
||||
// but we cannot do that for all cases, so we use this more general API that
|
||||
// can be used for many things, including the following:
|
||||
//
|
||||
// - Given an element in a table, get its key.
|
||||
// - Given an element initializer, get its key.
|
||||
// - Given `emplace()` arguments, get the element key.
|
||||
//
|
||||
// Implementations of this must adhere to a very strict technical
|
||||
// specification around aliasing and consuming arguments:
|
||||
//
|
||||
// Let `value_type` be the result type of `element()` without ref- and
|
||||
// cv-qualifiers. The first argument is a functor, the rest are constructor
|
||||
// arguments for `value_type`. Returns `std::forward<F>(f)(k, xs...)`, where
|
||||
// `k` is the element key, and `xs...` are the new constructor arguments for
|
||||
// `value_type`. It's allowed for `k` to alias `xs...`, and for both to alias
|
||||
// `ts...`. The key won't be touched once `xs...` are used to construct an
|
||||
// element; `ts...` won't be touched at all, which allows `apply()` to consume
|
||||
// any rvalues among them.
|
||||
//
|
||||
// If `value_type` is constructible from `Ts&&...`, `Policy::apply()` must not
|
||||
// trigger a hard compile error unless it originates from `f`. In other words,
|
||||
// `Policy::apply()` must be SFINAE-friendly. If `value_type` is not
|
||||
// constructible from `Ts&&...`, either SFINAE or a hard compile error is OK.
|
||||
//
|
||||
// If `Ts...` is `[cv] value_type[&]` or `[cv] init_type[&]`,
|
||||
// `Policy::apply()` must work. A compile error is not allowed, SFINAE or not.
|
||||
template <class F, class... Ts, class P = Policy>
|
||||
static auto apply(F&& f, Ts&&... ts)
|
||||
-> decltype(P::apply(std::forward<F>(f), std::forward<Ts>(ts)...)) {
|
||||
return P::apply(std::forward<F>(f), std::forward<Ts>(ts)...);
|
||||
}
|
||||
|
||||
// Returns the "key" portion of the slot.
|
||||
// Used for node handle manipulation.
|
||||
template <class P = Policy>
|
||||
static auto mutable_key(slot_type* slot)
|
||||
-> decltype(P::apply(ReturnKey(), hash_policy_traits::element(slot))) {
|
||||
return P::apply(ReturnKey(), hash_policy_traits::element(slot));
|
||||
}
|
||||
|
||||
// Returns the "value" (as opposed to the "key") portion of the element. Used
|
||||
// by maps to implement `operator[]`, `at()` and `insert_or_assign()`.
|
||||
template <class T, class P = Policy>
|
||||
static auto value(T* elem) -> decltype(P::value(elem)) {
|
||||
return P::value(elem);
|
||||
}
|
||||
|
||||
using HashSlotFn = size_t (*)(const void* hash_fn, void* slot);
|
||||
|
||||
template <class Hash>
|
||||
static constexpr HashSlotFn get_hash_slot_fn() {
|
||||
// get_hash_slot_fn may return nullptr to signal that non type erased function
|
||||
// should be used. GCC warns against comparing function address with nullptr.
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
// silent error: the address of * will never be NULL [-Werror=address]
|
||||
#pragma GCC diagnostic ignored "-Waddress"
|
||||
#endif
|
||||
return Policy::template get_hash_slot_fn<Hash>() == nullptr
|
||||
? &hash_slot_fn_non_type_erased<Hash>
|
||||
: Policy::template get_hash_slot_fn<Hash>();
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
// Whether small object optimization is enabled. True by default.
|
||||
static constexpr bool soo_enabled() { return soo_enabled_impl(Rank1{}); }
|
||||
|
||||
private:
|
||||
template <class Hash>
|
||||
struct HashElement {
|
||||
template <class K, class... Args>
|
||||
size_t operator()(const K& key, Args&&...) const {
|
||||
return h(key);
|
||||
}
|
||||
const Hash& h;
|
||||
};
|
||||
|
||||
template <class Hash>
|
||||
static size_t hash_slot_fn_non_type_erased(const void* hash_fn, void* slot) {
|
||||
return Policy::apply(HashElement<Hash>{*static_cast<const Hash*>(hash_fn)},
|
||||
Policy::element(static_cast<slot_type*>(slot)));
|
||||
}
|
||||
|
||||
// Use go/ranked-overloads for dispatching. Rank1 is preferred.
|
||||
struct Rank0 {};
|
||||
struct Rank1 : Rank0 {};
|
||||
|
||||
// Use auto -> decltype as an enabler.
|
||||
template <class P = Policy>
|
||||
static constexpr auto soo_enabled_impl(Rank1) -> decltype(P::soo_enabled()) {
|
||||
return P::soo_enabled();
|
||||
}
|
||||
|
||||
static constexpr bool soo_enabled_impl(Rank0) { return true; }
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_HASH_POLICY_TRAITS_H_
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// Provides the internal API for hashtable_debug.h.
|
||||
|
||||
#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <algorithm>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
namespace hashtable_debug_internal {
|
||||
|
||||
// If it is a map, call get<0>().
|
||||
using std::get;
|
||||
template <typename T, typename = typename T::mapped_type>
|
||||
auto GetKey(const typename T::value_type& pair, int) -> decltype(get<0>(pair)) {
|
||||
return get<0>(pair);
|
||||
}
|
||||
|
||||
// If it is not a map, return the value directly.
|
||||
template <typename T>
|
||||
const typename T::key_type& GetKey(const typename T::key_type& key, char) {
|
||||
return key;
|
||||
}
|
||||
|
||||
// Containers should specialize this to provide debug information for that
|
||||
// container.
|
||||
template <class Container, typename Enabler = void>
|
||||
struct HashtableDebugAccess {
|
||||
// Returns the number of probes required to find `key` in `c`. The "number of
|
||||
// probes" is a concept that can vary by container. Implementations should
|
||||
// return 0 when `key` was found in the minimum number of operations and
|
||||
// should increment the result for each non-trivial operation required to find
|
||||
// `key`.
|
||||
//
|
||||
// The default implementation uses the bucket api from the standard and thus
|
||||
// works for `std::unordered_*` containers.
|
||||
static size_t GetNumProbes(const Container& c,
|
||||
const typename Container::key_type& key) {
|
||||
if (!c.bucket_count()) return {};
|
||||
size_t num_probes = 0;
|
||||
size_t bucket = c.bucket(key);
|
||||
for (auto it = c.begin(bucket), e = c.end(bucket);; ++it, ++num_probes) {
|
||||
if (it == e) return num_probes;
|
||||
if (c.key_eq()(key, GetKey<Container>(*it, 0))) return num_probes;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of bytes requested from the allocator by the container
|
||||
// and not freed.
|
||||
//
|
||||
// static size_t AllocatedByteSize(const Container& c);
|
||||
|
||||
// Returns a tight lower bound for AllocatedByteSize(c) where `c` is of type
|
||||
// `Container` and `c.size()` is equal to `num_elements`.
|
||||
//
|
||||
// static size_t LowerBoundAllocatedByteSize(size_t num_elements);
|
||||
};
|
||||
|
||||
} // namespace hashtable_debug_internal
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLE_DEBUG_HOOKS_H_
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: hashtablez_sampler.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the API for a low level library to sample hashtables
|
||||
// and collect runtime statistics about them.
|
||||
//
|
||||
// `HashtablezSampler` controls the lifecycle of `HashtablezInfo` objects which
|
||||
// store information about a single sample.
|
||||
//
|
||||
// `Record*` methods store information into samples.
|
||||
// `Sample()` and `Unsample()` make use of a single global sampler with
|
||||
// properties controlled by the flags hashtablez_enabled,
|
||||
// hashtablez_sample_rate, and hashtablez_max_samples.
|
||||
//
|
||||
// WARNING
|
||||
//
|
||||
// Using this sampling API may cause sampled Swiss tables to use the global
|
||||
// allocator (operator `new`) in addition to any custom allocator. If you
|
||||
// are using a table in an unusual circumstance where allocation or calling a
|
||||
// linux syscall is unacceptable, this could interfere.
|
||||
//
|
||||
// This utility is internal-only. Use at your own risk.
|
||||
|
||||
#ifndef ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/per_thread_tls.h"
|
||||
#include "absl/base/optimization.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/profiling/internal/sample_recorder.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "absl/utility/utility.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
// Stores information about a sampled hashtable. All mutations to this *must*
|
||||
// be made through `Record*` functions below. All reads from this *must* only
|
||||
// occur in the callback to `HashtablezSampler::Iterate`.
|
||||
struct HashtablezInfo : public profiling_internal::Sample<HashtablezInfo> {
|
||||
// Constructs the object but does not fill in any fields.
|
||||
HashtablezInfo();
|
||||
~HashtablezInfo();
|
||||
HashtablezInfo(const HashtablezInfo&) = delete;
|
||||
HashtablezInfo& operator=(const HashtablezInfo&) = delete;
|
||||
|
||||
// Puts the object into a clean state, fills in the logically `const` members,
|
||||
// blocking for any readers that are currently sampling the object.
|
||||
void PrepareForSampling(int64_t stride, size_t inline_element_size_value,
|
||||
size_t key_size, size_t value_size,
|
||||
uint16_t soo_capacity_value)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(init_mu);
|
||||
|
||||
// These fields are mutated by the various Record* APIs and need to be
|
||||
// thread-safe.
|
||||
std::atomic<size_t> capacity;
|
||||
std::atomic<size_t> size;
|
||||
std::atomic<size_t> num_erases;
|
||||
std::atomic<size_t> num_rehashes;
|
||||
std::atomic<size_t> max_probe_length;
|
||||
std::atomic<size_t> total_probe_length;
|
||||
std::atomic<size_t> hashes_bitwise_or;
|
||||
std::atomic<size_t> hashes_bitwise_and;
|
||||
std::atomic<size_t> hashes_bitwise_xor;
|
||||
std::atomic<size_t> max_reserve;
|
||||
|
||||
// All of the fields below are set by `PrepareForSampling`, they must not be
|
||||
// mutated in `Record*` functions. They are logically `const` in that sense.
|
||||
// These are guarded by init_mu, but that is not externalized to clients,
|
||||
// which can read them only during `SampleRecorder::Iterate` which will hold
|
||||
// the lock.
|
||||
static constexpr int kMaxStackDepth = 64;
|
||||
absl::Time create_time;
|
||||
int32_t depth;
|
||||
// The SOO capacity for this table in elements (not bytes). Note that sampled
|
||||
// tables are never SOO because we need to store the infoz handle on the heap.
|
||||
// Tables that would be SOO if not sampled should have: soo_capacity > 0 &&
|
||||
// size <= soo_capacity && max_reserve <= soo_capacity.
|
||||
uint16_t soo_capacity;
|
||||
void* stack[kMaxStackDepth];
|
||||
size_t inline_element_size; // How big is the slot in bytes?
|
||||
size_t key_size; // sizeof(key_type)
|
||||
size_t value_size; // sizeof(value_type)
|
||||
};
|
||||
|
||||
void RecordRehashSlow(HashtablezInfo* info, size_t total_probe_length);
|
||||
|
||||
void RecordReservationSlow(HashtablezInfo* info, size_t target_capacity);
|
||||
|
||||
void RecordClearedReservationSlow(HashtablezInfo* info);
|
||||
|
||||
void RecordStorageChangedSlow(HashtablezInfo* info, size_t size,
|
||||
size_t capacity);
|
||||
|
||||
void RecordInsertSlow(HashtablezInfo* info, size_t hash,
|
||||
size_t distance_from_desired);
|
||||
|
||||
void RecordEraseSlow(HashtablezInfo* info);
|
||||
|
||||
struct SamplingState {
|
||||
int64_t next_sample;
|
||||
// When we make a sampling decision, we record that distance so we can weight
|
||||
// each sample.
|
||||
int64_t sample_stride;
|
||||
};
|
||||
|
||||
HashtablezInfo* SampleSlow(SamplingState& next_sample,
|
||||
size_t inline_element_size, size_t key_size,
|
||||
size_t value_size, uint16_t soo_capacity);
|
||||
void UnsampleSlow(HashtablezInfo* info);
|
||||
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
#error ABSL_INTERNAL_HASHTABLEZ_SAMPLE cannot be directly set
|
||||
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
class HashtablezInfoHandle {
|
||||
public:
|
||||
explicit HashtablezInfoHandle() : info_(nullptr) {}
|
||||
explicit HashtablezInfoHandle(HashtablezInfo* info) : info_(info) {}
|
||||
|
||||
// We do not have a destructor. Caller is responsible for calling Unregister
|
||||
// before destroying the handle.
|
||||
void Unregister() {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
UnsampleSlow(info_);
|
||||
}
|
||||
|
||||
inline bool IsSampled() const { return ABSL_PREDICT_FALSE(info_ != nullptr); }
|
||||
|
||||
inline void RecordStorageChanged(size_t size, size_t capacity) {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordStorageChangedSlow(info_, size, capacity);
|
||||
}
|
||||
|
||||
inline void RecordRehash(size_t total_probe_length) {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordRehashSlow(info_, total_probe_length);
|
||||
}
|
||||
|
||||
inline void RecordReservation(size_t target_capacity) {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordReservationSlow(info_, target_capacity);
|
||||
}
|
||||
|
||||
inline void RecordClearedReservation() {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordClearedReservationSlow(info_);
|
||||
}
|
||||
|
||||
inline void RecordInsert(size_t hash, size_t distance_from_desired) {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordInsertSlow(info_, hash, distance_from_desired);
|
||||
}
|
||||
|
||||
inline void RecordErase() {
|
||||
if (ABSL_PREDICT_TRUE(info_ == nullptr)) return;
|
||||
RecordEraseSlow(info_);
|
||||
}
|
||||
|
||||
friend inline void swap(HashtablezInfoHandle& lhs,
|
||||
HashtablezInfoHandle& rhs) {
|
||||
std::swap(lhs.info_, rhs.info_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class HashtablezInfoHandlePeer;
|
||||
HashtablezInfo* info_;
|
||||
};
|
||||
#else
|
||||
// Ensure that when Hashtablez is turned off at compile time, HashtablezInfo can
|
||||
// be removed by the linker, in order to reduce the binary size.
|
||||
class HashtablezInfoHandle {
|
||||
public:
|
||||
explicit HashtablezInfoHandle() = default;
|
||||
explicit HashtablezInfoHandle(std::nullptr_t) {}
|
||||
|
||||
inline void Unregister() {}
|
||||
inline bool IsSampled() const { return false; }
|
||||
inline void RecordStorageChanged(size_t /*size*/, size_t /*capacity*/) {}
|
||||
inline void RecordRehash(size_t /*total_probe_length*/) {}
|
||||
inline void RecordReservation(size_t /*target_capacity*/) {}
|
||||
inline void RecordClearedReservation() {}
|
||||
inline void RecordInsert(size_t /*hash*/, size_t /*distance_from_desired*/) {}
|
||||
inline void RecordErase() {}
|
||||
|
||||
friend inline void swap(HashtablezInfoHandle& /*lhs*/,
|
||||
HashtablezInfoHandle& /*rhs*/) {}
|
||||
};
|
||||
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
extern ABSL_PER_THREAD_TLS_KEYWORD SamplingState global_next_sample;
|
||||
#endif // defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
|
||||
// Returns a sampling handle.
|
||||
inline HashtablezInfoHandle Sample(
|
||||
ABSL_ATTRIBUTE_UNUSED size_t inline_element_size,
|
||||
ABSL_ATTRIBUTE_UNUSED size_t key_size,
|
||||
ABSL_ATTRIBUTE_UNUSED size_t value_size,
|
||||
ABSL_ATTRIBUTE_UNUSED uint16_t soo_capacity) {
|
||||
#if defined(ABSL_INTERNAL_HASHTABLEZ_SAMPLE)
|
||||
if (ABSL_PREDICT_TRUE(--global_next_sample.next_sample > 0)) {
|
||||
return HashtablezInfoHandle(nullptr);
|
||||
}
|
||||
return HashtablezInfoHandle(SampleSlow(global_next_sample,
|
||||
inline_element_size, key_size,
|
||||
value_size, soo_capacity));
|
||||
#else
|
||||
return HashtablezInfoHandle(nullptr);
|
||||
#endif // !ABSL_PER_THREAD_TLS
|
||||
}
|
||||
|
||||
using HashtablezSampler =
|
||||
::absl::profiling_internal::SampleRecorder<HashtablezInfo>;
|
||||
|
||||
// Returns a global Sampler.
|
||||
HashtablezSampler& GlobalHashtablezSampler();
|
||||
|
||||
using HashtablezConfigListener = void (*)();
|
||||
void SetHashtablezConfigListener(HashtablezConfigListener l);
|
||||
|
||||
// Enables or disables sampling for Swiss tables.
|
||||
bool IsHashtablezEnabled();
|
||||
void SetHashtablezEnabled(bool enabled);
|
||||
void SetHashtablezEnabledInternal(bool enabled);
|
||||
|
||||
// Sets the rate at which Swiss tables will be sampled.
|
||||
int32_t GetHashtablezSampleParameter();
|
||||
void SetHashtablezSampleParameter(int32_t rate);
|
||||
void SetHashtablezSampleParameterInternal(int32_t rate);
|
||||
|
||||
// Sets a soft max for the number of samples that will be kept.
|
||||
size_t GetHashtablezMaxSamples();
|
||||
void SetHashtablezMaxSamples(size_t max);
|
||||
void SetHashtablezMaxSamplesInternal(size_t max);
|
||||
|
||||
// Configuration override.
|
||||
// This allows process-wide sampling without depending on order of
|
||||
// initialization of static storage duration objects.
|
||||
// The definition of this constant is weak, which allows us to inject a
|
||||
// different value for it at link time.
|
||||
extern "C" bool ABSL_INTERNAL_C_SYMBOL(AbslContainerInternalSampleEverything)();
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_HASHTABLEZ_SAMPLER_H_
|
||||
+1105
File diff suppressed because it is too large.
Load diff
+226
@@ -0,0 +1,226 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
|
||||
#define ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
|
||||
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/internal/throw_delegate.h"
|
||||
#include "absl/container/internal/container_memory.h"
|
||||
#include "absl/container/internal/raw_hash_set.h" // IWYU pragma: export
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace container_internal {
|
||||
|
||||
template <class Policy, class Hash, class Eq, class Alloc>
|
||||
class raw_hash_map : public raw_hash_set<Policy, Hash, Eq, Alloc> {
|
||||
// P is Policy. It's passed as a template argument to support maps that have
|
||||
// incomplete types as values, as in unordered_map<K, IncompleteType>.
|
||||
// MappedReference<> may be a non-reference type.
|
||||
template <class P>
|
||||
using MappedReference = decltype(P::value(
|
||||
std::addressof(std::declval<typename raw_hash_map::reference>())));
|
||||
|
||||
// MappedConstReference<> may be a non-reference type.
|
||||
template <class P>
|
||||
using MappedConstReference = decltype(P::value(
|
||||
std::addressof(std::declval<typename raw_hash_map::const_reference>())));
|
||||
|
||||
using KeyArgImpl =
|
||||
KeyArg<IsTransparent<Eq>::value && IsTransparent<Hash>::value>;
|
||||
|
||||
public:
|
||||
using key_type = typename Policy::key_type;
|
||||
using mapped_type = typename Policy::mapped_type;
|
||||
template <class K>
|
||||
using key_arg = typename KeyArgImpl::template type<K, key_type>;
|
||||
|
||||
static_assert(!std::is_reference<key_type>::value, "");
|
||||
|
||||
// TODO(b/187807849): Evaluate whether to support reference mapped_type and
|
||||
// remove this assertion if/when it is supported.
|
||||
static_assert(!std::is_reference<mapped_type>::value, "");
|
||||
|
||||
using iterator = typename raw_hash_map::raw_hash_set::iterator;
|
||||
using const_iterator = typename raw_hash_map::raw_hash_set::const_iterator;
|
||||
|
||||
raw_hash_map() {}
|
||||
using raw_hash_map::raw_hash_set::raw_hash_set;
|
||||
|
||||
// The last two template parameters ensure that both arguments are rvalues
|
||||
// (lvalue arguments are handled by the overloads below). This is necessary
|
||||
// for supporting bitfield arguments.
|
||||
//
|
||||
// union { int n : 1; };
|
||||
// flat_hash_map<int, int> m;
|
||||
// m.insert_or_assign(n, n);
|
||||
template <class K = key_type, class V = mapped_type, K* = nullptr,
|
||||
V* = nullptr>
|
||||
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, V&& v)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign_impl(std::forward<K>(k), std::forward<V>(v));
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type, K* = nullptr>
|
||||
std::pair<iterator, bool> insert_or_assign(key_arg<K>&& k, const V& v)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign_impl(std::forward<K>(k), v);
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type, V* = nullptr>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, V&& v)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign_impl(k, std::forward<V>(v));
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_arg<K>& k, const V& v)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign_impl(k, v);
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type, K* = nullptr,
|
||||
V* = nullptr>
|
||||
iterator insert_or_assign(const_iterator, key_arg<K>&& k,
|
||||
V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign(std::forward<K>(k), std::forward<V>(v)).first;
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type, K* = nullptr>
|
||||
iterator insert_or_assign(const_iterator, key_arg<K>&& k,
|
||||
const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign(std::forward<K>(k), v).first;
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type, V* = nullptr>
|
||||
iterator insert_or_assign(const_iterator, const key_arg<K>& k,
|
||||
V&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign(k, std::forward<V>(v)).first;
|
||||
}
|
||||
|
||||
template <class K = key_type, class V = mapped_type>
|
||||
iterator insert_or_assign(const_iterator, const key_arg<K>& k,
|
||||
const V& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return insert_or_assign(k, v).first;
|
||||
}
|
||||
|
||||
// All `try_emplace()` overloads make the same guarantees regarding rvalue
|
||||
// arguments as `std::unordered_map::try_emplace()`, namely that these
|
||||
// functions will not move from rvalue arguments if insertions do not happen.
|
||||
template <class K = key_type, class... Args,
|
||||
typename std::enable_if<
|
||||
!std::is_convertible<K, const_iterator>::value, int>::type = 0,
|
||||
K* = nullptr>
|
||||
std::pair<iterator, bool> try_emplace(key_arg<K>&& k, Args&&... args)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return try_emplace_impl(std::forward<K>(k), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K = key_type, class... Args,
|
||||
typename std::enable_if<
|
||||
!std::is_convertible<K, const_iterator>::value, int>::type = 0>
|
||||
std::pair<iterator, bool> try_emplace(const key_arg<K>& k, Args&&... args)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return try_emplace_impl(k, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K = key_type, class... Args, K* = nullptr>
|
||||
iterator try_emplace(const_iterator, key_arg<K>&& k,
|
||||
Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return try_emplace(std::forward<K>(k), std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class K = key_type, class... Args>
|
||||
iterator try_emplace(const_iterator, const key_arg<K>& k,
|
||||
Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
return try_emplace(k, std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class K = key_type, class P = Policy>
|
||||
MappedReference<P> at(const key_arg<K>& key) ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
auto it = this->find(key);
|
||||
if (it == this->end()) {
|
||||
base_internal::ThrowStdOutOfRange(
|
||||
"absl::container_internal::raw_hash_map<>::at");
|
||||
}
|
||||
return Policy::value(&*it);
|
||||
}
|
||||
|
||||
template <class K = key_type, class P = Policy>
|
||||
MappedConstReference<P> at(const key_arg<K>& key) const
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
auto it = this->find(key);
|
||||
if (it == this->end()) {
|
||||
base_internal::ThrowStdOutOfRange(
|
||||
"absl::container_internal::raw_hash_map<>::at");
|
||||
}
|
||||
return Policy::value(&*it);
|
||||
}
|
||||
|
||||
template <class K = key_type, class P = Policy, K* = nullptr>
|
||||
MappedReference<P> operator[](key_arg<K>&& key)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
// It is safe to use unchecked_deref here because try_emplace
|
||||
// will always return an iterator pointing to a valid item in the table,
|
||||
// since it inserts if nothing is found for the given key.
|
||||
return Policy::value(
|
||||
&this->unchecked_deref(try_emplace(std::forward<K>(key)).first));
|
||||
}
|
||||
|
||||
template <class K = key_type, class P = Policy>
|
||||
MappedReference<P> operator[](const key_arg<K>& key)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
// It is safe to use unchecked_deref here because try_emplace
|
||||
// will always return an iterator pointing to a valid item in the table,
|
||||
// since it inserts if nothing is found for the given key.
|
||||
return Policy::value(&this->unchecked_deref(try_emplace(key).first));
|
||||
}
|
||||
|
||||
private:
|
||||
template <class K, class V>
|
||||
std::pair<iterator, bool> insert_or_assign_impl(K&& k, V&& v)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
auto res = this->find_or_prepare_insert(k);
|
||||
if (res.second) {
|
||||
this->emplace_at(res.first, std::forward<K>(k), std::forward<V>(v));
|
||||
} else {
|
||||
Policy::value(&*res.first) = std::forward<V>(v);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class K = key_type, class... Args>
|
||||
std::pair<iterator, bool> try_emplace_impl(K&& k, Args&&... args)
|
||||
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
||||
auto res = this->find_or_prepare_insert(k);
|
||||
if (res.second) {
|
||||
this->emplace_at(res.first, std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace container_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CONTAINER_INTERNAL_RAW_HASH_MAP_H_
|
||||
+4166
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,190 @@
|
||||
// Copyright 2022 The Abseil Authors
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: crc32c.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines the API for computing CRC32C values as checksums
|
||||
// for arbitrary sequences of bytes provided as a string buffer.
|
||||
//
|
||||
// The API includes the basic functions for computing such CRC32C values and
|
||||
// some utility functions for performing more efficient mathematical
|
||||
// computations using an existing checksum.
|
||||
#ifndef ABSL_CRC_CRC32C_H_
|
||||
#define ABSL_CRC_CRC32C_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
#include "absl/crc/internal/crc32c_inline.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// crc32c_t
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// `crc32c_t` defines a strongly-typed integer for holding a CRC32C value.
|
||||
//
|
||||
// Some operators are intentionally omitted. Only equality operators are defined
|
||||
// so that `crc32c_t` can be directly compared. Methods for putting `crc32c_t`
|
||||
// directly into a set are omitted because this is bug-prone due to checksum
|
||||
// collisions. Use an explicit conversion to the `uint32_t` space for operations
|
||||
// that treat `crc32c_t` as an integer.
|
||||
class crc32c_t final {
|
||||
public:
|
||||
crc32c_t() = default;
|
||||
constexpr explicit crc32c_t(uint32_t crc) : crc_(crc) {}
|
||||
|
||||
crc32c_t(const crc32c_t&) = default;
|
||||
crc32c_t& operator=(const crc32c_t&) = default;
|
||||
|
||||
explicit operator uint32_t() const { return crc_; }
|
||||
|
||||
friend bool operator==(crc32c_t lhs, crc32c_t rhs) {
|
||||
return static_cast<uint32_t>(lhs) == static_cast<uint32_t>(rhs);
|
||||
}
|
||||
|
||||
friend bool operator!=(crc32c_t lhs, crc32c_t rhs) { return !(lhs == rhs); }
|
||||
|
||||
template <typename Sink>
|
||||
friend void AbslStringify(Sink& sink, crc32c_t crc) {
|
||||
absl::Format(&sink, "%08x", static_cast<uint32_t>(crc));
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t crc_;
|
||||
};
|
||||
|
||||
|
||||
namespace crc_internal {
|
||||
// Non-inline code path for `absl::ExtendCrc32c()`. Do not call directly.
|
||||
// Call `absl::ExtendCrc32c()` (defined below) instead.
|
||||
crc32c_t ExtendCrc32cInternal(crc32c_t initial_crc,
|
||||
absl::string_view buf_to_add);
|
||||
} // namespace crc_internal
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CRC32C Computation Functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// ComputeCrc32c()
|
||||
//
|
||||
// Returns the CRC32C value of the provided string.
|
||||
crc32c_t ComputeCrc32c(absl::string_view buf);
|
||||
|
||||
// ExtendCrc32c()
|
||||
//
|
||||
// Computes a CRC32C value from an `initial_crc` CRC32C value including the
|
||||
// `buf_to_add` bytes of an additional buffer. Using this function is more
|
||||
// efficient than computing a CRC32C value for the combined buffer from
|
||||
// scratch.
|
||||
//
|
||||
// Note: `ExtendCrc32c` with an initial_crc of 0 is equivalent to
|
||||
// `ComputeCrc32c`.
|
||||
//
|
||||
// This operation has a runtime cost of O(`buf_to_add.size()`)
|
||||
inline crc32c_t ExtendCrc32c(crc32c_t initial_crc,
|
||||
absl::string_view buf_to_add) {
|
||||
// Approximately 75% of calls have size <= 64.
|
||||
if (buf_to_add.size() <= 64) {
|
||||
uint32_t crc = static_cast<uint32_t>(initial_crc);
|
||||
if (crc_internal::ExtendCrc32cInline(&crc, buf_to_add.data(),
|
||||
buf_to_add.size())) {
|
||||
return crc32c_t{crc};
|
||||
}
|
||||
}
|
||||
return crc_internal::ExtendCrc32cInternal(initial_crc, buf_to_add);
|
||||
}
|
||||
|
||||
// ExtendCrc32cByZeroes()
|
||||
//
|
||||
// Computes a CRC32C value for a buffer with an `initial_crc` CRC32C value,
|
||||
// where `length` bytes with a value of 0 are appended to the buffer. Using this
|
||||
// function is more efficient than computing a CRC32C value for the combined
|
||||
// buffer from scratch.
|
||||
//
|
||||
// This operation has a runtime cost of O(log(`length`))
|
||||
crc32c_t ExtendCrc32cByZeroes(crc32c_t initial_crc, size_t length);
|
||||
|
||||
// MemcpyCrc32c()
|
||||
//
|
||||
// Copies `src` to `dest` using `memcpy()` semantics, returning the CRC32C
|
||||
// value of the copied buffer.
|
||||
//
|
||||
// Using `MemcpyCrc32c()` is potentially faster than performing the `memcpy()`
|
||||
// and `ComputeCrc32c()` operations separately.
|
||||
crc32c_t MemcpyCrc32c(void* dest, const void* src, size_t count,
|
||||
crc32c_t initial_crc = crc32c_t{0});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CRC32C Arithmetic Functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// The following functions perform arithmetic on CRC32C values, which are
|
||||
// generally more efficient than recalculating any given result's CRC32C value.
|
||||
|
||||
// ConcatCrc32c()
|
||||
//
|
||||
// Calculates the CRC32C value of two buffers with known CRC32C values
|
||||
// concatenated together.
|
||||
//
|
||||
// Given a buffer with CRC32C value `crc1` and a buffer with
|
||||
// CRC32C value `crc2` and length, `crc2_length`, returns the CRC32C value of
|
||||
// the concatenation of these two buffers.
|
||||
//
|
||||
// This operation has a runtime cost of O(log(`crc2_length`)).
|
||||
crc32c_t ConcatCrc32c(crc32c_t crc1, crc32c_t crc2, size_t crc2_length);
|
||||
|
||||
// RemoveCrc32cPrefix()
|
||||
//
|
||||
// Calculates the CRC32C value of an existing buffer with a series of bytes
|
||||
// (the prefix) removed from the beginning of that buffer.
|
||||
//
|
||||
// Given the CRC32C value of an existing buffer, `full_string_crc`; The CRC32C
|
||||
// value of a prefix of that buffer, `prefix_crc`; and the length of the buffer
|
||||
// with the prefix removed, `remaining_string_length` , return the CRC32C
|
||||
// value of the buffer with the prefix removed.
|
||||
//
|
||||
// This operation has a runtime cost of O(log(`remaining_string_length`)).
|
||||
crc32c_t RemoveCrc32cPrefix(crc32c_t prefix_crc, crc32c_t full_string_crc,
|
||||
size_t remaining_string_length);
|
||||
// RemoveCrc32cSuffix()
|
||||
//
|
||||
// Calculates the CRC32C value of an existing buffer with a series of bytes
|
||||
// (the suffix) removed from the end of that buffer.
|
||||
//
|
||||
// Given a CRC32C value of an existing buffer `full_string_crc`, the CRC32C
|
||||
// value of the suffix to remove `suffix_crc`, and the length of that suffix
|
||||
// `suffix_len`, returns the CRC32C value of the buffer with suffix removed.
|
||||
//
|
||||
// This operation has a runtime cost of O(log(`suffix_len`))
|
||||
crc32c_t RemoveCrc32cSuffix(crc32c_t full_string_crc, crc32c_t suffix_crc,
|
||||
size_t suffix_length);
|
||||
|
||||
// operator<<
|
||||
//
|
||||
// Streams the CRC32C value `crc` to the stream `os`.
|
||||
inline std::ostream& operator<<(std::ostream& os, crc32c_t crc) {
|
||||
return os << absl::StreamFormat("%08x", static_cast<uint32_t>(crc));
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CRC_CRC32C_H_
|
||||
+300
@@ -0,0 +1,300 @@
|
||||
// Copyright 2022 The Abseil Authors.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// https://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 ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_
|
||||
#define ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Many x86 and ARM machines have CRC acceleration hardware.
|
||||
// We can do a faster version of Extend() on such machines.
|
||||
// We define a translation layer for both x86 and ARM for the ease of use and
|
||||
// most performance gains.
|
||||
|
||||
// This implementation requires 64-bit CRC instructions (part of SSE 4.2) and
|
||||
// PCLMULQDQ instructions. 32-bit builds with SSE 4.2 do exist, so the
|
||||
// __x86_64__ condition is necessary.
|
||||
#if defined(__x86_64__) && defined(__SSE4_2__) && defined(__PCLMUL__)
|
||||
|
||||
#include <x86intrin.h>
|
||||
#define ABSL_CRC_INTERNAL_HAVE_X86_SIMD
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(__clang__) && defined(__AVX__) && \
|
||||
defined(_M_AMD64)
|
||||
|
||||
// MSVC AVX (/arch:AVX) implies SSE 4.2 and PCLMULQDQ.
|
||||
#include <intrin.h>
|
||||
#define ABSL_CRC_INTERNAL_HAVE_X86_SIMD
|
||||
|
||||
#elif defined(__aarch64__) && defined(__LITTLE_ENDIAN__) && \
|
||||
defined(__ARM_FEATURE_CRC32) && defined(ABSL_INTERNAL_HAVE_ARM_NEON) && \
|
||||
defined(__ARM_FEATURE_CRYPTO)
|
||||
|
||||
#include <arm_acle.h>
|
||||
#include <arm_neon.h>
|
||||
#define ABSL_CRC_INTERNAL_HAVE_ARM_SIMD
|
||||
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace crc_internal {
|
||||
|
||||
#if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD) || \
|
||||
defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD)
|
||||
|
||||
#if defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD)
|
||||
using V128 = uint64x2_t;
|
||||
#else
|
||||
// Note: Do not use __m128i_u, it is not portable.
|
||||
// Use V128_LoadU() perform an unaligned load from __m128i*.
|
||||
using V128 = __m128i;
|
||||
#endif
|
||||
|
||||
// Starting with the initial value in |crc|, accumulates a CRC32 value for
|
||||
// unsigned integers of different sizes.
|
||||
uint32_t CRC32_u8(uint32_t crc, uint8_t v);
|
||||
|
||||
uint32_t CRC32_u16(uint32_t crc, uint16_t v);
|
||||
|
||||
uint32_t CRC32_u32(uint32_t crc, uint32_t v);
|
||||
|
||||
uint32_t CRC32_u64(uint32_t crc, uint64_t v);
|
||||
|
||||
// Loads 128 bits of integer data. |src| must be 16-byte aligned.
|
||||
V128 V128_Load(const V128* src);
|
||||
|
||||
// Load 128 bits of integer data. |src| does not need to be aligned.
|
||||
V128 V128_LoadU(const V128* src);
|
||||
|
||||
// Store 128 bits of integer data. |src| must be 16-byte aligned.
|
||||
void V128_Store(V128* dst, V128 data);
|
||||
|
||||
// Polynomially multiplies the high 64 bits of |l| and |r|.
|
||||
V128 V128_PMulHi(const V128 l, const V128 r);
|
||||
|
||||
// Polynomially multiplies the low 64 bits of |l| and |r|.
|
||||
V128 V128_PMulLow(const V128 l, const V128 r);
|
||||
|
||||
// Polynomially multiplies the low 64 bits of |r| and high 64 bits of |l|.
|
||||
V128 V128_PMul01(const V128 l, const V128 r);
|
||||
|
||||
// Polynomially multiplies the low 64 bits of |l| and high 64 bits of |r|.
|
||||
V128 V128_PMul10(const V128 l, const V128 r);
|
||||
|
||||
// Produces a XOR operation of |l| and |r|.
|
||||
V128 V128_Xor(const V128 l, const V128 r);
|
||||
|
||||
// Produces an AND operation of |l| and |r|.
|
||||
V128 V128_And(const V128 l, const V128 r);
|
||||
|
||||
// Sets the lower half of a 128 bit register to the given 64-bit value and
|
||||
// zeroes the upper half.
|
||||
// dst[63:0] := |r|
|
||||
// dst[127:64] := |0|
|
||||
V128 V128_From64WithZeroFill(const uint64_t r);
|
||||
|
||||
// Shift |l| right by |imm| bytes while shifting in zeros.
|
||||
template <int imm>
|
||||
V128 V128_ShiftRight(const V128 l);
|
||||
|
||||
// Extracts a 32-bit integer from |l|, selected with |imm|.
|
||||
template <int imm>
|
||||
int V128_Extract32(const V128 l);
|
||||
|
||||
// Extracts a 64-bit integer from |l|, selected with |imm|.
|
||||
template <int imm>
|
||||
uint64_t V128_Extract64(const V128 l);
|
||||
|
||||
// Extracts the low 64 bits from V128.
|
||||
int64_t V128_Low64(const V128 l);
|
||||
|
||||
// Add packed 64-bit integers in |l| and |r|.
|
||||
V128 V128_Add64(const V128 l, const V128 r);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ABSL_CRC_INTERNAL_HAVE_X86_SIMD)
|
||||
|
||||
inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) {
|
||||
return _mm_crc32_u8(crc, v);
|
||||
}
|
||||
|
||||
inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) {
|
||||
return _mm_crc32_u16(crc, v);
|
||||
}
|
||||
|
||||
inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) {
|
||||
return _mm_crc32_u32(crc, v);
|
||||
}
|
||||
|
||||
inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) {
|
||||
return static_cast<uint32_t>(_mm_crc32_u64(crc, v));
|
||||
}
|
||||
|
||||
inline V128 V128_Load(const V128* src) { return _mm_load_si128(src); }
|
||||
|
||||
inline V128 V128_LoadU(const V128* src) { return _mm_loadu_si128(src); }
|
||||
|
||||
inline void V128_Store(V128* dst, V128 data) { _mm_store_si128(dst, data); }
|
||||
|
||||
inline V128 V128_PMulHi(const V128 l, const V128 r) {
|
||||
return _mm_clmulepi64_si128(l, r, 0x11);
|
||||
}
|
||||
|
||||
inline V128 V128_PMulLow(const V128 l, const V128 r) {
|
||||
return _mm_clmulepi64_si128(l, r, 0x00);
|
||||
}
|
||||
|
||||
inline V128 V128_PMul01(const V128 l, const V128 r) {
|
||||
return _mm_clmulepi64_si128(l, r, 0x01);
|
||||
}
|
||||
|
||||
inline V128 V128_PMul10(const V128 l, const V128 r) {
|
||||
return _mm_clmulepi64_si128(l, r, 0x10);
|
||||
}
|
||||
|
||||
inline V128 V128_Xor(const V128 l, const V128 r) { return _mm_xor_si128(l, r); }
|
||||
|
||||
inline V128 V128_And(const V128 l, const V128 r) { return _mm_and_si128(l, r); }
|
||||
|
||||
inline V128 V128_From64WithZeroFill(const uint64_t r) {
|
||||
return _mm_set_epi64x(static_cast<int64_t>(0), static_cast<int64_t>(r));
|
||||
}
|
||||
|
||||
template <int imm>
|
||||
inline V128 V128_ShiftRight(const V128 l) {
|
||||
return _mm_srli_si128(l, imm);
|
||||
}
|
||||
|
||||
template <int imm>
|
||||
inline int V128_Extract32(const V128 l) {
|
||||
return _mm_extract_epi32(l, imm);
|
||||
}
|
||||
|
||||
template <int imm>
|
||||
inline uint64_t V128_Extract64(const V128 l) {
|
||||
return static_cast<uint64_t>(_mm_extract_epi64(l, imm));
|
||||
}
|
||||
|
||||
inline int64_t V128_Low64(const V128 l) { return _mm_cvtsi128_si64(l); }
|
||||
|
||||
inline V128 V128_Add64(const V128 l, const V128 r) {
|
||||
return _mm_add_epi64(l, r);
|
||||
}
|
||||
|
||||
#elif defined(ABSL_CRC_INTERNAL_HAVE_ARM_SIMD)
|
||||
|
||||
inline uint32_t CRC32_u8(uint32_t crc, uint8_t v) { return __crc32cb(crc, v); }
|
||||
|
||||
inline uint32_t CRC32_u16(uint32_t crc, uint16_t v) {
|
||||
return __crc32ch(crc, v);
|
||||
}
|
||||
|
||||
inline uint32_t CRC32_u32(uint32_t crc, uint32_t v) {
|
||||
return __crc32cw(crc, v);
|
||||
}
|
||||
|
||||
inline uint32_t CRC32_u64(uint32_t crc, uint64_t v) {
|
||||
return __crc32cd(crc, v);
|
||||
}
|
||||
|
||||
inline V128 V128_Load(const V128* src) {
|
||||
return vld1q_u64(reinterpret_cast<const uint64_t*>(src));
|
||||
}
|
||||
|
||||
inline V128 V128_LoadU(const V128* src) {
|
||||
return vld1q_u64(reinterpret_cast<const uint64_t*>(src));
|
||||
}
|
||||
|
||||
inline void V128_Store(V128* dst, V128 data) {
|
||||
vst1q_u64(reinterpret_cast<uint64_t*>(dst), data);
|
||||
}
|
||||
|
||||
// Using inline assembly as clang does not generate the pmull2 instruction and
|
||||
// performance drops by 15-20%.
|
||||
// TODO(b/193678732): Investigate why there is a slight performance hit when
|
||||
// using intrinsics instead of inline assembly.
|
||||
inline V128 V128_PMulHi(const V128 l, const V128 r) {
|
||||
uint64x2_t res;
|
||||
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t"
|
||||
: "=w"(res)
|
||||
: "w"(l), "w"(r));
|
||||
return res;
|
||||
}
|
||||
|
||||
// TODO(b/193678732): Investigate why the compiler decides to move the constant
|
||||
// loop multiplicands from GPR to Neon registers every loop iteration.
|
||||
inline V128 V128_PMulLow(const V128 l, const V128 r) {
|
||||
uint64x2_t res;
|
||||
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t"
|
||||
: "=w"(res)
|
||||
: "w"(l), "w"(r));
|
||||
return res;
|
||||
}
|
||||
|
||||
inline V128 V128_PMul01(const V128 l, const V128 r) {
|
||||
return reinterpret_cast<V128>(vmull_p64(
|
||||
reinterpret_cast<poly64_t>(vget_high_p64(vreinterpretq_p64_u64(l))),
|
||||
reinterpret_cast<poly64_t>(vget_low_p64(vreinterpretq_p64_u64(r)))));
|
||||
}
|
||||
|
||||
inline V128 V128_PMul10(const V128 l, const V128 r) {
|
||||
return reinterpret_cast<V128>(vmull_p64(
|
||||
reinterpret_cast<poly64_t>(vget_low_p64(vreinterpretq_p64_u64(l))),
|
||||
reinterpret_cast<poly64_t>(vget_high_p64(vreinterpretq_p64_u64(r)))));
|
||||
}
|
||||
|
||||
inline V128 V128_Xor(const V128 l, const V128 r) { return veorq_u64(l, r); }
|
||||
|
||||
inline V128 V128_And(const V128 l, const V128 r) { return vandq_u64(l, r); }
|
||||
|
||||
inline V128 V128_From64WithZeroFill(const uint64_t r){
|
||||
constexpr uint64x2_t kZero = {0, 0};
|
||||
return vsetq_lane_u64(r, kZero, 0);
|
||||
}
|
||||
|
||||
|
||||
template <int imm>
|
||||
inline V128 V128_ShiftRight(const V128 l) {
|
||||
return vreinterpretq_u64_s8(
|
||||
vextq_s8(vreinterpretq_s8_u64(l), vdupq_n_s8(0), imm));
|
||||
}
|
||||
|
||||
template <int imm>
|
||||
inline int V128_Extract32(const V128 l) {
|
||||
return vgetq_lane_s32(vreinterpretq_s32_u64(l), imm);
|
||||
}
|
||||
|
||||
template <int imm>
|
||||
inline uint64_t V128_Extract64(const V128 l) {
|
||||
return vgetq_lane_u64(l, imm);
|
||||
}
|
||||
|
||||
inline int64_t V128_Low64(const V128 l) {
|
||||
return vgetq_lane_s64(vreinterpretq_s64_u64(l), 0);
|
||||
}
|
||||
|
||||
inline V128 V128_Add64(const V128 l, const V128 r) { return vaddq_u64(l, r); }
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace crc_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_CRC_INTERNAL_CRC32_X86_ARM_COMBINED_SIMD_H_
|
||||
Loaded 100 of 205 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user