From 99fdfb260048961409643b2024f0524db42c5196 Mon Sep 17 00:00:00 2001 From: pszsh Date: Tue, 3 Mar 2026 17:40:26 -0800 Subject: [PATCH] Init. "MIDI library for pico-sdk, extracted from Control-Surface" --- AH/Arduino-Wrapper.h | 4 + AH/Containers/Array.hpp | 533 ++ AH/Containers/ArrayHelpers.hpp | 167 + AH/Containers/BitArray.hpp | 142 + AH/Containers/CRTP.hpp | 5 + AH/Containers/LinkedList.hpp | 341 + AH/Containers/Updatable.hpp | 191 + AH/Debug/Debug.cpp | 23 + AH/Debug/Debug.hpp | 195 + AH/Debug/DebugVal.hpp | 55 + AH/Error/Error.hpp | 40 + AH/Error/Exit.cpp | 20 + AH/Filters/EMA.hpp | 185 + AH/Filters/Hysteresis.hpp | 99 + AH/Hardware/ADCConfig.hpp | 7 + AH/Hardware/Arduino-Hardware-Types.hpp | 22 + AH/Hardware/Button.cpp | 64 + AH/Hardware/Button.hpp | 142 + AH/Hardware/ButtonMatrix.hpp | 94 + AH/Hardware/ButtonMatrix.ipp | 91 + .../ExtendedInputOutput/ExtendedIOElement.cpp | 45 + .../ExtendedInputOutput/ExtendedIOElement.hpp | 71 + .../ExtendedInputOutput.cpp | 175 + .../ExtendedInputOutput.hpp | 36 + AH/Hardware/FilteredAnalog.hpp | 321 + AH/Hardware/Hardware-Types.hpp | 67 + AH/Hardware/IncrementButton.cpp | 38 + AH/Hardware/IncrementButton.hpp | 77 + AH/Hardware/IncrementDecrementButtons.cpp | 73 + AH/Hardware/IncrementDecrementButtons.hpp | 95 + AH/Math/Divide.hpp | 58 + AH/Math/IncreaseBitDepth.hpp | 142 + AH/Math/MinMaxFix.hpp | 21 + AH/PrintStream/PrintStream.cpp | 281 + AH/PrintStream/PrintStream.hpp | 145 + AH/STL/Fallback/algorithm | 68 + AH/STL/Fallback/array | 399 ++ AH/STL/Fallback/backward/binders.h | 182 + AH/STL/Fallback/bits/algorithmfwd.h | 854 +++ AH/STL/Fallback/bits/alloc_traits.h | 605 ++ AH/STL/Fallback/bits/allocator.h | 238 + AH/STL/Fallback/bits/boost_concept_check.h | 788 +++ AH/STL/Fallback/bits/c++0x_warning.h | 37 + AH/STL/Fallback/bits/c++allocator.h | 55 + AH/STL/Fallback/bits/c++config.h | 1962 ++++++ AH/STL/Fallback/bits/concept_check.h | 81 + AH/STL/Fallback/bits/cpp_type_traits.h | 415 ++ AH/STL/Fallback/bits/cpu_defines.h | 33 + AH/STL/Fallback/bits/enable_special_members.h | 312 + AH/STL/Fallback/bits/exception_defines.h | 45 + AH/STL/Fallback/bits/functexcept.h | 165 + AH/STL/Fallback/bits/functional_hash.h | 274 + AH/STL/Fallback/bits/hash_bytes.h | 59 + AH/STL/Fallback/bits/invoke.h | 104 + AH/STL/Fallback/bits/memoryfwd.h | 78 + AH/STL/Fallback/bits/move.h | 225 + AH/STL/Fallback/bits/os_defines.h | 54 + AH/STL/Fallback/bits/predefined_ops.h | 362 + AH/STL/Fallback/bits/ptr_traits.h | 154 + AH/STL/Fallback/bits/range_access.h | 328 + AH/STL/Fallback/bits/std_abs.h | 110 + AH/STL/Fallback/bits/stl_algo.h | 5836 +++++++++++++++++ AH/STL/Fallback/bits/stl_algobase.h | 1423 ++++ AH/STL/Fallback/bits/stl_bvector.h | 1308 ++++ AH/STL/Fallback/bits/stl_construct.h | 235 + AH/STL/Fallback/bits/stl_function.h | 1130 ++++ AH/STL/Fallback/bits/stl_heap.h | 561 ++ AH/STL/Fallback/bits/stl_iterator.h | 1263 ++++ .../Fallback/bits/stl_iterator_base_funcs.h | 235 + .../Fallback/bits/stl_iterator_base_types.h | 241 + AH/STL/Fallback/bits/stl_numeric.h | 387 ++ AH/STL/Fallback/bits/stl_pair.h | 543 ++ AH/STL/Fallback/bits/stl_relops.h | 134 + AH/STL/Fallback/bits/stl_tempbuf.h | 278 + AH/STL/Fallback/bits/stl_uninitialized.h | 885 +++ AH/STL/Fallback/bits/stl_vector.h | 1662 +++++ AH/STL/Fallback/bits/uniform_int_dist.h | 375 ++ AH/STL/Fallback/bits/unique_ptr.h | 844 +++ AH/STL/Fallback/bits/uses_allocator.h | 186 + AH/STL/Fallback/bits/vector.tcc | 905 +++ AH/STL/Fallback/bitset | 1626 +++++ AH/STL/Fallback/climits | 59 + AH/STL/Fallback/cmath | 3169 +++++++++ AH/STL/Fallback/complex | 1991 ++++++ AH/STL/Fallback/cstddef | 191 + AH/STL/Fallback/cstdint | 89 + AH/STL/Fallback/cstdlib | 268 + AH/STL/Fallback/debug/assertions.h | 68 + AH/STL/Fallback/debug/debug.h | 125 + AH/STL/Fallback/ext/alloc_traits.h | 163 + AH/STL/Fallback/ext/new_allocator.h | 172 + AH/STL/Fallback/ext/numeric_traits.h | 138 + AH/STL/Fallback/ext/type_traits.h | 221 + AH/STL/Fallback/initializer_list | 107 + AH/STL/Fallback/iterator | 70 + AH/STL/Fallback/limits | 1827 ++++++ AH/STL/Fallback/memory | 8 + AH/STL/Fallback/new | 229 + AH/STL/Fallback/numeric | 165 + AH/STL/Fallback/optional | 1054 +++ AH/STL/Fallback/tuple | 1700 +++++ AH/STL/Fallback/type_traits | 3113 +++++++++ AH/STL/Fallback/utility | 407 ++ AH/STL/Fallback/vector | 80 + AH/STL/README.md | 2 + AH/STL/algorithm | 16 + AH/STL/array | 15 + AH/STL/bitset | 20 + AH/STL/climits | 11 + AH/STL/cmath | 61 + AH/STL/complex | 20 + AH/STL/cstddef | 15 + AH/STL/cstdint | 15 + AH/STL/cstdlib | 15 + AH/STL/initializer_list | 15 + AH/STL/iterator | 12 + AH/STL/limits | 15 + AH/STL/memory | 53 + AH/STL/new | 15 + AH/STL/numeric | 11 + AH/STL/optional | 17 + AH/STL/tuple | 11 + AH/STL/type_traits | 26 + AH/STL/utility | 27 + AH/STL/vector | 15 + AH/STL/vector.cpp | 12 + AH/Settings/NamespaceSettings.hpp | 22 + AH/Settings/Settings.hpp | 36 + AH/Settings/SettingsWrapper.hpp | 34 + AH/Settings/Warnings.hpp | 53 + AH/Timing/MillisMicrosTimer.hpp | 61 + AH/Types/Frequency.hpp | 32 + Banks/Bank.hpp | 169 + Banks/BankAddresses.hpp | 170 + Banks/BankConfig.hpp | 84 + Banks/BankableAddresses.hpp | 165 + Banks/Transposer.hpp | 41 + CMakeLists.txt | 47 + Control_Surface/Control_Surface_Class.cpp | 199 + Control_Surface/Control_Surface_Class.hpp | 92 + Def/Cable.cpp | 8 + Def/Cable.hpp | 154 + Def/Channel.cpp | 8 + Def/Channel.hpp | 156 + Def/Def.hpp | 58 + Def/MIDIAddress.cpp | 53 + Def/MIDIAddress.hpp | 360 + Def/TypeTraits.hpp | 31 + LICENSE | 674 ++ MIDI_Constants/Chords/Chords.hpp | 76 + MIDI_Constants/Chords/Intervals.hpp | 21 + MIDI_Constants/Control_Change.hpp | 119 + MIDI_Constants/Notes.hpp | 80 + MIDI_Constants/Program_Change.hpp | 149 + MIDI_Inputs/BankableMIDIMatcherHelpers.hpp | 231 + MIDI_Inputs/InterfaceMIDIInputElements.hpp | 119 + MIDI_Inputs/LEDs/NoteCCKPLED.hpp | 103 + MIDI_Inputs/MIDIInputElement.hpp | 152 + MIDI_Inputs/MIDIInputElementMatchers.hpp | 271 + MIDI_Inputs/NoteCCKPRange.hpp | 110 + MIDI_Inputs/NoteCCKPValue.hpp | 93 + MIDI_Inputs/PBValue.hpp | 75 + MIDI_Interfaces/BLEMIDI/BLEAPI.hpp | 168 + MIDI_Interfaces/BLEMIDI/BLEAPI.ipp | 87 + .../BLEMIDI/BLEMIDIPacketBuilder.cpp | 190 + .../BLEMIDI/BLEMIDIPacketBuilder.hpp | 237 + MIDI_Interfaces/BLEMIDI/BLERingBuf.hpp | 163 + .../BLEMIDI/BTstack/advertising.cpp | 65 + .../BLEMIDI/BTstack/advertising.hpp | 9 + MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp | 309 + MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.h | 65 + MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp | 11 + .../BLEMIDI/BTstack/hci_event_names.hpp | 426 ++ .../BLEMIDI/BTstackBackgroundBackend.hpp | 135 + .../BLEMIDI/BufferedBLEMIDIParser.hpp | 79 + .../BLEMIDI/PollingBLEMIDISender.hpp | 79 + .../BLEMIDI/PollingBLEMIDISender.ipp | 59 + MIDI_Interfaces/BLEMIDI/Util/compat.hpp | 57 + MIDI_Interfaces/GenericBLEMIDI_Interface.hpp | 115 + MIDI_Interfaces/GenericBLEMIDI_Interface.ipp | 168 + MIDI_Interfaces/MIDI_Callbacks.hpp | 254 + MIDI_Interfaces/MIDI_Interface.cpp | 55 + MIDI_Interfaces/MIDI_Interface.hpp | 218 + MIDI_Interfaces/MIDI_Pipes.cpp | 367 ++ MIDI_Interfaces/MIDI_Pipes.hpp | 737 +++ MIDI_Interfaces/MIDI_Sender.hpp | 179 + MIDI_Interfaces/MIDI_Sender.ipp | 255 + MIDI_Interfaces/MIDI_Staller.hpp | 56 + MIDI_Outputs/Abstract/EncoderState.hpp | 48 + MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp | 75 + MIDI_Outputs/Abstract/MIDIButton.hpp | 39 + MIDI_Outputs/Abstract/MIDIButtonLatched.hpp | 50 + MIDI_Outputs/Abstract/MIDIButtonLatching.hpp | 38 + MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp | 56 + MIDI_Outputs/Abstract/MIDIButtons.hpp | 65 + MIDI_Outputs/Abstract/MIDIChordButton.hpp | 59 + MIDI_Outputs/Abstract/MIDIFilteredAnalog.hpp | 47 + .../MIDIIncrementDecrementButtons.hpp | 77 + MIDI_Outputs/Abstract/MIDIOutputElement.hpp | 18 + MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp | 58 + MIDI_Outputs/CCAbsoluteEncoder.hpp | 16 + MIDI_Outputs/CCButton.hpp | 14 + MIDI_Outputs/CCButtonLatched.hpp | 15 + MIDI_Outputs/CCButtonLatching.hpp | 15 + MIDI_Outputs/CCButtonMatrix.hpp | 21 + MIDI_Outputs/CCButtons.hpp | 18 + MIDI_Outputs/CCIncrementDecrementButtons.hpp | 22 + MIDI_Outputs/CCPotentiometer.hpp | 14 + MIDI_Outputs/CCRotaryEncoder.hpp | 26 + MIDI_Outputs/NoteButton.hpp | 17 + MIDI_Outputs/NoteButtonLatched.hpp | 17 + MIDI_Outputs/NoteButtonLatching.hpp | 17 + MIDI_Outputs/NoteButtonMatrix.hpp | 24 + MIDI_Outputs/NoteButtons.hpp | 21 + MIDI_Outputs/NoteChordButton.hpp | 20 + MIDI_Outputs/PBAbsoluteEncoder.hpp | 16 + MIDI_Outputs/PBPotentiometer.hpp | 14 + MIDI_Outputs/PCButton.hpp | 13 + MIDI_Outputs/ProgramChanger.hpp | 26 + MIDI_Parsers/AnyMIDI_Message.hpp | 42 + MIDI_Parsers/BLEMIDIParser.hpp | 113 + MIDI_Parsers/MIDIReadEvent.hpp | 36 + MIDI_Parsers/MIDI_MessageTypes.cpp | 37 + MIDI_Parsers/MIDI_MessageTypes.hpp | 419 ++ MIDI_Parsers/MIDI_Parser.hpp | 44 + MIDI_Parsers/SerialMIDI_Parser.cpp | 229 + MIDI_Parsers/SerialMIDI_Parser.hpp | 113 + MIDI_Parsers/SysExBuffer.cpp | 36 + MIDI_Parsers/SysExBuffer.hpp | 38 + MIDI_Parsers/USBMIDI_Parser.hpp | 126 + MIDI_Senders/ContinuousCCSender.hpp | 32 + MIDI_Senders/DigitalCCSender.hpp | 29 + MIDI_Senders/DigitalNoteSender.hpp | 25 + MIDI_Senders/PitchBendSender.hpp | 24 + MIDI_Senders/ProgramChangeSender.hpp | 15 + MIDI_Senders/RelativeCCSender.cpp | 7 + MIDI_Senders/RelativeCCSender.hpp | 59 + Selectors/EncoderSelector.hpp | 86 + Selectors/IncrementDecrementSelector.hpp | 82 + Selectors/IncrementSelector.hpp | 74 + Selectors/LEDs/SelectorLEDs.hpp | 218 + Selectors/ManyButtonsSelector.hpp | 71 + Selectors/ProgramChangeSelector.hpp | 57 + Selectors/Selectable.hpp | 43 + Selectors/Selector.hpp | 160 + Selectors/SwitchSelector.hpp | 60 + Settings/NamespaceSettings.hpp | 31 + Settings/Settings.hpp | 27 + Settings/SettingsWrapper.hpp | 15 + Submodules/Encoder/AHEncoder.cpp | 102 + Submodules/Encoder/AHEncoder.hpp | 48 + Submodules/Encoder/AHEncoder.ipp | 63 + Submodules/Encoder/AtomicPosition.hpp | 33 + Submodules/Encoder/DirectPinRead.hpp | 19 + Submodules/Encoder/NumInterrupts.hpp | 12 + cs_midi.h | 78 + platform/pico_shim.h | 236 + 257 files changed, 60706 insertions(+) create mode 100644 AH/Arduino-Wrapper.h create mode 100644 AH/Containers/Array.hpp create mode 100644 AH/Containers/ArrayHelpers.hpp create mode 100644 AH/Containers/BitArray.hpp create mode 100644 AH/Containers/CRTP.hpp create mode 100644 AH/Containers/LinkedList.hpp create mode 100644 AH/Containers/Updatable.hpp create mode 100644 AH/Debug/Debug.cpp create mode 100644 AH/Debug/Debug.hpp create mode 100644 AH/Debug/DebugVal.hpp create mode 100644 AH/Error/Error.hpp create mode 100644 AH/Error/Exit.cpp create mode 100644 AH/Filters/EMA.hpp create mode 100644 AH/Filters/Hysteresis.hpp create mode 100644 AH/Hardware/ADCConfig.hpp create mode 100644 AH/Hardware/Arduino-Hardware-Types.hpp create mode 100644 AH/Hardware/Button.cpp create mode 100644 AH/Hardware/Button.hpp create mode 100644 AH/Hardware/ButtonMatrix.hpp create mode 100644 AH/Hardware/ButtonMatrix.ipp create mode 100644 AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp create mode 100644 AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp create mode 100644 AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp create mode 100644 AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp create mode 100755 AH/Hardware/FilteredAnalog.hpp create mode 100644 AH/Hardware/Hardware-Types.hpp create mode 100644 AH/Hardware/IncrementButton.cpp create mode 100644 AH/Hardware/IncrementButton.hpp create mode 100644 AH/Hardware/IncrementDecrementButtons.cpp create mode 100644 AH/Hardware/IncrementDecrementButtons.hpp create mode 100644 AH/Math/Divide.hpp create mode 100644 AH/Math/IncreaseBitDepth.hpp create mode 100644 AH/Math/MinMaxFix.hpp create mode 100644 AH/PrintStream/PrintStream.cpp create mode 100644 AH/PrintStream/PrintStream.hpp create mode 100644 AH/STL/Fallback/algorithm create mode 100644 AH/STL/Fallback/array create mode 100644 AH/STL/Fallback/backward/binders.h create mode 100644 AH/STL/Fallback/bits/algorithmfwd.h create mode 100644 AH/STL/Fallback/bits/alloc_traits.h create mode 100644 AH/STL/Fallback/bits/allocator.h create mode 100644 AH/STL/Fallback/bits/boost_concept_check.h create mode 100644 AH/STL/Fallback/bits/c++0x_warning.h create mode 100644 AH/STL/Fallback/bits/c++allocator.h create mode 100644 AH/STL/Fallback/bits/c++config.h create mode 100644 AH/STL/Fallback/bits/concept_check.h create mode 100644 AH/STL/Fallback/bits/cpp_type_traits.h create mode 100644 AH/STL/Fallback/bits/cpu_defines.h create mode 100644 AH/STL/Fallback/bits/enable_special_members.h create mode 100644 AH/STL/Fallback/bits/exception_defines.h create mode 100644 AH/STL/Fallback/bits/functexcept.h create mode 100644 AH/STL/Fallback/bits/functional_hash.h create mode 100644 AH/STL/Fallback/bits/hash_bytes.h create mode 100644 AH/STL/Fallback/bits/invoke.h create mode 100644 AH/STL/Fallback/bits/memoryfwd.h create mode 100644 AH/STL/Fallback/bits/move.h create mode 100644 AH/STL/Fallback/bits/os_defines.h create mode 100644 AH/STL/Fallback/bits/predefined_ops.h create mode 100644 AH/STL/Fallback/bits/ptr_traits.h create mode 100644 AH/STL/Fallback/bits/range_access.h create mode 100644 AH/STL/Fallback/bits/std_abs.h create mode 100644 AH/STL/Fallback/bits/stl_algo.h create mode 100644 AH/STL/Fallback/bits/stl_algobase.h create mode 100644 AH/STL/Fallback/bits/stl_bvector.h create mode 100644 AH/STL/Fallback/bits/stl_construct.h create mode 100644 AH/STL/Fallback/bits/stl_function.h create mode 100644 AH/STL/Fallback/bits/stl_heap.h create mode 100644 AH/STL/Fallback/bits/stl_iterator.h create mode 100644 AH/STL/Fallback/bits/stl_iterator_base_funcs.h create mode 100644 AH/STL/Fallback/bits/stl_iterator_base_types.h create mode 100644 AH/STL/Fallback/bits/stl_numeric.h create mode 100644 AH/STL/Fallback/bits/stl_pair.h create mode 100644 AH/STL/Fallback/bits/stl_relops.h create mode 100644 AH/STL/Fallback/bits/stl_tempbuf.h create mode 100644 AH/STL/Fallback/bits/stl_uninitialized.h create mode 100644 AH/STL/Fallback/bits/stl_vector.h create mode 100644 AH/STL/Fallback/bits/uniform_int_dist.h create mode 100644 AH/STL/Fallback/bits/unique_ptr.h create mode 100644 AH/STL/Fallback/bits/uses_allocator.h create mode 100644 AH/STL/Fallback/bits/vector.tcc create mode 100644 AH/STL/Fallback/bitset create mode 100644 AH/STL/Fallback/climits create mode 100644 AH/STL/Fallback/cmath create mode 100644 AH/STL/Fallback/complex create mode 100644 AH/STL/Fallback/cstddef create mode 100644 AH/STL/Fallback/cstdint create mode 100644 AH/STL/Fallback/cstdlib create mode 100644 AH/STL/Fallback/debug/assertions.h create mode 100644 AH/STL/Fallback/debug/debug.h create mode 100644 AH/STL/Fallback/ext/alloc_traits.h create mode 100644 AH/STL/Fallback/ext/new_allocator.h create mode 100644 AH/STL/Fallback/ext/numeric_traits.h create mode 100644 AH/STL/Fallback/ext/type_traits.h create mode 100644 AH/STL/Fallback/initializer_list create mode 100644 AH/STL/Fallback/iterator create mode 100644 AH/STL/Fallback/limits create mode 100644 AH/STL/Fallback/memory create mode 100644 AH/STL/Fallback/new create mode 100644 AH/STL/Fallback/numeric create mode 100644 AH/STL/Fallback/optional create mode 100644 AH/STL/Fallback/tuple create mode 100644 AH/STL/Fallback/type_traits create mode 100644 AH/STL/Fallback/utility create mode 100644 AH/STL/Fallback/vector create mode 100644 AH/STL/README.md create mode 100644 AH/STL/algorithm create mode 100644 AH/STL/array create mode 100644 AH/STL/bitset create mode 100644 AH/STL/climits create mode 100644 AH/STL/cmath create mode 100644 AH/STL/complex create mode 100644 AH/STL/cstddef create mode 100644 AH/STL/cstdint create mode 100644 AH/STL/cstdlib create mode 100644 AH/STL/initializer_list create mode 100644 AH/STL/iterator create mode 100644 AH/STL/limits create mode 100644 AH/STL/memory create mode 100644 AH/STL/new create mode 100644 AH/STL/numeric create mode 100644 AH/STL/optional create mode 100644 AH/STL/tuple create mode 100644 AH/STL/type_traits create mode 100644 AH/STL/utility create mode 100644 AH/STL/vector create mode 100644 AH/STL/vector.cpp create mode 100644 AH/Settings/NamespaceSettings.hpp create mode 100644 AH/Settings/Settings.hpp create mode 100644 AH/Settings/SettingsWrapper.hpp create mode 100644 AH/Settings/Warnings.hpp create mode 100644 AH/Timing/MillisMicrosTimer.hpp create mode 100644 AH/Types/Frequency.hpp create mode 100644 Banks/Bank.hpp create mode 100644 Banks/BankAddresses.hpp create mode 100644 Banks/BankConfig.hpp create mode 100644 Banks/BankableAddresses.hpp create mode 100644 Banks/Transposer.hpp create mode 100644 CMakeLists.txt create mode 100644 Control_Surface/Control_Surface_Class.cpp create mode 100644 Control_Surface/Control_Surface_Class.hpp create mode 100644 Def/Cable.cpp create mode 100644 Def/Cable.hpp create mode 100644 Def/Channel.cpp create mode 100644 Def/Channel.hpp create mode 100644 Def/Def.hpp create mode 100644 Def/MIDIAddress.cpp create mode 100644 Def/MIDIAddress.hpp create mode 100644 Def/TypeTraits.hpp create mode 100644 LICENSE create mode 100644 MIDI_Constants/Chords/Chords.hpp create mode 100644 MIDI_Constants/Chords/Intervals.hpp create mode 100644 MIDI_Constants/Control_Change.hpp create mode 100644 MIDI_Constants/Notes.hpp create mode 100644 MIDI_Constants/Program_Change.hpp create mode 100644 MIDI_Inputs/BankableMIDIMatcherHelpers.hpp create mode 100644 MIDI_Inputs/InterfaceMIDIInputElements.hpp create mode 100644 MIDI_Inputs/LEDs/NoteCCKPLED.hpp create mode 100644 MIDI_Inputs/MIDIInputElement.hpp create mode 100644 MIDI_Inputs/MIDIInputElementMatchers.hpp create mode 100644 MIDI_Inputs/NoteCCKPRange.hpp create mode 100644 MIDI_Inputs/NoteCCKPValue.hpp create mode 100644 MIDI_Inputs/PBValue.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BLEAPI.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BLEAPI.ipp create mode 100644 MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.cpp create mode 100644 MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BLERingBuf.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/advertising.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.h create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstack/hci_event_names.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BTstackBackgroundBackend.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/BufferedBLEMIDIParser.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.hpp create mode 100644 MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.ipp create mode 100644 MIDI_Interfaces/BLEMIDI/Util/compat.hpp create mode 100644 MIDI_Interfaces/GenericBLEMIDI_Interface.hpp create mode 100644 MIDI_Interfaces/GenericBLEMIDI_Interface.ipp create mode 100644 MIDI_Interfaces/MIDI_Callbacks.hpp create mode 100644 MIDI_Interfaces/MIDI_Interface.cpp create mode 100644 MIDI_Interfaces/MIDI_Interface.hpp create mode 100644 MIDI_Interfaces/MIDI_Pipes.cpp create mode 100644 MIDI_Interfaces/MIDI_Pipes.hpp create mode 100644 MIDI_Interfaces/MIDI_Sender.hpp create mode 100644 MIDI_Interfaces/MIDI_Sender.ipp create mode 100644 MIDI_Interfaces/MIDI_Staller.hpp create mode 100644 MIDI_Outputs/Abstract/EncoderState.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIButton.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIButtonLatched.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIButtonLatching.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIButtons.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIChordButton.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIFilteredAnalog.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIIncrementDecrementButtons.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIOutputElement.hpp create mode 100644 MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp create mode 100644 MIDI_Outputs/CCAbsoluteEncoder.hpp create mode 100644 MIDI_Outputs/CCButton.hpp create mode 100644 MIDI_Outputs/CCButtonLatched.hpp create mode 100644 MIDI_Outputs/CCButtonLatching.hpp create mode 100644 MIDI_Outputs/CCButtonMatrix.hpp create mode 100644 MIDI_Outputs/CCButtons.hpp create mode 100644 MIDI_Outputs/CCIncrementDecrementButtons.hpp create mode 100644 MIDI_Outputs/CCPotentiometer.hpp create mode 100644 MIDI_Outputs/CCRotaryEncoder.hpp create mode 100644 MIDI_Outputs/NoteButton.hpp create mode 100644 MIDI_Outputs/NoteButtonLatched.hpp create mode 100644 MIDI_Outputs/NoteButtonLatching.hpp create mode 100644 MIDI_Outputs/NoteButtonMatrix.hpp create mode 100644 MIDI_Outputs/NoteButtons.hpp create mode 100644 MIDI_Outputs/NoteChordButton.hpp create mode 100644 MIDI_Outputs/PBAbsoluteEncoder.hpp create mode 100644 MIDI_Outputs/PBPotentiometer.hpp create mode 100644 MIDI_Outputs/PCButton.hpp create mode 100644 MIDI_Outputs/ProgramChanger.hpp create mode 100644 MIDI_Parsers/AnyMIDI_Message.hpp create mode 100644 MIDI_Parsers/BLEMIDIParser.hpp create mode 100644 MIDI_Parsers/MIDIReadEvent.hpp create mode 100644 MIDI_Parsers/MIDI_MessageTypes.cpp create mode 100644 MIDI_Parsers/MIDI_MessageTypes.hpp create mode 100644 MIDI_Parsers/MIDI_Parser.hpp create mode 100644 MIDI_Parsers/SerialMIDI_Parser.cpp create mode 100644 MIDI_Parsers/SerialMIDI_Parser.hpp create mode 100644 MIDI_Parsers/SysExBuffer.cpp create mode 100644 MIDI_Parsers/SysExBuffer.hpp create mode 100644 MIDI_Parsers/USBMIDI_Parser.hpp create mode 100644 MIDI_Senders/ContinuousCCSender.hpp create mode 100644 MIDI_Senders/DigitalCCSender.hpp create mode 100644 MIDI_Senders/DigitalNoteSender.hpp create mode 100644 MIDI_Senders/PitchBendSender.hpp create mode 100644 MIDI_Senders/ProgramChangeSender.hpp create mode 100644 MIDI_Senders/RelativeCCSender.cpp create mode 100644 MIDI_Senders/RelativeCCSender.hpp create mode 100644 Selectors/EncoderSelector.hpp create mode 100644 Selectors/IncrementDecrementSelector.hpp create mode 100644 Selectors/IncrementSelector.hpp create mode 100644 Selectors/LEDs/SelectorLEDs.hpp create mode 100644 Selectors/ManyButtonsSelector.hpp create mode 100644 Selectors/ProgramChangeSelector.hpp create mode 100644 Selectors/Selectable.hpp create mode 100644 Selectors/Selector.hpp create mode 100644 Selectors/SwitchSelector.hpp create mode 100644 Settings/NamespaceSettings.hpp create mode 100644 Settings/Settings.hpp create mode 100644 Settings/SettingsWrapper.hpp create mode 100644 Submodules/Encoder/AHEncoder.cpp create mode 100644 Submodules/Encoder/AHEncoder.hpp create mode 100644 Submodules/Encoder/AHEncoder.ipp create mode 100644 Submodules/Encoder/AtomicPosition.hpp create mode 100644 Submodules/Encoder/DirectPinRead.hpp create mode 100644 Submodules/Encoder/NumInterrupts.hpp create mode 100644 cs_midi.h create mode 100644 platform/pico_shim.h diff --git a/AH/Arduino-Wrapper.h b/AH/Arduino-Wrapper.h new file mode 100644 index 0000000..51ca753 --- /dev/null +++ b/AH/Arduino-Wrapper.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include "../platform/pico_shim.h" diff --git a/AH/Containers/Array.hpp b/AH/Containers/Array.hpp new file mode 100644 index 0000000..0028762 --- /dev/null +++ b/AH/Containers/Array.hpp @@ -0,0 +1,533 @@ +/* ✔ */ + +#pragma once + +#include +#include +#include // conditional +#include // size_t + +BEGIN_AH_NAMESPACE + +template +constexpr T abs_diff(const T &a, const T &b) { + return a < b ? b - a : a - b; +} + +/// @addtogroup AH_Containers +/// @{ + +template +class ArraySlice; + +/** + * @brief An array wrapper for easy copying, comparing, and iterating. + * + * @tparam T + * The type of the elements in the array. + * @tparam N + * The number of elements in the array. + */ +template +struct Array { + T data[N]; + using type = T; + constexpr static size_t length = N; + + /** + * @brief Get the element at the given index. + * + * @note Bounds checking is performed. If fatal errors are disabled, the + * last element is returned if the index is out of bounds. + * + * @param index + * The (zero-based) index of the element to return. + */ + T &operator[](size_t index) { + if (index >= N) { // TODO + ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDED); + index = N - 1; // LCOV_EXCL_LINE + } // LCOV_EXCL_LINE + return data[index]; + } + + /** + * @brief Get the element at the given index. + * + * @note Bounds checking is performed. If fatal errors are disabled, the + * last element is returned if the index is out of bounds. + * + * @param index + * The (zero-based) index of the element to return. + */ + const T &operator[](size_t index) const { + if (index >= N) { // TODO + ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDED); + index = N - 1; // LCOV_EXCL_LINE + } // LCOV_EXCL_LINE + return data[index]; + } + + /** + * @brief Get a pointer to the first element. + */ + T *begin() { return &data[0]; } + + /** + * @brief Get a pointer to the first element. + */ + const T *begin() const { return &data[0]; } + + /** + * @brief Get a pointer to the memory beyond the array. + */ + T *end() { return &data[N]; } + + /** + * @brief Get a pointer to the memory beyond the array. + */ + const T *end() const { return &data[N]; } + + /** + * @brief Check the equality of all elements in two arrays. + * + * @param rhs + * The array to compare this array to. + */ + bool operator==(const Array &rhs) const { + if (this == &rhs) + return true; + for (size_t i = 0; i < N; i++) + if ((*this)[i] != rhs[i]) + return false; + return true; + } + + /** + * @brief Check the inequality of all elements in two arrays. + * + * @param rhs + * The array to compare this array to. + */ + bool operator!=(const Array &rhs) const { return !(*this == rhs); } + + public: + /** + * @brief Get a view on a slice of the Array. + * + * Doesn't copy the contents of the array, it's just a reference to the + * original array. + * + * @tparam Start + * The start index of the slice. + * @tparam End + * The end index of the slice. + */ + template + ArraySlice slice(); + + /** + * @brief Get a read-only view on a slice of the Array. + * @copydetails slice() + */ + template + ArraySlice slice() const; + + /** + * @brief Get a read-only view on a slice of the Array. + * @copydetails slice() + */ + template + ArraySlice + cslice() const { + const Array *This = this; + return This->template slice(); + } +}; + +/** + * @brief Class for a view on a slice of an array. + * + * Doesn't copy the contents of the array, it's just a reference to the original + * array. + * + * @tparam T + * The type of elements of the Array. + * @tparam N + * The size of the slice. + * @tparam Reverse + * Whether the slice is reversed or not. + * @tparam Const + * Whether to save a read-only or mutable reference to the Array. + */ +template +class ArraySlice { + using ElementRefType = + typename std::conditional::type; + using ElementPtrType = + typename std::conditional::type; + + public: + /// Constructor + ArraySlice(ElementPtrType array) : array {array} {} + + /// Implicit conversion from slice to new array (creates a copy). + operator Array() const { return asArray(); } + + Array asArray() const { + Array slice = {{}}; + for (size_t i = 0; i < N; ++i) + slice[i] = (*this)[i]; + return slice; + } + + using iterator = typename std::conditional< + Reverse, std::reverse_iterator, ElementPtrType>::type; + + /** + * @brief Get the element at the given index. + * + * @note Bounds checking is performed. If fatal errors are disabled, the + * last element is returned if the index is out of bounds. + * + * @param index + * The (zero-based) index of the element to return. + */ + ElementRefType operator[](size_t index) const { + if (index >= N) { // TODO + ERROR(F("Index out of bounds: ") << index << F(" ≥ ") << N, 0xEDEF); + index = N - 1; // LCOV_EXCL_LINE + } // LCOV_EXCL_LINE + if (Reverse) + return *(array - index); + else + return *(array + index); + } + + iterator begin() const { + if (Reverse) + return iterator {array + 1}; + else + return iterator {array}; + } + + iterator end() const { + if (Reverse) + return iterator {array + 1 - N}; + else + return iterator {array + N}; + } + + template + ArraySlice + slice() const; + + private: + ElementPtrType array; +}; + +template +template +auto Array::slice() + -> ArraySlice { + static_assert(Start < N, ""); + static_assert(End < N, ""); + return &(*this)[Start]; +} + +template +template +auto Array::slice() const + -> ArraySlice { + static_assert(Start < N, ""); + static_assert(End < N, ""); + return &(*this)[Start]; +} + +template +template +auto ArraySlice::slice() const + -> ArraySlice { + static_assert(Start < N, ""); + static_assert(End < N, ""); + return &(*this)[Start]; +} + +/// @related ArraySlice::iterator +template +typename ArraySlice::iterator operator+( + typename ArraySlice::iterator::difference_type n, + typename ArraySlice::iterator a) { + return a + n; +} + +// Equality :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice == Slice +/// @related ArraySlice +template +bool operator==(ArraySlice a, + ArraySlice b) { + static_assert(N1 == N2, "Error: sizes do not match"); + for (size_t i = 0; i < N1; ++i) + if (a[i] != b[i]) + return false; + return true; +} + +/// Array == Slice +/// @related ArraySlice +template +bool operator==(const Array &a, + ArraySlice b) { + return a.slice() == b; +} + +/// Slice == Array +/// @related ArraySlice +template +bool operator==(ArraySlice a, + const Array &b) { + return a == b.slice(); +} + +// Inequality :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice != Slice +/// @related ArraySlice +template +bool operator!=(ArraySlice a, + ArraySlice b) { + return !(a == b); +} + +/// Array != Slice +/// @related ArraySlice +template +bool operator!=(const Array &a, + ArraySlice b) { + return a.slice() != b; +} + +/// Slice != Array +/// @related ArraySlice +template +bool operator!=(ArraySlice a, + const Array &b) { + return a != b.slice(); +} + +// Addition :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice + Slice +/// @related ArraySlice +template +Array +operator+(ArraySlice a, + ArraySlice b) { + static_assert(N1 == N2, "Error: sizes do not match"); + Array result = {{}}; + for (size_t i = 0; i < N1; ++i) + result[i] = a[i] + b[i]; + return result; +} + +/// Array + Array +/// @related Array +template +Array operator+(const Array &a, + const Array &b) { + return a.slice() + b.slice(); +} + +/// Slice += Slice +/// @related ArraySlice +template +const ArraySlice & +operator+=(const ArraySlice &a, + const ArraySlice &b) { + static_assert(N1 == N2, "Error: sizes do not match"); + for (size_t i = 0; i < N1; ++i) + a[i] += b[i]; + return a; +} + +/// Array += Array +/// @related Array +template +Array &operator+=(Array &a, const Array &b) { + a.slice() += b.slice(); + return a; +} + +// Subtraction ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice - Slice +/// @related ArraySlice +template +Array +operator-(ArraySlice a, + ArraySlice b) { + static_assert(N1 == N2, "Error: sizes do not match"); + Array result = {{}}; + for (size_t i = 0; i < N1; ++i) + result[i] = a[i] - b[i]; + return result; +} + +/// Array - Array +/// @related Array +template +Array operator-(const Array &a, + const Array &b) { + return a.slice() - b.slice(); +} + +/// Slice -= Slice +/// @related ArraySlice +template +const ArraySlice & +operator-=(const ArraySlice &a, + const ArraySlice &b) { + static_assert(N1 == N2, "Error: sizes do not match"); + for (size_t i = 0; i < N1; ++i) + a[i] -= b[i]; + return a; +} + +/// Array -= Array +/// @related Array +template +Array &operator-=(Array &a, const Array &b) { + a.slice() -= b.slice(); + return a; +} + +// Scalar Multiplication ::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice * Scalar +/// @related ArraySlice +template +Array +operator*(ArraySlice a, T2 b) { + Array result = {{}}; + for (size_t i = 0; i < N1; ++i) + result[i] = a[i] * b; + return result; +} + +/// Array * Scalar +/// @related Array +template +Array operator*(const Array &a, T2 b) { + return a.slice() * b; +} + +/// Scalar * Slice +/// @related ArraySlice +template +Array +operator*(T1 a, ArraySlice b) { + Array result = {{}}; + for (size_t i = 0; i < N2; ++i) + result[i] = a * b[i]; + return result; +} + +/// Scalar * Array +/// @related Array +template +Array operator*(T1 a, const Array &b) { + return a * b.slice(); +} + +/// Slice *= Scalar +/// @related ArraySlice +template +const ArraySlice & +operator*=(const ArraySlice &a, T2 b) { + for (size_t i = 0; i < N1; ++i) + a[i] *= b; + return a; +} + +/// Array *= Scalar +/// @related Array +template +Array &operator*=(Array &a, T2 b) { + a.slice() *= b; + return a; +} + +// Scalar Division ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Slice / Scalar +/// @related ArraySlice +template +Array +operator/(ArraySlice a, T2 b) { + Array result = {{}}; + for (size_t i = 0; i < N1; ++i) + result[i] = a[i] / b; + return result; +} + +/// Array / Scalar +/// @related Array +template +Array operator/(const Array &a, T2 b) { + return a.slice() / b; +} + +/// Slice /= Scalar +/// @related ArraySlice +template +const ArraySlice & +operator/=(const ArraySlice &a, T2 b) { + for (size_t i = 0; i < N1; ++i) + a[i] /= b; + return a; +} + +/// Array /= Scalar +/// @related Array +template +Array &operator/=(Array &a, T2 b) { + a.slice() /= b; + return a; +} + +// Negation :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// -Slice +/// @related ArraySlice +template +Array operator-(ArraySlice a) { + Array result = {{}}; + for (size_t i = 0; i < N; ++i) + result[i] = -a[i]; + return result; +} + +/// -Array +/// @related Array +template +Array operator-(const Array &a) { + return -a.slice(); +} + +// Type aliases :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// An easy alias for two-dimensional Arrays. +template +using Array2D = Array, NumRows>; + +/// @} + +END_AH_NAMESPACE diff --git a/AH/Containers/ArrayHelpers.hpp b/AH/Containers/ArrayHelpers.hpp new file mode 100644 index 0000000..e1673a4 --- /dev/null +++ b/AH/Containers/ArrayHelpers.hpp @@ -0,0 +1,167 @@ +#pragma once + +#include "Array.hpp" +#include + +#if __cplusplus >= 201400L +#define USE_CONSTEXPR_ARRAY_HELPERS constexpr +#else +#define USE_CONSTEXPR_ARRAY_HELPERS +#endif + +BEGIN_AH_NAMESPACE + +namespace detail { + +template +class Incrementor { + public: + USE_CONSTEXPR_ARRAY_HELPERS Incrementor(T start = 0, V increment = 1) + : value(start), increment(increment) {} + USE_CONSTEXPR_ARRAY_HELPERS T operator()() { + T temp = value; + value += increment; + return temp; + } + + private: + T value; + const V increment; +}; + +} // namespace detail + +template +USE_CONSTEXPR_ARRAY_HELPERS Array generateArray(G generator) { + Array array{{}}; + std::generate(array.begin(), array.end(), generator); + return array; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS auto generateArray(G generator) + -> Array { + Array array{{}}; + std::generate(array.begin(), array.end(), generator); + return array; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array copyAs(const Array &src) { + Array dest{{}}; + std::transform(std::begin(src), std::end(src), std::begin(dest), + [](const U &src) { return T(src); }); + return dest; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +apply(const Array &src, F f) { + Array dest{{}}; + std::transform(std::begin(src), std::end(src), std::begin(dest), f); + return dest; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array fillArray(Args... args) { + return generateArray([&]() { return T{args...}; }); +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +generateIncrementalArray(U start = 0, V increment = V(1)) { + detail::Incrementor g(start, increment); + return generateArray(g); +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array cat(const Array &a, + const Array &b) { + Array result{{}}; + size_t r = 0; + for (size_t i = 0; i < M; ++i, ++r) + result[r] = a[i]; + for (size_t i = 0; i < N; ++i, ++r) + result[r] = b[i]; + return result; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +distribute(const ArraySlice &a, + const ArraySlice &b) { + Array result = {{}}; + for (size_t i = 0; i < N1; ++i) + for (size_t j = 0; j < N2; ++j) + result[i + j] += a[i] * b[j]; + return result; +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +distribute(const ArraySlice &a, + const Array &b) { + return distribute(a, b.slice()); +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +distribute(const Array &a, + const ArraySlice &b) { + return distribute(a.slice(), b); +} + +template +USE_CONSTEXPR_ARRAY_HELPERS Array +distribute(const Array &a, const Array &b) { + return distribute(a.slice(), b.slice()); +} + +END_AH_NAMESPACE + +#ifndef ARDUINO + +#include + +BEGIN_AH_NAMESPACE + +template +std::enable_if_t::value, std::ostream &> +operator<<(std::ostream &os, const AH::ArraySlice &a) { + for (const T &el : a.template slice<0, N - 2>()) + os << el << ", "; + os << a[N - 1]; + return os; +} + +template +std::enable_if_t::value, std::ostream &> +operator<<(std::ostream &os, const AH::Array &a) { + return os << a.slice(); +} + +END_AH_NAMESPACE + +#endif + +#include + +BEGIN_AH_NAMESPACE + +template +std::enable_if_t::value, Print &> +operator<<(Print &os, const AH::ArraySlice &a) { + for (const T &el : a.template slice<0, N - 2>()) + os << el << ", "; + os << a[N - 1]; + return os; +} + +template +std::enable_if_t::value, Print &> +operator<<(Print &os, const AH::Array &a) { + return os << a.slice(); +} + +END_AH_NAMESPACE diff --git a/AH/Containers/BitArray.hpp b/AH/Containers/BitArray.hpp new file mode 100644 index 0000000..ad3a6a5 --- /dev/null +++ b/AH/Containers/BitArray.hpp @@ -0,0 +1,142 @@ +/* ✔ */ + +#pragma once + +#include +#include +#include + +BEGIN_AH_NAMESPACE + +/// @addtogroup AH_Containers +/// @{ + +/** + * @brief A class for arrays of bits. + * + * @tparam N + * The number of bits. + */ +template +class BitArray { + public: + /** + * @brief Get the value of the given bit. + * + * @param bitIndex + * The (zero-based) index of the bit to read. + */ + bool get(uint16_t bitIndex) const { + return buffer[getBufferIndex(bitIndex)] & getBufferMask(bitIndex); + } + + /** + * @brief Set the value of the given bit to 1. + * + * @param bitIndex + * The (zero-based) index of the bit to set. + */ + void set(uint16_t bitIndex) { + buffer[getBufferIndex(bitIndex)] |= getBufferMask(bitIndex); + } + + /** + * @brief Clear the value of the given bit to 0. + * + * @param bitIndex + * The (zero-based) index of the bit to clear. + */ + void clear(uint16_t bitIndex) { + buffer[getBufferIndex(bitIndex)] &= ~getBufferMask(bitIndex); + } + + /** + * @brief Set the value of the given bit to the given state. + * + * @param bitIndex + * The (zero-based) index of the bit to set. + * @param state + * The value to set the bit to. + */ + void set(uint16_t bitIndex, bool state) { + state ? set(bitIndex) : clear(bitIndex); + } + + /** + * @brief Check the given byte index, and return it if it is within the + * bounds of the array, otherwise, throw an error, and return + * the last valid index. + * + * @param byteIndex + * The index to check. + */ + uint16_t safeIndex(uint16_t byteIndex) const { + if (byteIndex >= getBufferLength()) { + ERROR(F("Error: index out of bounds (") + << byteIndex << F(", length is ") << getBufferLength() + << ')', + 0xFFFF); + return getBufferLength() - 1; // LCOV_EXCL_LINE + } + return byteIndex; + } + + /** + * @brief Get the byte at the given index. + * + * This function can be used to quickly access all of the bits, to send + * them out to a shift register, for example. + * + * @note No bounds checking is performed. + * + * @param byteIndex + * The index of the byte within the array. + */ + const uint8_t &getByte(uint16_t byteIndex) const { + return buffer[byteIndex]; + // return buffer[safeIndex(byteIndex)]; + } + /// @copydoc AH::BitArray::getByte(uint16_t) const + uint8_t &getByte(uint16_t byteIndex) { + return buffer[byteIndex]; + // return buffer[safeIndex(byteIndex)]; + } + + /** + * @brief Set the byte at the given index. + * + * This function can be used to quickly write all of the bits, when reading + * them in from an I/O expander, for example. + * + * @note No bounds checking is performed. + * + * @param byteIndex + * The index of the byte within the array. + * @param value + * The byte to write. + */ + void setByte(uint16_t byteIndex, uint8_t value) { + buffer[byteIndex] = value; + } + + /** + * @brief Get the buffer length in bytes. + */ + uint16_t getBufferLength() const { return bufferLength; } + + private: + uint16_t getBufferIndex(uint16_t bitIndex) const { + return safeIndex(bitIndex / 8); + } + uint8_t getBufferBit(uint16_t bitIndex) const { return bitIndex % 8; } + uint8_t getBufferMask(uint16_t bitIndex) const { + return 1 << getBufferBit(bitIndex); + } + + constexpr static uint16_t bufferLength = (uint16_t)((N + 7) / 8); + uint8_t buffer[bufferLength] = {}; +}; + +/// @} + +END_AH_NAMESPACE diff --git a/AH/Containers/CRTP.hpp b/AH/Containers/CRTP.hpp new file mode 100644 index 0000000..97f4280 --- /dev/null +++ b/AH/Containers/CRTP.hpp @@ -0,0 +1,5 @@ +#pragma once + +/// Helper for the Curiously Recurring Template Pattern. +#define CRTP(Derived) (*static_cast(this)) +#define CRTP_INST(Derived, el) (static_cast(el)) diff --git a/AH/Containers/LinkedList.hpp b/AH/Containers/LinkedList.hpp new file mode 100644 index 0000000..0d9558e --- /dev/null +++ b/AH/Containers/LinkedList.hpp @@ -0,0 +1,341 @@ +/* ✔ */ + +#pragma once + +#include +#include +#include + +#include + +/// @addtogroup AH_Containers +/// @{ + +/** + * @brief A class for doubly linked lists. + * + * @tparam Node + * The type of the nodes of the list. + */ +template +class DoublyLinkedList { + public: + /// Base class for doubly linked list iterators + template + class node_iterator_base { + public: + node_iterator_base(INode *node) : node(node) {} + + bool operator!=(const node_iterator_base &rhs) const { + return node != rhs.node; + } + + bool operator==(const node_iterator_base &rhs) const { + return !(*this != rhs); + } + + INode &operator*() const { + // TODO: check node != nullptr + return *node; + } + + INode *operator->() const { + // TODO: check node != nullptr + return node; + } + + protected: + INode *node; + }; + + /// Forward bidirectional doubly linked list iterator + template + class node_iterator : public node_iterator_base { + public: + node_iterator(INode *node) : node_iterator_base(node) {} + + using difference_type = long; + using value_type = INode; + using pointer = INode *; + using reference = INode &; + using iterator_category = std::bidirectional_iterator_tag; + + /// Prefix increment operator + node_iterator &operator++() { + // TODO: check node != nullptr + this->node = this->node->next; + return *this; + } + + /// Prefix decrement operator + node_iterator &operator--() { + // TODO: check node != nullptr + this->node = this->node->previous; + return *this; + } + }; + + /// Reverse bidirectional doubly linked list iterator + template + class reverse_node_iterator : public node_iterator_base { + public: + reverse_node_iterator(INode *node) : node_iterator_base(node) {} + + using difference_type = long; + using value_type = INode; + using pointer = INode *; + using reference = INode &; + using iterator_category = std::bidirectional_iterator_tag; + + /// Prefix increment operator + reverse_node_iterator &operator++() { + // TODO: check node != nullptr + this->node = this->node->previous; + return *this; + } + + /// Prefix decrement operator + reverse_node_iterator &operator--() { + // TODO: check node != nullptr + this->node = this->node->next; + return *this; + } + }; + + using iterator = node_iterator; + using const_iterator = node_iterator; + using reverse_iterator = reverse_node_iterator; + using const_reverse_iterator = reverse_node_iterator; + + /** + * @brief Append a node to a linked list. + * + * @param node + * A pointer to the node to be appended. + */ + void append(Node *node) { + if (first == nullptr) + first = node; + node->previous = last; + if (node->previous != nullptr) + node->previous->next = node; + last = node; + node->next = nullptr; + } + + /** + * @brief Append a node to a linked list. + * + * @param node + * A reference to the node to be appended. + */ + void append(Node &node) { append(&node); } + + /** + * @brief Insert a node before another node. + * + * @param toBeInserted + * The new node to be inserted. + * @param before + * The node to insert the new node before. It must be in the list + * already. + */ + void insertBefore(Node *toBeInserted, Node *before) { + if (before == first) + first = toBeInserted; + else + before->previous->next = toBeInserted; + toBeInserted->previous = before->previous; + toBeInserted->next = before; + before->previous = toBeInserted; + } + + /// @see insertBefore(Node *, Node *) + void insertBefore(Node &toBeInserted, Node &before) { + insertBefore(&toBeInserted, &before); + } + + /** + * @brief Insert a new node at the correct location into a sorted list. + * + * @param node + * The new node to be inserted. + * @param cmp + * The function to order the nodes. + * @tparam Compare + * A functor that compares two Nodes and returns a boolean. + */ + template + void insertSorted(Node *node, Compare cmp) { + iterator it = this->begin(); + iterator end = this->end(); + while (it != end) { + if (cmp(*node, *it)) { + insertBefore(*node, *it); + return; + } + ++it; + } + append(node); + } + + /** + * @brief Insert a new node at the correct location into a sorted list, + * using `operator<`. + * + * @param node + * The new node to be inserted. + */ + void insertSorted(Node *node) { + insertSorted(node, [](Node &lhs, Node &rhs) { return lhs < rhs; }); + } + + /** + * @brief Remove a node from the linked list. + * + * @param node + * A pointer to the node to be removed. + */ + void remove(Node *node) { + if (node->previous != nullptr) + node->previous->next = node->next; + if (node == last) + last = node->previous; + if (node->next != nullptr) + node->next->previous = node->previous; + if (node == first) + first = node->next; + node->previous = nullptr; + node->next = nullptr; + } + + /** + * @brief Remove a node from the linked list. + * + * @param node + * A reference to the node to be removed. + */ + void remove(Node &node) { remove(&node); } + + /** + * @brief Move down the given node in the linked list. + * + * For example: moving down node `C`: + * ``` + * Before: ... → A → B → C → D → ... + * After: ... → A → C → B → D → ... + * ``` + * @param node + * A pointer to the node to be moved down. + */ + void moveDown(Node *node) { + Node *nodeB = node->previous; + if (nodeB == nullptr) // Can't move first node further down + return; + Node *nodeA = nodeB->previous; + Node *nodeD = node->next; + + if (nodeA != nullptr) + nodeA->next = node; + else + first = node; + nodeB->next = nodeD; + nodeB->previous = node; + node->next = nodeB; + node->previous = nodeA; + if (nodeD != nullptr) + nodeD->previous = nodeB; + else + last = nodeB; + } + + /** + * @brief Move down the given node in the linked list. + * + * For example: moving down node `C`: + * ``` + * Before: ... → A → B → C → D → ... + * After: ... → A → C → B → D → ... + * ``` + * @param node + * A reference to the node to be moved down. + */ + void moveDown(Node &node) { moveDown(&node); } + + /** + * @brief Check if the linked list could contain the given node. + * + * @retval true + * The given node is part of some linked list or it is the first + * node of the given linked list. + * It could be that the node is part of a different linked list + * if it was ever added to a different list. + * However, **if this function returns true and the node was never + * added to another linked list, it means that this linked list + * contains the given node**. + * @retval false + * The given node is not part of any linked list, or it is the + * only element of a different linked list. + */ + bool couldContain(const Node *node) const { + return node && (node == first || node->next != nullptr || + node->previous != nullptr); + } + + /// @copydoc DoublyLinkedList::couldContain(const Node *) const + bool couldContain(const Node &node) const { return couldContain(&node); } + + iterator begin() { return {first}; } + iterator end() { return {nullptr}; } + + const_iterator begin() const { return {first}; } + const_iterator end() const { return {nullptr}; } + + reverse_iterator rbegin() { return {last}; } + reverse_iterator rend() { return {nullptr}; } + + const_reverse_iterator rbegin() const { return {last}; } + const_reverse_iterator rend() const { return {nullptr}; } + + /// Get a pointer to the first node. + Node *getFirst() const { return first; } + /// Get a pointer to the last node. + Node *getLast() const { return last; } + + private: + Node *first = nullptr; + Node *last = nullptr; +}; + +/** + * @brief A class that can be inherited from to allow inserting into a + * DoublyLinkedList. + * @tparam Node + * The type of the nodes of the list. + */ +template +class DoublyLinkable { + protected: + friend class DoublyLinkedList; + Node *next = nullptr; + Node *previous = nullptr; + virtual ~DoublyLinkable() = default; + + DoublyLinkable() = default; + DoublyLinkable(const DoublyLinkable &) { + // Don't copy the pointers + } + DoublyLinkable &operator=(const DoublyLinkable &) { + // Don't copy the pointers + return *this; + } + DoublyLinkable(DoublyLinkable &&) { + // Don't swap the pointers + } + DoublyLinkable &operator=(DoublyLinkable &&) { + // Don't swap the pointers + return *this; + } +}; + +/// @} diff --git a/AH/Containers/Updatable.hpp b/AH/Containers/Updatable.hpp new file mode 100644 index 0000000..7ca74a9 --- /dev/null +++ b/AH/Containers/Updatable.hpp @@ -0,0 +1,191 @@ +/* ✔ */ + +#pragma once + +#include +#include +#include +#include +#include // std::forward +#include +#include + +BEGIN_AH_NAMESPACE + +/** + * @brief A super class for object that have to be updated regularly. + * + * All instances of this class are kept in a linked list, so it's easy to + * iterate over all of them to update them. + * + * This version uses static polymorphism using the Curiously Recurring Template + * Pattern. This requires less virtual function calls. + * (Only the destructor is virtual.) + * + * @nosubgrouping + */ +template +class UpdatableCRTP : public DoublyLinkable { + + public: +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif + + // When a Derived instance is constructed, the base class constructor + // UpdatableCRTP is called first. Because the Derived constructor hasn't + // been run yet, the dynamic type is just Updatable, not yet Derived. + // The undefined behavior sanitizer checks this dynamic type when the this + // pointer is casted to Derived using the CRTP macro, and thus causes an + // error. + // The constructor only casts and stores the pointer, it doesn't dereference + // it to call any of Derived methods, so I don't think that it's undefined + // behavior (and I don't know of a better way to do this). + // Also see https://stackoverflow.com/q/61061051/6356744 + + protected: + /// Constructor: create an Updatable and add it to the linked list of + /// instances. + UpdatableCRTP() __attribute__((no_sanitize("undefined"))) { + updatables.append(CRTP(Derived)); + } + + UpdatableCRTP(const UpdatableCRTP &) + __attribute__((no_sanitize("undefined"))) + : DoublyLinkable() { + updatables.append(CRTP(Derived)); + } + UpdatableCRTP &operator=(const UpdatableCRTP &) { return *this; } + + UpdatableCRTP(UpdatableCRTP &&) __attribute__((no_sanitize("undefined"))) { + updatables.append(CRTP(Derived)); + } + UpdatableCRTP &operator=(UpdatableCRTP &&) { return *this; } + + public: + /// Destructor: remove the updatable from the linked list of instances. + virtual ~UpdatableCRTP() __attribute__((no_sanitize("undefined"))) { + if (updatables.couldContain(CRTP(Derived))) + updatables.remove(CRTP(Derived)); + } + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif + + public: + /// @name Main initialization and updating methods + /// @{ + + template + static void __attribute__((always_inline)) + applyToAll(void (Derived::*method)(Args...), Args... args) { + for (auto &el : updatables) + (el.*method)(args...); + } + + /// @} + + public: + /// @name Enabling and disabling updatables + /// @{ + + /// Enable this updatable: insert it into the linked list of instances, + /// so it gets updated automatically + void enable() { + if (isEnabled()) { + ERROR(F("Error: This element is already enabled."), 0x1212); + return; // LCOV_EXCL_LINE + } + updatables.append(CRTP(Derived)); + } + + /// Disable this updatable: remove it from the linked list of instances, + /// so it no longer gets updated automatically + void disable() { + if (!isEnabled()) { + ERROR(F("Error: This element is already disabled."), 0x1213); + return; // LCOV_EXCL_LINE + } + updatables.remove(CRTP(Derived)); + } + + /** + * @brief Check if this updatable is enabled. + * + * @note Assumes that the updatable is not added to a different linked + * list by the user. + */ + bool isEnabled() const { + return updatables.couldContain(CRTP(const Derived)); + } + + /// @copydoc enable() + static void enable(UpdatableCRTP *element) { element->enable(); } + /// @copydoc enable() + static void enable(UpdatableCRTP &element) { element.enable(); } + /// @copydoc enable() + template + static void enable(U (&array)[N]) { + for (U &el : array) + enable(el); + } + + /// @copydoc disable() + static void disable(UpdatableCRTP *element) { element->disable(); } + /// @copydoc disable() + static void disable(UpdatableCRTP &element) { element.disable(); } + /// @copydoc disable() + template + static void disable(U (&array)[N]) { + for (U &el : array) + disable(el); + } + + /// Move down this element in the list. + void moveDown() { updatables.moveDown(CRTP(Derived)); } + + /// @} + + protected: + static DoublyLinkedList updatables; +}; + +template +DoublyLinkedList UpdatableCRTP::updatables; + +struct NormalUpdatable {}; + +/** + * @brief A super class for object that have to be updated regularly. + * + * All instances of this class are kept in a linked list, so it's easy to + * iterate over all of them to update them. + * + * @nosubgrouping + */ +template +class Updatable : public UpdatableCRTP> { + public: + /// @name Main initialization and updating methods + /// @{ + + /// Initialize this updatable. + virtual void begin() = 0; + + /// Update this updatable. + virtual void update() = 0; + + /// Begin all enabled instances of this class + /// @see begin() + static void beginAll() { Updatable::applyToAll(&Updatable::begin); } + + /// Update all enabled instances of this class + /// @see update() + static void updateAll() { Updatable::applyToAll(&Updatable::update); } + + /// @} +}; + +END_AH_NAMESPACE diff --git a/AH/Debug/Debug.cpp b/AH/Debug/Debug.cpp new file mode 100644 index 0000000..e9cad2d --- /dev/null +++ b/AH/Debug/Debug.cpp @@ -0,0 +1,23 @@ +#include "Debug.hpp" + +#ifdef DEBUG_OUT +#pragma message("Debugging enabled on output " DEBUG_STR(DEBUG_OUT)) + +#ifndef ARDUINO +BEGIN_AH_NAMESPACE +const decltype(std::chrono::high_resolution_clock::now()) start_time = + std::chrono::high_resolution_clock::now(); +END_AH_NAMESPACE +#endif + +#endif + +#if defined(ESP32) +BEGIN_AH_NAMESPACE +std::mutex debugmutex; +END_AH_NAMESPACE +#elif defined(ARDUINO_ARCH_MBED) +BEGIN_AH_NAMESPACE +rtos::Mutex debugmutex; +END_AH_NAMESPACE +#endif \ No newline at end of file diff --git a/AH/Debug/Debug.hpp b/AH/Debug/Debug.hpp new file mode 100644 index 0000000..6a8b876 --- /dev/null +++ b/AH/Debug/Debug.hpp @@ -0,0 +1,195 @@ +#pragma once + +/// @file + +#include +#include + +#ifndef FLUSH_ON_EVERY_DEBUG_STATEMENT +#if !(defined(ESP32) || defined(ESP8266)) + +/// Should the output stream be flushed after each debug statement? +/// Enabling this feature can slow things down significantly, and is not +/// supported on ESP32 / ESP8266. +/// +/// @todo I should probably use Streams instead of Prints, so Espressif boards +/// can flush as well. +#define FLUSH_ON_EVERY_DEBUG_STATEMENT 0 + +#else + +#define FLUSH_ON_EVERY_DEBUG_STATEMENT 0 + +#endif +#endif + +#if defined(ESP32) +#include +#elif defined(ARDUINO_ARCH_MBED) +#include +#include +#endif + +// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +#ifdef ARDUINO + +// Uncomment this line to override Arduino debug output +// #define DEBUG_OUT Serial + +#else + +// Uncomment this line to override PC tests debug output +// #define DEBUG_OUT std::cout + +#endif + +// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +#if FLUSH_ON_EVERY_DEBUG_STATEMENT +#define DEBUG_ENDL endl +#else +#define DEBUG_ENDL "\r\n" +#endif + +#if (defined(ESP32) || defined(ESP8266)) && FLUSH_ON_EVERY_DEBUG_STATEMENT +#error "ESP32 and ESP8266 don't support flushing `Print` objects" +#endif + +// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +#define DEBUG_STR_HELPER(x) #x +#define DEBUG_STR(x) DEBUG_STR_HELPER(x) + +#define DEBUG_FUNC_LOCATION \ + '[' << __PRETTY_FUNCTION__ << F(" @ line " DEBUG_STR(__LINE__) "]:\t") +#define DEBUG_LOCATION "[" __FILE__ ":" DEBUG_STR(__LINE__) "]:\t" + +// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +#if defined(ESP32) +#define DEBUG_LOCK_MUTEX std::lock_guard lock(AH::debugmutex); +BEGIN_AH_NAMESPACE +extern std::mutex debugmutex; +END_AH_NAMESPACE +#elif defined(ARDUINO_ARCH_MBED) +#define DEBUG_LOCK_MUTEX std::lock_guard lock(AH::debugmutex); +BEGIN_AH_NAMESPACE +extern rtos::Mutex debugmutex; +END_AH_NAMESPACE +#else +#define DEBUG_LOCK_MUTEX +#endif + +// ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +/// Macro for printing an expression as a string, followed by its value. +/// The expression string is saved in PROGMEM using the `F(...)` macro. +/// @ingroup AH_Debug +#define NAMEDVALUE(x) F(DEBUG_STR(x) " = ") << x + +#ifdef DEBUG_OUT // Debugging enabled ========================================== + +/// Print an expression to the debug output if debugging is enabled. +/// @ingroup AH_Debug +#define DEBUG(x) \ + do { \ + DEBUG_LOCK_MUTEX \ + DEBUG_OUT << x << DEBUG_ENDL; \ + } while (0) + +/// Print an expression and its location (file and line number) to the debug +/// output if debugging is enabled. +/// The location is saved in PROGMEM using the `F(...)` macro. +/// @ingroup AH_Debug +#define DEBUGREF(x) \ + do { \ + DEBUG_LOCK_MUTEX \ + DEBUG_OUT << F(DEBUG_LOCATION) << x << DEBUG_ENDL; \ + } while (0) + +/// Print an expression and its function (function name and line number) to the +/// debug output if debugging is enabled. +/// The function name is saved in RAM. +/// @ingroup AH_Debug +#define DEBUGFN(x) \ + do { \ + DEBUG_LOCK_MUTEX \ + DEBUG_OUT << DEBUG_FUNC_LOCATION << x << DEBUG_ENDL; \ + } while (0) + +#ifdef ARDUINO + +/// Print an expression and the time since startup to the debug output if +/// debugging is enabled. +/// Format: `[hours:minutes:seconds.milliseconds]` +/// @ingroup AH_Debug +#define DEBUGTIME(x) \ + do { \ + DEBUG_LOCK_MUTEX \ + unsigned long t = millis(); \ + unsigned long h = t / (60UL * 60 * 1000); \ + unsigned long m = (t / (60UL * 1000)) % 60; \ + unsigned long s = (t / (1000UL)) % 60; \ + unsigned long ms = t % 1000; \ + const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \ + DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \ + << "]:\t" << x << DEBUG_ENDL; \ + } while (0) + +#else // !ARDUINO + +#include + +BEGIN_AH_NAMESPACE +extern const decltype(std::chrono::high_resolution_clock::now()) start_time; +END_AH_NAMESPACE + +#define DEBUGTIME(x) \ + do { \ + USING_AH_NAMESPACE; \ + using namespace std::chrono; \ + auto now = high_resolution_clock::now(); \ + unsigned long t = \ + duration_cast(now - start_time).count(); \ + unsigned long h = t / (60UL * 60 * 1000); \ + unsigned long m = (t / (60UL * 1000)) % 60; \ + unsigned long s = (t / (1000UL)) % 60; \ + unsigned long ms = t % 1000; \ + const char *ms_zeros = ms > 99 ? "" : (ms > 9 ? "0" : "00"); \ + DEBUG_OUT << '[' << h << ':' << m << ':' << s << '.' << ms_zeros << ms \ + << "]:\t" << x << DEBUG_ENDL; \ + } while (0) + +#endif // ARDUINO + +#include "DebugVal.hpp" + +/// Print multiple expressions and their values to the debug output if debugging +/// is enabled. +/// For example, `DEBUGVAL(1 + 1, digitalRead(2))` could print `1 + 1 = 2, +/// digitalRead(2) = 0`. +/// A maximum of 10 expressions is supported. +/// The expression strings are saved in PROGMEM using the `F(...)` macro. +/// @ingroup AH_Debug +#define DEBUGVAL(...) DEBUGVALN(COUNT(__VA_ARGS__))(__VA_ARGS__) + +#else // Debugging disabled ==================================================== + +#define DEBUG(x) \ + do { \ + } while (0) +#define DEBUGREF(x) \ + do { \ + } while (0) +#define DEBUGFN(x) \ + do { \ + } while (0) +#define DEBUGTIME(x) \ + do { \ + } while (0) +#define DEBUGVAL(...) \ + do { \ + } while (0) + +#endif diff --git a/AH/Debug/DebugVal.hpp b/AH/Debug/DebugVal.hpp new file mode 100644 index 0000000..6361da3 --- /dev/null +++ b/AH/Debug/DebugVal.hpp @@ -0,0 +1,55 @@ +#define COUNT(...) COUNT_HELPER(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1) +#define COUNT_HELPER(N1, N2, N3, N4, N5, N6, N7, N8, N9, N10, N, ...) N + +#define DEBUGVALN(N) DEBUGVALN_HELPER(N) +#define DEBUGVALN_HELPER(N) DEBUGVAL##N + +#define DEBUGVAL10(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL9(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL9(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL8(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL8(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL7(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL7(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL6(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL6(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL5(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL5(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL4(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL4(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL3(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL3(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL2(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL2(x, ...) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << ", "; \ + DEBUGVAL1(__VA_ARGS__); \ + } while (0) +#define DEBUGVAL1(x) \ + do { \ + DEBUG_OUT << NAMEDVALUE(x) << DEBUG_ENDL; \ + } while (0) diff --git a/AH/Error/Error.hpp b/AH/Error/Error.hpp new file mode 100644 index 0000000..3702ac8 --- /dev/null +++ b/AH/Error/Error.hpp @@ -0,0 +1,40 @@ +#pragma once + +/// @file + +#include + +BEGIN_AH_NAMESPACE + +/// Blinks the built-in LED and loops forever on fatal error. +extern void fatalErrorExit() __attribute__((noreturn)); + +END_AH_NAMESPACE + +#ifdef FATAL_ERRORS + +#define ERROR(msg, errc) \ + do { \ + USING_AH_NAMESPACE; \ + DEBUGFN(msg << " (0x" << hex << uppercase << errc << dec \ + << nouppercase << ')'); \ + fatalErrorExit(); \ + } while (0) + +#else + +#define ERROR(msg, errc) \ + do { \ + DEBUGFN(msg << " (0x" << hex << uppercase << errc << dec \ + << nouppercase << ')'); \ + } while (0) + +#endif + +#define FATAL_ERROR(msg, errc) \ + do { \ + USING_AH_NAMESPACE; \ + DEBUGFN(F("Fatal Error: ") << msg << " (0x" << hex << uppercase \ + << errc << dec << nouppercase << ')'); \ + fatalErrorExit(); \ + } while (0) diff --git a/AH/Error/Exit.cpp b/AH/Error/Exit.cpp new file mode 100644 index 0000000..504351c --- /dev/null +++ b/AH/Error/Exit.cpp @@ -0,0 +1,20 @@ +#include "Error.hpp" +#include + +BEGIN_AH_NAMESPACE + +void fatalErrorExit() { + pinMode(LED_BUILTIN, OUTPUT); + while (1) { + digitalWrite(LED_BUILTIN, HIGH); + sleep_ms(50); + digitalWrite(LED_BUILTIN, LOW); + sleep_ms(50); + digitalWrite(LED_BUILTIN, HIGH); + sleep_ms(50); + digitalWrite(LED_BUILTIN, LOW); + sleep_ms(850); + } +} + +END_AH_NAMESPACE diff --git a/AH/Filters/EMA.hpp b/AH/Filters/EMA.hpp new file mode 100644 index 0000000..be4b325 --- /dev/null +++ b/AH/Filters/EMA.hpp @@ -0,0 +1,185 @@ +#pragma once + +#include +#include +#include + +#include + +BEGIN_AH_NAMESPACE + +/** + * @brief Exponential moving average filter. + * + * Fast integer EMA implementation where the weight factor is a power of two. + * + * Difference equation: @f$ y[n] = \alpha·x[n]+(1-\alpha)·y[n-1] @f$ + * where @f$ \alpha = \left(\frac{1}{2}\right)^{K} @f$, @f$ x @f$ is the + * input sequence, and @f$ y @f$ is the output sequence. + * + * [An in-depth explanation of the EMA filter](https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/) + * + * @tparam K + * The amount of bits to shift by. This determines the location + * of the pole in the EMA transfer function, and therefore the + * cut-off frequency. + * The higher this number, the more filtering takes place. + * The pole location is @f$ 1 - 2^{-K} @f$. + * @tparam input_t + * The integer type to use for the input and output of the filter. + * Can be signed or unsigned. + * @tparam state_t + * The unsigned integer type to use for the internal state of the + * filter. A fixed-point representation with @f$ K @f$ fractional + * bits is used, so this type should be at least @f$ M + K @f$ bits + * wide, where @f$ M @f$ is the maximum number of bits of the input. + * + * Some examples of different combinations of template parameters: + * + * 1. Filtering the result of `analogRead`: analogRead returns an integer + * between 0 and 1023, which can be represented using 10 bits, so + * @f$ M = 10 @f$. If `input_t` and `output_t` are both `uint16_t`, + * the maximum shift factor `K` is @f$ 16 - M = 6 @f$. If `state_t` + * is increased to `uint32_t`, the maximum shift factor `K` is + * @f$ 32 - M = 22 @f$. + * 2. Filtering a signed integer between -32768 and 32767: this can be + * represented using a 16-bit signed integer, so `input_t` is `int16_t`, + * and @f$ M = 16 @f$. (2¹⁵ = 32768) + * Let's say the shift factor `K` is 1, then the minimum width of + * `state_t` should be @f$ M + K = 17 @f$ bits, so `uint32_t` would be + * a sensible choice. + * + * @ingroup AH_Filters + */ +template ::type> +class EMA { + public: + /// Constructor: initialize filter to zero or optional given value. + EMA(input_t initial = input_t{0}) { reset(initial); } + + /** + * @brief Reset the filter to the given value. + * + * @param value + * The value to reset the filter state to. + */ + void reset(input_t value = input_t(0)) { + state_t value_s = static_cast(value); + state = zero + (value_s << K) - value_s; + } + + /** + * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$. + * + * @param input + * The new raw input value. + * @return The new filtered output value. + */ + input_t filter(input_t input) { + state += static_cast(input); + state_t output = (state + half) >> K; + output -= zero >> K; + state -= output; + return static_cast(output); + } + + /// @copydoc EMA::filter(input_t) + input_t operator()(input_t input) { + return filter(input); + } + + constexpr static state_t + max_state = std::numeric_limits::max(), + half_state = max_state / 2 + 1, + zero = std::is_unsigned::value ? state_t{0} : half_state, + half = K > 0 ? state_t{1} << (K - 1) : state_t{0}; + + static_assert(std::is_unsigned::value, + "state type should be unsigned"); + + static_assert(max_state >= std::numeric_limits::max(), + "state type cannot be narrower than input type"); + + /// Verify the input range to make sure it's compatible with the shift + /// factor and the width of the state type. + /// + /// Examples: + /// ~~~cpp + /// EMA<5, int_fast16_t, uint_fast16_t> filter; + /// static_assert(filter.supports_range(-1024, 1023), + /// "use a wider state or input type, or a smaller shift factor"); + /// ~~~ + /// ~~~cpp + /// EMA<5, uint_fast16_t, uint_fast16_t> filter; + /// static_assert(filter.supports_range(0u, 2047u), + /// "use a wider state or input type, or a smaller shift factor"); + /// ~~~ + template + constexpr static bool supports_range(T min, T max) { + using sstate_t = typename std::make_signed::type; + return min <= max && + min >= std::numeric_limits::min() && + max <= std::numeric_limits::max() && + (std::is_unsigned::value + ? state_t(max) <= (max_state >> K) + : min >= -static_cast(max_state >> (K + 1)) - 1 && + max <= static_cast(max_state >> (K + 1))); + } + + private: + state_t state; +}; + +// -------------------------------------------------------------------------- // + +/** + * @brief A class for single-pole infinite impulse response filters + * or exponential moving average filters. + * + * This version uses floating point maths. + * + * Difference equation: @f$ y[n] = \alpha·x[n]+(1-\alpha)·y[n-1] @f$ + * @f$ x @f$ is the input sequence, and @f$ y @f$ is the output sequence. + * + * [An in-depth explanation of the EMA filter] + * (https://tttapa.github.io/Pages/Mathematics/Systems-and-Control-Theory/Digital-filters/Exponential%20Moving%20Average/) + * + * @ingroup AH_Filters + */ +class EMA_f { + public: + /** + * @brief Create an exponential moving average filter with a pole at the + * given location. + * + * @param pole + * The pole of the filter (@f$1-\alpha@f$). + * Should be a value in the range + * @f$ \left[0,1\right) @f$. + * Zero means no filtering, and closer to one means more filtering. + */ + EMA_f(float pole) : alpha(1 - pole) {} + + /** + * @brief Filter the input: Given @f$ x[n] @f$, calculate @f$ y[n] @f$. + * + * @param value + * The new raw input value. + * @return The new filtered output value. + */ + float filter(float value) { + filtered += (value - filtered) * alpha; + return filtered; + } + + /// @copydoc filter(float) + float operator()(float value) { return filter(value); } + + private: + float alpha; + float filtered = 0; +}; + +END_AH_NAMESPACE diff --git a/AH/Filters/Hysteresis.hpp b/AH/Filters/Hysteresis.hpp new file mode 100644 index 0000000..d12e7ea --- /dev/null +++ b/AH/Filters/Hysteresis.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include + +#include + +BEGIN_AH_NAMESPACE + +/// @addtogroup AH_Filters +/// @{ + +/** + * @brief A class for applying hysteresis to a given input. + * + * This reduces the noise by decreasing the resolution, and it prevents flipping + * back and forth between two values. + * + * An example for `BITS` = 7 and an input from 0 to 1023 + * ``` + * 7 ┌───◄───┬─── + * o 6 ┌───◄───┼───►───┘ + * u 5 ┌───◄───┼───►───┘ + * t 4 ┌───◄───┼───►───┘ + * p 3 ┌───◄───┼───►───┘ + * u 2 ┌───◄───┼───►───┘ + * t 1 ┌───◄───┼───►───┘ + * 0 ────┴───►───┘ + * 0 128 256 384 512 640 768 896 1023 + * i n p u t + * ``` + * + * @tparam BITS + * The number of bits to decrease in resolution. + * Increasing this number will result in a decrease in fluctuations. + */ +template +class Hysteresis { + public: + /** + * @brief Update the hysteresis output with a new input value. + * + * @param inputLevel + * The input to calculate the output level from. + * @retval true + * The output level has changed. + * @retval false + * The output level is still the same. + */ + bool update(T_in inputLevel) { + T_in prevLevelFull = (T_in(prevLevel) << Bits) | offset; + T_in lowerbound = prevLevel > 0 ? prevLevelFull - margin : 0; + T_in upperbound = prevLevel < max_out ? prevLevelFull + margin : max_in; + if (inputLevel < lowerbound || inputLevel > upperbound) { + setValue(inputLevel); + return true; + } + return false; + } + + /** + * @brief Get the current output level. + * + * @return The output level. + */ + T_out getValue() const { return prevLevel; } + + /** + * @brief Forcefully update the internal state to the given level. + */ + void setValue(T_in inputLevel) { prevLevel = inputLevel >> Bits; } + + private: + T_out prevLevel = 0; + constexpr static T_in margin = (1ul << Bits) - 1ul; + constexpr static T_in offset = Bits >= 1 ? 1ul << (Bits - 1) : 0; + constexpr static T_in max_in = static_cast(-1); + constexpr static T_out max_out = static_cast(max_in >> Bits); + static_assert(max_in > 0, "Error: only unsigned types are supported"); +}; + +template +class Hysteresis<0, T_in, T_out> { + public: + bool update(T_in inputLevel) { + bool changed = inputLevel != prevLevel; + prevLevel = inputLevel; + return changed; + } + + T_out getValue() const { return prevLevel; } + void setValue(T_in inputLevel) { prevLevel = inputLevel; } + + private: + T_in prevLevel = 0; +}; + +/// @} + +END_AH_NAMESPACE diff --git a/AH/Hardware/ADCConfig.hpp b/AH/Hardware/ADCConfig.hpp new file mode 100644 index 0000000..ebb4657 --- /dev/null +++ b/AH/Hardware/ADCConfig.hpp @@ -0,0 +1,7 @@ +#pragma once + +// RP2350 has a 12-bit SAR ADC +#ifndef ADC_RESOLUTION +#define ADC_RESOLUTION 12 +#endif +#define HAS_ANALOG_READ_RESOLUTION 1 diff --git a/AH/Hardware/Arduino-Hardware-Types.hpp b/AH/Hardware/Arduino-Hardware-Types.hpp new file mode 100644 index 0000000..b2adc54 --- /dev/null +++ b/AH/Hardware/Arduino-Hardware-Types.hpp @@ -0,0 +1,22 @@ +#pragma once + +// pico-sdk version: simple typedefs, no FunctionTraits introspection + +#include +#include +#include + +using ArduinoPin_t = uint8_t; +using PinStatus_t = uint8_t; +using PinMode_t = uint8_t; +using BitOrder_t = uint8_t; + +BEGIN_AH_NAMESPACE + +template +constexpr ArduinoPin_t arduino_pin_cast(T t) { + return static_cast(t); +} +constexpr ArduinoPin_t arduino_pin_cast(pin_t t) { return t.pin; } + +END_AH_NAMESPACE diff --git a/AH/Hardware/Button.cpp b/AH/Hardware/Button.cpp new file mode 100644 index 0000000..76ed08f --- /dev/null +++ b/AH/Hardware/Button.cpp @@ -0,0 +1,64 @@ +#include "Button.hpp" + +BEGIN_AH_NAMESPACE + +Button::Button(pin_t pin) : pin(pin) {} + +void Button::begin() { ExtIO::pinMode(pin, INPUT_PULLUP); } + +void Button::invert() { state.invert = true; } + +Button::State Button::update() { + // Read pin state and current time + bool input = ExtIO::digitalRead(pin) ^ state.invert; + unsigned long now = millis(); + // Check if enough time has elapsed after last bounce + if (state.bouncing) + state.bouncing = now - state.prevBounceTime <= debounceTime; + // Shift the debounced state one bit to the left, either appending the + // new input state if not bouncing, or repeat the old state if bouncing + bool prevState = state.debounced & 0b01; + bool newState = state.bouncing ? prevState : input; + state.debounced = (prevState << 1) | newState; + // Check if the input changed state (button pressed, released or bouncing) + if (input != state.prevInput) { + state.bouncing = true; + state.prevInput = input; + state.prevBounceTime = now; + } + return getState(); +} + +Button::State Button::getState() const { + return static_cast(state.debounced); +} + +FlashString_t Button::getName(Button::State state) { + switch (state) { + case Button::Pressed: return F("Pressed"); + case Button::Released: return F("Released"); + case Button::Falling: return F("Falling"); + case Button::Rising: return F("Rising"); + default: return F(""); // Keeps the compiler happy + } +} + +unsigned long Button::previousBounceTime() const { + return state.prevBounceTime; +} + +unsigned long Button::stableTime(unsigned long now) const { + return now - previousBounceTime(); +} + +unsigned long Button::stableTime() const { return stableTime(millis()); } + +void Button::setDebounceTime(unsigned long debounceTime) { + Button::debounceTime = debounceTime; +} + +unsigned long Button::getDebounceTime() { return Button::debounceTime; } + +unsigned long Button::debounceTime = BUTTON_DEBOUNCE_TIME; + +END_AH_NAMESPACE diff --git a/AH/Hardware/Button.hpp b/AH/Hardware/Button.hpp new file mode 100644 index 0000000..44d8949 --- /dev/null +++ b/AH/Hardware/Button.hpp @@ -0,0 +1,142 @@ +/* ✔ */ + +#pragma once + +#include +#include + +BEGIN_AH_NAMESPACE + +/** + * @brief A class for reading and debouncing buttons and switches. + * + * @ingroup AH_HardwareUtils + */ +class Button { + public: + /** + * @brief Construct a new Button object. + * + * **This constructor should not be used.** + * It is just a way to easily create arrays of buttons, and initializing + * them later. + */ + Button() : pin(NO_PIN) {} + + /** + * @brief Construct a new Button object. + * + * @param pin + * The digital pin to read from. The internal pull-up resistor + * will be enabled when `begin` is called. + */ + Button(pin_t pin); + /// @copydoc Button(pin_t) + Button(ArduinoPin_t pin) : Button(pin_t(pin)) {} + + /// @brief Initialize (enable the internal pull-up resistor). + void begin(); + + /** + * @brief Invert the input state of this button + * (button pressed is `HIGH` instead of `LOW`). + */ + void invert(); + + /// @brief An enumeration of the different states a button can be in. + enum State { + Pressed = 0b00, ///< Input went from low to low (0,0) + Released = 0b11, ///< Input went from high to high (1,1) + Falling = 0b10, ///< Input went from high to low (1,0) + Rising = 0b01 ///< Input went from low to high (0,1) + }; + + /** + * @brief Read the button and return its new state. + * + * The button is debounced, the debounce time can be set in + * Settings.hpp: #BUTTON_DEBOUNCE_TIME. + * + * ``` + * Debounce time: ├────┤ + * + * Raw input: + * HIGH ──────┐ ┌──────┐ ┌─┐ ┌─┐ ┌──────┐ ┌──────── + * LOW └──────┘ └─┘ └──────┘ └─┘ └─┘ + * ├────┤ ├────┤ ├─┼─┼────┤ ├─┼─┼────┤ ├─┼────┤ + * + * Debounced output: + * HIGH ──────┐ ┌──────┐ ┌──────────┐ ┌─── + * LOW └──────┘ └──────────┘ └──────┘ + * + * States: + * HIGH ────────────────┐ ┌───────────────── + * LOW └──────────────────┘ + * Released Falling Pressed Rising + * ``` + * + * @return The state of the button, either Button::Pressed, + * Button::Released, Button::Falling or Button::Rising. + */ + State update(); + + /** + * @brief Get the state of the button, without updating it. + * Returns the same value as the last call to @ref update. + * + * @return The state of the button, either Button::Pressed, + * Button::Released, Button::Falling or Button::Rising. + */ + State getState() const; + + /// @brief Return the name of the state as a string. + static FlashString_t getName(State state); + + /// Return the time point (in milliseconds) when the button last bounced. + unsigned long previousBounceTime() const; + + /// Return the time (in milliseconds) that the button has been stable for, + /// compared to the given time point. + unsigned long stableTime(unsigned long now) const; + + /// Return the time (in milliseconds) that the button has been stable for. + unsigned long stableTime() const; + + /** + * @brief Set the debounce time for all Button%s. + * + * @note This function affects **all** Button objects. + * + * @param debounceTime + * The new debounce time in milliseconds. + */ + static void + setDebounceTime(unsigned long debounceTime = BUTTON_DEBOUNCE_TIME); + + /** + * @brief Get the debounce time. + * @return The debounce time in milliseconds. + * @see setDebounceTime + */ + static unsigned long getDebounceTime(); + + private: + pin_t pin; + + struct InternalState { + InternalState() + : debounced(0b11), bouncing(true), prevInput(HIGH), invert(false), + prevBounceTime(0) {} + uint8_t debounced : 2; + bool bouncing : 1; + bool prevInput : 1; + bool invert : 1; + unsigned long prevBounceTime; + } state; + + /// Edit this in Settings.hpp + /// @see BUTTON_DEBOUNCE_TIME + static unsigned long debounceTime; +}; + +END_AH_NAMESPACE diff --git a/AH/Hardware/ButtonMatrix.hpp b/AH/Hardware/ButtonMatrix.hpp new file mode 100644 index 0000000..f1f5721 --- /dev/null +++ b/AH/Hardware/ButtonMatrix.hpp @@ -0,0 +1,94 @@ +/* ✔ */ + +#pragma once + +#include + +BEGIN_AH_NAMESPACE + +/** + * @brief A class that reads the states of a button matrix. + * + * @tparam NumRows + * The number of rows in the button matrix. + * @tparam NumCols + * The number of columns in the button matrix. + * + * @ingroup AH_HardwareUtils + */ +template +class ButtonMatrix { + public: + /** + * @brief Construct a new ButtonMatrix object. + * + * @param rowPins + * A list of pin numbers connected to the rows of the button + * matrix. + * **⚠** These pins will be driven LOW as outputs (Lo-Z). + * @param colPins + * A list of pin numbers connected to the columns of the button + * matrix. + * These pins will be used as inputs (Hi-Z), and the internal + * pull-up resistor will be enabled. + */ + ButtonMatrix(const PinList &rowPins, + const PinList &colPins); + + /** + * @brief Initialize (enable internal pull-up resistors on column pins). + */ + void begin(); + + /** + * @brief Scan the matrix, read all button states, and call the + * onButtonChanged callback. + */ + void update(); + + /** + * Get the state of the button in the given column and row. + * + * @note No bounds checking is performed. + */ + bool getPrevState(uint8_t col, uint8_t row); + + /// Configure the debounce time interval. Only one button can change in each + /// debounce interval. Time in milliseconds. + void setDebounceTime(unsigned long debounceTime) { + this->debounceTime = debounceTime; + } + /// Get the debounce time. + unsigned long getDebounceTime() const { return debounceTime; } + + protected: + /** + * @brief The callback function that is called whenever a button changes + * state. Implement this in the derived class. + * + * @param row + * The row of the button that changed state. + * @param col + * The column of the button that changed state. + * @param state + * The new state of the button. + */ + void onButtonChanged(uint8_t row, uint8_t col, bool state) = delete; + + private: + static inline uint8_t positionToBits(uint8_t col, uint8_t row); + static inline uint8_t bitsToIndex(uint8_t bits); + static inline uint8_t bitsToBitmask(uint8_t bits); + void setPrevState(uint8_t col, uint8_t row, bool state); + + unsigned long debounceTime = BUTTON_DEBOUNCE_TIME; + unsigned long prevRefresh = 0; + uint8_t prevStates[(NumCols * NumRows + 7) / 8]; + + const PinList rowPins; + const PinList colPins; +}; + +END_AH_NAMESPACE + +#include "ButtonMatrix.ipp" // Template implementations diff --git a/AH/Hardware/ButtonMatrix.ipp b/AH/Hardware/ButtonMatrix.ipp new file mode 100644 index 0000000..387fa65 --- /dev/null +++ b/AH/Hardware/ButtonMatrix.ipp @@ -0,0 +1,91 @@ +#include "ButtonMatrix.hpp" +#include +#include +#include + +BEGIN_AH_NAMESPACE + +template +ButtonMatrix::ButtonMatrix( + const PinList &rowPins, const PinList &colPins) + : rowPins(rowPins), colPins(colPins) { + memset(prevStates, 0xFF, sizeof(prevStates)); +} + +template +void ButtonMatrix::update() { + unsigned long now = millis(); + // only update 25 ms after previous change (crude software debounce). + // Edit this in Settings/Settings.hpp + if (now - prevRefresh < debounceTime) + return; + + for (size_t row = 0; row < NumRows; row++) { // scan through all rows + pinMode(rowPins[row], OUTPUT); // make the current row Lo-Z 0V +#if !defined(__AVR__) && defined(ARDUINO) + delayMicroseconds(SELECT_LINE_DELAY); +#endif + for (size_t col = 0; col < NumCols; col++) { // scan through all columns + bool state = digitalRead(colPins[col]); // read the state + if (state != getPrevState(col, row)) { + // if the state changed since last time + // execute the handler + CRTP(Derived).onButtonChanged(row, col, state); + setPrevState(col, row, state); // remember the state + prevRefresh = now; + } + } + pinMode(rowPins[row], INPUT); // make the current row Hi-Z again + } +} + +template +void ButtonMatrix::begin() { + // make all columns input pins and enable + // the internal pull-up resistors + for (const pin_t &colPin : colPins) + pinMode(colPin, INPUT_PULLUP); + // make all rows Hi-Z + for (const pin_t &rowPin : rowPins) + pinMode(rowPin, INPUT); +} + +template +inline uint8_t +ButtonMatrix::positionToBits(uint8_t col, + uint8_t row) { + // map from a 2D array of bits to a flat array of bits + return col * NumRows + row; +} + +template +inline uint8_t +ButtonMatrix::bitsToIndex(uint8_t bits) { + return bits >> 3; // bits / 8 +} + +template +inline uint8_t +ButtonMatrix::bitsToBitmask(uint8_t bits) { + return 1 << (bits & 7); // bits % 8 +} + +template +bool ButtonMatrix::getPrevState(uint8_t col, + uint8_t row) { + uint8_t bits = positionToBits(col, row); + return !!(prevStates[bitsToIndex(bits)] & bitsToBitmask(bits)); +} + +template +void ButtonMatrix::setPrevState(uint8_t col, + uint8_t row, + bool state) { + uint8_t bits = positionToBits(col, row); + if (state) + prevStates[bitsToIndex(bits)] |= bitsToBitmask(bits); + else + prevStates[bitsToIndex(bits)] &= ~bitsToBitmask(bits); +} + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp b/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp new file mode 100644 index 0000000..24e4c0a --- /dev/null +++ b/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp @@ -0,0 +1,45 @@ +#include "ExtendedIOElement.hpp" +#include +#include + +BEGIN_AH_NAMESPACE + +ExtendedIOElement::ExtendedIOElement(pin_int_t length) + : length(length), start(offset), end(offset + length) { + if (end > NO_PIN) + FATAL_ERROR(F("ExtIO ran out of pin numbers."), 0x00FF); + offset = end; +} + +void ExtendedIOElement::beginAll() { + ExtendedIOElement::applyToAll(&ExtendedIOElement::begin); +} + +void ExtendedIOElement::updateAllBufferedOutputs() { + ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedOutputs); +} + +void ExtendedIOElement::updateAllBufferedInputs() { + ExtendedIOElement::applyToAll(&ExtendedIOElement::updateBufferedInputs); +} + +pin_t ExtendedIOElement::pin(pin_int_t p) const { + if (p >= length) { + ERROR(F("Error: pin number out of range"), 0x4567); + return end - 1; + } + return p + start; +} + +pin_t ExtendedIOElement::operator[](pin_int_t p) const { return pin(p); } +pin_int_t ExtendedIOElement::getLength() const { return length; } +pin_t ExtendedIOElement::getEnd() const { return end; } +pin_t ExtendedIOElement::getStart() const { return start; } + +DoublyLinkedList &ExtendedIOElement::getAll() { + return updatables; +} + +pin_t ExtendedIOElement::offset = NUM_DIGITAL_PINS + NUM_ANALOG_INPUTS; + +END_AH_NAMESPACE diff --git a/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp b/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp new file mode 100644 index 0000000..58c88f7 --- /dev/null +++ b/AH/Hardware/ExtendedInputOutput/ExtendedIOElement.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include "ExtendedInputOutput.hpp" +#include +#include + +BEGIN_AH_NAMESPACE + +class ExtendedIOElement : public UpdatableCRTP { + protected: + ExtendedIOElement(pin_int_t length); + ExtendedIOElement(const ExtendedIOElement &) = delete; + ExtendedIOElement &operator=(const ExtendedIOElement &) = delete; + ExtendedIOElement(ExtendedIOElement &&) = default; + ExtendedIOElement &operator=(ExtendedIOElement &&) = delete; + + public: + virtual void pinMode(pin_int_t pin, PinMode_t mode) { + pinModeBuffered(pin, mode); + updateBufferedOutputs(); + } + virtual void pinModeBuffered(pin_int_t pin, PinMode_t mode) = 0; + + virtual void digitalWrite(pin_int_t pin, PinStatus_t state) { + digitalWriteBuffered(pin, state); + updateBufferedOutputs(); + } + virtual void digitalWriteBuffered(pin_int_t pin, PinStatus_t state) = 0; + + virtual PinStatus_t digitalRead(pin_int_t pin) { + updateBufferedInputs(); + return digitalReadBuffered(pin); + } + virtual PinStatus_t digitalReadBuffered(pin_int_t pin) = 0; + + virtual void analogWrite(pin_int_t pin, analog_t val) { + analogWriteBuffered(pin, val); + updateBufferedOutputs(); + } + virtual void analogWriteBuffered(pin_int_t pin, analog_t val) = 0; + + virtual analog_t analogRead(pin_int_t pin) { + updateBufferedInputs(); + return analogReadBuffered(pin); + } + virtual analog_t analogReadBuffered(pin_int_t pin) = 0; + + virtual void begin() = 0; + static void beginAll(); + + virtual void updateBufferedOutputs() = 0; + static void updateAllBufferedOutputs(); + + virtual void updateBufferedInputs() = 0; + static void updateAllBufferedInputs(); + + pin_t pin(pin_int_t pin) const; + pin_t operator[](pin_int_t pin) const; + pin_int_t getLength() const; + pin_t getEnd() const; + pin_t getStart() const; + static DoublyLinkedList &getAll(); + + private: + const pin_int_t length; + const pin_t start; + const pin_t end; + static pin_t offset; +}; + +END_AH_NAMESPACE diff --git a/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp b/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp new file mode 100644 index 0000000..b3accc3 --- /dev/null +++ b/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp @@ -0,0 +1,175 @@ +#include "ExtendedInputOutput.hpp" +#include "ExtendedIOElement.hpp" +#include + +BEGIN_AH_NAMESPACE + +namespace ExtIO { + +template +static bool inRange(T target, T start, T end) { + return target >= start && target < end; +} + +ExtendedIOElement *getIOElementOfPinOrNull(pin_t pin) { + for (auto &el : ExtendedIOElement::getAll()) + if (pin < el.getStart()) + break; + else if (inRange(pin, el.getStart(), el.getEnd())) + return ⪙ + return nullptr; +} + +ExtendedIOElement *getIOElementOfPin(pin_t pin) { + auto *el = getIOElementOfPinOrNull(pin); + if (el == nullptr) + FATAL_ERROR( + F("The given pin does not correspond to an Extended IO element."), + 0x8888); + return el; +} + +void pinMode(pin_t pin, PinMode_t mode) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::pinMode(arduino_pin_cast(pin), mode); + else { + auto el = getIOElementOfPin(pin); + el->pinMode(pin - el->getStart(), mode); + } +} + +void digitalWrite(pin_t pin, PinStatus_t val) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::digitalWrite(arduino_pin_cast(pin), val); + else { + auto el = getIOElementOfPin(pin); + el->digitalWrite(pin - el->getStart(), val); + } +} + +PinStatus_t digitalRead(pin_t pin) { + if (pin == NO_PIN) + return LOW; + else if (isNativePin(pin)) + return ::digitalRead(arduino_pin_cast(pin)); + else { + auto el = getIOElementOfPin(pin); + return el->digitalRead(pin - el->getStart()); + } +} + +analog_t analogRead(pin_t pin) { + if (pin == NO_PIN) + return 0; + else if (isNativePin(pin)) + return ::analogRead(arduino_pin_cast(pin)); + else { + auto el = getIOElementOfPin(pin); + return el->analogRead(pin - el->getStart()); + } +} + +void analogWrite(pin_t pin, analog_t val) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::analogWrite(arduino_pin_cast(pin), val); + else { + auto el = getIOElementOfPin(pin); + el->analogWrite(pin - el->getStart(), val); + } +} +void analogWrite(pin_t pin, int val) { analogWrite(pin, (analog_t)val); } + +void pinModeBuffered(pin_t pin, PinMode_t mode) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::pinMode(arduino_pin_cast(pin), mode); + else { + auto el = getIOElementOfPin(pin); + el->pinModeBuffered(pin - el->getStart(), mode); + } +} + +void digitalWriteBuffered(pin_t pin, PinStatus_t val) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::digitalWrite(arduino_pin_cast(pin), val); + else { + auto el = getIOElementOfPin(pin); + el->digitalWriteBuffered(pin - el->getStart(), val); + } +} + +PinStatus_t digitalReadBuffered(pin_t pin) { + if (pin == NO_PIN) + return LOW; + else if (isNativePin(pin)) + return ::digitalRead(arduino_pin_cast(pin)); + else { + auto el = getIOElementOfPin(pin); + return el->digitalReadBuffered(pin - el->getStart()); + } +} + +analog_t analogReadBuffered(pin_t pin) { + if (pin == NO_PIN) + return 0; + else if (isNativePin(pin)) + return ::analogRead(arduino_pin_cast(pin)); + else { + auto el = getIOElementOfPin(pin); + return el->analogReadBuffered(pin - el->getStart()); + } +} + +void analogWriteBuffered(pin_t pin, analog_t val) { + if (pin == NO_PIN) + return; + else if (isNativePin(pin)) + ::analogWrite(arduino_pin_cast(pin), val); + else { + auto el = getIOElementOfPin(pin); + el->analogWriteBuffered(pin - el->getStart(), val); + } +} +void analogWriteBuffered(pin_t pin, int val) { + analogWriteBuffered(pin, (analog_t)val); +} + +void shiftOut(pin_t dataPin, pin_t clockPin, BitOrder_t bitOrder, uint8_t val) { + if (dataPin == NO_PIN || clockPin == NO_PIN) + return; + if (isNativePin(dataPin) && isNativePin(clockPin)) { + ::shiftOut(arduino_pin_cast(dataPin), arduino_pin_cast(clockPin), + bitOrder, val); + } else if (!isNativePin(dataPin) && !isNativePin(clockPin)) { + auto dataEl = getIOElementOfPin(dataPin); + auto dataPinN = dataPin - dataEl->getStart(); + auto clockEl = getIOElementOfPin(clockPin); + auto clockPinN = clockPin - clockEl->getStart(); + for (uint8_t i = 0; i < 8; i++) { + uint8_t mask = bitOrder == LSBFIRST ? (1 << i) : (1 << (7 - i)); + dataEl->digitalWrite(dataPinN, (val & mask) ? HIGH : LOW); + clockEl->digitalWrite(clockPinN, HIGH); + clockEl->digitalWrite(clockPinN, LOW); + } + } else { + for (uint8_t i = 0; i < 8; i++) { + uint8_t mask = bitOrder == LSBFIRST ? (1 << i) : (1 << (7 - i)); + digitalWrite(dataPin, (val & mask) ? HIGH : LOW); + digitalWrite(clockPin, HIGH); + digitalWrite(clockPin, LOW); + } + } +} + +} // namespace ExtIO + +END_AH_NAMESPACE diff --git a/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp b/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp new file mode 100644 index 0000000..31eef6b --- /dev/null +++ b/AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +BEGIN_AH_NAMESPACE + +class ExtendedIOElement; + +namespace ExtIO { + +inline bool isNativePin(pin_t pin) { + return pin.pin < NUM_DIGITAL_PINS + NUM_ANALOG_INPUTS; +} + +ExtendedIOElement *getIOElementOfPinOrNull(pin_t pin); +ExtendedIOElement *getIOElementOfPin(pin_t pin); + +void pinMode(pin_t pin, PinMode_t mode); +void digitalWrite(pin_t pin, PinStatus_t val); +PinStatus_t digitalRead(pin_t pin); +analog_t analogRead(pin_t pin); +void analogWrite(pin_t pin, analog_t val); +void analogWrite(pin_t pin, int val); +void shiftOut(pin_t dataPin, pin_t clockPin, BitOrder_t bitOrder, uint8_t val); + +void pinModeBuffered(pin_t pin, PinMode_t mode); +void digitalWriteBuffered(pin_t pin, PinStatus_t val); +PinStatus_t digitalReadBuffered(pin_t pin); +analog_t analogReadBuffered(pin_t pin); +void analogWriteBuffered(pin_t pin, analog_t val); +void analogWriteBuffered(pin_t pin, int val); + +} // namespace ExtIO + +END_AH_NAMESPACE diff --git a/AH/Hardware/FilteredAnalog.hpp b/AH/Hardware/FilteredAnalog.hpp new file mode 100755 index 0000000..789bd11 --- /dev/null +++ b/AH/Hardware/FilteredAnalog.hpp @@ -0,0 +1,321 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include // std::enable_if, std::is_constructible +#include // std::forward +#include + +BEGIN_AH_NAMESPACE + +/** + * @brief Helper to determine how many of the remaining bits of the filter + * data types can be used to achieve higher precision. + */ +template +struct MaximumFilteredAnalogIncRes { + constexpr static uint8_t value = + min(sizeof(FilterType) * CHAR_BIT - ADC_BITS - FilterShiftFactor, + sizeof(AnalogType) * CHAR_BIT - ADC_BITS); +}; + +/** + * @brief FilteredAnalog base class with generic MappingFunction. + * + * @see FilteredAnalog + */ +template ::value> +class GenericFilteredAnalog { + public: + /** + * @brief Construct a new GenericFilteredAnalog object. + * + * @param analogPin + * The analog pin to read from. + * @param mapFn + * The mapping function + * @param initial + * The initial value of the filter. + */ + GenericFilteredAnalog(pin_t analogPin, MappingFunction mapFn, + AnalogType initial = 0) + : analogPin(analogPin), mapFn(std::forward(mapFn)), + filter(increaseBitDepth(initial)) {} + + /// @copydoc GenericFilteredAnalog::GenericFilteredAnalog(pin_t,MappingFunction,AnalogType) + GenericFilteredAnalog(ArduinoPin_t analogPin, MappingFunction mapFn, + AnalogType initial = 0) + : GenericFilteredAnalog(pin_t(analogPin), + std::forward(mapFn), initial) { + } + + /** + * @brief Reset the filter to the given value. + * + * @param value + * The value to reset the filter state to. + * + * @todo Should the filter be initialized to the first value that is read + * instead of to zero? This would require adding a `begin` method. + */ + void reset(AnalogType value = 0) { + AnalogType widevalue = increaseBitDepth(value); + filter.reset(widevalue); + hysteresis.setValue(widevalue); + } + + /** + * @brief Reset the filtered value to the value that's currently being + * measured at the analog input. + * + * This is useful to avoid transient effects upon initialization. + */ + void resetToCurrentValue() { + AnalogType widevalue = getRawValue(); + filter.reset(widevalue); + hysteresis.setValue(widevalue); + } + + /** + * @brief Specify a mapping function/functor that is applied to the analog + * value after filtering and before applying hysteresis. + * + * @param fn + * This functor should have a call operator that takes the filtered + * value (of ADC_BITS + IncRes bits wide) as a parameter, + * and returns a value of ADC_BITS + IncRes bits wide. + * + * @note Applying the mapping function before filtering could result in + * the noise being amplified to such an extent that filtering it + * afterwards would be ineffective. + * Applying it after hysteresis would result in a lower resolution. + * That's why the mapping function is applied after filtering and + * before hysteresis. + */ + void map(MappingFunction fn) { mapFn = std::forward(fn); } + + /** + * @brief Get a reference to the mapping function. + */ + MappingFunction &getMappingFunction() { return mapFn; } + /** + * @brief Get a reference to the mapping function. + */ + const MappingFunction &getMappingFunction() const { return mapFn; } + + /** + * @brief Read the analog input value, apply the mapping function, and + * update the average. + * + * @retval true + * The value changed since last time it was updated. + * @retval false + * The value is still the same. + */ + bool update() { + AnalogType input = getRawValue(); // read the raw analog input value + input = filter.filter(input); // apply a low-pass EMA filter + input = mapFnHelper(input); // apply the mapping function + return hysteresis.update(input); // apply hysteresis, and return true + // if the value changed since last time + } + + /** + * @brief Get the filtered value of the analog input (with the mapping + * function applied). + * + * @note This function just returns the value from the last call to + * @ref update, it doesn't read the analog input again. + * + * @return The filtered value of the analog input, as a number + * of `Precision` bits wide. + */ + AnalogType getValue() const { return hysteresis.getValue(); } + + /** + * @brief Get the filtered value of the analog input with the mapping + * function applied as a floating point number from 0.0 to 1.0. + * + * @return The filtered value of the analog input, as a number + * from 0.0 to 1.0. + */ + float getFloatValue() const { + return getValue() * (1.0f / (ldexpf(1.0f, Precision) - 1.0f)); + } + + /** + * @brief Read the raw value of the analog input without any filtering or + * mapping applied, but with its bit depth increased by @c IncRes. + */ + AnalogType getRawValue() const { + AnalogType value = ExtIO::analogRead(analogPin); +#ifdef ESP8266 + if (value > 1023) + value = 1023; +#endif + return increaseBitDepth(value); + } + + /** + * @brief Get the maximum value that can be returned from @ref getRawValue. + */ + constexpr static AnalogType getMaxRawValue() { + return (1ul << (ADC_BITS + IncRes)) - 1ul; + } + + /** + * @brief Select the configured ADC resolution. By default, it is set to + * the maximum resolution supported by the hardware. + * + * @see @ref ADC_BITS "ADC_BITS" + * @see @ref ADCConfig.hpp "ADCConfig.hpp" + */ + static void setupADC() { +#if HAS_ANALOG_READ_RESOLUTION + analogReadResolution(ADC_BITS); +#endif + } + + private: + /// Helper function that applies the mapping function if it's enabled. + /// This function is only enabled if MappingFunction is explicitly + /// convertible to bool. + template + typename std::enable_if::value, + AnalogType>::type + mapFnHelper(AnalogType input) { + return bool(mapFn) ? mapFn(input) : input; + } + + /// Helper function that applies the mapping function without checking if + /// it's enabled. + /// This function is only enabled if MappingFunction is not convertible to + /// bool. + template + typename std::enable_if::value, + AnalogType>::type + mapFnHelper(AnalogType input) { + return mapFn(input); + } + + private: + pin_t analogPin; + MappingFunction mapFn; + + using EMA_t = EMA; + + static_assert( + ADC_BITS + IncRes + FilterShiftFactor <= sizeof(FilterType) * CHAR_BIT, + "Error: FilterType is not wide enough to hold the maximum value"); + static_assert( + ADC_BITS + IncRes <= sizeof(AnalogType) * CHAR_BIT, + "Error: AnalogType is not wide enough to hold the maximum value"); + static_assert( + Precision <= ADC_BITS + IncRes, + "Error: Precision is larger than the increased ADC precision"); + static_assert(EMA_t::supports_range(AnalogType(0), getMaxRawValue()), + "Error: EMA filter type doesn't support full ADC range"); + + EMA_t filter; + Hysteresis + hysteresis; +}; + +/** + * @brief A class that reads and filters an analog input. + * + * A map function can be applied to the analog value (e.g. to compensate for + * logarithmic taper potentiometers or to calibrate the range). The analog input + * value is filtered using an exponential moving average filter. The default + * settings for this filter can be changed in Settings.hpp. + * After filtering, hysteresis is applied to prevent flipping back and forth + * between two values when the input is not changing. + * + * @tparam Precision + * The number of bits of precision the output should have. + * @tparam FilterShiftFactor + * The number of bits used for the EMA filter. + * The pole location is + * @f$ 1 - \left(\frac{1}{2}\right)^{\text{FilterShiftFactor}} @f$. + * A lower shift factor means less filtering (@f$0@f$ is no filtering), + * and a higher shift factor means more filtering (and more latency). + * @tparam FilterType + * The type to use for the intermediate types of the filter. + * Should be at least + * @f$ \text{ADC_BITS} + \text{IncRes} + + * \text{FilterShiftFactor} @f$ bits wide. + * @tparam AnalogType + * The type to use for the analog values. + * Should be at least @f$ \text{ADC_BITS} + \text{IncRes} @f$ + * bits wide. + * @tparam IncRes + * The number of bits to increase the resolution of the analog reading + * by. + * + * @ingroup AH_HardwareUtils + */ +template ::value> +class FilteredAnalog + : public GenericFilteredAnalog { + public: + /** + * @brief Construct a new FilteredAnalog object. + * + * @param analogPin + * The analog pin to read from. + * @param initial + * The initial value of the filter. + */ + FilteredAnalog(pin_t analogPin, AnalogType initial = 0) + : GenericFilteredAnalog(analogPin, nullptr, initial) {} + + /// @copydoc FilteredAnalog(pin_t,AnalogType) + FilteredAnalog(ArduinoPin_t analogPin, AnalogType initial = 0) + : FilteredAnalog(pin_t(analogPin), initial) {} + + /** + * @brief Construct a new FilteredAnalog object. + * + * **This constructor should not be used.** + * It is just a way to easily create arrays of FilteredAnalog objects, and + * initializing them later. Trying to update a default-constructed or + * uninitialized FilteredAnalog object will result in a fatal runtime error. + */ + FilteredAnalog() : FilteredAnalog(NO_PIN) {} + + /// A function pointer to a mapping function to map analog values. + /// @see map() + using MappingFunction = AnalogType (*)(AnalogType); + + /** + * @brief Invert the analog value. For example, if the precision is 10 + * bits, when the analog input measures 1023, the output will be 0, + * and when the analog input measures 0, the output will be 1023. + * + * @note This overrides the mapping function set by the `map` method. + */ + void invert() { + constexpr AnalogType maxval = FilteredAnalog::getMaxRawValue(); + this->map([](AnalogType val) -> AnalogType { return maxval - val; }); + } +}; + +END_AH_NAMESPACE diff --git a/AH/Hardware/Hardware-Types.hpp b/AH/Hardware/Hardware-Types.hpp new file mode 100644 index 0000000..c2d7c8c --- /dev/null +++ b/AH/Hardware/Hardware-Types.hpp @@ -0,0 +1,67 @@ +#pragma once + +#include +#include +#include +#include +#include + +BEGIN_AH_NAMESPACE + +using analog_t = uint16_t; +using pin_int_t = uint_fast16_t; +constexpr pin_int_t NO_PIN_INT = + (std::numeric_limits::max() >> 1) + 1; + +namespace ExtIO { +struct pin_t { + constexpr pin_t() = default; + constexpr pin_t(pin_int_t pin) : pin(pin) {} + + pin_int_t pin = NO_PIN_INT; + + static_assert(std::is_unsigned::value, + "Error: pin_t should be an unsigned integer type"); + + pin_t &operator+=(pin_int_t b) { this->pin += b; return *this; } + pin_t &operator++() { ++pin; return *this; } + pin_t operator++(int) { pin_t t = *this; ++pin; return t; } + pin_t &operator-=(pin_int_t b) { this->pin -= b; return *this; } + pin_t &operator--() { --pin; return *this; } + pin_t operator--(int) { pin_t t = *this; --pin; return t; } +}; +constexpr inline bool operator==(pin_t a, pin_t b) { return a.pin == b.pin; } +constexpr inline bool operator<(pin_t a, pin_t b) { return a.pin < b.pin; } +constexpr inline bool operator<=(pin_t a, pin_t b) { return a.pin <= b.pin; } +constexpr inline bool operator>(pin_t a, pin_t b) { return a.pin > b.pin; } +constexpr inline bool operator>=(pin_t a, pin_t b) { return a.pin >= b.pin; } +constexpr inline bool operator!=(pin_t a, pin_t b) { return !(a == b); } +constexpr inline pin_int_t operator-(pin_t a, pin_t b) { return a.pin - b.pin; } +constexpr inline pin_t operator-(pin_t a, pin_int_t b) { return a.pin - b; } +constexpr inline pin_t operator+(pin_t a, pin_int_t b) { return a.pin + b; } +constexpr inline pin_t operator+(pin_int_t a, pin_t b) { return a + b.pin; } +constexpr inline pin_t operator*(pin_t a, pin_int_t b) { return a.pin * b; } +constexpr inline pin_t operator*(pin_int_t a, pin_t b) { return a * b.pin; } +inline Print &operator<<(Print &os, pin_t p) { + using AH::operator<<; + return os << +p.pin; +} +#ifndef ARDUINO +inline std::ostream &operator<<(std::ostream &os, pin_t p) { + return os << +p.pin; +} +#endif +} // namespace ExtIO + +using ExtIO::pin_t; + +#ifdef NO_PIN +#undef NO_PIN +#endif + +constexpr pin_t NO_PIN {}; + +template +using PinList = Array; + +END_AH_NAMESPACE diff --git a/AH/Hardware/IncrementButton.cpp b/AH/Hardware/IncrementButton.cpp new file mode 100644 index 0000000..2a059d2 --- /dev/null +++ b/AH/Hardware/IncrementButton.cpp @@ -0,0 +1,38 @@ +#include "IncrementButton.hpp" + +BEGIN_AH_NAMESPACE + +IncrementButton::State IncrementButton::updateImplementation() { + Button::State incrState = button.update(); + + if (incrState == Button::Released) { + // Button released, don't do anything + // This one is first to minimize overhead + // because most of the time, the button will + // be released + return Nothing; + } else if (incrState == Button::Rising) { + auto res = longPressState == LongPress ? ReleasedLong : ReleasedShort; + longPressState = Initial; + return res; + } else if (incrState == Button::Falling) { + return IncrementShort; + } else { // if (incrState == Button::Pressed) + auto now = millis(); + if (longPressState == LongPress) { + // still long pressed + if (now - longPressRepeat >= LONG_PRESS_REPEAT_DELAY) { + longPressRepeat += LONG_PRESS_REPEAT_DELAY; + return IncrementHold; + } + } else if (button.stableTime(now) >= LONG_PRESS_DELAY) { + // long press starts + longPressState = LongPress; + longPressRepeat = now; + return IncrementLong; + } + } + return Nothing; +} + +END_AH_NAMESPACE diff --git a/AH/Hardware/IncrementButton.hpp b/AH/Hardware/IncrementButton.hpp new file mode 100644 index 0000000..be286ea --- /dev/null +++ b/AH/Hardware/IncrementButton.hpp @@ -0,0 +1,77 @@ +/* ✔ */ + +#pragma once + +#include "Button.hpp" + +BEGIN_AH_NAMESPACE + +/** + * @brief A class for buttons that increment some counter or setting. + * + * It behaves the same way as a computer keyboard: when you press the button, + * it increments the counter once. If you keep on pressing it for longer than + * a certain threshold, it keeps on incrementing at a faster rate, until you + * release it. + * + * @ingroup AH_HardwareUtils + */ +class IncrementButton { + public: + /** + * @brief Create a IncrementButton. + * + * @param button + * The button to read from. + * The button is copied. + */ + IncrementButton(const Button &button) : button(button) {} + + /// @see Button::begin + void begin() { button.begin(); } + + /** + * @brief An enumeration of the different actions to be performed by the + * counter. + * @todo Add states for initial press. + */ + enum State { + Nothing = 0, ///< The counter must not be incremented. + IncrementShort, ///< The counter must be incremented (after short press). + IncrementLong, ///< The counter must be incremented (after long press). + IncrementHold, ///< The counter must be incremented (still pressed). + ReleasedShort, ///< The button was released after a short press. + ReleasedLong, ///< The button was released after a long press. + }; + + /** + * @brief Update and return the state of the increment button. + */ + State update() { return state = updateImplementation(); } + + /** + * @brief Return the state of the increment button without updating it. + * + * Returns the same value as the last @ref update call. + */ + State getState() const { return state; } + + /// @see Button::invert + void invert() { button.invert(); } + + protected: + State updateImplementation(); + + private: + Button button; + + enum { + Initial, + LongPress, + } longPressState = Initial; + unsigned long longPressRepeat; + + State state = Nothing; +}; + +END_AH_NAMESPACE diff --git a/AH/Hardware/IncrementDecrementButtons.cpp b/AH/Hardware/IncrementDecrementButtons.cpp new file mode 100644 index 0000000..fbb5118 --- /dev/null +++ b/AH/Hardware/IncrementDecrementButtons.cpp @@ -0,0 +1,73 @@ +#include "IncrementDecrementButtons.hpp" + +BEGIN_AH_NAMESPACE + +IncrementDecrementButtons::State +IncrementDecrementButtons::updateImplementation() { + Button::State incrState = incrementButton.update(); + Button::State decrState = decrementButton.update(); + + if (decrState == Button::Released && incrState == Button::Released) { + // Both released + } else if ((decrState == Button::Rising && incrState == Button::Released) || + (incrState == Button::Rising && decrState == Button::Released) || + (incrState == Button::Rising && decrState == Button::Rising)) { + // One released, the other rising → nothing + // now both released, so go to initial state + longPressState = Initial; + } else if (incrState == Button::Falling && decrState == Button::Falling) { + // Both falling → reset + // (rather unlikely, but just in case) + longPressState = AfterReset; + return Reset; + } else if (incrState == Button::Falling) { + if (decrState == Button::Pressed) { + // One pressed, the other falling → reset + longPressState = AfterReset; + return Reset; + } else { + // Increment falling, the other released → increment + return IncrementShort; + } + } else if (decrState == Button::Falling) { + if (incrState == Button::Pressed) { + // One pressed, the other falling → reset + longPressState = AfterReset; + return Reset; + } else { + // Decrement falling, the other released → decrement + return DecrementShort; + } + } else if (incrState == Button::Pressed && decrState == Button::Pressed) { + // Both pressed → nothing + } else if (longPressState != AfterReset && incrState == Button::Pressed) { + // Not reset and increment pressed → long press? + auto now = millis(); + if (longPressState == LongPress) { + if (now - longPressRepeat >= LONG_PRESS_REPEAT_DELAY) { + longPressRepeat += LONG_PRESS_REPEAT_DELAY; + return IncrementHold; + } + } else if (incrementButton.stableTime() >= LONG_PRESS_DELAY) { + longPressState = LongPress; + longPressRepeat = now; + return IncrementLong; + } + } else if (longPressState != AfterReset && decrState == Button::Pressed) { + // Not reset and decrement pressed → long press? + auto now = millis(); + if (longPressState == LongPress) { + if (now - longPressRepeat >= LONG_PRESS_REPEAT_DELAY) { + longPressRepeat += LONG_PRESS_REPEAT_DELAY; + return DecrementHold; + } + } else if (decrementButton.stableTime() >= LONG_PRESS_DELAY) { + longPressState = LongPress; + longPressRepeat = now; + return DecrementLong; + } + } + return Nothing; +} + +END_AH_NAMESPACE diff --git a/AH/Hardware/IncrementDecrementButtons.hpp b/AH/Hardware/IncrementDecrementButtons.hpp new file mode 100644 index 0000000..4d104c2 --- /dev/null +++ b/AH/Hardware/IncrementDecrementButtons.hpp @@ -0,0 +1,95 @@ +/* ✔ */ + +#pragma once + +#include "Button.hpp" + +BEGIN_AH_NAMESPACE + +/** + * @brief A class for buttons that increment and decrement some counter or + * setting. + * + * It behaves the same way as a computer keyboard: when you press the increment + * (decrement) button, it increments (decrements) the counter once. + * If you keep on pressing it for longer than a certain threshold, it keeps on + * incrementing (decrementing) at a faster rate, until you release it. + * If both the increment and the decrement button are pressed at once, it resets + * the counter. + * + * @ingroup AH_HardwareUtils + */ +class IncrementDecrementButtons { + public: + /** + * @brief Create a IncrementDecrementButtons object. + * + * @param incrementButton + * The button to increment the counter. + * The button is copied. + * @param decrementButton + * The button to decrement the counter. + * The button is copied. + */ + IncrementDecrementButtons(const Button &incrementButton, + const Button &decrementButton) + : incrementButton(incrementButton), decrementButton(decrementButton) {} + + /// @see Button::begin + void begin() { + incrementButton.begin(); + decrementButton.begin(); + } + + /** + * @brief An enumeration of the different actions to be performed by the + * counter. + * @todo Add states for initial press. + */ + enum State { + Nothing = 0, ///< The counter should not be incremented. + IncrementShort, ///< The counter must be incremented (after short press). + IncrementLong, ///< The counter must be incremented (after long press). + IncrementHold, ///< The counter must be incremented (still pressed). + DecrementShort, ///< The counter must be decremented (after short press). + DecrementLong, ///< The counter must be decremented (after long press). + DecrementHold, ///< The counter must be decremented (still pressed). + Reset, ///< The counter should be reset to the initial value. + }; + + /** + * @brief Update and return the state of the increment/decrement button. + */ + State update() { return state = updateImplementation(); } + + /** + * @brief Return the state of the increment/decrement button without + * updating it. + * + * Returns the same value as the last @ref update call. + */ + State getState() const { return state; } + + /// @see Button::invert + void invert() { + incrementButton.invert(); + decrementButton.invert(); + } + + protected: + State updateImplementation(); + + private: + Button incrementButton; + Button decrementButton; + + enum { + Initial, + LongPress, + AfterReset, + } longPressState = Initial; + unsigned long longPressRepeat; + State state = Nothing; +}; + +END_AH_NAMESPACE diff --git a/AH/Math/Divide.hpp b/AH/Math/Divide.hpp new file mode 100644 index 0000000..33be00d --- /dev/null +++ b/AH/Math/Divide.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include + +BEGIN_AH_NAMESPACE + +/// Divide by N using the default division operator, without explicit rounding +/// This should be used for floating point types. For integers, prefer using +/// @ref round_div_unsigned_int and @ref round_div_signed_int. +template +struct round_div_default { + static T div(T val) { return val / N; } +}; + +/// Divide an unsigned integer by N, rounding the result. +template +struct round_div_unsigned_int { + static T div(T val) { + return (val + (N / 2)) / N; + static_assert(std::is_unsigned::value && std::is_integral::value, + "This function is only valid for unsigned integers"); + } +}; + +/// Divide a signed integer by N, rounding the result. +template +struct round_div_signed_int { + static T div(T val) { + T offset = val >= 0 ? (N / 2) : (-N / 2); + return (val + offset) / N; + } +}; + +/// Select the right rounding division operator, depending on whether T is a +/// signed or unsigned integer. +template +struct round_div_int + : std::conditional::value, round_div_signed_int, + round_div_unsigned_int>::type {}; + +/// Select the right rounding division operator, depending on whether T is an +/// integer or not. +template +struct round_div_helper + : std::conditional::value, round_div_int, + round_div_default>::type {}; + +/// Divide a number by N and round the result. Uses different specializations +/// for integers to implement efficient rounding. +template +T round_div(T val) { + return round_div_helper::div(val); +} + +END_AH_NAMESPACE diff --git a/AH/Math/IncreaseBitDepth.hpp b/AH/Math/IncreaseBitDepth.hpp new file mode 100644 index 0000000..7b1babc --- /dev/null +++ b/AH/Math/IncreaseBitDepth.hpp @@ -0,0 +1,142 @@ +#pragma once + +#include // enable_if +#include // CHAR_BIT +#include // size_t + +BEGIN_AH_NAMESPACE + +namespace detail { + +template +std::enable_if_t<(Bits_out <= 2 * Bits_in) && (Bits_out > Bits_in), T_out> +increaseBitDepthImpl(T_in in) { + constexpr size_t leftShift = Bits_out - Bits_in; + constexpr size_t rightShift = Bits_in - leftShift; + return (static_cast(in) << leftShift) | (in >> rightShift); +} + +template +std::enable_if_t<(Bits_out <= Bits_in), T_out> increaseBitDepthImpl(T_in in) { + constexpr size_t rightShift = Bits_in - Bits_out; + return static_cast(in >> rightShift); +} + +template +std::enable_if_t<(Bits_out > 2 * Bits_in), T_out> +increaseBitDepthImpl(T_in in) { + constexpr size_t leftShift = Bits_out - Bits_in; + return (static_cast(in) << leftShift) | + increaseBitDepthImpl(in); +} + +} // namespace detail + +/// @addtogroup AH_Math +/// @{ + +/** + * @brief Increase the bit depth of the given value from `Bits_in` bits wide + * to `Bits_out` bits wide, (approximately) evenly distributing the + * error across the entire range, such that the error for each element + * is between -1 and +1. + * + * @see @ref increaseBitDepthMiddle + * + * For example, converting 3-bit numbers to 7-bit numbers would result in the + * following: + * + * | in (dec) | in (bin) | out (bin) | out (dec) | exact | error | + * |:--------:|:--------:|:---------:|:---------:|:------:|:-----:| + * | 0 | 000 | 000'0000 | 0 | 0.00 | +0.00 | + * | 1 | 001 | 001'0010 | 18 | 18.14 | +0.14 | + * | 2 | 010 | 010'0100 | 36 | 36.29 | +0.29 | + * | 3 | 011 | 011'0110 | 54 | 54.43 | +0.43 | + * | 4 | 100 | 100'1001 | 73 | 72.57 | -0.43 | + * | 5 | 101 | 101'1011 | 91 | 90.71 | -0.29 | + * | 6 | 110 | 110'1101 | 109 | 108.86 | -0.14 | + * | 7 | 111 | 111'1111 | 127 | 127.00 | +0.00 | + * + * The following is a comparison to the @ref increaseBitDepthMiddle function. + * + * @image html increase-bit-depth.svg + * + * @tparam Bits_out + * The number of bits of the output range. + * @tparam Bits_in + * The number of bits of the input range. + * @tparam T_out + * The type of the output (return type). + * @tparam T_in + * The type of the input. + * @param in + * The value to scale up. + * @return The scaled up value. + */ +template +T_out increaseBitDepth(T_in in) { + static_assert(Bits_in <= sizeof(T_in) * CHAR_BIT, + "Error: Bits_in > bits(T_in)"); + static_assert(Bits_out <= sizeof(T_out) * CHAR_BIT, + "Error: Bits_out > bits(T_out)"); + return detail::increaseBitDepthImpl(in); +} + +/** + * @brief Increase the bit depth of the given value from `Bits_in` bits wide + * to `Bits_out` bits wide, while ensuring that the middle of the input + * range maps exactly to the middle of the output range, i.e. + * @f$ 2^{\texttt{Bits\_in} - 1} @f$ maps to + * @f$ 2^{\texttt{Bits\_out} - 1} @f$. + * + * @see @ref increaseBitDepth + * + * For example, converting 3-bit numbers to 7-bit numbers would result in the + * following: + * + * | in (dec) | in (bin) | out (bin) | out (dec) | exact | error | + * |:--------:|:--------:|:---------:|:---------:|:------:|:-----:| + * | 0 | 000 | 000'0000 | 0 | 0.00 | +0.00 | + * | 1 | 001 | 001'0000 | 16 | 18.14 | -2.14 | + * | 2 | 010 | 010'0000 | 32 | 36.29 | -4.29 | + * | 3 | 011 | 011'0000 | 48 | 54.43 | -6.43 | + * | 4 | 100 | 100'0000 | 64 | 72.57 | -8.57 | + * | 5 | 101 | 101'0101 | 85 | 90.71 | -5.71 | + * | 6 | 110 | 110'1010 | 106 | 108.86 | -2.86 | + * | 7 | 111 | 111'1111 | 127 | 127.00 | +0.00 | + * + * The following is a comparison to the @ref increaseBitDepth function. + * + * @image html increase-bit-depth.svg + * + * @tparam Bits_out + * The number of bits of the output range. + * @tparam Bits_in + * The number of bits of the input range. + * @tparam T_out + * The type of the output (return type). + * @tparam T_in + * The type of the input. + * @param in + * The value to scale up. + * @return The scaled up value. + */ +template +T_out increaseBitDepthMiddle(T_in in) { + static_assert(Bits_in <= sizeof(T_in) * CHAR_BIT, + "Error: Bits_in > bits(T_in)"); + static_assert(Bits_out <= sizeof(T_out) * CHAR_BIT, + "Error: Bits_out > bits(T_out)"); + constexpr size_t leftShift = Bits_out - Bits_in; + T_in half = T_in {1} << (Bits_in - 1); + T_out out = static_cast(in) << leftShift; + if (in > half) { + T_in repeat = in & (half - 1); + out |= increaseBitDepth(repeat); + } + return out; +} + +/// @} + +END_AH_NAMESPACE diff --git a/AH/Math/MinMaxFix.hpp b/AH/Math/MinMaxFix.hpp new file mode 100644 index 0000000..9d2b967 --- /dev/null +++ b/AH/Math/MinMaxFix.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +BEGIN_AH_NAMESPACE + +/// Return the smaller of two numbers/objects. +/// @ingroup AH_Math +template +constexpr auto min(const T &a, const U &b) -> decltype(b < a ? b : a) { + return b < a ? b : a; +} + +/// Return the larger of two numbers/objects. +/// @ingroup AH_Math +template +constexpr auto max(const T &a, const U &b) -> decltype(a < b ? b : a) { + return a < b ? b : a; +} + +END_AH_NAMESPACE diff --git a/AH/PrintStream/PrintStream.cpp b/AH/PrintStream/PrintStream.cpp new file mode 100644 index 0000000..cd08e11 --- /dev/null +++ b/AH/PrintStream/PrintStream.cpp @@ -0,0 +1,281 @@ +// https://github.com/tttapa/Arduino-PrintStream/blob/6a9e0d365be0b3d84187daa2a8a7bda8d541472e/src/PrintStream.cpp + +#include "PrintStream.hpp" + +// LCOV_EXCL_START + +#if not defined(ARDUINO_ARCH_ESP32) && not defined(ARDUINO_ARCH_SAM) && \ + not defined(ARDUINO_API_VERSION) && not defined(ArduinoFake) && \ + not defined(ARDUINO_ARCH_STM32) +#define FLUSH +#endif + +BEGIN_AH_NAMESPACE + +/* #define OCT 8 */ + +uint8_t formatPrintStream = DEC; +bool boolalphaPrintStream = false; +bool leadingZerosPrintStream = false; +uint8_t precisionPrintStream = 2; +char byteSeparatorPrintStream = '\0'; +enum : char { LOWERCASE = 0x7F, UPPERCASE = 0x5F } casePrintStream = LOWERCASE; +bool showbasePrintStream = false; + +template +Print &printIntegral(Print &printer, T i); + +Print &endl(Print &printer) { + printer.println(); +#ifdef FLUSH + printer.flush(); +#endif + return printer; +} + +Print &uppercase(Print &printer) { + casePrintStream = UPPERCASE; + return printer; +} + +Print &nouppercase(Print &printer) { + casePrintStream = LOWERCASE; + return printer; +} + +Print &showbase(Print &printer) { + showbasePrintStream = true; + return printer; +} + +Print &noshowbase(Print &printer) { + showbasePrintStream = false; + return printer; +} + +Print &flush(Print &printer) { +#ifdef FLUSH + printer.flush(); +#endif + return printer; +} + +Print &hex(Print &printer) { + formatPrintStream = HEX; + return printer; +} + +/* Print &oct(Print &printer) { + formatPrintStream = OCT; + return printer; +} */ + +Print &bin(Print &printer) { + formatPrintStream = BIN; + return printer; +} + +Print &dec(Print &printer) { + formatPrintStream = DEC; + return printer; +} + +Print &boolalpha(Print &printer) { + boolalphaPrintStream = true; + return printer; +} +Print &noboolalpha(Print &printer) { + boolalphaPrintStream = false; + return printer; +} + +Print &leadingzeros(Print &printer) { + leadingZerosPrintStream = true; + return printer; +} +Print &noleadingzeros(Print &printer) { + leadingZerosPrintStream = false; + return printer; +} +Print &operator<<(Print &printer, const __FlashStringHelper *s) { + printer.print(s); + return printer; +} +#ifdef ARDUINO +Print &operator<<(Print &printer, const String &s) { + printer.print(s); + return printer; +} +#endif +Print &operator<<(Print &printer, const char s[]) { + printer.print(s); + return printer; +} +Print &operator<<(Print &printer, char c) { + printer.print(c); + return printer; +} +Print &operator<<(Print &printer, unsigned char i) { + return printIntegral(printer, i); +} +Print &operator<<(Print &printer, int i) { return printIntegral(printer, i); } +Print &operator<<(Print &printer, unsigned int i) { + return printIntegral(printer, i); +} +Print &operator<<(Print &printer, int8_t i) { + return printIntegral(printer, i); +} +Print &operator<<(Print &printer, long i) { return printIntegral(printer, i); } +Print &operator<<(Print &printer, unsigned long i) { + return printIntegral(printer, i); +} +Print &operator<<(Print &printer, double d) { + printer.print(d, +precisionPrintStream); + return printer; +} +Print &operator<<(Print &printer, float f) { + return printer << static_cast(f); +} +Print &operator<<(Print &printer, const Printable &p) { + printer.print(p); + return printer; +} +Print &operator<<(Print &printer, bool b) { + if (boolalphaPrintStream) + printer.print(b ? F("true") : F("false")); + else + printer.print(b); + return printer; +} + +Print &operator<<(Print &printer, manipulator pf) { return pf(printer); } + +Setbase setbase(uint8_t base) { return {base}; } +Print &operator<<(Print &printer, Setbase f) { + formatPrintStream = f.M_base; + return printer; +} + +Setbytesep setbytesep(char bytesep) { return {bytesep}; } +Print &operator<<(Print &printer, Setbytesep f) { + byteSeparatorPrintStream = f.M_bytesep; + return printer; +} + +Setprecision setprecision(int n) { return {n}; } +Print &operator<<(Print &printer, Setprecision f) { + precisionPrintStream = f.M_n; + return printer; +} + +static char nibble_to_hex( + uint8_t nibble) { // convert a 4-bit nibble to a hexadecimal character + nibble &= 0xF; + return nibble > 9 ? nibble - 10 + ('a' & casePrintStream) : nibble + '0'; +} + +#if __BYTE_ORDER != __LITTLE_ENDIAN +#error "Byte order not supported" +#endif + +template +void printHex(Print &printer, T val) { + if (showbasePrintStream) + printer.print("0x"); + bool nonZero = false; + for (int i = sizeof(val) - 1; i >= 0; i--) { + uint8_t currByte = ((uint8_t *)&val)[i]; + if (currByte != 0 || i == 0) + nonZero = true; + if (leadingZerosPrintStream || nonZero) { + printer.print(nibble_to_hex(currByte >> 4)); + printer.print(nibble_to_hex(currByte)); + if (byteSeparatorPrintStream && i) + printer.print(byteSeparatorPrintStream); + } + } +} + +template +void printBin(Print &printer, T val) { + if (showbasePrintStream) + printer.print("0b"); + bool nonZero = false; + for (int i = sizeof(val) - 1; i >= 0; i--) { + uint8_t currByte = ((uint8_t *)&val)[i]; + for (int j = 7; j >= 0; j--) { + uint8_t currBit = currByte & 0x80; + if (currBit != 0 || (i == 0 && j == 0)) + nonZero = true; + if (leadingZerosPrintStream || nonZero) + printer.print(currBit ? '1' : '0'); + currByte <<= 1; + } + if (byteSeparatorPrintStream && i && + (leadingZerosPrintStream || nonZero)) + printer.print(byteSeparatorPrintStream); + } +} + +/* template +void printOct(Print &printer, T val) +{ + ; // TODO +} */ + +template +Print &printIntegral(Print &printer, T i) { + switch (formatPrintStream) { + case DEC: printer.print(i); break; + case HEX: printHex(printer, i); break; + case BIN: printBin(printer, i); break; + /* case OCT: + printOct(printer, i); + break; */ + default: break; + } + return printer; +} + +Print &operator<<(Print &p, HexDump h) { + if (h.length == 0) + return p; + + auto temp_case = casePrintStream; + casePrintStream = UPPERCASE; + while (h.length-- > 1) { + printHex(p, *h.data++); + p.print(' '); + } + printHex(p, *h.data++); + casePrintStream = temp_case; + return p; +} + +#ifndef ARDUINO + +std::ostream &operator<<(std::ostream &p, HexDump h) { + if (h.length == 0) + return p; + + auto hex_nibble_to_char = [](uint8_t nibble) -> char { + nibble &= 0xF; + return nibble > 9 ? nibble - 10 + 'A' : nibble + '0'; + }; + auto printHex = [&](std::ostream &p, uint8_t b) { + p << hex_nibble_to_char(b >> 4) << hex_nibble_to_char(b); + }; + + while (h.length-- > 1) { + printHex(p, *h.data++); + p << ' '; + } + printHex(p, *h.data++); + return p; +} + +#endif + +END_AH_NAMESPACE + +// LCOV_EXCL_STOP diff --git a/AH/PrintStream/PrintStream.hpp b/AH/PrintStream/PrintStream.hpp new file mode 100644 index 0000000..6d8867e --- /dev/null +++ b/AH/PrintStream/PrintStream.hpp @@ -0,0 +1,145 @@ +/** + * @brief [PrintStream library](https://github.com/tttapa/Arduino-PrintStream/blob/6a9e0d365be0b3d84187daa2a8a7bda8d541472e/src/PrintStream.h) + */ + +#ifndef PrintStream_h +#define PrintStream_h + +#include +#include + +BEGIN_AH_NAMESPACE + +/// @addtogroup AH_PrintStream +/// @{ + +typedef Print &manipulator(Print &); + +Print &endl(Print &printer); +Print &flush(Print &printer); +Print &hex(Print &printer); +Print &bin(Print &printer); +Print &dec(Print &printer); +/* Print &oct(Print &printer); */ +Print &boolalpha(Print &printer); +Print &noboolalpha(Print &printer); +Print &leadingzeros(Print &printer); +Print &noleadingzeros(Print &printer); +Print &uppercase(Print &printer); +Print &nouppercase(Print &printer); +Print &showbase(Print &printer); +Print &noshowbase(Print &printer); + +Print &operator<<(Print &printer, const __FlashStringHelper *s); +#ifdef ARDUINO +Print &operator<<(Print &printer, const String &s); +#endif +Print &operator<<(Print &printer, const char s[]); +Print &operator<<(Print &printer, char c); +Print &operator<<(Print &printer, unsigned char c); +Print &operator<<(Print &printer, int i); +Print &operator<<(Print &printer, unsigned int i); +Print &operator<<(Print &printer, int8_t i); +Print &operator<<(Print &printer, long i); +Print &operator<<(Print &printer, unsigned long i); +Print &operator<<(Print &printer, float f); +Print &operator<<(Print &printer, double d); +Print &operator<<(Print &printer, const Printable &p); +Print &operator<<(Print &printer, bool b); + +Print &operator<<(Print &printer, manipulator pf); + +struct Setbase { + uint8_t M_base; +}; +Setbase setbase(uint8_t base); +Print &operator<<(Print &printer, Setbase f); + +struct Setprecision { + int M_n; +}; +Setprecision setprecision(int n); +Print &operator<<(Print &printer, Setprecision f); + +struct Setbytesep { + char M_bytesep; +}; +Setbytesep setbytesep(char bytesep); +Print &operator<<(Print &printer, Setbytesep f); + +struct HexDump { + HexDump(const uint8_t *data, size_t length) : data(data), length(length) {} + template + explicit HexDump(const uint8_t (&data)[N]) : HexDump {data, N} {} + const uint8_t *data; + size_t length; +}; + +Print &operator<<(Print &p, HexDump h); + +/// @} + +END_AH_NAMESPACE + +#ifndef ARDUINO + +#include +#include + +BEGIN_AH_NAMESPACE + +// TODO: check conflicts between Arduino version and C++ STL version +using std::endl; +// using std::setbase; +// using std::setprecision; +using std::boolalpha; +using std::dec; +using std::flush; +using std::hex; +using std::noboolalpha; +using std::noshowbase; +using std::nouppercase; +using std::showbase; +using std::uppercase; + +inline std::ostream &operator<<(std::ostream &os, uint8_t u) { + // I'm lazy, I should probably implement one for uint8_t to get the leading + // zeros right + return os << static_cast(u); +} + +inline std::ostream &operator<<(std::ostream &os, + const __FlashStringHelper *s) { + return os << reinterpret_cast(s); +} + +std::ostream &operator<<(std::ostream &p, HexDump h); + +END_AH_NAMESPACE + +#endif + +#include + +BEGIN_CS_NAMESPACE +using AH::operator<<; +using AH::manipulator; +using AH::endl; +using AH::flush; +using AH::hex; +using AH::bin; +using AH::dec; +using AH::boolalpha; +using AH::noboolalpha; +using AH::leadingzeros; +using AH::noleadingzeros; +using AH::uppercase; +using AH::nouppercase; +using AH::showbase; +using AH::noshowbase; +using AH::setbase; +using AH::setprecision; +using AH::setbytesep; +END_CS_NAMESPACE + +#endif // PrintStream_h diff --git a/AH/STL/Fallback/algorithm b/AH/STL/Fallback/algorithm new file mode 100644 index 0000000..b23aef1 --- /dev/null +++ b/AH/STL/Fallback/algorithm @@ -0,0 +1,68 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/algorithm + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_ALGORITHM +#define _GLIBCXX_ALGORITHM 1 + +#pragma GCC system_header + +#include "utility" // UK-300. +#include "bits/stl_algobase.h" +#include "bits/stl_algo.h" + +#ifdef _GLIBCXX_PARALLEL +# include +#endif + +#endif /* _GLIBCXX_ALGORITHM */ diff --git a/AH/STL/Fallback/array b/AH/STL/Fallback/array new file mode 100644 index 0000000..042aaaf --- /dev/null +++ b/AH/STL/Fallback/array @@ -0,0 +1,399 @@ +// -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/array + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_ARRAY +#define _GLIBCXX_ARRAY 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "bits/c++0x_warning.h" +#else + +#include "utility" +#include "bits/stl_algobase.h" +#include "bits/range_access.h" + +#ifndef __AVR__ +#include +#else +#include +#endif + + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + template + struct __array_traits + { + typedef _Tp _Type[_Nm]; + typedef __is_swappable<_Tp> _Is_swappable; + typedef __is_nothrow_swappable<_Tp> _Is_nothrow_swappable; + + static constexpr _Tp& + _S_ref(const _Type& __t, std::size_t __n) noexcept + { return const_cast<_Tp&>(__t[__n]); } + + static constexpr _Tp* + _S_ptr(const _Type& __t) noexcept + { return const_cast<_Tp*>(__t); } + }; + + template + struct __array_traits<_Tp, 0> + { + struct _Type { }; + typedef true_type _Is_swappable; + typedef true_type _Is_nothrow_swappable; + + static constexpr _Tp& + _S_ref(const _Type&, std::size_t) noexcept + { return *static_cast<_Tp*>(nullptr); } + + static constexpr _Tp* + _S_ptr(const _Type&) noexcept + { return nullptr; } + }; + + /** + * @brief A standard container for storing a fixed size sequence of elements. + * + * @ingroup sequences + * + * Meets the requirements of a container, a + * reversible container, and a + * sequence. + * + * Sets support random access iterators. + * + * @tparam Tp Type of element. Required to be a complete type. + * @tparam N Number of elements. + */ + template + struct array + { + typedef _Tp value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* iterator; + typedef const value_type* const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // Support for zero-sized arrays mandatory. + typedef _GLIBCXX_STD_C::__array_traits<_Tp, _Nm> _AT_Type; + typename _AT_Type::_Type _M_elems; + + // No explicit construct/copy/destroy for aggregate type. + + // DR 776. + void + fill(const value_type& __u) + { std::fill_n(begin(), size(), __u); } + + void + swap(array& __other) + noexcept(_AT_Type::_Is_nothrow_swappable::value) + { std::swap_ranges(begin(), end(), __other.begin()); } + + // Iterators. + _GLIBCXX17_CONSTEXPR iterator + begin() noexcept + { return iterator(data()); } + + _GLIBCXX17_CONSTEXPR const_iterator + begin() const noexcept + { return const_iterator(data()); } + + _GLIBCXX17_CONSTEXPR iterator + end() noexcept + { return iterator(data() + _Nm); } + + _GLIBCXX17_CONSTEXPR const_iterator + end() const noexcept + { return const_iterator(data() + _Nm); } + + _GLIBCXX17_CONSTEXPR reverse_iterator + rbegin() noexcept + { return reverse_iterator(end()); } + + _GLIBCXX17_CONSTEXPR const_reverse_iterator + rbegin() const noexcept + { return const_reverse_iterator(end()); } + + _GLIBCXX17_CONSTEXPR reverse_iterator + rend() noexcept + { return reverse_iterator(begin()); } + + _GLIBCXX17_CONSTEXPR const_reverse_iterator + rend() const noexcept + { return const_reverse_iterator(begin()); } + + _GLIBCXX17_CONSTEXPR const_iterator + cbegin() const noexcept + { return const_iterator(data()); } + + _GLIBCXX17_CONSTEXPR const_iterator + cend() const noexcept + { return const_iterator(data() + _Nm); } + + _GLIBCXX17_CONSTEXPR const_reverse_iterator + crbegin() const noexcept + { return const_reverse_iterator(end()); } + + _GLIBCXX17_CONSTEXPR const_reverse_iterator + crend() const noexcept + { return const_reverse_iterator(begin()); } + + // Capacity. + constexpr size_type + size() const noexcept { return _Nm; } + + constexpr size_type + max_size() const noexcept { return _Nm; } + + constexpr bool + empty() const noexcept { return size() == 0; } + + // Element access. + _GLIBCXX17_CONSTEXPR reference + operator[](size_type __n) noexcept + { return _AT_Type::_S_ref(_M_elems, __n); } + + constexpr const_reference + operator[](size_type __n) const noexcept + { return _AT_Type::_S_ref(_M_elems, __n); } + + _GLIBCXX17_CONSTEXPR reference + at(size_type __n) + { + #ifndef __AVR__ + if (__n >= _Nm) + std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " + ">= _Nm (which is %zu)"), + __n, _Nm); + #else + if (__n >= _Nm) { + ERROR(F("array::at: __n (which is ") << __n << ") " << + F(">= _Nm (which is ") << _Nm << ")", 0x6784); + __n = _Nm - 1; + } + #endif + return _AT_Type::_S_ref(_M_elems, __n); + } + + constexpr const_reference + at(size_type __n) const + { + // Result of conditional expression must be an lvalue so use + // boolean ? lvalue : (throw-expr, lvalue) + #ifndef __AVR__ + return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n) + : (std::__throw_out_of_range_fmt(__N("array::at: __n (which is %zu) " + ">= _Nm (which is %zu)"), + __n, _Nm), + _AT_Type::_S_ref(_M_elems, 0)); + #else + return __n < _Nm ? _AT_Type::_S_ref(_M_elems, __n) + : ([=] {ERROR(F("array::at: __n (which is ") << __n << ") " << + F(">= _Nm (which is ") << _Nm << ")", 0x6784);}(), + _AT_Type::_S_ref(_M_elems, _Nm - 1)); + #endif + } + + _GLIBCXX17_CONSTEXPR reference + front() noexcept + { return *begin(); } + + constexpr const_reference + front() const noexcept + { return _AT_Type::_S_ref(_M_elems, 0); } + + _GLIBCXX17_CONSTEXPR reference + back() noexcept + { return _Nm ? *(end() - 1) : *end(); } + + constexpr const_reference + back() const noexcept + { + return _Nm ? _AT_Type::_S_ref(_M_elems, _Nm - 1) + : _AT_Type::_S_ref(_M_elems, 0); + } + + _GLIBCXX17_CONSTEXPR pointer + data() noexcept + { return _AT_Type::_S_ptr(_M_elems); } + + _GLIBCXX17_CONSTEXPR const_pointer + data() const noexcept + { return _AT_Type::_S_ptr(_M_elems); } + }; + +#if __cpp_deduction_guides >= 201606 + template + array(_Tp, _Up...) + -> array && ...), _Tp>, + 1 + sizeof...(_Up)>; +#endif + + // Array comparisons. + template + inline bool + operator==(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) + { return std::equal(__one.begin(), __one.end(), __two.begin()); } + + template + inline bool + operator!=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) + { return !(__one == __two); } + + template + inline bool + operator<(const array<_Tp, _Nm>& __a, const array<_Tp, _Nm>& __b) + { + return std::lexicographical_compare(__a.begin(), __a.end(), + __b.begin(), __b.end()); + } + + template + inline bool + operator>(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) + { return __two < __one; } + + template + inline bool + operator<=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) + { return !(__one > __two); } + + template + inline bool + operator>=(const array<_Tp, _Nm>& __one, const array<_Tp, _Nm>& __two) + { return !(__one < __two); } + + // Specialized algorithms. + template + inline +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // Constrained free swap overload, see p0185r1 + typename enable_if< + _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>::_Is_swappable::value + >::type +#else + void +#endif + swap(array<_Tp, _Nm>& __one, array<_Tp, _Nm>& __two) + noexcept(noexcept(__one.swap(__two))) + { __one.swap(__two); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + template + typename enable_if< + !_GLIBCXX_STD_C::__array_traits<_Tp, _Nm>::_Is_swappable::value>::type + swap(array<_Tp, _Nm>&, array<_Tp, _Nm>&) = delete; +#endif + + template + constexpr _Tp& + get(array<_Tp, _Nm>& __arr) noexcept + { + static_assert(_Int < _Nm, "array index is within bounds"); + return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>:: + _S_ref(__arr._M_elems, _Int); + } + + template + constexpr _Tp&& + get(array<_Tp, _Nm>&& __arr) noexcept + { + static_assert(_Int < _Nm, "array index is within bounds"); + return std::move(_GLIBCXX_STD_C::get<_Int>(__arr)); + } + + template + constexpr const _Tp& + get(const array<_Tp, _Nm>& __arr) noexcept + { + static_assert(_Int < _Nm, "array index is within bounds"); + return _GLIBCXX_STD_C::__array_traits<_Tp, _Nm>:: + _S_ref(__arr._M_elems, _Int); + } + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Tuple interface to class template array. + + /// tuple_size + template + class tuple_size; + + /// Partial specialization for std::array + template + struct tuple_size<_GLIBCXX_STD_C::array<_Tp, _Nm>> + : public integral_constant { }; + + /// tuple_element + template + class tuple_element; + + /// Partial specialization for std::array + template + struct tuple_element<_Int, _GLIBCXX_STD_C::array<_Tp, _Nm>> + { + static_assert(_Int < _Nm, "index is out of bounds"); + typedef _Tp type; + }; + + template + struct __is_tuple_like_impl<_GLIBCXX_STD_C::array<_Tp, _Nm>> : true_type + { }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#ifdef _GLIBCXX_DEBUG +# include +#endif + +#ifdef _GLIBCXX_PROFILE +# include +#endif + +#endif // C++11 + +#endif // _GLIBCXX_ARRAY diff --git a/AH/STL/Fallback/backward/binders.h b/AH/STL/Fallback/backward/binders.h new file mode 100644 index 0000000..7564a6c --- /dev/null +++ b/AH/STL/Fallback/backward/binders.h @@ -0,0 +1,182 @@ +// Functor implementations -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file backward/binders.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _BACKWARD_BINDERS_H +#define _BACKWARD_BINDERS_H 1 + +// Suppress deprecated warning for this file. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // 20.3.6 binders + /** @defgroup binders Binder Classes + * @ingroup functors + * + * Binders turn functions/functors with two arguments into functors + * with a single argument, storing an argument to be applied later. + * For example, a variable @c B of type @c binder1st is constructed + * from a functor @c f and an argument @c x. Later, B's @c + * operator() is called with a single argument @c y. The return + * value is the value of @c f(x,y). @c B can be @a called with + * various arguments (y1, y2, ...) and will in turn call @c + * f(x,y1), @c f(x,y2), ... + * + * The function @c bind1st is provided to save some typing. It takes the + * function and an argument as parameters, and returns an instance of + * @c binder1st. + * + * The type @c binder2nd and its creator function @c bind2nd do the same + * thing, but the stored argument is passed as the second parameter instead + * of the first, e.g., @c bind2nd(std::minus(),1.3) will create a + * functor whose @c operator() accepts a floating-point number, subtracts + * 1.3 from it, and returns the result. (If @c bind1st had been used, + * the functor would perform 1.3 - x instead. + * + * Creator-wrapper functions like @c bind1st are intended to be used in + * calling algorithms. Their return values will be temporary objects. + * (The goal is to not require you to type names like + * @c std::binder1st> for declaring a variable to hold the + * return value from @c bind1st(std::plus(),5). + * + * These become more useful when combined with the composition functions. + * + * These functions are deprecated in C++11 and can be replaced by + * @c std::bind (or @c std::tr1::bind) which is more powerful and flexible, + * supporting functions with any number of arguments. Uses of @c bind1st + * can be replaced by @c std::bind(f, x, std::placeholders::_1) and + * @c bind2nd by @c std::bind(f, std::placeholders::_1, x). + * @{ + */ + /// One of the @link binders binder functors@endlink. + template + class binder1st + : public unary_function + { + protected: + _Operation op; + typename _Operation::first_argument_type value; + + public: + binder1st(const _Operation& __x, + const typename _Operation::first_argument_type& __y) + : op(__x), value(__y) { } + + typename _Operation::result_type + operator()(const typename _Operation::second_argument_type& __x) const + { return op(value, __x); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 109. Missing binders for non-const sequence elements + typename _Operation::result_type + operator()(typename _Operation::second_argument_type& __x) const + { return op(value, __x); } + } _GLIBCXX_DEPRECATED; + + /// One of the @link binders binder functors@endlink. + template + inline binder1st<_Operation> + bind1st(const _Operation& __fn, const _Tp& __x) + { + typedef typename _Operation::first_argument_type _Arg1_type; + return binder1st<_Operation>(__fn, _Arg1_type(__x)); + } + + /// One of the @link binders binder functors@endlink. + template + class binder2nd + : public unary_function + { + protected: + _Operation op; + typename _Operation::second_argument_type value; + + public: + binder2nd(const _Operation& __x, + const typename _Operation::second_argument_type& __y) + : op(__x), value(__y) { } + + typename _Operation::result_type + operator()(const typename _Operation::first_argument_type& __x) const + { return op(__x, value); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 109. Missing binders for non-const sequence elements + typename _Operation::result_type + operator()(typename _Operation::first_argument_type& __x) const + { return op(__x, value); } + } _GLIBCXX_DEPRECATED; + + /// One of the @link binders binder functors@endlink. + template + inline binder2nd<_Operation> + bind2nd(const _Operation& __fn, const _Tp& __x) + { + typedef typename _Operation::second_argument_type _Arg2_type; + return binder2nd<_Operation>(__fn, _Arg2_type(__x)); + } + /** @} */ + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#pragma GCC diagnostic pop + +#endif /* _BACKWARD_BINDERS_H */ diff --git a/AH/STL/Fallback/bits/algorithmfwd.h b/AH/STL/Fallback/bits/algorithmfwd.h new file mode 100644 index 0000000..84393dc --- /dev/null +++ b/AH/STL/Fallback/bits/algorithmfwd.h @@ -0,0 +1,854 @@ +// Forward declarations -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/algorithmfwd.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{algorithm} + */ + +#ifndef _GLIBCXX_ALGORITHMFWD_H +#define _GLIBCXX_ALGORITHMFWD_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" +#include "../bits/stl_pair.h" +#include "../bits/stl_iterator_base_types.h" +#if __cplusplus >= 201103L +#include "../initializer_list" +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /* + adjacent_find + all_of (C++11) + any_of (C++11) + binary_search + clamp (C++17) + copy + copy_backward + copy_if (C++11) + copy_n (C++11) + count + count_if + equal + equal_range + fill + fill_n + find + find_end + find_first_of + find_if + find_if_not (C++11) + for_each + generate + generate_n + includes + inplace_merge + is_heap (C++11) + is_heap_until (C++11) + is_partitioned (C++11) + is_sorted (C++11) + is_sorted_until (C++11) + iter_swap + lexicographical_compare + lower_bound + make_heap + max + max_element + merge + min + min_element + minmax (C++11) + minmax_element (C++11) + mismatch + next_permutation + none_of (C++11) + nth_element + partial_sort + partial_sort_copy + partition + partition_copy (C++11) + partition_point (C++11) + pop_heap + prev_permutation + push_heap + random_shuffle + remove + remove_copy + remove_copy_if + remove_if + replace + replace_copy + replace_copy_if + replace_if + reverse + reverse_copy + rotate + rotate_copy + search + search_n + set_difference + set_intersection + set_symmetric_difference + set_union + shuffle (C++11) + sort + sort_heap + stable_partition + stable_sort + swap + swap_ranges + transform + unique + unique_copy + upper_bound + */ + + /** + * @defgroup algorithms Algorithms + * + * Components for performing algorithmic operations. Includes + * non-modifying sequence, modifying (mutating) sequence, sorting, + * searching, merge, partition, heap, set, minima, maxima, and + * permutation operations. + */ + + /** + * @defgroup mutating_algorithms Mutating + * @ingroup algorithms + */ + + /** + * @defgroup non_mutating_algorithms Non-Mutating + * @ingroup algorithms + */ + + /** + * @defgroup sorting_algorithms Sorting + * @ingroup algorithms + */ + + /** + * @defgroup set_algorithms Set Operation + * @ingroup sorting_algorithms + * + * These algorithms are common set operations performed on sequences + * that are already sorted. The number of comparisons will be + * linear. + */ + + /** + * @defgroup binary_search_algorithms Binary Search + * @ingroup sorting_algorithms + * + * These algorithms are variations of a classic binary search, and + * all assume that the sequence being searched is already sorted. + * + * The number of comparisons will be logarithmic (and as few as + * possible). The number of steps through the sequence will be + * logarithmic for random-access iterators (e.g., pointers), and + * linear otherwise. + * + * The LWG has passed Defect Report 270, which notes: The + * proposed resolution reinterprets binary search. Instead of + * thinking about searching for a value in a sorted range, we view + * that as an important special case of a more general algorithm: + * searching for the partition point in a partitioned range. We + * also add a guarantee that the old wording did not: we ensure that + * the upper bound is no earlier than the lower bound, that the pair + * returned by equal_range is a valid range, and that the first part + * of that pair is the lower bound. + * + * The actual effect of the first sentence is that a comparison + * functor passed by the user doesn't necessarily need to induce a + * strict weak ordering relation. Rather, it partitions the range. + */ + + // adjacent_find + +#if __cplusplus >= 201103L + template + bool + all_of(_IIter, _IIter, _Predicate); + + template + bool + any_of(_IIter, _IIter, _Predicate); +#endif + + template + bool + binary_search(_FIter, _FIter, const _Tp&); + + template + bool + binary_search(_FIter, _FIter, const _Tp&, _Compare); + +#if __cplusplus > 201402L + template + _GLIBCXX14_CONSTEXPR + const _Tp& + clamp(const _Tp&, const _Tp&, const _Tp&); + + template + _GLIBCXX14_CONSTEXPR + const _Tp& + clamp(const _Tp&, const _Tp&, const _Tp&, _Compare); +#endif + + template + _OIter + copy(_IIter, _IIter, _OIter); + + template + _BIter2 + copy_backward(_BIter1, _BIter1, _BIter2); + +#if __cplusplus >= 201103L + template + _OIter + copy_if(_IIter, _IIter, _OIter, _Predicate); + + template + _OIter + copy_n(_IIter, _Size, _OIter); +#endif + + // count + // count_if + + template + pair<_FIter, _FIter> + equal_range(_FIter, _FIter, const _Tp&); + + template + pair<_FIter, _FIter> + equal_range(_FIter, _FIter, const _Tp&, _Compare); + + template + void + fill(_FIter, _FIter, const _Tp&); + + template + _OIter + fill_n(_OIter, _Size, const _Tp&); + + // find + + template + _FIter1 + find_end(_FIter1, _FIter1, _FIter2, _FIter2); + + template + _FIter1 + find_end(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate); + + // find_first_of + // find_if + +#if __cplusplus >= 201103L + template + _IIter + find_if_not(_IIter, _IIter, _Predicate); +#endif + + // for_each + // generate + // generate_n + + template + bool + includes(_IIter1, _IIter1, _IIter2, _IIter2); + + template + bool + includes(_IIter1, _IIter1, _IIter2, _IIter2, _Compare); + + template + void + inplace_merge(_BIter, _BIter, _BIter); + + template + void + inplace_merge(_BIter, _BIter, _BIter, _Compare); + +#if __cplusplus >= 201103L + template + bool + is_heap(_RAIter, _RAIter); + + template + bool + is_heap(_RAIter, _RAIter, _Compare); + + template + _RAIter + is_heap_until(_RAIter, _RAIter); + + template + _RAIter + is_heap_until(_RAIter, _RAIter, _Compare); + + template + bool + is_partitioned(_IIter, _IIter, _Predicate); + + template + bool + is_permutation(_FIter1, _FIter1, _FIter2); + + template + bool + is_permutation(_FIter1, _FIter1, _FIter2, _BinaryPredicate); + + template + bool + is_sorted(_FIter, _FIter); + + template + bool + is_sorted(_FIter, _FIter, _Compare); + + template + _FIter + is_sorted_until(_FIter, _FIter); + + template + _FIter + is_sorted_until(_FIter, _FIter, _Compare); +#endif + + template + void + iter_swap(_FIter1, _FIter2); + + template + _FIter + lower_bound(_FIter, _FIter, const _Tp&); + + template + _FIter + lower_bound(_FIter, _FIter, const _Tp&, _Compare); + + template + void + make_heap(_RAIter, _RAIter); + + template + void + make_heap(_RAIter, _RAIter, _Compare); + + template + _GLIBCXX14_CONSTEXPR + const _Tp& + max(const _Tp&, const _Tp&); + + template + _GLIBCXX14_CONSTEXPR + const _Tp& + max(const _Tp&, const _Tp&, _Compare); + + // max_element + // merge + + template + _GLIBCXX14_CONSTEXPR + const _Tp& + min(const _Tp&, const _Tp&); + + template + _GLIBCXX14_CONSTEXPR + const _Tp& + min(const _Tp&, const _Tp&, _Compare); + + // min_element + +#if __cplusplus >= 201103L + template + _GLIBCXX14_CONSTEXPR + pair + minmax(const _Tp&, const _Tp&); + + template + _GLIBCXX14_CONSTEXPR + pair + minmax(const _Tp&, const _Tp&, _Compare); + + template + _GLIBCXX14_CONSTEXPR + pair<_FIter, _FIter> + minmax_element(_FIter, _FIter); + + template + _GLIBCXX14_CONSTEXPR + pair<_FIter, _FIter> + minmax_element(_FIter, _FIter, _Compare); + + template + _GLIBCXX14_CONSTEXPR + _Tp + min(initializer_list<_Tp>); + + template + _GLIBCXX14_CONSTEXPR + _Tp + min(initializer_list<_Tp>, _Compare); + + template + _GLIBCXX14_CONSTEXPR + _Tp + max(initializer_list<_Tp>); + + template + _GLIBCXX14_CONSTEXPR + _Tp + max(initializer_list<_Tp>, _Compare); + + template + _GLIBCXX14_CONSTEXPR + pair<_Tp, _Tp> + minmax(initializer_list<_Tp>); + + template + _GLIBCXX14_CONSTEXPR + pair<_Tp, _Tp> + minmax(initializer_list<_Tp>, _Compare); +#endif + + // mismatch + + template + bool + next_permutation(_BIter, _BIter); + + template + bool + next_permutation(_BIter, _BIter, _Compare); + +#if __cplusplus >= 201103L + template + bool + none_of(_IIter, _IIter, _Predicate); +#endif + + // nth_element + // partial_sort + + template + _RAIter + partial_sort_copy(_IIter, _IIter, _RAIter, _RAIter); + + template + _RAIter + partial_sort_copy(_IIter, _IIter, _RAIter, _RAIter, _Compare); + + // partition + +#if __cplusplus >= 201103L + template + pair<_OIter1, _OIter2> + partition_copy(_IIter, _IIter, _OIter1, _OIter2, _Predicate); + + template + _FIter + partition_point(_FIter, _FIter, _Predicate); +#endif + + template + void + pop_heap(_RAIter, _RAIter); + + template + void + pop_heap(_RAIter, _RAIter, _Compare); + + template + bool + prev_permutation(_BIter, _BIter); + + template + bool + prev_permutation(_BIter, _BIter, _Compare); + + template + void + push_heap(_RAIter, _RAIter); + + template + void + push_heap(_RAIter, _RAIter, _Compare); + + // random_shuffle + + template + _FIter + remove(_FIter, _FIter, const _Tp&); + + template + _FIter + remove_if(_FIter, _FIter, _Predicate); + + template + _OIter + remove_copy(_IIter, _IIter, _OIter, const _Tp&); + + template + _OIter + remove_copy_if(_IIter, _IIter, _OIter, _Predicate); + + // replace + + template + _OIter + replace_copy(_IIter, _IIter, _OIter, const _Tp&, const _Tp&); + + template + _OIter + replace_copy_if(_Iter, _Iter, _OIter, _Predicate, const _Tp&); + + // replace_if + + template + void + reverse(_BIter, _BIter); + + template + _OIter + reverse_copy(_BIter, _BIter, _OIter); + + inline namespace _V2 + { + template + _FIter + rotate(_FIter, _FIter, _FIter); + } + + template + _OIter + rotate_copy(_FIter, _FIter, _FIter, _OIter); + + // search + // search_n + // set_difference + // set_intersection + // set_symmetric_difference + // set_union + +#if (__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99_STDINT_TR1) + template + void + shuffle(_RAIter, _RAIter, _UGenerator&&); +#endif + + template + void + sort_heap(_RAIter, _RAIter); + + template + void + sort_heap(_RAIter, _RAIter, _Compare); + + template + _BIter + stable_partition(_BIter, _BIter, _Predicate); + +#if __cplusplus < 201103L + // For C++11 swap() is declared in . + + template + inline void + swap(_Tp& __a, _Tp& __b); + + template + inline void + swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]); +#endif + + template + _FIter2 + swap_ranges(_FIter1, _FIter1, _FIter2); + + // transform + + template + _FIter + unique(_FIter, _FIter); + + template + _FIter + unique(_FIter, _FIter, _BinaryPredicate); + + // unique_copy + + template + _FIter + upper_bound(_FIter, _FIter, const _Tp&); + + template + _FIter + upper_bound(_FIter, _FIter, const _Tp&, _Compare); + +_GLIBCXX_END_NAMESPACE_VERSION + +_GLIBCXX_BEGIN_NAMESPACE_ALGO + + template + _FIter + adjacent_find(_FIter, _FIter); + + template + _FIter + adjacent_find(_FIter, _FIter, _BinaryPredicate); + + template + typename iterator_traits<_IIter>::difference_type + count(_IIter, _IIter, const _Tp&); + + template + typename iterator_traits<_IIter>::difference_type + count_if(_IIter, _IIter, _Predicate); + + template + bool + equal(_IIter1, _IIter1, _IIter2); + + template + bool + equal(_IIter1, _IIter1, _IIter2, _BinaryPredicate); + + template + _IIter + find(_IIter, _IIter, const _Tp&); + + template + _FIter1 + find_first_of(_FIter1, _FIter1, _FIter2, _FIter2); + + template + _FIter1 + find_first_of(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate); + + template + _IIter + find_if(_IIter, _IIter, _Predicate); + + template + _Funct + for_each(_IIter, _IIter, _Funct); + + template + void + generate(_FIter, _FIter, _Generator); + + template + _OIter + generate_n(_OIter, _Size, _Generator); + + template + bool + lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2); + + template + bool + lexicographical_compare(_IIter1, _IIter1, _IIter2, _IIter2, _Compare); + + template + _GLIBCXX14_CONSTEXPR + _FIter + max_element(_FIter, _FIter); + + template + _GLIBCXX14_CONSTEXPR + _FIter + max_element(_FIter, _FIter, _Compare); + + template + _OIter + merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter); + + template + _OIter + merge(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare); + + template + _GLIBCXX14_CONSTEXPR + _FIter + min_element(_FIter, _FIter); + + template + _GLIBCXX14_CONSTEXPR + _FIter + min_element(_FIter, _FIter, _Compare); + + template + pair<_IIter1, _IIter2> + mismatch(_IIter1, _IIter1, _IIter2); + + template + pair<_IIter1, _IIter2> + mismatch(_IIter1, _IIter1, _IIter2, _BinaryPredicate); + + template + void + nth_element(_RAIter, _RAIter, _RAIter); + + template + void + nth_element(_RAIter, _RAIter, _RAIter, _Compare); + + template + void + partial_sort(_RAIter, _RAIter, _RAIter); + + template + void + partial_sort(_RAIter, _RAIter, _RAIter, _Compare); + + template + _BIter + partition(_BIter, _BIter, _Predicate); + + template + void + random_shuffle(_RAIter, _RAIter); + + template + void + random_shuffle(_RAIter, _RAIter, +#if __cplusplus >= 201103L + _Generator&&); +#else + _Generator&); +#endif + + template + void + replace(_FIter, _FIter, const _Tp&, const _Tp&); + + template + void + replace_if(_FIter, _FIter, _Predicate, const _Tp&); + + template + _FIter1 + search(_FIter1, _FIter1, _FIter2, _FIter2); + + template + _FIter1 + search(_FIter1, _FIter1, _FIter2, _FIter2, _BinaryPredicate); + + template + _FIter + search_n(_FIter, _FIter, _Size, const _Tp&); + + template + _FIter + search_n(_FIter, _FIter, _Size, const _Tp&, _BinaryPredicate); + + template + _OIter + set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter); + + template + _OIter + set_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare); + + template + _OIter + set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter); + + template + _OIter + set_intersection(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare); + + template + _OIter + set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, _OIter); + + template + _OIter + set_symmetric_difference(_IIter1, _IIter1, _IIter2, _IIter2, + _OIter, _Compare); + + template + _OIter + set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter); + + template + _OIter + set_union(_IIter1, _IIter1, _IIter2, _IIter2, _OIter, _Compare); + + template + void + sort(_RAIter, _RAIter); + + template + void + sort(_RAIter, _RAIter, _Compare); + + template + void + stable_sort(_RAIter, _RAIter); + + template + void + stable_sort(_RAIter, _RAIter, _Compare); + + template + _OIter + transform(_IIter, _IIter, _OIter, _UnaryOperation); + + template + _OIter + transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation); + + template + _OIter + unique_copy(_IIter, _IIter, _OIter); + + template + _OIter + unique_copy(_IIter, _IIter, _OIter, _BinaryPredicate); + +_GLIBCXX_END_NAMESPACE_ALGO +} // namespace std + +#ifdef _GLIBCXX_PARALLEL +# include +#endif + +#endif diff --git a/AH/STL/Fallback/bits/alloc_traits.h b/AH/STL/Fallback/bits/alloc_traits.h new file mode 100644 index 0000000..80116b3 --- /dev/null +++ b/AH/STL/Fallback/bits/alloc_traits.h @@ -0,0 +1,605 @@ +// Allocator traits -*- C++ -*- + +// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/alloc_traits.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _ALLOC_TRAITS_H +#define _ALLOC_TRAITS_H 1 + +#if __cplusplus >= 201103L + +#include "../bits/memoryfwd.h" +#include "../bits/ptr_traits.h" +#include "../ext/numeric_traits.h" + +#define __cpp_lib_allocator_traits_is_always_equal 201411 + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct __allocator_traits_base + { + template + struct __rebind : __replace_first_arg<_Tp, _Up> { }; + + template + struct __rebind<_Tp, _Up, + __void_t::other>> + { using type = typename _Tp::template rebind<_Up>::other; }; + + protected: + template + using __pointer = typename _Tp::pointer; + template + using __c_pointer = typename _Tp::const_pointer; + template + using __v_pointer = typename _Tp::void_pointer; + template + using __cv_pointer = typename _Tp::const_void_pointer; + template + using __pocca = typename _Tp::propagate_on_container_copy_assignment; + template + using __pocma = typename _Tp::propagate_on_container_move_assignment; + template + using __pocs = typename _Tp::propagate_on_container_swap; + template + using __equal = typename _Tp::is_always_equal; + }; + + template + using __alloc_rebind + = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type; + + /** + * @brief Uniform interface to all allocator types. + * @ingroup allocators + */ + template + struct allocator_traits : __allocator_traits_base + { + /// The allocator type + typedef _Alloc allocator_type; + /// The allocated type + typedef typename _Alloc::value_type value_type; + + /** + * @brief The allocator's pointer type. + * + * @c Alloc::pointer if that type exists, otherwise @c value_type* + */ + using pointer = __detected_or_t; + + private: + // Select _Func<_Alloc> or pointer_traits::rebind<_Tp> + template class _Func, typename _Tp, typename = void> + struct _Ptr + { + using type = typename pointer_traits::template rebind<_Tp>; + }; + + template class _Func, typename _Tp> + struct _Ptr<_Func, _Tp, __void_t<_Func<_Alloc>>> + { + using type = _Func<_Alloc>; + }; + + // Select _A2::difference_type or pointer_traits<_Ptr>::difference_type + template + struct _Diff + { using type = typename pointer_traits<_PtrT>::difference_type; }; + + template + struct _Diff<_A2, _PtrT, __void_t> + { using type = typename _A2::difference_type; }; + + // Select _A2::size_type or make_unsigned<_DiffT>::type + template + struct _Size : make_unsigned<_DiffT> { }; + + template + struct _Size<_A2, _DiffT, __void_t> + { using type = typename _A2::size_type; }; + + public: + /** + * @brief The allocator's const pointer type. + * + * @c Alloc::const_pointer if that type exists, otherwise + * pointer_traits::rebind + */ + using const_pointer = typename _Ptr<__c_pointer, const value_type>::type; + + /** + * @brief The allocator's void pointer type. + * + * @c Alloc::void_pointer if that type exists, otherwise + * pointer_traits::rebind + */ + using void_pointer = typename _Ptr<__v_pointer, void>::type; + + /** + * @brief The allocator's const void pointer type. + * + * @c Alloc::const_void_pointer if that type exists, otherwise + * pointer_traits::rebind + */ + using const_void_pointer = typename _Ptr<__cv_pointer, const void>::type; + + /** + * @brief The allocator's difference type + * + * @c Alloc::difference_type if that type exists, otherwise + * pointer_traits::difference_type + */ + using difference_type = typename _Diff<_Alloc, pointer>::type; + + /** + * @brief The allocator's size type + * + * @c Alloc::size_type if that type exists, otherwise + * make_unsigned::type + */ + using size_type = typename _Size<_Alloc, difference_type>::type; + + /** + * @brief How the allocator is propagated on copy assignment + * + * @c Alloc::propagate_on_container_copy_assignment if that type exists, + * otherwise @c false_type + */ + using propagate_on_container_copy_assignment + = __detected_or_t; + + /** + * @brief How the allocator is propagated on move assignment + * + * @c Alloc::propagate_on_container_move_assignment if that type exists, + * otherwise @c false_type + */ + using propagate_on_container_move_assignment + = __detected_or_t; + + /** + * @brief How the allocator is propagated on swap + * + * @c Alloc::propagate_on_container_swap if that type exists, + * otherwise @c false_type + */ + using propagate_on_container_swap + = __detected_or_t; + + /** + * @brief Whether all instances of the allocator type compare equal. + * + * @c Alloc::is_always_equal if that type exists, + * otherwise @c is_empty::type + */ + using is_always_equal + = __detected_or_t::type, __equal, _Alloc>; + + template + using rebind_alloc = __alloc_rebind<_Alloc, _Tp>; + template + using rebind_traits = allocator_traits>; + + private: + template + static auto + _S_allocate(_Alloc2& __a, size_type __n, const_void_pointer __hint, int) + -> decltype(__a.allocate(__n, __hint)) + { return __a.allocate(__n, __hint); } + + template + static pointer + _S_allocate(_Alloc2& __a, size_type __n, const_void_pointer, ...) + { return __a.allocate(__n); } + + template + struct __construct_helper + { + template()->construct( + std::declval<_Tp*>(), std::declval<_Args>()...))> + static true_type __test(int); + + template + static false_type __test(...); + + using type = decltype(__test<_Alloc>(0)); + }; + + template + using __has_construct + = typename __construct_helper<_Tp, _Args...>::type; + + template + static _Require<__has_construct<_Tp, _Args...>> + _S_construct(_Alloc& __a, _Tp* __p, _Args&&... __args) + { __a.construct(__p, std::forward<_Args>(__args)...); } + + template + static + _Require<__and_<__not_<__has_construct<_Tp, _Args...>>, + is_constructible<_Tp, _Args...>>> + _S_construct(_Alloc&, _Tp* __p, _Args&&... __args) + { ::new((void*)__p) _Tp(std::forward<_Args>(__args)...); } + + template + static auto + _S_destroy(_Alloc2& __a, _Tp* __p, int) + -> decltype(__a.destroy(__p)) + { __a.destroy(__p); } + + template + static void + _S_destroy(_Alloc2&, _Tp* __p, ...) + { __p->~_Tp(); } + + template + static auto + _S_max_size(_Alloc2& __a, int) + -> decltype(__a.max_size()) + { return __a.max_size(); } + + template + static size_type + _S_max_size(_Alloc2&, ...) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2466. allocator_traits::max_size() default behavior is incorrect + return __gnu_cxx::__numeric_traits::__max + / sizeof(value_type); + } + + template + static auto + _S_select(_Alloc2& __a, int) + -> decltype(__a.select_on_container_copy_construction()) + { return __a.select_on_container_copy_construction(); } + + template + static _Alloc2 + _S_select(_Alloc2& __a, ...) + { return __a; } + + public: + + /** + * @brief Allocate memory. + * @param __a An allocator. + * @param __n The number of objects to allocate space for. + * + * Calls @c a.allocate(n) + */ + static pointer + allocate(_Alloc& __a, size_type __n) + { return __a.allocate(__n); } + + /** + * @brief Allocate memory. + * @param __a An allocator. + * @param __n The number of objects to allocate space for. + * @param __hint Aid to locality. + * @return Memory of suitable size and alignment for @a n objects + * of type @c value_type + * + * Returns a.allocate(n, hint) if that expression is + * well-formed, otherwise returns @c a.allocate(n) + */ + static pointer + allocate(_Alloc& __a, size_type __n, const_void_pointer __hint) + { return _S_allocate(__a, __n, __hint, 0); } + + /** + * @brief Deallocate memory. + * @param __a An allocator. + * @param __p Pointer to the memory to deallocate. + * @param __n The number of objects space was allocated for. + * + * Calls a.deallocate(p, n) + */ + static void + deallocate(_Alloc& __a, pointer __p, size_type __n) + { __a.deallocate(__p, __n); } + + /** + * @brief Construct an object of type @a _Tp + * @param __a An allocator. + * @param __p Pointer to memory of suitable size and alignment for Tp + * @param __args Constructor arguments. + * + * Calls __a.construct(__p, std::forward(__args)...) + * if that expression is well-formed, otherwise uses placement-new + * to construct an object of type @a _Tp at location @a __p from the + * arguments @a __args... + */ + template + static auto construct(_Alloc& __a, _Tp* __p, _Args&&... __args) + -> decltype(_S_construct(__a, __p, std::forward<_Args>(__args)...)) + { _S_construct(__a, __p, std::forward<_Args>(__args)...); } + + /** + * @brief Destroy an object of type @a _Tp + * @param __a An allocator. + * @param __p Pointer to the object to destroy + * + * Calls @c __a.destroy(__p) if that expression is well-formed, + * otherwise calls @c __p->~_Tp() + */ + template + static void destroy(_Alloc& __a, _Tp* __p) + { _S_destroy(__a, __p, 0); } + + /** + * @brief The maximum supported allocation size + * @param __a An allocator. + * @return @c __a.max_size() or @c numeric_limits::max() + * + * Returns @c __a.max_size() if that expression is well-formed, + * otherwise returns @c numeric_limits::max() + */ + static size_type max_size(const _Alloc& __a) noexcept + { return _S_max_size(__a, 0); } + + /** + * @brief Obtain an allocator to use when copying a container. + * @param __rhs An allocator. + * @return @c __rhs.select_on_container_copy_construction() or @a __rhs + * + * Returns @c __rhs.select_on_container_copy_construction() if that + * expression is well-formed, otherwise returns @a __rhs + */ + static _Alloc + select_on_container_copy_construction(const _Alloc& __rhs) + { return _S_select(__rhs, 0); } + }; + + /// Partial specialization for std::allocator. + template + struct allocator_traits> + { + /// The allocator type + using allocator_type = allocator<_Tp>; + /// The allocated type + using value_type = _Tp; + + /// The allocator's pointer type. + using pointer = _Tp*; + + /// The allocator's const pointer type. + using const_pointer = const _Tp*; + + /// The allocator's void pointer type. + using void_pointer = void*; + + /// The allocator's const void pointer type. + using const_void_pointer = const void*; + + /// The allocator's difference type + using difference_type = std::ptrdiff_t; + + /// The allocator's size type + using size_type = std::size_t; + + /// How the allocator is propagated on copy assignment + using propagate_on_container_copy_assignment = false_type; + + /// How the allocator is propagated on move assignment + using propagate_on_container_move_assignment = true_type; + + /// How the allocator is propagated on swap + using propagate_on_container_swap = false_type; + + /// Whether all instances of the allocator type compare equal. + using is_always_equal = true_type; + + template + using rebind_alloc = allocator<_Up>; + + template + using rebind_traits = allocator_traits>; + + /** + * @brief Allocate memory. + * @param __a An allocator. + * @param __n The number of objects to allocate space for. + * + * Calls @c a.allocate(n) + */ + static pointer + allocate(allocator_type& __a, size_type __n) + { return __a.allocate(__n); } + + /** + * @brief Allocate memory. + * @param __a An allocator. + * @param __n The number of objects to allocate space for. + * @param __hint Aid to locality. + * @return Memory of suitable size and alignment for @a n objects + * of type @c value_type + * + * Returns a.allocate(n, hint) + */ + static pointer + allocate(allocator_type& __a, size_type __n, const_void_pointer __hint) + { return __a.allocate(__n, __hint); } + + /** + * @brief Deallocate memory. + * @param __a An allocator. + * @param __p Pointer to the memory to deallocate. + * @param __n The number of objects space was allocated for. + * + * Calls a.deallocate(p, n) + */ + static void + deallocate(allocator_type& __a, pointer __p, size_type __n) + { __a.deallocate(__p, __n); } + + /** + * @brief Construct an object of type @a _Up + * @param __a An allocator. + * @param __p Pointer to memory of suitable size and alignment for Tp + * @param __args Constructor arguments. + * + * Calls __a.construct(__p, std::forward(__args)...) + */ + template + static void + construct(allocator_type& __a, _Up* __p, _Args&&... __args) + { __a.construct(__p, std::forward<_Args>(__args)...); } + + /** + * @brief Destroy an object of type @a _Up + * @param __a An allocator. + * @param __p Pointer to the object to destroy + * + * Calls @c __a.destroy(__p). + */ + template + static void + destroy(allocator_type& __a, _Up* __p) + { __a.destroy(__p); } + + /** + * @brief The maximum supported allocation size + * @param __a An allocator. + * @return @c __a.max_size() + */ + static size_type + max_size(const allocator_type& __a) noexcept + { return __a.max_size(); } + + /** + * @brief Obtain an allocator to use when copying a container. + * @param __rhs An allocator. + * @return @c __rhs + */ + static allocator_type + select_on_container_copy_construction(const allocator_type& __rhs) + { return __rhs; } + }; + + + template + inline void + __do_alloc_on_copy(_Alloc& __one, const _Alloc& __two, true_type) + { __one = __two; } + + template + inline void + __do_alloc_on_copy(_Alloc&, const _Alloc&, false_type) + { } + + template + inline void __alloc_on_copy(_Alloc& __one, const _Alloc& __two) + { + typedef allocator_traits<_Alloc> __traits; + typedef typename __traits::propagate_on_container_copy_assignment __pocca; + __do_alloc_on_copy(__one, __two, __pocca()); + } + + template + inline _Alloc __alloc_on_copy(const _Alloc& __a) + { + typedef allocator_traits<_Alloc> __traits; + return __traits::select_on_container_copy_construction(__a); + } + + template + inline void __do_alloc_on_move(_Alloc& __one, _Alloc& __two, true_type) + { __one = std::move(__two); } + + template + inline void __do_alloc_on_move(_Alloc&, _Alloc&, false_type) + { } + + template + inline void __alloc_on_move(_Alloc& __one, _Alloc& __two) + { + typedef allocator_traits<_Alloc> __traits; + typedef typename __traits::propagate_on_container_move_assignment __pocma; + __do_alloc_on_move(__one, __two, __pocma()); + } + + template + inline void __do_alloc_on_swap(_Alloc& __one, _Alloc& __two, true_type) + { + using std::swap; + swap(__one, __two); + } + + template + inline void __do_alloc_on_swap(_Alloc&, _Alloc&, false_type) + { } + + template + inline void __alloc_on_swap(_Alloc& __one, _Alloc& __two) + { + typedef allocator_traits<_Alloc> __traits; + typedef typename __traits::propagate_on_container_swap __pocs; + __do_alloc_on_swap(__one, __two, __pocs()); + } + + template + class __is_copy_insertable_impl + { + typedef allocator_traits<_Alloc> _Traits; + + template(), + std::declval<_Up*>(), + std::declval()))> + static true_type + _M_select(int); + + template + static false_type + _M_select(...); + + public: + typedef decltype(_M_select(0)) type; + }; + + // true if _Alloc::value_type is CopyInsertable into containers using _Alloc + template + struct __is_copy_insertable + : __is_copy_insertable_impl<_Alloc>::type + { }; + + // std::allocator<_Tp> just requires CopyConstructible + template + struct __is_copy_insertable> + : is_copy_constructible<_Tp> + { }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif +#endif diff --git a/AH/STL/Fallback/bits/allocator.h b/AH/STL/Fallback/bits/allocator.h new file mode 100644 index 0000000..9d2f042 --- /dev/null +++ b/AH/STL/Fallback/bits/allocator.h @@ -0,0 +1,238 @@ +// Allocators -*- C++ -*- + +// Copyright (C) 2001-2015 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * Copyright (c) 1996-1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/allocator.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _ALLOCATOR_H +#define _ALLOCATOR_H 1 + +#include "../bits/c++allocator.h" // Define the base class to std::allocator. +#include "../bits/memoryfwd.h" +#if __cplusplus >= 201103L +#include "../type_traits" +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup allocators + * @{ + */ + + /// allocator specialization. + template<> + class allocator + { + public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef void* pointer; + typedef const void* const_pointer; + typedef void value_type; + + template + struct rebind + { typedef allocator<_Tp1> other; }; + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2103. std::allocator propagate_on_container_move_assignment + typedef true_type propagate_on_container_move_assignment; + + template + void + construct(_Up* __p, _Args&&... __args) + { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } + + template + void + destroy(_Up* __p) { __p->~_Up(); } +#endif + }; + + /** + * @brief The @a standard allocator, as per [20.4]. + * + * See https://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.allocator + * for further details. + * + * @tparam _Tp Type of allocated object. + */ + template + class allocator: public __allocator_base<_Tp> + { + public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp value_type; + + template + struct rebind + { typedef allocator<_Tp1> other; }; + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2103. std::allocator propagate_on_container_move_assignment + typedef true_type propagate_on_container_move_assignment; +#endif + + allocator() throw() { } + + allocator(const allocator& __a) throw() + : __allocator_base<_Tp>(__a) { } + + template + allocator(const allocator<_Tp1>&) throw() { } + + ~allocator() throw() { } + + // Inherit everything else. + }; + + template + inline bool + operator==(const allocator<_T1>&, const allocator<_T2>&) + _GLIBCXX_USE_NOEXCEPT + { return true; } + + template + inline bool + operator==(const allocator<_Tp>&, const allocator<_Tp>&) + _GLIBCXX_USE_NOEXCEPT + { return true; } + + template + inline bool + operator!=(const allocator<_T1>&, const allocator<_T2>&) + _GLIBCXX_USE_NOEXCEPT + { return false; } + + template + inline bool + operator!=(const allocator<_Tp>&, const allocator<_Tp>&) + _GLIBCXX_USE_NOEXCEPT + { return false; } + + /// @} group allocator + + // Inhibit implicit instantiations for required instantiations, + // which are defined via explicit instantiations elsewhere. +#if _GLIBCXX_EXTERN_TEMPLATE + extern template class allocator; + extern template class allocator; +#endif + + // Undefine. +#undef __allocator_base + + // To implement Option 3 of DR 431. + template + struct __alloc_swap + { static void _S_do_it(_Alloc&, _Alloc&) _GLIBCXX_NOEXCEPT { } }; + + template + struct __alloc_swap<_Alloc, false> + { + static void + _S_do_it(_Alloc& __one, _Alloc& __two) _GLIBCXX_NOEXCEPT + { + // Precondition: swappable allocators. + if (__one != __two) + swap(__one, __two); + } + }; + + // Optimize for stateless allocators. + template + struct __alloc_neq + { + static bool + _S_do_it(const _Alloc&, const _Alloc&) + { return false; } + }; + + template + struct __alloc_neq<_Alloc, false> + { + static bool + _S_do_it(const _Alloc& __one, const _Alloc& __two) + { return __one != __two; } + }; + +#if __cplusplus >= 201103L + template, + is_nothrow_move_constructible>::value> + struct __shrink_to_fit_aux + { static bool _S_do_it(_Tp&) noexcept { return false; } }; + + template + struct __shrink_to_fit_aux<_Tp, true> + { + static bool + _S_do_it(_Tp& __c) noexcept + { +#if __cpp_exceptions + try + { + _Tp(__make_move_if_noexcept_iterator(__c.begin()), + __make_move_if_noexcept_iterator(__c.end()), + __c.get_allocator()).swap(__c); + return true; + } + catch(...) + { return false; } +#else + return false; +#endif + } + }; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif diff --git a/AH/STL/Fallback/bits/boost_concept_check.h b/AH/STL/Fallback/bits/boost_concept_check.h new file mode 100644 index 0000000..46269ec --- /dev/null +++ b/AH/STL/Fallback/bits/boost_concept_check.h @@ -0,0 +1,788 @@ +// -*- C++ -*- + +// Copyright (C) 2004-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +// (C) Copyright Jeremy Siek 2000. Permission to copy, use, modify, +// sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. +// + +/** @file bits/boost_concept_check.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + */ + +// GCC Note: based on version 1.12.0 of the Boost library. + +#ifndef _BOOST_CONCEPT_CHECK_H +#define _BOOST_CONCEPT_CHECK_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" +#include "../bits/stl_iterator_base_types.h" // for traits and tags + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#define _IsUnused __attribute__ ((__unused__)) + +// When the C-C code is in use, we would like this function to do as little +// as possible at runtime, use as few resources as possible, and hopefully +// be elided out of existence... hmmm. +template +inline void __function_requires() +{ + void (_Concept::*__x)() _IsUnused = &_Concept::__constraints; +} + +// No definition: if this is referenced, there's a problem with +// the instantiating type not being one of the required integer types. +// Unfortunately, this results in a link-time error, not a compile-time error. +void __error_type_must_be_an_integer_type(); +void __error_type_must_be_an_unsigned_integer_type(); +void __error_type_must_be_a_signed_integer_type(); + +// ??? Should the "concept_checking*" structs begin with more than _ ? +#define _GLIBCXX_CLASS_REQUIRES(_type_var, _ns, _concept) \ + typedef void (_ns::_concept <_type_var>::* _func##_type_var##_concept)(); \ + template <_func##_type_var##_concept _Tp1> \ + struct _concept_checking##_type_var##_concept { }; \ + typedef _concept_checking##_type_var##_concept< \ + &_ns::_concept <_type_var>::__constraints> \ + _concept_checking_typedef##_type_var##_concept + +#define _GLIBCXX_CLASS_REQUIRES2(_type_var1, _type_var2, _ns, _concept) \ + typedef void (_ns::_concept <_type_var1,_type_var2>::* _func##_type_var1##_type_var2##_concept)(); \ + template <_func##_type_var1##_type_var2##_concept _Tp1> \ + struct _concept_checking##_type_var1##_type_var2##_concept { }; \ + typedef _concept_checking##_type_var1##_type_var2##_concept< \ + &_ns::_concept <_type_var1,_type_var2>::__constraints> \ + _concept_checking_typedef##_type_var1##_type_var2##_concept + +#define _GLIBCXX_CLASS_REQUIRES3(_type_var1, _type_var2, _type_var3, _ns, _concept) \ + typedef void (_ns::_concept <_type_var1,_type_var2,_type_var3>::* _func##_type_var1##_type_var2##_type_var3##_concept)(); \ + template <_func##_type_var1##_type_var2##_type_var3##_concept _Tp1> \ + struct _concept_checking##_type_var1##_type_var2##_type_var3##_concept { }; \ + typedef _concept_checking##_type_var1##_type_var2##_type_var3##_concept< \ + &_ns::_concept <_type_var1,_type_var2,_type_var3>::__constraints> \ + _concept_checking_typedef##_type_var1##_type_var2##_type_var3##_concept + +#define _GLIBCXX_CLASS_REQUIRES4(_type_var1, _type_var2, _type_var3, _type_var4, _ns, _concept) \ + typedef void (_ns::_concept <_type_var1,_type_var2,_type_var3,_type_var4>::* _func##_type_var1##_type_var2##_type_var3##_type_var4##_concept)(); \ + template <_func##_type_var1##_type_var2##_type_var3##_type_var4##_concept _Tp1> \ + struct _concept_checking##_type_var1##_type_var2##_type_var3##_type_var4##_concept { }; \ + typedef _concept_checking##_type_var1##_type_var2##_type_var3##_type_var4##_concept< \ + &_ns::_concept <_type_var1,_type_var2,_type_var3,_type_var4>::__constraints> \ + _concept_checking_typedef##_type_var1##_type_var2##_type_var3##_type_var4##_concept + + +template +struct _Aux_require_same { }; + +template +struct _Aux_require_same<_Tp,_Tp> { typedef _Tp _Type; }; + + template + struct _SameTypeConcept + { + void __constraints() { + typedef typename _Aux_require_same<_Tp1, _Tp2>::_Type _Required; + } + }; + + template + struct _IntegerConcept { + void __constraints() { + __error_type_must_be_an_integer_type(); + } + }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept { void __constraints(){} }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept { void __constraints() {} }; + template <> struct _IntegerConcept + { void __constraints() {} }; + + template + struct _SignedIntegerConcept { + void __constraints() { + __error_type_must_be_a_signed_integer_type(); + } + }; + template <> struct _SignedIntegerConcept { void __constraints() {} }; + template <> struct _SignedIntegerConcept { void __constraints() {} }; + template <> struct _SignedIntegerConcept { void __constraints() {} }; + template <> struct _SignedIntegerConcept { void __constraints(){}}; + + template + struct _UnsignedIntegerConcept { + void __constraints() { + __error_type_must_be_an_unsigned_integer_type(); + } + }; + template <> struct _UnsignedIntegerConcept + { void __constraints() {} }; + template <> struct _UnsignedIntegerConcept + { void __constraints() {} }; + template <> struct _UnsignedIntegerConcept + { void __constraints() {} }; + template <> struct _UnsignedIntegerConcept + { void __constraints() {} }; + + //=========================================================================== + // Basic Concepts + + template + struct _DefaultConstructibleConcept + { + void __constraints() { + _Tp __a _IsUnused; // require default constructor + } + }; + + template + struct _AssignableConcept + { + void __constraints() { + __a = __a; // require assignment operator + __const_constraints(__a); + } + void __const_constraints(const _Tp& __b) { + __a = __b; // const required for argument to assignment + } + _Tp __a; + // possibly should be "Tp* a;" and then dereference "a" in constraint + // functions? present way would require a default ctor, i think... + }; + + template + struct _CopyConstructibleConcept + { + void __constraints() { + _Tp __a(__b); // require copy constructor + _Tp* __ptr _IsUnused = &__a; // require address of operator + __const_constraints(__a); + } + void __const_constraints(const _Tp& __a) { + _Tp __c _IsUnused(__a); // require const copy constructor + const _Tp* __ptr _IsUnused = &__a; // require const address of operator + } + _Tp __b; + }; + + // The SGI STL version of Assignable requires copy constructor and operator= + template + struct _SGIAssignableConcept + { + void __constraints() { + _Tp __b _IsUnused(__a); + __a = __a; // require assignment operator + __const_constraints(__a); + } + void __const_constraints(const _Tp& __b) { + _Tp __c _IsUnused(__b); + __a = __b; // const required for argument to assignment + } + _Tp __a; + }; + + template + struct _ConvertibleConcept + { + void __constraints() { + _To __y _IsUnused = __x; + } + _From __x; + }; + + // The C++ standard requirements for many concepts talk about return + // types that must be "convertible to bool". The problem with this + // requirement is that it leaves the door open for evil proxies that + // define things like operator|| with strange return types. Two + // possible solutions are: + // 1) require the return type to be exactly bool + // 2) stay with convertible to bool, and also + // specify stuff about all the logical operators. + // For now we just test for convertible to bool. + template + void __aux_require_boolean_expr(const _Tp& __t) { + bool __x _IsUnused = __t; + } + +// FIXME + template + struct _EqualityComparableConcept + { + void __constraints() { + __aux_require_boolean_expr(__a == __b); + } + _Tp __a, __b; + }; + + template + struct _LessThanComparableConcept + { + void __constraints() { + __aux_require_boolean_expr(__a < __b); + } + _Tp __a, __b; + }; + + // This is equivalent to SGI STL's LessThanComparable. + template + struct _ComparableConcept + { + void __constraints() { + __aux_require_boolean_expr(__a < __b); + __aux_require_boolean_expr(__a > __b); + __aux_require_boolean_expr(__a <= __b); + __aux_require_boolean_expr(__a >= __b); + } + _Tp __a, __b; + }; + +#define _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(_OP,_NAME) \ + template \ + struct _NAME { \ + void __constraints() { (void)__constraints_(); } \ + bool __constraints_() { \ + return __a _OP __b; \ + } \ + _First __a; \ + _Second __b; \ + } + +#define _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(_OP,_NAME) \ + template \ + struct _NAME { \ + void __constraints() { (void)__constraints_(); } \ + _Ret __constraints_() { \ + return __a _OP __b; \ + } \ + _First __a; \ + _Second __b; \ + } + + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(==, _EqualOpConcept); + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(!=, _NotEqualOpConcept); + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(<, _LessThanOpConcept); + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(<=, _LessEqualOpConcept); + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(>, _GreaterThanOpConcept); + _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(>=, _GreaterEqualOpConcept); + + _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(+, _PlusOpConcept); + _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(*, _TimesOpConcept); + _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(/, _DivideOpConcept); + _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(-, _SubtractOpConcept); + _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT(%, _ModOpConcept); + +#undef _GLIBCXX_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT +#undef _GLIBCXX_DEFINE_BINARY_OPERATOR_CONSTRAINT + + //=========================================================================== + // Function Object Concepts + + template + struct _GeneratorConcept + { + void __constraints() { + const _Return& __r _IsUnused = __f();// require operator() member function + } + _Func __f; + }; + + + template + struct _GeneratorConcept<_Func,void> + { + void __constraints() { + __f(); // require operator() member function + } + _Func __f; + }; + + template + struct _UnaryFunctionConcept + { + void __constraints() { + __r = __f(__arg); // require operator() + } + _Func __f; + _Arg __arg; + _Return __r; + }; + + template + struct _UnaryFunctionConcept<_Func, void, _Arg> { + void __constraints() { + __f(__arg); // require operator() + } + _Func __f; + _Arg __arg; + }; + + template + struct _BinaryFunctionConcept + { + void __constraints() { + __r = __f(__first, __second); // require operator() + } + _Func __f; + _First __first; + _Second __second; + _Return __r; + }; + + template + struct _BinaryFunctionConcept<_Func, void, _First, _Second> + { + void __constraints() { + __f(__first, __second); // require operator() + } + _Func __f; + _First __first; + _Second __second; + }; + + template + struct _UnaryPredicateConcept + { + void __constraints() { + __aux_require_boolean_expr(__f(__arg)); // require op() returning bool + } + _Func __f; + _Arg __arg; + }; + + template + struct _BinaryPredicateConcept + { + void __constraints() { + __aux_require_boolean_expr(__f(__a, __b)); // require op() returning bool + } + _Func __f; + _First __a; + _Second __b; + }; + + // use this when functor is used inside a container class like std::set + template + struct _Const_BinaryPredicateConcept { + void __constraints() { + __const_constraints(__f); + } + void __const_constraints(const _Func& __fun) { + __function_requires<_BinaryPredicateConcept<_Func, _First, _Second> >(); + // operator() must be a const member function + __aux_require_boolean_expr(__fun(__a, __b)); + } + _Func __f; + _First __a; + _Second __b; + }; + + //=========================================================================== + // Iterator Concepts + + template + struct _TrivialIteratorConcept + { + void __constraints() { +// __function_requires< _DefaultConstructibleConcept<_Tp> >(); + __function_requires< _AssignableConcept<_Tp> >(); + __function_requires< _EqualityComparableConcept<_Tp> >(); +// typedef typename std::iterator_traits<_Tp>::value_type _V; + (void)*__i; // require dereference operator + } + _Tp __i; + }; + + template + struct _Mutable_TrivialIteratorConcept + { + void __constraints() { + __function_requires< _TrivialIteratorConcept<_Tp> >(); + *__i = *__j; // require dereference and assignment + } + _Tp __i, __j; + }; + + template + struct _InputIteratorConcept + { + void __constraints() { + __function_requires< _TrivialIteratorConcept<_Tp> >(); + // require iterator_traits typedef's + typedef typename std::iterator_traits<_Tp>::difference_type _Diff; +// __function_requires< _SignedIntegerConcept<_Diff> >(); + typedef typename std::iterator_traits<_Tp>::reference _Ref; + typedef typename std::iterator_traits<_Tp>::pointer _Pt; + typedef typename std::iterator_traits<_Tp>::iterator_category _Cat; + __function_requires< _ConvertibleConcept< + typename std::iterator_traits<_Tp>::iterator_category, + std::input_iterator_tag> >(); + ++__i; // require preincrement operator + __i++; // require postincrement operator + } + _Tp __i; + }; + + template + struct _OutputIteratorConcept + { + void __constraints() { + __function_requires< _AssignableConcept<_Tp> >(); + ++__i; // require preincrement operator + __i++; // require postincrement operator + *__i++ = __t; // require postincrement and assignment + } + _Tp __i; + _ValueT __t; + }; + + template + struct _ForwardIteratorConcept + { + void __constraints() { + __function_requires< _InputIteratorConcept<_Tp> >(); + __function_requires< _DefaultConstructibleConcept<_Tp> >(); + __function_requires< _ConvertibleConcept< + typename std::iterator_traits<_Tp>::iterator_category, + std::forward_iterator_tag> >(); + typedef typename std::iterator_traits<_Tp>::reference _Ref; + _Ref __r _IsUnused = *__i; + } + _Tp __i; + }; + + template + struct _Mutable_ForwardIteratorConcept + { + void __constraints() { + __function_requires< _ForwardIteratorConcept<_Tp> >(); + *__i++ = *__i; // require postincrement and assignment + } + _Tp __i; + }; + + template + struct _BidirectionalIteratorConcept + { + void __constraints() { + __function_requires< _ForwardIteratorConcept<_Tp> >(); + __function_requires< _ConvertibleConcept< + typename std::iterator_traits<_Tp>::iterator_category, + std::bidirectional_iterator_tag> >(); + --__i; // require predecrement operator + __i--; // require postdecrement operator + } + _Tp __i; + }; + + template + struct _Mutable_BidirectionalIteratorConcept + { + void __constraints() { + __function_requires< _BidirectionalIteratorConcept<_Tp> >(); + __function_requires< _Mutable_ForwardIteratorConcept<_Tp> >(); + *__i-- = *__i; // require postdecrement and assignment + } + _Tp __i; + }; + + + template + struct _RandomAccessIteratorConcept + { + void __constraints() { + __function_requires< _BidirectionalIteratorConcept<_Tp> >(); + __function_requires< _ComparableConcept<_Tp> >(); + __function_requires< _ConvertibleConcept< + typename std::iterator_traits<_Tp>::iterator_category, + std::random_access_iterator_tag> >(); + // ??? We don't use _Ref, are we just checking for "referenceability"? + typedef typename std::iterator_traits<_Tp>::reference _Ref; + + __i += __n; // require assignment addition operator + __i = __i + __n; __i = __n + __i; // require addition with difference type + __i -= __n; // require assignment subtraction op + __i = __i - __n; // require subtraction with + // difference type + __n = __i - __j; // require difference operator + (void)__i[__n]; // require element access operator + } + _Tp __a, __b; + _Tp __i, __j; + typename std::iterator_traits<_Tp>::difference_type __n; + }; + + template + struct _Mutable_RandomAccessIteratorConcept + { + void __constraints() { + __function_requires< _RandomAccessIteratorConcept<_Tp> >(); + __function_requires< _Mutable_BidirectionalIteratorConcept<_Tp> >(); + __i[__n] = *__i; // require element access and assignment + } + _Tp __i; + typename std::iterator_traits<_Tp>::difference_type __n; + }; + + //=========================================================================== + // Container Concepts + + template + struct _ContainerConcept + { + typedef typename _Container::value_type _Value_type; + typedef typename _Container::difference_type _Difference_type; + typedef typename _Container::size_type _Size_type; + typedef typename _Container::const_reference _Const_reference; + typedef typename _Container::const_pointer _Const_pointer; + typedef typename _Container::const_iterator _Const_iterator; + + void __constraints() { + __function_requires< _InputIteratorConcept<_Const_iterator> >(); + __function_requires< _AssignableConcept<_Container> >(); + const _Container __c; + __i = __c.begin(); + __i = __c.end(); + __n = __c.size(); + __n = __c.max_size(); + __b = __c.empty(); + } + bool __b; + _Const_iterator __i; + _Size_type __n; + }; + + template + struct _Mutable_ContainerConcept + { + typedef typename _Container::value_type _Value_type; + typedef typename _Container::reference _Reference; + typedef typename _Container::iterator _Iterator; + typedef typename _Container::pointer _Pointer; + + void __constraints() { + __function_requires< _ContainerConcept<_Container> >(); + __function_requires< _AssignableConcept<_Value_type> >(); + __function_requires< _InputIteratorConcept<_Iterator> >(); + + __i = __c.begin(); + __i = __c.end(); + __c.swap(__c2); + } + _Iterator __i; + _Container __c, __c2; + }; + + template + struct _ForwardContainerConcept + { + void __constraints() { + __function_requires< _ContainerConcept<_ForwardContainer> >(); + typedef typename _ForwardContainer::const_iterator _Const_iterator; + __function_requires< _ForwardIteratorConcept<_Const_iterator> >(); + } + }; + + template + struct _Mutable_ForwardContainerConcept + { + void __constraints() { + __function_requires< _ForwardContainerConcept<_ForwardContainer> >(); + __function_requires< _Mutable_ContainerConcept<_ForwardContainer> >(); + typedef typename _ForwardContainer::iterator _Iterator; + __function_requires< _Mutable_ForwardIteratorConcept<_Iterator> >(); + } + }; + + template + struct _ReversibleContainerConcept + { + typedef typename _ReversibleContainer::const_iterator _Const_iterator; + typedef typename _ReversibleContainer::const_reverse_iterator + _Const_reverse_iterator; + + void __constraints() { + __function_requires< _ForwardContainerConcept<_ReversibleContainer> >(); + __function_requires< _BidirectionalIteratorConcept<_Const_iterator> >(); + __function_requires< + _BidirectionalIteratorConcept<_Const_reverse_iterator> >(); + + const _ReversibleContainer __c; + _Const_reverse_iterator __i = __c.rbegin(); + __i = __c.rend(); + } + }; + + template + struct _Mutable_ReversibleContainerConcept + { + typedef typename _ReversibleContainer::iterator _Iterator; + typedef typename _ReversibleContainer::reverse_iterator _Reverse_iterator; + + void __constraints() { + __function_requires<_ReversibleContainerConcept<_ReversibleContainer> >(); + __function_requires< + _Mutable_ForwardContainerConcept<_ReversibleContainer> >(); + __function_requires<_Mutable_BidirectionalIteratorConcept<_Iterator> >(); + __function_requires< + _Mutable_BidirectionalIteratorConcept<_Reverse_iterator> >(); + + _Reverse_iterator __i = __c.rbegin(); + __i = __c.rend(); + } + _ReversibleContainer __c; + }; + + template + struct _RandomAccessContainerConcept + { + typedef typename _RandomAccessContainer::size_type _Size_type; + typedef typename _RandomAccessContainer::const_reference _Const_reference; + typedef typename _RandomAccessContainer::const_iterator _Const_iterator; + typedef typename _RandomAccessContainer::const_reverse_iterator + _Const_reverse_iterator; + + void __constraints() { + __function_requires< + _ReversibleContainerConcept<_RandomAccessContainer> >(); + __function_requires< _RandomAccessIteratorConcept<_Const_iterator> >(); + __function_requires< + _RandomAccessIteratorConcept<_Const_reverse_iterator> >(); + + const _RandomAccessContainer __c; + _Const_reference __r _IsUnused = __c[__n]; + } + _Size_type __n; + }; + + template + struct _Mutable_RandomAccessContainerConcept + { + typedef typename _RandomAccessContainer::size_type _Size_type; + typedef typename _RandomAccessContainer::reference _Reference; + typedef typename _RandomAccessContainer::iterator _Iterator; + typedef typename _RandomAccessContainer::reverse_iterator _Reverse_iterator; + + void __constraints() { + __function_requires< + _RandomAccessContainerConcept<_RandomAccessContainer> >(); + __function_requires< + _Mutable_ReversibleContainerConcept<_RandomAccessContainer> >(); + __function_requires< _Mutable_RandomAccessIteratorConcept<_Iterator> >(); + __function_requires< + _Mutable_RandomAccessIteratorConcept<_Reverse_iterator> >(); + + _Reference __r _IsUnused = __c[__i]; + } + _Size_type __i; + _RandomAccessContainer __c; + }; + + // A Sequence is inherently mutable + template + struct _SequenceConcept + { + typedef typename _Sequence::reference _Reference; + typedef typename _Sequence::const_reference _Const_reference; + + void __constraints() { + // Matt Austern's book puts DefaultConstructible here, the C++ + // standard places it in Container + // function_requires< DefaultConstructible >(); + __function_requires< _Mutable_ForwardContainerConcept<_Sequence> >(); + __function_requires< _DefaultConstructibleConcept<_Sequence> >(); + + _Sequence + __c _IsUnused(__n, __t), + __c2 _IsUnused(__first, __last); + + __c.insert(__p, __t); + __c.insert(__p, __n, __t); + __c.insert(__p, __first, __last); + + __c.erase(__p); + __c.erase(__p, __q); + + _Reference __r _IsUnused = __c.front(); + + __const_constraints(__c); + } + void __const_constraints(const _Sequence& __c) { + _Const_reference __r _IsUnused = __c.front(); + } + typename _Sequence::value_type __t; + typename _Sequence::size_type __n; + typename _Sequence::value_type *__first, *__last; + typename _Sequence::iterator __p, __q; + }; + + template + struct _FrontInsertionSequenceConcept + { + void __constraints() { + __function_requires< _SequenceConcept<_FrontInsertionSequence> >(); + + __c.push_front(__t); + __c.pop_front(); + } + _FrontInsertionSequence __c; + typename _FrontInsertionSequence::value_type __t; + }; + + template + struct _BackInsertionSequenceConcept + { + typedef typename _BackInsertionSequence::reference _Reference; + typedef typename _BackInsertionSequence::const_reference _Const_reference; + + void __constraints() { + __function_requires< _SequenceConcept<_BackInsertionSequence> >(); + + __c.push_back(__t); + __c.pop_back(); + _Reference __r _IsUnused = __c.back(); + } + void __const_constraints(const _BackInsertionSequence& __c) { + _Const_reference __r _IsUnused = __c.back(); + }; + _BackInsertionSequence __c; + typename _BackInsertionSequence::value_type __t; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#undef _IsUnused + +#endif // _GLIBCXX_BOOST_CONCEPT_CHECK diff --git a/AH/STL/Fallback/bits/c++0x_warning.h b/AH/STL/Fallback/bits/c++0x_warning.h new file mode 100644 index 0000000..d2bc714 --- /dev/null +++ b/AH/STL/Fallback/bits/c++0x_warning.h @@ -0,0 +1,37 @@ +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/c++0x_warning.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iosfwd} + */ + +#ifndef _CXX0X_WARNING_H +#define _CXX0X_WARNING_H 1 + +#if __cplusplus < 201103L +#error This file requires compiler and library support \ +for the ISO C++ 2011 standard. This support must be enabled \ +with the -std=c++11 or -std=gnu++11 compiler options. +#endif + +#endif diff --git a/AH/STL/Fallback/bits/c++allocator.h b/AH/STL/Fallback/bits/c++allocator.h new file mode 100644 index 0000000..034afc9 --- /dev/null +++ b/AH/STL/Fallback/bits/c++allocator.h @@ -0,0 +1,55 @@ +// Base to std::allocator -*- C++ -*- + +// Copyright (C) 2004-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/c++allocator.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _GLIBCXX_CXX_ALLOCATOR_H +#define _GLIBCXX_CXX_ALLOCATOR_H 1 + +#include "../ext/new_allocator.h" + +#if __cplusplus >= 201103L +namespace std +{ + /** + * @brief An alias to the base class for std::allocator. + * @ingroup allocators + * + * Used to set the std::allocator base class to + * __gnu_cxx::new_allocator. + * + * @tparam _Tp Type of allocated object. + */ + template + using __allocator_base = __gnu_cxx::new_allocator<_Tp>; +} +#else +// Define new_allocator as the base class to std::allocator. +# define __allocator_base __gnu_cxx::new_allocator +#endif + +#endif diff --git a/AH/STL/Fallback/bits/c++config.h b/AH/STL/Fallback/bits/c++config.h new file mode 100644 index 0000000..0c0e89d --- /dev/null +++ b/AH/STL/Fallback/bits/c++config.h @@ -0,0 +1,1962 @@ +// Predefined symbols and macros -*- C++ -*- + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/c++config.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iosfwd} + */ + +#ifndef _GLIBCXX_CXX_CONFIG_H +#define _GLIBCXX_CXX_CONFIG_H 1 + +// The major release number for the GCC release the C++ library belongs to. +#define _GLIBCXX_RELEASE 7 + +// The datestamp of the C++ library in compressed ISO date format. +#define __GLIBCXX__ 20181206 + +// Macros for various attributes. +// _GLIBCXX_PURE +// _GLIBCXX_CONST +// _GLIBCXX_NORETURN +// _GLIBCXX_NOTHROW +// _GLIBCXX_VISIBILITY +#ifndef _GLIBCXX_PURE +# define _GLIBCXX_PURE __attribute__ ((__pure__)) +#endif + +#ifndef _GLIBCXX_CONST +# define _GLIBCXX_CONST __attribute__ ((__const__)) +#endif + +#ifndef _GLIBCXX_NORETURN +# define _GLIBCXX_NORETURN __attribute__ ((__noreturn__)) +#endif + +// See below for C++ +#ifndef _GLIBCXX_NOTHROW +# ifndef __cplusplus +# define _GLIBCXX_NOTHROW __attribute__((__nothrow__)) +# endif +#endif + +// Macros for visibility attributes. +// _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY +// _GLIBCXX_VISIBILITY +# define _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY 1 + +#if _GLIBCXX_HAVE_ATTRIBUTE_VISIBILITY +# define _GLIBCXX_VISIBILITY(V) __attribute__ ((__visibility__ (#V))) +#else +// If this is not supplied by the OS-specific or CPU-specific +// headers included below, it will be defined to an empty default. +# define _GLIBCXX_VISIBILITY(V) _GLIBCXX_PSEUDO_VISIBILITY(V) +#endif + +// Macros for deprecated attributes. +// _GLIBCXX_USE_DEPRECATED +// _GLIBCXX_DEPRECATED +#ifndef _GLIBCXX_USE_DEPRECATED +# define _GLIBCXX_USE_DEPRECATED 1 +#endif + +#if defined(__DEPRECATED) && (__cplusplus >= 201103L) +# define _GLIBCXX_DEPRECATED __attribute__ ((__deprecated__)) +#else +# define _GLIBCXX_DEPRECATED +#endif + +// Macros for ABI tag attributes. +#ifndef _GLIBCXX_ABI_TAG_CXX11 +# define _GLIBCXX_ABI_TAG_CXX11 __attribute ((__abi_tag__ ("cxx11"))) +#endif + + +#if __cplusplus + +// Macro for constexpr, to support in mixed 03/0x mode. +#ifndef _GLIBCXX_CONSTEXPR +# if __cplusplus >= 201103L +# define _GLIBCXX_CONSTEXPR constexpr +# define _GLIBCXX_USE_CONSTEXPR constexpr +# else +# define _GLIBCXX_CONSTEXPR +# define _GLIBCXX_USE_CONSTEXPR const +# endif +#endif + +#ifndef _GLIBCXX14_CONSTEXPR +# if __cplusplus >= 201402L +# define _GLIBCXX14_CONSTEXPR constexpr +# else +# define _GLIBCXX14_CONSTEXPR +# endif +#endif + +#ifndef _GLIBCXX17_CONSTEXPR +# if __cplusplus > 201402L +# define _GLIBCXX17_CONSTEXPR constexpr +# else +# define _GLIBCXX17_CONSTEXPR +# endif +#endif + +#ifndef _GLIBCXX17_INLINE +# if __cplusplus > 201402L +# define _GLIBCXX17_INLINE inline +# else +# define _GLIBCXX17_INLINE +# endif +#endif + +// Macro for noexcept, to support in mixed 03/0x mode. +#ifndef _GLIBCXX_NOEXCEPT +# if __cplusplus >= 201103L +# define _GLIBCXX_NOEXCEPT noexcept +# define _GLIBCXX_NOEXCEPT_IF(_COND) noexcept(_COND) +# define _GLIBCXX_USE_NOEXCEPT noexcept +# define _GLIBCXX_THROW(_EXC) +# else +# define _GLIBCXX_NOEXCEPT +# define _GLIBCXX_NOEXCEPT_IF(_COND) +# define _GLIBCXX_USE_NOEXCEPT throw() +# define _GLIBCXX_THROW(_EXC) throw(_EXC) +# endif +#endif + +#ifndef _GLIBCXX_NOTHROW +# define _GLIBCXX_NOTHROW _GLIBCXX_USE_NOEXCEPT +#endif + +#ifndef _GLIBCXX_THROW_OR_ABORT +# if __cpp_exceptions +# define _GLIBCXX_THROW_OR_ABORT(_EXC) (throw (_EXC)) +# else +# define _GLIBCXX_THROW_OR_ABORT(_EXC) (__builtin_abort()) +# endif +#endif + +#if __cpp_noexcept_function_type +#define _GLIBCXX_NOEXCEPT_PARM , bool _NE +#define _GLIBCXX_NOEXCEPT_QUAL noexcept (_NE) +#else +#define _GLIBCXX_NOEXCEPT_PARM +#define _GLIBCXX_NOEXCEPT_QUAL +#endif + +// Macro for extern template, ie controlling template linkage via use +// of extern keyword on template declaration. As documented in the g++ +// manual, it inhibits all implicit instantiations and is used +// throughout the library to avoid multiple weak definitions for +// required types that are already explicitly instantiated in the +// library binary. This substantially reduces the binary size of +// resulting executables. +// Special case: _GLIBCXX_EXTERN_TEMPLATE == -1 disallows extern +// templates only in basic_string, thus activating its debug-mode +// checks even at -O0. +# define _GLIBCXX_EXTERN_TEMPLATE 1 + +/* + Outline of libstdc++ namespaces. + + namespace std + { + namespace __debug { } + namespace __parallel { } + namespace __profile { } + namespace __cxx1998 { } + + namespace __detail { + namespace __variant { } // C++17 + } + + namespace rel_ops { } + + namespace tr1 + { + namespace placeholders { } + namespace regex_constants { } + namespace __detail { } + } + + namespace tr2 { } + + namespace decimal { } + + namespace chrono { } // C++11 + namespace placeholders { } // C++11 + namespace regex_constants { } // C++11 + namespace this_thread { } // C++11 + inline namespace literals { // C++14 + inline namespace chrono_literals { } // C++14 + inline namespace complex_literals { } // C++14 + inline namespace string_literals { } // C++14 + inline namespace string_view_literals { } // C++17 + } + } + + namespace abi { } + + namespace __gnu_cxx + { + namespace __detail { } + } + + For full details see: + http://gcc.gnu.org/onlinedocs/libstdc++/latest-doxygen/namespaces.html +*/ +namespace std +{ + typedef __SIZE_TYPE__ size_t; + typedef __PTRDIFF_TYPE__ ptrdiff_t; + +#if __cplusplus >= 201103L + typedef decltype(nullptr) nullptr_t; +#endif +} + +# define _GLIBCXX_USE_DUAL_ABI 1 + +#if ! _GLIBCXX_USE_DUAL_ABI +// Ignore any pre-defined value of _GLIBCXX_USE_CXX11_ABI +# undef _GLIBCXX_USE_CXX11_ABI +#endif + +#ifndef _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_USE_CXX11_ABI 1 +#endif + +#if _GLIBCXX_USE_CXX11_ABI +namespace std +{ + inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } +} +namespace __gnu_cxx +{ + inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } +} +# define _GLIBCXX_NAMESPACE_CXX11 __cxx11:: +# define _GLIBCXX_BEGIN_NAMESPACE_CXX11 namespace __cxx11 { +# define _GLIBCXX_END_NAMESPACE_CXX11 } +# define _GLIBCXX_DEFAULT_ABI_TAG _GLIBCXX_ABI_TAG_CXX11 +#else +# define _GLIBCXX_NAMESPACE_CXX11 +# define _GLIBCXX_BEGIN_NAMESPACE_CXX11 +# define _GLIBCXX_END_NAMESPACE_CXX11 +# define _GLIBCXX_DEFAULT_ABI_TAG +#endif + + +// Defined if inline namespaces are used for versioning. +# define _GLIBCXX_INLINE_VERSION 0 + +// Inline namespace for symbol versioning. +#if _GLIBCXX_INLINE_VERSION + +namespace std +{ + inline namespace __7 { } + + namespace rel_ops { inline namespace __7 { } } + + namespace tr1 + { + inline namespace __7 { } + namespace placeholders { inline namespace __7 { } } + namespace regex_constants { inline namespace __7 { } } + namespace __detail { inline namespace __7 { } } + } + + namespace tr2 + { inline namespace __7 { } } + + namespace decimal { inline namespace __7 { } } + +#if __cplusplus >= 201103L + namespace chrono { inline namespace __7 { } } + namespace placeholders { inline namespace __7 { } } + namespace regex_constants { inline namespace __7 { } } + namespace this_thread { inline namespace __7 { } } + +#if __cplusplus >= 201402L + inline namespace literals { + inline namespace chrono_literals { inline namespace __7 { } } + inline namespace complex_literals { inline namespace __7 { } } + inline namespace string_literals { inline namespace __7 { } } +#if __cplusplus > 201402L + inline namespace string_view_literals { inline namespace __7 { } } +#endif // C++17 + } +#endif // C++14 +#endif // C++11 + + namespace __detail { + inline namespace __7 { } +#if __cplusplus > 201402L + namespace __variant { inline namespace __7 { } } +#endif + } +} + +namespace __gnu_cxx +{ + inline namespace __7 { } + namespace __detail { inline namespace __7 { } } +} +# define _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace __7 { +# define _GLIBCXX_END_NAMESPACE_VERSION } +#else +# define _GLIBCXX_BEGIN_NAMESPACE_VERSION +# define _GLIBCXX_END_NAMESPACE_VERSION +#endif + + +// Inline namespaces for special modes: debug, parallel, profile. +#if defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_PARALLEL) \ + || defined(_GLIBCXX_PROFILE) +namespace std +{ + // Non-inline namespace for components replaced by alternates in active mode. + namespace __cxx1998 + { +# if _GLIBCXX_INLINE_VERSION + inline namespace __7 { } +# endif + +# if _GLIBCXX_USE_CXX11_ABI + inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { } +# endif + } + + // Inline namespace for debug mode. +# ifdef _GLIBCXX_DEBUG + inline namespace __debug { } +# endif + + // Inline namespaces for parallel mode. +# ifdef _GLIBCXX_PARALLEL + inline namespace __parallel { } +# endif + + // Inline namespaces for profile mode +# ifdef _GLIBCXX_PROFILE + inline namespace __profile { } +# endif +} + +// Check for invalid usage and unsupported mixed-mode use. +# if defined(_GLIBCXX_DEBUG) && defined(_GLIBCXX_PARALLEL) +# error illegal use of multiple inlined namespaces +# endif +# if defined(_GLIBCXX_PROFILE) && defined(_GLIBCXX_DEBUG) +# error illegal use of multiple inlined namespaces +# endif +# if defined(_GLIBCXX_PROFILE) && defined(_GLIBCXX_PARALLEL) +# error illegal use of multiple inlined namespaces +# endif + +// Check for invalid use due to lack for weak symbols. +# if __NO_INLINE__ && !__GXX_WEAK__ +# warning currently using inlined namespace mode which may fail \ + without inlining due to lack of weak symbols +# endif +#endif + +// Macros for namespace scope. Either namespace std:: or the name +// of some nested namespace within it corresponding to the active mode. +// _GLIBCXX_STD_A +// _GLIBCXX_STD_C +// +// Macros for opening/closing conditional namespaces. +// _GLIBCXX_BEGIN_NAMESPACE_ALGO +// _GLIBCXX_END_NAMESPACE_ALGO +// _GLIBCXX_BEGIN_NAMESPACE_CONTAINER +// _GLIBCXX_END_NAMESPACE_CONTAINER +#if defined(_GLIBCXX_DEBUG) || defined(_GLIBCXX_PROFILE) +# define _GLIBCXX_STD_C __cxx1998 +# define _GLIBCXX_BEGIN_NAMESPACE_CONTAINER \ + namespace _GLIBCXX_STD_C { _GLIBCXX_BEGIN_NAMESPACE_VERSION +# define _GLIBCXX_END_NAMESPACE_CONTAINER \ + _GLIBCXX_END_NAMESPACE_VERSION } +#else +# define _GLIBCXX_STD_C std +# define _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX_BEGIN_NAMESPACE_VERSION +# define _GLIBCXX_END_NAMESPACE_CONTAINER _GLIBCXX_END_NAMESPACE_VERSION +#endif + +#ifdef _GLIBCXX_PARALLEL +# define _GLIBCXX_STD_A __cxx1998 +# define _GLIBCXX_BEGIN_NAMESPACE_ALGO \ + namespace _GLIBCXX_STD_A { _GLIBCXX_BEGIN_NAMESPACE_VERSION +# define _GLIBCXX_END_NAMESPACE_ALGO \ + _GLIBCXX_END_NAMESPACE_VERSION } +#else +# define _GLIBCXX_STD_A std +# define _GLIBCXX_BEGIN_NAMESPACE_ALGO _GLIBCXX_BEGIN_NAMESPACE_VERSION +# define _GLIBCXX_END_NAMESPACE_ALGO _GLIBCXX_END_NAMESPACE_VERSION +#endif + +// GLIBCXX_ABI Deprecated +// Define if compatibility should be provided for -mlong-double-64. +#undef _GLIBCXX_LONG_DOUBLE_COMPAT + +// Inline namespace for long double 128 mode. +#if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined __LONG_DOUBLE_128__ +namespace std +{ + inline namespace __gnu_cxx_ldbl128 { } +} +# define _GLIBCXX_NAMESPACE_LDBL __gnu_cxx_ldbl128:: +# define _GLIBCXX_BEGIN_NAMESPACE_LDBL namespace __gnu_cxx_ldbl128 { +# define _GLIBCXX_END_NAMESPACE_LDBL } +#else +# define _GLIBCXX_NAMESPACE_LDBL +# define _GLIBCXX_BEGIN_NAMESPACE_LDBL +# define _GLIBCXX_END_NAMESPACE_LDBL +#endif +#if _GLIBCXX_USE_CXX11_ABI +# define _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_NAMESPACE_CXX11 +# define _GLIBCXX_BEGIN_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_BEGIN_NAMESPACE_CXX11 +# define _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_END_NAMESPACE_CXX11 +#else +# define _GLIBCXX_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_NAMESPACE_LDBL +# define _GLIBCXX_BEGIN_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_BEGIN_NAMESPACE_LDBL +# define _GLIBCXX_END_NAMESPACE_LDBL_OR_CXX11 _GLIBCXX_END_NAMESPACE_LDBL +#endif + +// Debug Mode implies checking assertions. +#if defined(_GLIBCXX_DEBUG) && !defined(_GLIBCXX_ASSERTIONS) +# define _GLIBCXX_ASSERTIONS 1 +#endif + +// Disable std::string explicit instantiation declarations in order to assert. +#ifdef _GLIBCXX_ASSERTIONS +# undef _GLIBCXX_EXTERN_TEMPLATE +# define _GLIBCXX_EXTERN_TEMPLATE -1 +#endif + +// Assert. +#if defined(_GLIBCXX_ASSERTIONS) \ + || defined(_GLIBCXX_PARALLEL) || defined(_GLIBCXX_PARALLEL_ASSERTIONS) +namespace std +{ + // Avoid the use of assert, because we're trying to keep the + // include out of the mix. + inline void + __replacement_assert(const char* __file, int __line, + const char* __function, const char* __condition) + { + __builtin_printf("%s:%d: %s: Assertion '%s' failed.\n", __file, __line, + __function, __condition); + __builtin_abort(); + } +} +#define __glibcxx_assert_impl(_Condition) \ + do \ + { \ + if (! (_Condition)) \ + std::__replacement_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ + #_Condition); \ + } while (false) +#endif + +#if defined(_GLIBCXX_ASSERTIONS) +# define __glibcxx_assert(_Condition) __glibcxx_assert_impl(_Condition) +#else +# define __glibcxx_assert(_Condition) +#endif + +// Macros for race detectors. +// _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) and +// _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) should be used to explain +// atomic (lock-free) synchronization to race detectors: +// the race detector will infer a happens-before arc from the former to the +// latter when they share the same argument pointer. +// +// The most frequent use case for these macros (and the only case in the +// current implementation of the library) is atomic reference counting: +// void _M_remove_reference() +// { +// _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(&this->_M_refcount); +// if (__gnu_cxx::__exchange_and_add_dispatch(&this->_M_refcount, -1) <= 0) +// { +// _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(&this->_M_refcount); +// _M_destroy(__a); +// } +// } +// The annotations in this example tell the race detector that all memory +// accesses occurred when the refcount was positive do not race with +// memory accesses which occurred after the refcount became zero. +#ifndef _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE +# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_BEFORE(A) +#endif +#ifndef _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER +# define _GLIBCXX_SYNCHRONIZATION_HAPPENS_AFTER(A) +#endif + +// Macros for C linkage: define extern "C" linkage only when using C++. +# define _GLIBCXX_BEGIN_EXTERN_C extern "C" { +# define _GLIBCXX_END_EXTERN_C } + +# define _GLIBCXX_USE_ALLOCATOR_NEW 1 + +#else // !__cplusplus +# define _GLIBCXX_BEGIN_EXTERN_C +# define _GLIBCXX_END_EXTERN_C +#endif + + +// First includes. + +// Pick up any OS-specific definitions. +#include "../bits/os_defines.h" + +// Pick up any CPU-specific definitions. +#include "../bits/cpu_defines.h" + +// If platform uses neither visibility nor psuedo-visibility, +// specify empty default for namespace annotation macros. +#ifndef _GLIBCXX_PSEUDO_VISIBILITY +# define _GLIBCXX_PSEUDO_VISIBILITY(V) +#endif + +// Certain function definitions that are meant to be overridable from +// user code are decorated with this macro. For some targets, this +// macro causes these definitions to be weak. +#ifndef _GLIBCXX_WEAK_DEFINITION +# define _GLIBCXX_WEAK_DEFINITION +#endif + +// By default, we assume that __GXX_WEAK__ also means that there is support +// for declaring functions as weak while not defining such functions. This +// allows for referring to functions provided by other libraries (e.g., +// libitm) without depending on them if the respective features are not used. +#ifndef _GLIBCXX_USE_WEAK_REF +# define _GLIBCXX_USE_WEAK_REF __GXX_WEAK__ +#endif + +// Conditionally enable annotations for the Transactional Memory TS on C++11. +// Most of the following conditions are due to limitations in the current +// implementation. +#if __cplusplus >= 201103L && _GLIBCXX_USE_CXX11_ABI \ + && _GLIBCXX_USE_DUAL_ABI && __cpp_transactional_memory >= 201505L \ + && !_GLIBCXX_FULLY_DYNAMIC_STRING && _GLIBCXX_USE_WEAK_REF \ + && _GLIBCXX_USE_ALLOCATOR_NEW +#define _GLIBCXX_TXN_SAFE transaction_safe +#define _GLIBCXX_TXN_SAFE_DYN transaction_safe_dynamic +#else +#define _GLIBCXX_TXN_SAFE +#define _GLIBCXX_TXN_SAFE_DYN +#endif + +#if __cplusplus > 201402L +// In C++17 mathematical special functions are in namespace std. +// # define _GLIBCXX_USE_STD_SPEC_FUNCS 1 +#elif __cplusplus >= 201103L && __STDCPP_WANT_MATH_SPEC_FUNCS__ != 0 +// For C++11 and C++14 they are in namespace std when requested. +// # define _GLIBCXX_USE_STD_SPEC_FUNCS 1 +#endif + +// The remainder of the prewritten config is automatic; all the +// user hooks are listed above. + +// Create a boolean flag to be used to determine if --fast-math is set. +#ifdef __FAST_MATH__ +# define _GLIBCXX_FAST_MATH 1 +#else +# define _GLIBCXX_FAST_MATH 0 +#endif + +// This marks string literals in header files to be extracted for eventual +// translation. It is primarily used for messages in thrown exceptions; see +// src/functexcept.cc. We use __N because the more traditional _N is used +// for something else under certain OSes (see BADNAMES). +#define __N(msgid) (msgid) + +// For example, is known to #define min and max as macros... +#undef min +#undef max + +// N.B. these _GLIBCXX_USE_C99_XXX macros are defined unconditionally +// so they should be tested with #if not with #ifdef. +#if __cplusplus >= 201103L +# ifndef _GLIBCXX_USE_C99_MATH +# define _GLIBCXX_USE_C99_MATH _GLIBCXX11_USE_C99_MATH +# endif +# ifndef _GLIBCXX_USE_C99_COMPLEX +# define _GLIBCXX_USE_C99_COMPLEX _GLIBCXX11_USE_C99_COMPLEX +# endif +# ifndef _GLIBCXX_USE_C99_STDIO +# define _GLIBCXX_USE_C99_STDIO _GLIBCXX11_USE_C99_STDIO +# endif +# ifndef _GLIBCXX_USE_C99_STDLIB +# define _GLIBCXX_USE_C99_STDLIB _GLIBCXX11_USE_C99_STDLIB +# endif +# ifndef _GLIBCXX_USE_C99_WCHAR +# define _GLIBCXX_USE_C99_WCHAR _GLIBCXX11_USE_C99_WCHAR +# endif +#else +# ifndef _GLIBCXX_USE_C99_MATH +# define _GLIBCXX_USE_C99_MATH _GLIBCXX98_USE_C99_MATH +# endif +# ifndef _GLIBCXX_USE_C99_COMPLEX +# define _GLIBCXX_USE_C99_COMPLEX _GLIBCXX98_USE_C99_COMPLEX +# endif +# ifndef _GLIBCXX_USE_C99_STDIO +# define _GLIBCXX_USE_C99_STDIO _GLIBCXX98_USE_C99_STDIO +# endif +# ifndef _GLIBCXX_USE_C99_STDLIB +# define _GLIBCXX_USE_C99_STDLIB _GLIBCXX98_USE_C99_STDLIB +# endif +# ifndef _GLIBCXX_USE_C99_WCHAR +# define _GLIBCXX_USE_C99_WCHAR _GLIBCXX98_USE_C99_WCHAR +# endif +#endif + +/* Define if __float128 is supported on this host. */ +#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__) +#define _GLIBCXX_USE_FLOAT128 1 +#endif + +// TODO +#define _GLIBCXX_USE_C99_LONG_LONG_DYNAMIC 1 +#define _GLIBCXX_USE_C99_DYNAMIC 1 + +// End of prewritten config; the settings discovered at configure time follow. +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the `acosf' function. */ +#define _GLIBCXX_HAVE_ACOSF 1 + +/* Define to 1 if you have the `acosl' function. */ +#define _GLIBCXX_HAVE_ACOSL 1 + +/* Define to 1 if you have the `aligned_alloc' function. */ +// #define _GLIBCXX_HAVE_ALIGNED_ALLOC 1 + +/* Define to 1 if you have the `asinf' function. */ +#define _GLIBCXX_HAVE_ASINF 1 + +/* Define to 1 if you have the `asinl' function. */ +#define _GLIBCXX_HAVE_ASINL 1 + +/* Define to 1 if the target assembler supports .symver directive. */ +#define _GLIBCXX_HAVE_AS_SYMVER_DIRECTIVE 1 + +/* Define to 1 if you have the `atan2f' function. */ +#define _GLIBCXX_HAVE_ATAN2F 1 + +/* Define to 1 if you have the `atan2l' function. */ +#define _GLIBCXX_HAVE_ATAN2L 1 + +/* Define to 1 if you have the `atanf' function. */ +#define _GLIBCXX_HAVE_ATANF 1 + +/* Define to 1 if you have the `atanl' function. */ +#define _GLIBCXX_HAVE_ATANL 1 + +/* Define to 1 if you have the `at_quick_exit' function. */ +// #define _GLIBCXX_HAVE_AT_QUICK_EXIT 1 + +/* Define to 1 if the target assembler supports thread-local storage. */ +/* #undef _GLIBCXX_HAVE_CC_TLS */ + +/* Define to 1 if you have the `ceilf' function. */ +#define _GLIBCXX_HAVE_CEILF 1 + +/* Define to 1 if you have the `ceill' function. */ +#define _GLIBCXX_HAVE_CEILL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_COMPLEX_H 1 + +/* Define to 1 if you have the `cosf' function. */ +#define _GLIBCXX_HAVE_COSF 1 + +/* Define to 1 if you have the `coshf' function. */ +#define _GLIBCXX_HAVE_COSHF 1 + +/* Define to 1 if you have the `coshl' function. */ +#define _GLIBCXX_HAVE_COSHL 1 + +/* Define to 1 if you have the `cosl' function. */ +#define _GLIBCXX_HAVE_COSL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_DLFCN_H 1 + +/* Define if EBADMSG exists. */ +#define _GLIBCXX_HAVE_EBADMSG 1 + +/* Define if ECANCELED exists. */ +#define _GLIBCXX_HAVE_ECANCELED 1 + +/* Define if ECHILD exists. */ +#define _GLIBCXX_HAVE_ECHILD 1 + +/* Define if EIDRM exists. */ +#define _GLIBCXX_HAVE_EIDRM 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_ENDIAN_H 1 + +/* Define if ENODATA exists. */ +#define _GLIBCXX_HAVE_ENODATA 1 + +/* Define if ENOLINK exists. */ +#define _GLIBCXX_HAVE_ENOLINK 1 + +/* Define if ENOSPC exists. */ +#define _GLIBCXX_HAVE_ENOSPC 1 + +/* Define if ENOSR exists. */ +#define _GLIBCXX_HAVE_ENOSR 1 + +/* Define if ENOSTR exists. */ +#define _GLIBCXX_HAVE_ENOSTR 1 + +/* Define if ENOTRECOVERABLE exists. */ +#define _GLIBCXX_HAVE_ENOTRECOVERABLE 1 + +/* Define if ENOTSUP exists. */ +#define _GLIBCXX_HAVE_ENOTSUP 1 + +/* Define if EOVERFLOW exists. */ +#define _GLIBCXX_HAVE_EOVERFLOW 1 + +/* Define if EOWNERDEAD exists. */ +#define _GLIBCXX_HAVE_EOWNERDEAD 1 + +/* Define if EPERM exists. */ +#define _GLIBCXX_HAVE_EPERM 1 + +/* Define if EPROTO exists. */ +#define _GLIBCXX_HAVE_EPROTO 1 + +/* Define if ETIME exists. */ +#define _GLIBCXX_HAVE_ETIME 1 + +/* Define if ETIMEDOUT exists. */ +#define _GLIBCXX_HAVE_ETIMEDOUT 1 + +/* Define if ETXTBSY exists. */ +#define _GLIBCXX_HAVE_ETXTBSY 1 + +/* Define if EWOULDBLOCK exists. */ +#define _GLIBCXX_HAVE_EWOULDBLOCK 1 + +/* Define to 1 if GCC 4.6 supported std::exception_ptr for the target */ +#define _GLIBCXX_HAVE_EXCEPTION_PTR_SINCE_GCC46 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_EXECINFO_H 1 + +/* Define to 1 if you have the `expf' function. */ +#define _GLIBCXX_HAVE_EXPF 1 + +/* Define to 1 if you have the `expl' function. */ +#define _GLIBCXX_HAVE_EXPL 1 + +/* Define to 1 if you have the `fabsf' function. */ +#define _GLIBCXX_HAVE_FABSF 1 + +/* Define to 1 if you have the `fabsl' function. */ +#define _GLIBCXX_HAVE_FABSL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_FENV_H 1 + +/* Define to 1 if you have the `finite' function. */ +#define _GLIBCXX_HAVE_FINITE 1 + +/* Define to 1 if you have the `finitef' function. */ +#define _GLIBCXX_HAVE_FINITEF 1 + +/* Define to 1 if you have the `finitel' function. */ +#define _GLIBCXX_HAVE_FINITEL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `floorf' function. */ +#define _GLIBCXX_HAVE_FLOORF 1 + +/* Define to 1 if you have the `floorl' function. */ +#define _GLIBCXX_HAVE_FLOORL 1 + +/* Define to 1 if you have the `fmodf' function. */ +#define _GLIBCXX_HAVE_FMODF 1 + +/* Define to 1 if you have the `fmodl' function. */ +#define _GLIBCXX_HAVE_FMODL 1 + +/* Define to 1 if you have the `fpclass' function. */ +/* #undef _GLIBCXX_HAVE_FPCLASS */ + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_FP_H */ + +/* Define to 1 if you have the `frexpf' function. */ +#define _GLIBCXX_HAVE_FREXPF 1 + +/* Define to 1 if you have the `frexpl' function. */ +#define _GLIBCXX_HAVE_FREXPL 1 + +/* Define if _Unwind_GetIPInfo is available. */ +#define _GLIBCXX_HAVE_GETIPINFO 1 + +/* Define if gets is available in before C++14. */ +#define _GLIBCXX_HAVE_GETS 1 + +/* Define to 1 if you have the `hypot' function. */ +#define _GLIBCXX_HAVE_HYPOT 1 + +/* Define to 1 if you have the `hypotf' function. */ +#define _GLIBCXX_HAVE_HYPOTF 1 + +/* Define to 1 if you have the `hypotl' function. */ +#define _GLIBCXX_HAVE_HYPOTL 1 + +/* Define if you have the iconv() function. */ +#define _GLIBCXX_HAVE_ICONV 1 + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_IEEEFP_H */ + +/* Define if int64_t is available in . */ +#define _GLIBCXX_HAVE_INT64_T 1 + +/* Define if int64_t is a long. */ +#define _GLIBCXX_HAVE_INT64_T_LONG 1 + +/* Define if int64_t is a long long. */ +/* #undef _GLIBCXX_HAVE_INT64_T_LONG_LONG */ + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isinf' function. */ +/* #undef _GLIBCXX_HAVE_ISINF */ + +/* Define to 1 if you have the `isinff' function. */ +#define _GLIBCXX_HAVE_ISINFF 1 + +/* Define to 1 if you have the `isinfl' function. */ +#define _GLIBCXX_HAVE_ISINFL 1 + +/* Define to 1 if you have the `isnan' function. */ +/* #undef _GLIBCXX_HAVE_ISNAN */ + +/* Define to 1 if you have the `isnanf' function. */ +#define _GLIBCXX_HAVE_ISNANF 1 + +/* Define to 1 if you have the `isnanl' function. */ +#define _GLIBCXX_HAVE_ISNANL 1 + +/* Defined if iswblank exists. */ +#define _GLIBCXX_HAVE_ISWBLANK 1 + +/* Define if LC_MESSAGES is available in . */ +#define _GLIBCXX_HAVE_LC_MESSAGES 1 + +/* Define to 1 if you have the `ldexpf' function. */ +#define _GLIBCXX_HAVE_LDEXPF 1 + +/* Define to 1 if you have the `ldexpl' function. */ +#define _GLIBCXX_HAVE_LDEXPL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_LIBINTL_H 1 + +/* Only used in build directory testsuite_hooks.h. */ +#define _GLIBCXX_HAVE_LIMIT_AS 1 + +/* Only used in build directory testsuite_hooks.h. */ +#define _GLIBCXX_HAVE_LIMIT_DATA 1 + +/* Only used in build directory testsuite_hooks.h. */ +#define _GLIBCXX_HAVE_LIMIT_FSIZE 1 + +/* Only used in build directory testsuite_hooks.h. */ +#define _GLIBCXX_HAVE_LIMIT_RSS 1 + +/* Only used in build directory testsuite_hooks.h. */ +#define _GLIBCXX_HAVE_LIMIT_VMEM 0 + +/* Define if futex syscall is available. */ +#define _GLIBCXX_HAVE_LINUX_FUTEX 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `log10f' function. */ +#define _GLIBCXX_HAVE_LOG10F 1 + +/* Define to 1 if you have the `log10l' function. */ +#define _GLIBCXX_HAVE_LOG10L 1 + +/* Define to 1 if you have the `logf' function. */ +#define _GLIBCXX_HAVE_LOGF 1 + +/* Define to 1 if you have the `logl' function. */ +#define _GLIBCXX_HAVE_LOGL 1 + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_MACHINE_ENDIAN_H */ + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_MACHINE_PARAM_H */ + +/* Define if mbstate_t exists in wchar.h. */ +// #define _GLIBCXX_HAVE_MBSTATE_T 1 + +/* Define to 1 if you have the `memalign' function. */ +#define _GLIBCXX_HAVE_MEMALIGN 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `modf' function. */ +#define _GLIBCXX_HAVE_MODF 1 + +/* Define to 1 if you have the `modff' function. */ +#define _GLIBCXX_HAVE_MODFF 1 + +/* Define to 1 if you have the `modfl' function. */ +#define _GLIBCXX_HAVE_MODFL 1 + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_NAN_H */ + +/* Define if defines obsolete isinf function. */ +/* #undef _GLIBCXX_HAVE_OBSOLETE_ISINF */ + +/* Define if defines obsolete isnan function. */ +/* #undef _GLIBCXX_HAVE_OBSOLETE_ISNAN */ + +/* Define if poll is available in . */ +#define _GLIBCXX_HAVE_POLL 1 + +/* Define to 1 if you have the `posix_memalign' function. */ +#define _GLIBCXX_HAVE_POSIX_MEMALIGN 1 + +/* Define to 1 if you have the `powf' function. */ +#define _GLIBCXX_HAVE_POWF 1 + +/* Define to 1 if you have the `powl' function. */ +#define _GLIBCXX_HAVE_POWL 1 + +/* Define to 1 if you have the `qfpclass' function. */ +/* #undef _GLIBCXX_HAVE_QFPCLASS */ + +/* Define to 1 if you have the `quick_exit' function. */ +// #define _GLIBCXX_HAVE_QUICK_EXIT 1 + +/* Define to 1 if you have the `setenv' function. */ +// #define _GLIBCXX_HAVE_SETENV 1 + +/* Define to 1 if you have the `sincos' function. */ +#define _GLIBCXX_HAVE_SINCOS 1 + +/* Define to 1 if you have the `sincosf' function. */ +#define _GLIBCXX_HAVE_SINCOSF 1 + +/* Define to 1 if you have the `sincosl' function. */ +#define _GLIBCXX_HAVE_SINCOSL 1 + +/* Define to 1 if you have the `sinf' function. */ +#define _GLIBCXX_HAVE_SINF 1 + +/* Define to 1 if you have the `sinhf' function. */ +#define _GLIBCXX_HAVE_SINHF 1 + +/* Define to 1 if you have the `sinhl' function. */ +#define _GLIBCXX_HAVE_SINHL 1 + +/* Define to 1 if you have the `sinl' function. */ +#define _GLIBCXX_HAVE_SINL 1 + +/* Defined if sleep exists. */ +/* #undef _GLIBCXX_HAVE_SLEEP */ + +/* Define to 1 if you have the `sqrtf' function. */ +#define _GLIBCXX_HAVE_SQRTF 1 + +/* Define to 1 if you have the `sqrtl' function. */ +#define _GLIBCXX_HAVE_SQRTL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STDALIGN_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STDBOOL_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STDLIB_H 1 + +/* Define if strerror_l is available in . */ +#define _GLIBCXX_HAVE_STRERROR_L 1 + +/* Define if strerror_r is available in . */ +#define _GLIBCXX_HAVE_STRERROR_R 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_STRING_H 1 + +/* Define to 1 if you have the `strtof' function. */ +#define _GLIBCXX_HAVE_STRTOF 1 + +/* Define to 1 if you have the `strtold' function. */ +#define _GLIBCXX_HAVE_STRTOLD 1 + +/* Define to 1 if `d_type' is a member of `struct dirent'. */ +#define _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE 1 + +/* Define if strxfrm_l is available in . */ +#define _GLIBCXX_HAVE_STRXFRM_L 1 + +/* Define to 1 if the target runtime linker supports binding the same symbol + to different versions. */ +#define _GLIBCXX_HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT 1 + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_SYS_FILIO_H */ + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_IPC_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_SYS_ISA_DEFS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef _GLIBCXX_HAVE_SYS_MACHINE_H */ + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_RESOURCE_H 1 + +/* Define to 1 if you have a suitable header file */ +#define _GLIBCXX_HAVE_SYS_SDT_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_SEM_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_SYSINFO_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_SYS_UIO_H 1 + +/* Define if S_IFREG is available in . */ +/* #undef _GLIBCXX_HAVE_S_IFREG */ + +/* Define if S_ISREG is available in . */ +#define _GLIBCXX_HAVE_S_ISREG 1 + +/* Define to 1 if you have the `tanf' function. */ +#define _GLIBCXX_HAVE_TANF 1 + +/* Define to 1 if you have the `tanhf' function. */ +#define _GLIBCXX_HAVE_TANHF 1 + +/* Define to 1 if you have the `tanhl' function. */ +#define _GLIBCXX_HAVE_TANHL 1 + +/* Define to 1 if you have the `tanl' function. */ +#define _GLIBCXX_HAVE_TANL 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_TGMATH_H 1 + +/* Define to 1 if the target supports thread-local storage. */ +#define _GLIBCXX_HAVE_TLS 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_UCHAR_H 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_UNISTD_H 1 + +/* Defined if usleep exists. */ +/* #undef _GLIBCXX_HAVE_USLEEP */ + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_UTIME_H 1 + +/* Defined if vfwscanf exists. */ +#define _GLIBCXX_HAVE_VFWSCANF 1 + +/* Defined if vswscanf exists. */ +#define _GLIBCXX_HAVE_VSWSCANF 1 + +/* Defined if vwscanf exists. */ +#define _GLIBCXX_HAVE_VWSCANF 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_WCHAR_H 1 + +/* Defined if wcstof exists. */ +#define _GLIBCXX_HAVE_WCSTOF 1 + +/* Define to 1 if you have the header file. */ +#define _GLIBCXX_HAVE_WCTYPE_H 1 + +/* Defined if Sleep exists. */ +/* #undef _GLIBCXX_HAVE_WIN32_SLEEP */ + +/* Define if writev is available in . */ +#define _GLIBCXX_HAVE_WRITEV 1 + +/* Define to 1 if you have the `_acosf' function. */ +/* #undef _GLIBCXX_HAVE__ACOSF */ + +/* Define to 1 if you have the `_acosl' function. */ +/* #undef _GLIBCXX_HAVE__ACOSL */ + +/* Define to 1 if you have the `_aligned_malloc' function. */ +/* #undef _GLIBCXX_HAVE__ALIGNED_MALLOC */ + +/* Define to 1 if you have the `_asinf' function. */ +/* #undef _GLIBCXX_HAVE__ASINF */ + +/* Define to 1 if you have the `_asinl' function. */ +/* #undef _GLIBCXX_HAVE__ASINL */ + +/* Define to 1 if you have the `_atan2f' function. */ +/* #undef _GLIBCXX_HAVE__ATAN2F */ + +/* Define to 1 if you have the `_atan2l' function. */ +/* #undef _GLIBCXX_HAVE__ATAN2L */ + +/* Define to 1 if you have the `_atanf' function. */ +/* #undef _GLIBCXX_HAVE__ATANF */ + +/* Define to 1 if you have the `_atanl' function. */ +/* #undef _GLIBCXX_HAVE__ATANL */ + +/* Define to 1 if you have the `_ceilf' function. */ +/* #undef _GLIBCXX_HAVE__CEILF */ + +/* Define to 1 if you have the `_ceill' function. */ +/* #undef _GLIBCXX_HAVE__CEILL */ + +/* Define to 1 if you have the `_cosf' function. */ +/* #undef _GLIBCXX_HAVE__COSF */ + +/* Define to 1 if you have the `_coshf' function. */ +/* #undef _GLIBCXX_HAVE__COSHF */ + +/* Define to 1 if you have the `_coshl' function. */ +/* #undef _GLIBCXX_HAVE__COSHL */ + +/* Define to 1 if you have the `_cosl' function. */ +/* #undef _GLIBCXX_HAVE__COSL */ + +/* Define to 1 if you have the `_expf' function. */ +/* #undef _GLIBCXX_HAVE__EXPF */ + +/* Define to 1 if you have the `_expl' function. */ +/* #undef _GLIBCXX_HAVE__EXPL */ + +/* Define to 1 if you have the `_fabsf' function. */ +/* #undef _GLIBCXX_HAVE__FABSF */ + +/* Define to 1 if you have the `_fabsl' function. */ +/* #undef _GLIBCXX_HAVE__FABSL */ + +/* Define to 1 if you have the `_finite' function. */ +/* #undef _GLIBCXX_HAVE__FINITE */ + +/* Define to 1 if you have the `_finitef' function. */ +/* #undef _GLIBCXX_HAVE__FINITEF */ + +/* Define to 1 if you have the `_finitel' function. */ +/* #undef _GLIBCXX_HAVE__FINITEL */ + +/* Define to 1 if you have the `_floorf' function. */ +/* #undef _GLIBCXX_HAVE__FLOORF */ + +/* Define to 1 if you have the `_floorl' function. */ +/* #undef _GLIBCXX_HAVE__FLOORL */ + +/* Define to 1 if you have the `_fmodf' function. */ +/* #undef _GLIBCXX_HAVE__FMODF */ + +/* Define to 1 if you have the `_fmodl' function. */ +/* #undef _GLIBCXX_HAVE__FMODL */ + +/* Define to 1 if you have the `_fpclass' function. */ +/* #undef _GLIBCXX_HAVE__FPCLASS */ + +/* Define to 1 if you have the `_frexpf' function. */ +/* #undef _GLIBCXX_HAVE__FREXPF */ + +/* Define to 1 if you have the `_frexpl' function. */ +/* #undef _GLIBCXX_HAVE__FREXPL */ + +/* Define to 1 if you have the `_hypot' function. */ +/* #undef _GLIBCXX_HAVE__HYPOT */ + +/* Define to 1 if you have the `_hypotf' function. */ +/* #undef _GLIBCXX_HAVE__HYPOTF */ + +/* Define to 1 if you have the `_hypotl' function. */ +/* #undef _GLIBCXX_HAVE__HYPOTL */ + +/* Define to 1 if you have the `_isinf' function. */ +/* #undef _GLIBCXX_HAVE__ISINF */ + +/* Define to 1 if you have the `_isinff' function. */ +/* #undef _GLIBCXX_HAVE__ISINFF */ + +/* Define to 1 if you have the `_isinfl' function. */ +/* #undef _GLIBCXX_HAVE__ISINFL */ + +/* Define to 1 if you have the `_isnan' function. */ +/* #undef _GLIBCXX_HAVE__ISNAN */ + +/* Define to 1 if you have the `_isnanf' function. */ +/* #undef _GLIBCXX_HAVE__ISNANF */ + +/* Define to 1 if you have the `_isnanl' function. */ +/* #undef _GLIBCXX_HAVE__ISNANL */ + +/* Define to 1 if you have the `_ldexpf' function. */ +/* #undef _GLIBCXX_HAVE__LDEXPF */ + +/* Define to 1 if you have the `_ldexpl' function. */ +/* #undef _GLIBCXX_HAVE__LDEXPL */ + +/* Define to 1 if you have the `_log10f' function. */ +/* #undef _GLIBCXX_HAVE__LOG10F */ + +/* Define to 1 if you have the `_log10l' function. */ +/* #undef _GLIBCXX_HAVE__LOG10L */ + +/* Define to 1 if you have the `_logf' function. */ +/* #undef _GLIBCXX_HAVE__LOGF */ + +/* Define to 1 if you have the `_logl' function. */ +/* #undef _GLIBCXX_HAVE__LOGL */ + +/* Define to 1 if you have the `_modf' function. */ +/* #undef _GLIBCXX_HAVE__MODF */ + +/* Define to 1 if you have the `_modff' function. */ +/* #undef _GLIBCXX_HAVE__MODFF */ + +/* Define to 1 if you have the `_modfl' function. */ +/* #undef _GLIBCXX_HAVE__MODFL */ + +/* Define to 1 if you have the `_powf' function. */ +/* #undef _GLIBCXX_HAVE__POWF */ + +/* Define to 1 if you have the `_powl' function. */ +/* #undef _GLIBCXX_HAVE__POWL */ + +/* Define to 1 if you have the `_qfpclass' function. */ +/* #undef _GLIBCXX_HAVE__QFPCLASS */ + +/* Define to 1 if you have the `_sincos' function. */ +/* #undef _GLIBCXX_HAVE__SINCOS */ + +/* Define to 1 if you have the `_sincosf' function. */ +/* #undef _GLIBCXX_HAVE__SINCOSF */ + +/* Define to 1 if you have the `_sincosl' function. */ +/* #undef _GLIBCXX_HAVE__SINCOSL */ + +/* Define to 1 if you have the `_sinf' function. */ +/* #undef _GLIBCXX_HAVE__SINF */ + +/* Define to 1 if you have the `_sinhf' function. */ +/* #undef _GLIBCXX_HAVE__SINHF */ + +/* Define to 1 if you have the `_sinhl' function. */ +/* #undef _GLIBCXX_HAVE__SINHL */ + +/* Define to 1 if you have the `_sinl' function. */ +/* #undef _GLIBCXX_HAVE__SINL */ + +/* Define to 1 if you have the `_sqrtf' function. */ +/* #undef _GLIBCXX_HAVE__SQRTF */ + +/* Define to 1 if you have the `_sqrtl' function. */ +/* #undef _GLIBCXX_HAVE__SQRTL */ + +/* Define to 1 if you have the `_tanf' function. */ +/* #undef _GLIBCXX_HAVE__TANF */ + +/* Define to 1 if you have the `_tanhf' function. */ +/* #undef _GLIBCXX_HAVE__TANHF */ + +/* Define to 1 if you have the `_tanhl' function. */ +/* #undef _GLIBCXX_HAVE__TANHL */ + +/* Define to 1 if you have the `_tanl' function. */ +/* #undef _GLIBCXX_HAVE__TANL */ + +/* Define to 1 if you have the `__cxa_thread_atexit' function. */ +/* #undef _GLIBCXX_HAVE___CXA_THREAD_ATEXIT */ + +/* Define to 1 if you have the `__cxa_thread_atexit_impl' function. */ +#define _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL 1 + +/* Define as const if the declaration of iconv() needs const. */ +#define _GLIBCXX_ICONV_CONST + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +/* #undef _GLIBCXX_PACKAGE */ + +/* Define to the address where bug reports for this package should be sent. */ +#define _GLIBCXX_PACKAGE_BUGREPORT "" + +/* Define to the full name of this package. */ +#define _GLIBCXX_PACKAGE_NAME "package-unused" + +/* Define to the full name and version of this package. */ +#define _GLIBCXX_PACKAGE_STRING "package-unused version-unused" + +/* Define to the one symbol short name of this package. */ +#define _GLIBCXX_PACKAGE_TARNAME "libstdc++" + +/* Define to the home page for this package. */ +#define _GLIBCXX_PACKAGE_URL "" + +/* Define to the version of this package. */ +#define _GLIBCXX_PACKAGE__GLIBCXX_VERSION "version-unused" + +/* The size of `char', as computed by sizeof. */ +/* #undef SIZEOF_CHAR */ + +/* The size of `int', as computed by sizeof. */ +/* #undef SIZEOF_INT */ + +/* The size of `long', as computed by sizeof. */ +/* #undef SIZEOF_LONG */ + +/* The size of `short', as computed by sizeof. */ +/* #undef SIZEOF_SHORT */ + +/* The size of `void *', as computed by sizeof. */ +/* #undef SIZEOF_VOID_P */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +/* #undef _GLIBCXX_VERSION */ + +/* Define if C99 functions in should be used in for + C++11. Using compiler builtins for these functions requires corresponding + C99 library functions to be present. */ +#define _GLIBCXX11_USE_C99_COMPLEX 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++11. */ +#define _GLIBCXX11_USE_C99_MATH 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++11. */ +#define _GLIBCXX11_USE_C99_STDIO 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++11. */ +#define _GLIBCXX11_USE_C99_STDLIB 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++11. */ +#define _GLIBCXX11_USE_C99_WCHAR 1 + +/* Define if C99 functions in should be used in for + C++98. Using compiler builtins for these functions requires corresponding + C99 library functions to be present. */ +#define _GLIBCXX98_USE_C99_COMPLEX 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++98. */ +#define _GLIBCXX98_USE_C99_MATH 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++98. */ +#define _GLIBCXX98_USE_C99_STDIO 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++98. */ +#define _GLIBCXX98_USE_C99_STDLIB 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std for C++98. */ +#define _GLIBCXX98_USE_C99_WCHAR 1 + +/* Define if the compiler supports C++11 atomics. */ +#define _GLIBCXX_ATOMIC_BUILTINS 1 + +/* Define to use concept checking code from the boost libraries. */ +/* #undef _GLIBCXX_CONCEPT_CHECKS */ + +/* Define to 1 if a fully dynamic basic_string is wanted, 0 to disable, + undefined for platform defaults */ +#define _GLIBCXX_FULLY_DYNAMIC_STRING 0 + +/* Define if gthreads library is available. */ +#define _GLIBCXX_HAS_GTHREADS 1 + +/* Define to 1 if a full hosted library is built, or 0 if freestanding. */ +#define _GLIBCXX_HOSTED 1 + +/* Define if compatibility should be provided for -mlong-double-64. */ + +/* Define to the letter to which size_t is mangled. */ +#define _GLIBCXX_MANGLE_SIZE_T m + +/* Define if C99 llrint and llround functions are missing from . */ +/* #undef _GLIBCXX_NO_C99_ROUNDING_FUNCS */ + +/* Define if ptrdiff_t is int. */ +/* #undef _GLIBCXX_PTRDIFF_T_IS_INT */ + +/* Define if using setrlimit to set resource limits during "make check" */ +#define _GLIBCXX_RES_LIMITS 1 + +/* Define if size_t is unsigned int. */ +/* #undef _GLIBCXX_SIZE_T_IS_UINT */ + +/* Define to the value of the EOF integer constant. */ +#define _GLIBCXX_STDIO_EOF -1 + +/* Define to the value of the SEEK_CUR integer constant. */ +#define _GLIBCXX_STDIO_SEEK_CUR 1 + +/* Define to the value of the SEEK_END integer constant. */ +#define _GLIBCXX_STDIO_SEEK_END 2 + +/* Define to use symbol versioning in the shared library. */ +#define _GLIBCXX_SYMVER 1 + +/* Define to use darwin versioning in the shared library. */ +/* #undef _GLIBCXX_SYMVER_DARWIN */ + +/* Define to use GNU versioning in the shared library. */ +#define _GLIBCXX_SYMVER_GNU 1 + +/* Define to use GNU namespace versioning in the shared library. */ +/* #undef _GLIBCXX_SYMVER_GNU_NAMESPACE */ + +/* Define to use Sun versioning in the shared library. */ +/* #undef _GLIBCXX_SYMVER_SUN */ + +/* Define if C11 functions in should be imported into namespace std + in . */ +#define _GLIBCXX_USE_C11_UCHAR_CXX11 1 + +/* Define if C99 functions or macros from , , , + , and can be used or exposed. */ +#define _GLIBCXX_USE_C99 1 + +/* Define if C99 functions in should be used in . + Using compiler builtins for these functions requires corresponding C99 + library functions to be present. */ +#define _GLIBCXX_USE_C99_COMPLEX_TR1 1 + +/* Define if C99 functions in should be imported in in + namespace std::tr1. */ +#define _GLIBCXX_USE_C99_CTYPE_TR1 1 + +/* Define if C99 functions in should be imported in in + namespace std::tr1. */ +#define _GLIBCXX_USE_C99_FENV_TR1 1 + +/* Define if C99 functions in should be imported in + in namespace std::tr1. */ +#define _GLIBCXX_USE_C99_INTTYPES_TR1 1 + +/* Define if wchar_t C99 functions in should be imported in + in namespace std::tr1. */ +#define _GLIBCXX_USE_C99_INTTYPES_WCHAR_T_TR1 1 + +/* Define if C99 functions or macros in should be imported in + in namespace std::tr1. */ +#define _GLIBCXX_USE_C99_MATH_TR1 1 + +/* Define if C99 types in should be imported in in + namespace std::tr1. */ +#define _GLIBCXX_USE_C99_STDINT_TR1 1 + +/* Defined if clock_gettime syscall has monotonic and realtime clock support. + */ +/* #undef _GLIBCXX_USE_CLOCK_GETTIME_SYSCALL */ + +/* Defined if clock_gettime has monotonic clock support. */ +#define _GLIBCXX_USE_CLOCK_MONOTONIC 1 + +/* Defined if clock_gettime has realtime clock support. */ +#define _GLIBCXX_USE_CLOCK_REALTIME 1 + +/* Define if ISO/IEC TR 24733 decimal floating point types are supported on + this host. */ +#define _GLIBCXX_USE_DECIMAL_FLOAT 1 + +/* Define if fchmod is available in . */ +#define _GLIBCXX_USE_FCHMOD 1 + +/* Define if fchmodat is available in . */ +#define _GLIBCXX_USE_FCHMODAT 1 + +/* Defined if gettimeofday is available. */ +#define _GLIBCXX_USE_GETTIMEOFDAY 1 + +/* Define if get_nprocs is available in . */ +#define _GLIBCXX_USE_GET_NPROCS 1 + +/* Define if __int128 is supported on this host. */ +#define _GLIBCXX_USE_INT128 1 + +/* Define if LFS support is available. */ +#define _GLIBCXX_USE_LFS 1 + +/* Define if code specialized for long long should be used. */ +#define _GLIBCXX_USE_LONG_LONG 1 + +/* Defined if nanosleep is available. */ +#define _GLIBCXX_USE_NANOSLEEP 1 + +/* Define if NLS translations are to be used. */ +#define _GLIBCXX_USE_NLS 1 + +/* Define if pthreads_num_processors_np is available in . */ +/* #undef _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP */ + +/* Define if POSIX read/write locks are available in . */ +#define _GLIBCXX_USE_PTHREAD_RWLOCK_T 1 + +/* Define if /dev/random and /dev/urandom are available for the random_device + of TR1 (Chapter 5.1). */ +#define _GLIBCXX_USE_RANDOM_TR1 1 + +/* Define if usable realpath is available in . */ +#define _GLIBCXX_USE_REALPATH 1 + +/* Defined if sched_yield is available. */ +#define _GLIBCXX_USE_SCHED_YIELD 1 + +/* Define if _SC_NPROCESSORS_ONLN is available in . */ +#define _GLIBCXX_USE_SC_NPROCESSORS_ONLN 1 + +/* Define if _SC_NPROC_ONLN is available in . */ +/* #undef _GLIBCXX_USE_SC_NPROC_ONLN */ + +/* Define if sendfile is available in . */ +#define _GLIBCXX_USE_SENDFILE 1 + +/* Define if struct stat has timespec members. */ +#define _GLIBCXX_USE_ST_MTIM 1 + +/* Define if sysctl(), CTL_HW and HW_NCPU are available in . */ +/* #undef _GLIBCXX_USE_SYSCTL_HW_NCPU */ + +/* Define if obsolescent tmpnam is available in . */ +#define _GLIBCXX_USE_TMPNAM 1 + +/* Define if utimensat and UTIME_OMIT are available in and + AT_FDCWD in . */ +#define _GLIBCXX_USE_UTIMENSAT 1 + +/* Define if code specialized for wchar_t should be used. */ +// #define _GLIBCXX_USE_WCHAR_T 1 + +/* Define to 1 if a verbose library is built, or 0 otherwise. */ +#define _GLIBCXX_VERBOSE 1 + +/* Defined if as can handle rdrand. */ +#define _GLIBCXX_X86_RDRAND 1 + +/* Define to 1 if mutex_timedlock is available. */ +#define _GTHREAD_USE_MUTEX_TIMEDLOCK 1 + +/* Define if all C++11 floating point overloads are available in . */ +#if __cplusplus >= 201103L +/* #undef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP */ +#endif + +/* Define if all C++11 integral type overloads are available in . */ +#if __cplusplus >= 201103L +/* #undef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT */ +#endif + +#if defined (_GLIBCXX_HAVE__ACOSF) && ! defined (_GLIBCXX_HAVE_ACOSF) +# define _GLIBCXX_HAVE_ACOSF 1 +# define acosf _acosf +#endif + +#if defined (_GLIBCXX_HAVE__ACOSL) && ! defined (_GLIBCXX_HAVE_ACOSL) +# define _GLIBCXX_HAVE_ACOSL 1 +# define acosl _acosl +#endif + +#if defined (_GLIBCXX_HAVE__ASINF) && ! defined (_GLIBCXX_HAVE_ASINF) +# define _GLIBCXX_HAVE_ASINF 1 +# define asinf _asinf +#endif + +#if defined (_GLIBCXX_HAVE__ASINL) && ! defined (_GLIBCXX_HAVE_ASINL) +# define _GLIBCXX_HAVE_ASINL 1 +# define asinl _asinl +#endif + +#if defined (_GLIBCXX_HAVE__ATAN2F) && ! defined (_GLIBCXX_HAVE_ATAN2F) +# define _GLIBCXX_HAVE_ATAN2F 1 +# define atan2f _atan2f +#endif + +#if defined (_GLIBCXX_HAVE__ATAN2L) && ! defined (_GLIBCXX_HAVE_ATAN2L) +# define _GLIBCXX_HAVE_ATAN2L 1 +# define atan2l _atan2l +#endif + +#if defined (_GLIBCXX_HAVE__ATANF) && ! defined (_GLIBCXX_HAVE_ATANF) +# define _GLIBCXX_HAVE_ATANF 1 +# define atanf _atanf +#endif + +#if defined (_GLIBCXX_HAVE__ATANL) && ! defined (_GLIBCXX_HAVE_ATANL) +# define _GLIBCXX_HAVE_ATANL 1 +# define atanl _atanl +#endif + +#if defined (_GLIBCXX_HAVE__CEILF) && ! defined (_GLIBCXX_HAVE_CEILF) +# define _GLIBCXX_HAVE_CEILF 1 +# define ceilf _ceilf +#endif + +#if defined (_GLIBCXX_HAVE__CEILL) && ! defined (_GLIBCXX_HAVE_CEILL) +# define _GLIBCXX_HAVE_CEILL 1 +# define ceill _ceill +#endif + +#if defined (_GLIBCXX_HAVE__COSF) && ! defined (_GLIBCXX_HAVE_COSF) +# define _GLIBCXX_HAVE_COSF 1 +# define cosf _cosf +#endif + +#if defined (_GLIBCXX_HAVE__COSHF) && ! defined (_GLIBCXX_HAVE_COSHF) +# define _GLIBCXX_HAVE_COSHF 1 +# define coshf _coshf +#endif + +#if defined (_GLIBCXX_HAVE__COSHL) && ! defined (_GLIBCXX_HAVE_COSHL) +# define _GLIBCXX_HAVE_COSHL 1 +# define coshl _coshl +#endif + +#if defined (_GLIBCXX_HAVE__COSL) && ! defined (_GLIBCXX_HAVE_COSL) +# define _GLIBCXX_HAVE_COSL 1 +# define cosl _cosl +#endif + +#if defined (_GLIBCXX_HAVE__EXPF) && ! defined (_GLIBCXX_HAVE_EXPF) +# define _GLIBCXX_HAVE_EXPF 1 +# define expf _expf +#endif + +#if defined (_GLIBCXX_HAVE__EXPL) && ! defined (_GLIBCXX_HAVE_EXPL) +# define _GLIBCXX_HAVE_EXPL 1 +# define expl _expl +#endif + +#if defined (_GLIBCXX_HAVE__FABSF) && ! defined (_GLIBCXX_HAVE_FABSF) +# define _GLIBCXX_HAVE_FABSF 1 +# define fabsf _fabsf +#endif + +#if defined (_GLIBCXX_HAVE__FABSL) && ! defined (_GLIBCXX_HAVE_FABSL) +# define _GLIBCXX_HAVE_FABSL 1 +# define fabsl _fabsl +#endif + +#if defined (_GLIBCXX_HAVE__FINITE) && ! defined (_GLIBCXX_HAVE_FINITE) +# define _GLIBCXX_HAVE_FINITE 1 +# define finite _finite +#endif + +#if defined (_GLIBCXX_HAVE__FINITEF) && ! defined (_GLIBCXX_HAVE_FINITEF) +# define _GLIBCXX_HAVE_FINITEF 1 +# define finitef _finitef +#endif + +#if defined (_GLIBCXX_HAVE__FINITEL) && ! defined (_GLIBCXX_HAVE_FINITEL) +# define _GLIBCXX_HAVE_FINITEL 1 +# define finitel _finitel +#endif + +#if defined (_GLIBCXX_HAVE__FLOORF) && ! defined (_GLIBCXX_HAVE_FLOORF) +# define _GLIBCXX_HAVE_FLOORF 1 +# define floorf _floorf +#endif + +#if defined (_GLIBCXX_HAVE__FLOORL) && ! defined (_GLIBCXX_HAVE_FLOORL) +# define _GLIBCXX_HAVE_FLOORL 1 +# define floorl _floorl +#endif + +#if defined (_GLIBCXX_HAVE__FMODF) && ! defined (_GLIBCXX_HAVE_FMODF) +# define _GLIBCXX_HAVE_FMODF 1 +# define fmodf _fmodf +#endif + +#if defined (_GLIBCXX_HAVE__FMODL) && ! defined (_GLIBCXX_HAVE_FMODL) +# define _GLIBCXX_HAVE_FMODL 1 +# define fmodl _fmodl +#endif + +#if defined (_GLIBCXX_HAVE__FPCLASS) && ! defined (_GLIBCXX_HAVE_FPCLASS) +# define _GLIBCXX_HAVE_FPCLASS 1 +# define fpclass _fpclass +#endif + +#if defined (_GLIBCXX_HAVE__FREXPF) && ! defined (_GLIBCXX_HAVE_FREXPF) +# define _GLIBCXX_HAVE_FREXPF 1 +# define frexpf _frexpf +#endif + +#if defined (_GLIBCXX_HAVE__FREXPL) && ! defined (_GLIBCXX_HAVE_FREXPL) +# define _GLIBCXX_HAVE_FREXPL 1 +# define frexpl _frexpl +#endif + +#if defined (_GLIBCXX_HAVE__HYPOT) && ! defined (_GLIBCXX_HAVE_HYPOT) +# define _GLIBCXX_HAVE_HYPOT 1 +# define hypot _hypot +#endif + +#if defined (_GLIBCXX_HAVE__HYPOTF) && ! defined (_GLIBCXX_HAVE_HYPOTF) +# define _GLIBCXX_HAVE_HYPOTF 1 +# define hypotf _hypotf +#endif + +#if defined (_GLIBCXX_HAVE__HYPOTL) && ! defined (_GLIBCXX_HAVE_HYPOTL) +# define _GLIBCXX_HAVE_HYPOTL 1 +# define hypotl _hypotl +#endif + +#if defined (_GLIBCXX_HAVE__ISINF) && ! defined (_GLIBCXX_HAVE_ISINF) +# define _GLIBCXX_HAVE_ISINF 1 +# define isinf _isinf +#endif + +#if defined (_GLIBCXX_HAVE__ISINFF) && ! defined (_GLIBCXX_HAVE_ISINFF) +# define _GLIBCXX_HAVE_ISINFF 1 +# define isinff _isinff +#endif + +#if defined (_GLIBCXX_HAVE__ISINFL) && ! defined (_GLIBCXX_HAVE_ISINFL) +# define _GLIBCXX_HAVE_ISINFL 1 +# define isinfl _isinfl +#endif + +#if defined (_GLIBCXX_HAVE__ISNAN) && ! defined (_GLIBCXX_HAVE_ISNAN) +# define _GLIBCXX_HAVE_ISNAN 1 +# define isnan _isnan +#endif + +#if defined (_GLIBCXX_HAVE__ISNANF) && ! defined (_GLIBCXX_HAVE_ISNANF) +# define _GLIBCXX_HAVE_ISNANF 1 +# define isnanf _isnanf +#endif + +#if defined (_GLIBCXX_HAVE__ISNANL) && ! defined (_GLIBCXX_HAVE_ISNANL) +# define _GLIBCXX_HAVE_ISNANL 1 +# define isnanl _isnanl +#endif + +#if defined (_GLIBCXX_HAVE__LDEXPF) && ! defined (_GLIBCXX_HAVE_LDEXPF) +# define _GLIBCXX_HAVE_LDEXPF 1 +# define ldexpf _ldexpf +#endif + +#if defined (_GLIBCXX_HAVE__LDEXPL) && ! defined (_GLIBCXX_HAVE_LDEXPL) +# define _GLIBCXX_HAVE_LDEXPL 1 +# define ldexpl _ldexpl +#endif + +#if defined (_GLIBCXX_HAVE__LOG10F) && ! defined (_GLIBCXX_HAVE_LOG10F) +# define _GLIBCXX_HAVE_LOG10F 1 +# define log10f _log10f +#endif + +#if defined (_GLIBCXX_HAVE__LOG10L) && ! defined (_GLIBCXX_HAVE_LOG10L) +# define _GLIBCXX_HAVE_LOG10L 1 +# define log10l _log10l +#endif + +#if defined (_GLIBCXX_HAVE__LOGF) && ! defined (_GLIBCXX_HAVE_LOGF) +# define _GLIBCXX_HAVE_LOGF 1 +# define logf _logf +#endif + +#if defined (_GLIBCXX_HAVE__LOGL) && ! defined (_GLIBCXX_HAVE_LOGL) +# define _GLIBCXX_HAVE_LOGL 1 +# define logl _logl +#endif + +#if defined (_GLIBCXX_HAVE__MODF) && ! defined (_GLIBCXX_HAVE_MODF) +# define _GLIBCXX_HAVE_MODF 1 +# define modf _modf +#endif + +#if defined (_GLIBCXX_HAVE__MODFF) && ! defined (_GLIBCXX_HAVE_MODFF) +# define _GLIBCXX_HAVE_MODFF 1 +# define modff _modff +#endif + +#if defined (_GLIBCXX_HAVE__MODFL) && ! defined (_GLIBCXX_HAVE_MODFL) +# define _GLIBCXX_HAVE_MODFL 1 +# define modfl _modfl +#endif + +#if defined (_GLIBCXX_HAVE__POWF) && ! defined (_GLIBCXX_HAVE_POWF) +# define _GLIBCXX_HAVE_POWF 1 +# define powf _powf +#endif + +#if defined (_GLIBCXX_HAVE__POWL) && ! defined (_GLIBCXX_HAVE_POWL) +# define _GLIBCXX_HAVE_POWL 1 +# define powl _powl +#endif + +#if defined (_GLIBCXX_HAVE__QFPCLASS) && ! defined (_GLIBCXX_HAVE_QFPCLASS) +# define _GLIBCXX_HAVE_QFPCLASS 1 +# define qfpclass _qfpclass +#endif + +#if defined (_GLIBCXX_HAVE__SINCOS) && ! defined (_GLIBCXX_HAVE_SINCOS) +# define _GLIBCXX_HAVE_SINCOS 1 +# define sincos _sincos +#endif + +#if defined (_GLIBCXX_HAVE__SINCOSF) && ! defined (_GLIBCXX_HAVE_SINCOSF) +# define _GLIBCXX_HAVE_SINCOSF 1 +# define sincosf _sincosf +#endif + +#if defined (_GLIBCXX_HAVE__SINCOSL) && ! defined (_GLIBCXX_HAVE_SINCOSL) +# define _GLIBCXX_HAVE_SINCOSL 1 +# define sincosl _sincosl +#endif + +#if defined (_GLIBCXX_HAVE__SINF) && ! defined (_GLIBCXX_HAVE_SINF) +# define _GLIBCXX_HAVE_SINF 1 +# define sinf _sinf +#endif + +#if defined (_GLIBCXX_HAVE__SINHF) && ! defined (_GLIBCXX_HAVE_SINHF) +# define _GLIBCXX_HAVE_SINHF 1 +# define sinhf _sinhf +#endif + +#if defined (_GLIBCXX_HAVE__SINHL) && ! defined (_GLIBCXX_HAVE_SINHL) +# define _GLIBCXX_HAVE_SINHL 1 +# define sinhl _sinhl +#endif + +#if defined (_GLIBCXX_HAVE__SINL) && ! defined (_GLIBCXX_HAVE_SINL) +# define _GLIBCXX_HAVE_SINL 1 +# define sinl _sinl +#endif + +#if defined (_GLIBCXX_HAVE__SQRTF) && ! defined (_GLIBCXX_HAVE_SQRTF) +# define _GLIBCXX_HAVE_SQRTF 1 +# define sqrtf _sqrtf +#endif + +#if defined (_GLIBCXX_HAVE__SQRTL) && ! defined (_GLIBCXX_HAVE_SQRTL) +# define _GLIBCXX_HAVE_SQRTL 1 +# define sqrtl _sqrtl +#endif + +#if defined (_GLIBCXX_HAVE__STRTOF) && ! defined (_GLIBCXX_HAVE_STRTOF) +# define _GLIBCXX_HAVE_STRTOF 1 +# define strtof _strtof +#endif + +#if defined (_GLIBCXX_HAVE__STRTOLD) && ! defined (_GLIBCXX_HAVE_STRTOLD) +# define _GLIBCXX_HAVE_STRTOLD 1 +# define strtold _strtold +#endif + +#if defined (_GLIBCXX_HAVE__TANF) && ! defined (_GLIBCXX_HAVE_TANF) +# define _GLIBCXX_HAVE_TANF 1 +# define tanf _tanf +#endif + +#if defined (_GLIBCXX_HAVE__TANHF) && ! defined (_GLIBCXX_HAVE_TANHF) +# define _GLIBCXX_HAVE_TANHF 1 +# define tanhf _tanhf +#endif + +#if defined (_GLIBCXX_HAVE__TANHL) && ! defined (_GLIBCXX_HAVE_TANHL) +# define _GLIBCXX_HAVE_TANHL 1 +# define tanhl _tanhl +#endif + +#if defined (_GLIBCXX_HAVE__TANL) && ! defined (_GLIBCXX_HAVE_TANL) +# define _GLIBCXX_HAVE_TANL 1 +# define tanl _tanl +#endif + +#endif // _GLIBCXX_CXX_CONFIG_H diff --git a/AH/STL/Fallback/bits/concept_check.h b/AH/STL/Fallback/bits/concept_check.h new file mode 100644 index 0000000..421bf97 --- /dev/null +++ b/AH/STL/Fallback/bits/concept_check.h @@ -0,0 +1,81 @@ +// Concept-checking control -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/concept_check.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + */ + +#ifndef _CONCEPT_CHECK_H +#define _CONCEPT_CHECK_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" + +// All places in libstdc++-v3 where these are used, or /might/ be used, or +// don't need to be used, or perhaps /should/ be used, are commented with +// "concept requirements" (and maybe some more text). So grep like crazy +// if you're looking for additional places to use these. + +// Concept-checking code is off by default unless users turn it on via +// configure options or editing c++config.h. +// It is not supported for freestanding implementations. + +#if !defined(_GLIBCXX_CONCEPT_CHECKS) || !_GLIBCXX_HOSTED + +#define __glibcxx_function_requires(...) +#define __glibcxx_class_requires(_a,_b) +#define __glibcxx_class_requires2(_a,_b,_c) +#define __glibcxx_class_requires3(_a,_b,_c,_d) +#define __glibcxx_class_requires4(_a,_b,_c,_d,_e) + +#else // the checks are on + +#include "../bits/boost_concept_check.h" + +// Note that the obvious and elegant approach of +// +//#define glibcxx_function_requires(C) debug::function_requires< debug::C >() +// +// won't work due to concept templates with more than one parameter, e.g., +// BinaryPredicateConcept. The preprocessor tries to split things up on +// the commas in the template argument list. We can't use an inner pair of +// parenthesis to hide the commas, because "debug::(Temp)" isn't +// a valid instantiation pattern. Thus, we steal a feature from C99. + +#define __glibcxx_function_requires(...) \ + __gnu_cxx::__function_requires< __gnu_cxx::__VA_ARGS__ >(); +#define __glibcxx_class_requires(_a,_C) \ + _GLIBCXX_CLASS_REQUIRES(_a, __gnu_cxx, _C); +#define __glibcxx_class_requires2(_a,_b,_C) \ + _GLIBCXX_CLASS_REQUIRES2(_a, _b, __gnu_cxx, _C); +#define __glibcxx_class_requires3(_a,_b,_c,_C) \ + _GLIBCXX_CLASS_REQUIRES3(_a, _b, _c, __gnu_cxx, _C); +#define __glibcxx_class_requires4(_a,_b,_c,_d,_C) \ + _GLIBCXX_CLASS_REQUIRES4(_a, _b, _c, _d, __gnu_cxx, _C); + +#endif // enable/disable + +#endif // _GLIBCXX_CONCEPT_CHECK diff --git a/AH/STL/Fallback/bits/cpp_type_traits.h b/AH/STL/Fallback/bits/cpp_type_traits.h new file mode 100644 index 0000000..bbeef43 --- /dev/null +++ b/AH/STL/Fallback/bits/cpp_type_traits.h @@ -0,0 +1,415 @@ +// The -*- C++ -*- type traits classes for internal use in libstdc++ + +// Copyright (C) 2000-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/cpp_type_traits.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{ext/type_traits} + */ + +// Written by Gabriel Dos Reis + +#ifndef _CPP_TYPE_TRAITS_H +#define _CPP_TYPE_TRAITS_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" + +// +// This file provides some compile-time information about various types. +// These representations were designed, on purpose, to be constant-expressions +// and not types as found in . In particular, they +// can be used in control structures and the optimizer hopefully will do +// the obvious thing. +// +// Why integral expressions, and not functions nor types? +// Firstly, these compile-time entities are used as template-arguments +// so function return values won't work: We need compile-time entities. +// We're left with types and constant integral expressions. +// Secondly, from the point of view of ease of use, type-based compile-time +// information is -not- *that* convenient. On has to write lots of +// overloaded functions and to hope that the compiler will select the right +// one. As a net effect, the overall structure isn't very clear at first +// glance. +// Thirdly, partial ordering and overload resolution (of function templates) +// is highly costly in terms of compiler-resource. It is a Good Thing to +// keep these resource consumption as least as possible. +// +// See valarray_array.h for a case use. +// +// -- Gaby (dosreis@cmla.ens-cachan.fr) 2000-03-06. +// +// Update 2005: types are also provided and has been +// removed. +// + +extern "C++" { + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct __true_type { }; + struct __false_type { }; + + template + struct __truth_type + { typedef __false_type __type; }; + + template<> + struct __truth_type + { typedef __true_type __type; }; + + // N.B. The conversions to bool are needed due to the issue + // explained in c++/19404. + template + struct __traitor + { + enum { __value = bool(_Sp::__value) || bool(_Tp::__value) }; + typedef typename __truth_type<__value>::__type __type; + }; + + // Compare for equality of types. + template + struct __are_same + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + template + struct __are_same<_Tp, _Tp> + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + // Holds if the template-argument is a void type. + template + struct __is_void + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + template<> + struct __is_void + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + // + // Integer types + // + template + struct __is_integer + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + // Thirteen specializations (yes there are eleven standard integer + // types; long long and unsigned long long are + // supported as extensions). Up to four target-specific __int + // types are supported as well. + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + +# ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; +# endif + +#if __cplusplus >= 201103L + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; +#endif + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_integer + { + enum { __value = 1 }; + typedef __true_type __type; + }; + +#define __INT_N(TYPE) \ + template<> \ + struct __is_integer \ + { \ + enum { __value = 1 }; \ + typedef __true_type __type; \ + }; \ + template<> \ + struct __is_integer \ + { \ + enum { __value = 1 }; \ + typedef __true_type __type; \ + }; + +#ifdef __GLIBCXX_TYPE_INT_N_0 +__INT_N(__GLIBCXX_TYPE_INT_N_0) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_1 +__INT_N(__GLIBCXX_TYPE_INT_N_1) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_2 +__INT_N(__GLIBCXX_TYPE_INT_N_2) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_3 +__INT_N(__GLIBCXX_TYPE_INT_N_3) +#endif + +#undef __INT_N + + // + // Floating point types + // + template + struct __is_floating + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + // three specializations (float, double and 'long double') + template<> + struct __is_floating + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_floating + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_floating + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + // + // Pointer types + // + template + struct __is_pointer + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + template + struct __is_pointer<_Tp*> + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + // + // An arithmetic type is an integer type or a floating point type + // + template + struct __is_arithmetic + : public __traitor<__is_integer<_Tp>, __is_floating<_Tp> > + { }; + + // + // A scalar type is an arithmetic type or a pointer type + // + template + struct __is_scalar + : public __traitor<__is_arithmetic<_Tp>, __is_pointer<_Tp> > + { }; + + // + // For use in std::copy and std::find overloads for streambuf iterators. + // + template + struct __is_char + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + template<> + struct __is_char + { + enum { __value = 1 }; + typedef __true_type __type; + }; + +#ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct __is_char + { + enum { __value = 1 }; + typedef __true_type __type; + }; +#endif + + template + struct __is_byte + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + template<> + struct __is_byte + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_byte + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template<> + struct __is_byte + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + // + // Move iterator type + // + template + struct __is_move_iterator + { + enum { __value = 0 }; + typedef __false_type __type; + }; + + // Fallback implementation of the function in bits/stl_iterator.h used to + // remove the move_iterator wrapper. + template + inline _Iterator + __miter_base(_Iterator __it) + { return __it; } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace +} // extern "C++" + +#endif //_CPP_TYPE_TRAITS_H diff --git a/AH/STL/Fallback/bits/cpu_defines.h b/AH/STL/Fallback/bits/cpu_defines.h new file mode 100644 index 0000000..a177f84 --- /dev/null +++ b/AH/STL/Fallback/bits/cpu_defines.h @@ -0,0 +1,33 @@ +// Specific definitions for generic platforms -*- C++ -*- + +// Copyright (C) 2005-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/cpu_defines.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iosfwd} + */ + +#ifndef _GLIBCXX_CPU_DEFINES +#define _GLIBCXX_CPU_DEFINES 1 + +#endif diff --git a/AH/STL/Fallback/bits/enable_special_members.h b/AH/STL/Fallback/bits/enable_special_members.h new file mode 100644 index 0000000..2c35eb5 --- /dev/null +++ b/AH/STL/Fallback/bits/enable_special_members.h @@ -0,0 +1,312 @@ +// -*- C++ -*- + +// Copyright (C) 2013-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/enable_special_members.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. + */ + +#ifndef _ENABLE_SPECIAL_MEMBERS_H +#define _ENABLE_SPECIAL_MEMBERS_H 1 + +#pragma GCC system_header + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct _Enable_default_constructor_tag + { + explicit constexpr _Enable_default_constructor_tag() = default; + }; + +/** + * @brief A mixin helper to conditionally enable or disable the default + * constructor. + * @sa _Enable_special_members + */ +template + struct _Enable_default_constructor + { + constexpr _Enable_default_constructor() noexcept = default; + constexpr _Enable_default_constructor(_Enable_default_constructor const&) + noexcept = default; + constexpr _Enable_default_constructor(_Enable_default_constructor&&) + noexcept = default; + _Enable_default_constructor& + operator=(_Enable_default_constructor const&) noexcept = default; + _Enable_default_constructor& + operator=(_Enable_default_constructor&&) noexcept = default; + + // Can be used in other ctors. + constexpr explicit + _Enable_default_constructor(_Enable_default_constructor_tag) { } + }; + + +/** + * @brief A mixin helper to conditionally enable or disable the default + * destructor. + * @sa _Enable_special_members + */ +template + struct _Enable_destructor { }; + +/** + * @brief A mixin helper to conditionally enable or disable the copy/move + * special members. + * @sa _Enable_special_members + */ +template + struct _Enable_copy_move { }; + +/** + * @brief A mixin helper to conditionally enable or disable the special + * members. + * + * The @c _Tag type parameter is to make mixin bases unique and thus avoid + * ambiguities. + */ +template + struct _Enable_special_members + : private _Enable_default_constructor<_Default, _Tag>, + private _Enable_destructor<_Destructor, _Tag>, + private _Enable_copy_move<_Copy, _CopyAssignment, + _Move, _MoveAssignment, + _Tag> + { }; + +// Boilerplate follows. + +template + struct _Enable_default_constructor + { + constexpr _Enable_default_constructor() noexcept = delete; + constexpr _Enable_default_constructor(_Enable_default_constructor const&) + noexcept = default; + constexpr _Enable_default_constructor(_Enable_default_constructor&&) + noexcept = default; + _Enable_default_constructor& + operator=(_Enable_default_constructor const&) noexcept = default; + _Enable_default_constructor& + operator=(_Enable_default_constructor&&) noexcept = default; + + // Can be used in other ctors. + constexpr explicit + _Enable_default_constructor(_Enable_default_constructor_tag) { } + }; + +template + struct _Enable_destructor + { ~_Enable_destructor() noexcept = delete; }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = default; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = default; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +template + struct _Enable_copy_move + { + constexpr _Enable_copy_move() noexcept = default; + constexpr _Enable_copy_move(_Enable_copy_move const&) noexcept = delete; + constexpr _Enable_copy_move(_Enable_copy_move&&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move const&) noexcept = delete; + _Enable_copy_move& + operator=(_Enable_copy_move&&) noexcept = delete; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // _ENABLE_SPECIAL_MEMBERS_H diff --git a/AH/STL/Fallback/bits/exception_defines.h b/AH/STL/Fallback/bits/exception_defines.h new file mode 100644 index 0000000..3668a37 --- /dev/null +++ b/AH/STL/Fallback/bits/exception_defines.h @@ -0,0 +1,45 @@ +// -fno-exceptions Support -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/exception_defines.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{exception} + */ + +#ifndef _EXCEPTION_DEFINES_H +#define _EXCEPTION_DEFINES_H 1 + +#if ! __cpp_exceptions +// Iff -fno-exceptions, transform error handling code to work without it. +# define __try if (true) +# define __catch(X) if (false) +# define __throw_exception_again +#else +// Else proceed normally. +# define __try try +# define __catch(X) catch(X) +# define __throw_exception_again throw +#endif + +#endif diff --git a/AH/STL/Fallback/bits/functexcept.h b/AH/STL/Fallback/bits/functexcept.h new file mode 100644 index 0000000..0aedc19 --- /dev/null +++ b/AH/STL/Fallback/bits/functexcept.h @@ -0,0 +1,165 @@ +// Function-Based Exception Support -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/functexcept.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{exception} + * + * This header provides support for -fno-exceptions. + */ + +// +// ISO C++ 14882: 19.1 Exception classes +// + +#ifndef _FUNCTEXCEPT_H +#define _FUNCTEXCEPT_H 1 + +#include "../bits/c++config.h" +#include "../bits/exception_defines.h" + +#ifndef __AVR__ + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Helper for exception objects in + void + __throw_bad_exception(void) __attribute__((__noreturn__)); + + // Helper for exception objects in + void + __throw_bad_alloc(void) __attribute__((__noreturn__)); + + // Helper for exception objects in + void + __throw_bad_cast(void) __attribute__((__noreturn__)); + + void + __throw_bad_typeid(void) __attribute__((__noreturn__)); + + // Helpers for exception objects in + void + __throw_logic_error(const char*) __attribute__((__noreturn__)); + + void + __throw_domain_error(const char*) __attribute__((__noreturn__)); + + void + __throw_invalid_argument(const char*) __attribute__((__noreturn__)); + + void + __throw_length_error(const char*) __attribute__((__noreturn__)); + + void + __throw_out_of_range(const char*) __attribute__((__noreturn__)); + + void + __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__)) + __attribute__((__format__(__gnu_printf__, 1, 2))); + + void + __throw_runtime_error(const char*) __attribute__((__noreturn__)); + + void + __throw_range_error(const char*) __attribute__((__noreturn__)); + + void + __throw_overflow_error(const char*) __attribute__((__noreturn__)); + + void + __throw_underflow_error(const char*) __attribute__((__noreturn__)); + + // Helpers for exception objects in + void + __throw_ios_failure(const char*) __attribute__((__noreturn__)); + + void + __throw_system_error(int) __attribute__((__noreturn__)); + + void + __throw_future_error(int) __attribute__((__noreturn__)); + + // Helpers for exception objects in + void + __throw_bad_function_call() __attribute__((__noreturn__)); + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#else // __AVR__ + +#include + +// Helper for exception objects in + #define __throw_bad_exception() FATAL_ERROR(F("std::bad_exception"), 0x1111) + + // Helper for exception objects in + #define __throw_bad_alloc() FATAL_ERROR(F("std::bad_alloc"), 0x1112) + + // Helper for exception objects in + #define __throw_bad_cast() FATAL_ERROR(F("std::bad_cast"), 0x1113) + + #define __throw_bad_typeid() FATAL_ERROR(F("std::bad_typeid"), 0x1114) + + // Helpers for exception objects in + #define __throw_logic_error(msg) FATAL_ERROR(F("std::logic_error: ") << msg, 0x1115) + + #define __throw_domain_error(msg) FATAL_ERROR(F("std::domain_error: ") << msg, 0x1116) + + #define __throw_invalid_argument(msg) FATAL_ERROR(F("std::invalid_argument: ") << msg, 0x1117) + + #define __throw_length_error(msg) FATAL_ERROR(F("std::length_error: ") << msg, 0x1118) + + #define __throw_out_of_range(msg) FATAL_ERROR(F("std::out_of_range: ") << msg, 0x1119) + + // void + // __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__)) + // __attribute__((__format__(__gnu_printf__, 1, 2))) + #define __throw_out_of_range_index_length(msg, index, size) \ + FATAL_ERROR(F("std::out_of_range: ") << msg << F("; index = ") << index << F(", length = ") << size, 0x1119) + + #define __throw_runtime_error(msg) FATAL_ERROR(F("std::runtime_error: ") << msg, 0x111A) + + #define __throw_range_error(msg) FATAL_ERROR(F("std::range_error: ") << msg, 0x111B) + + #define __throw_overflow_error(msg) FATAL_ERROR(F("std::overflow_error: ") << msg, 0x111C) + + #define __throw_underflow_error(msg) FATAL_ERROR(F("std::underflow_error: ") << msg, 0x111D) + + // Helpers for exception objects in + #define __throw_ios_failure(msg) FATAL_ERROR(F("std::ios_failure: ") << msg, 0x111E) + + #define __throw_system_error(code) FATAL_ERROR(F("std::system_error: ") << code, 0x1120) + + #define __throw_future_error(code) FATAL_ERROR(F("std::future_error: ") << code, 0x1121) + + + // Helpers for exception objects in + #define __throw_bad_function_call() FATAL_ERROR(F("std::bad_function_call"), 0x111F) + +#endif + +#endif diff --git a/AH/STL/Fallback/bits/functional_hash.h b/AH/STL/Fallback/bits/functional_hash.h new file mode 100644 index 0000000..db66e80 --- /dev/null +++ b/AH/STL/Fallback/bits/functional_hash.h @@ -0,0 +1,274 @@ +// functional_hash.h header -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/functional_hash.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _FUNCTIONAL_HASH_H +#define _FUNCTIONAL_HASH_H 1 + +#pragma GCC system_header + +#include "../bits/hash_bytes.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** @defgroup hashes Hashes + * @ingroup functors + * + * Hashing functors taking a variable type and returning a @c std::size_t. + * + * @{ + */ + + template + struct __hash_base + { + typedef _Result result_type; + typedef _Arg argument_type; + }; + + /// Primary class template hash. + template + struct hash; + + template + struct __poison_hash + { + static constexpr bool __enable_hash_call = false; + private: + // Private rather than deleted to be non-trivially-copyable. + __poison_hash(__poison_hash&&); + ~__poison_hash(); + }; + + template + struct __poison_hash<_Tp, __void_t()(declval<_Tp>()))>> + { + static constexpr bool __enable_hash_call = true; + }; + + // Helper struct for SFINAE-poisoning non-enum types. + template::value> + struct __hash_enum + { + private: + // Private rather than deleted to be non-trivially-copyable. + __hash_enum(__hash_enum&&); + ~__hash_enum(); + }; + + // Helper struct for hash with enum types. + template + struct __hash_enum<_Tp, true> : public __hash_base + { + size_t + operator()(_Tp __val) const noexcept + { + using __type = typename underlying_type<_Tp>::type; + return hash<__type>{}(static_cast<__type>(__val)); + } + }; + + /// Primary class template hash, usable for enum types only. + // Use with non-enum types still SFINAES. + template + struct hash : __hash_enum<_Tp> + { }; + + /// Partial specializations for pointer types. + template + struct hash<_Tp*> : public __hash_base + { + size_t + operator()(_Tp* __p) const noexcept + { return reinterpret_cast(__p); } + }; + + // Explicit specializations for integer types. +#define _Cxx_hashtable_define_trivial_hash(_Tp) \ + template<> \ + struct hash<_Tp> : public __hash_base \ + { \ + size_t \ + operator()(_Tp __val) const noexcept \ + { return static_cast(__val); } \ + }; + + /// Explicit specialization for bool. + _Cxx_hashtable_define_trivial_hash(bool) + + /// Explicit specialization for char. + _Cxx_hashtable_define_trivial_hash(char) + + /// Explicit specialization for signed char. + _Cxx_hashtable_define_trivial_hash(signed char) + + /// Explicit specialization for unsigned char. + _Cxx_hashtable_define_trivial_hash(unsigned char) + + /// Explicit specialization for wchar_t. + _Cxx_hashtable_define_trivial_hash(wchar_t) + + /// Explicit specialization for char16_t. + _Cxx_hashtable_define_trivial_hash(char16_t) + + /// Explicit specialization for char32_t. + _Cxx_hashtable_define_trivial_hash(char32_t) + + /// Explicit specialization for short. + _Cxx_hashtable_define_trivial_hash(short) + + /// Explicit specialization for int. + _Cxx_hashtable_define_trivial_hash(int) + + /// Explicit specialization for long. + _Cxx_hashtable_define_trivial_hash(long) + + /// Explicit specialization for long long. + _Cxx_hashtable_define_trivial_hash(long long) + + /// Explicit specialization for unsigned short. + _Cxx_hashtable_define_trivial_hash(unsigned short) + + /// Explicit specialization for unsigned int. + _Cxx_hashtable_define_trivial_hash(unsigned int) + + /// Explicit specialization for unsigned long. + _Cxx_hashtable_define_trivial_hash(unsigned long) + + /// Explicit specialization for unsigned long long. + _Cxx_hashtable_define_trivial_hash(unsigned long long) + +#ifdef __GLIBCXX_TYPE_INT_N_0 + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_0) + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_0 unsigned) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_1 + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_1) + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_1 unsigned) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_2 + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_2) + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_2 unsigned) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_3 + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_3) + _Cxx_hashtable_define_trivial_hash(__GLIBCXX_TYPE_INT_N_3 unsigned) +#endif + +#undef _Cxx_hashtable_define_trivial_hash + + struct _Hash_impl + { + static size_t + hash(const void* __ptr, size_t __clength, + size_t __seed = static_cast(0xc70f6907UL)) + { return _Hash_bytes(__ptr, __clength, __seed); } + + template + static size_t + hash(const _Tp& __val) + { return hash(&__val, sizeof(__val)); } + + template + static size_t + __hash_combine(const _Tp& __val, size_t __hash) + { return hash(&__val, sizeof(__val), __hash); } + }; + + // A hash function similar to FNV-1a (see PR59406 for how it differs). + struct _Fnv_hash_impl + { + static size_t + hash(const void* __ptr, size_t __clength, + size_t __seed = static_cast(2166136261UL)) + { return _Fnv_hash_bytes(__ptr, __clength, __seed); } + + template + static size_t + hash(const _Tp& __val) + { return hash(&__val, sizeof(__val)); } + + template + static size_t + __hash_combine(const _Tp& __val, size_t __hash) + { return hash(&__val, sizeof(__val), __hash); } + }; + + /// Specialization for float. + template<> + struct hash : public __hash_base + { + size_t + operator()(float __val) const noexcept + { + // 0 and -0 both hash to zero. + return __val != 0.0f ? std::_Hash_impl::hash(__val) : 0; + } + }; + + /// Specialization for double. + template<> + struct hash : public __hash_base + { + size_t + operator()(double __val) const noexcept + { + // 0 and -0 both hash to zero. + return __val != 0.0 ? std::_Hash_impl::hash(__val) : 0; + } + }; + + /// Specialization for long double. + template<> + struct hash + : public __hash_base + { + _GLIBCXX_PURE size_t + operator()(long double __val) const noexcept; + }; + + // @} group hashes + + // Hint about performance of hash functor. If not fast the hash-based + // containers will cache the hash code. + // Default behavior is to consider that hashers are fast unless specified + // otherwise. + template + struct __is_fast_hash : public std::true_type + { }; + + template<> + struct __is_fast_hash> : public std::false_type + { }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _FUNCTIONAL_HASH_H diff --git a/AH/STL/Fallback/bits/hash_bytes.h b/AH/STL/Fallback/bits/hash_bytes.h new file mode 100644 index 0000000..4272aa1 --- /dev/null +++ b/AH/STL/Fallback/bits/hash_bytes.h @@ -0,0 +1,59 @@ +// Declarations for hash functions. -*- C++ -*- + +// Copyright (C) 2010-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/hash_bytes.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _HASH_BYTES_H +#define _HASH_BYTES_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" + +namespace std +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Hash function implementation for the nontrivial specialization. + // All of them are based on a primitive that hashes a pointer to a + // byte array. The actual hash algorithm is not guaranteed to stay + // the same from release to release -- it may be updated or tuned to + // improve hash quality or speed. + size_t + _Hash_bytes(const void* __ptr, size_t __len, size_t __seed); + + // A similar hash primitive, using the FNV hash algorithm. This + // algorithm is guaranteed to stay the same from release to release. + // (although it might not produce the same values on different + // machines.) + size_t + _Fnv_hash_bytes(const void* __ptr, size_t __len, size_t __seed); + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif diff --git a/AH/STL/Fallback/bits/invoke.h b/AH/STL/Fallback/bits/invoke.h new file mode 100644 index 0000000..646d5a8 --- /dev/null +++ b/AH/STL/Fallback/bits/invoke.h @@ -0,0 +1,104 @@ +// Implementation of INVOKE -*- C++ -*- + +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/invoke.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _GLIBCXX_INVOKE_H +#define _GLIBCXX_INVOKE_H 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "../bits/c++0x_warning.h" +#else + +#include "../type_traits" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + // Used by __invoke_impl instead of std::forward<_Tp> so that a + // reference_wrapper is converted to an lvalue-reference. + template::type> + constexpr _Up&& + __invfwd(typename remove_reference<_Tp>::type& __t) noexcept + { return static_cast<_Up&&>(__t); } + + template + constexpr _Res + __invoke_impl(__invoke_other, _Fn&& __f, _Args&&... __args) + { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); } + + template + constexpr _Res + __invoke_impl(__invoke_memfun_ref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + { return (__invfwd<_Tp>(__t).*__f)(std::forward<_Args>(__args)...); } + + template + constexpr _Res + __invoke_impl(__invoke_memfun_deref, _MemFun&& __f, _Tp&& __t, + _Args&&... __args) + { + return ((*std::forward<_Tp>(__t)).*__f)(std::forward<_Args>(__args)...); + } + + template + constexpr _Res + __invoke_impl(__invoke_memobj_ref, _MemPtr&& __f, _Tp&& __t) + { return __invfwd<_Tp>(__t).*__f; } + + template + constexpr _Res + __invoke_impl(__invoke_memobj_deref, _MemPtr&& __f, _Tp&& __t) + { return (*std::forward<_Tp>(__t)).*__f; } + + /// Invoke a callable object. + template + constexpr typename __invoke_result<_Callable, _Args...>::type + __invoke(_Callable&& __fn, _Args&&... __args) + noexcept(__is_nothrow_invocable<_Callable, _Args...>::value) + { + using __result = __invoke_result<_Callable, _Args...>; + using __type = typename __result::type; + using __tag = typename __result::__invoke_type; + return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn), + std::forward<_Args>(__args)...); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++11 + +#endif // _GLIBCXX_INVOKE_H diff --git a/AH/STL/Fallback/bits/memoryfwd.h b/AH/STL/Fallback/bits/memoryfwd.h new file mode 100644 index 0000000..5da9e18 --- /dev/null +++ b/AH/STL/Fallback/bits/memoryfwd.h @@ -0,0 +1,78 @@ +// Forward declarations -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * Copyright (c) 1996-1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/memoryfwd.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _MEMORYFWD_H +#define _MEMORYFWD_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup allocators Allocators + * @ingroup memory + * + * Classes encapsulating memory operations. + * + * @{ + */ + + template + class allocator; + + template<> + class allocator; + + /// Declare uses_allocator so it can be specialized in \ etc. + template + struct uses_allocator; + + /// @} group memory + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif diff --git a/AH/STL/Fallback/bits/move.h b/AH/STL/Fallback/bits/move.h new file mode 100644 index 0000000..c5fcd91 --- /dev/null +++ b/AH/STL/Fallback/bits/move.h @@ -0,0 +1,225 @@ +// Move, forward and identity for C++11 + swap -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/move.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{utility} + */ + +#ifndef _MOVE_H +#define _MOVE_H 1 + +#include "../bits/c++config.h" +#include "../bits/concept_check.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Used, in C++03 mode too, by allocators, etc. + /** + * @brief Same as C++11 std::addressof + * @ingroup utilities + */ + template + inline _GLIBCXX_CONSTEXPR _Tp* + __addressof(_Tp& __r) _GLIBCXX_NOEXCEPT + { return __builtin_addressof(__r); } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if __cplusplus >= 201103L +#include "../type_traits" // Brings in std::declval too. + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + /** + * @brief Forward an lvalue. + * @return The parameter cast to the specified type. + * + * This function is used to implement "perfect forwarding". + */ + template + constexpr _Tp&& + forward(typename std::remove_reference<_Tp>::type& __t) noexcept + { return static_cast<_Tp&&>(__t); } + + /** + * @brief Forward an rvalue. + * @return The parameter cast to the specified type. + * + * This function is used to implement "perfect forwarding". + */ + template + constexpr _Tp&& + forward(typename std::remove_reference<_Tp>::type&& __t) noexcept + { + static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument" + " substituting _Tp is an lvalue reference type"); + return static_cast<_Tp&&>(__t); + } + + /** + * @brief Convert a value to an rvalue. + * @param __t A thing of arbitrary type. + * @return The parameter cast to an rvalue-reference to allow moving it. + */ + template + constexpr typename std::remove_reference<_Tp>::type&& + move(_Tp&& __t) noexcept + { return static_cast::type&&>(__t); } + + + template + struct __move_if_noexcept_cond + : public __and_<__not_>, + is_copy_constructible<_Tp>>::type { }; + + /** + * @brief Conditionally convert a value to an rvalue. + * @param __x A thing of arbitrary type. + * @return The parameter, possibly cast to an rvalue-reference. + * + * Same as std::move unless the type's move constructor could throw and the + * type is copyable, in which case an lvalue-reference is returned instead. + */ + template + constexpr typename + conditional<__move_if_noexcept_cond<_Tp>::value, const _Tp&, _Tp&&>::type + move_if_noexcept(_Tp& __x) noexcept + { return std::move(__x); } + + // declval, from type_traits. + +#if __cplusplus > 201402L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2296. std::addressof should be constexpr +# define __cpp_lib_addressof_constexpr 201603 +#endif + /** + * @brief Returns the actual address of the object or function + * referenced by r, even in the presence of an overloaded + * operator&. + * @param __r Reference to an object or function. + * @return The actual address. + */ + template + inline _GLIBCXX17_CONSTEXPR _Tp* + addressof(_Tp& __r) noexcept + { return std::__addressof(__r); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2598. addressof works on temporaries + template + const _Tp* addressof(const _Tp&&) = delete; + + // C++11 version of std::exchange for internal use. + template + inline _Tp + __exchange(_Tp& __obj, _Up&& __new_val) + { + _Tp __old_val = std::move(__obj); + __obj = std::forward<_Up>(__new_val); + return __old_val; + } + + /// @} group utilities +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#define _GLIBCXX_MOVE(__val) std::move(__val) +#define _GLIBCXX_FORWARD(_Tp, __val) std::forward<_Tp>(__val) +#else +#define _GLIBCXX_MOVE(__val) (__val) +#define _GLIBCXX_FORWARD(_Tp, __val) (__val) +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + /** + * @brief Swaps two values. + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @return Nothing. + */ + template + inline +#if __cplusplus >= 201103L + typename enable_if<__and_<__not_<__is_tuple_like<_Tp>>, + is_move_constructible<_Tp>, + is_move_assignable<_Tp>>::value>::type + swap(_Tp& __a, _Tp& __b) + noexcept(__and_, + is_nothrow_move_assignable<_Tp>>::value) +#else + void + swap(_Tp& __a, _Tp& __b) +#endif + { + // concept requirements + __glibcxx_function_requires(_SGIAssignableConcept<_Tp>) + + _Tp __tmp = _GLIBCXX_MOVE(__a); + __a = _GLIBCXX_MOVE(__b); + __b = _GLIBCXX_MOVE(__tmp); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 809. std::swap should be overloaded for array types. + /// Swap the contents of two arrays. + template + inline +#if __cplusplus >= 201103L + typename enable_if<__is_swappable<_Tp>::value>::type + swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]) + noexcept(__is_nothrow_swappable<_Tp>::value) +#else + void + swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]) +#endif + { + for (size_t __n = 0; __n < _Nm; ++__n) + swap(__a[__n], __b[__n]); + } + + /// @} group utilities +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _MOVE_H */ diff --git a/AH/STL/Fallback/bits/os_defines.h b/AH/STL/Fallback/bits/os_defines.h new file mode 100644 index 0000000..a3435aa --- /dev/null +++ b/AH/STL/Fallback/bits/os_defines.h @@ -0,0 +1,54 @@ +// Specific definitions for GNU/Linux -*- C++ -*- + +// Copyright (C) 2000-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/os_defines.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iosfwd} + */ + +#ifndef _GLIBCXX_OS_DEFINES +#define _GLIBCXX_OS_DEFINES 1 + +// System-specific #define, typedefs, corrections, etc, go here. This +// file will come before all others. + +// This keeps isanum, et al from being propagated as macros. +#define __NO_CTYPE 1 + +#if 0 // No GlibC +#include // TODO + +// Provide a declaration for the possibly deprecated gets function, as +// glibc 2.15 and later does not declare gets for ISO C11 when +// __GNU_SOURCE is defined. +#if __GLIBC_PREREQ(2,15) && defined(_GNU_SOURCE) +# undef _GLIBCXX_HAVE_GETS +#endif + +// Glibc 2.23 removed the obsolete isinf and isnan declarations. Check the +// version dynamically in case it has changed since libstdc++ was configured. +#define _GLIBCXX_NO_OBSOLETE_ISINF_ISNAN_DYNAMIC __GLIBC_PREREQ(2,23) +#endif + +#endif diff --git a/AH/STL/Fallback/bits/predefined_ops.h b/AH/STL/Fallback/bits/predefined_ops.h new file mode 100644 index 0000000..0624a38 --- /dev/null +++ b/AH/STL/Fallback/bits/predefined_ops.h @@ -0,0 +1,362 @@ +// Default predicates for internal use -*- C++ -*- + +// Copyright (C) 2013-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file predefined_ops.h + * This is an internal header file, included by other library headers. + * You should not attempt to use it directly. @headername{algorithm} + */ + +#ifndef _GLIBCXX_PREDEFINED_OPS_H +#define _GLIBCXX_PREDEFINED_OPS_H 1 + +namespace __gnu_cxx +{ +namespace __ops +{ + struct _Iter_less_iter + { + template + _GLIBCXX14_CONSTEXPR + bool + operator()(_Iterator1 __it1, _Iterator2 __it2) const + { return *__it1 < *__it2; } + }; + + _GLIBCXX14_CONSTEXPR + inline _Iter_less_iter + __iter_less_iter() + { return _Iter_less_iter(); } + + struct _Iter_less_val + { +#if __cplusplus >= 201103L + constexpr _Iter_less_val() = default; +#else + _Iter_less_val() { } +#endif + + explicit + _Iter_less_val(_Iter_less_iter) { } + + template + bool + operator()(_Iterator __it, _Value& __val) const + { return *__it < __val; } + }; + + inline _Iter_less_val + __iter_less_val() + { return _Iter_less_val(); } + + inline _Iter_less_val + __iter_comp_val(_Iter_less_iter) + { return _Iter_less_val(); } + + struct _Val_less_iter + { +#if __cplusplus >= 201103L + constexpr _Val_less_iter() = default; +#else + _Val_less_iter() { } +#endif + + explicit + _Val_less_iter(_Iter_less_iter) { } + + template + bool + operator()(_Value& __val, _Iterator __it) const + { return __val < *__it; } + }; + + inline _Val_less_iter + __val_less_iter() + { return _Val_less_iter(); } + + inline _Val_less_iter + __val_comp_iter(_Iter_less_iter) + { return _Val_less_iter(); } + + struct _Iter_equal_to_iter + { + template + bool + operator()(_Iterator1 __it1, _Iterator2 __it2) const + { return *__it1 == *__it2; } + }; + + inline _Iter_equal_to_iter + __iter_equal_to_iter() + { return _Iter_equal_to_iter(); } + + struct _Iter_equal_to_val + { + template + bool + operator()(_Iterator __it, _Value& __val) const + { return *__it == __val; } + }; + + inline _Iter_equal_to_val + __iter_equal_to_val() + { return _Iter_equal_to_val(); } + + inline _Iter_equal_to_val + __iter_comp_val(_Iter_equal_to_iter) + { return _Iter_equal_to_val(); } + + template + struct _Iter_comp_iter + { + _Compare _M_comp; + + explicit _GLIBCXX14_CONSTEXPR + _Iter_comp_iter(_Compare __comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) + { } + + template + _GLIBCXX14_CONSTEXPR + bool + operator()(_Iterator1 __it1, _Iterator2 __it2) + { return bool(_M_comp(*__it1, *__it2)); } + }; + + template + _GLIBCXX14_CONSTEXPR + inline _Iter_comp_iter<_Compare> + __iter_comp_iter(_Compare __comp) + { return _Iter_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp)); } + + template + struct _Iter_comp_val + { + _Compare _M_comp; + + explicit + _Iter_comp_val(_Compare __comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) + { } + + explicit + _Iter_comp_val(const _Iter_comp_iter<_Compare>& __comp) + : _M_comp(__comp._M_comp) + { } + +#if __cplusplus >= 201103L + explicit + _Iter_comp_val(_Iter_comp_iter<_Compare>&& __comp) + : _M_comp(std::move(__comp._M_comp)) + { } +#endif + + template + bool + operator()(_Iterator __it, _Value& __val) + { return bool(_M_comp(*__it, __val)); } + }; + + template + inline _Iter_comp_val<_Compare> + __iter_comp_val(_Compare __comp) + { return _Iter_comp_val<_Compare>(_GLIBCXX_MOVE(__comp)); } + + template + inline _Iter_comp_val<_Compare> + __iter_comp_val(_Iter_comp_iter<_Compare> __comp) + { return _Iter_comp_val<_Compare>(_GLIBCXX_MOVE(__comp)); } + + template + struct _Val_comp_iter + { + _Compare _M_comp; + + explicit + _Val_comp_iter(_Compare __comp) + : _M_comp(_GLIBCXX_MOVE(__comp)) + { } + + explicit + _Val_comp_iter(const _Iter_comp_iter<_Compare>& __comp) + : _M_comp(__comp._M_comp) + { } + +#if __cplusplus >= 201103L + explicit + _Val_comp_iter(_Iter_comp_iter<_Compare>&& __comp) + : _M_comp(std::move(__comp._M_comp)) + { } +#endif + + template + bool + operator()(_Value& __val, _Iterator __it) + { return bool(_M_comp(__val, *__it)); } + }; + + template + inline _Val_comp_iter<_Compare> + __val_comp_iter(_Compare __comp) + { return _Val_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp)); } + + template + inline _Val_comp_iter<_Compare> + __val_comp_iter(_Iter_comp_iter<_Compare> __comp) + { return _Val_comp_iter<_Compare>(_GLIBCXX_MOVE(__comp)); } + + template + struct _Iter_equals_val + { + _Value& _M_value; + + explicit + _Iter_equals_val(_Value& __value) + : _M_value(__value) + { } + + template + bool + operator()(_Iterator __it) + { return *__it == _M_value; } + }; + + template + inline _Iter_equals_val<_Value> + __iter_equals_val(_Value& __val) + { return _Iter_equals_val<_Value>(__val); } + + template + struct _Iter_equals_iter + { + _Iterator1 _M_it1; + + explicit + _Iter_equals_iter(_Iterator1 __it1) + : _M_it1(__it1) + { } + + template + bool + operator()(_Iterator2 __it2) + { return *__it2 == *_M_it1; } + }; + + template + inline _Iter_equals_iter<_Iterator> + __iter_comp_iter(_Iter_equal_to_iter, _Iterator __it) + { return _Iter_equals_iter<_Iterator>(__it); } + + template + struct _Iter_pred + { + _Predicate _M_pred; + + explicit + _Iter_pred(_Predicate __pred) + : _M_pred(_GLIBCXX_MOVE(__pred)) + { } + + template + bool + operator()(_Iterator __it) + { return bool(_M_pred(*__it)); } + }; + + template + inline _Iter_pred<_Predicate> + __pred_iter(_Predicate __pred) + { return _Iter_pred<_Predicate>(_GLIBCXX_MOVE(__pred)); } + + template + struct _Iter_comp_to_val + { + _Compare _M_comp; + _Value& _M_value; + + _Iter_comp_to_val(_Compare __comp, _Value& __value) + : _M_comp(_GLIBCXX_MOVE(__comp)), _M_value(__value) + { } + + template + bool + operator()(_Iterator __it) + { return bool(_M_comp(*__it, _M_value)); } + }; + + template + _Iter_comp_to_val<_Compare, _Value> + __iter_comp_val(_Compare __comp, _Value &__val) + { + return _Iter_comp_to_val<_Compare, _Value>(_GLIBCXX_MOVE(__comp), __val); + } + + template + struct _Iter_comp_to_iter + { + _Compare _M_comp; + _Iterator1 _M_it1; + + _Iter_comp_to_iter(_Compare __comp, _Iterator1 __it1) + : _M_comp(_GLIBCXX_MOVE(__comp)), _M_it1(__it1) + { } + + template + bool + operator()(_Iterator2 __it2) + { return bool(_M_comp(*__it2, *_M_it1)); } + }; + + template + inline _Iter_comp_to_iter<_Compare, _Iterator> + __iter_comp_iter(_Iter_comp_iter<_Compare> __comp, _Iterator __it) + { + return _Iter_comp_to_iter<_Compare, _Iterator>( + _GLIBCXX_MOVE(__comp._M_comp), __it); + } + + template + struct _Iter_negate + { + _Predicate _M_pred; + + explicit + _Iter_negate(_Predicate __pred) + : _M_pred(_GLIBCXX_MOVE(__pred)) + { } + + template + bool + operator()(_Iterator __it) + { return !bool(_M_pred(*__it)); } + }; + + template + inline _Iter_negate<_Predicate> + __negate(_Iter_pred<_Predicate> __pred) + { return _Iter_negate<_Predicate>(_GLIBCXX_MOVE(__pred._M_pred)); } + +} // namespace __ops +} // namespace __gnu_cxx + +#endif diff --git a/AH/STL/Fallback/bits/ptr_traits.h b/AH/STL/Fallback/bits/ptr_traits.h new file mode 100644 index 0000000..01cfea7 --- /dev/null +++ b/AH/STL/Fallback/bits/ptr_traits.h @@ -0,0 +1,154 @@ +// Pointer Traits -*- C++ -*- + +// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/ptr_traits.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _PTR_TRAITS_H +#define _PTR_TRAITS_H 1 + +#if __cplusplus >= 201103L + +#include "../bits/move.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + class __undefined; + + // Given Template return T, otherwise invalid. + template + struct __get_first_arg + { using type = __undefined; }; + + template class _Template, typename _Tp, + typename... _Types> + struct __get_first_arg<_Template<_Tp, _Types...>> + { using type = _Tp; }; + + template + using __get_first_arg_t = typename __get_first_arg<_Tp>::type; + + // Given Template and U return Template, otherwise invalid. + template + struct __replace_first_arg + { }; + + template class _Template, typename _Up, + typename _Tp, typename... _Types> + struct __replace_first_arg<_Template<_Tp, _Types...>, _Up> + { using type = _Template<_Up, _Types...>; }; + + template + using __replace_first_arg_t = typename __replace_first_arg<_Tp, _Up>::type; + + template + using __make_not_void + = typename conditional::value, __undefined, _Tp>::type; + + /** + * @brief Uniform interface to all pointer-like types + * @ingroup pointer_abstractions + */ + template + struct pointer_traits + { + private: + template + using __element_type = typename _Tp::element_type; + + template + using __difference_type = typename _Tp::difference_type; + + template + struct __rebind : __replace_first_arg<_Tp, _Up> { }; + + template + struct __rebind<_Tp, _Up, __void_t>> + { using type = typename _Tp::template rebind<_Up>; }; + + public: + /// The pointer type. + using pointer = _Ptr; + + /// The type pointed to. + using element_type + = __detected_or_t<__get_first_arg_t<_Ptr>, __element_type, _Ptr>; + + /// The type used to represent the difference between two pointers. + using difference_type + = __detected_or_t; + + /// A pointer to a different type. + template + using rebind = typename __rebind<_Ptr, _Up>::type; + + static _Ptr + pointer_to(__make_not_void& __e) + { return _Ptr::pointer_to(__e); } + + static_assert(!is_same::value, + "pointer type defines element_type or is like SomePointer"); + }; + + /** + * @brief Partial specialization for built-in pointers. + * @ingroup pointer_abstractions + */ + template + struct pointer_traits<_Tp*> + { + /// The pointer type + typedef _Tp* pointer; + /// The type pointed to + typedef _Tp element_type; + /// Type used to represent the difference between two pointers + typedef ptrdiff_t difference_type; + + template + using rebind = _Up*; + + /** + * @brief Obtain a pointer to an object + * @param __r A reference to an object of type @c element_type + * @return @c addressof(__r) + */ + static pointer + pointer_to(__make_not_void& __r) noexcept + { return std::addressof(__r); } + }; + + /// Convenience alias for rebinding pointers. + template + using __ptr_rebind = typename pointer_traits<_Ptr>::template rebind<_Tp>; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif + +#endif diff --git a/AH/STL/Fallback/bits/range_access.h b/AH/STL/Fallback/bits/range_access.h new file mode 100644 index 0000000..00c01c7 --- /dev/null +++ b/AH/STL/Fallback/bits/range_access.h @@ -0,0 +1,328 @@ +// -*- C++ -*- + +// Copyright (C) 2010-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/range_access.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + */ + +#ifndef _GLIBCXX_RANGE_ACCESS_H +#define _GLIBCXX_RANGE_ACCESS_H 1 + +#pragma GCC system_header + +#if __cplusplus >= 201103L +#include "../initializer_list" +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief Return an iterator pointing to the first element of + * the container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + begin(_Container& __cont) -> decltype(__cont.begin()) + { return __cont.begin(); } + + /** + * @brief Return an iterator pointing to the first element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + begin(const _Container& __cont) -> decltype(__cont.begin()) + { return __cont.begin(); } + + /** + * @brief Return an iterator pointing to one past the last element of + * the container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + end(_Container& __cont) -> decltype(__cont.end()) + { return __cont.end(); } + + /** + * @brief Return an iterator pointing to one past the last element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + end(const _Container& __cont) -> decltype(__cont.end()) + { return __cont.end(); } + + /** + * @brief Return an iterator pointing to the first element of the array. + * @param __arr Array. + */ + template + inline _GLIBCXX14_CONSTEXPR _Tp* + begin(_Tp (&__arr)[_Nm]) + { return __arr; } + + /** + * @brief Return an iterator pointing to one past the last element + * of the array. + * @param __arr Array. + */ + template + inline _GLIBCXX14_CONSTEXPR _Tp* + end(_Tp (&__arr)[_Nm]) + { return __arr + _Nm; } + +#if __cplusplus >= 201402L + + template class valarray; + // These overloads must be declared for cbegin and cend to use them. + template _Tp* begin(valarray<_Tp>&); + template const _Tp* begin(const valarray<_Tp>&); + template _Tp* end(valarray<_Tp>&); + template const _Tp* end(const valarray<_Tp>&); + + /** + * @brief Return an iterator pointing to the first element of + * the const container. + * @param __cont Container. + */ + template + inline constexpr auto + cbegin(const _Container& __cont) noexcept(noexcept(std::begin(__cont))) + -> decltype(std::begin(__cont)) + { return std::begin(__cont); } + + /** + * @brief Return an iterator pointing to one past the last element of + * the const container. + * @param __cont Container. + */ + template + inline constexpr auto + cend(const _Container& __cont) noexcept(noexcept(std::end(__cont))) + -> decltype(std::end(__cont)) + { return std::end(__cont); } + + /** + * @brief Return a reverse iterator pointing to the last element of + * the container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + rbegin(_Container& __cont) -> decltype(__cont.rbegin()) + { return __cont.rbegin(); } + + /** + * @brief Return a reverse iterator pointing to the last element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + rbegin(const _Container& __cont) -> decltype(__cont.rbegin()) + { return __cont.rbegin(); } + + /** + * @brief Return a reverse iterator pointing one past the first element of + * the container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + rend(_Container& __cont) -> decltype(__cont.rend()) + { return __cont.rend(); } + + /** + * @brief Return a reverse iterator pointing one past the first element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + rend(const _Container& __cont) -> decltype(__cont.rend()) + { return __cont.rend(); } + + /** + * @brief Return a reverse iterator pointing to the last element of + * the array. + * @param __arr Array. + */ + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Tp*> + rbegin(_Tp (&__arr)[_Nm]) + { return reverse_iterator<_Tp*>(__arr + _Nm); } + + /** + * @brief Return a reverse iterator pointing one past the first element of + * the array. + * @param __arr Array. + */ + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Tp*> + rend(_Tp (&__arr)[_Nm]) + { return reverse_iterator<_Tp*>(__arr); } + + /** + * @brief Return a reverse iterator pointing to the last element of + * the initializer_list. + * @param __il initializer_list. + */ + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator + rbegin(initializer_list<_Tp> __il) + { return reverse_iterator(__il.end()); } + + /** + * @brief Return a reverse iterator pointing one past the first element of + * the initializer_list. + * @param __il initializer_list. + */ + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator + rend(initializer_list<_Tp> __il) + { return reverse_iterator(__il.begin()); } + + /** + * @brief Return a reverse iterator pointing to the last element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + crbegin(const _Container& __cont) -> decltype(std::rbegin(__cont)) + { return std::rbegin(__cont); } + + /** + * @brief Return a reverse iterator pointing one past the first element of + * the const container. + * @param __cont Container. + */ + template + inline _GLIBCXX17_CONSTEXPR auto + crend(const _Container& __cont) -> decltype(std::rend(__cont)) + { return std::rend(__cont); } + +#endif // C++14 + +#if __cplusplus >= 201703L +#define __cpp_lib_nonmember_container_access 201411 + + /** + * @brief Return the size of a container. + * @param __cont Container. + */ + template + constexpr auto + size(const _Container& __cont) noexcept(noexcept(__cont.size())) + -> decltype(__cont.size()) + { return __cont.size(); } + + /** + * @brief Return the size of an array. + * @param __array Array. + */ + template + constexpr size_t + size(const _Tp (&/*__array*/)[_Nm]) noexcept + { return _Nm; } + + /** + * @brief Return whether a container is empty. + * @param __cont Container. + */ + template + constexpr auto + empty(const _Container& __cont) noexcept(noexcept(__cont.empty())) + -> decltype(__cont.empty()) + { return __cont.empty(); } + + /** + * @brief Return whether an array is empty (always false). + * @param __array Container. + */ + template + constexpr bool + empty(const _Tp (&/*__array*/)[_Nm]) noexcept + { return false; } + + /** + * @brief Return whether an initializer_list is empty. + * @param __il Initializer list. + */ + template + constexpr bool + empty(initializer_list<_Tp> __il) noexcept + { return __il.size() == 0;} + + /** + * @brief Return the data pointer of a container. + * @param __cont Container. + */ + template + constexpr auto + data(_Container& __cont) noexcept(noexcept(__cont.data())) + -> decltype(__cont.data()) + { return __cont.data(); } + + /** + * @brief Return the data pointer of a const container. + * @param __cont Container. + */ + template + constexpr auto + data(const _Container& __cont) noexcept(noexcept(__cont.data())) + -> decltype(__cont.data()) + { return __cont.data(); } + + /** + * @brief Return the data pointer of an array. + * @param __array Array. + */ + template + constexpr _Tp* + data(_Tp (&__array)[_Nm]) noexcept + { return __array; } + + /** + * @brief Return the data pointer of an initializer list. + * @param __il Initializer list. + */ + template + constexpr const _Tp* + data(initializer_list<_Tp> __il) noexcept + { return __il.begin(); } + +#endif // C++17 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // C++11 + +#endif // _GLIBCXX_RANGE_ACCESS_H diff --git a/AH/STL/Fallback/bits/std_abs.h b/AH/STL/Fallback/bits/std_abs.h new file mode 100644 index 0000000..c3c3d15 --- /dev/null +++ b/AH/STL/Fallback/bits/std_abs.h @@ -0,0 +1,110 @@ +// -*- C++ -*- C library enhancements header. + +// Copyright (C) 2016-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/bits/std_abs.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{cmath, cstdlib} + */ + +#ifndef _GLIBCXX_BITS_STD_ABS_H +#define _GLIBCXX_BITS_STD_ABS_H + +#pragma GCC system_header + +#include "../bits/c++config.h" + +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include_next +#ifdef __CORRECT_ISO_CPP_MATH_H_PROTO +# include_next +#endif +#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS + +#undef abs + +extern "C++" +{ +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + using ::abs; + +#ifndef __CORRECT_ISO_CPP_STDLIB_H_PROTO + inline long + abs(long __i) { return __builtin_labs(__i); } +#endif + +#ifdef _GLIBCXX_USE_LONG_LONG + inline long long + abs(long long __x) { return __builtin_llabs (__x); } +#endif + +// _GLIBCXX_RESOLVE_LIB_DEFECTS +// 2192. Validity and return type of std::abs(0u) is unclear +// 2294. should declare abs(double) + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR double + abs(double __x) + { return __builtin_fabs(__x); } + + inline _GLIBCXX_CONSTEXPR float + abs(float __x) + { return __builtin_fabsf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + abs(long double __x) + { return __builtin_fabsl(__x); } +#endif + +#if defined(__GLIBCXX_TYPE_INT_N_0) + inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_0 + abs(__GLIBCXX_TYPE_INT_N_0 __x) { return __x >= 0 ? __x : -__x; } +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_1 + abs(__GLIBCXX_TYPE_INT_N_1 __x) { return __x >= 0 ? __x : -__x; } +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_2 + abs(__GLIBCXX_TYPE_INT_N_2 __x) { return __x >= 0 ? __x : -__x; } +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) + inline _GLIBCXX_CONSTEXPR __GLIBCXX_TYPE_INT_N_3 + abs(__GLIBCXX_TYPE_INT_N_3 __x) { return __x >= 0 ? __x : -__x; } +#endif + +#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) && !defined(__CUDACC__) + inline _GLIBCXX_CONSTEXPR + __float128 + abs(__float128 __x) + { return __x < 0 ? -__x : __x; } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace +} + +#endif // _GLIBCXX_BITS_STD_ABS_H diff --git a/AH/STL/Fallback/bits/stl_algo.h b/AH/STL/Fallback/bits/stl_algo.h new file mode 100644 index 0000000..1a89f6f --- /dev/null +++ b/AH/STL/Fallback/bits/stl_algo.h @@ -0,0 +1,5836 @@ +// Algorithm implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_algo.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{algorithm} + */ + +#ifndef _STL_ALGO_H +#define _STL_ALGO_H 1 + +#include "../cstdlib" // for rand +#include "../bits/algorithmfwd.h" +#include "../bits/stl_heap.h" +#include "../bits/stl_tempbuf.h" // for _Temporary_buffer +#include "../bits/predefined_ops.h" + +#if __cplusplus >= 201103L +#include "../bits/uniform_int_dist.h" +#endif + +// See concept_check.h for the __glibcxx_*_requires macros. + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /// Swaps the median value of *__a, *__b and *__c under __comp to *__result + template + void + __move_median_to_first(_Iterator __result,_Iterator __a, _Iterator __b, + _Iterator __c, _Compare __comp) + { + if (__comp(__a, __b)) + { + if (__comp(__b, __c)) + std::iter_swap(__result, __b); + else if (__comp(__a, __c)) + std::iter_swap(__result, __c); + else + std::iter_swap(__result, __a); + } + else if (__comp(__a, __c)) + std::iter_swap(__result, __a); + else if (__comp(__b, __c)) + std::iter_swap(__result, __c); + else + std::iter_swap(__result, __b); + } + + /// This is an overload used by find algos for the Input Iterator case. + template + inline _InputIterator + __find_if(_InputIterator __first, _InputIterator __last, + _Predicate __pred, input_iterator_tag) + { + while (__first != __last && !__pred(__first)) + ++__first; + return __first; + } + + /// This is an overload used by find algos for the RAI case. + template + _RandomAccessIterator + __find_if(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Predicate __pred, random_access_iterator_tag) + { + typename iterator_traits<_RandomAccessIterator>::difference_type + __trip_count = (__last - __first) >> 2; + + for (; __trip_count > 0; --__trip_count) + { + if (__pred(__first)) + return __first; + ++__first; + + if (__pred(__first)) + return __first; + ++__first; + + if (__pred(__first)) + return __first; + ++__first; + + if (__pred(__first)) + return __first; + ++__first; + } + + switch (__last - __first) + { + case 3: + if (__pred(__first)) + return __first; + ++__first; + case 2: + if (__pred(__first)) + return __first; + ++__first; + case 1: + if (__pred(__first)) + return __first; + ++__first; + case 0: + default: + return __last; + } + } + + template + inline _Iterator + __find_if(_Iterator __first, _Iterator __last, _Predicate __pred) + { + return __find_if(__first, __last, __pred, + std::__iterator_category(__first)); + } + + /// Provided for stable_partition to use. + template + inline _InputIterator + __find_if_not(_InputIterator __first, _InputIterator __last, + _Predicate __pred) + { + return std::__find_if(__first, __last, + __gnu_cxx::__ops::__negate(__pred), + std::__iterator_category(__first)); + } + + /// Like find_if_not(), but uses and updates a count of the + /// remaining range length instead of comparing against an end + /// iterator. + template + _InputIterator + __find_if_not_n(_InputIterator __first, _Distance& __len, _Predicate __pred) + { + for (; __len; --__len, ++__first) + if (!__pred(__first)) + break; + return __first; + } + + // set_difference + // set_intersection + // set_symmetric_difference + // set_union + // for_each + // find + // find_if + // find_first_of + // adjacent_find + // count + // count_if + // search + + template + _ForwardIterator1 + __search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + _BinaryPredicate __predicate) + { + // Test for empty ranges + if (__first1 == __last1 || __first2 == __last2) + return __first1; + + // Test for a pattern of length 1. + _ForwardIterator2 __p1(__first2); + if (++__p1 == __last2) + return std::__find_if(__first1, __last1, + __gnu_cxx::__ops::__iter_comp_iter(__predicate, __first2)); + + // General case. + _ForwardIterator2 __p; + _ForwardIterator1 __current = __first1; + + for (;;) + { + __first1 = + std::__find_if(__first1, __last1, + __gnu_cxx::__ops::__iter_comp_iter(__predicate, __first2)); + + if (__first1 == __last1) + return __last1; + + __p = __p1; + __current = __first1; + if (++__current == __last1) + return __last1; + + while (__predicate(__current, __p)) + { + if (++__p == __last2) + return __first1; + if (++__current == __last1) + return __last1; + } + ++__first1; + } + return __first1; + } + + // search_n + + /** + * This is an helper function for search_n overloaded for forward iterators. + */ + template + _ForwardIterator + __search_n_aux(_ForwardIterator __first, _ForwardIterator __last, + _Integer __count, _UnaryPredicate __unary_pred, + std::forward_iterator_tag) + { + __first = std::__find_if(__first, __last, __unary_pred); + while (__first != __last) + { + typename iterator_traits<_ForwardIterator>::difference_type + __n = __count; + _ForwardIterator __i = __first; + ++__i; + while (__i != __last && __n != 1 && __unary_pred(__i)) + { + ++__i; + --__n; + } + if (__n == 1) + return __first; + if (__i == __last) + return __last; + __first = std::__find_if(++__i, __last, __unary_pred); + } + return __last; + } + + /** + * This is an helper function for search_n overloaded for random access + * iterators. + */ + template + _RandomAccessIter + __search_n_aux(_RandomAccessIter __first, _RandomAccessIter __last, + _Integer __count, _UnaryPredicate __unary_pred, + std::random_access_iterator_tag) + { + typedef typename std::iterator_traits<_RandomAccessIter>::difference_type + _DistanceType; + + _DistanceType __tailSize = __last - __first; + _DistanceType __remainder = __count; + + while (__remainder <= __tailSize) // the main loop... + { + __first += __remainder; + __tailSize -= __remainder; + // __first here is always pointing to one past the last element of + // next possible match. + _RandomAccessIter __backTrack = __first; + while (__unary_pred(--__backTrack)) + { + if (--__remainder == 0) + return (__first - __count); // Success + } + __remainder = __count + 1 - (__first - __backTrack); + } + return __last; // Failure + } + + template + _ForwardIterator + __search_n(_ForwardIterator __first, _ForwardIterator __last, + _Integer __count, + _UnaryPredicate __unary_pred) + { + if (__count <= 0) + return __first; + + if (__count == 1) + return std::__find_if(__first, __last, __unary_pred); + + return std::__search_n_aux(__first, __last, __count, __unary_pred, + std::__iterator_category(__first)); + } + + // find_end for forward iterators. + template + _ForwardIterator1 + __find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + forward_iterator_tag, forward_iterator_tag, + _BinaryPredicate __comp) + { + if (__first2 == __last2) + return __last1; + + _ForwardIterator1 __result = __last1; + while (1) + { + _ForwardIterator1 __new_result + = std::__search(__first1, __last1, __first2, __last2, __comp); + if (__new_result == __last1) + return __result; + else + { + __result = __new_result; + __first1 = __new_result; + ++__first1; + } + } + } + + // find_end for bidirectional iterators (much faster). + template + _BidirectionalIterator1 + __find_end(_BidirectionalIterator1 __first1, + _BidirectionalIterator1 __last1, + _BidirectionalIterator2 __first2, + _BidirectionalIterator2 __last2, + bidirectional_iterator_tag, bidirectional_iterator_tag, + _BinaryPredicate __comp) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator1>) + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator2>) + + typedef reverse_iterator<_BidirectionalIterator1> _RevIterator1; + typedef reverse_iterator<_BidirectionalIterator2> _RevIterator2; + + _RevIterator1 __rlast1(__first1); + _RevIterator2 __rlast2(__first2); + _RevIterator1 __rresult = std::__search(_RevIterator1(__last1), __rlast1, + _RevIterator2(__last2), __rlast2, + __comp); + + if (__rresult == __rlast1) + return __last1; + else + { + _BidirectionalIterator1 __result = __rresult.base(); + std::advance(__result, -std::distance(__first2, __last2)); + return __result; + } + } + + /** + * @brief Find last matching subsequence in a sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of range to search. + * @param __last1 End of range to search. + * @param __first2 Start of sequence to match. + * @param __last2 End of sequence to match. + * @return The last iterator @c i in the range + * @p [__first1,__last1-(__last2-__first2)) such that @c *(i+N) == + * @p *(__first2+N) for each @c N in the range @p + * [0,__last2-__first2), or @p __last1 if no such iterator exists. + * + * Searches the range @p [__first1,__last1) for a sub-sequence that + * compares equal value-by-value with the sequence given by @p + * [__first2,__last2) and returns an iterator to the __first + * element of the sub-sequence, or @p __last1 if the sub-sequence + * is not found. The sub-sequence will be the last such + * subsequence contained in [__first1,__last1). + * + * Because the sub-sequence must lie completely within the range @p + * [__first1,__last1) it must start at a position less than @p + * __last1-(__last2-__first2) where @p __last2-__first2 is the + * length of the sub-sequence. This means that the returned + * iterator @c i will be in the range @p + * [__first1,__last1-(__last2-__first2)) + */ + template + inline _ForwardIterator1 + find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__find_end(__first1, __last1, __first2, __last2, + std::__iterator_category(__first1), + std::__iterator_category(__first2), + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Find last matching subsequence in a sequence using a predicate. + * @ingroup non_mutating_algorithms + * @param __first1 Start of range to search. + * @param __last1 End of range to search. + * @param __first2 Start of sequence to match. + * @param __last2 End of sequence to match. + * @param __comp The predicate to use. + * @return The last iterator @c i in the range @p + * [__first1,__last1-(__last2-__first2)) such that @c + * predicate(*(i+N), @p (__first2+N)) is true for each @c N in the + * range @p [0,__last2-__first2), or @p __last1 if no such iterator + * exists. + * + * Searches the range @p [__first1,__last1) for a sub-sequence that + * compares equal value-by-value with the sequence given by @p + * [__first2,__last2) using comp as a predicate and returns an + * iterator to the first element of the sub-sequence, or @p __last1 + * if the sub-sequence is not found. The sub-sequence will be the + * last such subsequence contained in [__first,__last1). + * + * Because the sub-sequence must lie completely within the range @p + * [__first1,__last1) it must start at a position less than @p + * __last1-(__last2-__first2) where @p __last2-__first2 is the + * length of the sub-sequence. This means that the returned + * iterator @c i will be in the range @p + * [__first1,__last1-(__last2-__first2)) + */ + template + inline _ForwardIterator1 + find_end(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + _BinaryPredicate __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__find_end(__first1, __last1, __first2, __last2, + std::__iterator_category(__first1), + std::__iterator_category(__first2), + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + +#if __cplusplus >= 201103L + /** + * @brief Checks that a predicate is true for all the elements + * of a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return True if the check is true, false otherwise. + * + * Returns true if @p __pred is true for each element in the range + * @p [__first,__last), and false otherwise. + */ + template + inline bool + all_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) + { return __last == std::find_if_not(__first, __last, __pred); } + + /** + * @brief Checks that a predicate is false for all the elements + * of a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return True if the check is true, false otherwise. + * + * Returns true if @p __pred is false for each element in the range + * @p [__first,__last), and false otherwise. + */ + template + inline bool + none_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) + { return __last == _GLIBCXX_STD_A::find_if(__first, __last, __pred); } + + /** + * @brief Checks that a predicate is false for at least an element + * of a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return True if the check is true, false otherwise. + * + * Returns true if an element exists in the range @p + * [__first,__last) such that @p __pred is true, and false + * otherwise. + */ + template + inline bool + any_of(_InputIterator __first, _InputIterator __last, _Predicate __pred) + { return !std::none_of(__first, __last, __pred); } + + /** + * @brief Find the first element in a sequence for which a + * predicate is false. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return The first iterator @c i in the range @p [__first,__last) + * such that @p __pred(*i) is false, or @p __last if no such iterator exists. + */ + template + inline _InputIterator + find_if_not(_InputIterator __first, _InputIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + return std::__find_if_not(__first, __last, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + + /** + * @brief Checks whether the sequence is partitioned. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return True if the range @p [__first,__last) is partioned by @p __pred, + * i.e. if all elements that satisfy @p __pred appear before those that + * do not. + */ + template + inline bool + is_partitioned(_InputIterator __first, _InputIterator __last, + _Predicate __pred) + { + __first = std::find_if_not(__first, __last, __pred); + if (__first == __last) + return true; + ++__first; + return std::none_of(__first, __last, __pred); + } + + /** + * @brief Find the partition point of a partitioned range. + * @ingroup mutating_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __pred A predicate. + * @return An iterator @p mid such that @p all_of(__first, mid, __pred) + * and @p none_of(mid, __last, __pred) are both true. + */ + template + _ForwardIterator + partition_point(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_ForwardIterator>::value_type>) + + // A specific debug-mode test will be necessary... + __glibcxx_requires_valid_range(__first, __last); + + typedef typename iterator_traits<_ForwardIterator>::difference_type + _DistanceType; + + _DistanceType __len = std::distance(__first, __last); + _DistanceType __half; + _ForwardIterator __middle; + + while (__len > 0) + { + __half = __len >> 1; + __middle = __first; + std::advance(__middle, __half); + if (__pred(*__middle)) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else + __len = __half; + } + return __first; + } +#endif + + template + _OutputIterator + __remove_copy_if(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Predicate __pred) + { + for (; __first != __last; ++__first) + if (!__pred(__first)) + { + *__result = *__first; + ++__result; + } + return __result; + } + + /** + * @brief Copy a sequence, removing elements of a given value. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __value The value to be removed. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [__first,__last) not equal + * to @p __value to the range beginning at @p __result. + * remove_copy() is stable, so the relative order of elements that + * are copied is unchanged. + */ + template + inline _OutputIterator + remove_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, const _Tp& __value) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__remove_copy_if(__first, __last, __result, + __gnu_cxx::__ops::__iter_equals_val(__value)); + } + + /** + * @brief Copy a sequence, removing elements for which a predicate is true. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __pred A predicate. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [__first,__last) for which + * @p __pred returns false to the range beginning at @p __result. + * + * remove_copy_if() is stable, so the relative order of elements that are + * copied is unchanged. + */ + template + inline _OutputIterator + remove_copy_if(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__remove_copy_if(__first, __last, __result, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + +#if __cplusplus >= 201103L + /** + * @brief Copy the elements of a sequence for which a predicate is true. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __pred A predicate. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [__first,__last) for which + * @p __pred returns true to the range beginning at @p __result. + * + * copy_if() is stable, so the relative order of elements that are + * copied is unchanged. + */ + template + _OutputIterator + copy_if(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + if (__pred(*__first)) + { + *__result = *__first; + ++__result; + } + return __result; + } + + template + _OutputIterator + __copy_n(_InputIterator __first, _Size __n, + _OutputIterator __result, input_iterator_tag) + { + if (__n > 0) + { + while (true) + { + *__result = *__first; + ++__result; + if (--__n > 0) + ++__first; + else + break; + } + } + return __result; + } + + template + inline _OutputIterator + __copy_n(_RandomAccessIterator __first, _Size __n, + _OutputIterator __result, random_access_iterator_tag) + { return std::copy(__first, __first + __n, __result); } + + /** + * @brief Copies the range [first,first+n) into [result,result+n). + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __n The number of elements to copy. + * @param __result An output iterator. + * @return result+n. + * + * This inline function will boil down to a call to @c memmove whenever + * possible. Failing that, if random access iterators are passed, then the + * loop count will be known (and therefore a candidate for compiler + * optimizations such as unrolling). + */ + template + inline _OutputIterator + copy_n(_InputIterator __first, _Size __n, _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + + return std::__copy_n(__first, __n, __result, + std::__iterator_category(__first)); + } + + /** + * @brief Copy the elements of a sequence to separate output sequences + * depending on the truth value of a predicate. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __out_true An output iterator. + * @param __out_false An output iterator. + * @param __pred A predicate. + * @return A pair designating the ends of the resulting sequences. + * + * Copies each element in the range @p [__first,__last) for which + * @p __pred returns true to the range beginning at @p out_true + * and each element for which @p __pred returns false to @p __out_false. + */ + template + pair<_OutputIterator1, _OutputIterator2> + partition_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator1 __out_true, _OutputIterator2 __out_false, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator1, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator2, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + if (__pred(*__first)) + { + *__out_true = *__first; + ++__out_true; + } + else + { + *__out_false = *__first; + ++__out_false; + } + + return pair<_OutputIterator1, _OutputIterator2>(__out_true, __out_false); + } +#endif + + template + _ForwardIterator + __remove_if(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + __first = std::__find_if(__first, __last, __pred); + if (__first == __last) + return __first; + _ForwardIterator __result = __first; + ++__first; + for (; __first != __last; ++__first) + if (!__pred(__first)) + { + *__result = _GLIBCXX_MOVE(*__first); + ++__result; + } + return __result; + } + + /** + * @brief Remove elements from a sequence. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __value The value to be removed. + * @return An iterator designating the end of the resulting sequence. + * + * All elements equal to @p __value are removed from the range + * @p [__first,__last). + * + * remove() is stable, so the relative order of elements that are + * not removed is unchanged. + * + * Elements between the end of the resulting sequence and @p __last + * are still present, but their value is unspecified. + */ + template + inline _ForwardIterator + remove(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __value) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__remove_if(__first, __last, + __gnu_cxx::__ops::__iter_equals_val(__value)); + } + + /** + * @brief Remove elements from a sequence using a predicate. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __pred A predicate. + * @return An iterator designating the end of the resulting sequence. + * + * All elements for which @p __pred returns true are removed from the range + * @p [__first,__last). + * + * remove_if() is stable, so the relative order of elements that are + * not removed is unchanged. + * + * Elements between the end of the resulting sequence and @p __last + * are still present, but their value is unspecified. + */ + template + inline _ForwardIterator + remove_if(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__remove_if(__first, __last, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + + template + _ForwardIterator + __adjacent_find(_ForwardIterator __first, _ForwardIterator __last, + _BinaryPredicate __binary_pred) + { + if (__first == __last) + return __last; + _ForwardIterator __next = __first; + while (++__next != __last) + { + if (__binary_pred(__first, __next)) + return __first; + __first = __next; + } + return __last; + } + + template + _ForwardIterator + __unique(_ForwardIterator __first, _ForwardIterator __last, + _BinaryPredicate __binary_pred) + { + // Skip the beginning, if already unique. + __first = std::__adjacent_find(__first, __last, __binary_pred); + if (__first == __last) + return __last; + + // Do the real copy work. + _ForwardIterator __dest = __first; + ++__first; + while (++__first != __last) + if (!__binary_pred(__dest, __first)) + *++__dest = _GLIBCXX_MOVE(*__first); + return ++__dest; + } + + /** + * @brief Remove consecutive duplicate values from a sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @return An iterator designating the end of the resulting sequence. + * + * Removes all but the first element from each group of consecutive + * values that compare equal. + * unique() is stable, so the relative order of elements that are + * not removed is unchanged. + * Elements between the end of the resulting sequence and @p __last + * are still present, but their value is unspecified. + */ + template + inline _ForwardIterator + unique(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_EqualityComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__unique(__first, __last, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Remove consecutive values from a sequence using a predicate. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __binary_pred A binary predicate. + * @return An iterator designating the end of the resulting sequence. + * + * Removes all but the first element from each group of consecutive + * values for which @p __binary_pred returns true. + * unique() is stable, so the relative order of elements that are + * not removed is unchanged. + * Elements between the end of the resulting sequence and @p __last + * are still present, but their value is unspecified. + */ + template + inline _ForwardIterator + unique(_ForwardIterator __first, _ForwardIterator __last, + _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__unique(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); + } + + /** + * This is an uglified + * unique_copy(_InputIterator, _InputIterator, _OutputIterator, + * _BinaryPredicate) + * overloaded for forward iterators and output iterator as result. + */ + template + _OutputIterator + __unique_copy(_ForwardIterator __first, _ForwardIterator __last, + _OutputIterator __result, _BinaryPredicate __binary_pred, + forward_iterator_tag, output_iterator_tag) + { + // concept requirements -- iterators already checked + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + + _ForwardIterator __next = __first; + *__result = *__first; + while (++__next != __last) + if (!__binary_pred(__first, __next)) + { + __first = __next; + *++__result = *__first; + } + return ++__result; + } + + /** + * This is an uglified + * unique_copy(_InputIterator, _InputIterator, _OutputIterator, + * _BinaryPredicate) + * overloaded for input iterators and output iterator as result. + */ + template + _OutputIterator + __unique_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryPredicate __binary_pred, + input_iterator_tag, output_iterator_tag) + { + // concept requirements -- iterators already checked + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_InputIterator>::value_type, + typename iterator_traits<_InputIterator>::value_type>) + + typename iterator_traits<_InputIterator>::value_type __value = *__first; + __decltype(__gnu_cxx::__ops::__iter_comp_val(__binary_pred)) + __rebound_pred + = __gnu_cxx::__ops::__iter_comp_val(__binary_pred); + *__result = __value; + while (++__first != __last) + if (!__rebound_pred(__first, __value)) + { + __value = *__first; + *++__result = __value; + } + return ++__result; + } + + /** + * This is an uglified + * unique_copy(_InputIterator, _InputIterator, _OutputIterator, + * _BinaryPredicate) + * overloaded for input iterators and forward iterator as result. + */ + template + _ForwardIterator + __unique_copy(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, _BinaryPredicate __binary_pred, + input_iterator_tag, forward_iterator_tag) + { + // concept requirements -- iterators already checked + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_InputIterator>::value_type>) + *__result = *__first; + while (++__first != __last) + if (!__binary_pred(__result, __first)) + *++__result = *__first; + return ++__result; + } + + /** + * This is an uglified reverse(_BidirectionalIterator, + * _BidirectionalIterator) + * overloaded for bidirectional iterators. + */ + template + void + __reverse(_BidirectionalIterator __first, _BidirectionalIterator __last, + bidirectional_iterator_tag) + { + while (true) + if (__first == __last || __first == --__last) + return; + else + { + std::iter_swap(__first, __last); + ++__first; + } + } + + /** + * This is an uglified reverse(_BidirectionalIterator, + * _BidirectionalIterator) + * overloaded for random access iterators. + */ + template + void + __reverse(_RandomAccessIterator __first, _RandomAccessIterator __last, + random_access_iterator_tag) + { + if (__first == __last) + return; + --__last; + while (__first < __last) + { + std::iter_swap(__first, __last); + ++__first; + --__last; + } + } + + /** + * @brief Reverse a sequence. + * @ingroup mutating_algorithms + * @param __first A bidirectional iterator. + * @param __last A bidirectional iterator. + * @return reverse() returns no value. + * + * Reverses the order of the elements in the range @p [__first,__last), + * so that the first element becomes the last etc. + * For every @c i such that @p 0<=i<=(__last-__first)/2), @p reverse() + * swaps @p *(__first+i) and @p *(__last-(i+1)) + */ + template + inline void + reverse(_BidirectionalIterator __first, _BidirectionalIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_requires_valid_range(__first, __last); + std::__reverse(__first, __last, std::__iterator_category(__first)); + } + + /** + * @brief Copy a sequence, reversing its elements. + * @ingroup mutating_algorithms + * @param __first A bidirectional iterator. + * @param __last A bidirectional iterator. + * @param __result An output iterator. + * @return An iterator designating the end of the resulting sequence. + * + * Copies the elements in the range @p [__first,__last) to the + * range @p [__result,__result+(__last-__first)) such that the + * order of the elements is reversed. For every @c i such that @p + * 0<=i<=(__last-__first), @p reverse_copy() performs the + * assignment @p *(__result+(__last-__first)-1-i) = *(__first+i). + * The ranges @p [__first,__last) and @p + * [__result,__result+(__last-__first)) must not overlap. + */ + template + _OutputIterator + reverse_copy(_BidirectionalIterator __first, _BidirectionalIterator __last, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + while (__first != __last) + { + --__last; + *__result = *__last; + ++__result; + } + return __result; + } + + /** + * This is a helper function for the rotate algorithm specialized on RAIs. + * It returns the greatest common divisor of two integer values. + */ + template + _EuclideanRingElement + __gcd(_EuclideanRingElement __m, _EuclideanRingElement __n) + { + while (__n != 0) + { + _EuclideanRingElement __t = __m % __n; + __m = __n; + __n = __t; + } + return __m; + } + + inline namespace _V2 + { + + /// This is a helper function for the rotate algorithm. + template + _ForwardIterator + __rotate(_ForwardIterator __first, + _ForwardIterator __middle, + _ForwardIterator __last, + forward_iterator_tag) + { + if (__first == __middle) + return __last; + else if (__last == __middle) + return __first; + + _ForwardIterator __first2 = __middle; + do + { + std::iter_swap(__first, __first2); + ++__first; + ++__first2; + if (__first == __middle) + __middle = __first2; + } + while (__first2 != __last); + + _ForwardIterator __ret = __first; + + __first2 = __middle; + + while (__first2 != __last) + { + std::iter_swap(__first, __first2); + ++__first; + ++__first2; + if (__first == __middle) + __middle = __first2; + else if (__first2 == __last) + __first2 = __middle; + } + return __ret; + } + + /// This is a helper function for the rotate algorithm. + template + _BidirectionalIterator + __rotate(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + bidirectional_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept< + _BidirectionalIterator>) + + if (__first == __middle) + return __last; + else if (__last == __middle) + return __first; + + std::__reverse(__first, __middle, bidirectional_iterator_tag()); + std::__reverse(__middle, __last, bidirectional_iterator_tag()); + + while (__first != __middle && __middle != __last) + { + std::iter_swap(__first, --__last); + ++__first; + } + + if (__first == __middle) + { + std::__reverse(__middle, __last, bidirectional_iterator_tag()); + return __last; + } + else + { + std::__reverse(__first, __middle, bidirectional_iterator_tag()); + return __first; + } + } + + /// This is a helper function for the rotate algorithm. + template + _RandomAccessIterator + __rotate(_RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last, + random_access_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + + if (__first == __middle) + return __last; + else if (__last == __middle) + return __first; + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Distance; + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + + _Distance __n = __last - __first; + _Distance __k = __middle - __first; + + if (__k == __n - __k) + { + std::swap_ranges(__first, __middle, __middle); + return __middle; + } + + _RandomAccessIterator __p = __first; + _RandomAccessIterator __ret = __first + (__last - __middle); + + for (;;) + { + if (__k < __n - __k) + { + if (__is_pod(_ValueType) && __k == 1) + { + _ValueType __t = _GLIBCXX_MOVE(*__p); + _GLIBCXX_MOVE3(__p + 1, __p + __n, __p); + *(__p + __n - 1) = _GLIBCXX_MOVE(__t); + return __ret; + } + _RandomAccessIterator __q = __p + __k; + for (_Distance __i = 0; __i < __n - __k; ++ __i) + { + std::iter_swap(__p, __q); + ++__p; + ++__q; + } + __n %= __k; + if (__n == 0) + return __ret; + std::swap(__n, __k); + __k = __n - __k; + } + else + { + __k = __n - __k; + if (__is_pod(_ValueType) && __k == 1) + { + _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1)); + _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - 1, __p + __n); + *__p = _GLIBCXX_MOVE(__t); + return __ret; + } + _RandomAccessIterator __q = __p + __n; + __p = __q - __k; + for (_Distance __i = 0; __i < __n - __k; ++ __i) + { + --__p; + --__q; + std::iter_swap(__p, __q); + } + __n %= __k; + if (__n == 0) + return __ret; + std::swap(__n, __k); + } + } + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 488. rotate throws away useful information + /** + * @brief Rotate the elements of a sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __middle A forward iterator. + * @param __last A forward iterator. + * @return first + (last - middle). + * + * Rotates the elements of the range @p [__first,__last) by + * @p (__middle - __first) positions so that the element at @p __middle + * is moved to @p __first, the element at @p __middle+1 is moved to + * @p __first+1 and so on for each element in the range + * @p [__first,__last). + * + * This effectively swaps the ranges @p [__first,__middle) and + * @p [__middle,__last). + * + * Performs + * @p *(__first+(n+(__last-__middle))%(__last-__first))=*(__first+n) + * for each @p n in the range @p [0,__last-__first). + */ + template + inline _ForwardIterator + rotate(_ForwardIterator __first, _ForwardIterator __middle, + _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_requires_valid_range(__first, __middle); + __glibcxx_requires_valid_range(__middle, __last); + + return std::__rotate(__first, __middle, __last, + std::__iterator_category(__first)); + } + + } // namespace _V2 + + /** + * @brief Copy a sequence, rotating its elements. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __middle A forward iterator. + * @param __last A forward iterator. + * @param __result An output iterator. + * @return An iterator designating the end of the resulting sequence. + * + * Copies the elements of the range @p [__first,__last) to the + * range beginning at @result, rotating the copied elements by + * @p (__middle-__first) positions so that the element at @p __middle + * is moved to @p __result, the element at @p __middle+1 is moved + * to @p __result+1 and so on for each element in the range @p + * [__first,__last). + * + * Performs + * @p *(__result+(n+(__last-__middle))%(__last-__first))=*(__first+n) + * for each @p n in the range @p [0,__last-__first). + */ + template + inline _OutputIterator + rotate_copy(_ForwardIterator __first, _ForwardIterator __middle, + _ForwardIterator __last, _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __middle); + __glibcxx_requires_valid_range(__middle, __last); + + return std::copy(__first, __middle, + std::copy(__middle, __last, __result)); + } + + /// This is a helper function... + template + _ForwardIterator + __partition(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred, forward_iterator_tag) + { + if (__first == __last) + return __first; + + while (__pred(*__first)) + if (++__first == __last) + return __first; + + _ForwardIterator __next = __first; + + while (++__next != __last) + if (__pred(*__next)) + { + std::iter_swap(__first, __next); + ++__first; + } + + return __first; + } + + /// This is a helper function... + template + _BidirectionalIterator + __partition(_BidirectionalIterator __first, _BidirectionalIterator __last, + _Predicate __pred, bidirectional_iterator_tag) + { + while (true) + { + while (true) + if (__first == __last) + return __first; + else if (__pred(*__first)) + ++__first; + else + break; + --__last; + while (true) + if (__first == __last) + return __first; + else if (!bool(__pred(*__last))) + --__last; + else + break; + std::iter_swap(__first, __last); + ++__first; + } + } + + // partition + + /// This is a helper function... + /// Requires __first != __last and !__pred(__first) + /// and __len == distance(__first, __last). + /// + /// !__pred(__first) allows us to guarantee that we don't + /// move-assign an element onto itself. + template + _ForwardIterator + __stable_partition_adaptive(_ForwardIterator __first, + _ForwardIterator __last, + _Predicate __pred, _Distance __len, + _Pointer __buffer, + _Distance __buffer_size) + { + if (__len == 1) + return __first; + + if (__len <= __buffer_size) + { + _ForwardIterator __result1 = __first; + _Pointer __result2 = __buffer; + + // The precondition guarantees that !__pred(__first), so + // move that element to the buffer before starting the loop. + // This ensures that we only call __pred once per element. + *__result2 = _GLIBCXX_MOVE(*__first); + ++__result2; + ++__first; + for (; __first != __last; ++__first) + if (__pred(__first)) + { + *__result1 = _GLIBCXX_MOVE(*__first); + ++__result1; + } + else + { + *__result2 = _GLIBCXX_MOVE(*__first); + ++__result2; + } + + _GLIBCXX_MOVE3(__buffer, __result2, __result1); + return __result1; + } + + _ForwardIterator __middle = __first; + std::advance(__middle, __len / 2); + _ForwardIterator __left_split = + std::__stable_partition_adaptive(__first, __middle, __pred, + __len / 2, __buffer, + __buffer_size); + + // Advance past true-predicate values to satisfy this + // function's preconditions. + _Distance __right_len = __len - __len / 2; + _ForwardIterator __right_split = + std::__find_if_not_n(__middle, __right_len, __pred); + + if (__right_len) + __right_split = + std::__stable_partition_adaptive(__right_split, __last, __pred, + __right_len, + __buffer, __buffer_size); + + std::rotate(__left_split, __middle, __right_split); + std::advance(__left_split, std::distance(__middle, __right_split)); + return __left_split; + } + + template + _ForwardIterator + __stable_partition(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + __first = std::__find_if_not(__first, __last, __pred); + + if (__first == __last) + return __first; + + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + typedef typename iterator_traits<_ForwardIterator>::difference_type + _DistanceType; + + _Temporary_buffer<_ForwardIterator, _ValueType> __buf(__first, __last); + return + std::__stable_partition_adaptive(__first, __last, __pred, + _DistanceType(__buf.requested_size()), + __buf.begin(), + _DistanceType(__buf.size())); + } + + /** + * @brief Move elements for which a predicate is true to the beginning + * of a sequence, preserving relative ordering. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __pred A predicate functor. + * @return An iterator @p middle such that @p __pred(i) is true for each + * iterator @p i in the range @p [first,middle) and false for each @p i + * in the range @p [middle,last). + * + * Performs the same function as @p partition() with the additional + * guarantee that the relative ordering of elements in each group is + * preserved, so any two elements @p x and @p y in the range + * @p [__first,__last) such that @p __pred(x)==__pred(y) will have the same + * relative ordering after calling @p stable_partition(). + */ + template + inline _ForwardIterator + stable_partition(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__stable_partition(__first, __last, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + + /// This is a helper function for the sort routines. + template + void + __heap_select(_RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last, _Compare __comp) + { + std::__make_heap(__first, __middle, __comp); + for (_RandomAccessIterator __i = __middle; __i < __last; ++__i) + if (__comp(__i, __first)) + std::__pop_heap(__first, __middle, __i, __comp); + } + + // partial_sort + + template + _RandomAccessIterator + __partial_sort_copy(_InputIterator __first, _InputIterator __last, + _RandomAccessIterator __result_first, + _RandomAccessIterator __result_last, + _Compare __comp) + { + typedef typename iterator_traits<_InputIterator>::value_type + _InputValueType; + typedef iterator_traits<_RandomAccessIterator> _RItTraits; + typedef typename _RItTraits::difference_type _DistanceType; + + if (__result_first == __result_last) + return __result_last; + _RandomAccessIterator __result_real_last = __result_first; + while (__first != __last && __result_real_last != __result_last) + { + *__result_real_last = *__first; + ++__result_real_last; + ++__first; + } + + std::__make_heap(__result_first, __result_real_last, __comp); + while (__first != __last) + { + if (__comp(__first, __result_first)) + std::__adjust_heap(__result_first, _DistanceType(0), + _DistanceType(__result_real_last + - __result_first), + _InputValueType(*__first), __comp); + ++__first; + } + std::__sort_heap(__result_first, __result_real_last, __comp); + return __result_real_last; + } + + /** + * @brief Copy the smallest elements of a sequence. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __result_first A random-access iterator. + * @param __result_last Another random-access iterator. + * @return An iterator indicating the end of the resulting sequence. + * + * Copies and sorts the smallest N values from the range @p [__first,__last) + * to the range beginning at @p __result_first, where the number of + * elements to be copied, @p N, is the smaller of @p (__last-__first) and + * @p (__result_last-__result_first). + * After the sort if @e i and @e j are iterators in the range + * @p [__result_first,__result_first+N) such that i precedes j then + * *j<*i is false. + * The value returned is @p __result_first+N. + */ + template + inline _RandomAccessIterator + partial_sort_copy(_InputIterator __first, _InputIterator __last, + _RandomAccessIterator __result_first, + _RandomAccessIterator __result_last) + { +#ifdef _GLIBCXX_CONCEPT_CHECKS + typedef typename iterator_traits<_InputIterator>::value_type + _InputValueType; + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _OutputValueType; +#endif + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_ConvertibleConcept<_InputValueType, + _OutputValueType>) + __glibcxx_function_requires(_LessThanOpConcept<_InputValueType, + _OutputValueType>) + __glibcxx_function_requires(_LessThanComparableConcept<_OutputValueType>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + __glibcxx_requires_valid_range(__result_first, __result_last); + + return std::__partial_sort_copy(__first, __last, + __result_first, __result_last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Copy the smallest elements of a sequence using a predicate for + * comparison. + * @ingroup sorting_algorithms + * @param __first An input iterator. + * @param __last Another input iterator. + * @param __result_first A random-access iterator. + * @param __result_last Another random-access iterator. + * @param __comp A comparison functor. + * @return An iterator indicating the end of the resulting sequence. + * + * Copies and sorts the smallest N values from the range @p [__first,__last) + * to the range beginning at @p result_first, where the number of + * elements to be copied, @p N, is the smaller of @p (__last-__first) and + * @p (__result_last-__result_first). + * After the sort if @e i and @e j are iterators in the range + * @p [__result_first,__result_first+N) such that i precedes j then + * @p __comp(*j,*i) is false. + * The value returned is @p __result_first+N. + */ + template + inline _RandomAccessIterator + partial_sort_copy(_InputIterator __first, _InputIterator __last, + _RandomAccessIterator __result_first, + _RandomAccessIterator __result_last, + _Compare __comp) + { +#ifdef _GLIBCXX_CONCEPT_CHECKS + typedef typename iterator_traits<_InputIterator>::value_type + _InputValueType; + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _OutputValueType; +#endif + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_ConvertibleConcept<_InputValueType, + _OutputValueType>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + _InputValueType, _OutputValueType>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + _OutputValueType, _OutputValueType>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + __glibcxx_requires_valid_range(__result_first, __result_last); + + return std::__partial_sort_copy(__first, __last, + __result_first, __result_last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + /// This is a helper function for the sort routine. + template + void + __unguarded_linear_insert(_RandomAccessIterator __last, + _Compare __comp) + { + typename iterator_traits<_RandomAccessIterator>::value_type + __val = _GLIBCXX_MOVE(*__last); + _RandomAccessIterator __next = __last; + --__next; + while (__comp(__val, __next)) + { + *__last = _GLIBCXX_MOVE(*__next); + __last = __next; + --__next; + } + *__last = _GLIBCXX_MOVE(__val); + } + + /// This is a helper function for the sort routine. + template + void + __insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + if (__first == __last) return; + + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + { + if (__comp(__i, __first)) + { + typename iterator_traits<_RandomAccessIterator>::value_type + __val = _GLIBCXX_MOVE(*__i); + _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1); + *__first = _GLIBCXX_MOVE(__val); + } + else + std::__unguarded_linear_insert(__i, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + } + + /// This is a helper function for the sort routine. + template + inline void + __unguarded_insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + for (_RandomAccessIterator __i = __first; __i != __last; ++__i) + std::__unguarded_linear_insert(__i, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + + /** + * @doctodo + * This controls some aspect of the sort routines. + */ + enum { _S_threshold = 16 }; + + /// This is a helper function for the sort routine. + template + void + __final_insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + if (__last - __first > int(_S_threshold)) + { + std::__insertion_sort(__first, __first + int(_S_threshold), __comp); + std::__unguarded_insertion_sort(__first + int(_S_threshold), __last, + __comp); + } + else + std::__insertion_sort(__first, __last, __comp); + } + + /// This is a helper function... + template + _RandomAccessIterator + __unguarded_partition(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _RandomAccessIterator __pivot, _Compare __comp) + { + while (true) + { + while (__comp(__first, __pivot)) + ++__first; + --__last; + while (__comp(__pivot, __last)) + --__last; + if (!(__first < __last)) + return __first; + std::iter_swap(__first, __last); + ++__first; + } + } + + /// This is a helper function... + template + inline _RandomAccessIterator + __unguarded_partition_pivot(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + _RandomAccessIterator __mid = __first + (__last - __first) / 2; + std::__move_median_to_first(__first, __first + 1, __mid, __last - 1, + __comp); + return std::__unguarded_partition(__first + 1, __last, __first, __comp); + } + + template + inline void + __partial_sort(_RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last, + _Compare __comp) + { + std::__heap_select(__first, __middle, __last, __comp); + std::__sort_heap(__first, __middle, __comp); + } + + /// This is a helper function for the sort routine. + template + void + __introsort_loop(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Size __depth_limit, _Compare __comp) + { + while (__last - __first > int(_S_threshold)) + { + if (__depth_limit == 0) + { + std::__partial_sort(__first, __last, __last, __comp); + return; + } + --__depth_limit; + _RandomAccessIterator __cut = + std::__unguarded_partition_pivot(__first, __last, __comp); + std::__introsort_loop(__cut, __last, __depth_limit, __comp); + __last = __cut; + } + } + + // sort + + template + inline void + __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + if (__first != __last) + { + std::__introsort_loop(__first, __last, + std::__lg(__last - __first) * 2, + __comp); + std::__final_insertion_sort(__first, __last, __comp); + } + } + + template + void + __introselect(_RandomAccessIterator __first, _RandomAccessIterator __nth, + _RandomAccessIterator __last, _Size __depth_limit, + _Compare __comp) + { + while (__last - __first > 3) + { + if (__depth_limit == 0) + { + std::__heap_select(__first, __nth + 1, __last, __comp); + // Place the nth largest element in its final position. + std::iter_swap(__first, __nth); + return; + } + --__depth_limit; + _RandomAccessIterator __cut = + std::__unguarded_partition_pivot(__first, __last, __comp); + if (__cut <= __nth) + __first = __cut; + else + __last = __cut; + } + std::__insertion_sort(__first, __last, __comp); + } + + // nth_element + + // lower_bound moved to stl_algobase.h + + /** + * @brief Finds the first position in which @p __val could be inserted + * without changing the ordering. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @param __comp A functor to use for comparisons. + * @return An iterator pointing to the first element not less + * than @p __val, or end() if every element is less + * than @p __val. + * @ingroup binary_search_algorithms + * + * The comparison function should have the same effects on ordering as + * the function used for the initial sort. + */ + template + inline _ForwardIterator + lower_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_requires_partitioned_lower_pred(__first, __last, + __val, __comp); + + return std::__lower_bound(__first, __last, __val, + __gnu_cxx::__ops::__iter_comp_val(__comp)); + } + + template + _ForwardIterator + __upper_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + typedef typename iterator_traits<_ForwardIterator>::difference_type + _DistanceType; + + _DistanceType __len = std::distance(__first, __last); + + while (__len > 0) + { + _DistanceType __half = __len >> 1; + _ForwardIterator __middle = __first; + std::advance(__middle, __half); + if (__comp(__val, __middle)) + __len = __half; + else + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + } + return __first; + } + + /** + * @brief Finds the last position in which @p __val could be inserted + * without changing the ordering. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @return An iterator pointing to the first element greater than @p __val, + * or end() if no elements are greater than @p __val. + * @ingroup binary_search_algorithms + */ + template + inline _ForwardIterator + upper_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanOpConcept< + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_upper(__first, __last, __val); + + return std::__upper_bound(__first, __last, __val, + __gnu_cxx::__ops::__val_less_iter()); + } + + /** + * @brief Finds the last position in which @p __val could be inserted + * without changing the ordering. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @param __comp A functor to use for comparisons. + * @return An iterator pointing to the first element greater than @p __val, + * or end() if no elements are greater than @p __val. + * @ingroup binary_search_algorithms + * + * The comparison function should have the same effects on ordering as + * the function used for the initial sort. + */ + template + inline _ForwardIterator + upper_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_upper_pred(__first, __last, + __val, __comp); + + return std::__upper_bound(__first, __last, __val, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + + template + pair<_ForwardIterator, _ForwardIterator> + __equal_range(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, + _CompareItTp __comp_it_val, _CompareTpIt __comp_val_it) + { + typedef typename iterator_traits<_ForwardIterator>::difference_type + _DistanceType; + + _DistanceType __len = std::distance(__first, __last); + + while (__len > 0) + { + _DistanceType __half = __len >> 1; + _ForwardIterator __middle = __first; + std::advance(__middle, __half); + if (__comp_it_val(__middle, __val)) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else if (__comp_val_it(__val, __middle)) + __len = __half; + else + { + _ForwardIterator __left + = std::__lower_bound(__first, __middle, __val, __comp_it_val); + std::advance(__first, __len); + _ForwardIterator __right + = std::__upper_bound(++__middle, __first, __val, __comp_val_it); + return pair<_ForwardIterator, _ForwardIterator>(__left, __right); + } + } + return pair<_ForwardIterator, _ForwardIterator>(__first, __first); + } + + /** + * @brief Finds the largest subrange in which @p __val could be inserted + * at any place in it without changing the ordering. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @return An pair of iterators defining the subrange. + * @ingroup binary_search_algorithms + * + * This is equivalent to + * @code + * std::make_pair(lower_bound(__first, __last, __val), + * upper_bound(__first, __last, __val)) + * @endcode + * but does not actually call those functions. + */ + template + inline pair<_ForwardIterator, _ForwardIterator> + equal_range(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_function_requires(_LessThanOpConcept< + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_lower(__first, __last, __val); + __glibcxx_requires_partitioned_upper(__first, __last, __val); + + return std::__equal_range(__first, __last, __val, + __gnu_cxx::__ops::__iter_less_val(), + __gnu_cxx::__ops::__val_less_iter()); + } + + /** + * @brief Finds the largest subrange in which @p __val could be inserted + * at any place in it without changing the ordering. + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @param __comp A functor to use for comparisons. + * @return An pair of iterators defining the subrange. + * @ingroup binary_search_algorithms + * + * This is equivalent to + * @code + * std::make_pair(lower_bound(__first, __last, __val, __comp), + * upper_bound(__first, __last, __val, __comp)) + * @endcode + * but does not actually call those functions. + */ + template + inline pair<_ForwardIterator, _ForwardIterator> + equal_range(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_lower_pred(__first, __last, + __val, __comp); + __glibcxx_requires_partitioned_upper_pred(__first, __last, + __val, __comp); + + return std::__equal_range(__first, __last, __val, + __gnu_cxx::__ops::__iter_comp_val(__comp), + __gnu_cxx::__ops::__val_comp_iter(__comp)); + } + + /** + * @brief Determines whether an element exists in a range. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @return True if @p __val (or its equivalent) is in [@p + * __first,@p __last ]. + * + * Note that this does not actually return an iterator to @p __val. For + * that, use std::find or a container's specialized find member functions. + */ + template + bool + binary_search(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanOpConcept< + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_lower(__first, __last, __val); + __glibcxx_requires_partitioned_upper(__first, __last, __val); + + _ForwardIterator __i + = std::__lower_bound(__first, __last, __val, + __gnu_cxx::__ops::__iter_less_val()); + return __i != __last && !(__val < *__i); + } + + /** + * @brief Determines whether an element exists in a range. + * @ingroup binary_search_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @param __comp A functor to use for comparisons. + * @return True if @p __val (or its equivalent) is in @p [__first,__last]. + * + * Note that this does not actually return an iterator to @p __val. For + * that, use std::find or a container's specialized find member functions. + * + * The comparison function should have the same effects on ordering as + * the function used for the initial sort. + */ + template + bool + binary_search(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + _Tp, typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_partitioned_lower_pred(__first, __last, + __val, __comp); + __glibcxx_requires_partitioned_upper_pred(__first, __last, + __val, __comp); + + _ForwardIterator __i + = std::__lower_bound(__first, __last, __val, + __gnu_cxx::__ops::__iter_comp_val(__comp)); + return __i != __last && !bool(__comp(__val, *__i)); + } + + // merge + + /// This is a helper function for the __merge_adaptive routines. + template + void + __move_merge_adaptive(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (__comp(__first2, __first1)) + { + *__result = _GLIBCXX_MOVE(*__first2); + ++__first2; + } + else + { + *__result = _GLIBCXX_MOVE(*__first1); + ++__first1; + } + ++__result; + } + if (__first1 != __last1) + _GLIBCXX_MOVE3(__first1, __last1, __result); + } + + /// This is a helper function for the __merge_adaptive routines. + template + void + __move_merge_adaptive_backward(_BidirectionalIterator1 __first1, + _BidirectionalIterator1 __last1, + _BidirectionalIterator2 __first2, + _BidirectionalIterator2 __last2, + _BidirectionalIterator3 __result, + _Compare __comp) + { + if (__first1 == __last1) + { + _GLIBCXX_MOVE_BACKWARD3(__first2, __last2, __result); + return; + } + else if (__first2 == __last2) + return; + + --__last1; + --__last2; + while (true) + { + if (__comp(__last2, __last1)) + { + *--__result = _GLIBCXX_MOVE(*__last1); + if (__first1 == __last1) + { + _GLIBCXX_MOVE_BACKWARD3(__first2, ++__last2, __result); + return; + } + --__last1; + } + else + { + *--__result = _GLIBCXX_MOVE(*__last2); + if (__first2 == __last2) + return; + --__last2; + } + } + } + + /// This is a helper function for the merge routines. + template + _BidirectionalIterator1 + __rotate_adaptive(_BidirectionalIterator1 __first, + _BidirectionalIterator1 __middle, + _BidirectionalIterator1 __last, + _Distance __len1, _Distance __len2, + _BidirectionalIterator2 __buffer, + _Distance __buffer_size) + { + _BidirectionalIterator2 __buffer_end; + if (__len1 > __len2 && __len2 <= __buffer_size) + { + if (__len2) + { + __buffer_end = _GLIBCXX_MOVE3(__middle, __last, __buffer); + _GLIBCXX_MOVE_BACKWARD3(__first, __middle, __last); + return _GLIBCXX_MOVE3(__buffer, __buffer_end, __first); + } + else + return __first; + } + else if (__len1 <= __buffer_size) + { + if (__len1) + { + __buffer_end = _GLIBCXX_MOVE3(__first, __middle, __buffer); + _GLIBCXX_MOVE3(__middle, __last, __first); + return _GLIBCXX_MOVE_BACKWARD3(__buffer, __buffer_end, __last); + } + else + return __last; + } + else + { + std::rotate(__first, __middle, __last); + std::advance(__first, std::distance(__middle, __last)); + return __first; + } + } + + /// This is a helper function for the merge routines. + template + void + __merge_adaptive(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Distance __len1, _Distance __len2, + _Pointer __buffer, _Distance __buffer_size, + _Compare __comp) + { + if (__len1 <= __len2 && __len1 <= __buffer_size) + { + _Pointer __buffer_end = _GLIBCXX_MOVE3(__first, __middle, __buffer); + std::__move_merge_adaptive(__buffer, __buffer_end, __middle, __last, + __first, __comp); + } + else if (__len2 <= __buffer_size) + { + _Pointer __buffer_end = _GLIBCXX_MOVE3(__middle, __last, __buffer); + std::__move_merge_adaptive_backward(__first, __middle, __buffer, + __buffer_end, __last, __comp); + } + else + { + _BidirectionalIterator __first_cut = __first; + _BidirectionalIterator __second_cut = __middle; + _Distance __len11 = 0; + _Distance __len22 = 0; + if (__len1 > __len2) + { + __len11 = __len1 / 2; + std::advance(__first_cut, __len11); + __second_cut + = std::__lower_bound(__middle, __last, *__first_cut, + __gnu_cxx::__ops::__iter_comp_val(__comp)); + __len22 = std::distance(__middle, __second_cut); + } + else + { + __len22 = __len2 / 2; + std::advance(__second_cut, __len22); + __first_cut + = std::__upper_bound(__first, __middle, *__second_cut, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + __len11 = std::distance(__first, __first_cut); + } + + _BidirectionalIterator __new_middle + = std::__rotate_adaptive(__first_cut, __middle, __second_cut, + __len1 - __len11, __len22, __buffer, + __buffer_size); + std::__merge_adaptive(__first, __first_cut, __new_middle, __len11, + __len22, __buffer, __buffer_size, __comp); + std::__merge_adaptive(__new_middle, __second_cut, __last, + __len1 - __len11, + __len2 - __len22, __buffer, + __buffer_size, __comp); + } + } + + /// This is a helper function for the merge routines. + template + void + __merge_without_buffer(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Distance __len1, _Distance __len2, + _Compare __comp) + { + if (__len1 == 0 || __len2 == 0) + return; + + if (__len1 + __len2 == 2) + { + if (__comp(__middle, __first)) + std::iter_swap(__first, __middle); + return; + } + + _BidirectionalIterator __first_cut = __first; + _BidirectionalIterator __second_cut = __middle; + _Distance __len11 = 0; + _Distance __len22 = 0; + if (__len1 > __len2) + { + __len11 = __len1 / 2; + std::advance(__first_cut, __len11); + __second_cut + = std::__lower_bound(__middle, __last, *__first_cut, + __gnu_cxx::__ops::__iter_comp_val(__comp)); + __len22 = std::distance(__middle, __second_cut); + } + else + { + __len22 = __len2 / 2; + std::advance(__second_cut, __len22); + __first_cut + = std::__upper_bound(__first, __middle, *__second_cut, + __gnu_cxx::__ops::__val_comp_iter(__comp)); + __len11 = std::distance(__first, __first_cut); + } + + std::rotate(__first_cut, __middle, __second_cut); + _BidirectionalIterator __new_middle = __first_cut; + std::advance(__new_middle, std::distance(__middle, __second_cut)); + std::__merge_without_buffer(__first, __first_cut, __new_middle, + __len11, __len22, __comp); + std::__merge_without_buffer(__new_middle, __second_cut, __last, + __len1 - __len11, __len2 - __len22, __comp); + } + + template + void + __inplace_merge(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Compare __comp) + { + typedef typename iterator_traits<_BidirectionalIterator>::value_type + _ValueType; + typedef typename iterator_traits<_BidirectionalIterator>::difference_type + _DistanceType; + + if (__first == __middle || __middle == __last) + return; + + const _DistanceType __len1 = std::distance(__first, __middle); + const _DistanceType __len2 = std::distance(__middle, __last); + + typedef _Temporary_buffer<_BidirectionalIterator, _ValueType> _TmpBuf; + _TmpBuf __buf(__first, __last); + + if (__buf.begin() == 0) + std::__merge_without_buffer + (__first, __middle, __last, __len1, __len2, __comp); + else + std::__merge_adaptive + (__first, __middle, __last, __len1, __len2, __buf.begin(), + _DistanceType(__buf.size()), __comp); + } + + /** + * @brief Merges two sorted ranges in place. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __middle Another iterator. + * @param __last Another iterator. + * @return Nothing. + * + * Merges two sorted and consecutive ranges, [__first,__middle) and + * [__middle,__last), and puts the result in [__first,__last). The + * output will be sorted. The sort is @e stable, that is, for + * equivalent elements in the two ranges, elements from the first + * range will always come before elements from the second. + * + * If enough additional memory is available, this takes (__last-__first)-1 + * comparisons. Otherwise an NlogN algorithm is used, where N is + * distance(__first,__last). + */ + template + inline void + inplace_merge(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_sorted(__first, __middle); + __glibcxx_requires_sorted(__middle, __last); + __glibcxx_requires_irreflexive(__first, __last); + + std::__inplace_merge(__first, __middle, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Merges two sorted ranges in place. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __middle Another iterator. + * @param __last Another iterator. + * @param __comp A functor to use for comparisons. + * @return Nothing. + * + * Merges two sorted and consecutive ranges, [__first,__middle) and + * [middle,last), and puts the result in [__first,__last). The output will + * be sorted. The sort is @e stable, that is, for equivalent + * elements in the two ranges, elements from the first range will always + * come before elements from the second. + * + * If enough additional memory is available, this takes (__last-__first)-1 + * comparisons. Otherwise an NlogN algorithm is used, where N is + * distance(__first,__last). + * + * The comparison function should have the same effects on ordering as + * the function used for the initial sort. + */ + template + inline void + inplace_merge(_BidirectionalIterator __first, + _BidirectionalIterator __middle, + _BidirectionalIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_BidirectionalIterator>::value_type, + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_sorted_pred(__first, __middle, __comp); + __glibcxx_requires_sorted_pred(__middle, __last, __comp); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + std::__inplace_merge(__first, __middle, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + + /// This is a helper function for the __merge_sort_loop routines. + template + _OutputIterator + __move_merge(_InputIterator __first1, _InputIterator __last1, + _InputIterator __first2, _InputIterator __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (__comp(__first2, __first1)) + { + *__result = _GLIBCXX_MOVE(*__first2); + ++__first2; + } + else + { + *__result = _GLIBCXX_MOVE(*__first1); + ++__first1; + } + ++__result; + } + return _GLIBCXX_MOVE3(__first2, __last2, + _GLIBCXX_MOVE3(__first1, __last1, + __result)); + } + + template + void + __merge_sort_loop(_RandomAccessIterator1 __first, + _RandomAccessIterator1 __last, + _RandomAccessIterator2 __result, _Distance __step_size, + _Compare __comp) + { + const _Distance __two_step = 2 * __step_size; + + while (__last - __first >= __two_step) + { + __result = std::__move_merge(__first, __first + __step_size, + __first + __step_size, + __first + __two_step, + __result, __comp); + __first += __two_step; + } + __step_size = std::min(_Distance(__last - __first), __step_size); + + std::__move_merge(__first, __first + __step_size, + __first + __step_size, __last, __result, __comp); + } + + template + void + __chunk_insertion_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Distance __chunk_size, _Compare __comp) + { + while (__last - __first >= __chunk_size) + { + std::__insertion_sort(__first, __first + __chunk_size, __comp); + __first += __chunk_size; + } + std::__insertion_sort(__first, __last, __comp); + } + + enum { _S_chunk_size = 7 }; + + template + void + __merge_sort_with_buffer(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Pointer __buffer, _Compare __comp) + { + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _Distance; + + const _Distance __len = __last - __first; + const _Pointer __buffer_last = __buffer + __len; + + _Distance __step_size = _S_chunk_size; + std::__chunk_insertion_sort(__first, __last, __step_size, __comp); + + while (__step_size < __len) + { + std::__merge_sort_loop(__first, __last, __buffer, + __step_size, __comp); + __step_size *= 2; + std::__merge_sort_loop(__buffer, __buffer_last, __first, + __step_size, __comp); + __step_size *= 2; + } + } + + template + void + __stable_sort_adaptive(_RandomAccessIterator __first, + _RandomAccessIterator __last, + _Pointer __buffer, _Distance __buffer_size, + _Compare __comp) + { + const _Distance __len = (__last - __first + 1) / 2; + const _RandomAccessIterator __middle = __first + __len; + if (__len > __buffer_size) + { + std::__stable_sort_adaptive(__first, __middle, __buffer, + __buffer_size, __comp); + std::__stable_sort_adaptive(__middle, __last, __buffer, + __buffer_size, __comp); + } + else + { + std::__merge_sort_with_buffer(__first, __middle, __buffer, __comp); + std::__merge_sort_with_buffer(__middle, __last, __buffer, __comp); + } + std::__merge_adaptive(__first, __middle, __last, + _Distance(__middle - __first), + _Distance(__last - __middle), + __buffer, __buffer_size, + __comp); + } + + /// This is a helper function for the stable sorting routines. + template + void + __inplace_stable_sort(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + if (__last - __first < 15) + { + std::__insertion_sort(__first, __last, __comp); + return; + } + _RandomAccessIterator __middle = __first + (__last - __first) / 2; + std::__inplace_stable_sort(__first, __middle, __comp); + std::__inplace_stable_sort(__middle, __last, __comp); + std::__merge_without_buffer(__first, __middle, __last, + __middle - __first, + __last - __middle, + __comp); + } + + // stable_sort + + // Set algorithms: includes, set_union, set_intersection, set_difference, + // set_symmetric_difference. All of these algorithms have the precondition + // that their input ranges are sorted and the postcondition that their output + // ranges are sorted. + + template + bool + __includes(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + if (__comp(__first2, __first1)) + return false; + else if (__comp(__first1, __first2)) + ++__first1; + else + { + ++__first1; + ++__first2; + } + + return __first2 == __last2; + } + + /** + * @brief Determines whether all elements of a sequence exists in a range. + * @param __first1 Start of search range. + * @param __last1 End of search range. + * @param __first2 Start of sequence + * @param __last2 End of sequence. + * @return True if each element in [__first2,__last2) is contained in order + * within [__first1,__last1). False otherwise. + * @ingroup set_algorithms + * + * This operation expects both [__first1,__last1) and + * [__first2,__last2) to be sorted. Searches for the presence of + * each element in [__first2,__last2) within [__first1,__last1). + * The iterators over each range only move forward, so this is a + * linear algorithm. If an element in [__first2,__last2) is not + * found before the search iterator reaches @p __last2, false is + * returned. + */ + template + inline bool + includes(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return std::__includes(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Determines whether all elements of a sequence exists in a range + * using comparison. + * @ingroup set_algorithms + * @param __first1 Start of search range. + * @param __last1 End of search range. + * @param __first2 Start of sequence + * @param __last2 End of sequence. + * @param __comp Comparison function to use. + * @return True if each element in [__first2,__last2) is contained + * in order within [__first1,__last1) according to comp. False + * otherwise. @ingroup set_algorithms + * + * This operation expects both [__first1,__last1) and + * [__first2,__last2) to be sorted. Searches for the presence of + * each element in [__first2,__last2) within [__first1,__last1), + * using comp to decide. The iterators over each range only move + * forward, so this is a linear algorithm. If an element in + * [__first2,__last2) is not found before the search iterator + * reaches @p __last2, false is returned. + */ + template + inline bool + includes(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return std::__includes(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + // nth_element + // merge + // set_difference + // set_intersection + // set_union + // stable_sort + // set_symmetric_difference + // min_element + // max_element + + template + bool + __next_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last, _Compare __comp) + { + if (__first == __last) + return false; + _BidirectionalIterator __i = __first; + ++__i; + if (__i == __last) + return false; + __i = __last; + --__i; + + for(;;) + { + _BidirectionalIterator __ii = __i; + --__i; + if (__comp(__i, __ii)) + { + _BidirectionalIterator __j = __last; + while (!__comp(__i, --__j)) + {} + std::iter_swap(__i, __j); + std::__reverse(__ii, __last, + std::__iterator_category(__first)); + return true; + } + if (__i == __first) + { + std::__reverse(__first, __last, + std::__iterator_category(__first)); + return false; + } + } + } + + /** + * @brief Permute range into the next @e dictionary ordering. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @return False if wrapped to first permutation, true otherwise. + * + * Treats all permutations of the range as a set of @e dictionary sorted + * sequences. Permutes the current sequence into the next one of this set. + * Returns true if there are more sequences to generate. If the sequence + * is the largest of the set, the smallest is generated and false returned. + */ + template + inline bool + next_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return std::__next_permutation + (__first, __last, __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Permute range into the next @e dictionary ordering using + * comparison functor. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @param __comp A comparison functor. + * @return False if wrapped to first permutation, true otherwise. + * + * Treats all permutations of the range [__first,__last) as a set of + * @e dictionary sorted sequences ordered by @p __comp. Permutes the current + * sequence into the next one of this set. Returns true if there are more + * sequences to generate. If the sequence is the largest of the set, the + * smallest is generated and false returned. + */ + template + inline bool + next_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_BidirectionalIterator>::value_type, + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return std::__next_permutation + (__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + bool + __prev_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last, _Compare __comp) + { + if (__first == __last) + return false; + _BidirectionalIterator __i = __first; + ++__i; + if (__i == __last) + return false; + __i = __last; + --__i; + + for(;;) + { + _BidirectionalIterator __ii = __i; + --__i; + if (__comp(__ii, __i)) + { + _BidirectionalIterator __j = __last; + while (!__comp(--__j, __i)) + {} + std::iter_swap(__i, __j); + std::__reverse(__ii, __last, + std::__iterator_category(__first)); + return true; + } + if (__i == __first) + { + std::__reverse(__first, __last, + std::__iterator_category(__first)); + return false; + } + } + } + + /** + * @brief Permute range into the previous @e dictionary ordering. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @return False if wrapped to last permutation, true otherwise. + * + * Treats all permutations of the range as a set of @e dictionary sorted + * sequences. Permutes the current sequence into the previous one of this + * set. Returns true if there are more sequences to generate. If the + * sequence is the smallest of the set, the largest is generated and false + * returned. + */ + template + inline bool + prev_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return std::__prev_permutation(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Permute range into the previous @e dictionary ordering using + * comparison functor. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @param __comp A comparison functor. + * @return False if wrapped to last permutation, true otherwise. + * + * Treats all permutations of the range [__first,__last) as a set of + * @e dictionary sorted sequences ordered by @p __comp. Permutes the current + * sequence into the previous one of this set. Returns true if there are + * more sequences to generate. If the sequence is the smallest of the set, + * the largest is generated and false returned. + */ + template + inline bool + prev_permutation(_BidirectionalIterator __first, + _BidirectionalIterator __last, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_BidirectionalIterator>::value_type, + typename iterator_traits<_BidirectionalIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return std::__prev_permutation(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + // replace + // replace_if + + template + _OutputIterator + __replace_copy_if(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, + _Predicate __pred, const _Tp& __new_value) + { + for (; __first != __last; ++__first, (void)++__result) + if (__pred(__first)) + *__result = __new_value; + else + *__result = *__first; + return __result; + } + + /** + * @brief Copy a sequence, replacing each element of one value with another + * value. + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __old_value The value to be replaced. + * @param __new_value The replacement value. + * @return The end of the output sequence, @p result+(last-first). + * + * Copies each element in the input range @p [__first,__last) to the + * output range @p [__result,__result+(__last-__first)) replacing elements + * equal to @p __old_value with @p __new_value. + */ + template + inline _OutputIterator + replace_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, + const _Tp& __old_value, const _Tp& __new_value) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__replace_copy_if(__first, __last, __result, + __gnu_cxx::__ops::__iter_equals_val(__old_value), + __new_value); + } + + /** + * @brief Copy a sequence, replacing each value for which a predicate + * returns true with another value. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __pred A predicate. + * @param __new_value The replacement value. + * @return The end of the output sequence, @p __result+(__last-__first). + * + * Copies each element in the range @p [__first,__last) to the range + * @p [__result,__result+(__last-__first)) replacing elements for which + * @p __pred returns true with @p __new_value. + */ + template + inline _OutputIterator + replace_copy_if(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, + _Predicate __pred, const _Tp& __new_value) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__replace_copy_if(__first, __last, __result, + __gnu_cxx::__ops::__pred_iter(__pred), + __new_value); + } + + template + typename iterator_traits<_InputIterator>::difference_type + __count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) + { + typename iterator_traits<_InputIterator>::difference_type __n = 0; + for (; __first != __last; ++__first) + if (__pred(__first)) + ++__n; + return __n; + } + +#if __cplusplus >= 201103L + /** + * @brief Determines whether the elements of a sequence are sorted. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @return True if the elements are sorted, false otherwise. + */ + template + inline bool + is_sorted(_ForwardIterator __first, _ForwardIterator __last) + { return std::is_sorted_until(__first, __last) == __last; } + + /** + * @brief Determines whether the elements of a sequence are sorted + * according to a comparison functor. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return True if the elements are sorted, false otherwise. + */ + template + inline bool + is_sorted(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { return std::is_sorted_until(__first, __last, __comp) == __last; } + + template + _ForwardIterator + __is_sorted_until(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + if (__first == __last) + return __last; + + _ForwardIterator __next = __first; + for (++__next; __next != __last; __first = __next, (void)++__next) + if (__comp(__next, __first)) + return __next; + return __next; + } + + /** + * @brief Determines the end of a sorted sequence. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @return An iterator pointing to the last iterator i in [__first, __last) + * for which the range [__first, i) is sorted. + */ + template + inline _ForwardIterator + is_sorted_until(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return std::__is_sorted_until(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Determines the end of a sorted sequence using comparison functor. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return An iterator pointing to the last iterator i in [__first, __last) + * for which the range [__first, i) is sorted. + */ + template + inline _ForwardIterator + is_sorted_until(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return std::__is_sorted_until(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + /** + * @brief Determines min and max at once as an ordered pair. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @return A pair(__b, __a) if __b is smaller than __a, pair(__a, + * __b) otherwise. + */ + template + _GLIBCXX14_CONSTEXPR + inline pair + minmax(const _Tp& __a, const _Tp& __b) + { + // concept requirements + __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) + + return __b < __a ? pair(__b, __a) + : pair(__a, __b); + } + + /** + * @brief Determines min and max at once as an ordered pair. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @param __comp A @link comparison_functors comparison functor @endlink. + * @return A pair(__b, __a) if __b is smaller than __a, pair(__a, + * __b) otherwise. + */ + template + _GLIBCXX14_CONSTEXPR + inline pair + minmax(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + return __comp(__b, __a) ? pair(__b, __a) + : pair(__a, __b); + } + + template + _GLIBCXX14_CONSTEXPR + pair<_ForwardIterator, _ForwardIterator> + __minmax_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + _ForwardIterator __next = __first; + if (__first == __last + || ++__next == __last) + return std::make_pair(__first, __first); + + _ForwardIterator __min{}, __max{}; + if (__comp(__next, __first)) + { + __min = __next; + __max = __first; + } + else + { + __min = __first; + __max = __next; + } + + __first = __next; + ++__first; + + while (__first != __last) + { + __next = __first; + if (++__next == __last) + { + if (__comp(__first, __min)) + __min = __first; + else if (!__comp(__first, __max)) + __max = __first; + break; + } + + if (__comp(__next, __first)) + { + if (__comp(__next, __min)) + __min = __next; + if (!__comp(__first, __max)) + __max = __first; + } + else + { + if (__comp(__first, __min)) + __min = __first; + if (!__comp(__next, __max)) + __max = __next; + } + + __first = __next; + ++__first; + } + + return std::make_pair(__min, __max); + } + + /** + * @brief Return a pair of iterators pointing to the minimum and maximum + * elements in a range. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @return make_pair(m, M), where m is the first iterator i in + * [__first, __last) such that no other element in the range is + * smaller, and where M is the last iterator i in [__first, __last) + * such that no other element in the range is larger. + */ + template + _GLIBCXX14_CONSTEXPR + inline pair<_ForwardIterator, _ForwardIterator> + minmax_element(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return std::__minmax_element(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return a pair of iterators pointing to the minimum and maximum + * elements in a range. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @param __comp Comparison functor. + * @return make_pair(m, M), where m is the first iterator i in + * [__first, __last) such that no other element in the range is + * smaller, and where M is the last iterator i in [__first, __last) + * such that no other element in the range is larger. + */ + template + _GLIBCXX14_CONSTEXPR + inline pair<_ForwardIterator, _ForwardIterator> + minmax_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return std::__minmax_element(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + // N2722 + DR 915. + template + _GLIBCXX14_CONSTEXPR + inline _Tp + min(initializer_list<_Tp> __l) + { return *std::min_element(__l.begin(), __l.end()); } + + template + _GLIBCXX14_CONSTEXPR + inline _Tp + min(initializer_list<_Tp> __l, _Compare __comp) + { return *std::min_element(__l.begin(), __l.end(), __comp); } + + template + _GLIBCXX14_CONSTEXPR + inline _Tp + max(initializer_list<_Tp> __l) + { return *std::max_element(__l.begin(), __l.end()); } + + template + _GLIBCXX14_CONSTEXPR + inline _Tp + max(initializer_list<_Tp> __l, _Compare __comp) + { return *std::max_element(__l.begin(), __l.end(), __comp); } + + template + _GLIBCXX14_CONSTEXPR + inline pair<_Tp, _Tp> + minmax(initializer_list<_Tp> __l) + { + pair __p = + std::minmax_element(__l.begin(), __l.end()); + return std::make_pair(*__p.first, *__p.second); + } + + template + _GLIBCXX14_CONSTEXPR + inline pair<_Tp, _Tp> + minmax(initializer_list<_Tp> __l, _Compare __comp) + { + pair __p = + std::minmax_element(__l.begin(), __l.end(), __comp); + return std::make_pair(*__p.first, *__p.second); + } + + template + bool + __is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _BinaryPredicate __pred) + { + // Efficiently compare identical prefixes: O(N) if sequences + // have the same elements in the same order. + for (; __first1 != __last1; ++__first1, (void)++__first2) + if (!__pred(__first1, __first2)) + break; + + if (__first1 == __last1) + return true; + + // Establish __last2 assuming equal ranges by iterating over the + // rest of the list. + _ForwardIterator2 __last2 = __first2; + std::advance(__last2, std::distance(__first1, __last1)); + for (_ForwardIterator1 __scan = __first1; __scan != __last1; ++__scan) + { + if (__scan != std::__find_if(__first1, __scan, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan))) + continue; // We've seen this one before. + + auto __matches + = std::__count_if(__first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan)); + if (0 == __matches || + std::__count_if(__scan, __last1, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan)) + != __matches) + return false; + } + return true; + } + + /** + * @brief Checks whether a permutation of the second sequence is equal + * to the first sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @return true if there exists a permutation of the elements in the range + * [__first2, __first2 + (__last1 - __first1)), beginning with + * ForwardIterator2 begin, such that equal(__first1, __last1, begin) + * returns true; otherwise, returns false. + */ + template + inline bool + is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + + return std::__is_permutation(__first1, __last1, __first2, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Checks whether a permutation of the second sequence is equal + * to the first sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __pred A binary predicate. + * @return true if there exists a permutation of the elements in + * the range [__first2, __first2 + (__last1 - __first1)), + * beginning with ForwardIterator2 begin, such that + * equal(__first1, __last1, __begin, __pred) returns true; + * otherwise, returns false. + */ + template + inline bool + is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _BinaryPredicate __pred) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + + return std::__is_permutation(__first1, __last1, __first2, + __gnu_cxx::__ops::__iter_comp_iter(__pred)); + } + +#if __cplusplus > 201103L + template + bool + __is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + _BinaryPredicate __pred) + { + using _Cat1 + = typename iterator_traits<_ForwardIterator1>::iterator_category; + using _Cat2 + = typename iterator_traits<_ForwardIterator2>::iterator_category; + using _It1_is_RA = is_same<_Cat1, random_access_iterator_tag>; + using _It2_is_RA = is_same<_Cat2, random_access_iterator_tag>; + constexpr bool __ra_iters = _It1_is_RA() && _It2_is_RA(); + if (__ra_iters) + { + auto __d1 = std::distance(__first1, __last1); + auto __d2 = std::distance(__first2, __last2); + if (__d1 != __d2) + return false; + } + + // Efficiently compare identical prefixes: O(N) if sequences + // have the same elements in the same order. + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + if (!__pred(__first1, __first2)) + break; + + if (__ra_iters) + { + if (__first1 == __last1) + return true; + } + else + { + auto __d1 = std::distance(__first1, __last1); + auto __d2 = std::distance(__first2, __last2); + if (__d1 == 0 && __d2 == 0) + return true; + if (__d1 != __d2) + return false; + } + + for (_ForwardIterator1 __scan = __first1; __scan != __last1; ++__scan) + { + if (__scan != std::__find_if(__first1, __scan, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan))) + continue; // We've seen this one before. + + auto __matches = std::__count_if(__first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan)); + if (0 == __matches + || std::__count_if(__scan, __last1, + __gnu_cxx::__ops::__iter_comp_iter(__pred, __scan)) + != __matches) + return false; + } + return true; + } + + /** + * @brief Checks whether a permutaion of the second sequence is equal + * to the first sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of first range. + * @return true if there exists a permutation of the elements in the range + * [__first2, __last2), beginning with ForwardIterator2 begin, + * such that equal(__first1, __last1, begin) returns true; + * otherwise, returns false. + */ + template + inline bool + is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2) + { + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return + std::__is_permutation(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Checks whether a permutation of the second sequence is equal + * to the first sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of first range. + * @param __pred A binary predicate. + * @return true if there exists a permutation of the elements in the range + * [__first2, __last2), beginning with ForwardIterator2 begin, + * such that equal(__first1, __last1, __begin, __pred) returns true; + * otherwise, returns false. + */ + template + inline bool + is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + _BinaryPredicate __pred) + { + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__is_permutation(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__pred)); + } + +#if __cplusplus > 201402L + +#define __cpp_lib_clamp 201603 + + /** + * @brief Returns the value clamped between lo and hi. + * @ingroup sorting_algorithms + * @param __val A value of arbitrary type. + * @param __lo A lower limit of arbitrary type. + * @param __hi An upper limit of arbitrary type. + * @return max(__val, __lo) if __val < __hi or min(__val, __hi) otherwise. + */ + template + constexpr const _Tp& + clamp(const _Tp& __val, const _Tp& __lo, const _Tp& __hi) + { + __glibcxx_assert(!(__hi < __lo)); + return (__val < __lo) ? __lo : (__hi < __val) ? __hi : __val; + } + + /** + * @brief Returns the value clamped between lo and hi. + * @ingroup sorting_algorithms + * @param __val A value of arbitrary type. + * @param __lo A lower limit of arbitrary type. + * @param __hi An upper limit of arbitrary type. + * @param __comp A comparison functor. + * @return max(__val, __lo, __comp) if __comp(__val, __hi) + * or min(__val, __hi, __comp) otherwise. + */ + template + constexpr const _Tp& + clamp(const _Tp& __val, const _Tp& __lo, const _Tp& __hi, _Compare __comp) + { + __glibcxx_assert(!__comp(__hi, __lo)); + return __comp(__val, __lo) ? __lo : __comp(__hi, __val) ? __hi : __val; + } +#endif // C++17 +#endif // C++14 + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 + /** + * @brief Generate two uniformly distributed integers using a + * single distribution invocation. + * @param __b0 The upper bound for the first integer. + * @param __b1 The upper bound for the second integer. + * @param __g A UniformRandomBitGenerator. + * @return A pair (i, j) with i and j uniformly distributed + * over [0, __b0) and [0, __b1), respectively. + * + * Requires: __b0 * __b1 <= __g.max() - __g.min(). + * + * Using uniform_int_distribution with a range that is very + * small relative to the range of the generator ends up wasting + * potentially expensively generated randomness, since + * uniform_int_distribution does not store leftover randomness + * between invocations. + * + * If we know we want two integers in ranges that are sufficiently + * small, we can compose the ranges, use a single distribution + * invocation, and significantly reduce the waste. + */ + template + pair<_IntType, _IntType> + __gen_two_uniform_ints(_IntType __b0, _IntType __b1, + _UniformRandomBitGenerator&& __g) + { + _IntType __x + = uniform_int_distribution<_IntType>{0, (__b0 * __b1) - 1}(__g); + return std::make_pair(__x / __b1, __x % __b1); + } + + /** + * @brief Shuffle the elements of a sequence using a uniform random + * number generator. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __g A UniformRandomNumberGenerator (26.5.1.3). + * @return Nothing. + * + * Reorders the elements in the range @p [__first,__last) using @p __g to + * provide random numbers. + */ + template + void + shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, + _UniformRandomNumberGenerator&& __g) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return; + + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + typedef typename std::make_unsigned<_DistanceType>::type __ud_type; + typedef typename std::uniform_int_distribution<__ud_type> __distr_type; + typedef typename __distr_type::param_type __p_type; + + typedef typename remove_reference<_UniformRandomNumberGenerator>::type + _Gen; + typedef typename common_type::type + __uc_type; + + const __uc_type __urngrange = __g.max() - __g.min(); + const __uc_type __urange = __uc_type(__last - __first); + + if (__urngrange / __urange >= __urange) + // I.e. (__urngrange >= __urange * __urange) but without wrap issues. + { + _RandomAccessIterator __i = __first + 1; + + // Since we know the range isn't empty, an even number of elements + // means an uneven number of elements /to swap/, in which case we + // do the first one up front: + + if ((__urange % 2) == 0) + { + __distr_type __d{0, 1}; + std::iter_swap(__i++, __first + __d(__g)); + } + + // Now we know that __last - __i is even, so we do the rest in pairs, + // using a single distribution invocation to produce swap positions + // for two successive elements at a time: + + while (__i != __last) + { + const __uc_type __swap_range = __uc_type(__i - __first) + 1; + + const pair<__uc_type, __uc_type> __pospos = + __gen_two_uniform_ints(__swap_range, __swap_range + 1, __g); + + std::iter_swap(__i++, __first + __pospos.first); + std::iter_swap(__i++, __first + __pospos.second); + } + + return; + } + + __distr_type __d; + + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + std::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first))); + } +#endif + +#endif // C++11 + +_GLIBCXX_END_NAMESPACE_VERSION + +_GLIBCXX_BEGIN_NAMESPACE_ALGO + + /** + * @brief Apply a function to every element of a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __f A unary function object. + * @return @p __f + * + * Applies the function object @p __f to each element in the range + * @p [first,last). @p __f must not modify the order of the sequence. + * If @p __f has a return value it is ignored. + */ + template + _Function + for_each(_InputIterator __first, _InputIterator __last, _Function __f) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_requires_valid_range(__first, __last); + for (; __first != __last; ++__first) + __f(*__first); + return __f; // N.B. [alg.foreach] says std::move(f) but it's redundant. + } + + /** + * @brief Find the first occurrence of a value in a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __val The value to find. + * @return The first iterator @c i in the range @p [__first,__last) + * such that @c *i == @p __val, or @p __last if no such iterator exists. + */ + template + inline _InputIterator + find(_InputIterator __first, _InputIterator __last, + const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + return std::__find_if(__first, __last, + __gnu_cxx::__ops::__iter_equals_val(__val)); + } + + /** + * @brief Find the first element in a sequence for which a + * predicate is true. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return The first iterator @c i in the range @p [__first,__last) + * such that @p __pred(*i) is true, or @p __last if no such iterator exists. + */ + template + inline _InputIterator + find_if(_InputIterator __first, _InputIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__find_if(__first, __last, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + + /** + * @brief Find element from a set in a sequence. + * @ingroup non_mutating_algorithms + * @param __first1 Start of range to search. + * @param __last1 End of range to search. + * @param __first2 Start of match candidates. + * @param __last2 End of match candidates. + * @return The first iterator @c i in the range + * @p [__first1,__last1) such that @c *i == @p *(i2) such that i2 is an + * iterator in [__first2,__last2), or @p __last1 if no such iterator exists. + * + * Searches the range @p [__first1,__last1) for an element that is + * equal to some element in the range [__first2,__last2). If + * found, returns an iterator in the range [__first1,__last1), + * otherwise returns @p __last1. + */ + template + _InputIterator + find_first_of(_InputIterator __first1, _InputIterator __last1, + _ForwardIterator __first2, _ForwardIterator __last2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + for (; __first1 != __last1; ++__first1) + for (_ForwardIterator __iter = __first2; __iter != __last2; ++__iter) + if (*__first1 == *__iter) + return __first1; + return __last1; + } + + /** + * @brief Find element from a set in a sequence using a predicate. + * @ingroup non_mutating_algorithms + * @param __first1 Start of range to search. + * @param __last1 End of range to search. + * @param __first2 Start of match candidates. + * @param __last2 End of match candidates. + * @param __comp Predicate to use. + * @return The first iterator @c i in the range + * @p [__first1,__last1) such that @c comp(*i, @p *(i2)) is true + * and i2 is an iterator in [__first2,__last2), or @p __last1 if no + * such iterator exists. + * + + * Searches the range @p [__first1,__last1) for an element that is + * equal to some element in the range [__first2,__last2). If + * found, returns an iterator in the range [__first1,__last1), + * otherwise returns @p __last1. + */ + template + _InputIterator + find_first_of(_InputIterator __first1, _InputIterator __last1, + _ForwardIterator __first2, _ForwardIterator __last2, + _BinaryPredicate __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_InputIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + for (; __first1 != __last1; ++__first1) + for (_ForwardIterator __iter = __first2; __iter != __last2; ++__iter) + if (__comp(*__first1, *__iter)) + return __first1; + return __last1; + } + + /** + * @brief Find two adjacent values in a sequence that are equal. + * @ingroup non_mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @return The first iterator @c i such that @c i and @c i+1 are both + * valid iterators in @p [__first,__last) and such that @c *i == @c *(i+1), + * or @p __last if no such iterator exists. + */ + template + inline _ForwardIterator + adjacent_find(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_EqualityComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__adjacent_find(__first, __last, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Find two adjacent values in a sequence using a predicate. + * @ingroup non_mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __binary_pred A binary predicate. + * @return The first iterator @c i such that @c i and @c i+1 are both + * valid iterators in @p [__first,__last) and such that + * @p __binary_pred(*i,*(i+1)) is true, or @p __last if no such iterator + * exists. + */ + template + inline _ForwardIterator + adjacent_find(_ForwardIterator __first, _ForwardIterator __last, + _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__adjacent_find(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); + } + + /** + * @brief Count the number of copies of a value in a sequence. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __value The value to be counted. + * @return The number of iterators @c i in the range @p [__first,__last) + * for which @c *i == @p __value + */ + template + inline typename iterator_traits<_InputIterator>::difference_type + count(_InputIterator __first, _InputIterator __last, const _Tp& __value) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__count_if(__first, __last, + __gnu_cxx::__ops::__iter_equals_val(__value)); + } + + /** + * @brief Count the elements of a sequence for which a predicate is true. + * @ingroup non_mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __pred A predicate. + * @return The number of iterators @c i in the range @p [__first,__last) + * for which @p __pred(*i) is true. + */ + template + inline typename iterator_traits<_InputIterator>::difference_type + count_if(_InputIterator __first, _InputIterator __last, _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__count_if(__first, __last, + __gnu_cxx::__ops::__pred_iter(__pred)); + } + + /** + * @brief Search a sequence for a matching sub-sequence. + * @ingroup non_mutating_algorithms + * @param __first1 A forward iterator. + * @param __last1 A forward iterator. + * @param __first2 A forward iterator. + * @param __last2 A forward iterator. + * @return The first iterator @c i in the range @p + * [__first1,__last1-(__last2-__first2)) such that @c *(i+N) == @p + * *(__first2+N) for each @c N in the range @p + * [0,__last2-__first2), or @p __last1 if no such iterator exists. + * + * Searches the range @p [__first1,__last1) for a sub-sequence that + * compares equal value-by-value with the sequence given by @p + * [__first2,__last2) and returns an iterator to the first element + * of the sub-sequence, or @p __last1 if the sub-sequence is not + * found. + * + * Because the sub-sequence must lie completely within the range @p + * [__first1,__last1) it must start at a position less than @p + * __last1-(__last2-__first2) where @p __last2-__first2 is the + * length of the sub-sequence. + * + * This means that the returned iterator @c i will be in the range + * @p [__first1,__last1-(__last2-__first2)) + */ + template + inline _ForwardIterator1 + search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__search(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Search a sequence for a matching sub-sequence using a predicate. + * @ingroup non_mutating_algorithms + * @param __first1 A forward iterator. + * @param __last1 A forward iterator. + * @param __first2 A forward iterator. + * @param __last2 A forward iterator. + * @param __predicate A binary predicate. + * @return The first iterator @c i in the range + * @p [__first1,__last1-(__last2-__first2)) such that + * @p __predicate(*(i+N),*(__first2+N)) is true for each @c N in the range + * @p [0,__last2-__first2), or @p __last1 if no such iterator exists. + * + * Searches the range @p [__first1,__last1) for a sub-sequence that + * compares equal value-by-value with the sequence given by @p + * [__first2,__last2), using @p __predicate to determine equality, + * and returns an iterator to the first element of the + * sub-sequence, or @p __last1 if no such iterator exists. + * + * @see search(_ForwardIter1, _ForwardIter1, _ForwardIter2, _ForwardIter2) + */ + template + inline _ForwardIterator1 + search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2, _ForwardIterator2 __last2, + _BinaryPredicate __predicate) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator1>) + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator2>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator1>::value_type, + typename iterator_traits<_ForwardIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__search(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__predicate)); + } + + /** + * @brief Search a sequence for a number of consecutive values. + * @ingroup non_mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __count The number of consecutive values. + * @param __val The value to find. + * @return The first iterator @c i in the range @p + * [__first,__last-__count) such that @c *(i+N) == @p __val for + * each @c N in the range @p [0,__count), or @p __last if no such + * iterator exists. + * + * Searches the range @p [__first,__last) for @p count consecutive elements + * equal to @p __val. + */ + template + inline _ForwardIterator + search_n(_ForwardIterator __first, _ForwardIterator __last, + _Integer __count, const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__search_n(__first, __last, __count, + __gnu_cxx::__ops::__iter_equals_val(__val)); + } + + + /** + * @brief Search a sequence for a number of consecutive values using a + * predicate. + * @ingroup non_mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __count The number of consecutive values. + * @param __val The value to find. + * @param __binary_pred A binary predicate. + * @return The first iterator @c i in the range @p + * [__first,__last-__count) such that @p + * __binary_pred(*(i+N),__val) is true for each @c N in the range + * @p [0,__count), or @p __last if no such iterator exists. + * + * Searches the range @p [__first,__last) for @p __count + * consecutive elements for which the predicate returns true. + */ + template + inline _ForwardIterator + search_n(_ForwardIterator __first, _ForwardIterator __last, + _Integer __count, const _Tp& __val, + _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_BinaryPredicate, + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__search_n(__first, __last, __count, + __gnu_cxx::__ops::__iter_comp_val(__binary_pred, __val)); + } + +#if __cplusplus > 201402L + /** @brief Search a sequence using a Searcher object. + * + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __searcher A callable object. + * @return @p __searcher(__first,__last).first + */ + template + inline _ForwardIterator + search(_ForwardIterator __first, _ForwardIterator __last, + const _Searcher& __searcher) + { return __searcher(__first, __last).first; } +#endif + + /** + * @brief Perform an operation on a sequence. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __unary_op A unary operator. + * @return An output iterator equal to @p __result+(__last-__first). + * + * Applies the operator to each element in the input range and assigns + * the results to successive elements of the output sequence. + * Evaluates @p *(__result+N)=unary_op(*(__first+N)) for each @c N in the + * range @p [0,__last-__first). + * + * @p unary_op must not alter its argument. + */ + template + _OutputIterator + transform(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _UnaryOperation __unary_op) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + // "the type returned by a _UnaryOperation" + __typeof__(__unary_op(*__first))>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first, (void)++__result) + *__result = __unary_op(*__first); + return __result; + } + + /** + * @brief Perform an operation on corresponding elements of two sequences. + * @ingroup mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __result An output iterator. + * @param __binary_op A binary operator. + * @return An output iterator equal to @p result+(last-first). + * + * Applies the operator to the corresponding elements in the two + * input ranges and assigns the results to successive elements of the + * output sequence. + * Evaluates @p + * *(__result+N)=__binary_op(*(__first1+N),*(__first2+N)) for each + * @c N in the range @p [0,__last1-__first1). + * + * @p binary_op must not alter either of its arguments. + */ + template + _OutputIterator + transform(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _OutputIterator __result, + _BinaryOperation __binary_op) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + // "the type returned by a _BinaryOperation" + __typeof__(__binary_op(*__first1,*__first2))>) + __glibcxx_requires_valid_range(__first1, __last1); + + for (; __first1 != __last1; ++__first1, (void)++__first2, ++__result) + *__result = __binary_op(*__first1, *__first2); + return __result; + } + + /** + * @brief Replace each occurrence of one value in a sequence with another + * value. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __old_value The value to be replaced. + * @param __new_value The replacement value. + * @return replace() returns no value. + * + * For each iterator @c i in the range @p [__first,__last) if @c *i == + * @p __old_value then the assignment @c *i = @p __new_value is performed. + */ + template + void + replace(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __old_value, const _Tp& __new_value) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_function_requires(_ConvertibleConcept<_Tp, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + if (*__first == __old_value) + *__first = __new_value; + } + + /** + * @brief Replace each value in a sequence for which a predicate returns + * true with another value. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __pred A predicate. + * @param __new_value The replacement value. + * @return replace_if() returns no value. + * + * For each iterator @c i in the range @p [__first,__last) if @p __pred(*i) + * is true then the assignment @c *i = @p __new_value is performed. + */ + template + void + replace_if(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred, const _Tp& __new_value) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_ConvertibleConcept<_Tp, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + if (__pred(*__first)) + *__first = __new_value; + } + + /** + * @brief Assign the result of a function object to each value in a + * sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __gen A function object taking no arguments and returning + * std::iterator_traits<_ForwardIterator>::value_type + * @return generate() returns no value. + * + * Performs the assignment @c *i = @p __gen() for each @c i in the range + * @p [__first,__last). + */ + template + void + generate(_ForwardIterator __first, _ForwardIterator __last, + _Generator __gen) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_GeneratorConcept<_Generator, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + *__first = __gen(); + } + + /** + * @brief Assign the result of a function object to each value in a + * sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __n The length of the sequence. + * @param __gen A function object taking no arguments and returning + * std::iterator_traits<_ForwardIterator>::value_type + * @return The end of the sequence, @p __first+__n + * + * Performs the assignment @c *i = @p __gen() for each @c i in the range + * @p [__first,__first+__n). + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 865. More algorithms that throw away information + */ + template + _OutputIterator + generate_n(_OutputIterator __first, _Size __n, _Generator __gen) + { + // concept requirements + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + // "the type returned by a _Generator" + __typeof__(__gen())>) + + for (__decltype(__n + 0) __niter = __n; + __niter > 0; --__niter, ++__first) + *__first = __gen(); + return __first; + } + + /** + * @brief Copy a sequence, removing consecutive duplicate values. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [__first,__last) to the range + * beginning at @p __result, except that only the first element is copied + * from groups of consecutive elements that compare equal. + * unique_copy() is stable, so the relative order of elements that are + * copied is unchanged. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 241. Does unique_copy() require CopyConstructible and Assignable? + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 538. 241 again: Does unique_copy() require CopyConstructible and + * Assignable? + */ + template + inline _OutputIterator + unique_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_function_requires(_EqualityComparableConcept< + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + return std::__unique_copy(__first, __last, __result, + __gnu_cxx::__ops::__iter_equal_to_iter(), + std::__iterator_category(__first), + std::__iterator_category(__result)); + } + + /** + * @brief Copy a sequence, removing consecutive values using a predicate. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @param __binary_pred A binary predicate. + * @return An iterator designating the end of the resulting sequence. + * + * Copies each element in the range @p [__first,__last) to the range + * beginning at @p __result, except that only the first element is copied + * from groups of consecutive elements for which @p __binary_pred returns + * true. + * unique_copy() is stable, so the relative order of elements that are + * copied is unchanged. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 241. Does unique_copy() require CopyConstructible and Assignable? + */ + template + inline _OutputIterator + unique_copy(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, + _BinaryPredicate __binary_pred) + { + // concept requirements -- predicates checked later + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + return std::__unique_copy(__first, __last, __result, + __gnu_cxx::__ops::__iter_comp_iter(__binary_pred), + std::__iterator_category(__first), + std::__iterator_category(__result)); + } + +#if _GLIBCXX_HOSTED + /** + * @brief Randomly shuffle the elements of a sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @return Nothing. + * + * Reorder the elements in the range @p [__first,__last) using a random + * distribution, so that every possible ordering of the sequence is + * equally likely. + */ + template + inline void + random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first != __last) + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + { + // XXX rand() % N is not uniformly distributed + _RandomAccessIterator __j = __first + + std::rand() % ((__i - __first) + 1); + if (__i != __j) + std::iter_swap(__i, __j); + } + } +#endif + + /** + * @brief Shuffle the elements of a sequence using a random number + * generator. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __rand The RNG functor or function. + * @return Nothing. + * + * Reorders the elements in the range @p [__first,__last) using @p __rand to + * provide a random distribution. Calling @p __rand(N) for a positive + * integer @p N should return a randomly chosen integer from the + * range [0,N). + */ + template + void + random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, +#if __cplusplus >= 201103L + _RandomNumberGenerator&& __rand) +#else + _RandomNumberGenerator& __rand) +#endif + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return; + for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i) + { + _RandomAccessIterator __j = __first + __rand((__i - __first) + 1); + if (__i != __j) + std::iter_swap(__i, __j); + } + } + + + /** + * @brief Move elements for which a predicate is true to the beginning + * of a sequence. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __pred A predicate functor. + * @return An iterator @p middle such that @p __pred(i) is true for each + * iterator @p i in the range @p [__first,middle) and false for each @p i + * in the range @p [middle,__last). + * + * @p __pred must not modify its operand. @p partition() does not preserve + * the relative ordering of elements in each group, use + * @p stable_partition() if this is needed. + */ + template + inline _ForwardIterator + partition(_ForwardIterator __first, _ForwardIterator __last, + _Predicate __pred) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_UnaryPredicateConcept<_Predicate, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__partition(__first, __last, __pred, + std::__iterator_category(__first)); + } + + + /** + * @brief Sort the smallest elements of a sequence. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __middle Another iterator. + * @param __last Another iterator. + * @return Nothing. + * + * Sorts the smallest @p (__middle-__first) elements in the range + * @p [first,last) and moves them to the range @p [__first,__middle). The + * order of the remaining elements in the range @p [__middle,__last) is + * undefined. + * After the sort if @e i and @e j are iterators in the range + * @p [__first,__middle) such that i precedes j and @e k is an iterator in + * the range @p [__middle,__last) then *j<*i and *k<*i are both false. + */ + template + inline void + partial_sort(_RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __middle); + __glibcxx_requires_valid_range(__middle, __last); + __glibcxx_requires_irreflexive(__first, __last); + + std::__partial_sort(__first, __middle, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Sort the smallest elements of a sequence using a predicate + * for comparison. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __middle Another iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return Nothing. + * + * Sorts the smallest @p (__middle-__first) elements in the range + * @p [__first,__last) and moves them to the range @p [__first,__middle). The + * order of the remaining elements in the range @p [__middle,__last) is + * undefined. + * After the sort if @e i and @e j are iterators in the range + * @p [__first,__middle) such that i precedes j and @e k is an iterator in + * the range @p [__middle,__last) then @p *__comp(j,*i) and @p __comp(*k,*i) + * are both false. + */ + template + inline void + partial_sort(_RandomAccessIterator __first, + _RandomAccessIterator __middle, + _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_RandomAccessIterator>::value_type, + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __middle); + __glibcxx_requires_valid_range(__middle, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + std::__partial_sort(__first, __middle, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + /** + * @brief Sort a sequence just enough to find a particular position. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __nth Another iterator. + * @param __last Another iterator. + * @return Nothing. + * + * Rearranges the elements in the range @p [__first,__last) so that @p *__nth + * is the same element that would have been in that position had the + * whole sequence been sorted. The elements either side of @p *__nth are + * not completely sorted, but for any iterator @e i in the range + * @p [__first,__nth) and any iterator @e j in the range @p [__nth,__last) it + * holds that *j < *i is false. + */ + template + inline void + nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, + _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __nth); + __glibcxx_requires_valid_range(__nth, __last); + __glibcxx_requires_irreflexive(__first, __last); + + if (__first == __last || __nth == __last) + return; + + std::__introselect(__first, __nth, __last, + std::__lg(__last - __first) * 2, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Sort a sequence just enough to find a particular position + * using a predicate for comparison. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __nth Another iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return Nothing. + * + * Rearranges the elements in the range @p [__first,__last) so that @p *__nth + * is the same element that would have been in that position had the + * whole sequence been sorted. The elements either side of @p *__nth are + * not completely sorted, but for any iterator @e i in the range + * @p [__first,__nth) and any iterator @e j in the range @p [__nth,__last) it + * holds that @p __comp(*j,*i) is false. + */ + template + inline void + nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, + _RandomAccessIterator __last, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_RandomAccessIterator>::value_type, + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __nth); + __glibcxx_requires_valid_range(__nth, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + if (__first == __last || __nth == __last) + return; + + std::__introselect(__first, __nth, __last, + std::__lg(__last - __first) * 2, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + /** + * @brief Sort the elements of a sequence. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @return Nothing. + * + * Sorts the elements in the range @p [__first,__last) in ascending order, + * such that for each iterator @e i in the range @p [__first,__last-1), + * *(i+1)<*i is false. + * + * The relative ordering of equivalent elements is not preserved, use + * @p stable_sort() if this is needed. + */ + template + inline void + sort(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + std::__sort(__first, __last, __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Sort the elements of a sequence using a predicate for comparison. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return Nothing. + * + * Sorts the elements in the range @p [__first,__last) in ascending order, + * such that @p __comp(*(i+1),*i) is false for every iterator @e i in the + * range @p [__first,__last-1). + * + * The relative ordering of equivalent elements is not preserved, use + * @p stable_sort() if this is needed. + */ + template + inline void + sort(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_RandomAccessIterator>::value_type, + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + std::__sort(__first, __last, __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _OutputIterator + __merge(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (__comp(__first2, __first1)) + { + *__result = *__first2; + ++__first2; + } + else + { + *__result = *__first1; + ++__first1; + } + ++__result; + } + return std::copy(__first2, __last2, + std::copy(__first1, __last1, __result)); + } + + /** + * @brief Merges two sorted ranges. + * @ingroup sorting_algorithms + * @param __first1 An iterator. + * @param __first2 Another iterator. + * @param __last1 Another iterator. + * @param __last2 Another iterator. + * @param __result An iterator pointing to the end of the merged range. + * @return An iterator pointing to the first element not less + * than @e val. + * + * Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into + * the sorted range @p [__result, __result + (__last1-__first1) + + * (__last2-__first2)). Both input ranges must be sorted, and the + * output range must not overlap with either of the input ranges. + * The sort is @e stable, that is, for equivalent elements in the + * two ranges, elements from the first range will always come + * before elements from the second. + */ + template + inline _OutputIterator + merge(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return _GLIBCXX_STD_A::__merge(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Merges two sorted ranges. + * @ingroup sorting_algorithms + * @param __first1 An iterator. + * @param __first2 Another iterator. + * @param __last1 Another iterator. + * @param __last2 Another iterator. + * @param __result An iterator pointing to the end of the merged range. + * @param __comp A functor to use for comparisons. + * @return An iterator pointing to the first element "not less + * than" @e val. + * + * Merges the ranges @p [__first1,__last1) and @p [__first2,__last2) into + * the sorted range @p [__result, __result + (__last1-__first1) + + * (__last2-__first2)). Both input ranges must be sorted, and the + * output range must not overlap with either of the input ranges. + * The sort is @e stable, that is, for equivalent elements in the + * two ranges, elements from the first range will always come + * before elements from the second. + * + * The comparison function should have the same effects on ordering as + * the function used for the initial sort. + */ + template + inline _OutputIterator + merge(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return _GLIBCXX_STD_A::__merge(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + inline void + __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + typedef _Temporary_buffer<_RandomAccessIterator, _ValueType> _TmpBuf; + _TmpBuf __buf(__first, __last); + + if (__buf.begin() == 0) + std::__inplace_stable_sort(__first, __last, __comp); + else + std::__stable_sort_adaptive(__first, __last, __buf.begin(), + _DistanceType(__buf.size()), __comp); + } + + /** + * @brief Sort the elements of a sequence, preserving the relative order + * of equivalent elements. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @return Nothing. + * + * Sorts the elements in the range @p [__first,__last) in ascending order, + * such that for each iterator @p i in the range @p [__first,__last-1), + * @p *(i+1)<*i is false. + * + * The relative ordering of equivalent elements is preserved, so any two + * elements @p x and @p y in the range @p [__first,__last) such that + * @p x + inline void + stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + _GLIBCXX_STD_A::__stable_sort(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Sort the elements of a sequence using a predicate for comparison, + * preserving the relative order of equivalent elements. + * @ingroup sorting_algorithms + * @param __first An iterator. + * @param __last Another iterator. + * @param __comp A comparison functor. + * @return Nothing. + * + * Sorts the elements in the range @p [__first,__last) in ascending order, + * such that for each iterator @p i in the range @p [__first,__last-1), + * @p __comp(*(i+1),*i) is false. + * + * The relative ordering of equivalent elements is preserved, so any two + * elements @p x and @p y in the range @p [__first,__last) such that + * @p __comp(x,y) is false and @p __comp(y,x) is false will have the same + * relative ordering after calling @p stable_sort(). + */ + template + inline void + stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_RandomAccessIterator>::value_type, + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + _GLIBCXX_STD_A::__stable_sort(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _OutputIterator + __set_union(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (__comp(__first1, __first2)) + { + *__result = *__first1; + ++__first1; + } + else if (__comp(__first2, __first1)) + { + *__result = *__first2; + ++__first2; + } + else + { + *__result = *__first1; + ++__first1; + ++__first2; + } + ++__result; + } + return std::copy(__first2, __last2, + std::copy(__first1, __last1, __result)); + } + + /** + * @brief Return the union of two sorted ranges. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * each range in order to the output range. Iterators increment for each + * range. When the current element of one range is less than the other, + * that element is copied and the iterator advanced. If an element is + * contained in both ranges, the element from the first range is copied and + * both ranges advance. The output range may not overlap either input + * range. + */ + template + inline _OutputIterator + set_union(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return _GLIBCXX_STD_A::__set_union(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the union of two sorted ranges using a comparison functor. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @param __comp The comparison functor. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * each range in order to the output range. Iterators increment for each + * range. When the current element of one range is less than the other + * according to @p __comp, that element is copied and the iterator advanced. + * If an equivalent element according to @p __comp is contained in both + * ranges, the element from the first range is copied and both ranges + * advance. The output range may not overlap either input range. + */ + template + inline _OutputIterator + set_union(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return _GLIBCXX_STD_A::__set_union(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _OutputIterator + __set_intersection(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + if (__comp(__first1, __first2)) + ++__first1; + else if (__comp(__first2, __first1)) + ++__first2; + else + { + *__result = *__first1; + ++__first1; + ++__first2; + ++__result; + } + return __result; + } + + /** + * @brief Return the intersection of two sorted ranges. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * both ranges in order to the output range. Iterators increment for each + * range. When the current element of one range is less than the other, + * that iterator advances. If an element is contained in both ranges, the + * element from the first range is copied and both ranges advance. The + * output range may not overlap either input range. + */ + template + inline _OutputIterator + set_intersection(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return _GLIBCXX_STD_A::__set_intersection(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the intersection of two sorted ranges using comparison + * functor. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @param __comp The comparison functor. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * both ranges in order to the output range. Iterators increment for each + * range. When the current element of one range is less than the other + * according to @p __comp, that iterator advances. If an element is + * contained in both ranges according to @p __comp, the element from the + * first range is copied and both ranges advance. The output range may not + * overlap either input range. + */ + template + inline _OutputIterator + set_intersection(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return _GLIBCXX_STD_A::__set_intersection(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _OutputIterator + __set_difference(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + if (__comp(__first1, __first2)) + { + *__result = *__first1; + ++__first1; + ++__result; + } + else if (__comp(__first2, __first1)) + ++__first2; + else + { + ++__first1; + ++__first2; + } + return std::copy(__first1, __last1, __result); + } + + /** + * @brief Return the difference of two sorted ranges. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * the first range but not the second in order to the output range. + * Iterators increment for each range. When the current element of the + * first range is less than the second, that element is copied and the + * iterator advances. If the current element of the second range is less, + * the iterator advances, but no element is copied. If an element is + * contained in both ranges, no elements are copied and both ranges + * advance. The output range may not overlap either input range. + */ + template + inline _OutputIterator + set_difference(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return _GLIBCXX_STD_A::__set_difference(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the difference of two sorted ranges using comparison + * functor. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @param __comp The comparison functor. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * the first range but not the second in order to the output range. + * Iterators increment for each range. When the current element of the + * first range is less than the second according to @p __comp, that element + * is copied and the iterator advances. If the current element of the + * second range is less, no element is copied and the iterator advances. + * If an element is contained in both ranges according to @p __comp, no + * elements are copied and both ranges advance. The output range may not + * overlap either input range. + */ + template + inline _OutputIterator + set_difference(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return _GLIBCXX_STD_A::__set_difference(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _OutputIterator + __set_symmetric_difference(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) + { + while (__first1 != __last1 && __first2 != __last2) + if (__comp(__first1, __first2)) + { + *__result = *__first1; + ++__first1; + ++__result; + } + else if (__comp(__first2, __first1)) + { + *__result = *__first2; + ++__first2; + ++__result; + } + else + { + ++__first1; + ++__first2; + } + return std::copy(__first2, __last2, + std::copy(__first1, __last1, __result)); + } + + /** + * @brief Return the symmetric difference of two sorted ranges. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * one range but not the other in order to the output range. Iterators + * increment for each range. When the current element of one range is less + * than the other, that element is copied and the iterator advances. If an + * element is contained in both ranges, no elements are copied and both + * ranges advance. The output range may not overlap either input range. + */ + template + inline _OutputIterator + set_symmetric_difference(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set(__first1, __last1, __first2); + __glibcxx_requires_sorted_set(__first2, __last2, __first1); + __glibcxx_requires_irreflexive2(__first1, __last1); + __glibcxx_requires_irreflexive2(__first2, __last2); + + return _GLIBCXX_STD_A::__set_symmetric_difference(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the symmetric difference of two sorted ranges using + * comparison functor. + * @ingroup set_algorithms + * @param __first1 Start of first range. + * @param __last1 End of first range. + * @param __first2 Start of second range. + * @param __last2 End of second range. + * @param __comp The comparison functor. + * @return End of the output range. + * @ingroup set_algorithms + * + * This operation iterates over both ranges, copying elements present in + * one range but not the other in order to the output range. Iterators + * increment for each range. When the current element of one range is less + * than the other according to @p comp, that element is copied and the + * iterator advances. If an element is contained in both ranges according + * to @p __comp, no elements are copied and both ranges advance. The output + * range may not overlap either input range. + */ + template + inline _OutputIterator + set_symmetric_difference(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _OutputIterator __result, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_InputIterator2>::value_type, + typename iterator_traits<_InputIterator1>::value_type>) + __glibcxx_requires_sorted_set_pred(__first1, __last1, __first2, __comp); + __glibcxx_requires_sorted_set_pred(__first2, __last2, __first1, __comp); + __glibcxx_requires_irreflexive_pred2(__first1, __last1, __comp); + __glibcxx_requires_irreflexive_pred2(__first2, __last2, __comp); + + return _GLIBCXX_STD_A::__set_symmetric_difference(__first1, __last1, + __first2, __last2, __result, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _GLIBCXX14_CONSTEXPR + _ForwardIterator + __min_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + if (__first == __last) + return __first; + _ForwardIterator __result = __first; + while (++__first != __last) + if (__comp(__first, __result)) + __result = __first; + return __result; + } + + /** + * @brief Return the minimum element in a range. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @return Iterator referencing the first instance of the smallest value. + */ + template + _GLIBCXX14_CONSTEXPR + _ForwardIterator + inline min_element(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return _GLIBCXX_STD_A::__min_element(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the minimum element in a range using comparison functor. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @param __comp Comparison functor. + * @return Iterator referencing the first instance of the smallest value + * according to __comp. + */ + template + _GLIBCXX14_CONSTEXPR + inline _ForwardIterator + min_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return _GLIBCXX_STD_A::__min_element(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + _GLIBCXX14_CONSTEXPR + _ForwardIterator + __max_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + if (__first == __last) return __first; + _ForwardIterator __result = __first; + while (++__first != __last) + if (__comp(__result, __first)) + __result = __first; + return __result; + } + + /** + * @brief Return the maximum element in a range. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @return Iterator referencing the first instance of the largest value. + */ + template + _GLIBCXX14_CONSTEXPR + inline _ForwardIterator + max_element(_ForwardIterator __first, _ForwardIterator __last) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + return _GLIBCXX_STD_A::__max_element(__first, __last, + __gnu_cxx::__ops::__iter_less_iter()); + } + + /** + * @brief Return the maximum element in a range using comparison functor. + * @ingroup sorting_algorithms + * @param __first Start of range. + * @param __last End of range. + * @param __comp Comparison functor. + * @return Iterator referencing the first instance of the largest value + * according to __comp. + */ + template + _GLIBCXX14_CONSTEXPR + inline _ForwardIterator + max_element(_ForwardIterator __first, _ForwardIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_BinaryPredicateConcept<_Compare, + typename iterator_traits<_ForwardIterator>::value_type, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + return _GLIBCXX_STD_A::__max_element(__first, __last, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + +#if __cplusplus >= 201402L + /// Reservoir sampling algorithm. + template + _RandomAccessIterator + __sample(_InputIterator __first, _InputIterator __last, input_iterator_tag, + _RandomAccessIterator __out, random_access_iterator_tag, + _Size __n, _UniformRandomBitGenerator&& __g) + { + using __distrib_type = uniform_int_distribution<_Size>; + using __param_type = typename __distrib_type::param_type; + __distrib_type __d{}; + _Size __sample_sz = 0; + while (__first != __last && __sample_sz != __n) + { + __out[__sample_sz++] = *__first; + ++__first; + } + for (auto __pop_sz = __sample_sz; __first != __last; + ++__first, (void) ++__pop_sz) + { + const auto __k = __d(__g, __param_type{0, __pop_sz}); + if (__k < __n) + __out[__k] = *__first; + } + return __out + __sample_sz; + } + + /// Selection sampling algorithm. + template + _OutputIterator + __sample(_ForwardIterator __first, _ForwardIterator __last, + forward_iterator_tag, + _OutputIterator __out, _Cat, + _Size __n, _UniformRandomBitGenerator&& __g) + { + using __distrib_type = uniform_int_distribution<_Size>; + using __param_type = typename __distrib_type::param_type; + using _USize = make_unsigned_t<_Size>; + using _Gen = remove_reference_t<_UniformRandomBitGenerator>; + using __uc_type = common_type_t; + + __distrib_type __d{}; + _Size __unsampled_sz = std::distance(__first, __last); + __n = std::min(__n, __unsampled_sz); + + // If possible, we use __gen_two_uniform_ints to efficiently produce + // two random numbers using a single distribution invocation: + + const __uc_type __urngrange = __g.max() - __g.min(); + if (__urngrange / __uc_type(__unsampled_sz) >= __uc_type(__unsampled_sz)) + // I.e. (__urngrange >= __unsampled_sz * __unsampled_sz) but without + // wrapping issues. + { + while (__n != 0 && __unsampled_sz >= 2) + { + const pair<_Size, _Size> __p = + __gen_two_uniform_ints(__unsampled_sz, __unsampled_sz - 1, __g); + + --__unsampled_sz; + if (__p.first < __n) + { + *__out++ = *__first; + --__n; + } + + ++__first; + + if (__n == 0) break; + + --__unsampled_sz; + if (__p.second < __n) + { + *__out++ = *__first; + --__n; + } + + ++__first; + } + } + + // The loop above is otherwise equivalent to this one-at-a-time version: + + for (; __n != 0; ++__first) + if (__d(__g, __param_type{0, --__unsampled_sz}) < __n) + { + *__out++ = *__first; + --__n; + } + return __out; + } + +#if __cplusplus > 201402L +#define __cpp_lib_sample 201603 + /// Take a random sample from a population. + template + _SampleIterator + sample(_PopulationIterator __first, _PopulationIterator __last, + _SampleIterator __out, _Distance __n, + _UniformRandomBitGenerator&& __g) + { + using __pop_cat = typename + std::iterator_traits<_PopulationIterator>::iterator_category; + using __samp_cat = typename + std::iterator_traits<_SampleIterator>::iterator_category; + + static_assert( + __or_, + is_convertible<__samp_cat, random_access_iterator_tag>>::value, + "output range must use a RandomAccessIterator when input range" + " does not meet the ForwardIterator requirements"); + + static_assert(is_integral<_Distance>::value, + "sample size must be an integer type"); + + typename iterator_traits<_PopulationIterator>::difference_type __d = __n; + return _GLIBCXX_STD_A:: + __sample(__first, __last, __pop_cat{}, __out, __samp_cat{}, __d, + std::forward<_UniformRandomBitGenerator>(__g)); + } +#endif // C++17 +#endif // C++14 + +_GLIBCXX_END_NAMESPACE_ALGO +} // namespace std + +#endif /* _STL_ALGO_H */ diff --git a/AH/STL/Fallback/bits/stl_algobase.h b/AH/STL/Fallback/bits/stl_algobase.h new file mode 100644 index 0000000..ee07ccc --- /dev/null +++ b/AH/STL/Fallback/bits/stl_algobase.h @@ -0,0 +1,1423 @@ +// Core algorithmic facilities -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_algobase.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{algorithm} + */ + +#ifndef _STL_ALGOBASE_H +#define _STL_ALGOBASE_H 1 + +#include "../bits/c++config.h" +// #include +#include "../bits/cpp_type_traits.h" +#include "../ext/type_traits.h" +#include "../ext/numeric_traits.h" +#include "../bits/stl_pair.h" +#include "../bits/stl_iterator_base_types.h" +#include "../bits/stl_iterator_base_funcs.h" +#include "../bits/stl_iterator.h" +#include "../bits/concept_check.h" +#include "../debug/debug.h" +#include "../bits/move.h" // For std::swap and _GLIBCXX_MOVE +#include "../bits/predefined_ops.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if __cplusplus < 201103L + // See http://gcc.gnu.org/ml/libstdc++/2004-08/msg00167.html: in a + // nutshell, we are partially implementing the resolution of DR 187, + // when it's safe, i.e., the value_types are equal. + template + struct __iter_swap + { + template + static void + iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) + { + typedef typename iterator_traits<_ForwardIterator1>::value_type + _ValueType1; + _ValueType1 __tmp = _GLIBCXX_MOVE(*__a); + *__a = _GLIBCXX_MOVE(*__b); + *__b = _GLIBCXX_MOVE(__tmp); + } + }; + + template<> + struct __iter_swap + { + template + static void + iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) + { + swap(*__a, *__b); + } + }; +#endif + + /** + * @brief Swaps the contents of two iterators. + * @ingroup mutating_algorithms + * @param __a An iterator. + * @param __b Another iterator. + * @return Nothing. + * + * This function swaps the values pointed to by two iterators, not the + * iterators themselves. + */ + template + inline void + iter_swap(_ForwardIterator1 __a, _ForwardIterator2 __b) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator1>) + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator2>) + +#if __cplusplus < 201103L + typedef typename iterator_traits<_ForwardIterator1>::value_type + _ValueType1; + typedef typename iterator_traits<_ForwardIterator2>::value_type + _ValueType2; + + __glibcxx_function_requires(_ConvertibleConcept<_ValueType1, + _ValueType2>) + __glibcxx_function_requires(_ConvertibleConcept<_ValueType2, + _ValueType1>) + + typedef typename iterator_traits<_ForwardIterator1>::reference + _ReferenceType1; + typedef typename iterator_traits<_ForwardIterator2>::reference + _ReferenceType2; + std::__iter_swap<__are_same<_ValueType1, _ValueType2>::__value + && __are_same<_ValueType1&, _ReferenceType1>::__value + && __are_same<_ValueType2&, _ReferenceType2>::__value>:: + iter_swap(__a, __b); +#else + swap(*__a, *__b); +#endif + } + + /** + * @brief Swap the elements of two sequences. + * @ingroup mutating_algorithms + * @param __first1 A forward iterator. + * @param __last1 A forward iterator. + * @param __first2 A forward iterator. + * @return An iterator equal to @p first2+(last1-first1). + * + * Swaps each element in the range @p [first1,last1) with the + * corresponding element in the range @p [first2,(last1-first1)). + * The ranges must not overlap. + */ + template + _ForwardIterator2 + swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, + _ForwardIterator2 __first2) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator1>) + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator2>) + __glibcxx_requires_valid_range(__first1, __last1); + + for (; __first1 != __last1; ++__first1, (void)++__first2) + std::iter_swap(__first1, __first2); + return __first2; + } + + /** + * @brief This does what you think it does. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @return The lesser of the parameters. + * + * This is the simple classic generic implementation. It will work on + * temporary expressions, since they are only evaluated once, unlike a + * preprocessor macro. + */ + template + _GLIBCXX14_CONSTEXPR + inline const _Tp& + min(const _Tp& __a, const _Tp& __b) + { + // concept requirements + __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) + //return __b < __a ? __b : __a; + if (__b < __a) + return __b; + return __a; + } + + /** + * @brief This does what you think it does. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @return The greater of the parameters. + * + * This is the simple classic generic implementation. It will work on + * temporary expressions, since they are only evaluated once, unlike a + * preprocessor macro. + */ + template + _GLIBCXX14_CONSTEXPR + inline const _Tp& + max(const _Tp& __a, const _Tp& __b) + { + // concept requirements + __glibcxx_function_requires(_LessThanComparableConcept<_Tp>) + //return __a < __b ? __b : __a; + if (__a < __b) + return __b; + return __a; + } + + /** + * @brief This does what you think it does. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @param __comp A @link comparison_functors comparison functor@endlink. + * @return The lesser of the parameters. + * + * This will work on temporary expressions, since they are only evaluated + * once, unlike a preprocessor macro. + */ + template + _GLIBCXX14_CONSTEXPR + inline const _Tp& + min(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + //return __comp(__b, __a) ? __b : __a; + if (__comp(__b, __a)) + return __b; + return __a; + } + + /** + * @brief This does what you think it does. + * @ingroup sorting_algorithms + * @param __a A thing of arbitrary type. + * @param __b Another thing of arbitrary type. + * @param __comp A @link comparison_functors comparison functor@endlink. + * @return The greater of the parameters. + * + * This will work on temporary expressions, since they are only evaluated + * once, unlike a preprocessor macro. + */ + template + _GLIBCXX14_CONSTEXPR + inline const _Tp& + max(const _Tp& __a, const _Tp& __b, _Compare __comp) + { + //return __comp(__a, __b) ? __b : __a; + if (__comp(__a, __b)) + return __b; + return __a; + } + + // Fallback implementation of the function in bits/stl_iterator.h used to + // remove the __normal_iterator wrapper. See copy, fill, ... + template + inline _Iterator + __niter_base(_Iterator __it) + { return __it; } + + // All of these auxiliary structs serve two purposes. (1) Replace + // calls to copy with memmove whenever possible. (Memmove, not memcpy, + // because the input and output ranges are permitted to overlap.) + // (2) If we're using random access iterators, then write the loop as + // a for loop with an explicit count. + + template + struct __copy_move + { + template + static _OI + __copy_m(_II __first, _II __last, _OI __result) + { + for (; __first != __last; ++__result, (void)++__first) + *__result = *__first; + return __result; + } + }; + +#if __cplusplus >= 201103L + template + struct __copy_move + { + template + static _OI + __copy_m(_II __first, _II __last, _OI __result) + { + for (; __first != __last; ++__result, (void)++__first) + *__result = std::move(*__first); + return __result; + } + }; +#endif + + template<> + struct __copy_move + { + template + static _OI + __copy_m(_II __first, _II __last, _OI __result) + { + typedef typename iterator_traits<_II>::difference_type _Distance; + for(_Distance __n = __last - __first; __n > 0; --__n) + { + *__result = *__first; + ++__first; + ++__result; + } + return __result; + } + }; + +#if __cplusplus >= 201103L + template<> + struct __copy_move + { + template + static _OI + __copy_m(_II __first, _II __last, _OI __result) + { + typedef typename iterator_traits<_II>::difference_type _Distance; + for(_Distance __n = __last - __first; __n > 0; --__n) + { + *__result = std::move(*__first); + ++__first; + ++__result; + } + return __result; + } + }; +#endif + + template + struct __copy_move<_IsMove, true, random_access_iterator_tag> + { + template + static _Tp* + __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result) + { +#if __cplusplus >= 201103L + using __assignable = conditional<_IsMove, + is_move_assignable<_Tp>, + is_copy_assignable<_Tp>>; + // trivial types can have deleted assignment + static_assert( __assignable::type::value, "type is not assignable" ); +#endif + const ptrdiff_t _Num = __last - __first; + if (_Num) + __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); + return __result + _Num; + } + }; + + template + inline _OI + __copy_move_a(_II __first, _II __last, _OI __result) + { + typedef typename iterator_traits<_II>::value_type _ValueTypeI; + typedef typename iterator_traits<_OI>::value_type _ValueTypeO; + typedef typename iterator_traits<_II>::iterator_category _Category; + const bool __simple = (__is_trivial(_ValueTypeI) + && __is_pointer<_II>::__value + && __is_pointer<_OI>::__value + && __are_same<_ValueTypeI, _ValueTypeO>::__value); + + return std::__copy_move<_IsMove, __simple, + _Category>::__copy_m(__first, __last, __result); + } + + // Helpers for streambuf iterators (either istream or ostream). + // NB: avoid including , relatively large. + template + struct char_traits; + + template + class istreambuf_iterator; + + template + class ostreambuf_iterator; + + template + typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, + ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type + __copy_move_a2(_CharT*, _CharT*, + ostreambuf_iterator<_CharT, char_traits<_CharT> >); + + template + typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, + ostreambuf_iterator<_CharT, char_traits<_CharT> > >::__type + __copy_move_a2(const _CharT*, const _CharT*, + ostreambuf_iterator<_CharT, char_traits<_CharT> >); + + template + typename __gnu_cxx::__enable_if<__is_char<_CharT>::__value, + _CharT*>::__type + __copy_move_a2(istreambuf_iterator<_CharT, char_traits<_CharT> >, + istreambuf_iterator<_CharT, char_traits<_CharT> >, _CharT*); + + template + inline _OI + __copy_move_a2(_II __first, _II __last, _OI __result) + { + return _OI(std::__copy_move_a<_IsMove>(std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result))); + } + + /** + * @brief Copies the range [first,last) into result. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @return result + (first - last) + * + * This inline function will boil down to a call to @c memmove whenever + * possible. Failing that, if random access iterators are passed, then the + * loop count will be known (and therefore a candidate for compiler + * optimizations such as unrolling). Result may not be contained within + * [first,last); the copy_backward function should be used instead. + * + * Note that the end of the output range is permitted to be contained + * within [first,last). + */ + template + inline _OI + copy(_II __first, _II __last, _OI __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_II>) + __glibcxx_function_requires(_OutputIteratorConcept<_OI, + typename iterator_traits<_II>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return (std::__copy_move_a2<__is_move_iterator<_II>::__value> + (std::__miter_base(__first), std::__miter_base(__last), + __result)); + } + +#if __cplusplus >= 201103L + /** + * @brief Moves the range [first,last) into result. + * @ingroup mutating_algorithms + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @return result + (first - last) + * + * This inline function will boil down to a call to @c memmove whenever + * possible. Failing that, if random access iterators are passed, then the + * loop count will be known (and therefore a candidate for compiler + * optimizations such as unrolling). Result may not be contained within + * [first,last); the move_backward function should be used instead. + * + * Note that the end of the output range is permitted to be contained + * within [first,last). + */ + template + inline _OI + move(_II __first, _II __last, _OI __result) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_II>) + __glibcxx_function_requires(_OutputIteratorConcept<_OI, + typename iterator_traits<_II>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__copy_move_a2(std::__miter_base(__first), + std::__miter_base(__last), __result); + } + +#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::move(_Tp, _Up, _Vp) +#else +#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp) +#endif + + template + struct __copy_move_backward + { + template + static _BI2 + __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) + { + while (__first != __last) + *--__result = *--__last; + return __result; + } + }; + +#if __cplusplus >= 201103L + template + struct __copy_move_backward + { + template + static _BI2 + __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) + { + while (__first != __last) + *--__result = std::move(*--__last); + return __result; + } + }; +#endif + + template<> + struct __copy_move_backward + { + template + static _BI2 + __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) + { + typename iterator_traits<_BI1>::difference_type __n; + for (__n = __last - __first; __n > 0; --__n) + *--__result = *--__last; + return __result; + } + }; + +#if __cplusplus >= 201103L + template<> + struct __copy_move_backward + { + template + static _BI2 + __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result) + { + typename iterator_traits<_BI1>::difference_type __n; + for (__n = __last - __first; __n > 0; --__n) + *--__result = std::move(*--__last); + return __result; + } + }; +#endif + + template + struct __copy_move_backward<_IsMove, true, random_access_iterator_tag> + { + template + static _Tp* + __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result) + { +#if __cplusplus >= 201103L + using __assignable = conditional<_IsMove, + is_move_assignable<_Tp>, + is_copy_assignable<_Tp>>; + // trivial types can have deleted assignment + static_assert( __assignable::type::value, "type is not assignable" ); +#endif + const ptrdiff_t _Num = __last - __first; + if (_Num) + __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num); + return __result - _Num; + } + }; + + template + inline _BI2 + __copy_move_backward_a(_BI1 __first, _BI1 __last, _BI2 __result) + { + typedef typename iterator_traits<_BI1>::value_type _ValueType1; + typedef typename iterator_traits<_BI2>::value_type _ValueType2; + typedef typename iterator_traits<_BI1>::iterator_category _Category; + const bool __simple = (__is_trivial(_ValueType1) + && __is_pointer<_BI1>::__value + && __is_pointer<_BI2>::__value + && __are_same<_ValueType1, _ValueType2>::__value); + + return std::__copy_move_backward<_IsMove, __simple, + _Category>::__copy_move_b(__first, + __last, + __result); + } + + template + inline _BI2 + __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result) + { + return _BI2(std::__copy_move_backward_a<_IsMove> + (std::__niter_base(__first), std::__niter_base(__last), + std::__niter_base(__result))); + } + + /** + * @brief Copies the range [first,last) into result. + * @ingroup mutating_algorithms + * @param __first A bidirectional iterator. + * @param __last A bidirectional iterator. + * @param __result A bidirectional iterator. + * @return result - (first - last) + * + * The function has the same effect as copy, but starts at the end of the + * range and works its way to the start, returning the start of the result. + * This inline function will boil down to a call to @c memmove whenever + * possible. Failing that, if random access iterators are passed, then the + * loop count will be known (and therefore a candidate for compiler + * optimizations such as unrolling). + * + * Result may not be in the range (first,last]. Use copy instead. Note + * that the start of the output range may overlap [first,last). + */ + template + inline _BI2 + copy_backward(_BI1 __first, _BI1 __last, _BI2 __result) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) + __glibcxx_function_requires(_ConvertibleConcept< + typename iterator_traits<_BI1>::value_type, + typename iterator_traits<_BI2>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return (std::__copy_move_backward_a2<__is_move_iterator<_BI1>::__value> + (std::__miter_base(__first), std::__miter_base(__last), + __result)); + } + +#if __cplusplus >= 201103L + /** + * @brief Moves the range [first,last) into result. + * @ingroup mutating_algorithms + * @param __first A bidirectional iterator. + * @param __last A bidirectional iterator. + * @param __result A bidirectional iterator. + * @return result - (first - last) + * + * The function has the same effect as move, but starts at the end of the + * range and works its way to the start, returning the start of the result. + * This inline function will boil down to a call to @c memmove whenever + * possible. Failing that, if random access iterators are passed, then the + * loop count will be known (and therefore a candidate for compiler + * optimizations such as unrolling). + * + * Result may not be in the range (first,last]. Use move instead. Note + * that the start of the output range may overlap [first,last). + */ + template + inline _BI2 + move_backward(_BI1 __first, _BI1 __last, _BI2 __result) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept<_BI1>) + __glibcxx_function_requires(_Mutable_BidirectionalIteratorConcept<_BI2>) + __glibcxx_function_requires(_ConvertibleConcept< + typename iterator_traits<_BI1>::value_type, + typename iterator_traits<_BI2>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + return std::__copy_move_backward_a2(std::__miter_base(__first), + std::__miter_base(__last), + __result); + } + +#define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::move_backward(_Tp, _Up, _Vp) +#else +#define _GLIBCXX_MOVE_BACKWARD3(_Tp, _Up, _Vp) std::copy_backward(_Tp, _Up, _Vp) +#endif + + template + inline typename + __gnu_cxx::__enable_if::__value, void>::__type + __fill_a(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __value) + { + for (; __first != __last; ++__first) + *__first = __value; + } + + template + inline typename + __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, void>::__type + __fill_a(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __value) + { + const _Tp __tmp = __value; + for (; __first != __last; ++__first) + *__first = __tmp; + } + + // Specialization: for char types we can use memset. + template + inline typename + __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, void>::__type + __fill_a(_Tp* __first, _Tp* __last, const _Tp& __c) + { + const _Tp __tmp = __c; + if (const size_t __len = __last - __first) + __builtin_memset(__first, static_cast(__tmp), __len); + } + + /** + * @brief Fills the range [first,last) with copies of value. + * @ingroup mutating_algorithms + * @param __first A forward iterator. + * @param __last A forward iterator. + * @param __value A reference-to-const of arbitrary type. + * @return Nothing. + * + * This function fills a range with copies of the same value. For char + * types filling contiguous areas of memory, this becomes an inline call + * to @c memset or @c wmemset. + */ + template + inline void + fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_requires_valid_range(__first, __last); + + std::__fill_a(std::__niter_base(__first), std::__niter_base(__last), + __value); + } + + template + inline typename + __gnu_cxx::__enable_if::__value, _OutputIterator>::__type + __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) + { + for (__decltype(__n + 0) __niter = __n; + __niter > 0; --__niter, ++__first) + *__first = __value; + return __first; + } + + template + inline typename + __gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type + __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value) + { + const _Tp __tmp = __value; + for (__decltype(__n + 0) __niter = __n; + __niter > 0; --__niter, ++__first) + *__first = __tmp; + return __first; + } + + template + inline typename + __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, _Tp*>::__type + __fill_n_a(_Tp* __first, _Size __n, const _Tp& __c) + { + std::__fill_a(__first, __first + __n, __c); + return __first + __n; + } + + /** + * @brief Fills the range [first,first+n) with copies of value. + * @ingroup mutating_algorithms + * @param __first An output iterator. + * @param __n The count of copies to perform. + * @param __value A reference-to-const of arbitrary type. + * @return The iterator at first+n. + * + * This function fills a range with copies of the same value. For char + * types filling contiguous areas of memory, this becomes an inline call + * to @c memset or @ wmemset. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 865. More algorithms that throw away information + */ + template + inline _OI + fill_n(_OI __first, _Size __n, const _Tp& __value) + { + // concept requirements + __glibcxx_function_requires(_OutputIteratorConcept<_OI, _Tp>) + + return _OI(std::__fill_n_a(std::__niter_base(__first), __n, __value)); + } + + template + struct __equal + { + template + static bool + equal(_II1 __first1, _II1 __last1, _II2 __first2) + { + for (; __first1 != __last1; ++__first1, (void)++__first2) + if (!(*__first1 == *__first2)) + return false; + return true; + } + }; + + template<> + struct __equal + { + template + static bool + equal(const _Tp* __first1, const _Tp* __last1, const _Tp* __first2) + { + if (const size_t __len = (__last1 - __first1)) + return !__builtin_memcmp(__first1, __first2, sizeof(_Tp) * __len); + return true; + } + }; + + template + inline bool + __equal_aux(_II1 __first1, _II1 __last1, _II2 __first2) + { + typedef typename iterator_traits<_II1>::value_type _ValueType1; + typedef typename iterator_traits<_II2>::value_type _ValueType2; + const bool __simple = ((__is_integer<_ValueType1>::__value + || __is_pointer<_ValueType1>::__value) + && __is_pointer<_II1>::__value + && __is_pointer<_II2>::__value + && __are_same<_ValueType1, _ValueType2>::__value); + + return std::__equal<__simple>::equal(__first1, __last1, __first2); + } + + template + struct __lc_rai + { + template + static _II1 + __newlast1(_II1, _II1 __last1, _II2, _II2) + { return __last1; } + + template + static bool + __cnd2(_II __first, _II __last) + { return __first != __last; } + }; + + template<> + struct __lc_rai + { + template + static _RAI1 + __newlast1(_RAI1 __first1, _RAI1 __last1, + _RAI2 __first2, _RAI2 __last2) + { + const typename iterator_traits<_RAI1>::difference_type + __diff1 = __last1 - __first1; + const typename iterator_traits<_RAI2>::difference_type + __diff2 = __last2 - __first2; + return __diff2 < __diff1 ? __first1 + __diff2 : __last1; + } + + template + static bool + __cnd2(_RAI, _RAI) + { return true; } + }; + + template + bool + __lexicographical_compare_impl(_II1 __first1, _II1 __last1, + _II2 __first2, _II2 __last2, + _Compare __comp) + { + typedef typename iterator_traits<_II1>::iterator_category _Category1; + typedef typename iterator_traits<_II2>::iterator_category _Category2; + typedef std::__lc_rai<_Category1, _Category2> __rai_type; + + __last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2); + for (; __first1 != __last1 && __rai_type::__cnd2(__first2, __last2); + ++__first1, (void)++__first2) + { + if (__comp(__first1, __first2)) + return true; + if (__comp(__first2, __first1)) + return false; + } + return __first1 == __last1 && __first2 != __last2; + } + + template + struct __lexicographical_compare + { + template + static bool __lc(_II1, _II1, _II2, _II2); + }; + + template + template + bool + __lexicographical_compare<_BoolType>:: + __lc(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) + { + return std::__lexicographical_compare_impl(__first1, __last1, + __first2, __last2, + __gnu_cxx::__ops::__iter_less_iter()); + } + + template<> + struct __lexicographical_compare + { + template + static bool + __lc(const _Tp* __first1, const _Tp* __last1, + const _Up* __first2, const _Up* __last2) + { + const size_t __len1 = __last1 - __first1; + const size_t __len2 = __last2 - __first2; + if (const size_t __len = std::min(__len1, __len2)) + if (int __result = __builtin_memcmp(__first1, __first2, __len)) + return __result < 0; + return __len1 < __len2; + } + }; + + template + inline bool + __lexicographical_compare_aux(_II1 __first1, _II1 __last1, + _II2 __first2, _II2 __last2) + { + typedef typename iterator_traits<_II1>::value_type _ValueType1; + typedef typename iterator_traits<_II2>::value_type _ValueType2; + const bool __simple = + (__is_byte<_ValueType1>::__value && __is_byte<_ValueType2>::__value + && !__gnu_cxx::__numeric_traits<_ValueType1>::__is_signed + && !__gnu_cxx::__numeric_traits<_ValueType2>::__is_signed + && __is_pointer<_II1>::__value + && __is_pointer<_II2>::__value); + + return std::__lexicographical_compare<__simple>::__lc(__first1, __last1, + __first2, __last2); + } + + template + _ForwardIterator + __lower_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val, _Compare __comp) + { + typedef typename iterator_traits<_ForwardIterator>::difference_type + _DistanceType; + + _DistanceType __len = std::distance(__first, __last); + + while (__len > 0) + { + _DistanceType __half = __len >> 1; + _ForwardIterator __middle = __first; + std::advance(__middle, __half); + if (__comp(__middle, __val)) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else + __len = __half; + } + return __first; + } + + /** + * @brief Finds the first position in which @a val could be inserted + * without changing the ordering. + * @param __first An iterator. + * @param __last Another iterator. + * @param __val The search term. + * @return An iterator pointing to the first element not less + * than @a val, or end() if every element is less than + * @a val. + * @ingroup binary_search_algorithms + */ + template + inline _ForwardIterator + lower_bound(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __val) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + __glibcxx_function_requires(_LessThanOpConcept< + typename iterator_traits<_ForwardIterator>::value_type, _Tp>) + __glibcxx_requires_partitioned_lower(__first, __last, __val); + + return std::__lower_bound(__first, __last, __val, + __gnu_cxx::__ops::__iter_less_val()); + } + + /// This is a helper function for the sort routines and for random.tcc. + // Precondition: __n > 0. + inline _GLIBCXX_CONSTEXPR int + __lg(int __n) + { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } + + inline _GLIBCXX_CONSTEXPR unsigned + __lg(unsigned __n) + { return sizeof(int) * __CHAR_BIT__ - 1 - __builtin_clz(__n); } + + inline _GLIBCXX_CONSTEXPR long + __lg(long __n) + { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } + + inline _GLIBCXX_CONSTEXPR unsigned long + __lg(unsigned long __n) + { return sizeof(long) * __CHAR_BIT__ - 1 - __builtin_clzl(__n); } + + inline _GLIBCXX_CONSTEXPR long long + __lg(long long __n) + { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } + + inline _GLIBCXX_CONSTEXPR unsigned long long + __lg(unsigned long long __n) + { return sizeof(long long) * __CHAR_BIT__ - 1 - __builtin_clzll(__n); } + +_GLIBCXX_END_NAMESPACE_VERSION + +_GLIBCXX_BEGIN_NAMESPACE_ALGO + + /** + * @brief Tests a range for element-wise equality. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @return A boolean true or false. + * + * This compares the elements of two ranges using @c == and returns true or + * false depending on whether all of the corresponding elements of the + * ranges are equal. + */ + template + inline bool + equal(_II1 __first1, _II1 __last1, _II2 __first2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_II1>) + __glibcxx_function_requires(_InputIteratorConcept<_II2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_II1>::value_type, + typename iterator_traits<_II2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + + return std::__equal_aux(std::__niter_base(__first1), + std::__niter_base(__last1), + std::__niter_base(__first2)); + } + + /** + * @brief Tests a range for element-wise equality. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __binary_pred A binary predicate @link functors + * functor@endlink. + * @return A boolean true or false. + * + * This compares the elements of two ranges using the binary_pred + * parameter, and returns true or + * false depending on whether all of the corresponding elements of the + * ranges are equal. + */ + template + inline bool + equal(_IIter1 __first1, _IIter1 __last1, + _IIter2 __first2, _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) + __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) + __glibcxx_requires_valid_range(__first1, __last1); + + for (; __first1 != __last1; ++__first1, (void)++__first2) + if (!bool(__binary_pred(*__first1, *__first2))) + return false; + return true; + } + +#if __cplusplus > 201103L + +#define __cpp_lib_robust_nonmodifying_seq_ops 201304 + + /** + * @brief Tests a range for element-wise equality. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @return A boolean true or false. + * + * This compares the elements of two ranges using @c == and returns true or + * false depending on whether all of the corresponding elements of the + * ranges are equal. + */ + template + inline bool + equal(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_II1>) + __glibcxx_function_requires(_InputIteratorConcept<_II2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_II1>::value_type, + typename iterator_traits<_II2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + using _RATag = random_access_iterator_tag; + using _Cat1 = typename iterator_traits<_II1>::iterator_category; + using _Cat2 = typename iterator_traits<_II2>::iterator_category; + using _RAIters = __and_, is_same<_Cat2, _RATag>>; + if (_RAIters()) + { + auto __d1 = std::distance(__first1, __last1); + auto __d2 = std::distance(__first2, __last2); + if (__d1 != __d2) + return false; + return _GLIBCXX_STD_A::equal(__first1, __last1, __first2); + } + + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + if (!(*__first1 == *__first2)) + return false; + return __first1 == __last1 && __first2 == __last2; + } + + /** + * @brief Tests a range for element-wise equality. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @param __binary_pred A binary predicate @link functors + * functor@endlink. + * @return A boolean true or false. + * + * This compares the elements of two ranges using the binary_pred + * parameter, and returns true or + * false depending on whether all of the corresponding elements of the + * ranges are equal. + */ + template + inline bool + equal(_IIter1 __first1, _IIter1 __last1, + _IIter2 __first2, _IIter2 __last2, _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_IIter1>) + __glibcxx_function_requires(_InputIteratorConcept<_IIter2>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + using _RATag = random_access_iterator_tag; + using _Cat1 = typename iterator_traits<_IIter1>::iterator_category; + using _Cat2 = typename iterator_traits<_IIter2>::iterator_category; + using _RAIters = __and_, is_same<_Cat2, _RATag>>; + if (_RAIters()) + { + auto __d1 = std::distance(__first1, __last1); + auto __d2 = std::distance(__first2, __last2); + if (__d1 != __d2) + return false; + return _GLIBCXX_STD_A::equal(__first1, __last1, __first2, + __binary_pred); + } + + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + if (!bool(__binary_pred(*__first1, *__first2))) + return false; + return __first1 == __last1 && __first2 == __last2; + } +#endif + + /** + * @brief Performs @b dictionary comparison on ranges. + * @ingroup sorting_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @return A boolean true or false. + * + * Returns true if the sequence of elements defined by the range + * [first1,last1) is lexicographically less than the sequence of elements + * defined by the range [first2,last2). Returns false otherwise. + * (Quoted from [25.3.8]/1.) If the iterators are all character pointers, + * then this is an inline call to @c memcmp. + */ + template + inline bool + lexicographical_compare(_II1 __first1, _II1 __last1, + _II2 __first2, _II2 __last2) + { +#ifdef _GLIBCXX_CONCEPT_CHECKS + // concept requirements + typedef typename iterator_traits<_II1>::value_type _ValueType1; + typedef typename iterator_traits<_II2>::value_type _ValueType2; +#endif + __glibcxx_function_requires(_InputIteratorConcept<_II1>) + __glibcxx_function_requires(_InputIteratorConcept<_II2>) + __glibcxx_function_requires(_LessThanOpConcept<_ValueType1, _ValueType2>) + __glibcxx_function_requires(_LessThanOpConcept<_ValueType2, _ValueType1>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__lexicographical_compare_aux(std::__niter_base(__first1), + std::__niter_base(__last1), + std::__niter_base(__first2), + std::__niter_base(__last2)); + } + + /** + * @brief Performs @b dictionary comparison on ranges. + * @ingroup sorting_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @param __comp A @link comparison_functors comparison functor@endlink. + * @return A boolean true or false. + * + * The same as the four-parameter @c lexicographical_compare, but uses the + * comp parameter instead of @c <. + */ + template + inline bool + lexicographical_compare(_II1 __first1, _II1 __last1, + _II2 __first2, _II2 __last2, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_II1>) + __glibcxx_function_requires(_InputIteratorConcept<_II2>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return std::__lexicographical_compare_impl + (__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__comp)); + } + + template + pair<_InputIterator1, _InputIterator2> + __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _BinaryPredicate __binary_pred) + { + while (__first1 != __last1 && __binary_pred(__first1, __first2)) + { + ++__first1; + ++__first2; + } + return pair<_InputIterator1, _InputIterator2>(__first1, __first2); + } + + /** + * @brief Finds the places in ranges which don't match. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @return A pair of iterators pointing to the first mismatch. + * + * This compares the elements of two ranges using @c == and returns a pair + * of iterators. The first iterator points into the first range, the + * second iterator points into the second range, and the elements pointed + * to by the iterators are not equal. + */ + template + inline pair<_InputIterator1, _InputIterator2> + mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + + return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Finds the places in ranges which don't match. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __binary_pred A binary predicate @link functors + * functor@endlink. + * @return A pair of iterators pointing to the first mismatch. + * + * This compares the elements of two ranges using the binary_pred + * parameter, and returns a pair + * of iterators. The first iterator points into the first range, the + * second iterator points into the second range, and the elements pointed + * to by the iterators are not equal. + */ + template + inline pair<_InputIterator1, _InputIterator2> + mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_requires_valid_range(__first1, __last1); + + return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, + __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); + } + +#if __cplusplus > 201103L + + template + pair<_InputIterator1, _InputIterator2> + __mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _BinaryPredicate __binary_pred) + { + while (__first1 != __last1 && __first2 != __last2 + && __binary_pred(__first1, __first2)) + { + ++__first1; + ++__first2; + } + return pair<_InputIterator1, _InputIterator2>(__first1, __first2); + } + + /** + * @brief Finds the places in ranges which don't match. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @return A pair of iterators pointing to the first mismatch. + * + * This compares the elements of two ranges using @c == and returns a pair + * of iterators. The first iterator points into the first range, the + * second iterator points into the second range, and the elements pointed + * to by the iterators are not equal. + */ + template + inline pair<_InputIterator1, _InputIterator2> + mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_function_requires(_EqualOpConcept< + typename iterator_traits<_InputIterator1>::value_type, + typename iterator_traits<_InputIterator2>::value_type>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_equal_to_iter()); + } + + /** + * @brief Finds the places in ranges which don't match. + * @ingroup non_mutating_algorithms + * @param __first1 An input iterator. + * @param __last1 An input iterator. + * @param __first2 An input iterator. + * @param __last2 An input iterator. + * @param __binary_pred A binary predicate @link functors + * functor@endlink. + * @return A pair of iterators pointing to the first mismatch. + * + * This compares the elements of two ranges using the binary_pred + * parameter, and returns a pair + * of iterators. The first iterator points into the first range, the + * second iterator points into the second range, and the elements pointed + * to by the iterators are not equal. + */ + template + inline pair<_InputIterator1, _InputIterator2> + mismatch(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _InputIterator2 __last2, + _BinaryPredicate __binary_pred) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_requires_valid_range(__first1, __last1); + __glibcxx_requires_valid_range(__first2, __last2); + + return _GLIBCXX_STD_A::__mismatch(__first1, __last1, __first2, __last2, + __gnu_cxx::__ops::__iter_comp_iter(__binary_pred)); + } +#endif + +_GLIBCXX_END_NAMESPACE_ALGO +} // namespace std + +// NB: This file is included within many other C++ includes, as a way +// of getting the base algorithms. So, make sure that parallel bits +// come in too if requested. +#ifdef _GLIBCXX_PARALLEL +# include +#endif + +#endif diff --git a/AH/STL/Fallback/bits/stl_bvector.h b/AH/STL/Fallback/bits/stl_bvector.h new file mode 100644 index 0000000..101c81f --- /dev/null +++ b/AH/STL/Fallback/bits/stl_bvector.h @@ -0,0 +1,1308 @@ +// vector specialization -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1999 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_bvector.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{vector} + */ + +#ifndef _STL_BVECTOR_H +#define _STL_BVECTOR_H 1 + +#if __cplusplus >= 201103L +#include "../initializer_list" +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + typedef unsigned long _Bit_type; + enum { _S_word_bit = int(__CHAR_BIT__ * sizeof(_Bit_type)) }; + + struct _Bit_reference + { + _Bit_type * _M_p; + _Bit_type _M_mask; + + _Bit_reference(_Bit_type * __x, _Bit_type __y) + : _M_p(__x), _M_mask(__y) { } + + _Bit_reference() _GLIBCXX_NOEXCEPT : _M_p(0), _M_mask(0) { } + + operator bool() const _GLIBCXX_NOEXCEPT + { return !!(*_M_p & _M_mask); } + + _Bit_reference& + operator=(bool __x) _GLIBCXX_NOEXCEPT + { + if (__x) + *_M_p |= _M_mask; + else + *_M_p &= ~_M_mask; + return *this; + } + + _Bit_reference& + operator=(const _Bit_reference& __x) _GLIBCXX_NOEXCEPT + { return *this = bool(__x); } + + bool + operator==(const _Bit_reference& __x) const + { return bool(*this) == bool(__x); } + + bool + operator<(const _Bit_reference& __x) const + { return !bool(*this) && bool(__x); } + + void + flip() _GLIBCXX_NOEXCEPT + { *_M_p ^= _M_mask; } + }; + +#if __cplusplus >= 201103L + inline void + swap(_Bit_reference __x, _Bit_reference __y) noexcept + { + bool __tmp = __x; + __x = __y; + __y = __tmp; + } + + inline void + swap(_Bit_reference __x, bool& __y) noexcept + { + bool __tmp = __x; + __x = __y; + __y = __tmp; + } + + inline void + swap(bool& __x, _Bit_reference __y) noexcept + { + bool __tmp = __x; + __x = __y; + __y = __tmp; + } +#endif + + struct _Bit_iterator_base + : public std::iterator + { + _Bit_type * _M_p; + unsigned int _M_offset; + + _Bit_iterator_base(_Bit_type * __x, unsigned int __y) + : _M_p(__x), _M_offset(__y) { } + + void + _M_bump_up() + { + if (_M_offset++ == int(_S_word_bit) - 1) + { + _M_offset = 0; + ++_M_p; + } + } + + void + _M_bump_down() + { + if (_M_offset-- == 0) + { + _M_offset = int(_S_word_bit) - 1; + --_M_p; + } + } + + void + _M_incr(ptrdiff_t __i) + { + difference_type __n = __i + _M_offset; + _M_p += __n / int(_S_word_bit); + __n = __n % int(_S_word_bit); + if (__n < 0) + { + __n += int(_S_word_bit); + --_M_p; + } + _M_offset = static_cast(__n); + } + + bool + operator==(const _Bit_iterator_base& __i) const + { return _M_p == __i._M_p && _M_offset == __i._M_offset; } + + bool + operator<(const _Bit_iterator_base& __i) const + { + return _M_p < __i._M_p + || (_M_p == __i._M_p && _M_offset < __i._M_offset); + } + + bool + operator!=(const _Bit_iterator_base& __i) const + { return !(*this == __i); } + + bool + operator>(const _Bit_iterator_base& __i) const + { return __i < *this; } + + bool + operator<=(const _Bit_iterator_base& __i) const + { return !(__i < *this); } + + bool + operator>=(const _Bit_iterator_base& __i) const + { return !(*this < __i); } + }; + + inline ptrdiff_t + operator-(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) + { + return (int(_S_word_bit) * (__x._M_p - __y._M_p) + + __x._M_offset - __y._M_offset); + } + + struct _Bit_iterator : public _Bit_iterator_base + { + typedef _Bit_reference reference; + typedef _Bit_reference* pointer; + typedef _Bit_iterator iterator; + + _Bit_iterator() : _Bit_iterator_base(0, 0) { } + + _Bit_iterator(_Bit_type * __x, unsigned int __y) + : _Bit_iterator_base(__x, __y) { } + + iterator + _M_const_cast() const + { return *this; } + + reference + operator*() const + { return reference(_M_p, 1UL << _M_offset); } + + iterator& + operator++() + { + _M_bump_up(); + return *this; + } + + iterator + operator++(int) + { + iterator __tmp = *this; + _M_bump_up(); + return __tmp; + } + + iterator& + operator--() + { + _M_bump_down(); + return *this; + } + + iterator + operator--(int) + { + iterator __tmp = *this; + _M_bump_down(); + return __tmp; + } + + iterator& + operator+=(difference_type __i) + { + _M_incr(__i); + return *this; + } + + iterator& + operator-=(difference_type __i) + { + *this += -__i; + return *this; + } + + iterator + operator+(difference_type __i) const + { + iterator __tmp = *this; + return __tmp += __i; + } + + iterator + operator-(difference_type __i) const + { + iterator __tmp = *this; + return __tmp -= __i; + } + + reference + operator[](difference_type __i) const + { return *(*this + __i); } + }; + + inline _Bit_iterator + operator+(ptrdiff_t __n, const _Bit_iterator& __x) + { return __x + __n; } + + struct _Bit_const_iterator : public _Bit_iterator_base + { + typedef bool reference; + typedef bool const_reference; + typedef const bool* pointer; + typedef _Bit_const_iterator const_iterator; + + _Bit_const_iterator() : _Bit_iterator_base(0, 0) { } + + _Bit_const_iterator(_Bit_type * __x, unsigned int __y) + : _Bit_iterator_base(__x, __y) { } + + _Bit_const_iterator(const _Bit_iterator& __x) + : _Bit_iterator_base(__x._M_p, __x._M_offset) { } + + _Bit_iterator + _M_const_cast() const + { return _Bit_iterator(_M_p, _M_offset); } + + const_reference + operator*() const + { return _Bit_reference(_M_p, 1UL << _M_offset); } + + const_iterator& + operator++() + { + _M_bump_up(); + return *this; + } + + const_iterator + operator++(int) + { + const_iterator __tmp = *this; + _M_bump_up(); + return __tmp; + } + + const_iterator& + operator--() + { + _M_bump_down(); + return *this; + } + + const_iterator + operator--(int) + { + const_iterator __tmp = *this; + _M_bump_down(); + return __tmp; + } + + const_iterator& + operator+=(difference_type __i) + { + _M_incr(__i); + return *this; + } + + const_iterator& + operator-=(difference_type __i) + { + *this += -__i; + return *this; + } + + const_iterator + operator+(difference_type __i) const + { + const_iterator __tmp = *this; + return __tmp += __i; + } + + const_iterator + operator-(difference_type __i) const + { + const_iterator __tmp = *this; + return __tmp -= __i; + } + + const_reference + operator[](difference_type __i) const + { return *(*this + __i); } + }; + + inline _Bit_const_iterator + operator+(ptrdiff_t __n, const _Bit_const_iterator& __x) + { return __x + __n; } + + inline void + __fill_bvector(_Bit_iterator __first, _Bit_iterator __last, bool __x) + { + for (; __first != __last; ++__first) + *__first = __x; + } + + inline void + fill(_Bit_iterator __first, _Bit_iterator __last, const bool& __x) + { + if (__first._M_p != __last._M_p) + { + std::fill(__first._M_p + 1, __last._M_p, __x ? ~0 : 0); + __fill_bvector(__first, _Bit_iterator(__first._M_p + 1, 0), __x); + __fill_bvector(_Bit_iterator(__last._M_p, 0), __last, __x); + } + else + __fill_bvector(__first, __last, __x); + } + + template + struct _Bvector_base + { + typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template + rebind<_Bit_type>::other _Bit_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Bit_alloc_type> + _Bit_alloc_traits; + typedef typename _Bit_alloc_traits::pointer _Bit_pointer; + + struct _Bvector_impl + : public _Bit_alloc_type + { + _Bit_iterator _M_start; + _Bit_iterator _M_finish; + _Bit_pointer _M_end_of_storage; + + _Bvector_impl() + : _Bit_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage() + { } + + _Bvector_impl(const _Bit_alloc_type& __a) + : _Bit_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage() + { } + +#if __cplusplus >= 201103L + _Bvector_impl(_Bit_alloc_type&& __a) + : _Bit_alloc_type(std::move(__a)), _M_start(), _M_finish(), + _M_end_of_storage() + { } +#endif + + _Bit_type* + _M_end_addr() const _GLIBCXX_NOEXCEPT + { + if (_M_end_of_storage) + return std::__addressof(_M_end_of_storage[-1]) + 1; + return 0; + } + }; + + public: + typedef _Alloc allocator_type; + + _Bit_alloc_type& + _M_get_Bit_allocator() _GLIBCXX_NOEXCEPT + { return *static_cast<_Bit_alloc_type*>(&this->_M_impl); } + + const _Bit_alloc_type& + _M_get_Bit_allocator() const _GLIBCXX_NOEXCEPT + { return *static_cast(&this->_M_impl); } + + allocator_type + get_allocator() const _GLIBCXX_NOEXCEPT + { return allocator_type(_M_get_Bit_allocator()); } + + _Bvector_base() + : _M_impl() { } + + _Bvector_base(const allocator_type& __a) + : _M_impl(__a) { } + +#if __cplusplus >= 201103L + _Bvector_base(_Bvector_base&& __x) noexcept + : _M_impl(std::move(__x._M_get_Bit_allocator())) + { + this->_M_impl._M_start = __x._M_impl._M_start; + this->_M_impl._M_finish = __x._M_impl._M_finish; + this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage; + __x._M_impl._M_start = _Bit_iterator(); + __x._M_impl._M_finish = _Bit_iterator(); + __x._M_impl._M_end_of_storage = nullptr; + } +#endif + + ~_Bvector_base() + { this->_M_deallocate(); } + + protected: + _Bvector_impl _M_impl; + + _Bit_pointer + _M_allocate(size_t __n) + { return _Bit_alloc_traits::allocate(_M_impl, _S_nword(__n)); } + + void + _M_deallocate() + { + if (_M_impl._M_start._M_p) + { + const size_t __n = _M_impl._M_end_addr() - _M_impl._M_start._M_p; + _Bit_alloc_traits::deallocate(_M_impl, + _M_impl._M_end_of_storage - __n, + __n); + _M_impl._M_start = _M_impl._M_finish = _Bit_iterator(); + _M_impl._M_end_of_storage = _Bit_pointer(); + } + } + + static size_t + _S_nword(size_t __n) + { return (__n + int(_S_word_bit) - 1) / int(_S_word_bit); } + }; + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +// Declare a partial specialization of vector. +#include "../bits/stl_vector.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + /** + * @brief A specialization of vector for booleans which offers fixed time + * access to individual elements in any order. + * + * @ingroup sequences + * + * @tparam _Alloc Allocator type. + * + * Note that vector does not actually meet the requirements for being + * a container. This is because the reference and pointer types are not + * really references and pointers to bool. See DR96 for details. @see + * vector for function documentation. + * + * In some terminology a %vector can be described as a dynamic + * C-style array, it offers fast and efficient access to individual + * elements in any order and saves the user from worrying about + * memory and size allocation. Subscripting ( @c [] ) access is + * also provided as with C-style arrays. + */ +template + class vector : protected _Bvector_base<_Alloc> + { + typedef _Bvector_base<_Alloc> _Base; + typedef typename _Base::_Bit_pointer _Bit_pointer; + typedef typename _Base::_Bit_alloc_traits _Bit_alloc_traits; + +#if __cplusplus >= 201103L + template friend struct hash; +#endif + + public: + typedef bool value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Bit_reference reference; + typedef bool const_reference; + typedef _Bit_reference* pointer; + typedef const bool* const_pointer; + typedef _Bit_iterator iterator; + typedef _Bit_const_iterator const_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef _Alloc allocator_type; + + allocator_type get_allocator() const + { return _Base::get_allocator(); } + + protected: + using _Base::_M_allocate; + using _Base::_M_deallocate; + using _Base::_S_nword; + using _Base::_M_get_Bit_allocator; + + public: + vector() +#if __cplusplus >= 201103L + noexcept(is_nothrow_default_constructible::value) +#endif + : _Base() { } + + explicit + vector(const allocator_type& __a) + : _Base(__a) { } + +#if __cplusplus >= 201103L + explicit + vector(size_type __n, const allocator_type& __a = allocator_type()) + : vector(__n, false, __a) + { } + + vector(size_type __n, const bool& __value, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + _M_initialize(__n); + std::fill(this->_M_impl._M_start._M_p, this->_M_impl._M_end_addr(), + __value ? ~0 : 0); + } +#else + explicit + vector(size_type __n, const bool& __value = bool(), + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + _M_initialize(__n); + std::fill(this->_M_impl._M_start._M_p, this->_M_impl._M_end_addr(), + __value ? ~0 : 0); + } +#endif + + vector(const vector& __x) + : _Base(_Bit_alloc_traits::_S_select_on_copy(__x._M_get_Bit_allocator())) + { + _M_initialize(__x.size()); + _M_copy_aligned(__x.begin(), __x.end(), this->_M_impl._M_start); + } + +#if __cplusplus >= 201103L + vector(vector&& __x) noexcept + : _Base(std::move(__x)) { } + + vector(vector&& __x, const allocator_type& __a) + noexcept(_Bit_alloc_traits::_S_always_equal()) + : _Base(__a) + { + if (__x.get_allocator() == __a) + { + this->_M_impl._M_start = __x._M_impl._M_start; + this->_M_impl._M_finish = __x._M_impl._M_finish; + this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage; + __x._M_impl._M_start = _Bit_iterator(); + __x._M_impl._M_finish = _Bit_iterator(); + __x._M_impl._M_end_of_storage = nullptr; + } + else + { + _M_initialize(__x.size()); + _M_copy_aligned(__x.begin(), __x.end(), begin()); + __x.clear(); + } + } + + vector(const vector& __x, const allocator_type& __a) + : _Base(__a) + { + _M_initialize(__x.size()); + _M_copy_aligned(__x.begin(), __x.end(), this->_M_impl._M_start); + } + + vector(initializer_list __l, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + _M_initialize_range(__l.begin(), __l.end(), + random_access_iterator_tag()); + } +#endif + +#if __cplusplus >= 201103L + template> + vector(_InputIterator __first, _InputIterator __last, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { _M_initialize_dispatch(__first, __last, __false_type()); } +#else + template + vector(_InputIterator __first, _InputIterator __last, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_initialize_dispatch(__first, __last, _Integral()); + } +#endif + + ~vector() _GLIBCXX_NOEXCEPT { } + + vector& + operator=(const vector& __x) + { + if (&__x == this) + return *this; +#if __cplusplus >= 201103L + if (_Bit_alloc_traits::_S_propagate_on_copy_assign()) + { + if (this->_M_get_Bit_allocator() != __x._M_get_Bit_allocator()) + { + this->_M_deallocate(); + std::__alloc_on_copy(_M_get_Bit_allocator(), + __x._M_get_Bit_allocator()); + _M_initialize(__x.size()); + } + else + std::__alloc_on_copy(_M_get_Bit_allocator(), + __x._M_get_Bit_allocator()); + } +#endif + if (__x.size() > capacity()) + { + this->_M_deallocate(); + _M_initialize(__x.size()); + } + this->_M_impl._M_finish = _M_copy_aligned(__x.begin(), __x.end(), + begin()); + return *this; + } + +#if __cplusplus >= 201103L + vector& + operator=(vector&& __x) noexcept(_Bit_alloc_traits::_S_nothrow_move()) + { + if (_Bit_alloc_traits::_S_propagate_on_move_assign() + || this->_M_get_Bit_allocator() == __x._M_get_Bit_allocator()) + { + this->_M_deallocate(); + this->_M_impl._M_start = __x._M_impl._M_start; + this->_M_impl._M_finish = __x._M_impl._M_finish; + this->_M_impl._M_end_of_storage = __x._M_impl._M_end_of_storage; + __x._M_impl._M_start = _Bit_iterator(); + __x._M_impl._M_finish = _Bit_iterator(); + __x._M_impl._M_end_of_storage = nullptr; + std::__alloc_on_move(_M_get_Bit_allocator(), + __x._M_get_Bit_allocator()); + } + else + { + if (__x.size() > capacity()) + { + this->_M_deallocate(); + _M_initialize(__x.size()); + } + this->_M_impl._M_finish = _M_copy_aligned(__x.begin(), __x.end(), + begin()); + __x.clear(); + } + return *this; + } + + vector& + operator=(initializer_list __l) + { + this->assign (__l.begin(), __l.end()); + return *this; + } +#endif + + // assign(), a generalized assignment member function. Two + // versions: one that takes a count, and one that takes a range. + // The range version is a member template, so we dispatch on whether + // or not the type is an integer. + void + assign(size_type __n, const bool& __x) + { _M_fill_assign(__n, __x); } + +#if __cplusplus >= 201103L + template> + void + assign(_InputIterator __first, _InputIterator __last) + { _M_assign_dispatch(__first, __last, __false_type()); } +#else + template + void + assign(_InputIterator __first, _InputIterator __last) + { + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_assign_dispatch(__first, __last, _Integral()); + } +#endif + +#if __cplusplus >= 201103L + void + assign(initializer_list __l) + { this->assign(__l.begin(), __l.end()); } +#endif + + iterator + begin() _GLIBCXX_NOEXCEPT + { return this->_M_impl._M_start; } + + const_iterator + begin() const _GLIBCXX_NOEXCEPT + { return this->_M_impl._M_start; } + + iterator + end() _GLIBCXX_NOEXCEPT + { return this->_M_impl._M_finish; } + + const_iterator + end() const _GLIBCXX_NOEXCEPT + { return this->_M_impl._M_finish; } + + reverse_iterator + rbegin() _GLIBCXX_NOEXCEPT + { return reverse_iterator(end()); } + + const_reverse_iterator + rbegin() const _GLIBCXX_NOEXCEPT + { return const_reverse_iterator(end()); } + + reverse_iterator + rend() _GLIBCXX_NOEXCEPT + { return reverse_iterator(begin()); } + + const_reverse_iterator + rend() const _GLIBCXX_NOEXCEPT + { return const_reverse_iterator(begin()); } + +#if __cplusplus >= 201103L + const_iterator + cbegin() const noexcept + { return this->_M_impl._M_start; } + + const_iterator + cend() const noexcept + { return this->_M_impl._M_finish; } + + const_reverse_iterator + crbegin() const noexcept + { return const_reverse_iterator(end()); } + + const_reverse_iterator + crend() const noexcept + { return const_reverse_iterator(begin()); } +#endif + + size_type + size() const _GLIBCXX_NOEXCEPT + { return size_type(end() - begin()); } + + size_type + max_size() const _GLIBCXX_NOEXCEPT + { + const size_type __isize = + __gnu_cxx::__numeric_traits::__max + - int(_S_word_bit) + 1; + const size_type __asize + = _Bit_alloc_traits::max_size(_M_get_Bit_allocator()); + return (__asize <= __isize / int(_S_word_bit) + ? __asize * int(_S_word_bit) : __isize); + } + + size_type + capacity() const _GLIBCXX_NOEXCEPT + { return size_type(const_iterator(this->_M_impl._M_end_addr(), 0) + - begin()); } + + bool + empty() const _GLIBCXX_NOEXCEPT + { return begin() == end(); } + + reference + operator[](size_type __n) + { + return *iterator(this->_M_impl._M_start._M_p + + __n / int(_S_word_bit), __n % int(_S_word_bit)); + } + + const_reference + operator[](size_type __n) const + { + return *const_iterator(this->_M_impl._M_start._M_p + + __n / int(_S_word_bit), __n % int(_S_word_bit)); + } + + protected: + void + _M_range_check(size_type __n) const + { +#ifndef __AVR__ + if (__n >= this->size()) + __throw_out_of_range(__N("vector::_M_range_check: __n " + "(which is %zu) >= this->size() " + "(which is %zu)"), + __n, this->size()); +#else + if (__n >= this->size()) + __throw_out_of_range_index_length(F("vector::_M_range_check"), + __n, this->size()); +#endif + } + + public: + reference + at(size_type __n) + { _M_range_check(__n); return (*this)[__n]; } + + const_reference + at(size_type __n) const + { _M_range_check(__n); return (*this)[__n]; } + + void + reserve(size_type __n) + { + if (__n > max_size()) + __throw_length_error(__N("vector::reserve")); + if (capacity() < __n) + _M_reallocate(__n); + } + + reference + front() + { return *begin(); } + + const_reference + front() const + { return *begin(); } + + reference + back() + { return *(end() - 1); } + + const_reference + back() const + { return *(end() - 1); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 464. Suggestion for new member functions in standard containers. + // N.B. DR 464 says nothing about vector but we need something + // here due to the way we are implementing DR 464 in the debug-mode + // vector class. + void + data() _GLIBCXX_NOEXCEPT { } + + void + push_back(bool __x) + { + if (this->_M_impl._M_finish._M_p != this->_M_impl._M_end_addr()) + *this->_M_impl._M_finish++ = __x; + else + _M_insert_aux(end(), __x); + } + + void + swap(vector& __x) _GLIBCXX_NOEXCEPT + { + std::swap(this->_M_impl._M_start, __x._M_impl._M_start); + std::swap(this->_M_impl._M_finish, __x._M_impl._M_finish); + std::swap(this->_M_impl._M_end_of_storage, + __x._M_impl._M_end_of_storage); + _Bit_alloc_traits::_S_on_swap(_M_get_Bit_allocator(), + __x._M_get_Bit_allocator()); + } + + // [23.2.5]/1, third-to-last entry in synopsis listing + static void + swap(reference __x, reference __y) _GLIBCXX_NOEXCEPT + { + bool __tmp = __x; + __x = __y; + __y = __tmp; + } + + iterator +#if __cplusplus >= 201103L + insert(const_iterator __position, const bool& __x = bool()) +#else + insert(iterator __position, const bool& __x = bool()) +#endif + { + const difference_type __n = __position - begin(); + if (this->_M_impl._M_finish._M_p != this->_M_impl._M_end_addr() + && __position == end()) + *this->_M_impl._M_finish++ = __x; + else + _M_insert_aux(__position._M_const_cast(), __x); + return begin() + __n; + } + +#if __cplusplus >= 201103L + template> + iterator + insert(const_iterator __position, + _InputIterator __first, _InputIterator __last) + { + difference_type __offset = __position - cbegin(); + _M_insert_dispatch(__position._M_const_cast(), + __first, __last, __false_type()); + return begin() + __offset; + } +#else + template + void + insert(iterator __position, + _InputIterator __first, _InputIterator __last) + { + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_insert_dispatch(__position, __first, __last, _Integral()); + } +#endif + +#if __cplusplus >= 201103L + iterator + insert(const_iterator __position, size_type __n, const bool& __x) + { + difference_type __offset = __position - cbegin(); + _M_fill_insert(__position._M_const_cast(), __n, __x); + return begin() + __offset; + } +#else + void + insert(iterator __position, size_type __n, const bool& __x) + { _M_fill_insert(__position, __n, __x); } +#endif + +#if __cplusplus >= 201103L + iterator + insert(const_iterator __p, initializer_list __l) + { return this->insert(__p, __l.begin(), __l.end()); } +#endif + + void + pop_back() + { --this->_M_impl._M_finish; } + + iterator +#if __cplusplus >= 201103L + erase(const_iterator __position) +#else + erase(iterator __position) +#endif + { return _M_erase(__position._M_const_cast()); } + + iterator +#if __cplusplus >= 201103L + erase(const_iterator __first, const_iterator __last) +#else + erase(iterator __first, iterator __last) +#endif + { return _M_erase(__first._M_const_cast(), __last._M_const_cast()); } + + void + resize(size_type __new_size, bool __x = bool()) + { + if (__new_size < size()) + _M_erase_at_end(begin() + difference_type(__new_size)); + else + insert(end(), __new_size - size(), __x); + } + +#if __cplusplus >= 201103L + void + shrink_to_fit() + { _M_shrink_to_fit(); } +#endif + + void + flip() _GLIBCXX_NOEXCEPT + { + _Bit_type * const __end = this->_M_impl._M_end_addr(); + for (_Bit_type * __p = this->_M_impl._M_start._M_p; __p != __end; ++__p) + *__p = ~*__p; + } + + void + clear() _GLIBCXX_NOEXCEPT + { _M_erase_at_end(begin()); } + +#if __cplusplus >= 201103L + template +#if __cplusplus > 201402L + reference +#else + void +#endif + emplace_back(_Args&&... __args) + { + push_back(bool(__args...)); +#if __cplusplus > 201402L + return back(); +#endif + } + + template + iterator + emplace(const_iterator __pos, _Args&&... __args) + { return insert(__pos, bool(__args...)); } +#endif + + protected: + // Precondition: __first._M_offset == 0 && __result._M_offset == 0. + iterator + _M_copy_aligned(const_iterator __first, const_iterator __last, + iterator __result) + { + _Bit_type* __q = std::copy(__first._M_p, __last._M_p, __result._M_p); + return std::copy(const_iterator(__last._M_p, 0), __last, + iterator(__q, 0)); + } + + void + _M_initialize(size_type __n) + { + if (__n) + { + _Bit_pointer __q = this->_M_allocate(__n); + this->_M_impl._M_end_of_storage = __q + _S_nword(__n); + this->_M_impl._M_start = iterator(std::__addressof(*__q), 0); + } + else + { + this->_M_impl._M_end_of_storage = _Bit_pointer(); + this->_M_impl._M_start = iterator(0, 0); + } + this->_M_impl._M_finish = this->_M_impl._M_start + difference_type(__n); + } + + void + _M_reallocate(size_type __n); + +#if __cplusplus >= 201103L + bool + _M_shrink_to_fit(); +#endif + + // Check whether it's an integral type. If so, it's not an iterator. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_initialize_dispatch(_Integer __n, _Integer __x, __true_type) + { + _M_initialize(static_cast(__n)); + std::fill(this->_M_impl._M_start._M_p, + this->_M_impl._M_end_addr(), __x ? ~0 : 0); + } + + template + void + _M_initialize_dispatch(_InputIterator __first, _InputIterator __last, + __false_type) + { _M_initialize_range(__first, __last, + std::__iterator_category(__first)); } + + template + void + _M_initialize_range(_InputIterator __first, _InputIterator __last, + std::input_iterator_tag) + { + for (; __first != __last; ++__first) + push_back(*__first); + } + + template + void + _M_initialize_range(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag) + { + const size_type __n = std::distance(__first, __last); + _M_initialize(__n); + std::copy(__first, __last, this->_M_impl._M_start); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) + { _M_fill_assign(__n, __val); } + + template + void + _M_assign_dispatch(_InputIterator __first, _InputIterator __last, + __false_type) + { _M_assign_aux(__first, __last, std::__iterator_category(__first)); } + + void + _M_fill_assign(size_t __n, bool __x) + { + if (__n > size()) + { + std::fill(this->_M_impl._M_start._M_p, + this->_M_impl._M_end_addr(), __x ? ~0 : 0); + insert(end(), __n - size(), __x); + } + else + { + _M_erase_at_end(begin() + __n); + std::fill(this->_M_impl._M_start._M_p, + this->_M_impl._M_end_addr(), __x ? ~0 : 0); + } + } + + template + void + _M_assign_aux(_InputIterator __first, _InputIterator __last, + std::input_iterator_tag) + { + iterator __cur = begin(); + for (; __first != __last && __cur != end(); ++__cur, ++__first) + *__cur = *__first; + if (__first == __last) + _M_erase_at_end(__cur); + else + insert(end(), __first, __last); + } + + template + void + _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag) + { + const size_type __len = std::distance(__first, __last); + if (__len < size()) + _M_erase_at_end(std::copy(__first, __last, begin())); + else + { + _ForwardIterator __mid = __first; + std::advance(__mid, size()); + std::copy(__first, __mid, begin()); + insert(end(), __mid, __last); + } + } + + // Check whether it's an integral type. If so, it's not an iterator. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __x, + __true_type) + { _M_fill_insert(__pos, __n, __x); } + + template + void + _M_insert_dispatch(iterator __pos, + _InputIterator __first, _InputIterator __last, + __false_type) + { _M_insert_range(__pos, __first, __last, + std::__iterator_category(__first)); } + + void + _M_fill_insert(iterator __position, size_type __n, bool __x); + + template + void + _M_insert_range(iterator __pos, _InputIterator __first, + _InputIterator __last, std::input_iterator_tag) + { + for (; __first != __last; ++__first) + { + __pos = insert(__pos, *__first); + ++__pos; + } + } + + template + void + _M_insert_range(iterator __position, _ForwardIterator __first, + _ForwardIterator __last, std::forward_iterator_tag); + + void + _M_insert_aux(iterator __position, bool __x); + + size_type + _M_check_len(size_type __n, const char* __s) const + { + if (max_size() - size() < __n) + __throw_length_error(__N(__s)); + + const size_type __len = size() + std::max(size(), __n); + return (__len < size() || __len > max_size()) ? max_size() : __len; + } + + void + _M_erase_at_end(iterator __pos) + { this->_M_impl._M_finish = __pos; } + + iterator + _M_erase(iterator __pos); + + iterator + _M_erase(iterator __first, iterator __last); + }; + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +#if __cplusplus >= 201103L + +#include "../bits/functional_hash.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // DR 1182. + /// std::hash specialization for vector. + template + struct hash<_GLIBCXX_STD_C::vector> + : public __hash_base> + { + size_t + operator()(const _GLIBCXX_STD_C::vector&) const noexcept; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +}// namespace std + +#endif // C++11 + +#endif diff --git a/AH/STL/Fallback/bits/stl_construct.h b/AH/STL/Fallback/bits/stl_construct.h new file mode 100644 index 0000000..8b5519d --- /dev/null +++ b/AH/STL/Fallback/bits/stl_construct.h @@ -0,0 +1,235 @@ +// nonstandard construct and destroy functions -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_construct.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _STL_CONSTRUCT_H +#define _STL_CONSTRUCT_H 1 + +#include "../new" +#include "../bits/move.h" +#include "../ext/alloc_traits.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * Constructs an object in existing memory by invoking an allocated + * object's constructor with an initializer. + */ +#if __cplusplus >= 201103L + template + inline void + _Construct(_T1* __p, _Args&&... __args) + { ::new(static_cast(__p)) _T1(std::forward<_Args>(__args)...); } +#else + template + inline void + _Construct(_T1* __p, const _T2& __value) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 402. wrong new expression in [some_]allocator::construct + ::new(static_cast(__p)) _T1(__value); + } +#endif + + template + inline void + _Construct_novalue(_T1* __p) + { ::new(static_cast(__p)) _T1; } + + /** + * Destroy the object pointed to by a pointer type. + */ + template + inline void + _Destroy(_Tp* __pointer) + { __pointer->~_Tp(); } + + template + struct _Destroy_aux + { + template + static void + __destroy(_ForwardIterator __first, _ForwardIterator __last) + { + for (; __first != __last; ++__first) + std::_Destroy(std::__addressof(*__first)); + } + }; + + template<> + struct _Destroy_aux + { + template + static void + __destroy(_ForwardIterator, _ForwardIterator) { } + }; + + /** + * Destroy a range of objects. If the value_type of the object has + * a trivial destructor, the compiler should optimize all of this + * away, otherwise the objects' destructors must be invoked. + */ + template + inline void + _Destroy(_ForwardIterator __first, _ForwardIterator __last) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _Value_type; +#if __cplusplus >= 201103L + // A deleted destructor is trivial, this ensures we reject such types: + static_assert(is_destructible<_Value_type>::value, + "value type is destructible"); +#endif + std::_Destroy_aux<__has_trivial_destructor(_Value_type)>:: + __destroy(__first, __last); + } + + template + struct _Destroy_n_aux + { + template + static _ForwardIterator + __destroy_n(_ForwardIterator __first, _Size __count) + { + for (; __count > 0; (void)++__first, --__count) + std::_Destroy(std::__addressof(*__first)); + return __first; + } + }; + + template<> + struct _Destroy_n_aux + { + template + static _ForwardIterator + __destroy_n(_ForwardIterator __first, _Size __count) + { + std::advance(__first, __count); + return __first; + } + }; + + /** + * Destroy a range of objects. If the value_type of the object has + * a trivial destructor, the compiler should optimize all of this + * away, otherwise the objects' destructors must be invoked. + */ + template + inline _ForwardIterator + _Destroy_n(_ForwardIterator __first, _Size __count) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _Value_type; +#if __cplusplus >= 201103L + // A deleted destructor is trivial, this ensures we reject such types: + static_assert(is_destructible<_Value_type>::value, + "value type is destructible"); +#endif + return std::_Destroy_n_aux<__has_trivial_destructor(_Value_type)>:: + __destroy_n(__first, __count); + } + + /** + * Destroy a range of objects using the supplied allocator. For + * nondefault allocators we do not optimize away invocation of + * destroy() even if _Tp has a trivial destructor. + */ + + template + void + _Destroy(_ForwardIterator __first, _ForwardIterator __last, + _Allocator& __alloc) + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __first != __last; ++__first) + __traits::destroy(__alloc, std::__addressof(*__first)); + } + + template + inline void + _Destroy(_ForwardIterator __first, _ForwardIterator __last, + allocator<_Tp>&) + { + _Destroy(__first, __last); + } + +#if __cplusplus > 201402L + template + inline void + destroy_at(_Tp* __location) + { + std::_Destroy(__location); + } + + template + inline void + destroy(_ForwardIterator __first, _ForwardIterator __last) + { + std::_Destroy(__first, __last); + } + + template + inline _ForwardIterator + destroy_n(_ForwardIterator __first, _Size __count) + { + return std::_Destroy_n(__first, __count); + } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif /* _STL_CONSTRUCT_H */ diff --git a/AH/STL/Fallback/bits/stl_function.h b/AH/STL/Fallback/bits/stl_function.h new file mode 100644 index 0000000..38cb57f --- /dev/null +++ b/AH/STL/Fallback/bits/stl_function.h @@ -0,0 +1,1130 @@ +// Functor implementations -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_function.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{functional} + */ + +#ifndef _STL_FUNCTION_H +#define _STL_FUNCTION_H 1 + +#if __cplusplus > 201103L +#include "../bits/move.h" +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // 20.3.1 base classes + /** @defgroup functors Function Objects + * @ingroup utilities + * + * Function objects, or @e functors, are objects with an @c operator() + * defined and accessible. They can be passed as arguments to algorithm + * templates and used in place of a function pointer. Not only is the + * resulting expressiveness of the library increased, but the generated + * code can be more efficient than what you might write by hand. When we + * refer to @a functors, then, generally we include function pointers in + * the description as well. + * + * Often, functors are only created as temporaries passed to algorithm + * calls, rather than being created as named variables. + * + * Two examples taken from the standard itself follow. To perform a + * by-element addition of two vectors @c a and @c b containing @c double, + * and put the result in @c a, use + * \code + * transform (a.begin(), a.end(), b.begin(), a.begin(), plus()); + * \endcode + * To negate every element in @c a, use + * \code + * transform(a.begin(), a.end(), a.begin(), negate()); + * \endcode + * The addition and negation functions will be inlined directly. + * + * The standard functors are derived from structs named @c unary_function + * and @c binary_function. These two classes contain nothing but typedefs, + * to aid in generic (template) programming. If you write your own + * functors, you might consider doing the same. + * + * @{ + */ + /** + * This is one of the @link functors functor base classes@endlink. + */ + template + struct unary_function + { + /// @c argument_type is the type of the argument + typedef _Arg argument_type; + + /// @c result_type is the return type + typedef _Result result_type; + }; + + /** + * This is one of the @link functors functor base classes@endlink. + */ + template + struct binary_function + { + /// @c first_argument_type is the type of the first argument + typedef _Arg1 first_argument_type; + + /// @c second_argument_type is the type of the second argument + typedef _Arg2 second_argument_type; + + /// @c result_type is the return type + typedef _Result result_type; + }; + /** @} */ + + // 20.3.2 arithmetic + /** @defgroup arithmetic_functors Arithmetic Classes + * @ingroup functors + * + * Because basic math often needs to be done during an algorithm, + * the library provides functors for those operations. See the + * documentation for @link functors the base classes@endlink + * for examples of their use. + * + * @{ + */ + +#if __cplusplus > 201103L + struct __is_transparent; // undefined + + template + struct plus; + + template + struct minus; + + template + struct multiplies; + + template + struct divides; + + template + struct modulus; + + template + struct negate; +#endif + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct plus : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x + __y; } + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct minus : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x - __y; } + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct multiplies : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x * __y; } + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct divides : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x / __y; } + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct modulus : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x % __y; } + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template + struct negate : public unary_function<_Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x) const + { return -__x; } + }; + +#if __cplusplus > 201103L + +#define __cpp_lib_transparent_operators 201510 + + template<> + struct plus + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) + std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) + std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) + std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template<> + struct minus + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) - std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) - std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) - std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template<> + struct multiplies + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) * std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) * std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) * std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template<> + struct divides + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) / std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) / std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) / std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template<> + struct modulus + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) % std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) % std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) % std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link arithmetic_functors math functors@endlink. + template<> + struct negate + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t) const + noexcept(noexcept(-std::forward<_Tp>(__t))) + -> decltype(-std::forward<_Tp>(__t)) + { return -std::forward<_Tp>(__t); } + + typedef __is_transparent is_transparent; + }; +#endif + /** @} */ + + // 20.3.3 comparisons + /** @defgroup comparison_functors Comparison Classes + * @ingroup functors + * + * The library provides six wrapper functors for all the basic comparisons + * in C++, like @c <. + * + * @{ + */ +#if __cplusplus > 201103L + template + struct equal_to; + + template + struct not_equal_to; + + template + struct greater; + + template + struct less; + + template + struct greater_equal; + + template + struct less_equal; +#endif + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct equal_to : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x == __y; } + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct not_equal_to : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x != __y; } + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct greater : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x > __y; } + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct less : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x < __y; } + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct greater_equal : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x >= __y; } + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template + struct less_equal : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x <= __y; } + }; + +#if __cplusplus > 201103L + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct equal_to + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) == std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) == std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) == std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct not_equal_to + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) != std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) != std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) != std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct greater + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) > std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) > std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) > std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct less + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) < std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) < std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) < std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct greater_equal + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) >= std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) >= std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) >= std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link comparison_functors comparison functors@endlink. + template<> + struct less_equal + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) <= std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) <= std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) <= std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; +#endif + /** @} */ + + // 20.3.4 logical operations + /** @defgroup logical_functors Boolean Operations Classes + * @ingroup functors + * + * Here are wrapper functors for Boolean operations: @c &&, @c ||, + * and @c !. + * + * @{ + */ +#if __cplusplus > 201103L + template + struct logical_and; + + template + struct logical_or; + + template + struct logical_not; +#endif + + /// One of the @link logical_functors Boolean operations functors@endlink. + template + struct logical_and : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x && __y; } + }; + + /// One of the @link logical_functors Boolean operations functors@endlink. + template + struct logical_or : public binary_function<_Tp, _Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x, const _Tp& __y) const + { return __x || __y; } + }; + + /// One of the @link logical_functors Boolean operations functors@endlink. + template + struct logical_not : public unary_function<_Tp, bool> + { + _GLIBCXX14_CONSTEXPR + bool + operator()(const _Tp& __x) const + { return !__x; } + }; + +#if __cplusplus > 201103L + /// One of the @link logical_functors Boolean operations functors@endlink. + template<> + struct logical_and + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) && std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) && std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) && std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link logical_functors Boolean operations functors@endlink. + template<> + struct logical_or + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) || std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) || std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) || std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + /// One of the @link logical_functors Boolean operations functors@endlink. + template<> + struct logical_not + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t) const + noexcept(noexcept(!std::forward<_Tp>(__t))) + -> decltype(!std::forward<_Tp>(__t)) + { return !std::forward<_Tp>(__t); } + + typedef __is_transparent is_transparent; + }; +#endif + /** @} */ + +#if __cplusplus > 201103L + template + struct bit_and; + + template + struct bit_or; + + template + struct bit_xor; + + template + struct bit_not; +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 660. Missing Bitwise Operations. + template + struct bit_and : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x & __y; } + }; + + template + struct bit_or : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x | __y; } + }; + + template + struct bit_xor : public binary_function<_Tp, _Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x, const _Tp& __y) const + { return __x ^ __y; } + }; + + template + struct bit_not : public unary_function<_Tp, _Tp> + { + _GLIBCXX14_CONSTEXPR + _Tp + operator()(const _Tp& __x) const + { return ~__x; } + }; + +#if __cplusplus > 201103L + template <> + struct bit_and + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) & std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) & std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) & std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + template <> + struct bit_or + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) | std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) | std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) | std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + template <> + struct bit_xor + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t, _Up&& __u) const + noexcept(noexcept(std::forward<_Tp>(__t) ^ std::forward<_Up>(__u))) + -> decltype(std::forward<_Tp>(__t) ^ std::forward<_Up>(__u)) + { return std::forward<_Tp>(__t) ^ std::forward<_Up>(__u); } + + typedef __is_transparent is_transparent; + }; + + template <> + struct bit_not + { + template + _GLIBCXX14_CONSTEXPR + auto + operator()(_Tp&& __t) const + noexcept(noexcept(~std::forward<_Tp>(__t))) + -> decltype(~std::forward<_Tp>(__t)) + { return ~std::forward<_Tp>(__t); } + + typedef __is_transparent is_transparent; + }; +#endif + + // 20.3.5 negators + /** @defgroup negators Negators + * @ingroup functors + * + * The functions @c not1 and @c not2 each take a predicate functor + * and return an instance of @c unary_negate or + * @c binary_negate, respectively. These classes are functors whose + * @c operator() performs the stored predicate function and then returns + * the negation of the result. + * + * For example, given a vector of integers and a trivial predicate, + * \code + * struct IntGreaterThanThree + * : public std::unary_function + * { + * bool operator() (int x) { return x > 3; } + * }; + * + * std::find_if (v.begin(), v.end(), not1(IntGreaterThanThree())); + * \endcode + * The call to @c find_if will locate the first index (i) of @c v for which + * !(v[i] > 3) is true. + * + * The not1/unary_negate combination works on predicates taking a single + * argument. The not2/binary_negate combination works on predicates which + * take two arguments. + * + * @{ + */ + /// One of the @link negators negation functors@endlink. + template + class unary_negate + : public unary_function + { + protected: + _Predicate _M_pred; + + public: + _GLIBCXX14_CONSTEXPR + explicit + unary_negate(const _Predicate& __x) : _M_pred(__x) { } + + _GLIBCXX14_CONSTEXPR + bool + operator()(const typename _Predicate::argument_type& __x) const + { return !_M_pred(__x); } + }; + + /// One of the @link negators negation functors@endlink. + template + _GLIBCXX14_CONSTEXPR + inline unary_negate<_Predicate> + not1(const _Predicate& __pred) + { return unary_negate<_Predicate>(__pred); } + + /// One of the @link negators negation functors@endlink. + template + class binary_negate + : public binary_function + { + protected: + _Predicate _M_pred; + + public: + _GLIBCXX14_CONSTEXPR + explicit + binary_negate(const _Predicate& __x) : _M_pred(__x) { } + + _GLIBCXX14_CONSTEXPR + bool + operator()(const typename _Predicate::first_argument_type& __x, + const typename _Predicate::second_argument_type& __y) const + { return !_M_pred(__x, __y); } + }; + + /// One of the @link negators negation functors@endlink. + template + _GLIBCXX14_CONSTEXPR + inline binary_negate<_Predicate> + not2(const _Predicate& __pred) + { return binary_negate<_Predicate>(__pred); } + /** @} */ + + // 20.3.7 adaptors pointers functions + /** @defgroup pointer_adaptors Adaptors for pointers to functions + * @ingroup functors + * + * The advantage of function objects over pointers to functions is that + * the objects in the standard library declare nested typedefs describing + * their argument and result types with uniform names (e.g., @c result_type + * from the base classes @c unary_function and @c binary_function). + * Sometimes those typedefs are required, not just optional. + * + * Adaptors are provided to turn pointers to unary (single-argument) and + * binary (double-argument) functions into function objects. The + * long-winded functor @c pointer_to_unary_function is constructed with a + * function pointer @c f, and its @c operator() called with argument @c x + * returns @c f(x). The functor @c pointer_to_binary_function does the same + * thing, but with a double-argument @c f and @c operator(). + * + * The function @c ptr_fun takes a pointer-to-function @c f and constructs + * an instance of the appropriate functor. + * + * @{ + */ + /// One of the @link pointer_adaptors adaptors for function pointers@endlink. + template + class pointer_to_unary_function : public unary_function<_Arg, _Result> + { + protected: + _Result (*_M_ptr)(_Arg); + + public: + pointer_to_unary_function() { } + + explicit + pointer_to_unary_function(_Result (*__x)(_Arg)) + : _M_ptr(__x) { } + + _Result + operator()(_Arg __x) const + { return _M_ptr(__x); } + }; + + /// One of the @link pointer_adaptors adaptors for function pointers@endlink. + template + inline pointer_to_unary_function<_Arg, _Result> + ptr_fun(_Result (*__x)(_Arg)) + { return pointer_to_unary_function<_Arg, _Result>(__x); } + + /// One of the @link pointer_adaptors adaptors for function pointers@endlink. + template + class pointer_to_binary_function + : public binary_function<_Arg1, _Arg2, _Result> + { + protected: + _Result (*_M_ptr)(_Arg1, _Arg2); + + public: + pointer_to_binary_function() { } + + explicit + pointer_to_binary_function(_Result (*__x)(_Arg1, _Arg2)) + : _M_ptr(__x) { } + + _Result + operator()(_Arg1 __x, _Arg2 __y) const + { return _M_ptr(__x, __y); } + }; + + /// One of the @link pointer_adaptors adaptors for function pointers@endlink. + template + inline pointer_to_binary_function<_Arg1, _Arg2, _Result> + ptr_fun(_Result (*__x)(_Arg1, _Arg2)) + { return pointer_to_binary_function<_Arg1, _Arg2, _Result>(__x); } + /** @} */ + + template + struct _Identity + : public unary_function<_Tp,_Tp> + { + _Tp& + operator()(_Tp& __x) const + { return __x; } + + const _Tp& + operator()(const _Tp& __x) const + { return __x; } + }; + + template + struct _Select1st + : public unary_function<_Pair, typename _Pair::first_type> + { + typename _Pair::first_type& + operator()(_Pair& __x) const + { return __x.first; } + + const typename _Pair::first_type& + operator()(const _Pair& __x) const + { return __x.first; } + +#if __cplusplus >= 201103L + template + typename _Pair2::first_type& + operator()(_Pair2& __x) const + { return __x.first; } + + template + const typename _Pair2::first_type& + operator()(const _Pair2& __x) const + { return __x.first; } +#endif + }; + + template + struct _Select2nd + : public unary_function<_Pair, typename _Pair::second_type> + { + typename _Pair::second_type& + operator()(_Pair& __x) const + { return __x.second; } + + const typename _Pair::second_type& + operator()(const _Pair& __x) const + { return __x.second; } + }; + + // 20.3.8 adaptors pointers members + /** @defgroup memory_adaptors Adaptors for pointers to members + * @ingroup functors + * + * There are a total of 8 = 2^3 function objects in this family. + * (1) Member functions taking no arguments vs member functions taking + * one argument. + * (2) Call through pointer vs call through reference. + * (3) Const vs non-const member function. + * + * All of this complexity is in the function objects themselves. You can + * ignore it by using the helper function mem_fun and mem_fun_ref, + * which create whichever type of adaptor is appropriate. + * + * @{ + */ + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class mem_fun_t : public unary_function<_Tp*, _Ret> + { + public: + explicit + mem_fun_t(_Ret (_Tp::*__pf)()) + : _M_f(__pf) { } + + _Ret + operator()(_Tp* __p) const + { return (__p->*_M_f)(); } + + private: + _Ret (_Tp::*_M_f)(); + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class const_mem_fun_t : public unary_function + { + public: + explicit + const_mem_fun_t(_Ret (_Tp::*__pf)() const) + : _M_f(__pf) { } + + _Ret + operator()(const _Tp* __p) const + { return (__p->*_M_f)(); } + + private: + _Ret (_Tp::*_M_f)() const; + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class mem_fun_ref_t : public unary_function<_Tp, _Ret> + { + public: + explicit + mem_fun_ref_t(_Ret (_Tp::*__pf)()) + : _M_f(__pf) { } + + _Ret + operator()(_Tp& __r) const + { return (__r.*_M_f)(); } + + private: + _Ret (_Tp::*_M_f)(); + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class const_mem_fun_ref_t : public unary_function<_Tp, _Ret> + { + public: + explicit + const_mem_fun_ref_t(_Ret (_Tp::*__pf)() const) + : _M_f(__pf) { } + + _Ret + operator()(const _Tp& __r) const + { return (__r.*_M_f)(); } + + private: + _Ret (_Tp::*_M_f)() const; + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class mem_fun1_t : public binary_function<_Tp*, _Arg, _Ret> + { + public: + explicit + mem_fun1_t(_Ret (_Tp::*__pf)(_Arg)) + : _M_f(__pf) { } + + _Ret + operator()(_Tp* __p, _Arg __x) const + { return (__p->*_M_f)(__x); } + + private: + _Ret (_Tp::*_M_f)(_Arg); + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class const_mem_fun1_t : public binary_function + { + public: + explicit + const_mem_fun1_t(_Ret (_Tp::*__pf)(_Arg) const) + : _M_f(__pf) { } + + _Ret + operator()(const _Tp* __p, _Arg __x) const + { return (__p->*_M_f)(__x); } + + private: + _Ret (_Tp::*_M_f)(_Arg) const; + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class mem_fun1_ref_t : public binary_function<_Tp, _Arg, _Ret> + { + public: + explicit + mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg)) + : _M_f(__pf) { } + + _Ret + operator()(_Tp& __r, _Arg __x) const + { return (__r.*_M_f)(__x); } + + private: + _Ret (_Tp::*_M_f)(_Arg); + }; + + /// One of the @link memory_adaptors adaptors for member + /// pointers@endlink. + template + class const_mem_fun1_ref_t : public binary_function<_Tp, _Arg, _Ret> + { + public: + explicit + const_mem_fun1_ref_t(_Ret (_Tp::*__pf)(_Arg) const) + : _M_f(__pf) { } + + _Ret + operator()(const _Tp& __r, _Arg __x) const + { return (__r.*_M_f)(__x); } + + private: + _Ret (_Tp::*_M_f)(_Arg) const; + }; + + // Mem_fun adaptor helper functions. There are only two: + // mem_fun and mem_fun_ref. + template + inline mem_fun_t<_Ret, _Tp> + mem_fun(_Ret (_Tp::*__f)()) + { return mem_fun_t<_Ret, _Tp>(__f); } + + template + inline const_mem_fun_t<_Ret, _Tp> + mem_fun(_Ret (_Tp::*__f)() const) + { return const_mem_fun_t<_Ret, _Tp>(__f); } + + template + inline mem_fun_ref_t<_Ret, _Tp> + mem_fun_ref(_Ret (_Tp::*__f)()) + { return mem_fun_ref_t<_Ret, _Tp>(__f); } + + template + inline const_mem_fun_ref_t<_Ret, _Tp> + mem_fun_ref(_Ret (_Tp::*__f)() const) + { return const_mem_fun_ref_t<_Ret, _Tp>(__f); } + + template + inline mem_fun1_t<_Ret, _Tp, _Arg> + mem_fun(_Ret (_Tp::*__f)(_Arg)) + { return mem_fun1_t<_Ret, _Tp, _Arg>(__f); } + + template + inline const_mem_fun1_t<_Ret, _Tp, _Arg> + mem_fun(_Ret (_Tp::*__f)(_Arg) const) + { return const_mem_fun1_t<_Ret, _Tp, _Arg>(__f); } + + template + inline mem_fun1_ref_t<_Ret, _Tp, _Arg> + mem_fun_ref(_Ret (_Tp::*__f)(_Arg)) + { return mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); } + + template + inline const_mem_fun1_ref_t<_Ret, _Tp, _Arg> + mem_fun_ref(_Ret (_Tp::*__f)(_Arg) const) + { return const_mem_fun1_ref_t<_Ret, _Tp, _Arg>(__f); } + + /** @} */ + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if (__cplusplus < 201103L) || _GLIBCXX_USE_DEPRECATED +# include "../backward/binders.h" +#endif + +#endif /* _STL_FUNCTION_H */ diff --git a/AH/STL/Fallback/bits/stl_heap.h b/AH/STL/Fallback/bits/stl_heap.h new file mode 100644 index 0000000..9e42f82 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_heap.h @@ -0,0 +1,561 @@ +// Heap implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_heap.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{queue} + */ + +#ifndef _STL_HEAP_H +#define _STL_HEAP_H 1 + +#include "../debug/debug.h" +#include "../bits/move.h" +#include "../bits/predefined_ops.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup heap_algorithms Heap + * @ingroup sorting_algorithms + */ + + template + _Distance + __is_heap_until(_RandomAccessIterator __first, _Distance __n, + _Compare& __comp) + { + _Distance __parent = 0; + for (_Distance __child = 1; __child < __n; ++__child) + { + if (__comp(__first + __parent, __first + __child)) + return __child; + if ((__child & 1) == 0) + ++__parent; + } + return __n; + } + + // __is_heap, a predicate testing whether or not a range is a heap. + // This function is an extension, not part of the C++ standard. + template + inline bool + __is_heap(_RandomAccessIterator __first, _Distance __n) + { + __gnu_cxx::__ops::_Iter_less_iter __comp; + return std::__is_heap_until(__first, __n, __comp) == __n; + } + + template + inline bool + __is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n) + { + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + return std::__is_heap_until(__first, __n, __cmp) == __n; + } + + template + inline bool + __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { return std::__is_heap(__first, std::distance(__first, __last)); } + + template + inline bool + __is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + return std::__is_heap(__first, _GLIBCXX_MOVE(__comp), + std::distance(__first, __last)); + } + + // Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap, + // + is_heap and is_heap_until in C++0x. + + template + void + __push_heap(_RandomAccessIterator __first, + _Distance __holeIndex, _Distance __topIndex, _Tp __value, + _Compare& __comp) + { + _Distance __parent = (__holeIndex - 1) / 2; + while (__holeIndex > __topIndex && __comp(__first + __parent, __value)) + { + *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __parent)); + __holeIndex = __parent; + __parent = (__holeIndex - 1) / 2; + } + *(__first + __holeIndex) = _GLIBCXX_MOVE(__value); + } + + /** + * @brief Push an element onto a heap. + * @param __first Start of heap. + * @param __last End of heap + element. + * @ingroup heap_algorithms + * + * This operation pushes the element at last-1 onto the valid heap + * over the range [__first,__last-1). After completion, + * [__first,__last) is a valid heap. + */ + template + inline void + push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept<_ValueType>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + __glibcxx_requires_heap(__first, __last - 1); + + __gnu_cxx::__ops::_Iter_less_val __comp; + _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + std::__push_heap(__first, _DistanceType((__last - __first) - 1), + _DistanceType(0), _GLIBCXX_MOVE(__value), __comp); + } + + /** + * @brief Push an element onto a heap using comparison functor. + * @param __first Start of heap. + * @param __last End of heap + element. + * @param __comp Comparison functor. + * @ingroup heap_algorithms + * + * This operation pushes the element at __last-1 onto the valid + * heap over the range [__first,__last-1). After completion, + * [__first,__last) is a valid heap. Compare operations are + * performed using comp. + */ + template + inline void + push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + __glibcxx_requires_heap_pred(__first, __last - 1, __comp); + + __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp))) + __cmp(_GLIBCXX_MOVE(__comp)); + _ValueType __value = _GLIBCXX_MOVE(*(__last - 1)); + std::__push_heap(__first, _DistanceType((__last - __first) - 1), + _DistanceType(0), _GLIBCXX_MOVE(__value), __cmp); + } + + template + void + __adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex, + _Distance __len, _Tp __value, _Compare __comp) + { + const _Distance __topIndex = __holeIndex; + _Distance __secondChild = __holeIndex; + while (__secondChild < (__len - 1) / 2) + { + __secondChild = 2 * (__secondChild + 1); + if (__comp(__first + __secondChild, + __first + (__secondChild - 1))) + __secondChild--; + *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild)); + __holeIndex = __secondChild; + } + if ((__len & 1) == 0 && __secondChild == (__len - 2) / 2) + { + __secondChild = 2 * (__secondChild + 1); + *(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + + (__secondChild - 1))); + __holeIndex = __secondChild - 1; + } + __decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp))) + __cmp(_GLIBCXX_MOVE(__comp)); + std::__push_heap(__first, __holeIndex, __topIndex, + _GLIBCXX_MOVE(__value), __cmp); + } + + template + inline void + __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _RandomAccessIterator __result, _Compare& __comp) + { + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + _ValueType __value = _GLIBCXX_MOVE(*__result); + *__result = _GLIBCXX_MOVE(*__first); + std::__adjust_heap(__first, _DistanceType(0), + _DistanceType(__last - __first), + _GLIBCXX_MOVE(__value), __comp); + } + + /** + * @brief Pop an element off a heap. + * @param __first Start of heap. + * @param __last End of heap. + * @pre [__first, __last) is a valid, non-empty range. + * @ingroup heap_algorithms + * + * This operation pops the top of the heap. The elements __first + * and __last-1 are swapped and [__first,__last-1) is made into a + * heap. + */ + template + inline void + pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_non_empty_range(__first, __last); + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + __glibcxx_requires_heap(__first, __last); + + if (__last - __first > 1) + { + --__last; + __gnu_cxx::__ops::_Iter_less_iter __comp; + std::__pop_heap(__first, __last, __last, __comp); + } + } + + /** + * @brief Pop an element off a heap using comparison functor. + * @param __first Start of heap. + * @param __last End of heap. + * @param __comp Comparison functor to use. + * @ingroup heap_algorithms + * + * This operation pops the top of the heap. The elements __first + * and __last-1 are swapped and [__first,__last-1) is made into a + * heap. Comparisons are made using comp. + */ + template + inline void + pop_heap(_RandomAccessIterator __first, + _RandomAccessIterator __last, _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + __glibcxx_requires_non_empty_range(__first, __last); + __glibcxx_requires_heap_pred(__first, __last, __comp); + + if (__last - __first > 1) + { + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + --__last; + std::__pop_heap(__first, __last, __last, __cmp); + } + } + + template + void + __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare& __comp) + { + typedef typename iterator_traits<_RandomAccessIterator>::value_type + _ValueType; + typedef typename iterator_traits<_RandomAccessIterator>::difference_type + _DistanceType; + + if (__last - __first < 2) + return; + + const _DistanceType __len = __last - __first; + _DistanceType __parent = (__len - 2) / 2; + while (true) + { + _ValueType __value = _GLIBCXX_MOVE(*(__first + __parent)); + std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value), + __comp); + if (__parent == 0) + return; + __parent--; + } + } + + /** + * @brief Construct a heap over a range. + * @param __first Start of heap. + * @param __last End of heap. + * @ingroup heap_algorithms + * + * This operation makes the elements in [__first,__last) into a heap. + */ + template + inline void + make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + __gnu_cxx::__ops::_Iter_less_iter __comp; + std::__make_heap(__first, __last, __comp); + } + + /** + * @brief Construct a heap over a range using comparison functor. + * @param __first Start of heap. + * @param __last End of heap. + * @param __comp Comparison functor to use. + * @ingroup heap_algorithms + * + * This operation makes the elements in [__first,__last) into a heap. + * Comparisons are made using __comp. + */ + template + inline void + make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + std::__make_heap(__first, __last, __cmp); + } + + template + void + __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare& __comp) + { + while (__last - __first > 1) + { + --__last; + std::__pop_heap(__first, __last, __last, __comp); + } + } + + /** + * @brief Sort a heap. + * @param __first Start of heap. + * @param __last End of heap. + * @ingroup heap_algorithms + * + * This operation sorts the valid heap in the range [__first,__last). + */ + template + inline void + sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + __glibcxx_requires_heap(__first, __last); + + __gnu_cxx::__ops::_Iter_less_iter __comp; + std::__sort_heap(__first, __last, __comp); + } + + /** + * @brief Sort a heap using comparison functor. + * @param __first Start of heap. + * @param __last End of heap. + * @param __comp Comparison functor to use. + * @ingroup heap_algorithms + * + * This operation sorts the valid heap in the range [__first,__last). + * Comparisons are made using __comp. + */ + template + inline void + sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + __glibcxx_requires_heap_pred(__first, __last, __comp); + + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + std::__sort_heap(__first, __last, __cmp); + } + +#if __cplusplus >= 201103L + /** + * @brief Search the end of a heap. + * @param __first Start of range. + * @param __last End of range. + * @return An iterator pointing to the first element not in the heap. + * @ingroup heap_algorithms + * + * This operation returns the last iterator i in [__first, __last) for which + * the range [__first, i) is a heap. + */ + template + inline _RandomAccessIterator + is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last) + { + // concept requirements + __glibcxx_function_requires(_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_function_requires(_LessThanComparableConcept< + typename iterator_traits<_RandomAccessIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive(__first, __last); + + __gnu_cxx::__ops::_Iter_less_iter __comp; + return __first + + std::__is_heap_until(__first, std::distance(__first, __last), __comp); + } + + /** + * @brief Search the end of a heap using comparison functor. + * @param __first Start of range. + * @param __last End of range. + * @param __comp Comparison functor to use. + * @return An iterator pointing to the first element not in the heap. + * @ingroup heap_algorithms + * + * This operation returns the last iterator i in [__first, __last) for which + * the range [__first, i) is a heap. Comparisons are made using __comp. + */ + template + inline _RandomAccessIterator + is_heap_until(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + return __first + + std::__is_heap_until(__first, std::distance(__first, __last), __cmp); + } + + /** + * @brief Determines whether a range is a heap. + * @param __first Start of range. + * @param __last End of range. + * @return True if range is a heap, false otherwise. + * @ingroup heap_algorithms + */ + template + inline bool + is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) + { return std::is_heap_until(__first, __last) == __last; } + + /** + * @brief Determines whether a range is a heap using comparison functor. + * @param __first Start of range. + * @param __last End of range. + * @param __comp Comparison functor to use. + * @return True if range is a heap, false otherwise. + * @ingroup heap_algorithms + */ + template + inline bool + is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, + _Compare __comp) + { + // concept requirements + __glibcxx_function_requires(_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __glibcxx_requires_valid_range(__first, __last); + __glibcxx_requires_irreflexive_pred(__first, __last, __comp); + + const auto __dist = std::distance(__first, __last); + typedef __decltype(__comp) _Cmp; + __gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp)); + return std::__is_heap_until(__first, __dist, __cmp) == __dist; + } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _STL_HEAP_H */ diff --git a/AH/STL/Fallback/bits/stl_iterator.h b/AH/STL/Fallback/bits/stl_iterator.h new file mode 100644 index 0000000..a2be069 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_iterator.h @@ -0,0 +1,1263 @@ +// Iterators -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_iterator.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + * + * This file implements reverse_iterator, back_insert_iterator, + * front_insert_iterator, insert_iterator, __normal_iterator, and their + * supporting functions and overloaded operators. + */ + +#ifndef _STL_ITERATOR_H +#define _STL_ITERATOR_H 1 + +#include "../bits/cpp_type_traits.h" +#include "../ext/type_traits.h" +#include "../bits/move.h" +#include "../bits/ptr_traits.h" + +#if __cplusplus > 201402L +# define __cpp_lib_array_constexpr 201603 +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup iterators + * @{ + */ + + // 24.4.1 Reverse iterators + /** + * Bidirectional and random access iterators have corresponding reverse + * %iterator adaptors that iterate through the data structure in the + * opposite direction. They have the same signatures as the corresponding + * iterators. The fundamental relation between a reverse %iterator and its + * corresponding %iterator @c i is established by the identity: + * @code + * &*(reverse_iterator(i)) == &*(i - 1) + * @endcode + * + * This mapping is dictated by the fact that while there is always a + * pointer past the end of an array, there might not be a valid pointer + * before the beginning of an array. [24.4.1]/1,2 + * + * Reverse iterators can be tricky and surprising at first. Their + * semantics make sense, however, and the trickiness is a side effect of + * the requirement that the iterators must be safe. + */ + template + class reverse_iterator + : public iterator::iterator_category, + typename iterator_traits<_Iterator>::value_type, + typename iterator_traits<_Iterator>::difference_type, + typename iterator_traits<_Iterator>::pointer, + typename iterator_traits<_Iterator>::reference> + { + protected: + _Iterator current; + + typedef iterator_traits<_Iterator> __traits_type; + + public: + typedef _Iterator iterator_type; + typedef typename __traits_type::difference_type difference_type; + typedef typename __traits_type::pointer pointer; + typedef typename __traits_type::reference reference; + + /** + * The default constructor value-initializes member @p current. + * If it is a pointer, that means it is zero-initialized. + */ + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 235 No specification of default ctor for reverse_iterator + // 1012. reverse_iterator default ctor should value initialize + _GLIBCXX17_CONSTEXPR + reverse_iterator() : current() { } + + /** + * This %iterator will move in the opposite direction that @p x does. + */ + explicit _GLIBCXX17_CONSTEXPR + reverse_iterator(iterator_type __x) : current(__x) { } + + /** + * The copy constructor is normal. + */ + _GLIBCXX17_CONSTEXPR + reverse_iterator(const reverse_iterator& __x) + : current(__x.current) { } + + /** + * A %reverse_iterator across other types can be copied if the + * underlying %iterator can be converted to the type of @c current. + */ + template + _GLIBCXX17_CONSTEXPR + reverse_iterator(const reverse_iterator<_Iter>& __x) + : current(__x.base()) { } + + /** + * @return @c current, the %iterator used for underlying work. + */ + _GLIBCXX17_CONSTEXPR iterator_type + base() const + { return current; } + + /** + * @return A reference to the value at @c --current + * + * This requires that @c --current is dereferenceable. + * + * @warning This implementation requires that for an iterator of the + * underlying iterator type, @c x, a reference obtained by + * @c *x remains valid after @c x has been modified or + * destroyed. This is a bug: http://gcc.gnu.org/PR51823 + */ + _GLIBCXX17_CONSTEXPR reference + operator*() const + { + _Iterator __tmp = current; + return *--__tmp; + } + + /** + * @return A pointer to the value at @c --current + * + * This requires that @c --current is dereferenceable. + */ + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2188. Reverse iterator does not fully support targets that overload & + _GLIBCXX17_CONSTEXPR pointer + operator->() const + { return std::__addressof(operator*()); } + + /** + * @return @c *this + * + * Decrements the underlying iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator& + operator++() + { + --current; + return *this; + } + + /** + * @return The original value of @c *this + * + * Decrements the underlying iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator + operator++(int) + { + reverse_iterator __tmp = *this; + --current; + return __tmp; + } + + /** + * @return @c *this + * + * Increments the underlying iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator& + operator--() + { + ++current; + return *this; + } + + /** + * @return A reverse_iterator with the previous value of @c *this + * + * Increments the underlying iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator + operator--(int) + { + reverse_iterator __tmp = *this; + ++current; + return __tmp; + } + + /** + * @return A reverse_iterator that refers to @c current - @a __n + * + * The underlying iterator must be a Random Access Iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator + operator+(difference_type __n) const + { return reverse_iterator(current - __n); } + + /** + * @return *this + * + * Moves the underlying iterator backwards @a __n steps. + * The underlying iterator must be a Random Access Iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator& + operator+=(difference_type __n) + { + current -= __n; + return *this; + } + + /** + * @return A reverse_iterator that refers to @c current - @a __n + * + * The underlying iterator must be a Random Access Iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator + operator-(difference_type __n) const + { return reverse_iterator(current + __n); } + + /** + * @return *this + * + * Moves the underlying iterator forwards @a __n steps. + * The underlying iterator must be a Random Access Iterator. + */ + _GLIBCXX17_CONSTEXPR reverse_iterator& + operator-=(difference_type __n) + { + current += __n; + return *this; + } + + /** + * @return The value at @c current - @a __n - 1 + * + * The underlying iterator must be a Random Access Iterator. + */ + _GLIBCXX17_CONSTEXPR reference + operator[](difference_type __n) const + { return *(*this + __n); } + }; + + //@{ + /** + * @param __x A %reverse_iterator. + * @param __y A %reverse_iterator. + * @return A simple bool. + * + * Reverse iterators forward many operations to their underlying base() + * iterators. Others are implemented in terms of one another. + * + */ + template + inline _GLIBCXX17_CONSTEXPR bool + operator==(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __x.base() == __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __y.base() < __x.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator!=(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return !(__x == __y); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __y < __x; } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<=(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return !(__y < __x); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>=(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return !(__x < __y); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 280. Comparison of reverse_iterator to const reverse_iterator. + template + inline _GLIBCXX17_CONSTEXPR bool + operator==(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return __x.base() == __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return __y.base() < __x.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator!=(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return !(__x == __y); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return __y < __x; } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<=(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return !(__y < __x); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>=(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return !(__x < __y); } + //@} + +#if __cplusplus < 201103L + template + inline typename reverse_iterator<_Iterator>::difference_type + operator-(const reverse_iterator<_Iterator>& __x, + const reverse_iterator<_Iterator>& __y) + { return __y.base() - __x.base(); } + + template + inline typename reverse_iterator<_IteratorL>::difference_type + operator-(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + { return __y.base() - __x.base(); } +#else + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 685. reverse_iterator/move_iterator difference has invalid signatures + template + inline _GLIBCXX17_CONSTEXPR auto + operator-(const reverse_iterator<_IteratorL>& __x, + const reverse_iterator<_IteratorR>& __y) + -> decltype(__y.base() - __x.base()) + { return __y.base() - __x.base(); } +#endif + + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> + operator+(typename reverse_iterator<_Iterator>::difference_type __n, + const reverse_iterator<_Iterator>& __x) + { return reverse_iterator<_Iterator>(__x.base() - __n); } + +#if __cplusplus >= 201103L + // Same as C++14 make_reverse_iterator but used in C++03 mode too. + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> + __make_reverse_iterator(_Iterator __i) + { return reverse_iterator<_Iterator>(__i); } + +# if __cplusplus > 201103L +# define __cpp_lib_make_reverse_iterator 201402 + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 2285. make_reverse_iterator + /// Generator function for reverse_iterator. + template + inline _GLIBCXX17_CONSTEXPR reverse_iterator<_Iterator> + make_reverse_iterator(_Iterator __i) + { return reverse_iterator<_Iterator>(__i); } +# endif +#endif + +#if __cplusplus >= 201103L + template + auto + __niter_base(reverse_iterator<_Iterator> __it) + -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) + { return __make_reverse_iterator(__niter_base(__it.base())); } + + template + struct __is_move_iterator > + : __is_move_iterator<_Iterator> + { }; + + template + auto + __miter_base(reverse_iterator<_Iterator> __it) + -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) + { return __make_reverse_iterator(__miter_base(__it.base())); } +#endif + + // 24.4.2.2.1 back_insert_iterator + /** + * @brief Turns assignment into insertion. + * + * These are output iterators, constructed from a container-of-T. + * Assigning a T to the iterator appends it to the container using + * push_back. + * + * Tip: Using the back_inserter function to create these iterators can + * save typing. + */ + template + class back_insert_iterator + : public iterator + { + protected: + _Container* container; + + public: + /// A nested typedef for the type of whatever container you used. + typedef _Container container_type; + + /// The only way to create this %iterator is with a container. + explicit + back_insert_iterator(_Container& __x) + : container(std::__addressof(__x)) { } + + /** + * @param __value An instance of whatever type + * container_type::const_reference is; presumably a + * reference-to-const T for container. + * @return This %iterator, for chained operations. + * + * This kind of %iterator doesn't really have a @a position in the + * container (you can think of the position as being permanently at + * the end, if you like). Assigning a value to the %iterator will + * always append the value to the end of the container. + */ +#if __cplusplus < 201103L + back_insert_iterator& + operator=(typename _Container::const_reference __value) + { + container->push_back(__value); + return *this; + } +#else + back_insert_iterator& + operator=(const typename _Container::value_type& __value) + { + container->push_back(__value); + return *this; + } + + back_insert_iterator& + operator=(typename _Container::value_type&& __value) + { + container->push_back(std::move(__value)); + return *this; + } +#endif + + /// Simply returns *this. + back_insert_iterator& + operator*() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + back_insert_iterator& + operator++() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + back_insert_iterator + operator++(int) + { return *this; } + }; + + /** + * @param __x A container of arbitrary type. + * @return An instance of back_insert_iterator working on @p __x. + * + * This wrapper function helps in creating back_insert_iterator instances. + * Typing the name of the %iterator requires knowing the precise full + * type of the container, which can be tedious and impedes generic + * programming. Using this function lets you take advantage of automatic + * template parameter deduction, making the compiler match the correct + * types for you. + */ + template + inline back_insert_iterator<_Container> + back_inserter(_Container& __x) + { return back_insert_iterator<_Container>(__x); } + + /** + * @brief Turns assignment into insertion. + * + * These are output iterators, constructed from a container-of-T. + * Assigning a T to the iterator prepends it to the container using + * push_front. + * + * Tip: Using the front_inserter function to create these iterators can + * save typing. + */ + template + class front_insert_iterator + : public iterator + { + protected: + _Container* container; + + public: + /// A nested typedef for the type of whatever container you used. + typedef _Container container_type; + + /// The only way to create this %iterator is with a container. + explicit front_insert_iterator(_Container& __x) + : container(std::__addressof(__x)) { } + + /** + * @param __value An instance of whatever type + * container_type::const_reference is; presumably a + * reference-to-const T for container. + * @return This %iterator, for chained operations. + * + * This kind of %iterator doesn't really have a @a position in the + * container (you can think of the position as being permanently at + * the front, if you like). Assigning a value to the %iterator will + * always prepend the value to the front of the container. + */ +#if __cplusplus < 201103L + front_insert_iterator& + operator=(typename _Container::const_reference __value) + { + container->push_front(__value); + return *this; + } +#else + front_insert_iterator& + operator=(const typename _Container::value_type& __value) + { + container->push_front(__value); + return *this; + } + + front_insert_iterator& + operator=(typename _Container::value_type&& __value) + { + container->push_front(std::move(__value)); + return *this; + } +#endif + + /// Simply returns *this. + front_insert_iterator& + operator*() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + front_insert_iterator& + operator++() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + front_insert_iterator + operator++(int) + { return *this; } + }; + + /** + * @param __x A container of arbitrary type. + * @return An instance of front_insert_iterator working on @p x. + * + * This wrapper function helps in creating front_insert_iterator instances. + * Typing the name of the %iterator requires knowing the precise full + * type of the container, which can be tedious and impedes generic + * programming. Using this function lets you take advantage of automatic + * template parameter deduction, making the compiler match the correct + * types for you. + */ + template + inline front_insert_iterator<_Container> + front_inserter(_Container& __x) + { return front_insert_iterator<_Container>(__x); } + + /** + * @brief Turns assignment into insertion. + * + * These are output iterators, constructed from a container-of-T. + * Assigning a T to the iterator inserts it in the container at the + * %iterator's position, rather than overwriting the value at that + * position. + * + * (Sequences will actually insert a @e copy of the value before the + * %iterator's position.) + * + * Tip: Using the inserter function to create these iterators can + * save typing. + */ + template + class insert_iterator + : public iterator + { + protected: + _Container* container; + typename _Container::iterator iter; + + public: + /// A nested typedef for the type of whatever container you used. + typedef _Container container_type; + + /** + * The only way to create this %iterator is with a container and an + * initial position (a normal %iterator into the container). + */ + insert_iterator(_Container& __x, typename _Container::iterator __i) + : container(std::__addressof(__x)), iter(__i) {} + + /** + * @param __value An instance of whatever type + * container_type::const_reference is; presumably a + * reference-to-const T for container. + * @return This %iterator, for chained operations. + * + * This kind of %iterator maintains its own position in the + * container. Assigning a value to the %iterator will insert the + * value into the container at the place before the %iterator. + * + * The position is maintained such that subsequent assignments will + * insert values immediately after one another. For example, + * @code + * // vector v contains A and Z + * + * insert_iterator i (v, ++v.begin()); + * i = 1; + * i = 2; + * i = 3; + * + * // vector v contains A, 1, 2, 3, and Z + * @endcode + */ +#if __cplusplus < 201103L + insert_iterator& + operator=(typename _Container::const_reference __value) + { + iter = container->insert(iter, __value); + ++iter; + return *this; + } +#else + insert_iterator& + operator=(const typename _Container::value_type& __value) + { + iter = container->insert(iter, __value); + ++iter; + return *this; + } + + insert_iterator& + operator=(typename _Container::value_type&& __value) + { + iter = container->insert(iter, std::move(__value)); + ++iter; + return *this; + } +#endif + + /// Simply returns *this. + insert_iterator& + operator*() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + insert_iterator& + operator++() + { return *this; } + + /// Simply returns *this. (This %iterator does not @a move.) + insert_iterator& + operator++(int) + { return *this; } + }; + + /** + * @param __x A container of arbitrary type. + * @return An instance of insert_iterator working on @p __x. + * + * This wrapper function helps in creating insert_iterator instances. + * Typing the name of the %iterator requires knowing the precise full + * type of the container, which can be tedious and impedes generic + * programming. Using this function lets you take advantage of automatic + * template parameter deduction, making the compiler match the correct + * types for you. + */ + template + inline insert_iterator<_Container> + inserter(_Container& __x, _Iterator __i) + { + return insert_iterator<_Container>(__x, + typename _Container::iterator(__i)); + } + + // @} group iterators + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // This iterator adapter is @a normal in the sense that it does not + // change the semantics of any of the operators of its iterator + // parameter. Its primary purpose is to convert an iterator that is + // not a class, e.g. a pointer, into an iterator that is a class. + // The _Container parameter exists solely so that different containers + // using this template can instantiate different types, even if the + // _Iterator parameter is the same. + using std::iterator_traits; + using std::iterator; + template + class __normal_iterator + { + protected: + _Iterator _M_current; + + typedef iterator_traits<_Iterator> __traits_type; + + public: + typedef _Iterator iterator_type; + typedef typename __traits_type::iterator_category iterator_category; + typedef typename __traits_type::value_type value_type; + typedef typename __traits_type::difference_type difference_type; + typedef typename __traits_type::reference reference; + typedef typename __traits_type::pointer pointer; + + _GLIBCXX_CONSTEXPR __normal_iterator() _GLIBCXX_NOEXCEPT + : _M_current(_Iterator()) { } + + explicit + __normal_iterator(const _Iterator& __i) _GLIBCXX_NOEXCEPT + : _M_current(__i) { } + + // Allow iterator to const_iterator conversion + template + __normal_iterator(const __normal_iterator<_Iter, + typename __enable_if< + (std::__are_same<_Iter, typename _Container::pointer>::__value), + _Container>::__type>& __i) _GLIBCXX_NOEXCEPT + : _M_current(__i.base()) { } + + // Forward iterator requirements + reference + operator*() const _GLIBCXX_NOEXCEPT + { return *_M_current; } + + pointer + operator->() const _GLIBCXX_NOEXCEPT + { return _M_current; } + + __normal_iterator& + operator++() _GLIBCXX_NOEXCEPT + { + ++_M_current; + return *this; + } + + __normal_iterator + operator++(int) _GLIBCXX_NOEXCEPT + { return __normal_iterator(_M_current++); } + + // Bidirectional iterator requirements + __normal_iterator& + operator--() _GLIBCXX_NOEXCEPT + { + --_M_current; + return *this; + } + + __normal_iterator + operator--(int) _GLIBCXX_NOEXCEPT + { return __normal_iterator(_M_current--); } + + // Random access iterator requirements + reference + operator[](difference_type __n) const _GLIBCXX_NOEXCEPT + { return _M_current[__n]; } + + __normal_iterator& + operator+=(difference_type __n) _GLIBCXX_NOEXCEPT + { _M_current += __n; return *this; } + + __normal_iterator + operator+(difference_type __n) const _GLIBCXX_NOEXCEPT + { return __normal_iterator(_M_current + __n); } + + __normal_iterator& + operator-=(difference_type __n) _GLIBCXX_NOEXCEPT + { _M_current -= __n; return *this; } + + __normal_iterator + operator-(difference_type __n) const _GLIBCXX_NOEXCEPT + { return __normal_iterator(_M_current - __n); } + + const _Iterator& + base() const _GLIBCXX_NOEXCEPT + { return _M_current; } + }; + + // Note: In what follows, the left- and right-hand-side iterators are + // allowed to vary in types (conceptually in cv-qualification) so that + // comparison between cv-qualified and non-cv-qualified iterators be + // valid. However, the greedy and unfriendly operators in std::rel_ops + // will make overload resolution ambiguous (when in scope) if we don't + // provide overloads whose operands are of the same type. Can someone + // remind me what generic programming is about? -- Gaby + + // Forward iterator requirements + template + inline bool + operator==(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() == __rhs.base(); } + + template + inline bool + operator==(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() == __rhs.base(); } + + template + inline bool + operator!=(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() != __rhs.base(); } + + template + inline bool + operator!=(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() != __rhs.base(); } + + // Random access iterator requirements + template + inline bool + operator<(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() < __rhs.base(); } + + template + inline bool + operator<(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() < __rhs.base(); } + + template + inline bool + operator>(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() > __rhs.base(); } + + template + inline bool + operator>(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() > __rhs.base(); } + + template + inline bool + operator<=(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() <= __rhs.base(); } + + template + inline bool + operator<=(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() <= __rhs.base(); } + + template + inline bool + operator>=(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() >= __rhs.base(); } + + template + inline bool + operator>=(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() >= __rhs.base(); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // According to the resolution of DR179 not only the various comparison + // operators but also operator- must accept mixed iterator/const_iterator + // parameters. + template +#if __cplusplus >= 201103L + // DR 685. + inline auto + operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) noexcept + -> decltype(__lhs.base() - __rhs.base()) +#else + inline typename __normal_iterator<_IteratorL, _Container>::difference_type + operator-(const __normal_iterator<_IteratorL, _Container>& __lhs, + const __normal_iterator<_IteratorR, _Container>& __rhs) +#endif + { return __lhs.base() - __rhs.base(); } + + template + inline typename __normal_iterator<_Iterator, _Container>::difference_type + operator-(const __normal_iterator<_Iterator, _Container>& __lhs, + const __normal_iterator<_Iterator, _Container>& __rhs) + _GLIBCXX_NOEXCEPT + { return __lhs.base() - __rhs.base(); } + + template + inline __normal_iterator<_Iterator, _Container> + operator+(typename __normal_iterator<_Iterator, _Container>::difference_type + __n, const __normal_iterator<_Iterator, _Container>& __i) + _GLIBCXX_NOEXCEPT + { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template + _Iterator + __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) + { return __it.base(); } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if __cplusplus >= 201103L + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup iterators + * @{ + */ + + // 24.4.3 Move iterators + /** + * Class template move_iterator is an iterator adapter with the same + * behavior as the underlying iterator except that its dereference + * operator implicitly converts the value returned by the underlying + * iterator's dereference operator to an rvalue reference. Some + * generic algorithms can be called with move iterators to replace + * copying with moving. + */ + template + class move_iterator + { + protected: + _Iterator _M_current; + + typedef iterator_traits<_Iterator> __traits_type; + typedef typename __traits_type::reference __base_ref; + + public: + typedef _Iterator iterator_type; + typedef typename __traits_type::iterator_category iterator_category; + typedef typename __traits_type::value_type value_type; + typedef typename __traits_type::difference_type difference_type; + // NB: DR 680. + typedef _Iterator pointer; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2106. move_iterator wrapping iterators returning prvalues + typedef typename conditional::value, + typename remove_reference<__base_ref>::type&&, + __base_ref>::type reference; + + _GLIBCXX17_CONSTEXPR + move_iterator() + : _M_current() { } + + explicit _GLIBCXX17_CONSTEXPR + move_iterator(iterator_type __i) + : _M_current(__i) { } + + template + _GLIBCXX17_CONSTEXPR + move_iterator(const move_iterator<_Iter>& __i) + : _M_current(__i.base()) { } + + _GLIBCXX17_CONSTEXPR iterator_type + base() const + { return _M_current; } + + _GLIBCXX17_CONSTEXPR reference + operator*() const + { return static_cast(*_M_current); } + + _GLIBCXX17_CONSTEXPR pointer + operator->() const + { return _M_current; } + + _GLIBCXX17_CONSTEXPR move_iterator& + operator++() + { + ++_M_current; + return *this; + } + + _GLIBCXX17_CONSTEXPR move_iterator + operator++(int) + { + move_iterator __tmp = *this; + ++_M_current; + return __tmp; + } + + _GLIBCXX17_CONSTEXPR move_iterator& + operator--() + { + --_M_current; + return *this; + } + + _GLIBCXX17_CONSTEXPR move_iterator + operator--(int) + { + move_iterator __tmp = *this; + --_M_current; + return __tmp; + } + + _GLIBCXX17_CONSTEXPR move_iterator + operator+(difference_type __n) const + { return move_iterator(_M_current + __n); } + + _GLIBCXX17_CONSTEXPR move_iterator& + operator+=(difference_type __n) + { + _M_current += __n; + return *this; + } + + _GLIBCXX17_CONSTEXPR move_iterator + operator-(difference_type __n) const + { return move_iterator(_M_current - __n); } + + _GLIBCXX17_CONSTEXPR move_iterator& + operator-=(difference_type __n) + { + _M_current -= __n; + return *this; + } + + _GLIBCXX17_CONSTEXPR reference + operator[](difference_type __n) const + { return std::move(_M_current[__n]); } + }; + + // Note: See __normal_iterator operators note from Gaby to understand + // why there are always 2 versions for most of the move_iterator + // operators. + template + inline _GLIBCXX17_CONSTEXPR bool + operator==(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return __x.base() == __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator==(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return __x.base() == __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator!=(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return !(__x == __y); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator!=(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return !(__x == __y); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return __x.base() < __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return __x.base() < __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<=(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return !(__y < __x); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator<=(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return !(__y < __x); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return __y < __x; } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return __y < __x; } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>=(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + { return !(__x < __y); } + + template + inline _GLIBCXX17_CONSTEXPR bool + operator>=(const move_iterator<_Iterator>& __x, + const move_iterator<_Iterator>& __y) + { return !(__x < __y); } + + // DR 685. + template + inline _GLIBCXX17_CONSTEXPR auto + operator-(const move_iterator<_IteratorL>& __x, + const move_iterator<_IteratorR>& __y) + -> decltype(__x.base() - __y.base()) + { return __x.base() - __y.base(); } + + template + inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator> + operator+(typename move_iterator<_Iterator>::difference_type __n, + const move_iterator<_Iterator>& __x) + { return __x + __n; } + + template + inline _GLIBCXX17_CONSTEXPR move_iterator<_Iterator> + make_move_iterator(_Iterator __i) + { return move_iterator<_Iterator>(__i); } + + template::value_type>::value, + _Iterator, move_iterator<_Iterator>>::type> + inline _GLIBCXX17_CONSTEXPR _ReturnType + __make_move_if_noexcept_iterator(_Iterator __i) + { return _ReturnType(__i); } + + // Overload for pointers that matches std::move_if_noexcept more closely, + // returning a constant iterator when we don't want to move. + template::value, + const _Tp*, move_iterator<_Tp*>>::type> + inline _GLIBCXX17_CONSTEXPR _ReturnType + __make_move_if_noexcept_iterator(_Tp* __i) + { return _ReturnType(__i); } + + // @} group iterators + + template + auto + __niter_base(move_iterator<_Iterator> __it) + -> decltype(make_move_iterator(__niter_base(__it.base()))) + { return make_move_iterator(__niter_base(__it.base())); } + + template + struct __is_move_iterator > + { + enum { __value = 1 }; + typedef __true_type __type; + }; + + template + auto + __miter_base(move_iterator<_Iterator> __it) + -> decltype(__miter_base(__it.base())) + { return __miter_base(__it.base()); } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) std::make_move_iterator(_Iter) +#define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) \ + std::__make_move_if_noexcept_iterator(_Iter) +#else +#define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) (_Iter) +#define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) (_Iter) +#endif // C++11 + +#ifdef _GLIBCXX_DEBUG +# include +#endif + +#endif diff --git a/AH/STL/Fallback/bits/stl_iterator_base_funcs.h b/AH/STL/Fallback/bits/stl_iterator_base_funcs.h new file mode 100644 index 0000000..9bf0c0e --- /dev/null +++ b/AH/STL/Fallback/bits/stl_iterator_base_funcs.h @@ -0,0 +1,235 @@ +// Functions used by iterators -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_iterator_base_funcs.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + * + * This file contains all of the general iterator-related utility + * functions, such as distance() and advance(). + */ + +#ifndef _STL_ITERATOR_BASE_FUNCS_H +#define _STL_ITERATOR_BASE_FUNCS_H 1 + +#pragma GCC system_header + +#include "../bits/concept_check.h" +// #include + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + // Forward declaration for the overloads of __distance. + template struct _List_iterator; + template struct _List_const_iterator; +_GLIBCXX_END_NAMESPACE_CONTAINER + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template + inline _GLIBCXX14_CONSTEXPR + typename iterator_traits<_InputIterator>::difference_type + __distance(_InputIterator __first, _InputIterator __last, + input_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + + typename iterator_traits<_InputIterator>::difference_type __n = 0; + while (__first != __last) + { + ++__first; + ++__n; + } + return __n; + } + + template + inline _GLIBCXX14_CONSTEXPR + typename iterator_traits<_RandomAccessIterator>::difference_type + __distance(_RandomAccessIterator __first, _RandomAccessIterator __last, + random_access_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_RandomAccessIteratorConcept< + _RandomAccessIterator>) + return __last - __first; + } + +#if _GLIBCXX_USE_CXX11_ABI + // Forward declaration because of the qualified call in distance. + template + ptrdiff_t + __distance(_GLIBCXX_STD_C::_List_iterator<_Tp>, + _GLIBCXX_STD_C::_List_iterator<_Tp>, + input_iterator_tag); + + template + ptrdiff_t + __distance(_GLIBCXX_STD_C::_List_const_iterator<_Tp>, + _GLIBCXX_STD_C::_List_const_iterator<_Tp>, + input_iterator_tag); +#endif + + /** + * @brief A generalization of pointer arithmetic. + * @param __first An input iterator. + * @param __last An input iterator. + * @return The distance between them. + * + * Returns @c n such that __first + n == __last. This requires + * that @p __last must be reachable from @p __first. Note that @c + * n may be negative. + * + * For random access iterators, this uses their @c + and @c - operations + * and are constant time. For other %iterator classes they are linear time. + */ + template + inline _GLIBCXX17_CONSTEXPR + typename iterator_traits<_InputIterator>::difference_type + distance(_InputIterator __first, _InputIterator __last) + { + // concept requirements -- taken care of in __distance + return std::__distance(__first, __last, + std::__iterator_category(__first)); + } + + template + inline _GLIBCXX14_CONSTEXPR void + __advance(_InputIterator& __i, _Distance __n, input_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_assert(__n >= 0); + while (__n--) + ++__i; + } + + template + inline _GLIBCXX14_CONSTEXPR void + __advance(_BidirectionalIterator& __i, _Distance __n, + bidirectional_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + if (__n > 0) + while (__n--) + ++__i; + else + while (__n++) + --__i; + } + + template + inline _GLIBCXX14_CONSTEXPR void + __advance(_RandomAccessIterator& __i, _Distance __n, + random_access_iterator_tag) + { + // concept requirements + __glibcxx_function_requires(_RandomAccessIteratorConcept< + _RandomAccessIterator>) + __i += __n; + } + + /** + * @brief A generalization of pointer arithmetic. + * @param __i An input iterator. + * @param __n The @a delta by which to change @p __i. + * @return Nothing. + * + * This increments @p i by @p n. For bidirectional and random access + * iterators, @p __n may be negative, in which case @p __i is decremented. + * + * For random access iterators, this uses their @c + and @c - operations + * and are constant time. For other %iterator classes they are linear time. + */ + template + inline _GLIBCXX17_CONSTEXPR void + advance(_InputIterator& __i, _Distance __n) + { + // concept requirements -- taken care of in __advance + typename iterator_traits<_InputIterator>::difference_type __d = __n; + std::__advance(__i, __d, std::__iterator_category(__i)); + } + +#if __cplusplus >= 201103L + + template + inline _GLIBCXX17_CONSTEXPR _ForwardIterator + next(_ForwardIterator __x, typename + iterator_traits<_ForwardIterator>::difference_type __n = 1) + { + // concept requirements + __glibcxx_function_requires(_ForwardIteratorConcept< + _ForwardIterator>) + std::advance(__x, __n); + return __x; + } + + template + inline _GLIBCXX17_CONSTEXPR _BidirectionalIterator + prev(_BidirectionalIterator __x, typename + iterator_traits<_BidirectionalIterator>::difference_type __n = 1) + { + // concept requirements + __glibcxx_function_requires(_BidirectionalIteratorConcept< + _BidirectionalIterator>) + std::advance(__x, -__n); + return __x; + } + +#endif // C++11 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _STL_ITERATOR_BASE_FUNCS_H */ diff --git a/AH/STL/Fallback/bits/stl_iterator_base_types.h b/AH/STL/Fallback/bits/stl_iterator_base_types.h new file mode 100644 index 0000000..be6d377 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_iterator_base_types.h @@ -0,0 +1,241 @@ +// Types used in iterator implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996-1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_iterator_base_types.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{iterator} + * + * This file contains all of the general iterator-related utility types, + * such as iterator_traits and struct iterator. + */ + +#ifndef _STL_ITERATOR_BASE_TYPES_H +#define _STL_ITERATOR_BASE_TYPES_H 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" + +#if __cplusplus >= 201103L +# include "../type_traits" // For __void_t, is_convertible +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup iterators Iterators + * Abstractions for uniform iterating through various underlying types. + */ + //@{ + + /** + * @defgroup iterator_tags Iterator Tags + * These are empty types, used to distinguish different iterators. The + * distinction is not made by what they contain, but simply by what they + * are. Different underlying algorithms can then be used based on the + * different operations supported by different iterator types. + */ + //@{ + /// Marking input iterators. + struct input_iterator_tag { }; + + /// Marking output iterators. + struct output_iterator_tag { }; + + /// Forward iterators support a superset of input iterator operations. + struct forward_iterator_tag : public input_iterator_tag { }; + + /// Bidirectional iterators support a superset of forward iterator + /// operations. + struct bidirectional_iterator_tag : public forward_iterator_tag { }; + + /// Random-access iterators support a superset of bidirectional + /// iterator operations. + struct random_access_iterator_tag : public bidirectional_iterator_tag { }; + //@} + + /** + * @brief Common %iterator class. + * + * This class does nothing but define nested typedefs. %Iterator classes + * can inherit from this class to save some work. The typedefs are then + * used in specializations and overloading. + * + * In particular, there are no default implementations of requirements + * such as @c operator++ and the like. (How could there be?) + */ + template + struct iterator + { + /// One of the @link iterator_tags tag types@endlink. + typedef _Category iterator_category; + /// The type "pointed to" by the iterator. + typedef _Tp value_type; + /// Distance between iterators is represented as this type. + typedef _Distance difference_type; + /// This type represents a pointer-to-value_type. + typedef _Pointer pointer; + /// This type represents a reference-to-value_type. + typedef _Reference reference; + }; + + /** + * @brief Traits class for iterators. + * + * This class does nothing but define nested typedefs. The general + * version simply @a forwards the nested typedefs from the Iterator + * argument. Specialized versions for pointers and pointers-to-const + * provide tighter, more correct semantics. + */ +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2408. SFINAE-friendly common_type/iterator_traits is missing in C++14 + template> + struct __iterator_traits { }; + + template + struct __iterator_traits<_Iterator, + __void_t> + { + typedef typename _Iterator::iterator_category iterator_category; + typedef typename _Iterator::value_type value_type; + typedef typename _Iterator::difference_type difference_type; + typedef typename _Iterator::pointer pointer; + typedef typename _Iterator::reference reference; + }; + + template + struct iterator_traits + : public __iterator_traits<_Iterator> { }; +#else + template + struct iterator_traits + { + typedef typename _Iterator::iterator_category iterator_category; + typedef typename _Iterator::value_type value_type; + typedef typename _Iterator::difference_type difference_type; + typedef typename _Iterator::pointer pointer; + typedef typename _Iterator::reference reference; + }; +#endif + + /// Partial specialization for pointer types. + template + struct iterator_traits<_Tp*> + { + typedef random_access_iterator_tag iterator_category; + typedef _Tp value_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef _Tp& reference; + }; + + /// Partial specialization for const pointer types. + template + struct iterator_traits + { + typedef random_access_iterator_tag iterator_category; + typedef _Tp value_type; + typedef ptrdiff_t difference_type; + typedef const _Tp* pointer; + typedef const _Tp& reference; + }; + + /** + * This function is not a part of the C++ standard but is syntactic + * sugar for internal library use only. + */ + template + inline _GLIBCXX_CONSTEXPR + typename iterator_traits<_Iter>::iterator_category + __iterator_category(const _Iter&) + { return typename iterator_traits<_Iter>::iterator_category(); } + + //@} + +#if __cplusplus < 201103L + // If _Iterator has a base returns it otherwise _Iterator is returned + // untouched + template + struct _Iter_base + { + typedef _Iterator iterator_type; + static iterator_type _S_base(_Iterator __it) + { return __it; } + }; + + template + struct _Iter_base<_Iterator, true> + { + typedef typename _Iterator::iterator_type iterator_type; + static iterator_type _S_base(_Iterator __it) + { return __it.base(); } + }; +#endif + +#if __cplusplus >= 201103L + template + using _RequireInputIter = typename + enable_if::iterator_category, + input_iterator_tag>::value>::type; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _STL_ITERATOR_BASE_TYPES_H */ diff --git a/AH/STL/Fallback/bits/stl_numeric.h b/AH/STL/Fallback/bits/stl_numeric.h new file mode 100644 index 0000000..4d4faa8 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_numeric.h @@ -0,0 +1,387 @@ +// Numeric functions implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_numeric.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{numeric} + */ + +#ifndef _STL_NUMERIC_H +#define _STL_NUMERIC_H 1 + +#include "../bits/concept_check.h" +#include "../debug/debug.h" +#include "../bits/move.h" // For _GLIBCXX_MOVE + +#if __cplusplus >= 201103L + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief Create a range of sequentially increasing values. + * + * For each element in the range @p [first,last) assigns @p value and + * increments @p value as if by @p ++value. + * + * @param __first Start of range. + * @param __last End of range. + * @param __value Starting value. + * @return Nothing. + */ + template + void + iota(_ForwardIterator __first, _ForwardIterator __last, _Tp __value) + { + // concept requirements + __glibcxx_function_requires(_Mutable_ForwardIteratorConcept< + _ForwardIterator>) + __glibcxx_function_requires(_ConvertibleConcept<_Tp, + typename iterator_traits<_ForwardIterator>::value_type>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + { + *__first = __value; + ++__value; + } + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_ALGO + + /** + * @brief Accumulate values in a range. + * + * Accumulates the values in the range [first,last) using operator+(). The + * initial value is @a init. The values are processed in order. + * + * @param __first Start of range. + * @param __last End of range. + * @param __init Starting value to add other values to. + * @return The final sum. + */ + template + inline _Tp + accumulate(_InputIterator __first, _InputIterator __last, _Tp __init) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + __init = __init + *__first; + return __init; + } + + /** + * @brief Accumulate values in a range with operation. + * + * Accumulates the values in the range [first,last) using the function + * object @p __binary_op. The initial value is @p __init. The values are + * processed in order. + * + * @param __first Start of range. + * @param __last End of range. + * @param __init Starting value to add other values to. + * @param __binary_op Function object to accumulate with. + * @return The final sum. + */ + template + inline _Tp + accumulate(_InputIterator __first, _InputIterator __last, _Tp __init, + _BinaryOperation __binary_op) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_requires_valid_range(__first, __last); + + for (; __first != __last; ++__first) + __init = __binary_op(__init, *__first); + return __init; + } + + /** + * @brief Compute inner product of two ranges. + * + * Starting with an initial value of @p __init, multiplies successive + * elements from the two ranges and adds each product into the accumulated + * value using operator+(). The values in the ranges are processed in + * order. + * + * @param __first1 Start of range 1. + * @param __last1 End of range 1. + * @param __first2 Start of range 2. + * @param __init Starting value to add other values to. + * @return The final inner product. + */ + template + inline _Tp + inner_product(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _Tp __init) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_requires_valid_range(__first1, __last1); + + for (; __first1 != __last1; ++__first1, (void)++__first2) + __init = __init + (*__first1 * *__first2); + return __init; + } + + /** + * @brief Compute inner product of two ranges. + * + * Starting with an initial value of @p __init, applies @p __binary_op2 to + * successive elements from the two ranges and accumulates each result into + * the accumulated value using @p __binary_op1. The values in the ranges are + * processed in order. + * + * @param __first1 Start of range 1. + * @param __last1 End of range 1. + * @param __first2 Start of range 2. + * @param __init Starting value to add other values to. + * @param __binary_op1 Function object to accumulate with. + * @param __binary_op2 Function object to apply to pairs of input values. + * @return The final inner product. + */ + template + inline _Tp + inner_product(_InputIterator1 __first1, _InputIterator1 __last1, + _InputIterator2 __first2, _Tp __init, + _BinaryOperation1 __binary_op1, + _BinaryOperation2 __binary_op2) + { + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator1>) + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator2>) + __glibcxx_requires_valid_range(__first1, __last1); + + for (; __first1 != __last1; ++__first1, (void)++__first2) + __init = __binary_op1(__init, __binary_op2(*__first1, *__first2)); + return __init; + } + + /** + * @brief Return list of partial sums + * + * Accumulates the values in the range [first,last) using the @c + operator. + * As each successive input value is added into the total, that partial sum + * is written to @p __result. Therefore, the first value in @p __result is + * the first value of the input, the second value in @p __result is the sum + * of the first and second input values, and so on. + * + * @param __first Start of input range. + * @param __last End of input range. + * @param __result Output sum. + * @return Iterator pointing just beyond the values written to __result. + */ + template + _OutputIterator + partial_sum(_InputIterator __first, _InputIterator __last, + _OutputIterator __result) + { + typedef typename iterator_traits<_InputIterator>::value_type _ValueType; + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + _ValueType>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + _ValueType __value = *__first; + *__result = __value; + while (++__first != __last) + { + __value = __value + *__first; + *++__result = __value; + } + return ++__result; + } + + /** + * @brief Return list of partial sums + * + * Accumulates the values in the range [first,last) using @p __binary_op. + * As each successive input value is added into the total, that partial sum + * is written to @p __result. Therefore, the first value in @p __result is + * the first value of the input, the second value in @p __result is the sum + * of the first and second input values, and so on. + * + * @param __first Start of input range. + * @param __last End of input range. + * @param __result Output sum. + * @param __binary_op Function object. + * @return Iterator pointing just beyond the values written to __result. + */ + template + _OutputIterator + partial_sum(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOperation __binary_op) + { + typedef typename iterator_traits<_InputIterator>::value_type _ValueType; + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + _ValueType>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + _ValueType __value = *__first; + *__result = __value; + while (++__first != __last) + { + __value = __binary_op(__value, *__first); + *++__result = __value; + } + return ++__result; + } + + /** + * @brief Return differences between adjacent values. + * + * Computes the difference between adjacent values in the range + * [first,last) using operator-() and writes the result to @p __result. + * + * @param __first Start of input range. + * @param __last End of input range. + * @param __result Output sums. + * @return Iterator pointing just beyond the values written to result. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 539. partial_sum and adjacent_difference should mention requirements + */ + template + _OutputIterator + adjacent_difference(_InputIterator __first, + _InputIterator __last, _OutputIterator __result) + { + typedef typename iterator_traits<_InputIterator>::value_type _ValueType; + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + _ValueType>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + _ValueType __value = *__first; + *__result = __value; + while (++__first != __last) + { + _ValueType __tmp = *__first; + *++__result = __tmp - __value; + __value = _GLIBCXX_MOVE(__tmp); + } + return ++__result; + } + + /** + * @brief Return differences between adjacent values. + * + * Computes the difference between adjacent values in the range + * [__first,__last) using the function object @p __binary_op and writes the + * result to @p __result. + * + * @param __first Start of input range. + * @param __last End of input range. + * @param __result Output sum. + * @param __binary_op Function object. + * @return Iterator pointing just beyond the values written to result. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS + * DR 539. partial_sum and adjacent_difference should mention requirements + */ + template + _OutputIterator + adjacent_difference(_InputIterator __first, _InputIterator __last, + _OutputIterator __result, _BinaryOperation __binary_op) + { + typedef typename iterator_traits<_InputIterator>::value_type _ValueType; + + // concept requirements + __glibcxx_function_requires(_InputIteratorConcept<_InputIterator>) + __glibcxx_function_requires(_OutputIteratorConcept<_OutputIterator, + _ValueType>) + __glibcxx_requires_valid_range(__first, __last); + + if (__first == __last) + return __result; + _ValueType __value = *__first; + *__result = __value; + while (++__first != __last) + { + _ValueType __tmp = *__first; + *++__result = __binary_op(__tmp, __value); + __value = _GLIBCXX_MOVE(__tmp); + } + return ++__result; + } + +_GLIBCXX_END_NAMESPACE_ALGO +} // namespace std + +#endif /* _STL_NUMERIC_H */ diff --git a/AH/STL/Fallback/bits/stl_pair.h b/AH/STL/Fallback/bits/stl_pair.h new file mode 100644 index 0000000..5e6e3a0 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_pair.h @@ -0,0 +1,543 @@ +// Pair implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_pair.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{utility} + */ + +#ifndef _STL_PAIR_H +#define _STL_PAIR_H 1 + +#include "../bits/move.h" // for std::move / std::forward, and std::swap + +#if __cplusplus >= 201103L +#include "../type_traits" // for std::__decay_and_strip too +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + +#if __cplusplus >= 201103L + /// piecewise_construct_t + struct piecewise_construct_t { explicit piecewise_construct_t() = default; }; + + /// piecewise_construct + _GLIBCXX17_INLINE constexpr piecewise_construct_t piecewise_construct = + piecewise_construct_t(); + + // Forward declarations. + template + class tuple; + + template + struct _Index_tuple; + + // Concept utility functions, reused in conditionally-explicit + // constructors. + // See PR 70437, don't look at is_constructible or + // is_convertible if the types are the same to + // avoid querying those properties for incomplete types. + template + struct _PCC + { + template + static constexpr bool _ConstructiblePair() + { + return __and_, + is_constructible<_T2, const _U2&>>::value; + } + + template + static constexpr bool _ImplicitlyConvertiblePair() + { + return __and_, + is_convertible>::value; + } + + template + static constexpr bool _MoveConstructiblePair() + { + return __and_, + is_constructible<_T2, _U2&&>>::value; + } + + template + static constexpr bool _ImplicitlyMoveConvertiblePair() + { + return __and_, + is_convertible<_U2&&, _T2>>::value; + } + + template + static constexpr bool _CopyMovePair() + { + using __do_converts = __and_, + is_convertible<_U2&&, _T2>>; + using __converts = typename conditional<__implicit, + __do_converts, + __not_<__do_converts>>::type; + return __and_, + is_constructible<_T2, _U2&&>, + __converts + >::value; + } + + template + static constexpr bool _MoveCopyPair() + { + using __do_converts = __and_, + is_convertible>; + using __converts = typename conditional<__implicit, + __do_converts, + __not_<__do_converts>>::type; + return __and_, + is_constructible<_T2, const _U2&&>, + __converts + >::value; + } + }; + + template + struct _PCC + { + template + static constexpr bool _ConstructiblePair() + { + return false; + } + + template + static constexpr bool _ImplicitlyConvertiblePair() + { + return false; + } + + template + static constexpr bool _MoveConstructiblePair() + { + return false; + } + + template + static constexpr bool _ImplicitlyMoveConvertiblePair() + { + return false; + } + }; + + // PR libstdc++/79141, a utility type for preventing + // initialization of an argument of a disabled assignment + // operator from a pair of empty braces. + struct __nonesuch_no_braces : std::__nonesuch { + explicit __nonesuch_no_braces(const __nonesuch&) = delete; + }; +#endif // C++11 + + template class __pair_base + { +#if __cplusplus >= 201103L + template friend struct pair; + __pair_base() = default; + ~__pair_base() = default; + __pair_base(const __pair_base&) = default; + __pair_base& operator=(const __pair_base&) = delete; +#endif // C++11 + }; + + /** + * @brief Struct holding two objects of arbitrary type. + * + * @tparam _T1 Type of first object. + * @tparam _T2 Type of second object. + */ + template + struct pair + : private __pair_base<_T1, _T2> + { + typedef _T1 first_type; /// @c first_type is the first bound type + typedef _T2 second_type; /// @c second_type is the second bound type + + _T1 first; /// @c first is a copy of the first object + _T2 second; /// @c second is a copy of the second object + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 265. std::pair::pair() effects overly restrictive + /** The default constructor creates @c first and @c second using their + * respective default constructors. */ +#if __cplusplus >= 201103L + template , + __is_implicitly_default_constructible<_U2>> + ::value, bool>::type = true> +#endif + _GLIBCXX_CONSTEXPR pair() + : first(), second() { } + +#if __cplusplus >= 201103L + template , + is_default_constructible<_U2>, + __not_< + __and_<__is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>>>> + ::value, bool>::type = false> + explicit constexpr pair() + : first(), second() { } +#endif + + /** Two objects may be passed to a @c pair constructor to be copied. */ +#if __cplusplus < 201103L + pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } +#else + // Shortcut for constraining the templates that don't take pairs. + using _PCCP = _PCC; + + template() + && _PCCP::template + _ImplicitlyConvertiblePair<_U1, _U2>(), + bool>::type=true> + constexpr pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } + + template() + && !_PCCP::template + _ImplicitlyConvertiblePair<_U1, _U2>(), + bool>::type=false> + explicit constexpr pair(const _T1& __a, const _T2& __b) + : first(__a), second(__b) { } +#endif + + /** There is also a templated copy ctor for the @c pair class itself. */ +#if __cplusplus < 201103L + template + pair(const pair<_U1, _U2>& __p) + : first(__p.first), second(__p.second) { } +#else + // Shortcut for constraining the templates that take pairs. + template + using _PCCFP = _PCC::value + || !is_same<_T2, _U2>::value, + _T1, _T2>; + + template::template + _ConstructiblePair<_U1, _U2>() + && _PCCFP<_U1, _U2>::template + _ImplicitlyConvertiblePair<_U1, _U2>(), + bool>::type=true> + constexpr pair(const pair<_U1, _U2>& __p) + : first(__p.first), second(__p.second) { } + + template::template + _ConstructiblePair<_U1, _U2>() + && !_PCCFP<_U1, _U2>::template + _ImplicitlyConvertiblePair<_U1, _U2>(), + bool>::type=false> + explicit constexpr pair(const pair<_U1, _U2>& __p) + : first(__p.first), second(__p.second) { } + + constexpr pair(const pair&) = default; + constexpr pair(pair&&) = default; + + // DR 811. + template(), + bool>::type=true> + constexpr pair(_U1&& __x, const _T2& __y) + : first(std::forward<_U1>(__x)), second(__y) { } + + template(), + bool>::type=false> + explicit constexpr pair(_U1&& __x, const _T2& __y) + : first(std::forward<_U1>(__x)), second(__y) { } + + template(), + bool>::type=true> + constexpr pair(const _T1& __x, _U2&& __y) + : first(__x), second(std::forward<_U2>(__y)) { } + + template(), + bool>::type=false> + explicit pair(const _T1& __x, _U2&& __y) + : first(__x), second(std::forward<_U2>(__y)) { } + + template() + && _PCCP::template + _ImplicitlyMoveConvertiblePair<_U1, _U2>(), + bool>::type=true> + constexpr pair(_U1&& __x, _U2&& __y) + : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } + + template() + && !_PCCP::template + _ImplicitlyMoveConvertiblePair<_U1, _U2>(), + bool>::type=false> + explicit constexpr pair(_U1&& __x, _U2&& __y) + : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } + + + template::template + _MoveConstructiblePair<_U1, _U2>() + && _PCCFP<_U1, _U2>::template + _ImplicitlyMoveConvertiblePair<_U1, _U2>(), + bool>::type=true> + constexpr pair(pair<_U1, _U2>&& __p) + : first(std::forward<_U1>(__p.first)), + second(std::forward<_U2>(__p.second)) { } + + template::template + _MoveConstructiblePair<_U1, _U2>() + && !_PCCFP<_U1, _U2>::template + _ImplicitlyMoveConvertiblePair<_U1, _U2>(), + bool>::type=false> + explicit constexpr pair(pair<_U1, _U2>&& __p) + : first(std::forward<_U1>(__p.first)), + second(std::forward<_U2>(__p.second)) { } + + template + pair(piecewise_construct_t, tuple<_Args1...>, tuple<_Args2...>); + + pair& + operator=(typename conditional< + __and_, + is_copy_assignable<_T2>>::value, + const pair&, const __nonesuch_no_braces&>::type __p) + { + first = __p.first; + second = __p.second; + return *this; + } + + pair& + operator=(typename conditional< + __and_, + is_move_assignable<_T2>>::value, + pair&&, __nonesuch_no_braces&&>::type __p) + noexcept(__and_, + is_nothrow_move_assignable<_T2>>::value) + { + first = std::forward(__p.first); + second = std::forward(__p.second); + return *this; + } + + template + typename enable_if<__and_, + is_assignable<_T2&, const _U2&>>::value, + pair&>::type + operator=(const pair<_U1, _U2>& __p) + { + first = __p.first; + second = __p.second; + return *this; + } + + template + typename enable_if<__and_, + is_assignable<_T2&, _U2&&>>::value, + pair&>::type + operator=(pair<_U1, _U2>&& __p) + { + first = std::forward<_U1>(__p.first); + second = std::forward<_U2>(__p.second); + return *this; + } + + void + swap(pair& __p) + noexcept(__and_<__is_nothrow_swappable<_T1>, + __is_nothrow_swappable<_T2>>::value) + { + using std::swap; + swap(first, __p.first); + swap(second, __p.second); + } + + private: + template + pair(tuple<_Args1...>&, tuple<_Args2...>&, + _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>); +#endif + }; + +#if __cpp_deduction_guides >= 201606 + template pair(_T1, _T2) -> pair<_T1, _T2>; +#endif + + /// Two pairs of the same type are equal iff their members are equal. + template + inline _GLIBCXX_CONSTEXPR bool + operator==(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return __x.first == __y.first && __x.second == __y.second; } + + /// + template + inline _GLIBCXX_CONSTEXPR bool + operator<(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return __x.first < __y.first + || (!(__y.first < __x.first) && __x.second < __y.second); } + + /// Uses @c operator== to find the result. + template + inline _GLIBCXX_CONSTEXPR bool + operator!=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return !(__x == __y); } + + /// Uses @c operator< to find the result. + template + inline _GLIBCXX_CONSTEXPR bool + operator>(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return __y < __x; } + + /// Uses @c operator< to find the result. + template + inline _GLIBCXX_CONSTEXPR bool + operator<=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return !(__y < __x); } + + /// Uses @c operator< to find the result. + template + inline _GLIBCXX_CONSTEXPR bool + operator>=(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + { return !(__x < __y); } + +#if __cplusplus >= 201103L + /// See std::pair::swap(). + // Note: no std::swap overloads in C++03 mode, this has performance + // implications, see, eg, libstdc++/38466. + template + inline +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // Constrained free swap overload, see p0185r1 + typename enable_if<__and_<__is_swappable<_T1>, + __is_swappable<_T2>>::value>::type +#else + void +#endif + swap(pair<_T1, _T2>& __x, pair<_T1, _T2>& __y) + noexcept(noexcept(__x.swap(__y))) + { __x.swap(__y); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + template + typename enable_if, + __is_swappable<_T2>>::value>::type + swap(pair<_T1, _T2>&, pair<_T1, _T2>&) = delete; +#endif +#endif // __cplusplus >= 201103L + + /** + * @brief A convenience wrapper for creating a pair from two objects. + * @param __x The first object. + * @param __y The second object. + * @return A newly-constructed pair<> object of the appropriate type. + * + * The standard requires that the objects be passed by reference-to-const, + * but LWG issue #181 says they should be passed by const value. We follow + * the LWG by default. + */ + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 181. make_pair() unintended behavior +#if __cplusplus >= 201103L + // NB: DR 706. + template + constexpr pair::__type, + typename __decay_and_strip<_T2>::__type> + make_pair(_T1&& __x, _T2&& __y) + { + typedef typename __decay_and_strip<_T1>::__type __ds_type1; + typedef typename __decay_and_strip<_T2>::__type __ds_type2; + typedef pair<__ds_type1, __ds_type2> __pair_type; + return __pair_type(std::forward<_T1>(__x), std::forward<_T2>(__y)); + } +#else + template + inline pair<_T1, _T2> + make_pair(_T1 __x, _T2 __y) + { return pair<_T1, _T2>(__x, __y); } +#endif + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif /* _STL_PAIR_H */ diff --git a/AH/STL/Fallback/bits/stl_relops.h b/AH/STL/Fallback/bits/stl_relops.h new file mode 100644 index 0000000..a2614bd --- /dev/null +++ b/AH/STL/Fallback/bits/stl_relops.h @@ -0,0 +1,134 @@ +// std::rel_ops implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the, 2009 Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * Copyright (c) 1996,1997 + * Silicon Graphics + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +/** @file bits/stl_relops.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{utility} + * + * Inclusion of this file has been removed from + * all of the other STL headers for safety reasons, except std_utility.h. + * For more information, see the thread of about twenty messages starting + * with http://gcc.gnu.org/ml/libstdc++/2001-01/msg00223.html, or + * http://gcc.gnu.org/onlinedocs/libstdc++/faq.html#faq.ambiguous_overloads + * + * Short summary: the rel_ops operators should be avoided for the present. + */ + +#ifndef _STL_RELOPS_H +#define _STL_RELOPS_H 1 + +namespace std _GLIBCXX_VISIBILITY(default) +{ + namespace rel_ops + { + _GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** @namespace std::rel_ops + * @brief The generated relational operators are sequestered here. + */ + + /** + * @brief Defines @c != for arbitrary types, in terms of @c ==. + * @param __x A thing. + * @param __y Another thing. + * @return __x != __y + * + * This function uses @c == to determine its result. + */ + template + inline bool + operator!=(const _Tp& __x, const _Tp& __y) + { return !(__x == __y); } + + /** + * @brief Defines @c > for arbitrary types, in terms of @c <. + * @param __x A thing. + * @param __y Another thing. + * @return __x > __y + * + * This function uses @c < to determine its result. + */ + template + inline bool + operator>(const _Tp& __x, const _Tp& __y) + { return __y < __x; } + + /** + * @brief Defines @c <= for arbitrary types, in terms of @c <. + * @param __x A thing. + * @param __y Another thing. + * @return __x <= __y + * + * This function uses @c < to determine its result. + */ + template + inline bool + operator<=(const _Tp& __x, const _Tp& __y) + { return !(__y < __x); } + + /** + * @brief Defines @c >= for arbitrary types, in terms of @c <. + * @param __x A thing. + * @param __y Another thing. + * @return __x >= __y + * + * This function uses @c < to determine its result. + */ + template + inline bool + operator>=(const _Tp& __x, const _Tp& __y) + { return !(__x < __y); } + + _GLIBCXX_END_NAMESPACE_VERSION + } // namespace rel_ops + +} // namespace std + +#endif /* _STL_RELOPS_H */ diff --git a/AH/STL/Fallback/bits/stl_tempbuf.h b/AH/STL/Fallback/bits/stl_tempbuf.h new file mode 100644 index 0000000..589757a --- /dev/null +++ b/AH/STL/Fallback/bits/stl_tempbuf.h @@ -0,0 +1,278 @@ +// Temporary buffer implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_tempbuf.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _STL_TEMPBUF_H +#define _STL_TEMPBUF_H 1 + +#include "../bits/stl_algobase.h" +#include "../bits/stl_construct.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief Allocates a temporary buffer. + * @param __len The number of objects of type Tp. + * @return See full description. + * + * Reinventing the wheel, but this time with prettier spokes! + * + * This function tries to obtain storage for @c __len adjacent Tp + * objects. The objects themselves are not constructed, of course. + * A pair<> is returned containing the buffer s address and + * capacity (in the units of sizeof(_Tp)), or a pair of 0 values if + * no storage can be obtained. Note that the capacity obtained + * may be less than that requested if the memory is unavailable; + * you should compare len with the .second return value. + * + * Provides the nothrow exception guarantee. + */ + template + pair<_Tp*, ptrdiff_t> + get_temporary_buffer(ptrdiff_t __len) _GLIBCXX_NOEXCEPT + { + const ptrdiff_t __max = + __gnu_cxx::__numeric_traits::__max / sizeof(_Tp); + if (__len > __max) + __len = __max; + + while (__len > 0) + { + _Tp* __tmp = static_cast<_Tp*>(::operator new(__len * sizeof(_Tp), + std::nothrow)); + if (__tmp != 0) + return std::pair<_Tp*, ptrdiff_t>(__tmp, __len); + __len /= 2; + } + return std::pair<_Tp*, ptrdiff_t>(static_cast<_Tp*>(0), 0); + } + + /** + * @brief The companion to get_temporary_buffer(). + * @param __p A buffer previously allocated by get_temporary_buffer. + * @return None. + * + * Frees the memory pointed to by __p. + */ + template + inline void + return_temporary_buffer(_Tp* __p) + { ::operator delete(__p, std::nothrow); } + + + /** + * This class is used in two places: stl_algo.h and ext/memory, + * where it is wrapped as the temporary_buffer class. See + * temporary_buffer docs for more notes. + */ + template + class _Temporary_buffer + { + // concept requirements + __glibcxx_class_requires(_ForwardIterator, _ForwardIteratorConcept) + + public: + typedef _Tp value_type; + typedef value_type* pointer; + typedef pointer iterator; + typedef ptrdiff_t size_type; + + protected: + size_type _M_original_len; + size_type _M_len; + pointer _M_buffer; + + public: + /// As per Table mumble. + size_type + size() const + { return _M_len; } + + /// Returns the size requested by the constructor; may be >size(). + size_type + requested_size() const + { return _M_original_len; } + + /// As per Table mumble. + iterator + begin() + { return _M_buffer; } + + /// As per Table mumble. + iterator + end() + { return _M_buffer + _M_len; } + + /** + * Constructs a temporary buffer of a size somewhere between + * zero and the size of the given range. + */ + _Temporary_buffer(_ForwardIterator __first, _ForwardIterator __last); + + ~_Temporary_buffer() + { + std::_Destroy(_M_buffer, _M_buffer + _M_len); + std::return_temporary_buffer(_M_buffer); + } + + private: + // Disable copy constructor and assignment operator. + _Temporary_buffer(const _Temporary_buffer&); + + void + operator=(const _Temporary_buffer&); + }; + + + template + struct __uninitialized_construct_buf_dispatch + { + template + static void + __ucr(_Pointer __first, _Pointer __last, + _ForwardIterator __seed) + { + if(__first == __last) + return; + + _Pointer __cur = __first; + #ifdef AH_USE_EXCEPTIONS + __try + #endif + { + std::_Construct(std::__addressof(*__first), + _GLIBCXX_MOVE(*__seed)); + _Pointer __prev = __cur; + ++__cur; + for(; __cur != __last; ++__cur, ++__prev) + std::_Construct(std::__addressof(*__cur), + _GLIBCXX_MOVE(*__prev)); + *__seed = _GLIBCXX_MOVE(*__prev); + } + #ifdef AH_USE_EXCEPTIONS + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + #endif + } + }; + + template<> + struct __uninitialized_construct_buf_dispatch + { + template + static void + __ucr(_Pointer, _Pointer, _ForwardIterator) { } + }; + + // Constructs objects in the range [first, last). + // Note that while these new objects will take valid values, + // their exact value is not defined. In particular they may + // be 'moved from'. + // + // While *__seed may be altered during this algorithm, it will have + // the same value when the algorithm finishes, unless one of the + // constructions throws. + // + // Requirements: _Pointer::value_type(_Tp&&) is valid. + template + inline void + __uninitialized_construct_buf(_Pointer __first, _Pointer __last, + _ForwardIterator __seed) + { + typedef typename std::iterator_traits<_Pointer>::value_type + _ValueType; + + std::__uninitialized_construct_buf_dispatch< + __has_trivial_constructor(_ValueType)>:: + __ucr(__first, __last, __seed); + } + + template + _Temporary_buffer<_ForwardIterator, _Tp>:: + _Temporary_buffer(_ForwardIterator __first, _ForwardIterator __last) + : _M_original_len(std::distance(__first, __last)), + _M_len(0), _M_buffer(0) + { + #ifdef AH_USE_EXCEPTIONS + __try + #endif + { + std::pair __p(std::get_temporary_buffer< + value_type>(_M_original_len)); + _M_buffer = __p.first; + _M_len = __p.second; + if (_M_buffer) + std::__uninitialized_construct_buf(_M_buffer, _M_buffer + _M_len, + __first); + } + #ifdef AH_USE_EXCEPTIONS + __catch(...) + { + std::return_temporary_buffer(_M_buffer); + _M_buffer = 0; + _M_len = 0; + __throw_exception_again; + } + #endif + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _STL_TEMPBUF_H */ diff --git a/AH/STL/Fallback/bits/stl_uninitialized.h b/AH/STL/Fallback/bits/stl_uninitialized.h new file mode 100644 index 0000000..83e4812 --- /dev/null +++ b/AH/STL/Fallback/bits/stl_uninitialized.h @@ -0,0 +1,885 @@ +// Raw memory manipulators -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_uninitialized.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _STL_UNINITIALIZED_H +#define _STL_UNINITIALIZED_H 1 + +#if __cplusplus > 201402L +#include "../utility" +#endif + +#if __cplusplus >= 201103L +#include "../type_traits" +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template + struct __uninitialized_copy + { + template + static _ForwardIterator + __uninit_copy(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result) + { + _ForwardIterator __cur = __result; + __try + { + for (; __first != __last; ++__first, (void)++__cur) + std::_Construct(std::__addressof(*__cur), *__first); + return __cur; + } + __catch(...) + { + std::_Destroy(__result, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_copy + { + template + static _ForwardIterator + __uninit_copy(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result) + { return std::copy(__first, __last, __result); } + }; + + /** + * @brief Copies the range [first,last) into result. + * @param __first An input iterator. + * @param __last An input iterator. + * @param __result An output iterator. + * @return __result + (__first - __last) + * + * Like copy(), but does not require an initialized output range. + */ + template + inline _ForwardIterator + uninitialized_copy(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result) + { + typedef typename iterator_traits<_InputIterator>::value_type + _ValueType1; + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType2; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + typedef typename iterator_traits<_InputIterator>::reference _RefType1; + typedef typename iterator_traits<_ForwardIterator>::reference _RefType2; + const bool __assignable = is_assignable<_RefType2, _RefType1>::value; +#endif + + return std::__uninitialized_copy<__is_trivial(_ValueType1) + && __is_trivial(_ValueType2) + && __assignable>:: + __uninit_copy(__first, __last, __result); + } + + + template + struct __uninitialized_fill + { + template + static void + __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x) + { + _ForwardIterator __cur = __first; + __try + { + for (; __cur != __last; ++__cur) + std::_Construct(std::__addressof(*__cur), __x); + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_fill + { + template + static void + __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x) + { std::fill(__first, __last, __x); } + }; + + /** + * @brief Copies the value x into the range [first,last). + * @param __first An input iterator. + * @param __last An input iterator. + * @param __x The source value. + * @return Nothing. + * + * Like fill(), but does not require an initialized output range. + */ + template + inline void + uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; +#endif + + std::__uninitialized_fill<__is_trivial(_ValueType) && __assignable>:: + __uninit_fill(__first, __last, __x); + } + + + template + struct __uninitialized_fill_n + { + template + static _ForwardIterator + __uninit_fill_n(_ForwardIterator __first, _Size __n, + const _Tp& __x) + { + _ForwardIterator __cur = __first; + __try + { + for (; __n > 0; --__n, ++__cur) + std::_Construct(std::__addressof(*__cur), __x); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_fill_n + { + template + static _ForwardIterator + __uninit_fill_n(_ForwardIterator __first, _Size __n, + const _Tp& __x) + { return std::fill_n(__first, __n, __x); } + }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 1339. uninitialized_fill_n should return the end of its range + /** + * @brief Copies the value x into the range [first,first+n). + * @param __first An input iterator. + * @param __n The number of copies to make. + * @param __x The source value. + * @return Nothing. + * + * Like fill_n(), but does not require an initialized output range. + */ + template + inline _ForwardIterator + uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; +#if __cplusplus < 201103L + const bool __assignable = true; +#else + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; +#endif + return __uninitialized_fill_n<__is_trivial(_ValueType) && __assignable>:: + __uninit_fill_n(__first, __n, __x); + } + + // Extensions: versions of uninitialized_copy, uninitialized_fill, + // and uninitialized_fill_n that take an allocator parameter. + // We dispatch back to the standard versions when we're given the + // default allocator. For nondefault allocators we do not use + // any of the POD optimizations. + + template + _ForwardIterator + __uninitialized_copy_a(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, _Allocator& __alloc) + { + _ForwardIterator __cur = __result; + __try + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __first != __last; ++__first, (void)++__cur) + __traits::construct(__alloc, std::__addressof(*__cur), *__first); + return __cur; + } + __catch(...) + { + std::_Destroy(__result, __cur, __alloc); + __throw_exception_again; + } + } + + template + inline _ForwardIterator + __uninitialized_copy_a(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, allocator<_Tp>&) + { return std::uninitialized_copy(__first, __last, __result); } + + template + inline _ForwardIterator + __uninitialized_move_a(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result, _Allocator& __alloc) + { + return std::__uninitialized_copy_a(_GLIBCXX_MAKE_MOVE_ITERATOR(__first), + _GLIBCXX_MAKE_MOVE_ITERATOR(__last), + __result, __alloc); + } + + template + inline _ForwardIterator + __uninitialized_move_if_noexcept_a(_InputIterator __first, + _InputIterator __last, + _ForwardIterator __result, + _Allocator& __alloc) + { + return std::__uninitialized_copy_a + (_GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__first), + _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(__last), __result, __alloc); + } + + template + void + __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x, _Allocator& __alloc) + { + _ForwardIterator __cur = __first; + __try + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __cur != __last; ++__cur) + __traits::construct(__alloc, std::__addressof(*__cur), __x); + } + __catch(...) + { + std::_Destroy(__first, __cur, __alloc); + __throw_exception_again; + } + } + + template + inline void + __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x, allocator<_Tp2>&) + { std::uninitialized_fill(__first, __last, __x); } + + template + _ForwardIterator + __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, + const _Tp& __x, _Allocator& __alloc) + { + _ForwardIterator __cur = __first; + __try + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __n > 0; --__n, ++__cur) + __traits::construct(__alloc, std::__addressof(*__cur), __x); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur, __alloc); + __throw_exception_again; + } + } + + template + inline _ForwardIterator + __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, + const _Tp& __x, allocator<_Tp2>&) + { return std::uninitialized_fill_n(__first, __n, __x); } + + + // Extensions: __uninitialized_copy_move, __uninitialized_move_copy, + // __uninitialized_fill_move, __uninitialized_move_fill. + // All of these algorithms take a user-supplied allocator, which is used + // for construction and destruction. + + // __uninitialized_copy_move + // Copies [first1, last1) into [result, result + (last1 - first1)), and + // move [first2, last2) into + // [result, result + (last1 - first1) + (last2 - first2)). + template + inline _ForwardIterator + __uninitialized_copy_move(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _ForwardIterator __result, + _Allocator& __alloc) + { + _ForwardIterator __mid = std::__uninitialized_copy_a(__first1, __last1, + __result, + __alloc); + __try + { + return std::__uninitialized_move_a(__first2, __last2, __mid, __alloc); + } + __catch(...) + { + std::_Destroy(__result, __mid, __alloc); + __throw_exception_again; + } + } + + // __uninitialized_move_copy + // Moves [first1, last1) into [result, result + (last1 - first1)), and + // copies [first2, last2) into + // [result, result + (last1 - first1) + (last2 - first2)). + template + inline _ForwardIterator + __uninitialized_move_copy(_InputIterator1 __first1, + _InputIterator1 __last1, + _InputIterator2 __first2, + _InputIterator2 __last2, + _ForwardIterator __result, + _Allocator& __alloc) + { + _ForwardIterator __mid = std::__uninitialized_move_a(__first1, __last1, + __result, + __alloc); + __try + { + return std::__uninitialized_copy_a(__first2, __last2, __mid, __alloc); + } + __catch(...) + { + std::_Destroy(__result, __mid, __alloc); + __throw_exception_again; + } + } + + // __uninitialized_fill_move + // Fills [result, mid) with x, and moves [first, last) into + // [mid, mid + (last - first)). + template + inline _ForwardIterator + __uninitialized_fill_move(_ForwardIterator __result, _ForwardIterator __mid, + const _Tp& __x, _InputIterator __first, + _InputIterator __last, _Allocator& __alloc) + { + std::__uninitialized_fill_a(__result, __mid, __x, __alloc); + __try + { + return std::__uninitialized_move_a(__first, __last, __mid, __alloc); + } + __catch(...) + { + std::_Destroy(__result, __mid, __alloc); + __throw_exception_again; + } + } + + // __uninitialized_move_fill + // Moves [first1, last1) into [first2, first2 + (last1 - first1)), and + // fills [first2 + (last1 - first1), last2) with x. + template + inline void + __uninitialized_move_fill(_InputIterator __first1, _InputIterator __last1, + _ForwardIterator __first2, + _ForwardIterator __last2, const _Tp& __x, + _Allocator& __alloc) + { + _ForwardIterator __mid2 = std::__uninitialized_move_a(__first1, __last1, + __first2, + __alloc); + __try + { + std::__uninitialized_fill_a(__mid2, __last2, __x, __alloc); + } + __catch(...) + { + std::_Destroy(__first2, __mid2, __alloc); + __throw_exception_again; + } + } + +#if __cplusplus >= 201103L + // Extensions: __uninitialized_default, __uninitialized_default_n, + // __uninitialized_default_a, __uninitialized_default_n_a. + + template + struct __uninitialized_default_1 + { + template + static void + __uninit_default(_ForwardIterator __first, _ForwardIterator __last) + { + _ForwardIterator __cur = __first; + __try + { + for (; __cur != __last; ++__cur) + std::_Construct(std::__addressof(*__cur)); + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_1 + { + template + static void + __uninit_default(_ForwardIterator __first, _ForwardIterator __last) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + std::fill(__first, __last, _ValueType()); + } + }; + + template + struct __uninitialized_default_n_1 + { + template + static _ForwardIterator + __uninit_default_n(_ForwardIterator __first, _Size __n) + { + _ForwardIterator __cur = __first; + __try + { + for (; __n > 0; --__n, ++__cur) + std::_Construct(std::__addressof(*__cur)); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_n_1 + { + template + static _ForwardIterator + __uninit_default_n(_ForwardIterator __first, _Size __n) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + return std::fill_n(__first, __n, _ValueType()); + } + }; + + // __uninitialized_default + // Fills [first, last) with std::distance(first, last) default + // constructed value_types(s). + template + inline void + __uninitialized_default(_ForwardIterator __first, + _ForwardIterator __last) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; + + std::__uninitialized_default_1<__is_trivial(_ValueType) + && __assignable>:: + __uninit_default(__first, __last); + } + + // __uninitialized_default_n + // Fills [first, first + n) with n default constructed value_type(s). + template + inline _ForwardIterator + __uninitialized_default_n(_ForwardIterator __first, _Size __n) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + // trivial types can have deleted assignment + const bool __assignable = is_copy_assignable<_ValueType>::value; + + return __uninitialized_default_n_1<__is_trivial(_ValueType) + && __assignable>:: + __uninit_default_n(__first, __n); + } + + + // __uninitialized_default_a + // Fills [first, last) with std::distance(first, last) default + // constructed value_types(s), constructed with the allocator alloc. + template + void + __uninitialized_default_a(_ForwardIterator __first, + _ForwardIterator __last, + _Allocator& __alloc) + { + _ForwardIterator __cur = __first; + __try + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __cur != __last; ++__cur) + __traits::construct(__alloc, std::__addressof(*__cur)); + } + __catch(...) + { + std::_Destroy(__first, __cur, __alloc); + __throw_exception_again; + } + } + + template + inline void + __uninitialized_default_a(_ForwardIterator __first, + _ForwardIterator __last, + allocator<_Tp>&) + { std::__uninitialized_default(__first, __last); } + + + // __uninitialized_default_n_a + // Fills [first, first + n) with n default constructed value_types(s), + // constructed with the allocator alloc. + template + _ForwardIterator + __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, + _Allocator& __alloc) + { + _ForwardIterator __cur = __first; + __try + { + typedef __gnu_cxx::__alloc_traits<_Allocator> __traits; + for (; __n > 0; --__n, ++__cur) + __traits::construct(__alloc, std::__addressof(*__cur)); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur, __alloc); + __throw_exception_again; + } + } + + template + inline _ForwardIterator + __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, + allocator<_Tp>&) + { return std::__uninitialized_default_n(__first, __n); } + + template + struct __uninitialized_default_novalue_1 + { + template + static void + __uninit_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + _ForwardIterator __cur = __first; + __try + { + for (; __cur != __last; ++__cur) + std::_Construct_novalue(std::__addressof(*__cur)); + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_novalue_1 + { + template + static void + __uninit_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + } + }; + + template + struct __uninitialized_default_novalue_n_1 + { + template + static _ForwardIterator + __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) + { + _ForwardIterator __cur = __first; + __try + { + for (; __n > 0; --__n, ++__cur) + std::_Construct_novalue(std::__addressof(*__cur)); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + }; + + template<> + struct __uninitialized_default_novalue_n_1 + { + template + static _ForwardIterator + __uninit_default_novalue_n(_ForwardIterator __first, _Size __n) + { return std::next(__first, __n); } + }; + + // __uninitialized_default_novalue + // Fills [first, last) with std::distance(first, last) default-initialized + // value_types(s). + template + inline void + __uninitialized_default_novalue(_ForwardIterator __first, + _ForwardIterator __last) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + std::__uninitialized_default_novalue_1< + is_trivially_default_constructible<_ValueType>::value>:: + __uninit_default_novalue(__first, __last); + } + + // __uninitialized_default_n + // Fills [first, first + n) with n default-initialized value_type(s). + template + inline _ForwardIterator + __uninitialized_default_novalue_n(_ForwardIterator __first, _Size __n) + { + typedef typename iterator_traits<_ForwardIterator>::value_type + _ValueType; + + return __uninitialized_default_novalue_n_1< + is_trivially_default_constructible<_ValueType>::value>:: + __uninit_default_novalue_n(__first, __n); + } + + template + _ForwardIterator + __uninitialized_copy_n(_InputIterator __first, _Size __n, + _ForwardIterator __result, input_iterator_tag) + { + _ForwardIterator __cur = __result; + __try + { + for (; __n > 0; --__n, ++__first, ++__cur) + std::_Construct(std::__addressof(*__cur), *__first); + return __cur; + } + __catch(...) + { + std::_Destroy(__result, __cur); + __throw_exception_again; + } + } + + template + inline _ForwardIterator + __uninitialized_copy_n(_RandomAccessIterator __first, _Size __n, + _ForwardIterator __result, + random_access_iterator_tag) + { return std::uninitialized_copy(__first, __first + __n, __result); } + + template + pair<_InputIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, + _ForwardIterator __result, input_iterator_tag) + { + _ForwardIterator __cur = __result; + __try + { + for (; __n > 0; --__n, ++__first, ++__cur) + std::_Construct(std::__addressof(*__cur), *__first); + return {__first, __cur}; + } + __catch(...) + { + std::_Destroy(__result, __cur); + __throw_exception_again; + } + } + + template + inline pair<_RandomAccessIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_RandomAccessIterator __first, _Size __n, + _ForwardIterator __result, + random_access_iterator_tag) + { + auto __second_res = uninitialized_copy(__first, __first + __n, __result); + auto __first_res = std::next(__first, __n); + return {__first_res, __second_res}; + } + + /** + * @brief Copies the range [first,first+n) into result. + * @param __first An input iterator. + * @param __n The number of elements to copy. + * @param __result An output iterator. + * @return __result + __n + * + * Like copy_n(), but does not require an initialized output range. + */ + template + inline _ForwardIterator + uninitialized_copy_n(_InputIterator __first, _Size __n, + _ForwardIterator __result) + { return std::__uninitialized_copy_n(__first, __n, __result, + std::__iterator_category(__first)); } + + template + inline pair<_InputIterator, _ForwardIterator> + __uninitialized_copy_n_pair(_InputIterator __first, _Size __n, + _ForwardIterator __result) + { + return + std::__uninitialized_copy_n_pair(__first, __n, __result, + std::__iterator_category(__first)); + } + +#endif + +#if __cplusplus > 201402L + template + inline void + uninitialized_default_construct(_ForwardIterator __first, + _ForwardIterator __last) + { + __uninitialized_default_novalue(__first, __last); + } + + template + inline _ForwardIterator + uninitialized_default_construct_n(_ForwardIterator __first, _Size __count) + { + return __uninitialized_default_novalue_n(__first, __count); + } + + template + inline void + uninitialized_value_construct(_ForwardIterator __first, + _ForwardIterator __last) + { + return __uninitialized_default(__first, __last); + } + + template + inline _ForwardIterator + uninitialized_value_construct_n(_ForwardIterator __first, _Size __count) + { + return __uninitialized_default_n(__first, __count); + } + + template + inline _ForwardIterator + uninitialized_move(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result) + { + return std::uninitialized_copy + (_GLIBCXX_MAKE_MOVE_ITERATOR(__first), + _GLIBCXX_MAKE_MOVE_ITERATOR(__last), __result); + } + + template + inline pair<_InputIterator, _ForwardIterator> + uninitialized_move_n(_InputIterator __first, _Size __count, + _ForwardIterator __result) + { + auto __res = std::__uninitialized_copy_n_pair + (_GLIBCXX_MAKE_MOVE_ITERATOR(__first), + __count, __result); + return {__res.first.base(), __res.second}; + } +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _STL_UNINITIALIZED_H */ diff --git a/AH/STL/Fallback/bits/stl_vector.h b/AH/STL/Fallback/bits/stl_vector.h new file mode 100644 index 0000000..94fef2a --- /dev/null +++ b/AH/STL/Fallback/bits/stl_vector.h @@ -0,0 +1,1662 @@ +// Vector implementation -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/stl_vector.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{vector} + */ + +#ifndef _STL_VECTOR_H +#define _STL_VECTOR_H 1 + +#include "../bits/stl_iterator_base_funcs.h" +#include "../bits/functexcept.h" +#include "../bits/concept_check.h" +#if __cplusplus >= 201103L +#include "../initializer_list" +#endif + +#include "../debug/assertions.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + /// See bits/stl_deque.h's _Deque_base for an explanation. + template + struct _Vector_base + { + typedef typename __gnu_cxx::__alloc_traits<_Alloc>::template + rebind<_Tp>::other _Tp_alloc_type; + typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type>::pointer + pointer; + + struct _Vector_impl + : public _Tp_alloc_type + { + pointer _M_start; + pointer _M_finish; + pointer _M_end_of_storage; + + _Vector_impl() + : _Tp_alloc_type(), _M_start(), _M_finish(), _M_end_of_storage() + { } + + _Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT + : _Tp_alloc_type(__a), _M_start(), _M_finish(), _M_end_of_storage() + { } + +#if __cplusplus >= 201103L + _Vector_impl(_Tp_alloc_type&& __a) noexcept + : _Tp_alloc_type(std::move(__a)), + _M_start(), _M_finish(), _M_end_of_storage() + { } +#endif + + void _M_swap_data(_Vector_impl& __x) _GLIBCXX_NOEXCEPT + { + std::swap(_M_start, __x._M_start); + std::swap(_M_finish, __x._M_finish); + std::swap(_M_end_of_storage, __x._M_end_of_storage); + } + }; + + public: + typedef _Alloc allocator_type; + + _Tp_alloc_type& + _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT + { return *static_cast<_Tp_alloc_type*>(&this->_M_impl); } + + const _Tp_alloc_type& + _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT + { return *static_cast(&this->_M_impl); } + + allocator_type + get_allocator() const _GLIBCXX_NOEXCEPT + { return allocator_type(_M_get_Tp_allocator()); } + + _Vector_base() + : _M_impl() { } + + _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT + : _M_impl(__a) { } + + _Vector_base(size_t __n) + : _M_impl() + { _M_create_storage(__n); } + + _Vector_base(size_t __n, const allocator_type& __a) + : _M_impl(__a) + { _M_create_storage(__n); } + +#if __cplusplus >= 201103L + _Vector_base(_Tp_alloc_type&& __a) noexcept + : _M_impl(std::move(__a)) { } + + _Vector_base(_Vector_base&& __x) noexcept + : _M_impl(std::move(__x._M_get_Tp_allocator())) + { this->_M_impl._M_swap_data(__x._M_impl); } + + _Vector_base(_Vector_base&& __x, const allocator_type& __a) + : _M_impl(__a) + { + if (__x.get_allocator() == __a) + this->_M_impl._M_swap_data(__x._M_impl); + else + { + size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start; + _M_create_storage(__n); + } + } +#endif + + ~_Vector_base() _GLIBCXX_NOEXCEPT + { _M_deallocate(this->_M_impl._M_start, this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); } + + public: + _Vector_impl _M_impl; + + pointer + _M_allocate(size_t __n) + { + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; + return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer(); + } + + void + _M_deallocate(pointer __p, size_t __n) + { + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr; + if (__p) + _Tr::deallocate(_M_impl, __p, __n); + } + + private: + void + _M_create_storage(size_t __n) + { + this->_M_impl._M_start = this->_M_allocate(__n); + this->_M_impl._M_finish = this->_M_impl._M_start; + this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; + } + }; + + + /** + * @brief A standard container which offers fixed time access to + * individual elements in any order. + * + * @ingroup sequences + * + * @tparam _Tp Type of element. + * @tparam _Alloc Allocator type, defaults to allocator<_Tp>. + * + * Meets the requirements of a container, a + * reversible container, and a + * sequence, including the + * optional sequence requirements with the + * %exception of @c push_front and @c pop_front. + * + * In some terminology a %vector can be described as a dynamic + * C-style array, it offers fast and efficient access to individual + * elements in any order and saves the user from worrying about + * memory and size allocation. Subscripting ( @c [] ) access is + * also provided as with C-style arrays. + */ + template > + class vector : protected _Vector_base<_Tp, _Alloc> + { +#ifdef _GLIBCXX_CONCEPT_CHECKS + // Concept requirements. + typedef typename _Alloc::value_type _Alloc_value_type; +# if __cplusplus < 201103L + __glibcxx_class_requires(_Tp, _SGIAssignableConcept) +# endif + __glibcxx_class_requires2(_Tp, _Alloc_value_type, _SameTypeConcept) +#endif + + typedef _Vector_base<_Tp, _Alloc> _Base; + typedef typename _Base::_Tp_alloc_type _Tp_alloc_type; + typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Alloc_traits; + + public: + typedef _Tp value_type; + typedef typename _Base::pointer pointer; + typedef typename _Alloc_traits::const_pointer const_pointer; + typedef typename _Alloc_traits::reference reference; + typedef typename _Alloc_traits::const_reference const_reference; + typedef __gnu_cxx::__normal_iterator iterator; + typedef __gnu_cxx::__normal_iterator + const_iterator; + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Alloc allocator_type; + + protected: + using _Base::_M_allocate; + using _Base::_M_deallocate; + using _Base::_M_impl; + using _Base::_M_get_Tp_allocator; + + public: + // [23.2.4.1] construct/copy/destroy + // (assign() and get_allocator() are also listed in this section) + + /** + * @brief Creates a %vector with no elements. + */ + vector() +#if __cplusplus >= 201103L + noexcept(is_nothrow_default_constructible<_Alloc>::value) +#endif + : _Base() { } + + /** + * @brief Creates a %vector with no elements. + * @param __a An allocator object. + */ + explicit + vector(const allocator_type& __a) _GLIBCXX_NOEXCEPT + : _Base(__a) { } + +#if __cplusplus >= 201103L + /** + * @brief Creates a %vector with default constructed elements. + * @param __n The number of elements to initially create. + * @param __a An allocator. + * + * This constructor fills the %vector with @a __n default + * constructed elements. + */ + explicit + vector(size_type __n, const allocator_type& __a = allocator_type()) + : _Base(__n, __a) + { _M_default_initialize(__n); } + + /** + * @brief Creates a %vector with copies of an exemplar element. + * @param __n The number of elements to initially create. + * @param __value An element to copy. + * @param __a An allocator. + * + * This constructor fills the %vector with @a __n copies of @a __value. + */ + vector(size_type __n, const value_type& __value, + const allocator_type& __a = allocator_type()) + : _Base(__n, __a) + { _M_fill_initialize(__n, __value); } +#else + /** + * @brief Creates a %vector with copies of an exemplar element. + * @param __n The number of elements to initially create. + * @param __value An element to copy. + * @param __a An allocator. + * + * This constructor fills the %vector with @a __n copies of @a __value. + */ + explicit + vector(size_type __n, const value_type& __value = value_type(), + const allocator_type& __a = allocator_type()) + : _Base(__n, __a) + { _M_fill_initialize(__n, __value); } +#endif + + /** + * @brief %Vector copy constructor. + * @param __x A %vector of identical element and allocator types. + * + * All the elements of @a __x are copied, but any unused capacity in + * @a __x will not be copied + * (i.e. capacity() == size() in the new %vector). + * + * The newly-created %vector uses a copy of the allocator object used + * by @a __x (unless the allocator traits dictate a different object). + */ + vector(const vector& __x) + : _Base(__x.size(), + _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())) + { + this->_M_impl._M_finish = + std::__uninitialized_copy_a(__x.begin(), __x.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + } + +#if __cplusplus >= 201103L + /** + * @brief %Vector move constructor. + * @param __x A %vector of identical element and allocator types. + * + * The newly-created %vector contains the exact contents of @a __x. + * The contents of @a __x are a valid, but unspecified %vector. + */ + vector(vector&& __x) noexcept + : _Base(std::move(__x)) { } + + /// Copy constructor with alternative allocator + vector(const vector& __x, const allocator_type& __a) + : _Base(__x.size(), __a) + { + this->_M_impl._M_finish = + std::__uninitialized_copy_a(__x.begin(), __x.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + } + + /// Move constructor with alternative allocator + vector(vector&& __rv, const allocator_type& __m) + noexcept(_Alloc_traits::_S_always_equal()) + : _Base(std::move(__rv), __m) + { + if (__rv.get_allocator() != __m) + { + this->_M_impl._M_finish = + std::__uninitialized_move_a(__rv.begin(), __rv.end(), + this->_M_impl._M_start, + _M_get_Tp_allocator()); + __rv.clear(); + } + } + + /** + * @brief Builds a %vector from an initializer list. + * @param __l An initializer_list. + * @param __a An allocator. + * + * Create a %vector consisting of copies of the elements in the + * initializer_list @a __l. + * + * This will call the element type's copy constructor N times + * (where N is @a __l.size()) and do no memory reallocation. + */ + vector(initializer_list __l, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + _M_range_initialize(__l.begin(), __l.end(), + random_access_iterator_tag()); + } +#endif + + /** + * @brief Builds a %vector from a range. + * @param __first An input iterator. + * @param __last An input iterator. + * @param __a An allocator. + * + * Create a %vector consisting of copies of the elements from + * [first,last). + * + * If the iterators are forward, bidirectional, or + * random-access, then this will call the elements' copy + * constructor N times (where N is distance(first,last)) and do + * no memory reallocation. But if only input iterators are + * used, then this will do at most 2N calls to the copy + * constructor, and logN memory reallocations. + */ +#if __cplusplus >= 201103L + template> + vector(_InputIterator __first, _InputIterator __last, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { _M_initialize_dispatch(__first, __last, __false_type()); } +#else + template + vector(_InputIterator __first, _InputIterator __last, + const allocator_type& __a = allocator_type()) + : _Base(__a) + { + // Check whether it's an integral type. If so, it's not an iterator. + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_initialize_dispatch(__first, __last, _Integral()); + } +#endif + + /** + * The dtor only erases the elements, and note that if the + * elements themselves are pointers, the pointed-to memory is + * not touched in any way. Managing the pointer is the user's + * responsibility. + */ + ~vector() _GLIBCXX_NOEXCEPT + { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); } + + /** + * @brief %Vector assignment operator. + * @param __x A %vector of identical element and allocator types. + * + * All the elements of @a __x are copied, but any unused capacity in + * @a __x will not be copied. + * + * Whether the allocator is copied depends on the allocator traits. + */ + vector& + operator=(const vector& __x); + +#if __cplusplus >= 201103L + /** + * @brief %Vector move assignment operator. + * @param __x A %vector of identical element and allocator types. + * + * The contents of @a __x are moved into this %vector (without copying, + * if the allocators permit it). + * Afterwards @a __x is a valid, but unspecified %vector. + * + * Whether the allocator is moved depends on the allocator traits. + */ + vector& + operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) + { + constexpr bool __move_storage = + _Alloc_traits::_S_propagate_on_move_assign() + || _Alloc_traits::_S_always_equal(); + _M_move_assign(std::move(__x), __bool_constant<__move_storage>()); + return *this; + } + + /** + * @brief %Vector list assignment operator. + * @param __l An initializer_list. + * + * This function fills a %vector with copies of the elements in the + * initializer list @a __l. + * + * Note that the assignment completely changes the %vector and + * that the resulting %vector's size is the same as the number + * of elements assigned. + */ + vector& + operator=(initializer_list __l) + { + this->_M_assign_aux(__l.begin(), __l.end(), + random_access_iterator_tag()); + return *this; + } +#endif + + /** + * @brief Assigns a given value to a %vector. + * @param __n Number of elements to be assigned. + * @param __val Value to be assigned. + * + * This function fills a %vector with @a __n copies of the given + * value. Note that the assignment completely changes the + * %vector and that the resulting %vector's size is the same as + * the number of elements assigned. + */ + void + assign(size_type __n, const value_type& __val) + { _M_fill_assign(__n, __val); } + + /** + * @brief Assigns a range to a %vector. + * @param __first An input iterator. + * @param __last An input iterator. + * + * This function fills a %vector with copies of the elements in the + * range [__first,__last). + * + * Note that the assignment completely changes the %vector and + * that the resulting %vector's size is the same as the number + * of elements assigned. + */ +#if __cplusplus >= 201103L + template> + void + assign(_InputIterator __first, _InputIterator __last) + { _M_assign_dispatch(__first, __last, __false_type()); } +#else + template + void + assign(_InputIterator __first, _InputIterator __last) + { + // Check whether it's an integral type. If so, it's not an iterator. + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_assign_dispatch(__first, __last, _Integral()); + } +#endif + +#if __cplusplus >= 201103L + /** + * @brief Assigns an initializer list to a %vector. + * @param __l An initializer_list. + * + * This function fills a %vector with copies of the elements in the + * initializer list @a __l. + * + * Note that the assignment completely changes the %vector and + * that the resulting %vector's size is the same as the number + * of elements assigned. + */ + void + assign(initializer_list __l) + { + this->_M_assign_aux(__l.begin(), __l.end(), + random_access_iterator_tag()); + } +#endif + + /// Get a copy of the memory allocation object. + using _Base::get_allocator; + + // iterators + /** + * Returns a read/write iterator that points to the first + * element in the %vector. Iteration is done in ordinary + * element order. + */ + iterator + begin() _GLIBCXX_NOEXCEPT + { return iterator(this->_M_impl._M_start); } + + /** + * Returns a read-only (constant) iterator that points to the + * first element in the %vector. Iteration is done in ordinary + * element order. + */ + const_iterator + begin() const _GLIBCXX_NOEXCEPT + { return const_iterator(this->_M_impl._M_start); } + + /** + * Returns a read/write iterator that points one past the last + * element in the %vector. Iteration is done in ordinary + * element order. + */ + iterator + end() _GLIBCXX_NOEXCEPT + { return iterator(this->_M_impl._M_finish); } + + /** + * Returns a read-only (constant) iterator that points one past + * the last element in the %vector. Iteration is done in + * ordinary element order. + */ + const_iterator + end() const _GLIBCXX_NOEXCEPT + { return const_iterator(this->_M_impl._M_finish); } + + /** + * Returns a read/write reverse iterator that points to the + * last element in the %vector. Iteration is done in reverse + * element order. + */ + reverse_iterator + rbegin() _GLIBCXX_NOEXCEPT + { return reverse_iterator(end()); } + + /** + * Returns a read-only (constant) reverse iterator that points + * to the last element in the %vector. Iteration is done in + * reverse element order. + */ + const_reverse_iterator + rbegin() const _GLIBCXX_NOEXCEPT + { return const_reverse_iterator(end()); } + + /** + * Returns a read/write reverse iterator that points to one + * before the first element in the %vector. Iteration is done + * in reverse element order. + */ + reverse_iterator + rend() _GLIBCXX_NOEXCEPT + { return reverse_iterator(begin()); } + + /** + * Returns a read-only (constant) reverse iterator that points + * to one before the first element in the %vector. Iteration + * is done in reverse element order. + */ + const_reverse_iterator + rend() const _GLIBCXX_NOEXCEPT + { return const_reverse_iterator(begin()); } + +#if __cplusplus >= 201103L + /** + * Returns a read-only (constant) iterator that points to the + * first element in the %vector. Iteration is done in ordinary + * element order. + */ + const_iterator + cbegin() const noexcept + { return const_iterator(this->_M_impl._M_start); } + + /** + * Returns a read-only (constant) iterator that points one past + * the last element in the %vector. Iteration is done in + * ordinary element order. + */ + const_iterator + cend() const noexcept + { return const_iterator(this->_M_impl._M_finish); } + + /** + * Returns a read-only (constant) reverse iterator that points + * to the last element in the %vector. Iteration is done in + * reverse element order. + */ + const_reverse_iterator + crbegin() const noexcept + { return const_reverse_iterator(end()); } + + /** + * Returns a read-only (constant) reverse iterator that points + * to one before the first element in the %vector. Iteration + * is done in reverse element order. + */ + const_reverse_iterator + crend() const noexcept + { return const_reverse_iterator(begin()); } +#endif + + // [23.2.4.2] capacity + /** Returns the number of elements in the %vector. */ + size_type + size() const _GLIBCXX_NOEXCEPT + { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } + + /** Returns the size() of the largest possible %vector. */ + size_type + max_size() const _GLIBCXX_NOEXCEPT + { return _Alloc_traits::max_size(_M_get_Tp_allocator()); } + +#if __cplusplus >= 201103L + /** + * @brief Resizes the %vector to the specified number of elements. + * @param __new_size Number of elements the %vector should contain. + * + * This function will %resize the %vector to the specified + * number of elements. If the number is smaller than the + * %vector's current size the %vector is truncated, otherwise + * default constructed elements are appended. + */ + void + resize(size_type __new_size) + { + if (__new_size > size()) + _M_default_append(__new_size - size()); + else if (__new_size < size()) + _M_erase_at_end(this->_M_impl._M_start + __new_size); + } + + /** + * @brief Resizes the %vector to the specified number of elements. + * @param __new_size Number of elements the %vector should contain. + * @param __x Data with which new elements should be populated. + * + * This function will %resize the %vector to the specified + * number of elements. If the number is smaller than the + * %vector's current size the %vector is truncated, otherwise + * the %vector is extended and new elements are populated with + * given data. + */ + void + resize(size_type __new_size, const value_type& __x) + { + if (__new_size > size()) + _M_fill_insert(end(), __new_size - size(), __x); + else if (__new_size < size()) + _M_erase_at_end(this->_M_impl._M_start + __new_size); + } +#else + /** + * @brief Resizes the %vector to the specified number of elements. + * @param __new_size Number of elements the %vector should contain. + * @param __x Data with which new elements should be populated. + * + * This function will %resize the %vector to the specified + * number of elements. If the number is smaller than the + * %vector's current size the %vector is truncated, otherwise + * the %vector is extended and new elements are populated with + * given data. + */ + void + resize(size_type __new_size, value_type __x = value_type()) + { + if (__new_size > size()) + _M_fill_insert(end(), __new_size - size(), __x); + else if (__new_size < size()) + _M_erase_at_end(this->_M_impl._M_start + __new_size); + } +#endif + +#if __cplusplus >= 201103L + /** A non-binding request to reduce capacity() to size(). */ + void + shrink_to_fit() + { _M_shrink_to_fit(); } +#endif + + /** + * Returns the total number of elements that the %vector can + * hold before needing to allocate more memory. + */ + size_type + capacity() const _GLIBCXX_NOEXCEPT + { return size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); } + + /** + * Returns true if the %vector is empty. (Thus begin() would + * equal end().) + */ + bool + empty() const _GLIBCXX_NOEXCEPT + { return begin() == end(); } + + /** + * @brief Attempt to preallocate enough memory for specified number of + * elements. + * @param __n Number of elements required. + * @throw std::length_error If @a n exceeds @c max_size(). + * + * This function attempts to reserve enough memory for the + * %vector to hold the specified number of elements. If the + * number requested is more than max_size(), length_error is + * thrown. + * + * The advantage of this function is that if optimal code is a + * necessity and the user can determine the number of elements + * that will be required, the user can reserve the memory in + * %advance, and thus prevent a possible reallocation of memory + * and copying of %vector data. + */ + void + reserve(size_type __n); + + // element access + /** + * @brief Subscript access to the data contained in the %vector. + * @param __n The index of the element for which data should be + * accessed. + * @return Read/write reference to data. + * + * This operator allows for easy, array-style, data access. + * Note that data access with this operator is unchecked and + * out_of_range lookups are not defined. (For checked lookups + * see at().) + */ + reference + operator[](size_type __n) _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_subscript(__n); + return *(this->_M_impl._M_start + __n); + } + + /** + * @brief Subscript access to the data contained in the %vector. + * @param __n The index of the element for which data should be + * accessed. + * @return Read-only (constant) reference to data. + * + * This operator allows for easy, array-style, data access. + * Note that data access with this operator is unchecked and + * out_of_range lookups are not defined. (For checked lookups + * see at().) + */ + const_reference + operator[](size_type __n) const _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_subscript(__n); + return *(this->_M_impl._M_start + __n); + } + + protected: + /// Safety check used only from at(). + void + _M_range_check(size_type __n) const + { +#ifndef __AVR__ + if (__n >= this->size()) + __throw_out_of_range_fmt(__N("vector::_M_range_check: __n " + "(which is %zu) >= this->size() " + "(which is %zu)"), + __n, this->size()); +#else + if (__n >= this->size()) + __throw_out_of_range_index_length(F("vector::_M_range_check"), + __n, this->size()); +#endif + } + + public: + /** + * @brief Provides access to the data contained in the %vector. + * @param __n The index of the element for which data should be + * accessed. + * @return Read/write reference to data. + * @throw std::out_of_range If @a __n is an invalid index. + * + * This function provides for safer data access. The parameter + * is first checked that it is in the range of the vector. The + * function throws out_of_range if the check fails. + */ + reference + at(size_type __n) + { + _M_range_check(__n); + return (*this)[__n]; + } + + /** + * @brief Provides access to the data contained in the %vector. + * @param __n The index of the element for which data should be + * accessed. + * @return Read-only (constant) reference to data. + * @throw std::out_of_range If @a __n is an invalid index. + * + * This function provides for safer data access. The parameter + * is first checked that it is in the range of the vector. The + * function throws out_of_range if the check fails. + */ + const_reference + at(size_type __n) const + { + _M_range_check(__n); + return (*this)[__n]; + } + + /** + * Returns a read/write reference to the data at the first + * element of the %vector. + */ + reference + front() _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_nonempty(); + return *begin(); + } + + /** + * Returns a read-only (constant) reference to the data at the first + * element of the %vector. + */ + const_reference + front() const _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_nonempty(); + return *begin(); + } + + /** + * Returns a read/write reference to the data at the last + * element of the %vector. + */ + reference + back() _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_nonempty(); + return *(end() - 1); + } + + /** + * Returns a read-only (constant) reference to the data at the + * last element of the %vector. + */ + const_reference + back() const _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_nonempty(); + return *(end() - 1); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 464. Suggestion for new member functions in standard containers. + // data access + /** + * Returns a pointer such that [data(), data() + size()) is a valid + * range. For a non-empty %vector, data() == &front(). + */ + _Tp* + data() _GLIBCXX_NOEXCEPT + { return _M_data_ptr(this->_M_impl._M_start); } + + const _Tp* + data() const _GLIBCXX_NOEXCEPT + { return _M_data_ptr(this->_M_impl._M_start); } + + // [23.2.4.3] modifiers + /** + * @brief Add data to the end of the %vector. + * @param __x Data to be added. + * + * This is a typical stack operation. The function creates an + * element at the end of the %vector and assigns the given data + * to it. Due to the nature of a %vector this operation can be + * done in constant time if the %vector has preallocated space + * available. + */ + void + push_back(const value_type& __x) + { + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + __x); + ++this->_M_impl._M_finish; + } + else + _M_realloc_insert(end(), __x); + } + +#if __cplusplus >= 201103L + void + push_back(value_type&& __x) + { emplace_back(std::move(__x)); } + + template +#if __cplusplus > 201402L + reference +#else + void +#endif + emplace_back(_Args&&... __args); +#endif + + /** + * @brief Removes last element. + * + * This is a typical stack operation. It shrinks the %vector by one. + * + * Note that no data is returned, and if the last element's + * data is needed, it should be retrieved before pop_back() is + * called. + */ + void + pop_back() _GLIBCXX_NOEXCEPT + { + __glibcxx_requires_nonempty(); + --this->_M_impl._M_finish; + _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); + } + +#if __cplusplus >= 201103L + /** + * @brief Inserts an object in %vector before specified iterator. + * @param __position A const_iterator into the %vector. + * @param __args Arguments. + * @return An iterator that points to the inserted data. + * + * This function will insert an object of type T constructed + * with T(std::forward(args)...) before the specified location. + * Note that this kind of operation could be expensive for a %vector + * and if it is frequently used the user should consider using + * std::list. + */ + template + iterator + emplace(const_iterator __position, _Args&&... __args) + { return _M_emplace_aux(__position, std::forward<_Args>(__args)...); } + + /** + * @brief Inserts given value into %vector before specified iterator. + * @param __position A const_iterator into the %vector. + * @param __x Data to be inserted. + * @return An iterator that points to the inserted data. + * + * This function will insert a copy of the given value before + * the specified location. Note that this kind of operation + * could be expensive for a %vector and if it is frequently + * used the user should consider using std::list. + */ + iterator + insert(const_iterator __position, const value_type& __x); +#else + /** + * @brief Inserts given value into %vector before specified iterator. + * @param __position An iterator into the %vector. + * @param __x Data to be inserted. + * @return An iterator that points to the inserted data. + * + * This function will insert a copy of the given value before + * the specified location. Note that this kind of operation + * could be expensive for a %vector and if it is frequently + * used the user should consider using std::list. + */ + iterator + insert(iterator __position, const value_type& __x); +#endif + +#if __cplusplus >= 201103L + /** + * @brief Inserts given rvalue into %vector before specified iterator. + * @param __position A const_iterator into the %vector. + * @param __x Data to be inserted. + * @return An iterator that points to the inserted data. + * + * This function will insert a copy of the given rvalue before + * the specified location. Note that this kind of operation + * could be expensive for a %vector and if it is frequently + * used the user should consider using std::list. + */ + iterator + insert(const_iterator __position, value_type&& __x) + { return _M_insert_rval(__position, std::move(__x)); } + + /** + * @brief Inserts an initializer_list into the %vector. + * @param __position An iterator into the %vector. + * @param __l An initializer_list. + * + * This function will insert copies of the data in the + * initializer_list @a l into the %vector before the location + * specified by @a position. + * + * Note that this kind of operation could be expensive for a + * %vector and if it is frequently used the user should + * consider using std::list. + */ + iterator + insert(const_iterator __position, initializer_list __l) + { + auto __offset = __position - cbegin(); + _M_range_insert(begin() + __offset, __l.begin(), __l.end(), + std::random_access_iterator_tag()); + return begin() + __offset; + } +#endif + +#if __cplusplus >= 201103L + /** + * @brief Inserts a number of copies of given data into the %vector. + * @param __position A const_iterator into the %vector. + * @param __n Number of elements to be inserted. + * @param __x Data to be inserted. + * @return An iterator that points to the inserted data. + * + * This function will insert a specified number of copies of + * the given data before the location specified by @a position. + * + * Note that this kind of operation could be expensive for a + * %vector and if it is frequently used the user should + * consider using std::list. + */ + iterator + insert(const_iterator __position, size_type __n, const value_type& __x) + { + difference_type __offset = __position - cbegin(); + _M_fill_insert(begin() + __offset, __n, __x); + return begin() + __offset; + } +#else + /** + * @brief Inserts a number of copies of given data into the %vector. + * @param __position An iterator into the %vector. + * @param __n Number of elements to be inserted. + * @param __x Data to be inserted. + * + * This function will insert a specified number of copies of + * the given data before the location specified by @a position. + * + * Note that this kind of operation could be expensive for a + * %vector and if it is frequently used the user should + * consider using std::list. + */ + void + insert(iterator __position, size_type __n, const value_type& __x) + { _M_fill_insert(__position, __n, __x); } +#endif + +#if __cplusplus >= 201103L + /** + * @brief Inserts a range into the %vector. + * @param __position A const_iterator into the %vector. + * @param __first An input iterator. + * @param __last An input iterator. + * @return An iterator that points to the inserted data. + * + * This function will insert copies of the data in the range + * [__first,__last) into the %vector before the location specified + * by @a pos. + * + * Note that this kind of operation could be expensive for a + * %vector and if it is frequently used the user should + * consider using std::list. + */ + template> + iterator + insert(const_iterator __position, _InputIterator __first, + _InputIterator __last) + { + difference_type __offset = __position - cbegin(); + _M_insert_dispatch(begin() + __offset, + __first, __last, __false_type()); + return begin() + __offset; + } +#else + /** + * @brief Inserts a range into the %vector. + * @param __position An iterator into the %vector. + * @param __first An input iterator. + * @param __last An input iterator. + * + * This function will insert copies of the data in the range + * [__first,__last) into the %vector before the location specified + * by @a pos. + * + * Note that this kind of operation could be expensive for a + * %vector and if it is frequently used the user should + * consider using std::list. + */ + template + void + insert(iterator __position, _InputIterator __first, + _InputIterator __last) + { + // Check whether it's an integral type. If so, it's not an iterator. + typedef typename std::__is_integer<_InputIterator>::__type _Integral; + _M_insert_dispatch(__position, __first, __last, _Integral()); + } +#endif + + /** + * @brief Remove element at given position. + * @param __position Iterator pointing to element to be erased. + * @return An iterator pointing to the next element (or end()). + * + * This function will erase the element at the given position and thus + * shorten the %vector by one. + * + * Note This operation could be expensive and if it is + * frequently used the user should consider using std::list. + * The user is also cautioned that this function only erases + * the element, and that if the element is itself a pointer, + * the pointed-to memory is not touched in any way. Managing + * the pointer is the user's responsibility. + */ + iterator +#if __cplusplus >= 201103L + erase(const_iterator __position) + { return _M_erase(begin() + (__position - cbegin())); } +#else + erase(iterator __position) + { return _M_erase(__position); } +#endif + + /** + * @brief Remove a range of elements. + * @param __first Iterator pointing to the first element to be erased. + * @param __last Iterator pointing to one past the last element to be + * erased. + * @return An iterator pointing to the element pointed to by @a __last + * prior to erasing (or end()). + * + * This function will erase the elements in the range + * [__first,__last) and shorten the %vector accordingly. + * + * Note This operation could be expensive and if it is + * frequently used the user should consider using std::list. + * The user is also cautioned that this function only erases + * the elements, and that if the elements themselves are + * pointers, the pointed-to memory is not touched in any way. + * Managing the pointer is the user's responsibility. + */ + iterator +#if __cplusplus >= 201103L + erase(const_iterator __first, const_iterator __last) + { + const auto __beg = begin(); + const auto __cbeg = cbegin(); + return _M_erase(__beg + (__first - __cbeg), __beg + (__last - __cbeg)); + } +#else + erase(iterator __first, iterator __last) + { return _M_erase(__first, __last); } +#endif + + /** + * @brief Swaps data with another %vector. + * @param __x A %vector of the same element and allocator types. + * + * This exchanges the elements between two vectors in constant time. + * (Three pointers, so it should be quite fast.) + * Note that the global std::swap() function is specialized such that + * std::swap(v1,v2) will feed to this function. + * + * Whether the allocators are swapped depends on the allocator traits. + */ + void + swap(vector& __x) _GLIBCXX_NOEXCEPT + { +#if __cplusplus >= 201103L + __glibcxx_assert(_Alloc_traits::propagate_on_container_swap::value + || _M_get_Tp_allocator() == __x._M_get_Tp_allocator()); +#endif + this->_M_impl._M_swap_data(__x._M_impl); + _Alloc_traits::_S_on_swap(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + } + + /** + * Erases all the elements. Note that this function only erases the + * elements, and that if the elements themselves are pointers, the + * pointed-to memory is not touched in any way. Managing the pointer is + * the user's responsibility. + */ + void + clear() _GLIBCXX_NOEXCEPT + { _M_erase_at_end(this->_M_impl._M_start); } + + protected: + /** + * Memory expansion handler. Uses the member allocation function to + * obtain @a n bytes of memory, and then copies [first,last) into it. + */ + template + pointer + _M_allocate_and_copy(size_type __n, + _ForwardIterator __first, _ForwardIterator __last) + { + pointer __result = this->_M_allocate(__n); + __try + { + std::__uninitialized_copy_a(__first, __last, __result, + _M_get_Tp_allocator()); + return __result; + } + __catch(...) + { + _M_deallocate(__result, __n); + __throw_exception_again; + } + } + + + // Internal constructor functions follow. + + // Called by the range constructor to implement [23.1.1]/9 + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_initialize_dispatch(_Integer __n, _Integer __value, __true_type) + { + this->_M_impl._M_start = _M_allocate(static_cast(__n)); + this->_M_impl._M_end_of_storage = + this->_M_impl._M_start + static_cast(__n); + _M_fill_initialize(static_cast(__n), __value); + } + + // Called by the range constructor to implement [23.1.1]/9 + template + void + _M_initialize_dispatch(_InputIterator __first, _InputIterator __last, + __false_type) + { + typedef typename std::iterator_traits<_InputIterator>:: + iterator_category _IterCategory; + _M_range_initialize(__first, __last, _IterCategory()); + } + + // Called by the second initialize_dispatch above + template + void + _M_range_initialize(_InputIterator __first, _InputIterator __last, + std::input_iterator_tag) + { + __try { + for (; __first != __last; ++__first) +#if __cplusplus >= 201103L + emplace_back(*__first); +#else + push_back(*__first); +#endif + } __catch(...) { + clear(); + __throw_exception_again; + } + } + + // Called by the second initialize_dispatch above + template + void + _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag) + { + const size_type __n = std::distance(__first, __last); + this->_M_impl._M_start = this->_M_allocate(__n); + this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; + this->_M_impl._M_finish = + std::__uninitialized_copy_a(__first, __last, + this->_M_impl._M_start, + _M_get_Tp_allocator()); + } + + // Called by the first initialize_dispatch above and by the + // vector(n,value,a) constructor. + void + _M_fill_initialize(size_type __n, const value_type& __value) + { + this->_M_impl._M_finish = + std::__uninitialized_fill_n_a(this->_M_impl._M_start, __n, __value, + _M_get_Tp_allocator()); + } + +#if __cplusplus >= 201103L + // Called by the vector(n) constructor. + void + _M_default_initialize(size_type __n) + { + this->_M_impl._M_finish = + std::__uninitialized_default_n_a(this->_M_impl._M_start, __n, + _M_get_Tp_allocator()); + } +#endif + + // Internal assign functions follow. The *_aux functions do the actual + // assignment work for the range versions. + + // Called by the range assign to implement [23.1.1]/9 + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) + { _M_fill_assign(__n, __val); } + + // Called by the range assign to implement [23.1.1]/9 + template + void + _M_assign_dispatch(_InputIterator __first, _InputIterator __last, + __false_type) + { _M_assign_aux(__first, __last, std::__iterator_category(__first)); } + + // Called by the second assign_dispatch above + template + void + _M_assign_aux(_InputIterator __first, _InputIterator __last, + std::input_iterator_tag); + + // Called by the second assign_dispatch above + template + void + _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag); + + // Called by assign(n,t), and the range assign when it turns out + // to be the same thing. + void + _M_fill_assign(size_type __n, const value_type& __val); + + // Internal insert functions follow. + + // Called by the range insert to implement [23.1.1]/9 + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 438. Ambiguity in the "do the right thing" clause + template + void + _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val, + __true_type) + { _M_fill_insert(__pos, __n, __val); } + + // Called by the range insert to implement [23.1.1]/9 + template + void + _M_insert_dispatch(iterator __pos, _InputIterator __first, + _InputIterator __last, __false_type) + { + _M_range_insert(__pos, __first, __last, + std::__iterator_category(__first)); + } + + // Called by the second insert_dispatch above + template + void + _M_range_insert(iterator __pos, _InputIterator __first, + _InputIterator __last, std::input_iterator_tag); + + // Called by the second insert_dispatch above + template + void + _M_range_insert(iterator __pos, _ForwardIterator __first, + _ForwardIterator __last, std::forward_iterator_tag); + + // Called by insert(p,n,x), and the range insert when it turns out to be + // the same thing. + void + _M_fill_insert(iterator __pos, size_type __n, const value_type& __x); + +#if __cplusplus >= 201103L + // Called by resize(n). + void + _M_default_append(size_type __n); + + bool + _M_shrink_to_fit(); +#endif + +#if __cplusplus < 201103L + // Called by insert(p,x) + void + _M_insert_aux(iterator __position, const value_type& __x); + + void + _M_realloc_insert(iterator __position, const value_type& __x); +#else + // A value_type object constructed with _Alloc_traits::construct() + // and destroyed with _Alloc_traits::destroy(). + struct _Temporary_value + { + template + explicit + _Temporary_value(vector* __vec, _Args&&... __args) : _M_this(__vec) + { + _Alloc_traits::construct(_M_this->_M_impl, _M_ptr(), + std::forward<_Args>(__args)...); + } + + ~_Temporary_value() + { _Alloc_traits::destroy(_M_this->_M_impl, _M_ptr()); } + + value_type& + _M_val() { return *reinterpret_cast<_Tp*>(&__buf); } + + private: + pointer + _M_ptr() { return pointer_traits::pointer_to(_M_val()); } + + vector* _M_this; + typename aligned_storage::type __buf; + }; + + // Called by insert(p,x) and other functions when insertion needs to + // reallocate or move existing elements. _Arg is either _Tp& or _Tp. + template + void + _M_insert_aux(iterator __position, _Arg&& __arg); + + template + void + _M_realloc_insert(iterator __position, _Args&&... __args); + + // Either move-construct at the end, or forward to _M_insert_aux. + iterator + _M_insert_rval(const_iterator __position, value_type&& __v); + + // Try to emplace at the end, otherwise forward to _M_insert_aux. + template + iterator + _M_emplace_aux(const_iterator __position, _Args&&... __args); + + // Emplacing an rvalue of the correct type can use _M_insert_rval. + iterator + _M_emplace_aux(const_iterator __position, value_type&& __v) + { return _M_insert_rval(__position, std::move(__v)); } +#endif + + // Called by _M_fill_insert, _M_insert_aux etc. + size_type + _M_check_len(size_type __n, const char* __s) const + { + if (max_size() - size() < __n) + __throw_length_error(__N(__s)); + + const size_type __len = size() + std::max(size(), __n); + return (__len < size() || __len > max_size()) ? max_size() : __len; + } + + // Internal erase functions follow. + + // Called by erase(q1,q2), clear(), resize(), _M_fill_assign, + // _M_assign_aux. + void + _M_erase_at_end(pointer __pos) _GLIBCXX_NOEXCEPT + { + std::_Destroy(__pos, this->_M_impl._M_finish, _M_get_Tp_allocator()); + this->_M_impl._M_finish = __pos; + } + + iterator + _M_erase(iterator __position); + + iterator + _M_erase(iterator __first, iterator __last); + +#if __cplusplus >= 201103L + private: + // Constant-time move assignment when source object's memory can be + // moved, either because the source's allocator will move too + // or because the allocators are equal. + void + _M_move_assign(vector&& __x, std::true_type) noexcept + { + vector __tmp(get_allocator()); + this->_M_impl._M_swap_data(__tmp._M_impl); + this->_M_impl._M_swap_data(__x._M_impl); + std::__alloc_on_move(_M_get_Tp_allocator(), __x._M_get_Tp_allocator()); + } + + // Do move assignment when it might not be possible to move source + // object's memory, resulting in a linear-time operation. + void + _M_move_assign(vector&& __x, std::false_type) + { + if (__x._M_get_Tp_allocator() == this->_M_get_Tp_allocator()) + _M_move_assign(std::move(__x), std::true_type()); + else + { + // The rvalue's allocator cannot be moved and is not equal, + // so we need to individually move each element. + this->assign(std::__make_move_if_noexcept_iterator(__x.begin()), + std::__make_move_if_noexcept_iterator(__x.end())); + __x.clear(); + } + } +#endif + + template + _Up* + _M_data_ptr(_Up* __ptr) const _GLIBCXX_NOEXCEPT + { return __ptr; } + +#if __cplusplus >= 201103L + template + typename std::pointer_traits<_Ptr>::element_type* + _M_data_ptr(_Ptr __ptr) const + { return empty() ? nullptr : std::__addressof(*__ptr); } +#else + template + _Up* + _M_data_ptr(_Up* __ptr) _GLIBCXX_NOEXCEPT + { return __ptr; } + + template + value_type* + _M_data_ptr(_Ptr __ptr) + { return __ptr.operator->(); } + + template + const value_type* + _M_data_ptr(_Ptr __ptr) const + { return __ptr.operator->(); } +#endif + }; + + + /** + * @brief Vector equality comparison. + * @param __x A %vector. + * @param __y A %vector of the same type as @a __x. + * @return True iff the size and elements of the vectors are equal. + * + * This is an equivalence relation. It is linear in the size of the + * vectors. Vectors are considered equivalent if their sizes are equal, + * and if corresponding elements compare equal. + */ + template + inline bool + operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return (__x.size() == __y.size() + && std::equal(__x.begin(), __x.end(), __y.begin())); } + + /** + * @brief Vector ordering relation. + * @param __x A %vector. + * @param __y A %vector of the same type as @a __x. + * @return True iff @a __x is lexicographically less than @a __y. + * + * This is a total ordering relation. It is linear in the size of the + * vectors. The elements must be comparable with @c <. + * + * See std::lexicographical_compare() for how the determination is made. + */ + template + inline bool + operator<(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return std::lexicographical_compare(__x.begin(), __x.end(), + __y.begin(), __y.end()); } + + /// Based on operator== + template + inline bool + operator!=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return !(__x == __y); } + + /// Based on operator< + template + inline bool + operator>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return __y < __x; } + + /// Based on operator< + template + inline bool + operator<=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return !(__y < __x); } + + /// Based on operator< + template + inline bool + operator>=(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) + { return !(__x < __y); } + + /// See std::vector::swap(). + template + inline void + swap(vector<_Tp, _Alloc>& __x, vector<_Tp, _Alloc>& __y) + _GLIBCXX_NOEXCEPT_IF(noexcept(__x.swap(__y))) + { __x.swap(__y); } + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +#endif /* _STL_VECTOR_H */ diff --git a/AH/STL/Fallback/bits/uniform_int_dist.h b/AH/STL/Fallback/bits/uniform_int_dist.h new file mode 100644 index 0000000..46fdb8d --- /dev/null +++ b/AH/STL/Fallback/bits/uniform_int_dist.h @@ -0,0 +1,375 @@ +// Class template uniform_int_distribution -*- C++ -*- + +// Copyright (C) 2009-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** + * @file bits/uniform_int_dist.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{random} + */ + +#ifndef _GLIBCXX_BITS_UNIFORM_INT_DIST_H +#define _GLIBCXX_BITS_UNIFORM_INT_DIST_H + +#include "../type_traits" +#include "../limits" + +namespace std _GLIBCXX_VISIBILITY(default) +{ + + namespace __detail + { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + /* Determine whether number is a power of 2. */ + template + inline bool + _Power_of_2(_Tp __x) + { + return ((__x - 1) & __x) == 0; + }; +_GLIBCXX_END_NAMESPACE_VERSION + } + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief Uniform discrete distribution for random numbers. + * A discrete random distribution on the range @f$[min, max]@f$ with equal + * probability throughout the range. + */ + template + class uniform_int_distribution + { + static_assert(std::is_integral<_IntType>::value, + "template argument must be an integral type"); + + public: + /** The type of the range of the distribution. */ + typedef _IntType result_type; + /** Parameter type. */ + struct param_type + { + typedef uniform_int_distribution<_IntType> distribution_type; + + explicit + param_type(_IntType __a = 0, + _IntType __b = std::numeric_limits<_IntType>::max()) + : _M_a(__a), _M_b(__b) + { + __glibcxx_assert(_M_a <= _M_b); + } + + result_type + a() const + { return _M_a; } + + result_type + b() const + { return _M_b; } + + friend bool + operator==(const param_type& __p1, const param_type& __p2) + { return __p1._M_a == __p2._M_a && __p1._M_b == __p2._M_b; } + + friend bool + operator!=(const param_type& __p1, const param_type& __p2) + { return !(__p1 == __p2); } + + private: + _IntType _M_a; + _IntType _M_b; + }; + + public: + /** + * @brief Constructs a uniform distribution object. + */ + explicit + uniform_int_distribution(_IntType __a = 0, + _IntType __b = std::numeric_limits<_IntType>::max()) + : _M_param(__a, __b) + { } + + explicit + uniform_int_distribution(const param_type& __p) + : _M_param(__p) + { } + + /** + * @brief Resets the distribution state. + * + * Does nothing for the uniform integer distribution. + */ + void + reset() { } + + result_type + a() const + { return _M_param.a(); } + + result_type + b() const + { return _M_param.b(); } + + /** + * @brief Returns the parameter set of the distribution. + */ + param_type + param() const + { return _M_param; } + + /** + * @brief Sets the parameter set of the distribution. + * @param __param The new parameter set of the distribution. + */ + void + param(const param_type& __param) + { _M_param = __param; } + + /** + * @brief Returns the inclusive lower bound of the distribution range. + */ + result_type + min() const + { return this->a(); } + + /** + * @brief Returns the inclusive upper bound of the distribution range. + */ + result_type + max() const + { return this->b(); } + + /** + * @brief Generating functions. + */ + template + result_type + operator()(_UniformRandomNumberGenerator& __urng) + { return this->operator()(__urng, _M_param); } + + template + result_type + operator()(_UniformRandomNumberGenerator& __urng, + const param_type& __p); + + template + void + __generate(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng) + { this->__generate(__f, __t, __urng, _M_param); } + + template + void + __generate(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p) + { this->__generate_impl(__f, __t, __urng, __p); } + + template + void + __generate(result_type* __f, result_type* __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p) + { this->__generate_impl(__f, __t, __urng, __p); } + + /** + * @brief Return true if two uniform integer distributions have + * the same parameters. + */ + friend bool + operator==(const uniform_int_distribution& __d1, + const uniform_int_distribution& __d2) + { return __d1._M_param == __d2._M_param; } + + private: + template + void + __generate_impl(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __p); + + param_type _M_param; + }; + + template + template + typename uniform_int_distribution<_IntType>::result_type + uniform_int_distribution<_IntType>:: + operator()(_UniformRandomNumberGenerator& __urng, + const param_type& __param) + { + typedef typename _UniformRandomNumberGenerator::result_type + _Gresult_type; + typedef typename std::make_unsigned::type __utype; + typedef typename std::common_type<_Gresult_type, __utype>::type + __uctype; + + const __uctype __urngmin = __urng.min(); + const __uctype __urngmax = __urng.max(); + const __uctype __urngrange = __urngmax - __urngmin; + const __uctype __urange + = __uctype(__param.b()) - __uctype(__param.a()); + + __uctype __ret; + + if (__urngrange > __urange) + { + // downscaling + const __uctype __uerange = __urange + 1; // __urange can be zero + const __uctype __scaling = __urngrange / __uerange; + const __uctype __past = __uerange * __scaling; + do + __ret = __uctype(__urng()) - __urngmin; + while (__ret >= __past); + __ret /= __scaling; + } + else if (__urngrange < __urange) + { + // upscaling + /* + Note that every value in [0, urange] + can be written uniquely as + + (urngrange + 1) * high + low + + where + + high in [0, urange / (urngrange + 1)] + + and + + low in [0, urngrange]. + */ + __uctype __tmp; // wraparound control + do + { + const __uctype __uerngrange = __urngrange + 1; + __tmp = (__uerngrange * operator() + (__urng, param_type(0, __urange / __uerngrange))); + __ret = __tmp + (__uctype(__urng()) - __urngmin); + } + while (__ret > __urange || __ret < __tmp); + } + else + __ret = __uctype(__urng()) - __urngmin; + + return __ret + __param.a(); + } + + + template + template + void + uniform_int_distribution<_IntType>:: + __generate_impl(_ForwardIterator __f, _ForwardIterator __t, + _UniformRandomNumberGenerator& __urng, + const param_type& __param) + { + __glibcxx_function_requires(_ForwardIteratorConcept<_ForwardIterator>) + typedef typename _UniformRandomNumberGenerator::result_type + _Gresult_type; + typedef typename std::make_unsigned::type __utype; + typedef typename std::common_type<_Gresult_type, __utype>::type + __uctype; + + const __uctype __urngmin = __urng.min(); + const __uctype __urngmax = __urng.max(); + const __uctype __urngrange = __urngmax - __urngmin; + const __uctype __urange + = __uctype(__param.b()) - __uctype(__param.a()); + + __uctype __ret; + + if (__urngrange > __urange) + { + if (__detail::_Power_of_2(__urngrange + 1) + && __detail::_Power_of_2(__urange + 1)) + { + while (__f != __t) + { + __ret = __uctype(__urng()) - __urngmin; + *__f++ = (__ret & __urange) + __param.a(); + } + } + else + { + // downscaling + const __uctype __uerange = __urange + 1; // __urange can be zero + const __uctype __scaling = __urngrange / __uerange; + const __uctype __past = __uerange * __scaling; + while (__f != __t) + { + do + __ret = __uctype(__urng()) - __urngmin; + while (__ret >= __past); + *__f++ = __ret / __scaling + __param.a(); + } + } + } + else if (__urngrange < __urange) + { + // upscaling + /* + Note that every value in [0, urange] + can be written uniquely as + + (urngrange + 1) * high + low + + where + + high in [0, urange / (urngrange + 1)] + + and + + low in [0, urngrange]. + */ + __uctype __tmp; // wraparound control + while (__f != __t) + { + do + { + const __uctype __uerngrange = __urngrange + 1; + __tmp = (__uerngrange * operator() + (__urng, param_type(0, __urange / __uerngrange))); + __ret = __tmp + (__uctype(__urng()) - __urngmin); + } + while (__ret > __urange || __ret < __tmp); + *__f++ = __ret; + } + } + else + while (__f != __t) + *__f++ = __uctype(__urng()) - __urngmin + __param.a(); + } + + // operator!= and operator<< and operator>> are defined in + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif diff --git a/AH/STL/Fallback/bits/unique_ptr.h b/AH/STL/Fallback/bits/unique_ptr.h new file mode 100644 index 0000000..dcb5aad --- /dev/null +++ b/AH/STL/Fallback/bits/unique_ptr.h @@ -0,0 +1,844 @@ +// unique_ptr implementation -*- C++ -*- + +// Copyright (C) 2008-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/unique_ptr.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{memory} + */ + +#ifndef _UNIQUE_PTR_H +#define _UNIQUE_PTR_H 1 + +#include "../bits/c++config.h" +#include "../debug/assertions.h" +#include "../type_traits" +#include "../utility" +#include "../tuple" +#include "../bits/stl_function.h" +#include "../bits/functional_hash.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup pointer_abstractions + * @{ + */ + +#if _GLIBCXX_USE_DEPRECATED + template class auto_ptr; +#endif + + /// Primary template of default_delete, used by unique_ptr + template + struct default_delete + { + /// Default constructor + constexpr default_delete() noexcept = default; + + /** @brief Converting constructor. + * + * Allows conversion from a deleter for arrays of another type, @p _Up, + * only if @p _Up* is convertible to @p _Tp*. + */ + template::value>::type> + default_delete(const default_delete<_Up>&) noexcept { } + + /// Calls @c delete @p __ptr + void + operator()(_Tp* __ptr) const + { + static_assert(!is_void<_Tp>::value, + "can't delete pointer to incomplete type"); + static_assert(sizeof(_Tp)>0, + "can't delete pointer to incomplete type"); + delete __ptr; + } + }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 740 - omit specialization for array objects with a compile time length + /// Specialization for arrays, default_delete. + template + struct default_delete<_Tp[]> + { + public: + /// Default constructor + constexpr default_delete() noexcept = default; + + /** @brief Converting constructor. + * + * Allows conversion from a deleter for arrays of another type, such as + * a const-qualified version of @p _Tp. + * + * Conversions from types derived from @c _Tp are not allowed because + * it is unsafe to @c delete[] an array of derived types through a + * pointer to the base type. + */ + template::value>::type> + default_delete(const default_delete<_Up[]>&) noexcept { } + + /// Calls @c delete[] @p __ptr + template + typename enable_if::value>::type + operator()(_Up* __ptr) const + { + static_assert(sizeof(_Tp)>0, + "can't delete pointer to incomplete type"); + delete [] __ptr; + } + }; + + template + class __uniq_ptr_impl + { + template + struct _Ptr + { + using type = _Up*; + }; + + template + struct + _Ptr<_Up, _Ep, __void_t::type::pointer>> + { + using type = typename remove_reference<_Ep>::type::pointer; + }; + + public: + using _DeleterConstraint = enable_if< + __and_<__not_>, + is_default_constructible<_Dp>>::value>; + + using pointer = typename _Ptr<_Tp, _Dp>::type; + + __uniq_ptr_impl() = default; + __uniq_ptr_impl(pointer __p) : _M_t() { _M_ptr() = __p; } + + template + __uniq_ptr_impl(pointer __p, _Del&& __d) + : _M_t(__p, std::forward<_Del>(__d)) { } + + pointer& _M_ptr() { return std::get<0>(_M_t); } + pointer _M_ptr() const { return std::get<0>(_M_t); } + _Dp& _M_deleter() { return std::get<1>(_M_t); } + const _Dp& _M_deleter() const { return std::get<1>(_M_t); } + + private: + tuple _M_t; + }; + + /// 20.7.1.2 unique_ptr for single objects. + template > + class unique_ptr + { + template + using _DeleterConstraint = + typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; + + __uniq_ptr_impl<_Tp, _Dp> _M_t; + + public: + using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; + using element_type = _Tp; + using deleter_type = _Dp; + + // helper template for detecting a safe conversion from another + // unique_ptr + template + using __safe_conversion_up = __and_< + is_convertible::pointer, pointer>, + __not_>, + __or_<__and_, + is_same>, + __and_<__not_>, + is_convertible<_Ep, deleter_type>> + > + >; + + // Constructors. + + /// Default constructor, creates a unique_ptr that owns nothing. + template > + constexpr unique_ptr() noexcept + : _M_t() + { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an object of @c element_type + * + * The deleter will be value-initialized. + */ + template > + explicit + unique_ptr(pointer __p) noexcept + : _M_t(__p) + { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an object of @c element_type + * @param __d A reference to a deleter. + * + * The deleter will be initialized with @p __d + */ + unique_ptr(pointer __p, + typename conditional::value, + deleter_type, const deleter_type&>::type __d) noexcept + : _M_t(__p, __d) { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an object of @c element_type + * @param __d An rvalue reference to a deleter. + * + * The deleter will be initialized with @p std::move(__d) + */ + unique_ptr(pointer __p, + typename remove_reference::type&& __d) noexcept + : _M_t(std::move(__p), std::move(__d)) + { static_assert(!std::is_reference::value, + "rvalue deleter bound to reference"); } + + /// Creates a unique_ptr that owns nothing. + template > + constexpr unique_ptr(nullptr_t) noexcept : _M_t() { } + + // Move constructors. + + /// Move constructor. + unique_ptr(unique_ptr&& __u) noexcept + : _M_t(__u.release(), std::forward(__u.get_deleter())) { } + + /** @brief Converting constructor from another type + * + * Requires that the pointer owned by @p __u is convertible to the + * type of pointer owned by this object, @p __u does not own an array, + * and @p __u has a compatible deleter type. + */ + template, + typename conditional::value, + is_same<_Ep, _Dp>, + is_convertible<_Ep, _Dp>>::type>> + unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept + : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) + { } + +#if _GLIBCXX_USE_DEPRECATED + /// Converting constructor from @c auto_ptr + template, is_same<_Dp, default_delete<_Tp>>>> + unique_ptr(auto_ptr<_Up>&& __u) noexcept; +#endif + + /// Destructor, invokes the deleter if the stored pointer is not null. + ~unique_ptr() noexcept + { + auto& __ptr = _M_t._M_ptr(); + if (__ptr != nullptr) + get_deleter()(__ptr); + __ptr = pointer(); + } + + // Assignment. + + /** @brief Move assignment operator. + * + * @param __u The object to transfer ownership from. + * + * Invokes the deleter first if this object owns a pointer. + */ + unique_ptr& + operator=(unique_ptr&& __u) noexcept + { + reset(__u.release()); + get_deleter() = std::forward(__u.get_deleter()); + return *this; + } + + /** @brief Assignment from another type. + * + * @param __u The object to transfer ownership from, which owns a + * convertible pointer to a non-array object. + * + * Invokes the deleter first if this object owns a pointer. + */ + template + typename enable_if< __and_< + __safe_conversion_up<_Up, _Ep>, + is_assignable + >::value, + unique_ptr&>::type + operator=(unique_ptr<_Up, _Ep>&& __u) noexcept + { + reset(__u.release()); + get_deleter() = std::forward<_Ep>(__u.get_deleter()); + return *this; + } + + /// Reset the %unique_ptr to empty, invoking the deleter if necessary. + unique_ptr& + operator=(nullptr_t) noexcept + { + reset(); + return *this; + } + + // Observers. + + /// Dereference the stored pointer. + typename add_lvalue_reference::type + operator*() const + { + __glibcxx_assert(get() != pointer()); + return *get(); + } + + /// Return the stored pointer. + pointer + operator->() const noexcept + { + _GLIBCXX_DEBUG_PEDASSERT(get() != pointer()); + return get(); + } + + /// Return the stored pointer. + pointer + get() const noexcept + { return _M_t._M_ptr(); } + + /// Return a reference to the stored deleter. + deleter_type& + get_deleter() noexcept + { return _M_t._M_deleter(); } + + /// Return a reference to the stored deleter. + const deleter_type& + get_deleter() const noexcept + { return _M_t._M_deleter(); } + + /// Return @c true if the stored pointer is not null. + explicit operator bool() const noexcept + { return get() == pointer() ? false : true; } + + // Modifiers. + + /// Release ownership of any stored pointer. + pointer + release() noexcept + { + pointer __p = get(); + _M_t._M_ptr() = pointer(); + return __p; + } + + /** @brief Replace the stored pointer. + * + * @param __p The new pointer to store. + * + * The deleter will be invoked if a pointer is already owned. + */ + void + reset(pointer __p = pointer()) noexcept + { + using std::swap; + swap(_M_t._M_ptr(), __p); + if (__p != pointer()) + get_deleter()(__p); + } + + /// Exchange the pointer and deleter with another object. + void + swap(unique_ptr& __u) noexcept + { + using std::swap; + swap(_M_t, __u._M_t); + } + + // Disable copy from lvalue. + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + }; + + /// 20.7.1.3 unique_ptr for array objects with a runtime length + // [unique.ptr.runtime] + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 740 - omit specialization for array objects with a compile time length + template + class unique_ptr<_Tp[], _Dp> + { + template + using _DeleterConstraint = + typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type; + + __uniq_ptr_impl<_Tp, _Dp> _M_t; + + template + using __remove_cv = typename remove_cv<_Up>::type; + + // like is_base_of<_Tp, _Up> but false if unqualified types are the same + template + using __is_derived_Tp + = __and_< is_base_of<_Tp, _Up>, + __not_, __remove_cv<_Up>>> >; + + public: + using pointer = typename __uniq_ptr_impl<_Tp, _Dp>::pointer; + using element_type = _Tp; + using deleter_type = _Dp; + + // helper template for detecting a safe conversion from another + // unique_ptr + template, + typename _Up_element_type = typename _Up_up::element_type> + using __safe_conversion_up = __and_< + is_array<_Up>, + is_same, + is_same, + is_convertible<_Up_element_type(*)[], element_type(*)[]>, + __or_<__and_, is_same>, + __and_<__not_>, + is_convertible<_Ep, deleter_type>>> + >; + + // helper template for detecting a safe conversion from a raw pointer + template + using __safe_conversion_raw = __and_< + __or_<__or_, + is_same<_Up, nullptr_t>>, + __and_, + is_same, + is_convertible< + typename remove_pointer<_Up>::type(*)[], + element_type(*)[]> + > + > + >; + + // Constructors. + + /// Default constructor, creates a unique_ptr that owns nothing. + template > + constexpr unique_ptr() noexcept + : _M_t() + { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type + * + * The deleter will be value-initialized. + */ + template, + typename = typename enable_if< + __safe_conversion_raw<_Up>::value, bool>::type> + explicit + unique_ptr(_Up __p) noexcept + : _M_t(__p) + { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type + * @param __d A reference to a deleter. + * + * The deleter will be initialized with @p __d + */ + template::value, bool>::type> + unique_ptr(_Up __p, + typename conditional::value, + deleter_type, const deleter_type&>::type __d) noexcept + : _M_t(__p, __d) { } + + /** Takes ownership of a pointer. + * + * @param __p A pointer to an array of a type safely convertible + * to an array of @c element_type + * @param __d A reference to a deleter. + * + * The deleter will be initialized with @p std::move(__d) + */ + template::value, bool>::type> + unique_ptr(_Up __p, typename + remove_reference::type&& __d) noexcept + : _M_t(std::move(__p), std::move(__d)) + { static_assert(!is_reference::value, + "rvalue deleter bound to reference"); } + + /// Move constructor. + unique_ptr(unique_ptr&& __u) noexcept + : _M_t(__u.release(), std::forward(__u.get_deleter())) { } + + /// Creates a unique_ptr that owns nothing. + template > + constexpr unique_ptr(nullptr_t) noexcept : _M_t() { } + + template>> + unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept + : _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())) + { } + + /// Destructor, invokes the deleter if the stored pointer is not null. + ~unique_ptr() + { + auto& __ptr = _M_t._M_ptr(); + if (__ptr != nullptr) + get_deleter()(__ptr); + __ptr = pointer(); + } + + // Assignment. + + /** @brief Move assignment operator. + * + * @param __u The object to transfer ownership from. + * + * Invokes the deleter first if this object owns a pointer. + */ + unique_ptr& + operator=(unique_ptr&& __u) noexcept + { + reset(__u.release()); + get_deleter() = std::forward(__u.get_deleter()); + return *this; + } + + /** @brief Assignment from another type. + * + * @param __u The object to transfer ownership from, which owns a + * convertible pointer to an array object. + * + * Invokes the deleter first if this object owns a pointer. + */ + template + typename + enable_if<__and_<__safe_conversion_up<_Up, _Ep>, + is_assignable + >::value, + unique_ptr&>::type + operator=(unique_ptr<_Up, _Ep>&& __u) noexcept + { + reset(__u.release()); + get_deleter() = std::forward<_Ep>(__u.get_deleter()); + return *this; + } + + /// Reset the %unique_ptr to empty, invoking the deleter if necessary. + unique_ptr& + operator=(nullptr_t) noexcept + { + reset(); + return *this; + } + + // Observers. + + /// Access an element of owned array. + typename std::add_lvalue_reference::type + operator[](size_t __i) const + { + __glibcxx_assert(get() != pointer()); + return get()[__i]; + } + + /// Return the stored pointer. + pointer + get() const noexcept + { return _M_t._M_ptr(); } + + /// Return a reference to the stored deleter. + deleter_type& + get_deleter() noexcept + { return _M_t._M_deleter(); } + + /// Return a reference to the stored deleter. + const deleter_type& + get_deleter() const noexcept + { return _M_t._M_deleter(); } + + /// Return @c true if the stored pointer is not null. + explicit operator bool() const noexcept + { return get() == pointer() ? false : true; } + + // Modifiers. + + /// Release ownership of any stored pointer. + pointer + release() noexcept + { + pointer __p = get(); + _M_t._M_ptr() = pointer(); + return __p; + } + + /** @brief Replace the stored pointer. + * + * @param __p The new pointer to store. + * + * The deleter will be invoked if a pointer is already owned. + */ + template , + __and_, + is_pointer<_Up>, + is_convertible< + typename remove_pointer<_Up>::type(*)[], + element_type(*)[] + > + > + > + >> + void + reset(_Up __p) noexcept + { + pointer __ptr = __p; + using std::swap; + swap(_M_t._M_ptr(), __ptr); + if (__ptr != nullptr) + get_deleter()(__ptr); + } + + void reset(nullptr_t = nullptr) noexcept + { + reset(pointer()); + } + + /// Exchange the pointer and deleter with another object. + void + swap(unique_ptr& __u) noexcept + { + using std::swap; + swap(_M_t, __u._M_t); + } + + // Disable copy from lvalue. + unique_ptr(const unique_ptr&) = delete; + unique_ptr& operator=(const unique_ptr&) = delete; + }; + + template + inline +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // Constrained free swap overload, see p0185r1 + typename enable_if<__is_swappable<_Dp>::value>::type +#else + void +#endif + swap(unique_ptr<_Tp, _Dp>& __x, + unique_ptr<_Tp, _Dp>& __y) noexcept + { __x.swap(__y); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + template + typename enable_if::value>::type + swap(unique_ptr<_Tp, _Dp>&, + unique_ptr<_Tp, _Dp>&) = delete; +#endif + + template + inline bool + operator==(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return __x.get() == __y.get(); } + + template + inline bool + operator==(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept + { return !__x; } + + template + inline bool + operator==(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept + { return !__x; } + + template + inline bool + operator!=(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return __x.get() != __y.get(); } + + template + inline bool + operator!=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) noexcept + { return (bool)__x; } + + template + inline bool + operator!=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) noexcept + { return (bool)__x; } + + template + inline bool + operator<(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { + typedef typename + std::common_type::pointer, + typename unique_ptr<_Up, _Ep>::pointer>::type _CT; + return std::less<_CT>()(__x.get(), __y.get()); + } + + template + inline bool + operator<(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) + { return std::less::pointer>()(__x.get(), + nullptr); } + + template + inline bool + operator<(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) + { return std::less::pointer>()(nullptr, + __x.get()); } + + template + inline bool + operator<=(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return !(__y < __x); } + + template + inline bool + operator<=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) + { return !(nullptr < __x); } + + template + inline bool + operator<=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) + { return !(__x < nullptr); } + + template + inline bool + operator>(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return (__y < __x); } + + template + inline bool + operator>(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) + { return std::less::pointer>()(nullptr, + __x.get()); } + + template + inline bool + operator>(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) + { return std::less::pointer>()(__x.get(), + nullptr); } + + template + inline bool + operator>=(const unique_ptr<_Tp, _Dp>& __x, + const unique_ptr<_Up, _Ep>& __y) + { return !(__x < __y); } + + template + inline bool + operator>=(const unique_ptr<_Tp, _Dp>& __x, nullptr_t) + { return !(__x < nullptr); } + + template + inline bool + operator>=(nullptr_t, const unique_ptr<_Tp, _Dp>& __x) + { return !(nullptr < __x); } + + /// std::hash specialization for unique_ptr. + template + struct hash> + : public __hash_base>, + private __poison_hash::pointer> + { + size_t + operator()(const unique_ptr<_Tp, _Dp>& __u) const noexcept + { + typedef unique_ptr<_Tp, _Dp> _UP; + return std::hash()(__u.get()); + } + }; + +#if __cplusplus > 201103L + +#define __cpp_lib_make_unique 201304 + + template + struct _MakeUniq + { typedef unique_ptr<_Tp> __single_object; }; + + template + struct _MakeUniq<_Tp[]> + { typedef unique_ptr<_Tp[]> __array; }; + + template + struct _MakeUniq<_Tp[_Bound]> + { struct __invalid_type { }; }; + + /// std::make_unique for single objects + template + inline typename _MakeUniq<_Tp>::__single_object + make_unique(_Args&&... __args) + { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } + + /// std::make_unique for arrays of unknown bound + template + inline typename _MakeUniq<_Tp>::__array + make_unique(size_t __num) + { return unique_ptr<_Tp>(new remove_extent_t<_Tp>[__num]()); } + + /// Disable std::make_unique for arrays of known bound + template + inline typename _MakeUniq<_Tp>::__invalid_type + make_unique(_Args&&...) = delete; +#endif + + // @} group pointer_abstractions + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _UNIQUE_PTR_H */ diff --git a/AH/STL/Fallback/bits/uses_allocator.h b/AH/STL/Fallback/bits/uses_allocator.h new file mode 100644 index 0000000..701b9de --- /dev/null +++ b/AH/STL/Fallback/bits/uses_allocator.h @@ -0,0 +1,186 @@ +// Uses-allocator Construction -*- C++ -*- + +// Copyright (C) 2010-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +#ifndef _USES_ALLOCATOR_H +#define _USES_ALLOCATOR_H 1 + +#if __cplusplus < 201103L +# include "../bits/c++0x_warning.h" +#else + +#include "../type_traits" +#include "../bits/move.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + struct __erased_type { }; + + template + using __is_erased_or_convertible + = __or_, is_convertible<_Alloc, _Tp>>; + + /// [allocator.tag] + struct allocator_arg_t { explicit allocator_arg_t() = default; }; + + _GLIBCXX17_INLINE constexpr allocator_arg_t allocator_arg = + allocator_arg_t(); + + template> + struct __uses_allocator_helper + : false_type { }; + + template + struct __uses_allocator_helper<_Tp, _Alloc, + __void_t> + : __is_erased_or_convertible<_Alloc, typename _Tp::allocator_type>::type + { }; + + /// [allocator.uses.trait] + template + struct uses_allocator + : __uses_allocator_helper<_Tp, _Alloc>::type + { }; + + struct __uses_alloc_base { }; + + struct __uses_alloc0 : __uses_alloc_base + { + struct _Sink { void operator=(const void*) { } } _M_a; + }; + + template + struct __uses_alloc1 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc2 : __uses_alloc_base { const _Alloc* _M_a; }; + + template + struct __uses_alloc; + + template + struct __uses_alloc + : conditional< + is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value, + __uses_alloc1<_Alloc>, + __uses_alloc2<_Alloc>>::type + { + static_assert(__or_< + is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>, + is_constructible<_Tp, _Args..., _Alloc>>::value, "construction with" + " an allocator must be possible if uses_allocator is true"); + }; + + template + struct __uses_alloc + : __uses_alloc0 { }; + + template + using __uses_alloc_t = + __uses_alloc::value, _Tp, _Alloc, _Args...>; + + template + inline __uses_alloc_t<_Tp, _Alloc, _Args...> + __use_alloc(const _Alloc& __a) + { + __uses_alloc_t<_Tp, _Alloc, _Args...> __ret; + __ret._M_a = std::__addressof(__a); + return __ret; + } + + template + void + __use_alloc(const _Alloc&&) = delete; + +#if __cplusplus > 201402L + template + inline constexpr bool uses_allocator_v = + uses_allocator<_Tp, _Alloc>::value; +#endif // C++17 + + template class _Predicate, + typename _Tp, typename _Alloc, typename... _Args> + struct __is_uses_allocator_predicate + : conditional::value, + __or_<_Predicate<_Tp, allocator_arg_t, _Alloc, _Args...>, + _Predicate<_Tp, _Args..., _Alloc>>, + _Predicate<_Tp, _Args...>>::type { }; + + template + struct __is_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool __is_uses_allocator_constructible_v = + __is_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + struct __is_nothrow_uses_allocator_constructible + : __is_uses_allocator_predicate + { }; + + +#if __cplusplus >= 201402L + template + _GLIBCXX17_INLINE constexpr bool + __is_nothrow_uses_allocator_constructible_v = + __is_nothrow_uses_allocator_constructible<_Tp, _Alloc, _Args...>::value; +#endif // C++14 + + template + void __uses_allocator_construct_impl(__uses_alloc0 __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)...); } + + template + void __uses_allocator_construct_impl(__uses_alloc1<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { + ::new ((void*)__ptr) _Tp(allocator_arg, *__a._M_a, + std::forward<_Args>(__args)...); + } + + template + void __uses_allocator_construct_impl(__uses_alloc2<_Alloc> __a, _Tp* __ptr, + _Args&&... __args) + { ::new ((void*)__ptr) _Tp(std::forward<_Args>(__args)..., *__a._M_a); } + + template + void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, + _Args&&... __args) + { + __uses_allocator_construct_impl(__use_alloc<_Tp, _Alloc, _Args...>(__a), + __ptr, std::forward<_Args>(__args)...); + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif +#endif diff --git a/AH/STL/Fallback/bits/vector.tcc b/AH/STL/Fallback/bits/vector.tcc new file mode 100644 index 0000000..a2cc0cb --- /dev/null +++ b/AH/STL/Fallback/bits/vector.tcc @@ -0,0 +1,905 @@ +// Vector implementation (out of line) -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file bits/vector.tcc + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{vector} + */ + +#ifndef _VECTOR_TCC +#define _VECTOR_TCC 1 + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + template + void + vector<_Tp, _Alloc>:: + reserve(size_type __n) + { + if (__n > this->max_size()) + __throw_length_error(__N("vector::reserve")); + if (this->capacity() < __n) + { + const size_type __old_size = size(); + pointer __tmp = _M_allocate_and_copy(__n, + _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_start), + _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(this->_M_impl._M_finish)); + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __tmp; + this->_M_impl._M_finish = __tmp + __old_size; + this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n; + } + } + +#if __cplusplus >= 201103L + template + template +#if __cplusplus > 201402L + typename vector<_Tp, _Alloc>::reference +#else + void +#endif + vector<_Tp, _Alloc>:: + emplace_back(_Args&&... __args) + { + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + std::forward<_Args>(__args)...); + ++this->_M_impl._M_finish; + } + else + _M_realloc_insert(end(), std::forward<_Args>(__args)...); +#if __cplusplus > 201402L + return back(); +#endif + } +#endif + + template + typename vector<_Tp, _Alloc>::iterator + vector<_Tp, _Alloc>:: +#if __cplusplus >= 201103L + insert(const_iterator __position, const value_type& __x) +#else + insert(iterator __position, const value_type& __x) +#endif + { + const size_type __n = __position - begin(); + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) + if (__position == end()) + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + __x); + ++this->_M_impl._M_finish; + } + else + { +#if __cplusplus >= 201103L + const auto __pos = begin() + (__position - cbegin()); + // __x could be an existing element of this vector, so make a + // copy of it before _M_insert_aux moves elements around. + _Temporary_value __x_copy(this, __x); + _M_insert_aux(__pos, std::move(__x_copy._M_val())); +#else + _M_insert_aux(__position, __x); +#endif + } + else +#if __cplusplus >= 201103L + _M_realloc_insert(begin() + (__position - cbegin()), __x); +#else + _M_realloc_insert(__position, __x); +#endif + + return iterator(this->_M_impl._M_start + __n); + } + + template + typename vector<_Tp, _Alloc>::iterator + vector<_Tp, _Alloc>:: + _M_erase(iterator __position) + { + if (__position + 1 != end()) + _GLIBCXX_MOVE3(__position + 1, end(), __position); + --this->_M_impl._M_finish; + _Alloc_traits::destroy(this->_M_impl, this->_M_impl._M_finish); + return __position; + } + + template + typename vector<_Tp, _Alloc>::iterator + vector<_Tp, _Alloc>:: + _M_erase(iterator __first, iterator __last) + { + if (__first != __last) + { + if (__last != end()) + _GLIBCXX_MOVE3(__last, end(), __first); + _M_erase_at_end(__first.base() + (end() - __last)); + } + return __first; + } + + template + vector<_Tp, _Alloc>& + vector<_Tp, _Alloc>:: + operator=(const vector<_Tp, _Alloc>& __x) + { + if (&__x != this) + { +#if __cplusplus >= 201103L + if (_Alloc_traits::_S_propagate_on_copy_assign()) + { + if (!_Alloc_traits::_S_always_equal() + && _M_get_Tp_allocator() != __x._M_get_Tp_allocator()) + { + // replacement allocator cannot free existing storage + this->clear(); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = nullptr; + this->_M_impl._M_finish = nullptr; + this->_M_impl._M_end_of_storage = nullptr; + } + std::__alloc_on_copy(_M_get_Tp_allocator(), + __x._M_get_Tp_allocator()); + } +#endif + const size_type __xlen = __x.size(); + if (__xlen > capacity()) + { + pointer __tmp = _M_allocate_and_copy(__xlen, __x.begin(), + __x.end()); + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __tmp; + this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __xlen; + } + else if (size() >= __xlen) + { + std::_Destroy(std::copy(__x.begin(), __x.end(), begin()), + end(), _M_get_Tp_allocator()); + } + else + { + std::copy(__x._M_impl._M_start, __x._M_impl._M_start + size(), + this->_M_impl._M_start); + std::__uninitialized_copy_a(__x._M_impl._M_start + size(), + __x._M_impl._M_finish, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + } + this->_M_impl._M_finish = this->_M_impl._M_start + __xlen; + } + return *this; + } + + template + void + vector<_Tp, _Alloc>:: + _M_fill_assign(size_t __n, const value_type& __val) + { + if (__n > capacity()) + { + vector __tmp(__n, __val, _M_get_Tp_allocator()); + __tmp._M_impl._M_swap_data(this->_M_impl); + } + else if (__n > size()) + { + std::fill(begin(), end(), __val); + this->_M_impl._M_finish = + std::__uninitialized_fill_n_a(this->_M_impl._M_finish, + __n - size(), __val, + _M_get_Tp_allocator()); + } + else + _M_erase_at_end(std::fill_n(this->_M_impl._M_start, __n, __val)); + } + + template + template + void + vector<_Tp, _Alloc>:: + _M_assign_aux(_InputIterator __first, _InputIterator __last, + std::input_iterator_tag) + { + pointer __cur(this->_M_impl._M_start); + for (; __first != __last && __cur != this->_M_impl._M_finish; + ++__cur, ++__first) + *__cur = *__first; + if (__first == __last) + _M_erase_at_end(__cur); + else + _M_range_insert(end(), __first, __last, + std::__iterator_category(__first)); + } + + template + template + void + vector<_Tp, _Alloc>:: + _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, + std::forward_iterator_tag) + { + const size_type __len = std::distance(__first, __last); + + if (__len > capacity()) + { + pointer __tmp(_M_allocate_and_copy(__len, __first, __last)); + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __tmp; + this->_M_impl._M_finish = this->_M_impl._M_start + __len; + this->_M_impl._M_end_of_storage = this->_M_impl._M_finish; + } + else if (size() >= __len) + _M_erase_at_end(std::copy(__first, __last, this->_M_impl._M_start)); + else + { + _ForwardIterator __mid = __first; + std::advance(__mid, size()); + std::copy(__first, __mid, this->_M_impl._M_start); + this->_M_impl._M_finish = + std::__uninitialized_copy_a(__mid, __last, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + } + } + +#if __cplusplus >= 201103L + template + auto + vector<_Tp, _Alloc>:: + _M_insert_rval(const_iterator __position, value_type&& __v) -> iterator + { + const auto __n = __position - cbegin(); + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) + if (__position == cend()) + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + std::move(__v)); + ++this->_M_impl._M_finish; + } + else + _M_insert_aux(begin() + __n, std::move(__v)); + else + _M_realloc_insert(begin() + __n, std::move(__v)); + + return iterator(this->_M_impl._M_start + __n); + } + + template + template + auto + vector<_Tp, _Alloc>:: + _M_emplace_aux(const_iterator __position, _Args&&... __args) + -> iterator + { + const auto __n = __position - cbegin(); + if (this->_M_impl._M_finish != this->_M_impl._M_end_of_storage) + if (__position == cend()) + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + std::forward<_Args>(__args)...); + ++this->_M_impl._M_finish; + } + else + { + // We need to construct a temporary because something in __args... + // could alias one of the elements of the container and so we + // need to use it before _M_insert_aux moves elements around. + _Temporary_value __tmp(this, std::forward<_Args>(__args)...); + _M_insert_aux(begin() + __n, std::move(__tmp._M_val())); + } + else + _M_realloc_insert(begin() + __n, std::forward<_Args>(__args)...); + + return iterator(this->_M_impl._M_start + __n); + } + + template + template + void + vector<_Tp, _Alloc>:: + _M_insert_aux(iterator __position, _Arg&& __arg) +#else + template + void + vector<_Tp, _Alloc>:: + _M_insert_aux(iterator __position, const _Tp& __x) +#endif + { + _Alloc_traits::construct(this->_M_impl, this->_M_impl._M_finish, + _GLIBCXX_MOVE(*(this->_M_impl._M_finish + - 1))); + ++this->_M_impl._M_finish; +#if __cplusplus < 201103L + _Tp __x_copy = __x; +#endif + _GLIBCXX_MOVE_BACKWARD3(__position.base(), + this->_M_impl._M_finish - 2, + this->_M_impl._M_finish - 1); +#if __cplusplus < 201103L + *__position = __x_copy; +#else + *__position = std::forward<_Arg>(__arg); +#endif + } + +#if __cplusplus >= 201103L + template + template + void + vector<_Tp, _Alloc>:: + _M_realloc_insert(iterator __position, _Args&&... __args) +#else + template + void + vector<_Tp, _Alloc>:: + _M_realloc_insert(iterator __position, const _Tp& __x) +#endif + { + const size_type __len = + _M_check_len(size_type(1), "vector::_M_realloc_insert"); + const size_type __elems_before = __position - begin(); + pointer __new_start(this->_M_allocate(__len)); + pointer __new_finish(__new_start); + __try + { + // The order of the three operations is dictated by the C++11 + // case, where the moves could alter a new element belonging + // to the existing vector. This is an issue only for callers + // taking the element by lvalue ref (see last bullet of C++11 + // [res.on.arguments]). + _Alloc_traits::construct(this->_M_impl, + __new_start + __elems_before, +#if __cplusplus >= 201103L + std::forward<_Args>(__args)...); +#else + __x); +#endif + __new_finish = pointer(); + + __new_finish + = std::__uninitialized_move_if_noexcept_a + (this->_M_impl._M_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + + ++__new_finish; + + __new_finish + = std::__uninitialized_move_if_noexcept_a + (__position.base(), this->_M_impl._M_finish, + __new_finish, _M_get_Tp_allocator()); + } + __catch(...) + { + if (!__new_finish) + _Alloc_traits::destroy(this->_M_impl, + __new_start + __elems_before); + else + std::_Destroy(__new_start, __new_finish, _M_get_Tp_allocator()); + _M_deallocate(__new_start, __len); + __throw_exception_again; + } + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + + template + void + vector<_Tp, _Alloc>:: + _M_fill_insert(iterator __position, size_type __n, const value_type& __x) + { + if (__n != 0) + { + if (size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_finish) >= __n) + { +#if __cplusplus < 201103L + value_type __x_copy = __x; +#else + _Temporary_value __tmp(this, __x); + value_type& __x_copy = __tmp._M_val(); +#endif + const size_type __elems_after = end() - __position; + pointer __old_finish(this->_M_impl._M_finish); + if (__elems_after > __n) + { + std::__uninitialized_move_a(this->_M_impl._M_finish - __n, + this->_M_impl._M_finish, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + this->_M_impl._M_finish += __n; + _GLIBCXX_MOVE_BACKWARD3(__position.base(), + __old_finish - __n, __old_finish); + std::fill(__position.base(), __position.base() + __n, + __x_copy); + } + else + { + this->_M_impl._M_finish = + std::__uninitialized_fill_n_a(this->_M_impl._M_finish, + __n - __elems_after, + __x_copy, + _M_get_Tp_allocator()); + std::__uninitialized_move_a(__position.base(), __old_finish, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + this->_M_impl._M_finish += __elems_after; + std::fill(__position.base(), __old_finish, __x_copy); + } + } + else + { + const size_type __len = + _M_check_len(__n, "vector::_M_fill_insert"); + const size_type __elems_before = __position - begin(); + pointer __new_start(this->_M_allocate(__len)); + pointer __new_finish(__new_start); + __try + { + // See _M_realloc_insert above. + std::__uninitialized_fill_n_a(__new_start + __elems_before, + __n, __x, + _M_get_Tp_allocator()); + __new_finish = pointer(); + + __new_finish + = std::__uninitialized_move_if_noexcept_a + (this->_M_impl._M_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + + __new_finish += __n; + + __new_finish + = std::__uninitialized_move_if_noexcept_a + (__position.base(), this->_M_impl._M_finish, + __new_finish, _M_get_Tp_allocator()); + } + __catch(...) + { + if (!__new_finish) + std::_Destroy(__new_start + __elems_before, + __new_start + __elems_before + __n, + _M_get_Tp_allocator()); + else + std::_Destroy(__new_start, __new_finish, + _M_get_Tp_allocator()); + _M_deallocate(__new_start, __len); + __throw_exception_again; + } + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + } + } + +#if __cplusplus >= 201103L + template + void + vector<_Tp, _Alloc>:: + _M_default_append(size_type __n) + { + if (__n != 0) + { + if (size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_finish) >= __n) + { + this->_M_impl._M_finish = + std::__uninitialized_default_n_a(this->_M_impl._M_finish, + __n, _M_get_Tp_allocator()); + } + else + { + const size_type __len = + _M_check_len(__n, "vector::_M_default_append"); + const size_type __size = this->size(); + pointer __new_start(this->_M_allocate(__len)); + pointer __destroy_from = pointer(); + __try + { + std::__uninitialized_default_n_a(__new_start + __size, + __n, _M_get_Tp_allocator()); + __destroy_from = __new_start + __size; + std::__uninitialized_move_if_noexcept_a( + this->_M_impl._M_start, this->_M_impl._M_finish, + __new_start, _M_get_Tp_allocator()); + } + __catch(...) + { + if (__destroy_from) + std::_Destroy(__destroy_from, __destroy_from + __n, + _M_get_Tp_allocator()); + _M_deallocate(__new_start, __len); + __throw_exception_again; + } + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_start + __size + __n; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + } + } + + template + bool + vector<_Tp, _Alloc>:: + _M_shrink_to_fit() + { + if (capacity() == size()) + return false; + return std::__shrink_to_fit_aux::_S_do_it(*this); + } +#endif + + template + template + void + vector<_Tp, _Alloc>:: + _M_range_insert(iterator __pos, _InputIterator __first, + _InputIterator __last, std::input_iterator_tag) + { + for (; __first != __last; ++__first) + { + __pos = insert(__pos, *__first); + ++__pos; + } + } + + template + template + void + vector<_Tp, _Alloc>:: + _M_range_insert(iterator __position, _ForwardIterator __first, + _ForwardIterator __last, std::forward_iterator_tag) + { + if (__first != __last) + { + const size_type __n = std::distance(__first, __last); + if (size_type(this->_M_impl._M_end_of_storage + - this->_M_impl._M_finish) >= __n) + { + const size_type __elems_after = end() - __position; + pointer __old_finish(this->_M_impl._M_finish); + if (__elems_after > __n) + { + std::__uninitialized_move_a(this->_M_impl._M_finish - __n, + this->_M_impl._M_finish, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + this->_M_impl._M_finish += __n; + _GLIBCXX_MOVE_BACKWARD3(__position.base(), + __old_finish - __n, __old_finish); + std::copy(__first, __last, __position); + } + else + { + _ForwardIterator __mid = __first; + std::advance(__mid, __elems_after); + std::__uninitialized_copy_a(__mid, __last, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + this->_M_impl._M_finish += __n - __elems_after; + std::__uninitialized_move_a(__position.base(), + __old_finish, + this->_M_impl._M_finish, + _M_get_Tp_allocator()); + this->_M_impl._M_finish += __elems_after; + std::copy(__first, __mid, __position); + } + } + else + { + const size_type __len = + _M_check_len(__n, "vector::_M_range_insert"); + pointer __new_start(this->_M_allocate(__len)); + pointer __new_finish(__new_start); + __try + { + __new_finish + = std::__uninitialized_move_if_noexcept_a + (this->_M_impl._M_start, __position.base(), + __new_start, _M_get_Tp_allocator()); + __new_finish + = std::__uninitialized_copy_a(__first, __last, + __new_finish, + _M_get_Tp_allocator()); + __new_finish + = std::__uninitialized_move_if_noexcept_a + (__position.base(), this->_M_impl._M_finish, + __new_finish, _M_get_Tp_allocator()); + } + __catch(...) + { + std::_Destroy(__new_start, __new_finish, + _M_get_Tp_allocator()); + _M_deallocate(__new_start, __len); + __throw_exception_again; + } + std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, + _M_get_Tp_allocator()); + _M_deallocate(this->_M_impl._M_start, + this->_M_impl._M_end_of_storage + - this->_M_impl._M_start); + this->_M_impl._M_start = __new_start; + this->_M_impl._M_finish = __new_finish; + this->_M_impl._M_end_of_storage = __new_start + __len; + } + } + } + + + // vector + template + void + vector:: + _M_reallocate(size_type __n) + { + _Bit_pointer __q = this->_M_allocate(__n); + iterator __start(std::__addressof(*__q), 0); + iterator __finish(_M_copy_aligned(begin(), end(), __start)); + this->_M_deallocate(); + this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; + this->_M_impl._M_end_of_storage = __q + _S_nword(__n); + } + + template + void + vector:: + _M_fill_insert(iterator __position, size_type __n, bool __x) + { + if (__n == 0) + return; + if (capacity() - size() >= __n) + { + std::copy_backward(__position, end(), + this->_M_impl._M_finish + difference_type(__n)); + std::fill(__position, __position + difference_type(__n), __x); + this->_M_impl._M_finish += difference_type(__n); + } + else + { + const size_type __len = + _M_check_len(__n, "vector::_M_fill_insert"); + _Bit_pointer __q = this->_M_allocate(__len); + iterator __start(std::__addressof(*__q), 0); + iterator __i = _M_copy_aligned(begin(), __position, __start); + std::fill(__i, __i + difference_type(__n), __x); + iterator __finish = std::copy(__position, end(), + __i + difference_type(__n)); + this->_M_deallocate(); + this->_M_impl._M_end_of_storage = __q + _S_nword(__len); + this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; + } + } + + template + template + void + vector:: + _M_insert_range(iterator __position, _ForwardIterator __first, + _ForwardIterator __last, std::forward_iterator_tag) + { + if (__first != __last) + { + size_type __n = std::distance(__first, __last); + if (capacity() - size() >= __n) + { + std::copy_backward(__position, end(), + this->_M_impl._M_finish + + difference_type(__n)); + std::copy(__first, __last, __position); + this->_M_impl._M_finish += difference_type(__n); + } + else + { + const size_type __len = + _M_check_len(__n, "vector::_M_insert_range"); + _Bit_pointer __q = this->_M_allocate(__len); + iterator __start(std::__addressof(*__q), 0); + iterator __i = _M_copy_aligned(begin(), __position, __start); + __i = std::copy(__first, __last, __i); + iterator __finish = std::copy(__position, end(), __i); + this->_M_deallocate(); + this->_M_impl._M_end_of_storage = __q + _S_nword(__len); + this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; + } + } + } + + template + void + vector:: + _M_insert_aux(iterator __position, bool __x) + { + if (this->_M_impl._M_finish._M_p != this->_M_impl._M_end_addr()) + { + std::copy_backward(__position, this->_M_impl._M_finish, + this->_M_impl._M_finish + 1); + *__position = __x; + ++this->_M_impl._M_finish; + } + else + { + const size_type __len = + _M_check_len(size_type(1), "vector::_M_insert_aux"); + _Bit_pointer __q = this->_M_allocate(__len); + iterator __start(std::__addressof(*__q), 0); + iterator __i = _M_copy_aligned(begin(), __position, __start); + *__i++ = __x; + iterator __finish = std::copy(__position, end(), __i); + this->_M_deallocate(); + this->_M_impl._M_end_of_storage = __q + _S_nword(__len); + this->_M_impl._M_start = __start; + this->_M_impl._M_finish = __finish; + } + } + + template + typename vector::iterator + vector:: + _M_erase(iterator __position) + { + if (__position + 1 != end()) + std::copy(__position + 1, end(), __position); + --this->_M_impl._M_finish; + return __position; + } + + template + typename vector::iterator + vector:: + _M_erase(iterator __first, iterator __last) + { + if (__first != __last) + _M_erase_at_end(std::copy(__last, end(), __first)); + return __first; + } + +#if __cplusplus >= 201103L + template + bool + vector:: + _M_shrink_to_fit() + { + if (capacity() - size() < int(_S_word_bit)) + return false; + __try + { + _M_reallocate(size()); + return true; + } + __catch(...) + { return false; } + } +#endif + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +#if __cplusplus >= 201103L + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + template + size_t + hash<_GLIBCXX_STD_C::vector>:: + operator()(const _GLIBCXX_STD_C::vector& __b) const noexcept + { + size_t __hash = 0; + using _GLIBCXX_STD_C::_S_word_bit; + using _GLIBCXX_STD_C::_Bit_type; + + const size_t __words = __b.size() / _S_word_bit; + if (__words) + { + const size_t __clength = __words * sizeof(_Bit_type); + __hash = std::_Hash_impl::hash(__b._M_impl._M_start._M_p, __clength); + } + + const size_t __extrabits = __b.size() % _S_word_bit; + if (__extrabits) + { + _Bit_type __hiword = *__b._M_impl._M_finish._M_p; + __hiword &= ~((~static_cast<_Bit_type>(0)) << __extrabits); + + const size_t __clength + = (__extrabits + __CHAR_BIT__ - 1) / __CHAR_BIT__; + if (__words) + __hash = std::_Hash_impl::hash(&__hiword, __clength, __hash); + else + __hash = std::_Hash_impl::hash(&__hiword, __clength); + } + + return __hash; + } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++11 + +#endif /* _VECTOR_TCC */ diff --git a/AH/STL/Fallback/bitset b/AH/STL/Fallback/bitset new file mode 100644 index 0000000..c260e38 --- /dev/null +++ b/AH/STL/Fallback/bitset @@ -0,0 +1,1626 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * Copyright (c) 1998 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/bitset + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_BITSET +#define _GLIBCXX_BITSET 1 + +#pragma GCC system_header + +// #include +#include "bits/functexcept.h" // For invalid_argument, out_of_range, + // overflow_error +// #include +// #include +#include "algorithm" + +#define _GLIBCXX_BITSET_BITS_PER_WORD (__CHAR_BIT__ * __SIZEOF_LONG__) +#define _GLIBCXX_BITSET_WORDS(__n) \ + ((__n) / _GLIBCXX_BITSET_BITS_PER_WORD + \ + ((__n) % _GLIBCXX_BITSET_BITS_PER_WORD == 0 ? 0 : 1)) + +#define _GLIBCXX_BITSET_BITS_PER_ULL (__CHAR_BIT__ * __SIZEOF_LONG_LONG__) + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + + /** + * Base class, general case. It is a class invariant that _Nw will be + * nonnegative. + * + * See documentation for bitset. + */ + template + struct _Base_bitset + { + typedef unsigned long _WordT; + + /// 0 is the least significant word. + _WordT _M_w[_Nw]; + + _GLIBCXX_CONSTEXPR _Base_bitset() _GLIBCXX_NOEXCEPT + : _M_w() { } + +#if __cplusplus >= 201103L + constexpr _Base_bitset(unsigned long long __val) noexcept + : _M_w{ _WordT(__val) +#if __SIZEOF_LONG_LONG__ > __SIZEOF_LONG__ + , _WordT(__val >> _GLIBCXX_BITSET_BITS_PER_WORD) +#endif + } { } +#else + _Base_bitset(unsigned long __val) + : _M_w() + { _M_w[0] = __val; } +#endif + + static _GLIBCXX_CONSTEXPR size_t + _S_whichword(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos / _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbyte(size_t __pos) _GLIBCXX_NOEXCEPT + { return (__pos % _GLIBCXX_BITSET_BITS_PER_WORD) / __CHAR_BIT__; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos % _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR _WordT + _S_maskbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); } + + _WordT& + _M_getword(size_t __pos) _GLIBCXX_NOEXCEPT + { return _M_w[_S_whichword(__pos)]; } + + _GLIBCXX_CONSTEXPR _WordT + _M_getword(size_t __pos) const _GLIBCXX_NOEXCEPT + { return _M_w[_S_whichword(__pos)]; } + +#if __cplusplus >= 201103L + const _WordT* + _M_getdata() const noexcept + { return _M_w; } +#endif + + _WordT& + _M_hiword() _GLIBCXX_NOEXCEPT + { return _M_w[_Nw - 1]; } + + _GLIBCXX_CONSTEXPR _WordT + _M_hiword() const _GLIBCXX_NOEXCEPT + { return _M_w[_Nw - 1]; } + + void + _M_do_and(const _Base_bitset<_Nw>& __x) _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + _M_w[__i] &= __x._M_w[__i]; + } + + void + _M_do_or(const _Base_bitset<_Nw>& __x) _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + _M_w[__i] |= __x._M_w[__i]; + } + + void + _M_do_xor(const _Base_bitset<_Nw>& __x) _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + _M_w[__i] ^= __x._M_w[__i]; + } + + void + _M_do_left_shift(size_t __shift) _GLIBCXX_NOEXCEPT; + + void + _M_do_right_shift(size_t __shift) _GLIBCXX_NOEXCEPT; + + void + _M_do_flip() _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + _M_w[__i] = ~_M_w[__i]; + } + + void + _M_do_set() _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + _M_w[__i] = ~static_cast<_WordT>(0); + } + + void + _M_do_reset() _GLIBCXX_NOEXCEPT + { __builtin_memset(_M_w, 0, _Nw * sizeof(_WordT)); } + + bool + _M_is_equal(const _Base_bitset<_Nw>& __x) const _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; ++__i) + if (_M_w[__i] != __x._M_w[__i]) + return false; + return true; + } + + template + bool + _M_are_all() const _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw - 1; __i++) + if (_M_w[__i] != ~static_cast<_WordT>(0)) + return false; + return _M_hiword() == (~static_cast<_WordT>(0) + >> (_Nw * _GLIBCXX_BITSET_BITS_PER_WORD + - _Nb)); + } + + bool + _M_is_any() const _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + if (_M_w[__i] != static_cast<_WordT>(0)) + return true; + return false; + } + + size_t + _M_do_count() const _GLIBCXX_NOEXCEPT + { + size_t __result = 0; + for (size_t __i = 0; __i < _Nw; __i++) + __result += __builtin_popcountl(_M_w[__i]); + return __result; + } + + unsigned long + _M_do_to_ulong() const; + +#if __cplusplus >= 201103L + unsigned long long + _M_do_to_ullong() const; +#endif + + // find first "on" bit + size_t + _M_do_find_first(size_t) const _GLIBCXX_NOEXCEPT; + + // find the next "on" bit that follows "prev" + size_t + _M_do_find_next(size_t, size_t) const _GLIBCXX_NOEXCEPT; + }; + + // Definitions of non-inline functions from _Base_bitset. + template + void + _Base_bitset<_Nw>::_M_do_left_shift(size_t __shift) _GLIBCXX_NOEXCEPT + { + if (__builtin_expect(__shift != 0, 1)) + { + const size_t __wshift = __shift / _GLIBCXX_BITSET_BITS_PER_WORD; + const size_t __offset = __shift % _GLIBCXX_BITSET_BITS_PER_WORD; + + if (__offset == 0) + for (size_t __n = _Nw - 1; __n >= __wshift; --__n) + _M_w[__n] = _M_w[__n - __wshift]; + else + { + const size_t __sub_offset = (_GLIBCXX_BITSET_BITS_PER_WORD + - __offset); + for (size_t __n = _Nw - 1; __n > __wshift; --__n) + _M_w[__n] = ((_M_w[__n - __wshift] << __offset) + | (_M_w[__n - __wshift - 1] >> __sub_offset)); + _M_w[__wshift] = _M_w[0] << __offset; + } + + std::fill(_M_w + 0, _M_w + __wshift, static_cast<_WordT>(0)); + } + } + + template + void + _Base_bitset<_Nw>::_M_do_right_shift(size_t __shift) _GLIBCXX_NOEXCEPT + { + if (__builtin_expect(__shift != 0, 1)) + { + const size_t __wshift = __shift / _GLIBCXX_BITSET_BITS_PER_WORD; + const size_t __offset = __shift % _GLIBCXX_BITSET_BITS_PER_WORD; + const size_t __limit = _Nw - __wshift - 1; + + if (__offset == 0) + for (size_t __n = 0; __n <= __limit; ++__n) + _M_w[__n] = _M_w[__n + __wshift]; + else + { + const size_t __sub_offset = (_GLIBCXX_BITSET_BITS_PER_WORD + - __offset); + for (size_t __n = 0; __n < __limit; ++__n) + _M_w[__n] = ((_M_w[__n + __wshift] >> __offset) + | (_M_w[__n + __wshift + 1] << __sub_offset)); + _M_w[__limit] = _M_w[_Nw-1] >> __offset; + } + + std::fill(_M_w + __limit + 1, _M_w + _Nw, static_cast<_WordT>(0)); + } + } + + template + unsigned long + _Base_bitset<_Nw>::_M_do_to_ulong() const + { + for (size_t __i = 1; __i < _Nw; ++__i) + if (_M_w[__i]) + __throw_overflow_error(__N("_Base_bitset::_M_do_to_ulong")); + return _M_w[0]; + } + +#if __cplusplus >= 201103L + template + unsigned long long + _Base_bitset<_Nw>::_M_do_to_ullong() const + { + const bool __dw = sizeof(unsigned long long) > sizeof(unsigned long); + for (size_t __i = 1 + __dw; __i < _Nw; ++__i) + if (_M_w[__i]) + __throw_overflow_error(__N("_Base_bitset::_M_do_to_ullong")); + + if (__dw) + return _M_w[0] + (static_cast(_M_w[1]) + << _GLIBCXX_BITSET_BITS_PER_WORD); + return _M_w[0]; + } +#endif + + template + size_t + _Base_bitset<_Nw>:: + _M_do_find_first(size_t __not_found) const _GLIBCXX_NOEXCEPT + { + for (size_t __i = 0; __i < _Nw; __i++) + { + _WordT __thisword = _M_w[__i]; + if (__thisword != static_cast<_WordT>(0)) + return (__i * _GLIBCXX_BITSET_BITS_PER_WORD + + __builtin_ctzl(__thisword)); + } + // not found, so return an indication of failure. + return __not_found; + } + + template + size_t + _Base_bitset<_Nw>:: + _M_do_find_next(size_t __prev, size_t __not_found) const _GLIBCXX_NOEXCEPT + { + // make bound inclusive + ++__prev; + + // check out of bounds + if (__prev >= _Nw * _GLIBCXX_BITSET_BITS_PER_WORD) + return __not_found; + + // search first word + size_t __i = _S_whichword(__prev); + _WordT __thisword = _M_w[__i]; + + // mask off bits below bound + __thisword &= (~static_cast<_WordT>(0)) << _S_whichbit(__prev); + + if (__thisword != static_cast<_WordT>(0)) + return (__i * _GLIBCXX_BITSET_BITS_PER_WORD + + __builtin_ctzl(__thisword)); + + // check subsequent words + __i++; + for (; __i < _Nw; __i++) + { + __thisword = _M_w[__i]; + if (__thisword != static_cast<_WordT>(0)) + return (__i * _GLIBCXX_BITSET_BITS_PER_WORD + + __builtin_ctzl(__thisword)); + } + // not found, so return an indication of failure. + return __not_found; + } // end _M_do_find_next + + /** + * Base class, specialization for a single word. + * + * See documentation for bitset. + */ + template<> + struct _Base_bitset<1> + { + typedef unsigned long _WordT; + _WordT _M_w; + + _GLIBCXX_CONSTEXPR _Base_bitset() _GLIBCXX_NOEXCEPT + : _M_w(0) + { } + +#if __cplusplus >= 201103L + constexpr _Base_bitset(unsigned long long __val) noexcept +#else + _Base_bitset(unsigned long __val) +#endif + : _M_w(__val) + { } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichword(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos / _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbyte(size_t __pos) _GLIBCXX_NOEXCEPT + { return (__pos % _GLIBCXX_BITSET_BITS_PER_WORD) / __CHAR_BIT__; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos % _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR _WordT + _S_maskbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); } + + _WordT& + _M_getword(size_t) _GLIBCXX_NOEXCEPT + { return _M_w; } + + _GLIBCXX_CONSTEXPR _WordT + _M_getword(size_t) const _GLIBCXX_NOEXCEPT + { return _M_w; } + +#if __cplusplus >= 201103L + const _WordT* + _M_getdata() const noexcept + { return &_M_w; } +#endif + + _WordT& + _M_hiword() _GLIBCXX_NOEXCEPT + { return _M_w; } + + _GLIBCXX_CONSTEXPR _WordT + _M_hiword() const _GLIBCXX_NOEXCEPT + { return _M_w; } + + void + _M_do_and(const _Base_bitset<1>& __x) _GLIBCXX_NOEXCEPT + { _M_w &= __x._M_w; } + + void + _M_do_or(const _Base_bitset<1>& __x) _GLIBCXX_NOEXCEPT + { _M_w |= __x._M_w; } + + void + _M_do_xor(const _Base_bitset<1>& __x) _GLIBCXX_NOEXCEPT + { _M_w ^= __x._M_w; } + + void + _M_do_left_shift(size_t __shift) _GLIBCXX_NOEXCEPT + { _M_w <<= __shift; } + + void + _M_do_right_shift(size_t __shift) _GLIBCXX_NOEXCEPT + { _M_w >>= __shift; } + + void + _M_do_flip() _GLIBCXX_NOEXCEPT + { _M_w = ~_M_w; } + + void + _M_do_set() _GLIBCXX_NOEXCEPT + { _M_w = ~static_cast<_WordT>(0); } + + void + _M_do_reset() _GLIBCXX_NOEXCEPT + { _M_w = 0; } + + bool + _M_is_equal(const _Base_bitset<1>& __x) const _GLIBCXX_NOEXCEPT + { return _M_w == __x._M_w; } + + template + bool + _M_are_all() const _GLIBCXX_NOEXCEPT + { return _M_w == (~static_cast<_WordT>(0) + >> (_GLIBCXX_BITSET_BITS_PER_WORD - _Nb)); } + + bool + _M_is_any() const _GLIBCXX_NOEXCEPT + { return _M_w != 0; } + + size_t + _M_do_count() const _GLIBCXX_NOEXCEPT + { return __builtin_popcountl(_M_w); } + + unsigned long + _M_do_to_ulong() const _GLIBCXX_NOEXCEPT + { return _M_w; } + +#if __cplusplus >= 201103L + unsigned long long + _M_do_to_ullong() const noexcept + { return _M_w; } +#endif + + size_t + _M_do_find_first(size_t __not_found) const _GLIBCXX_NOEXCEPT + { + if (_M_w != 0) + return __builtin_ctzl(_M_w); + else + return __not_found; + } + + // find the next "on" bit that follows "prev" + size_t + _M_do_find_next(size_t __prev, size_t __not_found) const + _GLIBCXX_NOEXCEPT + { + ++__prev; + if (__prev >= ((size_t) _GLIBCXX_BITSET_BITS_PER_WORD)) + return __not_found; + + _WordT __x = _M_w >> __prev; + if (__x != 0) + return __builtin_ctzl(__x) + __prev; + else + return __not_found; + } + }; + + /** + * Base class, specialization for no storage (zero-length %bitset). + * + * See documentation for bitset. + */ + template<> + struct _Base_bitset<0> + { + typedef unsigned long _WordT; + + _GLIBCXX_CONSTEXPR _Base_bitset() _GLIBCXX_NOEXCEPT + { } + +#if __cplusplus >= 201103L + constexpr _Base_bitset(unsigned long long) noexcept +#else + _Base_bitset(unsigned long) +#endif + { } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichword(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos / _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbyte(size_t __pos) _GLIBCXX_NOEXCEPT + { return (__pos % _GLIBCXX_BITSET_BITS_PER_WORD) / __CHAR_BIT__; } + + static _GLIBCXX_CONSTEXPR size_t + _S_whichbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return __pos % _GLIBCXX_BITSET_BITS_PER_WORD; } + + static _GLIBCXX_CONSTEXPR _WordT + _S_maskbit(size_t __pos) _GLIBCXX_NOEXCEPT + { return (static_cast<_WordT>(1)) << _S_whichbit(__pos); } + + // This would normally give access to the data. The bounds-checking + // in the bitset class will prevent the user from getting this far, + // but (1) it must still return an lvalue to compile, and (2) the + // user might call _Unchecked_set directly, in which case this /needs/ + // to fail. Let's not penalize zero-length users unless they actually + // make an unchecked call; all the memory ugliness is therefore + // localized to this single should-never-get-this-far function. + _WordT& + _M_getword(size_t) _GLIBCXX_NOEXCEPT + { + __throw_out_of_range(__N("_Base_bitset::_M_getword")); + return *new _WordT; + } + + _GLIBCXX_CONSTEXPR _WordT + _M_getword(size_t __pos) const _GLIBCXX_NOEXCEPT + { return 0; } + + _GLIBCXX_CONSTEXPR _WordT + _M_hiword() const _GLIBCXX_NOEXCEPT + { return 0; } + + void + _M_do_and(const _Base_bitset<0>&) _GLIBCXX_NOEXCEPT + { } + + void + _M_do_or(const _Base_bitset<0>&) _GLIBCXX_NOEXCEPT + { } + + void + _M_do_xor(const _Base_bitset<0>&) _GLIBCXX_NOEXCEPT + { } + + void + _M_do_left_shift(size_t) _GLIBCXX_NOEXCEPT + { } + + void + _M_do_right_shift(size_t) _GLIBCXX_NOEXCEPT + { } + + void + _M_do_flip() _GLIBCXX_NOEXCEPT + { } + + void + _M_do_set() _GLIBCXX_NOEXCEPT + { } + + void + _M_do_reset() _GLIBCXX_NOEXCEPT + { } + + // Are all empty bitsets equal to each other? Are they equal to + // themselves? How to compare a thing which has no state? What is + // the sound of one zero-length bitset clapping? + bool + _M_is_equal(const _Base_bitset<0>&) const _GLIBCXX_NOEXCEPT + { return true; } + + template + bool + _M_are_all() const _GLIBCXX_NOEXCEPT + { return true; } + + bool + _M_is_any() const _GLIBCXX_NOEXCEPT + { return false; } + + size_t + _M_do_count() const _GLIBCXX_NOEXCEPT + { return 0; } + + unsigned long + _M_do_to_ulong() const _GLIBCXX_NOEXCEPT + { return 0; } + +#if __cplusplus >= 201103L + unsigned long long + _M_do_to_ullong() const noexcept + { return 0; } +#endif + + // Normally "not found" is the size, but that could also be + // misinterpreted as an index in this corner case. Oh well. + size_t + _M_do_find_first(size_t) const _GLIBCXX_NOEXCEPT + { return 0; } + + size_t + _M_do_find_next(size_t, size_t) const _GLIBCXX_NOEXCEPT + { return 0; } + }; + + + // Helper class to zero out the unused high-order bits in the highest word. + template + struct _Sanitize + { + typedef unsigned long _WordT; + + static void + _S_do_sanitize(_WordT& __val) _GLIBCXX_NOEXCEPT + { __val &= ~((~static_cast<_WordT>(0)) << _Extrabits); } + }; + + template<> + struct _Sanitize<0> + { + typedef unsigned long _WordT; + + static void + _S_do_sanitize(_WordT) _GLIBCXX_NOEXCEPT { } + }; + +#if __cplusplus >= 201103L + template + struct _Sanitize_val + { + static constexpr unsigned long long + _S_do_sanitize_val(unsigned long long __val) + { return __val; } + }; + + template + struct _Sanitize_val<_Nb, true> + { + static constexpr unsigned long long + _S_do_sanitize_val(unsigned long long __val) + { return __val & ~((~static_cast(0)) << _Nb); } + }; +#endif + + /** + * @brief The %bitset class represents a @e fixed-size sequence of bits. + * @ingroup utilities + * + * (Note that %bitset does @e not meet the formal requirements of a + * container. Mainly, it lacks iterators.) + * + * The template argument, @a Nb, may be any non-negative number, + * specifying the number of bits (e.g., "0", "12", "1024*1024"). + * + * In the general unoptimized case, storage is allocated in word-sized + * blocks. Let B be the number of bits in a word, then (Nb+(B-1))/B + * words will be used for storage. B - Nb%B bits are unused. (They are + * the high-order bits in the highest word.) It is a class invariant + * that those unused bits are always zero. + * + * If you think of %bitset as a simple array of bits, be + * aware that your mental picture is reversed: a %bitset behaves + * the same way as bits in integers do, with the bit at index 0 in + * the least significant / right-hand position, and the bit at + * index Nb-1 in the most significant / left-hand position. + * Thus, unlike other containers, a %bitset's index counts from + * right to left, to put it very loosely. + * + * This behavior is preserved when translating to and from strings. For + * example, the first line of the following program probably prints + * b('a') is 0001100001 on a modern ASCII system. + * + * @code + * #include + * #include + * #include + * + * using namespace std; + * + * int main() + * { + * long a = 'a'; + * bitset<10> b(a); + * + * cout << "b('a') is " << b << endl; + * + * ostringstream s; + * s << b; + * string str = s.str(); + * cout << "index 3 in the string is " << str[3] << " but\n" + * << "index 3 in the bitset is " << b[3] << endl; + * } + * @endcode + * + * Also see: + * https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_containers.html + * for a description of extensions. + * + * Most of the actual code isn't contained in %bitset<> itself, but in the + * base class _Base_bitset. The base class works with whole words, not with + * individual bits. This allows us to specialize _Base_bitset for the + * important special case where the %bitset is only a single word. + * + * Extra confusion can result due to the fact that the storage for + * _Base_bitset @e is a regular array, and is indexed as such. This is + * carefully encapsulated. + */ + template + class bitset + : private _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> + { + private: + typedef _Base_bitset<_GLIBCXX_BITSET_WORDS(_Nb)> _Base; + typedef unsigned long _WordT; + +#ifndef __AVR__ + template + void + _M_check_initial_position(const std::basic_string<_CharT, _Traits, _Alloc>& __s, + size_t __position) const + { + if (__position > __s.size()) + __throw_out_of_range_fmt(__N("bitset::bitset: __position " + "(which is %zu) > __s.size() " + "(which is %zu)"), + __position, __s.size()); + } +#endif // __AVR__ + +#ifndef __AVR__ + void _M_check(size_t __position, const char *__s) const + { + if (__position >= _Nb) + __throw_out_of_range_fmt(__N("%s: __position (which is %zu) " + ">= _Nb (which is %zu)"), + __s, __position, _Nb); + } +#else // __AVR__ + void _M_check(size_t __position, const char *__s) const + { + if (__position >= _Nb) + __throw_out_of_range_index_length(__s, __position, _Nb); + } + +#endif // __AVR__ + + + void + _M_do_sanitize() _GLIBCXX_NOEXCEPT + { + typedef _Sanitize<_Nb % _GLIBCXX_BITSET_BITS_PER_WORD> __sanitize_type; + __sanitize_type::_S_do_sanitize(this->_M_hiword()); + } + +#if __cplusplus >= 201103L + template friend struct hash; +#endif + + public: + /** + * This encapsulates the concept of a single bit. An instance of this + * class is a proxy for an actual bit; this way the individual bit + * operations are done as faster word-size bitwise instructions. + * + * Most users will never need to use this class directly; conversions + * to and from bool are automatic and should be transparent. Overloaded + * operators help to preserve the illusion. + * + * (On a typical system, this bit %reference is 64 + * times the size of an actual bit. Ha.) + */ + class reference + { + friend class bitset; + + _WordT* _M_wp; + size_t _M_bpos; + + // left undefined + reference(); + + public: + reference(bitset& __b, size_t __pos) _GLIBCXX_NOEXCEPT + { + _M_wp = &__b._M_getword(__pos); + _M_bpos = _Base::_S_whichbit(__pos); + } + + ~reference() _GLIBCXX_NOEXCEPT + { } + + // For b[i] = __x; + reference& + operator=(bool __x) _GLIBCXX_NOEXCEPT + { + if (__x) + *_M_wp |= _Base::_S_maskbit(_M_bpos); + else + *_M_wp &= ~_Base::_S_maskbit(_M_bpos); + return *this; + } + + // For b[i] = b[__j]; + reference& + operator=(const reference& __j) _GLIBCXX_NOEXCEPT + { + if ((*(__j._M_wp) & _Base::_S_maskbit(__j._M_bpos))) + *_M_wp |= _Base::_S_maskbit(_M_bpos); + else + *_M_wp &= ~_Base::_S_maskbit(_M_bpos); + return *this; + } + + // Flips the bit + bool + operator~() const _GLIBCXX_NOEXCEPT + { return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) == 0; } + + // For __x = b[i]; + operator bool() const _GLIBCXX_NOEXCEPT + { return (*(_M_wp) & _Base::_S_maskbit(_M_bpos)) != 0; } + + // For b[i].flip(); + reference& + flip() _GLIBCXX_NOEXCEPT + { + *_M_wp ^= _Base::_S_maskbit(_M_bpos); + return *this; + } + }; + friend class reference; + + // 23.3.5.1 constructors: + /// All bits set to zero. + _GLIBCXX_CONSTEXPR bitset() _GLIBCXX_NOEXCEPT + { } + + /// Initial bits bitwise-copied from a single word (others set to zero). +#if __cplusplus >= 201103L + constexpr bitset(unsigned long long __val) noexcept + : _Base(_Sanitize_val<_Nb>::_S_do_sanitize_val(__val)) { } +#else + bitset(unsigned long __val) + : _Base(__val) + { _M_do_sanitize(); } +#endif + +#ifndef __AVR__ + /** + * Use a subset of a string. + * @param __s A string of @a 0 and @a 1 characters. + * @param __position Index of the first character in @a __s to use; + * defaults to zero. + * @throw std::out_of_range If @a pos is bigger the size of @a __s. + * @throw std::invalid_argument If a character appears in the string + * which is neither @a 0 nor @a 1. + */ + template + explicit + bitset(const std::basic_string<_CharT, _Traits, _Alloc>& __s, + size_t __position = 0) + : _Base() + { + _M_check_initial_position(__s, __position); + _M_copy_from_string(__s, __position, + std::basic_string<_CharT, _Traits, _Alloc>::npos, + _CharT('0'), _CharT('1')); + } + + /** + * Use a subset of a string. + * @param __s A string of @a 0 and @a 1 characters. + * @param __position Index of the first character in @a __s to use. + * @param __n The number of characters to copy. + * @throw std::out_of_range If @a __position is bigger the size + * of @a __s. + * @throw std::invalid_argument If a character appears in the string + * which is neither @a 0 nor @a 1. + */ + template + bitset(const std::basic_string<_CharT, _Traits, _Alloc>& __s, + size_t __position, size_t __n) + : _Base() + { + _M_check_initial_position(__s, __position); + _M_copy_from_string(__s, __position, __n, _CharT('0'), _CharT('1')); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 396. what are characters zero and one. + template + bitset(const std::basic_string<_CharT, _Traits, _Alloc>& __s, + size_t __position, size_t __n, + _CharT __zero, _CharT __one = _CharT('1')) + : _Base() + { + _M_check_initial_position(__s, __position); + _M_copy_from_string(__s, __position, __n, __zero, __one); + } + +#if __cplusplus >= 201103L + /** + * Construct from a character %array. + * @param __str An %array of characters @a zero and @a one. + * @param __n The number of characters to use. + * @param __zero The character corresponding to the value 0. + * @param __one The character corresponding to the value 1. + * @throw std::invalid_argument If a character appears in the string + * which is neither @a __zero nor @a __one. + */ + template + explicit + bitset(const _CharT* __str, + typename std::basic_string<_CharT>::size_type __n + = std::basic_string<_CharT>::npos, + _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) + : _Base() + { + if (!__str) + __throw_logic_error(__N("bitset::bitset(const _CharT*, ...)")); + + if (__n == std::basic_string<_CharT>::npos) + __n = std::char_traits<_CharT>::length(__str); + _M_copy_from_ptr<_CharT, std::char_traits<_CharT>>(__str, __n, 0, + __n, __zero, + __one); + } +#endif + +#endif // __AVR__ + + // 23.3.5.2 bitset operations: + //@{ + /** + * Operations on bitsets. + * @param __rhs A same-sized bitset. + * + * These should be self-explanatory. + */ + bitset<_Nb>& + operator&=(const bitset<_Nb>& __rhs) _GLIBCXX_NOEXCEPT + { + this->_M_do_and(__rhs); + return *this; + } + + bitset<_Nb>& + operator|=(const bitset<_Nb>& __rhs) _GLIBCXX_NOEXCEPT + { + this->_M_do_or(__rhs); + return *this; + } + + bitset<_Nb>& + operator^=(const bitset<_Nb>& __rhs) _GLIBCXX_NOEXCEPT + { + this->_M_do_xor(__rhs); + return *this; + } + //@} + + //@{ + /** + * Operations on bitsets. + * @param __position The number of places to shift. + * + * These should be self-explanatory. + */ + bitset<_Nb>& + operator<<=(size_t __position) _GLIBCXX_NOEXCEPT + { + if (__builtin_expect(__position < _Nb, 1)) + { + this->_M_do_left_shift(__position); + this->_M_do_sanitize(); + } + else + this->_M_do_reset(); + return *this; + } + + bitset<_Nb>& + operator>>=(size_t __position) _GLIBCXX_NOEXCEPT + { + if (__builtin_expect(__position < _Nb, 1)) + { + this->_M_do_right_shift(__position); + this->_M_do_sanitize(); + } + else + this->_M_do_reset(); + return *this; + } + //@} + + //@{ + /** + * These versions of single-bit set, reset, flip, and test are + * extensions from the SGI version. They do no range checking. + * @ingroup SGIextensions + */ + bitset<_Nb>& + _Unchecked_set(size_t __pos) _GLIBCXX_NOEXCEPT + { + this->_M_getword(__pos) |= _Base::_S_maskbit(__pos); + return *this; + } + + bitset<_Nb>& + _Unchecked_set(size_t __pos, int __val) _GLIBCXX_NOEXCEPT + { + if (__val) + this->_M_getword(__pos) |= _Base::_S_maskbit(__pos); + else + this->_M_getword(__pos) &= ~_Base::_S_maskbit(__pos); + return *this; + } + + bitset<_Nb>& + _Unchecked_reset(size_t __pos) _GLIBCXX_NOEXCEPT + { + this->_M_getword(__pos) &= ~_Base::_S_maskbit(__pos); + return *this; + } + + bitset<_Nb>& + _Unchecked_flip(size_t __pos) _GLIBCXX_NOEXCEPT + { + this->_M_getword(__pos) ^= _Base::_S_maskbit(__pos); + return *this; + } + + _GLIBCXX_CONSTEXPR bool + _Unchecked_test(size_t __pos) const _GLIBCXX_NOEXCEPT + { return ((this->_M_getword(__pos) & _Base::_S_maskbit(__pos)) + != static_cast<_WordT>(0)); } + //@} + + // Set, reset, and flip. + /** + * @brief Sets every bit to true. + */ + bitset<_Nb>& + set() _GLIBCXX_NOEXCEPT + { + this->_M_do_set(); + this->_M_do_sanitize(); + return *this; + } + + /** + * @brief Sets a given bit to a particular value. + * @param __position The index of the bit. + * @param __val Either true or false, defaults to true. + * @throw std::out_of_range If @a pos is bigger the size of the %set. + */ + bitset<_Nb>& + set(size_t __position, bool __val = true) + { + this->_M_check(__position, __N("bitset::set")); + return _Unchecked_set(__position, __val); + } + + /** + * @brief Sets every bit to false. + */ + bitset<_Nb>& + reset() _GLIBCXX_NOEXCEPT + { + this->_M_do_reset(); + return *this; + } + + /** + * @brief Sets a given bit to false. + * @param __position The index of the bit. + * @throw std::out_of_range If @a pos is bigger the size of the %set. + * + * Same as writing @c set(pos,false). + */ + bitset<_Nb>& + reset(size_t __position) + { + this->_M_check(__position, __N("bitset::reset")); + return _Unchecked_reset(__position); + } + + /** + * @brief Toggles every bit to its opposite value. + */ + bitset<_Nb>& + flip() _GLIBCXX_NOEXCEPT + { + this->_M_do_flip(); + this->_M_do_sanitize(); + return *this; + } + + /** + * @brief Toggles a given bit to its opposite value. + * @param __position The index of the bit. + * @throw std::out_of_range If @a pos is bigger the size of the %set. + */ + bitset<_Nb>& + flip(size_t __position) + { + this->_M_check(__position, __N("bitset::flip")); + return _Unchecked_flip(__position); + } + + /// See the no-argument flip(). + bitset<_Nb> + operator~() const _GLIBCXX_NOEXCEPT + { return bitset<_Nb>(*this).flip(); } + + //@{ + /** + * @brief Array-indexing support. + * @param __position Index into the %bitset. + * @return A bool for a const %bitset. For non-const + * bitsets, an instance of the reference proxy class. + * @note These operators do no range checking and throw no exceptions, + * as required by DR 11 to the standard. + * + * _GLIBCXX_RESOLVE_LIB_DEFECTS Note that this implementation already + * resolves DR 11 (items 1 and 2), but does not do the range-checking + * required by that DR's resolution. -pme + * The DR has since been changed: range-checking is a precondition + * (users' responsibility), and these functions must not throw. -pme + */ + reference + operator[](size_t __position) + { return reference(*this, __position); } + + _GLIBCXX_CONSTEXPR bool + operator[](size_t __position) const + { return _Unchecked_test(__position); } + //@} + + /** + * @brief Returns a numerical interpretation of the %bitset. + * @return The integral equivalent of the bits. + * @throw std::overflow_error If there are too many bits to be + * represented in an @c unsigned @c long. + */ + unsigned long + to_ulong() const + { return this->_M_do_to_ulong(); } + +#if __cplusplus >= 201103L + unsigned long long + to_ullong() const + { return this->_M_do_to_ullong(); } +#endif + +#ifndef __AVR__ + + /** + * @brief Returns a character interpretation of the %bitset. + * @return The string equivalent of the bits. + * + * Note the ordering of the bits: decreasing character positions + * correspond to increasing bit positions (see the main class notes for + * an example). + */ + template + std::basic_string<_CharT, _Traits, _Alloc> + to_string() const + { + std::basic_string<_CharT, _Traits, _Alloc> __result; + _M_copy_to_string(__result, _CharT('0'), _CharT('1')); + return __result; + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 396. what are characters zero and one. + template + std::basic_string<_CharT, _Traits, _Alloc> + to_string(_CharT __zero, _CharT __one = _CharT('1')) const + { + std::basic_string<_CharT, _Traits, _Alloc> __result; + _M_copy_to_string(__result, __zero, __one); + return __result; + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 434. bitset::to_string() hard to use. + template + std::basic_string<_CharT, _Traits, std::allocator<_CharT> > + to_string() const + { return to_string<_CharT, _Traits, std::allocator<_CharT> >(); } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 853. to_string needs updating with zero and one. + template + std::basic_string<_CharT, _Traits, std::allocator<_CharT> > + to_string(_CharT __zero, _CharT __one = _CharT('1')) const + { return to_string<_CharT, _Traits, + std::allocator<_CharT> >(__zero, __one); } + + template + std::basic_string<_CharT, std::char_traits<_CharT>, + std::allocator<_CharT> > + to_string() const + { + return to_string<_CharT, std::char_traits<_CharT>, + std::allocator<_CharT> >(); + } + + template + std::basic_string<_CharT, std::char_traits<_CharT>, + std::allocator<_CharT> > + to_string(_CharT __zero, _CharT __one = _CharT('1')) const + { + return to_string<_CharT, std::char_traits<_CharT>, + std::allocator<_CharT> >(__zero, __one); + } + + std::basic_string, std::allocator > + to_string() const + { + return to_string, + std::allocator >(); + } + + std::basic_string, std::allocator > + to_string(char __zero, char __one = '1') const + { + return to_string, + std::allocator >(__zero, __one); + } + +#endif // __AVR__ + + // Helper functions for string operations. + template + void + _M_copy_from_ptr(const _CharT*, size_t, size_t, size_t, + _CharT, _CharT); + +#ifndef __AVR__ + + template + void + _M_copy_from_string(const std::basic_string<_CharT, + _Traits, _Alloc>& __s, size_t __pos, size_t __n, + _CharT __zero, _CharT __one) + { _M_copy_from_ptr<_CharT, _Traits>(__s.data(), __s.size(), __pos, __n, + __zero, __one); } + + template + void + _M_copy_to_string(std::basic_string<_CharT, _Traits, _Alloc>&, + _CharT, _CharT) const; + + // NB: Backward compat. + template + void + _M_copy_from_string(const std::basic_string<_CharT, + _Traits, _Alloc>& __s, size_t __pos, size_t __n) + { _M_copy_from_string(__s, __pos, __n, _CharT('0'), _CharT('1')); } + + template + void + _M_copy_to_string(std::basic_string<_CharT, _Traits,_Alloc>& __s) const + { _M_copy_to_string(__s, _CharT('0'), _CharT('1')); } + +#endif // __AVR__ + + /// Returns the number of bits which are set. + size_t + count() const _GLIBCXX_NOEXCEPT + { return this->_M_do_count(); } + + /// Returns the total number of bits. + _GLIBCXX_CONSTEXPR size_t + size() const _GLIBCXX_NOEXCEPT + { return _Nb; } + + //@{ + /// These comparisons for equality/inequality are, well, @e bitwise. + bool + operator==(const bitset<_Nb>& __rhs) const _GLIBCXX_NOEXCEPT + { return this->_M_is_equal(__rhs); } + + bool + operator!=(const bitset<_Nb>& __rhs) const _GLIBCXX_NOEXCEPT + { return !this->_M_is_equal(__rhs); } + //@} + + /** + * @brief Tests the value of a bit. + * @param __position The index of a bit. + * @return The value at @a pos. + * @throw std::out_of_range If @a pos is bigger the size of the %set. + */ + bool + test(size_t __position) const + { + this->_M_check(__position, __N("bitset::test")); + return _Unchecked_test(__position); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 693. std::bitset::all() missing. + /** + * @brief Tests whether all the bits are on. + * @return True if all the bits are set. + */ + bool + all() const _GLIBCXX_NOEXCEPT + { return this->template _M_are_all<_Nb>(); } + + /** + * @brief Tests whether any of the bits are on. + * @return True if at least one bit is set. + */ + bool + any() const _GLIBCXX_NOEXCEPT + { return this->_M_is_any(); } + + /** + * @brief Tests whether any of the bits are on. + * @return True if none of the bits are set. + */ + bool + none() const _GLIBCXX_NOEXCEPT + { return !this->_M_is_any(); } + + //@{ + /// Self-explanatory. + bitset<_Nb> + operator<<(size_t __position) const _GLIBCXX_NOEXCEPT + { return bitset<_Nb>(*this) <<= __position; } + + bitset<_Nb> + operator>>(size_t __position) const _GLIBCXX_NOEXCEPT + { return bitset<_Nb>(*this) >>= __position; } + //@} + + /** + * @brief Finds the index of the first "on" bit. + * @return The index of the first bit set, or size() if not found. + * @ingroup SGIextensions + * @sa _Find_next + */ + size_t + _Find_first() const _GLIBCXX_NOEXCEPT + { return this->_M_do_find_first(_Nb); } + + /** + * @brief Finds the index of the next "on" bit after prev. + * @return The index of the next bit set, or size() if not found. + * @param __prev Where to start searching. + * @ingroup SGIextensions + * @sa _Find_first + */ + size_t + _Find_next(size_t __prev) const _GLIBCXX_NOEXCEPT + { return this->_M_do_find_next(__prev, _Nb); } + }; + + // Definitions of non-inline member functions. + template + template + void + bitset<_Nb>:: + _M_copy_from_ptr(const _CharT* __s, size_t __len, + size_t __pos, size_t __n, _CharT __zero, _CharT __one) + { + reset(); + const size_t __nbits = std::min(_Nb, std::min(__n, size_t(__len - __pos))); + for (size_t __i = __nbits; __i > 0; --__i) + { + const _CharT __c = __s[__pos + __nbits - __i]; + if (_Traits::eq(__c, __zero)) + ; + else if (_Traits::eq(__c, __one)) + _Unchecked_set(__i - 1); + else + __throw_invalid_argument(__N("bitset::_M_copy_from_ptr")); + } + } + +#ifndef __AVR__ + + template + template + void + bitset<_Nb>:: + _M_copy_to_string(std::basic_string<_CharT, _Traits, _Alloc>& __s, + _CharT __zero, _CharT __one) const + { + __s.assign(_Nb, __zero); + for (size_t __i = _Nb; __i > 0; --__i) + if (_Unchecked_test(__i - 1)) + _Traits::assign(__s[_Nb - __i], __one); + } + +#endif // __AVR__ + + // 23.3.5.3 bitset operations: + //@{ + /** + * @brief Global bitwise operations on bitsets. + * @param __x A bitset. + * @param __y A bitset of the same size as @a __x. + * @return A new bitset. + * + * These should be self-explanatory. + */ + template + inline bitset<_Nb> + operator&(const bitset<_Nb>& __x, const bitset<_Nb>& __y) _GLIBCXX_NOEXCEPT + { + bitset<_Nb> __result(__x); + __result &= __y; + return __result; + } + + template + inline bitset<_Nb> + operator|(const bitset<_Nb>& __x, const bitset<_Nb>& __y) _GLIBCXX_NOEXCEPT + { + bitset<_Nb> __result(__x); + __result |= __y; + return __result; + } + + template + inline bitset<_Nb> + operator^(const bitset<_Nb>& __x, const bitset<_Nb>& __y) _GLIBCXX_NOEXCEPT + { + bitset<_Nb> __result(__x); + __result ^= __y; + return __result; + } + //@} + +#ifndef __AVR__ + + //@{ + /** + * @brief Global I/O operators for bitsets. + * + * Direct I/O between streams and bitsets is supported. Output is + * straightforward. Input will skip whitespace, only accept @a 0 and @a 1 + * characters, and will only extract as many digits as the %bitset will + * hold. + */ + template + std::basic_istream<_CharT, _Traits>& + operator>>(std::basic_istream<_CharT, _Traits>& __is, bitset<_Nb>& __x) + { + typedef typename _Traits::char_type char_type; + typedef std::basic_istream<_CharT, _Traits> __istream_type; + typedef typename __istream_type::ios_base __ios_base; + + std::basic_string<_CharT, _Traits> __tmp; + __tmp.reserve(_Nb); + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 303. Bitset input operator underspecified + const char_type __zero = __is.widen('0'); + const char_type __one = __is.widen('1'); + + typename __ios_base::iostate __state = __ios_base::goodbit; + typename __istream_type::sentry __sentry(__is); + if (__sentry) + { + __try + { + for (size_t __i = _Nb; __i > 0; --__i) + { + static typename _Traits::int_type __eof = _Traits::eof(); + + typename _Traits::int_type __c1 = __is.rdbuf()->sbumpc(); + if (_Traits::eq_int_type(__c1, __eof)) + { + __state |= __ios_base::eofbit; + break; + } + else + { + const char_type __c2 = _Traits::to_char_type(__c1); + if (_Traits::eq(__c2, __zero)) + __tmp.push_back(__zero); + else if (_Traits::eq(__c2, __one)) + __tmp.push_back(__one); + else if (_Traits:: + eq_int_type(__is.rdbuf()->sputbackc(__c2), + __eof)) + { + __state |= __ios_base::failbit; + break; + } + } + } + } + __catch(__cxxabiv1::__forced_unwind&) + { + __is._M_setstate(__ios_base::badbit); + __throw_exception_again; + } + __catch(...) + { __is._M_setstate(__ios_base::badbit); } + } + + if (__tmp.empty() && _Nb) + __state |= __ios_base::failbit; + else + __x._M_copy_from_string(__tmp, static_cast(0), _Nb, + __zero, __one); + if (__state) + __is.setstate(__state); + return __is; + } + + template + std::basic_ostream<_CharT, _Traits>& + operator<<(std::basic_ostream<_CharT, _Traits>& __os, + const bitset<_Nb>& __x) + { + std::basic_string<_CharT, _Traits> __tmp; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 396. what are characters zero and one. + const ctype<_CharT>& __ct = use_facet >(__os.getloc()); + __x._M_copy_to_string(__tmp, __ct.widen('0'), __ct.widen('1')); + return __os << __tmp; + } + //@} + +#endif // __AVR__ + +_GLIBCXX_END_NAMESPACE_CONTAINER +} // namespace std + +#undef _GLIBCXX_BITSET_WORDS +#undef _GLIBCXX_BITSET_BITS_PER_WORD +#undef _GLIBCXX_BITSET_BITS_PER_ULL + +#if __cplusplus >= 201103L + +#include "bits/functional_hash.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // DR 1182. + /// std::hash specialization for bitset. + template + struct hash<_GLIBCXX_STD_C::bitset<_Nb>> + : public __hash_base> + { + size_t + operator()(const _GLIBCXX_STD_C::bitset<_Nb>& __b) const noexcept + { + const size_t __clength = (_Nb + __CHAR_BIT__ - 1) / __CHAR_BIT__; + return std::_Hash_impl::hash(__b._M_getdata(), __clength); + } + }; + + template<> + struct hash<_GLIBCXX_STD_C::bitset<0>> + : public __hash_base> + { + size_t + operator()(const _GLIBCXX_STD_C::bitset<0>&) const noexcept + { return 0; } + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // C++11 + +#ifdef _GLIBCXX_DEBUG +# include +#endif + +#ifdef _GLIBCXX_PROFILE +# include +#endif + +#endif /* _GLIBCXX_BITSET */ diff --git a/AH/STL/Fallback/climits b/AH/STL/Fallback/climits new file mode 100644 index 0000000..1daf0e5 --- /dev/null +++ b/AH/STL/Fallback/climits @@ -0,0 +1,59 @@ +// -*- C++ -*- forwarding header. + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/climits + * This is a Standard C++ Library file. You should @c \#include this file + * in your programs, rather than any of the @a *.h implementation files. + * + * This is the C++ version of the Standard C Library header @c limits.h, + * and its contents are (mostly) the same as that header, but are all + * contained in the namespace @c std (except for names which are defined + * as macros in C). + */ + +// +// ISO C++ 14882: 18.2.2 Implementation properties: C library +// + +#pragma GCC system_header + +#include "bits/c++config.h" +#include + +#ifndef _GLIBCXX_CLIMITS +#define _GLIBCXX_CLIMITS 1 + +#ifndef LLONG_MIN +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1) +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX __LONG_LONG_MAX__ +#endif + +#ifndef ULLONG_MAX +#define ULLONG_MAX (__LONG_LONG_MAX__ * 2ULL + 1) +#endif + +#endif diff --git a/AH/STL/Fallback/cmath b/AH/STL/Fallback/cmath new file mode 100644 index 0000000..53f6d1f --- /dev/null +++ b/AH/STL/Fallback/cmath @@ -0,0 +1,3169 @@ +// -*- C++ -*- C forwarding header. + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/cmath + * This is a Standard C++ Library file. You should @c \#include this file + * in your programs, rather than any of the @a *.h implementation files. + * + * This is the C++ version of the Standard C Library header @c math.h, + * and its contents are (mostly) the same as that header, but are all + * contained in the namespace @c std (except for names which are defined + * as macros in C). + */ + +// +// ISO C++ 14882: 26.5 C library +// + +#pragma GCC system_header + +#include "bits/c++config.h" +#include "bits/cpp_type_traits.h" +#include "ext/type_traits.h" +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include_next +#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include "bits/std_abs.h" + +#ifdef ARDUINO +// #undef Arduino round macros by including it first +#include +#endif + +#ifndef _GLIBCXX_CMATH +#define _GLIBCXX_CMATH 1 + +#ifdef __AVR__ +enum + { + FP_NAN = +# define FP_NAN 0 + FP_NAN, + FP_INFINITE = +# define FP_INFINITE 1 + FP_INFINITE, + FP_ZERO = +# define FP_ZERO 2 + FP_ZERO, + FP_SUBNORMAL = +# define FP_SUBNORMAL 3 + FP_SUBNORMAL, + FP_NORMAL = +# define FP_NORMAL 4 + FP_NORMAL + }; +#endif // __AVR__ + +// Get rid of those macros defined in in lieu of real functions. +#undef div +#undef acos +#undef asin +#undef atan +#undef atan2 +#undef ceil +#undef cos +#undef cosh +#undef exp +#undef fabs +#undef floor +#undef fmod +#undef frexp +#undef ldexp +#undef log +#undef log10 +#undef modf +#undef pow +#undef sin +#undef sinh +#undef sqrt +#undef tan +#undef tanh + +extern "C++" +{ +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifndef __AVR__ + + using ::acos; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + acos(float __x) + { return __builtin_acosf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + acos(long double __x) + { return __builtin_acosl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + acos(_Tp __x) + { return __builtin_acos(__x); } + + using ::asin; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + asin(float __x) + { return __builtin_asinf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + asin(long double __x) + { return __builtin_asinl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + asin(_Tp __x) + { return __builtin_asin(__x); } + + using ::atan; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + atan(float __x) + { return __builtin_atanf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + atan(long double __x) + { return __builtin_atanl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + atan(_Tp __x) + { return __builtin_atan(__x); } + + using ::atan2; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + atan2(float __y, float __x) + { return __builtin_atan2f(__y, __x); } + + inline _GLIBCXX_CONSTEXPR long double + atan2(long double __y, long double __x) + { return __builtin_atan2l(__y, __x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + atan2(_Tp __y, _Up __x) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return atan2(__type(__y), __type(__x)); + } + + using ::ceil; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + ceil(float __x) + { return __builtin_ceilf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + ceil(long double __x) + { return __builtin_ceill(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + ceil(_Tp __x) + { return __builtin_ceil(__x); } + + using ::cos; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + cos(float __x) + { return __builtin_cosf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + cos(long double __x) + { return __builtin_cosl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cos(_Tp __x) + { return __builtin_cos(__x); } + + using ::cosh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + cosh(float __x) + { return __builtin_coshf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + cosh(long double __x) + { return __builtin_coshl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cosh(_Tp __x) + { return __builtin_cosh(__x); } + + using ::exp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + exp(float __x) + { return __builtin_expf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + exp(long double __x) + { return __builtin_expl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + exp(_Tp __x) + { return __builtin_exp(__x); } + + using ::fabs; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + fabs(float __x) + { return __builtin_fabsf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + fabs(long double __x) + { return __builtin_fabsl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + fabs(_Tp __x) + { return __builtin_fabs(__x); } + + using ::floor; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + floor(float __x) + { return __builtin_floorf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + floor(long double __x) + { return __builtin_floorl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + floor(_Tp __x) + { return __builtin_floor(__x); } + + using ::fmod; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + fmod(float __x, float __y) + { return __builtin_fmodf(__x, __y); } + + inline _GLIBCXX_CONSTEXPR long double + fmod(long double __x, long double __y) + { return __builtin_fmodl(__x, __y); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmod(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmod(__type(__x), __type(__y)); + } + + using ::frexp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline float + frexp(float __x, int* __exp) + { return __builtin_frexpf(__x, __exp); } + + inline long double + frexp(long double __x, int* __exp) + { return __builtin_frexpl(__x, __exp); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + frexp(_Tp __x, int* __exp) + { return __builtin_frexp(__x, __exp); } + + using ::ldexp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + ldexp(float __x, int __exp) + { return __builtin_ldexpf(__x, __exp); } + + inline _GLIBCXX_CONSTEXPR long double + ldexp(long double __x, int __exp) + { return __builtin_ldexpl(__x, __exp); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + ldexp(_Tp __x, int __exp) + { return __builtin_ldexp(__x, __exp); } + + using ::log; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + log(float __x) + { return __builtin_logf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + log(long double __x) + { return __builtin_logl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log(_Tp __x) + { return __builtin_log(__x); } + + using ::log10; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + log10(float __x) + { return __builtin_log10f(__x); } + + inline _GLIBCXX_CONSTEXPR long double + log10(long double __x) + { return __builtin_log10l(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log10(_Tp __x) + { return __builtin_log10(__x); } + + using ::modf; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline float + modf(float __x, float* __iptr) + { return __builtin_modff(__x, __iptr); } + + inline long double + modf(long double __x, long double* __iptr) + { return __builtin_modfl(__x, __iptr); } +#endif + + using ::pow; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + pow(float __x, float __y) + { return __builtin_powf(__x, __y); } + + inline _GLIBCXX_CONSTEXPR long double + pow(long double __x, long double __y) + { return __builtin_powl(__x, __y); } + +#if __cplusplus < 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 550. What should the return type of pow(float,int) be? + inline double + pow(double __x, int __i) + { return __builtin_powi(__x, __i); } + + inline float + pow(float __x, int __n) + { return __builtin_powif(__x, __n); } + + inline long double + pow(long double __x, int __n) + { return __builtin_powil(__x, __n); } +#endif +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + pow(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return pow(__type(__x), __type(__y)); + } + + using ::sin; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sin(float __x) + { return __builtin_sinf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sin(long double __x) + { return __builtin_sinl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sin(_Tp __x) + { return __builtin_sin(__x); } + + using ::sinh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sinh(float __x) + { return __builtin_sinhf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sinh(long double __x) + { return __builtin_sinhl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sinh(_Tp __x) + { return __builtin_sinh(__x); } + + using ::sqrt; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sqrt(float __x) + { return __builtin_sqrtf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sqrt(long double __x) + { return __builtin_sqrtl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sqrt(_Tp __x) + { return __builtin_sqrt(__x); } + + using ::tan; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + tan(float __x) + { return __builtin_tanf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + tan(long double __x) + { return __builtin_tanl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tan(_Tp __x) + { return __builtin_tan(__x); } + + using ::tanh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + tanh(float __x) + { return __builtin_tanhf(__x); } + + inline _GLIBCXX_CONSTEXPR long double + tanh(long double __x) + { return __builtin_tanhl(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tanh(_Tp __x) + { return __builtin_tanh(__x); } + +#else // __AVR__ + + + using ::acos; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + acos(float __x) + { return __builtin_acos(__x); } + + inline _GLIBCXX_CONSTEXPR long double + acos(long double __x) + { return __builtin_acos(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + acos(_Tp __x) + { return __builtin_acos(__x); } + + using ::asin; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + asin(float __x) + { return __builtin_asin(__x); } + + inline _GLIBCXX_CONSTEXPR long double + asin(long double __x) + { return __builtin_asin(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + asin(_Tp __x) + { return __builtin_asin(__x); } + + using ::atan; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + atan(float __x) + { return __builtin_atan(__x); } + + inline _GLIBCXX_CONSTEXPR long double + atan(long double __x) + { return __builtin_atan(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + atan(_Tp __x) + { return __builtin_atan(__x); } + + using ::atan2; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + atan2(float __y, float __x) + { return __builtin_atan2(__y, __x); } + + inline _GLIBCXX_CONSTEXPR long double + atan2(long double __y, long double __x) + { return __builtin_atan2(__y, __x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + atan2(_Tp __y, _Up __x) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return atan2(__type(__y), __type(__x)); + } + + using ::ceil; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + ceil(float __x) + { return __builtin_ceil(__x); } + + inline _GLIBCXX_CONSTEXPR long double + ceil(long double __x) + { return __builtin_ceil(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + ceil(_Tp __x) + { return __builtin_ceil(__x); } + + using ::cos; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + cos(float __x) + { return __builtin_cos(__x); } + + inline _GLIBCXX_CONSTEXPR long double + cos(long double __x) + { return __builtin_cos(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cos(_Tp __x) + { return __builtin_cos(__x); } + + using ::cosh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + cosh(float __x) + { return __builtin_cosh(__x); } + + inline _GLIBCXX_CONSTEXPR long double + cosh(long double __x) + { return __builtin_cosh(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cosh(_Tp __x) + { return __builtin_cosh(__x); } + + using ::exp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + exp(float __x) + { return __builtin_exp(__x); } + + inline _GLIBCXX_CONSTEXPR long double + exp(long double __x) + { return __builtin_exp(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + exp(_Tp __x) + { return __builtin_exp(__x); } + + using ::fabs; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + fabs(float __x) + { return __builtin_fabs(__x); } + + inline _GLIBCXX_CONSTEXPR long double + fabs(long double __x) + { return __builtin_fabs(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + fabs(_Tp __x) + { return __builtin_fabs(__x); } + + using ::floor; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + floor(float __x) + { return __builtin_floor(__x); } + + inline _GLIBCXX_CONSTEXPR long double + floor(long double __x) + { return __builtin_floor(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + floor(_Tp __x) + { return __builtin_floor(__x); } + + using ::fmod; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + fmod(float __x, float __y) + { return __builtin_fmod(__x, __y); } + + inline _GLIBCXX_CONSTEXPR long double + fmod(long double __x, long double __y) + { return __builtin_fmod(__x, __y); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmod(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmod(__type(__x), __type(__y)); + } + + using ::frexp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline float + frexp(float __x, int* __exp) + { return __builtin_frexp(__x, __exp); } + + inline long double + frexp(long double __x, int* __exp) + { return __builtin_frexp(__x, __exp); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + frexp(_Tp __x, int* __exp) + { return __builtin_frexp(__x, __exp); } + + using ::ldexp; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + ldexp(float __x, int __exp) + { return __builtin_ldexp(__x, __exp); } + + inline _GLIBCXX_CONSTEXPR long double + ldexp(long double __x, int __exp) + { return __builtin_ldexp(__x, __exp); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + ldexp(_Tp __x, int __exp) + { return __builtin_ldexp(__x, __exp); } + + using ::log; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + log(float __x) + { return __builtin_log(__x); } + + inline _GLIBCXX_CONSTEXPR long double + log(long double __x) + { return __builtin_log(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log(_Tp __x) + { return __builtin_log(__x); } + + using ::log10; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + log10(float __x) + { return __builtin_log10(__x); } + + inline _GLIBCXX_CONSTEXPR long double + log10(long double __x) + { return __builtin_log10(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log10(_Tp __x) + { return __builtin_log10(__x); } + + using ::modf; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline float + modf(float __x, float* __iptr) + { return __builtin_modf(__x, (double*)__iptr); } + + inline long double + modf(long double __x, long double* __iptr) + { return __builtin_modf(__x, (double*)__iptr); } +#endif + + using ::pow; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + pow(float __x, float __y) + { return __builtin_pow(__x, __y); } + + inline _GLIBCXX_CONSTEXPR long double + pow(long double __x, long double __y) + { return __builtin_pow(__x, __y); } + +#if __cplusplus < 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 550. What should the return type of pow(float,int) be? + inline double + pow(double __x, int __i) + { return __builtin_powi(__x, __i); } + + inline float + pow(float __x, int __n) + { return __builtin_powi(__x, __n); } + + inline long double + pow(long double __x, int __n) + { return __builtin_powi(__x, __n); } +#endif +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + pow(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return pow(__type(__x), __type(__y)); + } + + using ::sin; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sin(float __x) + { return __builtin_sin(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sin(long double __x) + { return __builtin_sin(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sin(_Tp __x) + { return __builtin_sin(__x); } + + using ::sinh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sinh(float __x) + { return __builtin_sinh(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sinh(long double __x) + { return __builtin_sinh(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sinh(_Tp __x) + { return __builtin_sinh(__x); } + + using ::sqrt; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + sqrt(float __x) + { return __builtin_sqrt(__x); } + + inline _GLIBCXX_CONSTEXPR long double + sqrt(long double __x) + { return __builtin_sqrt(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + sqrt(_Tp __x) + { return __builtin_sqrt(__x); } + + using ::tan; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + tan(float __x) + { return __builtin_tan(__x); } + + inline _GLIBCXX_CONSTEXPR long double + tan(long double __x) + { return __builtin_tan(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tan(_Tp __x) + { return __builtin_tan(__x); } + + using ::tanh; + +#ifndef __CORRECT_ISO_CPP_MATH_H_PROTO + inline _GLIBCXX_CONSTEXPR float + tanh(float __x) + { return __builtin_tanh(__x); } + + inline _GLIBCXX_CONSTEXPR long double + tanh(long double __x) + { return __builtin_tanh(__x); } +#endif + + template + inline _GLIBCXX_CONSTEXPR + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tanh(_Tp __x) + { return __builtin_tanh(__x); } + +#endif // __AVR__ +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if _GLIBCXX_USE_C99_MATH +#if !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC + +// These are possible macros imported from C99-land. +#undef fpclassify +#undef isfinite +#undef isinf +#undef isnan +#undef isnormal +#undef signbit +#undef isgreater +#undef isgreaterequal +#undef isless +#undef islessequal +#undef islessgreater +#undef isunordered + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if __cplusplus >= 201103L + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr int + fpclassify(float __x) + { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, + FP_SUBNORMAL, FP_ZERO, __x); } + + constexpr int + fpclassify(double __x) + { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, + FP_SUBNORMAL, FP_ZERO, __x); } + + constexpr int + fpclassify(long double __x) + { return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, + FP_SUBNORMAL, FP_ZERO, __x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + int>::__type + fpclassify(_Tp __x) + { return __x != 0 ? FP_NORMAL : FP_ZERO; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isfinite(float __x) + { return __builtin_isfinite(__x); } + + constexpr bool + isfinite(double __x) + { return __builtin_isfinite(__x); } + + constexpr bool + isfinite(long double __x) + { return __builtin_isfinite(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + bool>::__type + isfinite(_Tp __x) + { return true; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isinf(float __x) + { return __builtin_isinf(__x); } + +#if _GLIBCXX_HAVE_OBSOLETE_ISINF \ + && !_GLIBCXX_NO_OBSOLETE_ISINF_ISNAN_DYNAMIC + using ::isinf; +#else + constexpr bool + isinf(double __x) + { return __builtin_isinf(__x); } +#endif + + constexpr bool + isinf(long double __x) + { return __builtin_isinf(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + bool>::__type + isinf(_Tp __x) + { return false; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isnan(float __x) + { return __builtin_isnan(__x); } + +#if _GLIBCXX_HAVE_OBSOLETE_ISNAN \ + && !_GLIBCXX_NO_OBSOLETE_ISINF_ISNAN_DYNAMIC + using ::isnan; +#else + constexpr bool + isnan(double __x) + { return __builtin_isnan(__x); } +#endif + + constexpr bool + isnan(long double __x) + { return __builtin_isnan(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + bool>::__type + isnan(_Tp __x) + { return false; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isnormal(float __x) + { return __builtin_isnormal(__x); } + + constexpr bool + isnormal(double __x) + { return __builtin_isnormal(__x); } + + constexpr bool + isnormal(long double __x) + { return __builtin_isnormal(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + bool>::__type + isnormal(_Tp __x) + { return __x != 0 ? true : false; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + // Note: middle-end/36757 is fixed, __builtin_signbit is type-generic. + constexpr bool + signbit(float __x) + { return __builtin_signbit(__x); } + + constexpr bool + signbit(double __x) + { return __builtin_signbit(__x); } + + constexpr bool + signbit(long double __x) + { return __builtin_signbit(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + bool>::__type + signbit(_Tp __x) + { return __x < 0 ? true : false; } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isgreater(float __x, float __y) + { return __builtin_isgreater(__x, __y); } + + constexpr bool + isgreater(double __x, double __y) + { return __builtin_isgreater(__x, __y); } + + constexpr bool + isgreater(long double __x, long double __y) + { return __builtin_isgreater(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + isgreater(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_isgreater(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isgreaterequal(float __x, float __y) + { return __builtin_isgreaterequal(__x, __y); } + + constexpr bool + isgreaterequal(double __x, double __y) + { return __builtin_isgreaterequal(__x, __y); } + + constexpr bool + isgreaterequal(long double __x, long double __y) + { return __builtin_isgreaterequal(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + isgreaterequal(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_isgreaterequal(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isless(float __x, float __y) + { return __builtin_isless(__x, __y); } + + constexpr bool + isless(double __x, double __y) + { return __builtin_isless(__x, __y); } + + constexpr bool + isless(long double __x, long double __y) + { return __builtin_isless(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + isless(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_isless(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + islessequal(float __x, float __y) + { return __builtin_islessequal(__x, __y); } + + constexpr bool + islessequal(double __x, double __y) + { return __builtin_islessequal(__x, __y); } + + constexpr bool + islessequal(long double __x, long double __y) + { return __builtin_islessequal(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + islessequal(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_islessequal(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + islessgreater(float __x, float __y) + { return __builtin_islessgreater(__x, __y); } + + constexpr bool + islessgreater(double __x, double __y) + { return __builtin_islessgreater(__x, __y); } + + constexpr bool + islessgreater(long double __x, long double __y) + { return __builtin_islessgreater(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + islessgreater(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_islessgreater(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr bool + isunordered(float __x, float __y) + { return __builtin_isunordered(__x, __y); } + + constexpr bool + isunordered(double __x, double __y) + { return __builtin_isunordered(__x, __y); } + + constexpr bool + isunordered(long double __x, long double __y) + { return __builtin_isunordered(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename + __gnu_cxx::__enable_if<(__is_arithmetic<_Tp>::__value + && __is_arithmetic<_Up>::__value), bool>::__type + isunordered(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return __builtin_isunordered(__type(__x), __type(__y)); + } +#endif + +#else + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + fpclassify(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_fpclassify(FP_NAN, FP_INFINITE, FP_NORMAL, + FP_SUBNORMAL, FP_ZERO, __type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isfinite(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isfinite(__type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isinf(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isinf(__type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isnan(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isnan(__type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isnormal(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isnormal(__type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + signbit(_Tp __f) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_signbit(__type(__f)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isgreater(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isgreater(__type(__f1), __type(__f2)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isgreaterequal(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isgreaterequal(__type(__f1), __type(__f2)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isless(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isless(__type(__f1), __type(__f2)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + islessequal(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_islessequal(__type(__f1), __type(__f2)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + islessgreater(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_islessgreater(__type(__f1), __type(__f2)); + } + + template + inline typename __gnu_cxx::__enable_if<__is_arithmetic<_Tp>::__value, + int>::__type + isunordered(_Tp __f1, _Tp __f2) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __builtin_isunordered(__type(__f1), __type(__f2)); + } + +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif /* _GLIBCXX_USE_C99_FP_MACROS_DYNAMIC */ +#endif + +#if __cplusplus >= 201103L + +#ifdef _GLIBCXX_USE_C99_MATH_TR1 + +#undef acosh +#undef acoshf +#undef acoshl +#undef asinh +#undef asinhf +#undef asinhl +#undef atanh +#undef atanhf +#undef atanhl +#undef cbrt +#undef cbrtf +#undef cbrtl +#undef copysign +#undef copysignf +#undef copysignl +#undef erf +#undef erff +#undef erfl +#undef erfc +#undef erfcf +#undef erfcl +#undef exp2 +#undef exp2f +#undef exp2l +#undef expm1 +#undef expm1f +#undef expm1l +#undef fdim +#undef fdimf +#undef fdiml +#undef fma +#undef fmaf +#undef fmal +#undef fmax +#undef fmaxf +#undef fmaxl +#undef fmin +#undef fminf +#undef fminl +#undef hypot +#undef hypotf +#undef hypotl +#undef ilogb +#undef ilogbf +#undef ilogbl +#undef lgamma +#undef lgammaf +#undef lgammal +#ifndef _GLIBCXX_NO_C99_ROUNDING_FUNCS +#undef llrint +#undef llrintf +#undef llrintl +#undef llround +#undef llroundf +#undef llroundl +#endif +#undef log1p +#undef log1pf +#undef log1pl +#undef log2 +#undef log2f +#undef log2l +#undef logb +#undef logbf +#undef logbl +#undef lrint +#undef lrintf +#undef lrintl +#undef lround +#undef lroundf +#undef lroundl +#undef nan +#undef nanf +#undef nanl +#undef nearbyint +#undef nearbyintf +#undef nearbyintl +#undef nextafter +#undef nextafterf +#undef nextafterl +#undef nexttoward +#undef nexttowardf +#undef nexttowardl +#undef remainder +#undef remainderf +#undef remainderl +#undef remquo +#undef remquof +#undef remquol +#undef rint +#undef rintf +#undef rintl +#undef round +#undef roundf +#undef roundl +#undef scalbln +#undef scalblnf +#undef scalblnl +#undef scalbn +#undef scalbnf +#undef scalbnl +#undef tgamma +#undef tgammaf +#undef tgammal +#undef trunc +#undef truncf +#undef truncl + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#ifndef __AVR__ + // types + using ::double_t; + using ::float_t; + + // functions + using ::acosh; + using ::acoshf; + using ::acoshl; + + using ::asinh; + using ::asinhf; + using ::asinhl; + + using ::atanh; + using ::atanhf; + using ::atanhl; + + using ::cbrt; + using ::cbrtf; + using ::cbrtl; + + using ::copysign; + using ::copysignf; + using ::copysignl; + + using ::erf; + using ::erff; + using ::erfl; + + using ::erfc; + using ::erfcf; + using ::erfcl; + + using ::exp2; + using ::exp2f; + using ::exp2l; + + using ::expm1; + using ::expm1f; + using ::expm1l; + + using ::fdim; + using ::fdimf; + using ::fdiml; + + using ::fma; + using ::fmaf; + using ::fmal; + + using ::fmax; + using ::fmaxf; + using ::fmaxl; + + using ::fmin; + using ::fminf; + using ::fminl; + + using ::hypot; + using ::hypotf; + using ::hypotl; + + using ::ilogb; + using ::ilogbf; + using ::ilogbl; + + using ::lgamma; + using ::lgammaf; + using ::lgammal; + +#ifndef _GLIBCXX_NO_C99_ROUNDING_FUNCS + using ::llrint; + using ::llrintf; + using ::llrintl; + + using ::llround; + using ::llroundf; + using ::llroundl; +#endif + + using ::log1p; + using ::log1pf; + using ::log1pl; + + using ::log2; + using ::log2f; + using ::log2l; + + using ::logb; + using ::logbf; + using ::logbl; + + using ::lrint; + using ::lrintf; + using ::lrintl; + + using ::lround; + using ::lroundf; + using ::lroundl; + + using ::nan; + using ::nanf; + using ::nanl; + + using ::nearbyint; + using ::nearbyintf; + using ::nearbyintl; + + using ::nextafter; + using ::nextafterf; + using ::nextafterl; + + using ::nexttoward; + using ::nexttowardf; + using ::nexttowardl; + + using ::remainder; + using ::remainderf; + using ::remainderl; + + using ::remquo; + using ::remquof; + using ::remquol; + + using ::rint; + using ::rintf; + using ::rintl; + + using ::round; + using ::roundf; + using ::roundl; + + using ::scalbln; + using ::scalblnf; + using ::scalblnl; + + using ::scalbn; + using ::scalbnf; + using ::scalbnl; + + using ::tgamma; + using ::tgammaf; + using ::tgammal; + + using ::trunc; + using ::truncf; + using ::truncl; + +#else // __AVR__ + + using ::round; + + constexpr double + acosh(double __x) + { return __builtin_acosh(__x); } + + constexpr double + asinh(double __x) + { return __builtin_asinh(__x); } + + constexpr double + atanh(double __x) + { return __builtin_atanh(__x); } + + constexpr double + cbrt(double __x) + { return __builtin_cbrt(__x); } + + constexpr double + copysign(double __x, double __y) + { return __builtin_copysign(__x, __y); } + + constexpr double + erf(double __x) + { return __builtin_erf(__x); } + + constexpr double + erfc(double __x) + { return __builtin_erfc(__x); } + + constexpr double + exp2(double __x) + { return __builtin_exp2(__x); } + + constexpr double + expm1(double __x) + { return __builtin_expm1(__x); } + + constexpr double + fdim(double __x, double __y) + { return __builtin_fdim(__x, __y); } + + constexpr double + fma(double __x, double __y, double __z) + { return __builtin_fma(__x, __y, __z); } + + constexpr double + fmax(double __x, double __y) + { return __builtin_fmax(__x, __y); } + + constexpr double + fmin(double __x, double __y) + { return __builtin_fmin(__x, __y); } + + constexpr double + hypot(double __x, double __y) + { return __builtin_hypot(__x, __y); } + + constexpr double + ilogb(double __x) + { return __builtin_ilogb(__x); } + + constexpr double + lgamma(double __x) + { return __builtin_lgamma(__x); } + + constexpr long long + llrint(double __x) + { return __builtin_llrint(__x); } + + constexpr long long + llround(double __x) + { return __builtin_llround(__x); } + + constexpr double + log1p(double __x) + { return __builtin_log1p(__x); } + + constexpr double + log2(double __x) + { return __builtin_log2(__x); } + + constexpr double + logb(double __x) + { return __builtin_logb(__x); } + + constexpr long + lrint(double __x) + { return __builtin_lrint(__x); } + + constexpr long + lround(double __x) + { return __builtin_lround(__x); } + + constexpr double + nearbyint(double __x) + { return __builtin_nearbyint(__x); } + + constexpr double + nextafter(double __x, double __y) + { return __builtin_nextafter(__x, __y); } + + constexpr double + nexttoward(double __x, double __y) + { return __builtin_nexttoward(__x, __y); } + + constexpr double + remainder(double __x, double __y) + { return __builtin_remainder(__x, __y); } + + constexpr double + remquo(double __x, double __y, int * __pquo) + { return __builtin_remquo(__x, __y, __pquo); } + + constexpr double + rint(double __x) + { return __builtin_rint(__x); } + + constexpr double + scalbln(double __x, long __ex) + { return __builtin_scalbln(__x, __ex); } + + constexpr double + scalbn(double __x, int __ex) + { return __builtin_scalbn(__x, __ex); } + + constexpr double + tgamma(double __x) + { return __builtin_tgamma(__x); } + + constexpr double + trunc(double __x) + { return __builtin_trunc(__x); } + + +#endif // __AVR__ + +#ifndef __AVR__ + + /// Additional overloads. +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + acosh(float __x) + { return __builtin_acoshf(__x); } + + constexpr long double + acosh(long double __x) + { return __builtin_acoshl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + acosh(_Tp __x) + { return __builtin_acosh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + asinh(float __x) + { return __builtin_asinhf(__x); } + + constexpr long double + asinh(long double __x) + { return __builtin_asinhl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + asinh(_Tp __x) + { return __builtin_asinh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + atanh(float __x) + { return __builtin_atanhf(__x); } + + constexpr long double + atanh(long double __x) + { return __builtin_atanhl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + atanh(_Tp __x) + { return __builtin_atanh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + cbrt(float __x) + { return __builtin_cbrtf(__x); } + + constexpr long double + cbrt(long double __x) + { return __builtin_cbrtl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cbrt(_Tp __x) + { return __builtin_cbrt(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + copysign(float __x, float __y) + { return __builtin_copysignf(__x, __y); } + + constexpr long double + copysign(long double __x, long double __y) + { return __builtin_copysignl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + copysign(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return copysign(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + erf(float __x) + { return __builtin_erff(__x); } + + constexpr long double + erf(long double __x) + { return __builtin_erfl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + erf(_Tp __x) + { return __builtin_erf(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + erfc(float __x) + { return __builtin_erfcf(__x); } + + constexpr long double + erfc(long double __x) + { return __builtin_erfcl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + erfc(_Tp __x) + { return __builtin_erfc(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + exp2(float __x) + { return __builtin_exp2f(__x); } + + constexpr long double + exp2(long double __x) + { return __builtin_exp2l(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + exp2(_Tp __x) + { return __builtin_exp2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + expm1(float __x) + { return __builtin_expm1f(__x); } + + constexpr long double + expm1(long double __x) + { return __builtin_expm1l(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + expm1(_Tp __x) + { return __builtin_expm1(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fdim(float __x, float __y) + { return __builtin_fdimf(__x, __y); } + + constexpr long double + fdim(long double __x, long double __y) + { return __builtin_fdiml(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fdim(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fdim(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fma(float __x, float __y, float __z) + // { return __builtin_fmaf(__x, __y, __z); } + { return __builtin_fma(__x, __y, __z); } // AVR: float = double + + constexpr long double + fma(long double __x, long double __y, long double __z) + { return __builtin_fmal(__x, __y, __z); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type + fma(_Tp __x, _Up __y, _Vp __z) + { + typedef typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type __type; + return fma(__type(__x), __type(__y), __type(__z)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fmax(float __x, float __y) + { return __builtin_fmaxf(__x, __y); } + + constexpr long double + fmax(long double __x, long double __y) + { return __builtin_fmaxl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmax(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmax(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fmin(float __x, float __y) + { return __builtin_fminf(__x, __y); } + + constexpr long double + fmin(long double __x, long double __y) + { return __builtin_fminl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmin(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmin(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + hypot(float __x, float __y) + { return __builtin_hypotf(__x, __y); } + + constexpr long double + hypot(long double __x, long double __y) + { return __builtin_hypotl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + hypot(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return hypot(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr int + ilogb(float __x) + { return __builtin_ilogbf(__x); } + + constexpr int + ilogb(long double __x) + { return __builtin_ilogbl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + int>::__type + ilogb(_Tp __x) + { return __builtin_ilogb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + lgamma(float __x) + { return __builtin_lgammaf(__x); } + + constexpr long double + lgamma(long double __x) + { return __builtin_lgammal(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + lgamma(_Tp __x) + { return __builtin_lgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long long + llrint(float __x) + { return __builtin_llrintf(__x); } + + constexpr long long + llrint(long double __x) + { return __builtin_llrintl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long long>::__type + llrint(_Tp __x) + { return __builtin_llrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long long + llround(float __x) + { return __builtin_llroundf(__x); } + + constexpr long long + llround(long double __x) + { return __builtin_llroundl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long long>::__type + llround(_Tp __x) + { return __builtin_llround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + log1p(float __x) + { return __builtin_log1pf(__x); } + + constexpr long double + log1p(long double __x) + { return __builtin_log1pl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log1p(_Tp __x) + { return __builtin_log1p(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + // DR 568. + constexpr float + log2(float __x) + { return __builtin_log2f(__x); } + + constexpr long double + log2(long double __x) + { return __builtin_log2l(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log2(_Tp __x) + { return __builtin_log2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + logb(float __x) + { return __builtin_logbf(__x); } + + constexpr long double + logb(long double __x) + { return __builtin_logbl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + logb(_Tp __x) + { return __builtin_logb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long + lrint(float __x) + { return __builtin_lrintf(__x); } + + constexpr long + lrint(long double __x) + { return __builtin_lrintl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long>::__type + lrint(_Tp __x) + { return __builtin_lrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long + lround(float __x) + { return __builtin_lroundf(__x); } + + constexpr long + lround(long double __x) + { return __builtin_lroundl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long>::__type + lround(_Tp __x) + { return __builtin_lround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nearbyint(float __x) + { return __builtin_nearbyintf(__x); } + + constexpr long double + nearbyint(long double __x) + { return __builtin_nearbyintl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + nearbyint(_Tp __x) + { return __builtin_nearbyint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nextafter(float __x, float __y) + { return __builtin_nextafterf(__x, __y); } + + constexpr long double + nextafter(long double __x, long double __y) + { return __builtin_nextafterl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + nextafter(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return nextafter(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nexttoward(float __x, long double __y) + { return __builtin_nexttowardf(__x, __y); } + + constexpr long double + nexttoward(long double __x, long double __y) + { return __builtin_nexttowardl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + nexttoward(_Tp __x, long double __y) + { return __builtin_nexttoward(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + remainder(float __x, float __y) + { return __builtin_remainderf(__x, __y); } + + constexpr long double + remainder(long double __x, long double __y) + { return __builtin_remainderl(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + remainder(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return remainder(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + inline float + remquo(float __x, float __y, int* __pquo) + { return __builtin_remquof(__x, __y, __pquo); } + + inline long double + remquo(long double __x, long double __y, int* __pquo) + { return __builtin_remquol(__x, __y, __pquo); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + inline typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + remquo(_Tp __x, _Up __y, int* __pquo) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return remquo(__type(__x), __type(__y), __pquo); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + rint(float __x) + { return __builtin_rintf(__x); } + + constexpr long double + rint(long double __x) + { return __builtin_rintl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + rint(_Tp __x) + { return __builtin_rint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + round(float __x) + { return __builtin_roundf(__x); } + + constexpr long double + round(long double __x) + { return __builtin_roundl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + round(_Tp __x) + { return __builtin_round(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + scalbln(float __x, long __ex) + { return __builtin_scalblnf(__x, __ex); } + + constexpr long double + scalbln(long double __x, long __ex) + { return __builtin_scalblnl(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + scalbln(_Tp __x, long __ex) + { return __builtin_scalbln(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + scalbn(float __x, int __ex) + { return __builtin_scalbnf(__x, __ex); } + + constexpr long double + scalbn(long double __x, int __ex) + { return __builtin_scalbnl(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + scalbn(_Tp __x, int __ex) + { return __builtin_scalbn(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + tgamma(float __x) + { return __builtin_tgammaf(__x); } + + constexpr long double + tgamma(long double __x) + { return __builtin_tgammal(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tgamma(_Tp __x) + { return __builtin_tgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + trunc(float __x) + { return __builtin_truncf(__x); } + + constexpr long double + trunc(long double __x) + { return __builtin_truncl(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + trunc(_Tp __x) + { return __builtin_trunc(__x); } +#endif + +#else // __AVR__ + +// On AVR, float == double == long double +// All functions must call the double version, not the float or long double +// versions, because they don't exist and cause linker errors. + + /// Additional overloads. +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + acosh(float __x) + { return __builtin_acosh(__x); } + + constexpr long double + acosh(long double __x) + { return __builtin_acosh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + acosh(_Tp __x) + { return __builtin_acosh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + asinh(float __x) + { return __builtin_asinh(__x); } + + constexpr long double + asinh(long double __x) + { return __builtin_asinh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + asinh(_Tp __x) + { return __builtin_asinh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + atanh(float __x) + { return __builtin_atanh(__x); } + + constexpr long double + atanh(long double __x) + { return __builtin_atanh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + atanh(_Tp __x) + { return __builtin_atanh(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + cbrt(float __x) + { return __builtin_cbrt(__x); } + + constexpr long double + cbrt(long double __x) + { return __builtin_cbrt(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + cbrt(_Tp __x) + { return __builtin_cbrt(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + copysign(float __x, float __y) + { return __builtin_copysign(__x, __y); } + + constexpr long double + copysign(long double __x, long double __y) + { return __builtin_copysign(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + copysign(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return copysign(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + erf(float __x) + { return __builtin_erf(__x); } + + constexpr long double + erf(long double __x) + { return __builtin_erf(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + erf(_Tp __x) + { return __builtin_erf(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + erfc(float __x) + { return __builtin_erfc(__x); } + + constexpr long double + erfc(long double __x) + { return __builtin_erfc(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + erfc(_Tp __x) + { return __builtin_erfc(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + exp2(float __x) + { return __builtin_exp2(__x); } + + constexpr long double + exp2(long double __x) + { return __builtin_exp2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + exp2(_Tp __x) + { return __builtin_exp2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + expm1(float __x) + { return __builtin_expm1(__x); } + + constexpr long double + expm1(long double __x) + { return __builtin_expm1(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + expm1(_Tp __x) + { return __builtin_expm1(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fdim(float __x, float __y) + { return __builtin_fdim(__x, __y); } + + constexpr long double + fdim(long double __x, long double __y) + { return __builtin_fdim(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fdim(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fdim(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fma(float __x, float __y, float __z) + // { return __builtin_fma(__x, __y, __z); } + { return __builtin_fma(__x, __y, __z); } // AVR: float = double + + constexpr long double + fma(long double __x, long double __y, long double __z) + { return __builtin_fma(__x, __y, __z); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type + fma(_Tp __x, _Up __y, _Vp __z) + { + typedef typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type __type; + return fma(__type(__x), __type(__y), __type(__z)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fmax(float __x, float __y) + { return __builtin_fmax(__x, __y); } + + constexpr long double + fmax(long double __x, long double __y) + { return __builtin_fmax(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmax(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmax(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + fmin(float __x, float __y) + { return __builtin_fmin(__x, __y); } + + constexpr long double + fmin(long double __x, long double __y) + { return __builtin_fmin(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + fmin(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return fmin(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + hypot(float __x, float __y) + { return __builtin_hypot(__x, __y); } + + constexpr long double + hypot(long double __x, long double __y) + { return __builtin_hypot(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + hypot(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return hypot(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr int + ilogb(float __x) + { return __builtin_ilogb(__x); } + + constexpr int + ilogb(long double __x) + { return __builtin_ilogb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr + typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + int>::__type + ilogb(_Tp __x) + { return __builtin_ilogb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + lgamma(float __x) + { return __builtin_lgamma(__x); } + + constexpr long double + lgamma(long double __x) + { return __builtin_lgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + lgamma(_Tp __x) + { return __builtin_lgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long long + llrint(float __x) + { return __builtin_llrint(__x); } + + constexpr long long + llrint(long double __x) + { return __builtin_llrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long long>::__type + llrint(_Tp __x) + { return __builtin_llrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long long + llround(float __x) + { return __builtin_llround(__x); } + + constexpr long long + llround(long double __x) + { return __builtin_llround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long long>::__type + llround(_Tp __x) + { return __builtin_llround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + log1p(float __x) + { return __builtin_log1p(__x); } + + constexpr long double + log1p(long double __x) + { return __builtin_log1p(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log1p(_Tp __x) + { return __builtin_log1p(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + // DR 568. + constexpr float + log2(float __x) + { return __builtin_log2(__x); } + + constexpr long double + log2(long double __x) + { return __builtin_log2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + log2(_Tp __x) + { return __builtin_log2(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + logb(float __x) + { return __builtin_logb(__x); } + + constexpr long double + logb(long double __x) + { return __builtin_logb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + logb(_Tp __x) + { return __builtin_logb(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long + lrint(float __x) + { return __builtin_lrint(__x); } + + constexpr long + lrint(long double __x) + { return __builtin_lrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long>::__type + lrint(_Tp __x) + { return __builtin_lrint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr long + lround(float __x) + { return __builtin_lround(__x); } + + constexpr long + lround(long double __x) + { return __builtin_lround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + long>::__type + lround(_Tp __x) + { return __builtin_lround(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nearbyint(float __x) + { return __builtin_nearbyint(__x); } + + constexpr long double + nearbyint(long double __x) + { return __builtin_nearbyint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + nearbyint(_Tp __x) + { return __builtin_nearbyint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nextafter(float __x, float __y) + { return __builtin_nextafter(__x, __y); } + + constexpr long double + nextafter(long double __x, long double __y) + { return __builtin_nextafter(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + nextafter(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return nextafter(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + nexttoward(float __x, long double __y) + { return __builtin_nexttoward(__x, __y); } + + constexpr long double + nexttoward(long double __x, long double __y) + { return __builtin_nexttoward(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + nexttoward(_Tp __x, long double __y) + { return __builtin_nexttoward(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + remainder(float __x, float __y) + { return __builtin_remainder(__x, __y); } + + constexpr long double + remainder(long double __x, long double __y) + { return __builtin_remainder(__x, __y); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + remainder(_Tp __x, _Up __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return remainder(__type(__x), __type(__y)); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + inline float + remquo(float __x, float __y, int* __pquo) + { return __builtin_remquo(__x, __y, __pquo); } + + inline long double + remquo(long double __x, long double __y, int* __pquo) + { return __builtin_remquo(__x, __y, __pquo); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + inline typename __gnu_cxx::__promote_2<_Tp, _Up>::__type + remquo(_Tp __x, _Up __y, int* __pquo) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return remquo(__type(__x), __type(__y), __pquo); + } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + rint(float __x) + { return __builtin_rint(__x); } + + constexpr long double + rint(long double __x) + { return __builtin_rint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + rint(_Tp __x) + { return __builtin_rint(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + round(float __x) + { return __builtin_round(__x); } + + constexpr long double + round(long double __x) + { return __builtin_round(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + round(_Tp __x) + { return __builtin_round(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + scalbln(float __x, long __ex) + { return __builtin_scalbln(__x, __ex); } + + constexpr long double + scalbln(long double __x, long __ex) + { return __builtin_scalbln(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + scalbln(_Tp __x, long __ex) + { return __builtin_scalbln(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + scalbn(float __x, int __ex) + { return __builtin_scalbn(__x, __ex); } + + constexpr long double + scalbn(long double __x, int __ex) + { return __builtin_scalbn(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + scalbn(_Tp __x, int __ex) + { return __builtin_scalbn(__x, __ex); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + tgamma(float __x) + { return __builtin_tgamma(__x); } + + constexpr long double + tgamma(long double __x) + { return __builtin_tgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + tgamma(_Tp __x) + { return __builtin_tgamma(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_FP + constexpr float + trunc(float __x) + { return __builtin_trunc(__x); } + + constexpr long double + trunc(long double __x) + { return __builtin_trunc(__x); } +#endif + +#ifndef __CORRECT_ISO_CPP11_MATH_H_PROTO_INT + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + trunc(_Tp __x) + { return __builtin_trunc(__x); } +#endif + +#endif // __AVR__ + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif // _GLIBCXX_USE_C99_MATH_TR1 + +#endif // C++11 + +#if __cplusplus > 201402L +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // [c.math.hypot3], three-dimensional hypotenuse +#define __cpp_lib_hypot 201603 + + template + inline _Tp + __hypot3(_Tp __x, _Tp __y, _Tp __z) + { + __x = std::abs(__x); + __y = std::abs(__y); + __z = std::abs(__z); + if (_Tp __a = __x < __y ? __y < __z ? __z : __y : __x < __z ? __z : __x) + return __a * std::sqrt((__x / __a) * (__x / __a) + + (__y / __a) * (__y / __a) + + (__z / __a) * (__z / __a)); + else + return {}; + } + + inline float + hypot(float __x, float __y, float __z) + { return std::__hypot3(__x, __y, __z); } + + inline double + hypot(double __x, double __y, double __z) + { return std::__hypot3(__x, __y, __z); } + + inline long double + hypot(long double __x, long double __y, long double __z) + { return std::__hypot3(__x, __y, __z); } + + template + typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type + hypot(_Tp __x, _Up __y, _Vp __z) + { + using __type = typename __gnu_cxx::__promote_3<_Tp, _Up, _Vp>::__type; + return std::__hypot3<__type>(__x, __y, __z); + } +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace +#endif // C++17 + + +#if _GLIBCXX_USE_STD_SPEC_FUNCS +# include +#endif + +} // extern "C++" + +#endif diff --git a/AH/STL/Fallback/complex b/AH/STL/Fallback/complex new file mode 100644 index 0000000..cbf1276 --- /dev/null +++ b/AH/STL/Fallback/complex @@ -0,0 +1,1991 @@ +// The template and inlines for the -*- C++ -*- complex number classes. + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/complex + * This is a Standard C++ Library header. + */ + +// +// ISO C++ 14882: 26.2 Complex Numbers +// Note: this is not a conforming implementation. +// Initially implemented by Ulrich Drepper +// Improved by Gabriel Dos Reis +// + +#ifndef _GLIBCXX_COMPLEX +#define _GLIBCXX_COMPLEX 1 + +#pragma GCC system_header + +#include "bits/c++config.h" +#include "bits/cpp_type_traits.h" +#include "ext/type_traits.h" +#include "cmath" +#include "algorithm" +// #include + +// Get rid of a macro possibly defined in +#undef complex + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup complex_numbers Complex Numbers + * @ingroup numerics + * + * Classes and functions for complex numbers. + * @{ + */ + + // Forward declarations. + template class complex; + template<> class complex; + template<> class complex; + template<> class complex; + + /// Return magnitude of @a z. + template _Tp abs(const complex<_Tp>&); + /// Return phase angle of @a z. + template _Tp arg(const complex<_Tp>&); + /// Return @a z magnitude squared. + template _Tp norm(const complex<_Tp>&); + + /// Return complex conjugate of @a z. + template complex<_Tp> conj(const complex<_Tp>&); + /// Return complex with magnitude @a rho and angle @a theta. + template complex<_Tp> polar(const _Tp&, const _Tp& = 0); + + // Transcendentals: + /// Return complex cosine of @a z. + template complex<_Tp> cos(const complex<_Tp>&); + /// Return complex hyperbolic cosine of @a z. + template complex<_Tp> cosh(const complex<_Tp>&); + /// Return complex base e exponential of @a z. + template complex<_Tp> exp(const complex<_Tp>&); + /// Return complex natural logarithm of @a z. + template complex<_Tp> log(const complex<_Tp>&); + /// Return complex base 10 logarithm of @a z. + template complex<_Tp> log10(const complex<_Tp>&); + /// Return @a x to the @a y'th power. + template complex<_Tp> pow(const complex<_Tp>&, int); + /// Return @a x to the @a y'th power. + template complex<_Tp> pow(const complex<_Tp>&, const _Tp&); + /// Return @a x to the @a y'th power. + template complex<_Tp> pow(const complex<_Tp>&, + const complex<_Tp>&); + /// Return @a x to the @a y'th power. + template complex<_Tp> pow(const _Tp&, const complex<_Tp>&); + /// Return complex sine of @a z. + template complex<_Tp> sin(const complex<_Tp>&); + /// Return complex hyperbolic sine of @a z. + template complex<_Tp> sinh(const complex<_Tp>&); + /// Return complex square root of @a z. + template complex<_Tp> sqrt(const complex<_Tp>&); + /// Return complex tangent of @a z. + template complex<_Tp> tan(const complex<_Tp>&); + /// Return complex hyperbolic tangent of @a z. + template complex<_Tp> tanh(const complex<_Tp>&); + + + // 26.2.2 Primary template class complex + /** + * Template to represent complex numbers. + * + * Specializations for float, double, and long double are part of the + * library. Results with any other type are not guaranteed. + * + * @param Tp Type of real and imaginary values. + */ + template + struct complex + { + /// Value typedef. + typedef _Tp value_type; + + /// Default constructor. First parameter is x, second parameter is y. + /// Unspecified parameters default to 0. + _GLIBCXX_CONSTEXPR complex(const _Tp& __r = _Tp(), const _Tp& __i = _Tp()) + : _M_real(__r), _M_imag(__i) { } + + // Let the compiler synthesize the copy constructor +#if __cplusplus >= 201103L + constexpr complex(const complex&) = default; +#endif + + /// Converting constructor. + template + _GLIBCXX_CONSTEXPR complex(const complex<_Up>& __z) + : _M_real(__z.real()), _M_imag(__z.imag()) { } + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + _GLIBCXX_ABI_TAG_CXX11 + constexpr _Tp + real() const { return _M_real; } + + _GLIBCXX_ABI_TAG_CXX11 + constexpr _Tp + imag() const { return _M_imag; } +#else + /// Return real part of complex number. + _Tp& + real() { return _M_real; } + + /// Return real part of complex number. + const _Tp& + real() const { return _M_real; } + + /// Return imaginary part of complex number. + _Tp& + imag() { return _M_imag; } + + /// Return imaginary part of complex number. + const _Tp& + imag() const { return _M_imag; } +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + void + real(_Tp __val) { _M_real = __val; } + + void + imag(_Tp __val) { _M_imag = __val; } + + /// Assign a scalar to this complex number. + complex<_Tp>& operator=(const _Tp&); + + /// Add a scalar to this complex number. + // 26.2.5/1 + complex<_Tp>& + operator+=(const _Tp& __t) + { + _M_real += __t; + return *this; + } + + /// Subtract a scalar from this complex number. + // 26.2.5/3 + complex<_Tp>& + operator-=(const _Tp& __t) + { + _M_real -= __t; + return *this; + } + + /// Multiply this complex number by a scalar. + complex<_Tp>& operator*=(const _Tp&); + /// Divide this complex number by a scalar. + complex<_Tp>& operator/=(const _Tp&); + + // Let the compiler synthesize the copy assignment operator +#if __cplusplus >= 201103L + complex& operator=(const complex&) = default; +#endif + + /// Assign another complex number to this one. + template + complex<_Tp>& operator=(const complex<_Up>&); + /// Add another complex number to this one. + template + complex<_Tp>& operator+=(const complex<_Up>&); + /// Subtract another complex number from this one. + template + complex<_Tp>& operator-=(const complex<_Up>&); + /// Multiply this complex number by another. + template + complex<_Tp>& operator*=(const complex<_Up>&); + /// Divide this complex number by another. + template + complex<_Tp>& operator/=(const complex<_Up>&); + + _GLIBCXX_CONSTEXPR complex __rep() const + { return *this; } + + private: + _Tp _M_real; + _Tp _M_imag; + }; + + template + complex<_Tp>& + complex<_Tp>::operator=(const _Tp& __t) + { + _M_real = __t; + _M_imag = _Tp(); + return *this; + } + + // 26.2.5/5 + template + complex<_Tp>& + complex<_Tp>::operator*=(const _Tp& __t) + { + _M_real *= __t; + _M_imag *= __t; + return *this; + } + + // 26.2.5/7 + template + complex<_Tp>& + complex<_Tp>::operator/=(const _Tp& __t) + { + _M_real /= __t; + _M_imag /= __t; + return *this; + } + + template + template + complex<_Tp>& + complex<_Tp>::operator=(const complex<_Up>& __z) + { + _M_real = __z.real(); + _M_imag = __z.imag(); + return *this; + } + + // 26.2.5/9 + template + template + complex<_Tp>& + complex<_Tp>::operator+=(const complex<_Up>& __z) + { + _M_real += __z.real(); + _M_imag += __z.imag(); + return *this; + } + + // 26.2.5/11 + template + template + complex<_Tp>& + complex<_Tp>::operator-=(const complex<_Up>& __z) + { + _M_real -= __z.real(); + _M_imag -= __z.imag(); + return *this; + } + + // 26.2.5/13 + // XXX: This is a grammar school implementation. + template + template + complex<_Tp>& + complex<_Tp>::operator*=(const complex<_Up>& __z) + { + const _Tp __r = _M_real * __z.real() - _M_imag * __z.imag(); + _M_imag = _M_real * __z.imag() + _M_imag * __z.real(); + _M_real = __r; + return *this; + } + + // 26.2.5/15 + // XXX: This is a grammar school implementation. + template + template + complex<_Tp>& + complex<_Tp>::operator/=(const complex<_Up>& __z) + { + const _Tp __r = _M_real * __z.real() + _M_imag * __z.imag(); + const _Tp __n = std::norm(__z); + _M_imag = (_M_imag * __z.real() - _M_real * __z.imag()) / __n; + _M_real = __r / __n; + return *this; + } + + // Operators: + //@{ + /// Return new complex value @a x plus @a y. + template + inline complex<_Tp> + operator+(const complex<_Tp>& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __x; + __r += __y; + return __r; + } + + template + inline complex<_Tp> + operator+(const complex<_Tp>& __x, const _Tp& __y) + { + complex<_Tp> __r = __x; + __r += __y; + return __r; + } + + template + inline complex<_Tp> + operator+(const _Tp& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __y; + __r += __x; + return __r; + } + //@} + + //@{ + /// Return new complex value @a x minus @a y. + template + inline complex<_Tp> + operator-(const complex<_Tp>& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __x; + __r -= __y; + return __r; + } + + template + inline complex<_Tp> + operator-(const complex<_Tp>& __x, const _Tp& __y) + { + complex<_Tp> __r = __x; + __r -= __y; + return __r; + } + + template + inline complex<_Tp> + operator-(const _Tp& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r(__x, -__y.imag()); + __r -= __y.real(); + return __r; + } + //@} + + //@{ + /// Return new complex value @a x times @a y. + template + inline complex<_Tp> + operator*(const complex<_Tp>& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __x; + __r *= __y; + return __r; + } + + template + inline complex<_Tp> + operator*(const complex<_Tp>& __x, const _Tp& __y) + { + complex<_Tp> __r = __x; + __r *= __y; + return __r; + } + + template + inline complex<_Tp> + operator*(const _Tp& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __y; + __r *= __x; + return __r; + } + //@} + + //@{ + /// Return new complex value @a x divided by @a y. + template + inline complex<_Tp> + operator/(const complex<_Tp>& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __x; + __r /= __y; + return __r; + } + + template + inline complex<_Tp> + operator/(const complex<_Tp>& __x, const _Tp& __y) + { + complex<_Tp> __r = __x; + __r /= __y; + return __r; + } + + template + inline complex<_Tp> + operator/(const _Tp& __x, const complex<_Tp>& __y) + { + complex<_Tp> __r = __x; + __r /= __y; + return __r; + } + //@} + + /// Return @a x. + template + inline complex<_Tp> + operator+(const complex<_Tp>& __x) + { return __x; } + + /// Return complex negation of @a x. + template + inline complex<_Tp> + operator-(const complex<_Tp>& __x) + { return complex<_Tp>(-__x.real(), -__x.imag()); } + + //@{ + /// Return true if @a x is equal to @a y. + template + inline _GLIBCXX_CONSTEXPR bool + operator==(const complex<_Tp>& __x, const complex<_Tp>& __y) + { return __x.real() == __y.real() && __x.imag() == __y.imag(); } + + template + inline _GLIBCXX_CONSTEXPR bool + operator==(const complex<_Tp>& __x, const _Tp& __y) + { return __x.real() == __y && __x.imag() == _Tp(); } + + template + inline _GLIBCXX_CONSTEXPR bool + operator==(const _Tp& __x, const complex<_Tp>& __y) + { return __x == __y.real() && _Tp() == __y.imag(); } + //@} + + //@{ + /// Return false if @a x is equal to @a y. + template + inline _GLIBCXX_CONSTEXPR bool + operator!=(const complex<_Tp>& __x, const complex<_Tp>& __y) + { return __x.real() != __y.real() || __x.imag() != __y.imag(); } + + template + inline _GLIBCXX_CONSTEXPR bool + operator!=(const complex<_Tp>& __x, const _Tp& __y) + { return __x.real() != __y || __x.imag() != _Tp(); } + + template + inline _GLIBCXX_CONSTEXPR bool + operator!=(const _Tp& __x, const complex<_Tp>& __y) + { return __x != __y.real() || _Tp() != __y.imag(); } + //@} + +#ifndef __AVR__ + /// Extraction operator for complex values. + template + basic_istream<_CharT, _Traits>& + operator>>(basic_istream<_CharT, _Traits>& __is, complex<_Tp>& __x) + { + _Tp __re_x, __im_x; + _CharT __ch = _CharT(); + __is >> __ch; + if (__ch == '(') + { + __is >> __re_x >> __ch; + if (__ch == ',') + { + __is >> __im_x >> __ch; + if (__ch == ')') + __x = complex<_Tp>(__re_x, __im_x); + else + __is.setstate(ios_base::failbit); + } + else if (__ch == ')') + __x = __re_x; + else + __is.setstate(ios_base::failbit); + } + else if (__is) + { + __is.putback(__ch); + if (__is >> __re_x) + __x = __re_x; + else + __is.setstate(ios_base::failbit); + } + return __is; + } + + /// Insertion operator for complex values. + template + basic_ostream<_CharT, _Traits>& + operator<<(basic_ostream<_CharT, _Traits>& __os, const complex<_Tp>& __x) + { + basic_ostringstream<_CharT, _Traits> __s; + __s.flags(__os.flags()); + __s.imbue(__os.getloc()); + __s.precision(__os.precision()); + __s << '(' << __x.real() << ',' << __x.imag() << ')'; + return __os << __s.str(); + } +#endif // __AVR__ + + // Values +#if __cplusplus >= 201103L + template + constexpr _Tp + real(const complex<_Tp>& __z) + { return __z.real(); } + + template + constexpr _Tp + imag(const complex<_Tp>& __z) + { return __z.imag(); } +#else + template + inline _Tp& + real(complex<_Tp>& __z) + { return __z.real(); } + + template + inline const _Tp& + real(const complex<_Tp>& __z) + { return __z.real(); } + + template + inline _Tp& + imag(complex<_Tp>& __z) + { return __z.imag(); } + + template + inline const _Tp& + imag(const complex<_Tp>& __z) + { return __z.imag(); } +#endif + + // 26.2.7/3 abs(__z): Returns the magnitude of __z. + template + inline _Tp + __complex_abs(const complex<_Tp>& __z) + { + _Tp __x = __z.real(); + _Tp __y = __z.imag(); + const _Tp __s = std::max(abs(__x), abs(__y)); + if (__s == _Tp()) // well ... + return __s; + __x /= __s; + __y /= __s; + return __s * sqrt(__x * __x + __y * __y); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline float + __complex_abs(__complex__ float __z) { return __builtin_cabsf(__z); } + + inline double + __complex_abs(__complex__ double __z) { return __builtin_cabs(__z); } + + inline long double + __complex_abs(const __complex__ long double& __z) + { return __builtin_cabsl(__z); } + + template + inline _Tp + abs(const complex<_Tp>& __z) { return __complex_abs(__z.__rep()); } +#else + template + inline _Tp + abs(const complex<_Tp>& __z) { return __complex_abs(__z); } +#endif + + + // 26.2.7/4: arg(__z): Returns the phase angle of __z. + template + inline _Tp + __complex_arg(const complex<_Tp>& __z) + { return atan2(__z.imag(), __z.real()); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline float + __complex_arg(__complex__ float __z) { return __builtin_cargf(__z); } + + inline double + __complex_arg(__complex__ double __z) { return __builtin_carg(__z); } + + inline long double + __complex_arg(const __complex__ long double& __z) + { return __builtin_cargl(__z); } + + template + inline _Tp + arg(const complex<_Tp>& __z) { return __complex_arg(__z.__rep()); } +#else + template + inline _Tp + arg(const complex<_Tp>& __z) { return __complex_arg(__z); } +#endif + + // 26.2.7/5: norm(__z) returns the squared magnitude of __z. + // As defined, norm() is -not- a norm is the common mathematical + // sense used in numerics. The helper class _Norm_helper<> tries to + // distinguish between builtin floating point and the rest, so as + // to deliver an answer as close as possible to the real value. + template + struct _Norm_helper + { + template + static inline _Tp _S_do_it(const complex<_Tp>& __z) + { + const _Tp __x = __z.real(); + const _Tp __y = __z.imag(); + return __x * __x + __y * __y; + } + }; + + template<> + struct _Norm_helper + { + template + static inline _Tp _S_do_it(const complex<_Tp>& __z) + { + _Tp __res = std::abs(__z); + return __res * __res; + } + }; + + template + inline _Tp + norm(const complex<_Tp>& __z) + { + return _Norm_helper<__is_floating<_Tp>::__value + && !_GLIBCXX_FAST_MATH>::_S_do_it(__z); + } + + template + inline complex<_Tp> + polar(const _Tp& __rho, const _Tp& __theta) + { + __glibcxx_assert( __rho >= 0 ); + return complex<_Tp>(__rho * cos(__theta), __rho * sin(__theta)); + } + + template + inline complex<_Tp> + conj(const complex<_Tp>& __z) + { return complex<_Tp>(__z.real(), -__z.imag()); } + + // Transcendentals + + // 26.2.8/1 cos(__z): Returns the cosine of __z. + template + inline complex<_Tp> + __complex_cos(const complex<_Tp>& __z) + { + const _Tp __x = __z.real(); + const _Tp __y = __z.imag(); + return complex<_Tp>(cos(__x) * cosh(__y), -sin(__x) * sinh(__y)); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_cos(__complex__ float __z) { return __builtin_ccosf(__z); } + + inline __complex__ double + __complex_cos(__complex__ double __z) { return __builtin_ccos(__z); } + + inline __complex__ long double + __complex_cos(const __complex__ long double& __z) + { return __builtin_ccosl(__z); } + + template + inline complex<_Tp> + cos(const complex<_Tp>& __z) { return __complex_cos(__z.__rep()); } +#else + template + inline complex<_Tp> + cos(const complex<_Tp>& __z) { return __complex_cos(__z); } +#endif + + // 26.2.8/2 cosh(__z): Returns the hyperbolic cosine of __z. + template + inline complex<_Tp> + __complex_cosh(const complex<_Tp>& __z) + { + const _Tp __x = __z.real(); + const _Tp __y = __z.imag(); + return complex<_Tp>(cosh(__x) * cos(__y), sinh(__x) * sin(__y)); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_cosh(__complex__ float __z) { return __builtin_ccoshf(__z); } + + inline __complex__ double + __complex_cosh(__complex__ double __z) { return __builtin_ccosh(__z); } + + inline __complex__ long double + __complex_cosh(const __complex__ long double& __z) + { return __builtin_ccoshl(__z); } + + template + inline complex<_Tp> + cosh(const complex<_Tp>& __z) { return __complex_cosh(__z.__rep()); } +#else + template + inline complex<_Tp> + cosh(const complex<_Tp>& __z) { return __complex_cosh(__z); } +#endif + + // 26.2.8/3 exp(__z): Returns the complex base e exponential of x + template + inline complex<_Tp> + __complex_exp(const complex<_Tp>& __z) + { return std::polar<_Tp>(exp(__z.real()), __z.imag()); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_exp(__complex__ float __z) { return __builtin_cexpf(__z); } + + inline __complex__ double + __complex_exp(__complex__ double __z) { return __builtin_cexp(__z); } + + inline __complex__ long double + __complex_exp(const __complex__ long double& __z) + { return __builtin_cexpl(__z); } + + template + inline complex<_Tp> + exp(const complex<_Tp>& __z) { return __complex_exp(__z.__rep()); } +#else + template + inline complex<_Tp> + exp(const complex<_Tp>& __z) { return __complex_exp(__z); } +#endif + + // 26.2.8/5 log(__z): Returns the natural complex logarithm of __z. + // The branch cut is along the negative axis. + template + inline complex<_Tp> + __complex_log(const complex<_Tp>& __z) + { return complex<_Tp>(log(std::abs(__z)), std::arg(__z)); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_log(__complex__ float __z) { return __builtin_clogf(__z); } + + inline __complex__ double + __complex_log(__complex__ double __z) { return __builtin_clog(__z); } + + inline __complex__ long double + __complex_log(const __complex__ long double& __z) + { return __builtin_clogl(__z); } + + template + inline complex<_Tp> + log(const complex<_Tp>& __z) { return __complex_log(__z.__rep()); } +#else + template + inline complex<_Tp> + log(const complex<_Tp>& __z) { return __complex_log(__z); } +#endif + + template + inline complex<_Tp> + log10(const complex<_Tp>& __z) + { return std::log(__z) / log(_Tp(10.0)); } + + // 26.2.8/10 sin(__z): Returns the sine of __z. + template + inline complex<_Tp> + __complex_sin(const complex<_Tp>& __z) + { + const _Tp __x = __z.real(); + const _Tp __y = __z.imag(); + return complex<_Tp>(sin(__x) * cosh(__y), cos(__x) * sinh(__y)); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_sin(__complex__ float __z) { return __builtin_csinf(__z); } + + inline __complex__ double + __complex_sin(__complex__ double __z) { return __builtin_csin(__z); } + + inline __complex__ long double + __complex_sin(const __complex__ long double& __z) + { return __builtin_csinl(__z); } + + template + inline complex<_Tp> + sin(const complex<_Tp>& __z) { return __complex_sin(__z.__rep()); } +#else + template + inline complex<_Tp> + sin(const complex<_Tp>& __z) { return __complex_sin(__z); } +#endif + + // 26.2.8/11 sinh(__z): Returns the hyperbolic sine of __z. + template + inline complex<_Tp> + __complex_sinh(const complex<_Tp>& __z) + { + const _Tp __x = __z.real(); + const _Tp __y = __z.imag(); + return complex<_Tp>(sinh(__x) * cos(__y), cosh(__x) * sin(__y)); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_sinh(__complex__ float __z) { return __builtin_csinhf(__z); } + + inline __complex__ double + __complex_sinh(__complex__ double __z) { return __builtin_csinh(__z); } + + inline __complex__ long double + __complex_sinh(const __complex__ long double& __z) + { return __builtin_csinhl(__z); } + + template + inline complex<_Tp> + sinh(const complex<_Tp>& __z) { return __complex_sinh(__z.__rep()); } +#else + template + inline complex<_Tp> + sinh(const complex<_Tp>& __z) { return __complex_sinh(__z); } +#endif + + // 26.2.8/13 sqrt(__z): Returns the complex square root of __z. + // The branch cut is on the negative axis. + template + complex<_Tp> + __complex_sqrt(const complex<_Tp>& __z) + { + _Tp __x = __z.real(); + _Tp __y = __z.imag(); + + if (__x == _Tp()) + { + _Tp __t = sqrt(abs(__y) / 2); + return complex<_Tp>(__t, __y < _Tp() ? -__t : __t); + } + else + { + _Tp __t = sqrt(2 * (std::abs(__z) + abs(__x))); + _Tp __u = __t / 2; + return __x > _Tp() + ? complex<_Tp>(__u, __y / __t) + : complex<_Tp>(abs(__y) / __t, __y < _Tp() ? -__u : __u); + } + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_sqrt(__complex__ float __z) { return __builtin_csqrtf(__z); } + + inline __complex__ double + __complex_sqrt(__complex__ double __z) { return __builtin_csqrt(__z); } + + inline __complex__ long double + __complex_sqrt(const __complex__ long double& __z) + { return __builtin_csqrtl(__z); } + + template + inline complex<_Tp> + sqrt(const complex<_Tp>& __z) { return __complex_sqrt(__z.__rep()); } +#else + template + inline complex<_Tp> + sqrt(const complex<_Tp>& __z) { return __complex_sqrt(__z); } +#endif + + // 26.2.8/14 tan(__z): Return the complex tangent of __z. + + template + inline complex<_Tp> + __complex_tan(const complex<_Tp>& __z) + { return std::sin(__z) / std::cos(__z); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_tan(__complex__ float __z) { return __builtin_ctanf(__z); } + + inline __complex__ double + __complex_tan(__complex__ double __z) { return __builtin_ctan(__z); } + + inline __complex__ long double + __complex_tan(const __complex__ long double& __z) + { return __builtin_ctanl(__z); } + + template + inline complex<_Tp> + tan(const complex<_Tp>& __z) { return __complex_tan(__z.__rep()); } +#else + template + inline complex<_Tp> + tan(const complex<_Tp>& __z) { return __complex_tan(__z); } +#endif + + + // 26.2.8/15 tanh(__z): Returns the hyperbolic tangent of __z. + + template + inline complex<_Tp> + __complex_tanh(const complex<_Tp>& __z) + { return std::sinh(__z) / std::cosh(__z); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_tanh(__complex__ float __z) { return __builtin_ctanhf(__z); } + + inline __complex__ double + __complex_tanh(__complex__ double __z) { return __builtin_ctanh(__z); } + + inline __complex__ long double + __complex_tanh(const __complex__ long double& __z) + { return __builtin_ctanhl(__z); } + + template + inline complex<_Tp> + tanh(const complex<_Tp>& __z) { return __complex_tanh(__z.__rep()); } +#else + template + inline complex<_Tp> + tanh(const complex<_Tp>& __z) { return __complex_tanh(__z); } +#endif + + + // 26.2.8/9 pow(__x, __y): Returns the complex power base of __x + // raised to the __y-th power. The branch + // cut is on the negative axis. + template + complex<_Tp> + __complex_pow_unsigned(complex<_Tp> __x, unsigned __n) + { + complex<_Tp> __y = __n % 2 ? __x : complex<_Tp>(1); + + while (__n >>= 1) + { + __x *= __x; + if (__n % 2) + __y *= __x; + } + + return __y; + } + + // In C++11 mode we used to implement the resolution of + // DR 844. complex pow return type is ambiguous. + // thus the following overload was disabled in that mode. However, doing + // that causes all sorts of issues, see, for example: + // http://gcc.gnu.org/ml/libstdc++/2013-01/msg00058.html + // and also PR57974. + template + inline complex<_Tp> + pow(const complex<_Tp>& __z, int __n) + { + return __n < 0 + ? complex<_Tp>(1) / std::__complex_pow_unsigned(__z, -(unsigned)__n) + : std::__complex_pow_unsigned(__z, __n); + } + + template + complex<_Tp> + pow(const complex<_Tp>& __x, const _Tp& __y) + { +#if ! _GLIBCXX_USE_C99_COMPLEX + if (__x == _Tp()) + return _Tp(); +#endif + if (__x.imag() == _Tp() && __x.real() > _Tp()) + return pow(__x.real(), __y); + + complex<_Tp> __t = std::log(__x); + return std::polar<_Tp>(exp(__y * __t.real()), __y * __t.imag()); + } + + template + inline complex<_Tp> + __complex_pow(const complex<_Tp>& __x, const complex<_Tp>& __y) + { return __x == _Tp() ? _Tp() : std::exp(__y * std::log(__x)); } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_pow(__complex__ float __x, __complex__ float __y) + { return __builtin_cpowf(__x, __y); } + + inline __complex__ double + __complex_pow(__complex__ double __x, __complex__ double __y) + { return __builtin_cpow(__x, __y); } + + inline __complex__ long double + __complex_pow(const __complex__ long double& __x, + const __complex__ long double& __y) + { return __builtin_cpowl(__x, __y); } + + template + inline complex<_Tp> + pow(const complex<_Tp>& __x, const complex<_Tp>& __y) + { return __complex_pow(__x.__rep(), __y.__rep()); } +#else + template + inline complex<_Tp> + pow(const complex<_Tp>& __x, const complex<_Tp>& __y) + { return __complex_pow(__x, __y); } +#endif + + template + inline complex<_Tp> + pow(const _Tp& __x, const complex<_Tp>& __y) + { + return __x > _Tp() ? std::polar<_Tp>(pow(__x, __y.real()), + __y.imag() * log(__x)) + : std::pow(complex<_Tp>(__x), __y); + } + + /// 26.2.3 complex specializations + /// complex specialization + template<> + struct complex + { + typedef float value_type; + typedef __complex__ float _ComplexT; + + _GLIBCXX_CONSTEXPR complex(_ComplexT __z) : _M_value(__z) { } + + _GLIBCXX_CONSTEXPR complex(float __r = 0.0f, float __i = 0.0f) +#if __cplusplus >= 201103L + : _M_value{ __r, __i } { } +#else + { + __real__ _M_value = __r; + __imag__ _M_value = __i; + } +#endif + + explicit _GLIBCXX_CONSTEXPR complex(const complex&); + explicit _GLIBCXX_CONSTEXPR complex(const complex&); + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + __attribute ((__abi_tag__ ("cxx11"))) + constexpr float + real() const { return __real__ _M_value; } + + __attribute ((__abi_tag__ ("cxx11"))) + constexpr float + imag() const { return __imag__ _M_value; } +#else + float& + real() { return __real__ _M_value; } + + const float& + real() const { return __real__ _M_value; } + + float& + imag() { return __imag__ _M_value; } + + const float& + imag() const { return __imag__ _M_value; } +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + void + real(float __val) { __real__ _M_value = __val; } + + void + imag(float __val) { __imag__ _M_value = __val; } + + complex& + operator=(float __f) + { + _M_value = __f; + return *this; + } + + complex& + operator+=(float __f) + { + _M_value += __f; + return *this; + } + + complex& + operator-=(float __f) + { + _M_value -= __f; + return *this; + } + + complex& + operator*=(float __f) + { + _M_value *= __f; + return *this; + } + + complex& + operator/=(float __f) + { + _M_value /= __f; + return *this; + } + + // Let the compiler synthesize the copy and assignment + // operator. It always does a pretty good job. + // complex& operator=(const complex&); + + template + complex& + operator=(const complex<_Tp>& __z) + { + __real__ _M_value = __z.real(); + __imag__ _M_value = __z.imag(); + return *this; + } + + template + complex& + operator+=(const complex<_Tp>& __z) + { + __real__ _M_value += __z.real(); + __imag__ _M_value += __z.imag(); + return *this; + } + + template + complex& + operator-=(const complex<_Tp>& __z) + { + __real__ _M_value -= __z.real(); + __imag__ _M_value -= __z.imag(); + return *this; + } + + template + complex& + operator*=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value *= __t; + return *this; + } + + template + complex& + operator/=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value /= __t; + return *this; + } + + _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; } + + private: + _ComplexT _M_value; + }; + + /// 26.2.3 complex specializations + /// complex specialization + template<> + struct complex + { + typedef double value_type; + typedef __complex__ double _ComplexT; + + _GLIBCXX_CONSTEXPR complex(_ComplexT __z) : _M_value(__z) { } + + _GLIBCXX_CONSTEXPR complex(double __r = 0.0, double __i = 0.0) +#if __cplusplus >= 201103L + : _M_value{ __r, __i } { } +#else + { + __real__ _M_value = __r; + __imag__ _M_value = __i; + } +#endif + + _GLIBCXX_CONSTEXPR complex(const complex& __z) + : _M_value(__z.__rep()) { } + + explicit _GLIBCXX_CONSTEXPR complex(const complex&); + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + __attribute ((__abi_tag__ ("cxx11"))) + constexpr double + real() const { return __real__ _M_value; } + + __attribute ((__abi_tag__ ("cxx11"))) + constexpr double + imag() const { return __imag__ _M_value; } +#else + double& + real() { return __real__ _M_value; } + + const double& + real() const { return __real__ _M_value; } + + double& + imag() { return __imag__ _M_value; } + + const double& + imag() const { return __imag__ _M_value; } +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + void + real(double __val) { __real__ _M_value = __val; } + + void + imag(double __val) { __imag__ _M_value = __val; } + + complex& + operator=(double __d) + { + _M_value = __d; + return *this; + } + + complex& + operator+=(double __d) + { + _M_value += __d; + return *this; + } + + complex& + operator-=(double __d) + { + _M_value -= __d; + return *this; + } + + complex& + operator*=(double __d) + { + _M_value *= __d; + return *this; + } + + complex& + operator/=(double __d) + { + _M_value /= __d; + return *this; + } + + // The compiler will synthesize this, efficiently. + // complex& operator=(const complex&); + + template + complex& + operator=(const complex<_Tp>& __z) + { + __real__ _M_value = __z.real(); + __imag__ _M_value = __z.imag(); + return *this; + } + + template + complex& + operator+=(const complex<_Tp>& __z) + { + __real__ _M_value += __z.real(); + __imag__ _M_value += __z.imag(); + return *this; + } + + template + complex& + operator-=(const complex<_Tp>& __z) + { + __real__ _M_value -= __z.real(); + __imag__ _M_value -= __z.imag(); + return *this; + } + + template + complex& + operator*=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value *= __t; + return *this; + } + + template + complex& + operator/=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value /= __t; + return *this; + } + + _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; } + + private: + _ComplexT _M_value; + }; + + /// 26.2.3 complex specializations + /// complex specialization + template<> + struct complex + { + typedef long double value_type; + typedef __complex__ long double _ComplexT; + + _GLIBCXX_CONSTEXPR complex(_ComplexT __z) : _M_value(__z) { } + + _GLIBCXX_CONSTEXPR complex(long double __r = 0.0L, + long double __i = 0.0L) +#if __cplusplus >= 201103L + : _M_value{ __r, __i } { } +#else + { + __real__ _M_value = __r; + __imag__ _M_value = __i; + } +#endif + + _GLIBCXX_CONSTEXPR complex(const complex& __z) + : _M_value(__z.__rep()) { } + + _GLIBCXX_CONSTEXPR complex(const complex& __z) + : _M_value(__z.__rep()) { } + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + __attribute ((__abi_tag__ ("cxx11"))) + constexpr long double + real() const { return __real__ _M_value; } + + __attribute ((__abi_tag__ ("cxx11"))) + constexpr long double + imag() const { return __imag__ _M_value; } +#else + long double& + real() { return __real__ _M_value; } + + const long double& + real() const { return __real__ _M_value; } + + long double& + imag() { return __imag__ _M_value; } + + const long double& + imag() const { return __imag__ _M_value; } +#endif + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // DR 387. std::complex over-encapsulated. + void + real(long double __val) { __real__ _M_value = __val; } + + void + imag(long double __val) { __imag__ _M_value = __val; } + + complex& + operator=(long double __r) + { + _M_value = __r; + return *this; + } + + complex& + operator+=(long double __r) + { + _M_value += __r; + return *this; + } + + complex& + operator-=(long double __r) + { + _M_value -= __r; + return *this; + } + + complex& + operator*=(long double __r) + { + _M_value *= __r; + return *this; + } + + complex& + operator/=(long double __r) + { + _M_value /= __r; + return *this; + } + + // The compiler knows how to do this efficiently + // complex& operator=(const complex&); + + template + complex& + operator=(const complex<_Tp>& __z) + { + __real__ _M_value = __z.real(); + __imag__ _M_value = __z.imag(); + return *this; + } + + template + complex& + operator+=(const complex<_Tp>& __z) + { + __real__ _M_value += __z.real(); + __imag__ _M_value += __z.imag(); + return *this; + } + + template + complex& + operator-=(const complex<_Tp>& __z) + { + __real__ _M_value -= __z.real(); + __imag__ _M_value -= __z.imag(); + return *this; + } + + template + complex& + operator*=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value *= __t; + return *this; + } + + template + complex& + operator/=(const complex<_Tp>& __z) + { + _ComplexT __t; + __real__ __t = __z.real(); + __imag__ __t = __z.imag(); + _M_value /= __t; + return *this; + } + + _GLIBCXX_CONSTEXPR _ComplexT __rep() const { return _M_value; } + + private: + _ComplexT _M_value; + }; + + // These bits have to be at the end of this file, so that the + // specializations have all been defined. + inline _GLIBCXX_CONSTEXPR + complex::complex(const complex& __z) + : _M_value(__z.__rep()) { } + + inline _GLIBCXX_CONSTEXPR + complex::complex(const complex& __z) + : _M_value(__z.__rep()) { } + + inline _GLIBCXX_CONSTEXPR + complex::complex(const complex& __z) + : _M_value(__z.__rep()) { } + +#ifndef __AVR__ + // Inhibit implicit instantiations for required instantiations, + // which are defined via explicit instantiations elsewhere. + // NB: This syntax is a GNU extension. +#if _GLIBCXX_EXTERN_TEMPLATE + extern template istream& operator>>(istream&, complex&); + extern template ostream& operator<<(ostream&, const complex&); + extern template istream& operator>>(istream&, complex&); + extern template ostream& operator<<(ostream&, const complex&); + extern template istream& operator>>(istream&, complex&); + extern template ostream& operator<<(ostream&, const complex&); + +#ifdef _GLIBCXX_USE_WCHAR_T + extern template wistream& operator>>(wistream&, complex&); + extern template wostream& operator<<(wostream&, const complex&); + extern template wistream& operator>>(wistream&, complex&); + extern template wostream& operator<<(wostream&, const complex&); + extern template wistream& operator>>(wistream&, complex&); + extern template wostream& operator<<(wostream&, const complex&); +#endif +#endif +#endif // __AVR__ + + // @} group complex_numbers + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // See ext/type_traits.h for the primary template. + template + struct __promote_2, _Up> + { + public: + typedef std::complex::__type> __type; + }; + + template + struct __promote_2<_Tp, std::complex<_Up> > + { + public: + typedef std::complex::__type> __type; + }; + + template + struct __promote_2, std::complex<_Up> > + { + public: + typedef std::complex::__type> __type; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if __cplusplus >= 201103L + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Forward declarations. + template std::complex<_Tp> acos(const std::complex<_Tp>&); + template std::complex<_Tp> asin(const std::complex<_Tp>&); + template std::complex<_Tp> atan(const std::complex<_Tp>&); + + template std::complex<_Tp> acosh(const std::complex<_Tp>&); + template std::complex<_Tp> asinh(const std::complex<_Tp>&); + template std::complex<_Tp> atanh(const std::complex<_Tp>&); + // DR 595. + template _Tp fabs(const std::complex<_Tp>&); + + template + inline std::complex<_Tp> + __complex_acos(const std::complex<_Tp>& __z) + { + const std::complex<_Tp> __t = std::asin(__z); + const _Tp __pi_2 = 1.5707963267948966192313216916397514L; + return std::complex<_Tp>(__pi_2 - __t.real(), -__t.imag()); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_acos(__complex__ float __z) + { return __builtin_cacosf(__z); } + + inline __complex__ double + __complex_acos(__complex__ double __z) + { return __builtin_cacos(__z); } + + inline __complex__ long double + __complex_acos(const __complex__ long double& __z) + { return __builtin_cacosl(__z); } + + template + inline std::complex<_Tp> + acos(const std::complex<_Tp>& __z) + { return __complex_acos(__z.__rep()); } +#else + /// acos(__z) [8.1.2]. + // Effects: Behaves the same as C99 function cacos, defined + // in subclause 7.3.5.1. + template + inline std::complex<_Tp> + acos(const std::complex<_Tp>& __z) + { return __complex_acos(__z); } +#endif + + template + inline std::complex<_Tp> + __complex_asin(const std::complex<_Tp>& __z) + { + std::complex<_Tp> __t(-__z.imag(), __z.real()); + __t = std::asinh(__t); + return std::complex<_Tp>(__t.imag(), -__t.real()); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_asin(__complex__ float __z) + { return __builtin_casinf(__z); } + + inline __complex__ double + __complex_asin(__complex__ double __z) + { return __builtin_casin(__z); } + + inline __complex__ long double + __complex_asin(const __complex__ long double& __z) + { return __builtin_casinl(__z); } + + template + inline std::complex<_Tp> + asin(const std::complex<_Tp>& __z) + { return __complex_asin(__z.__rep()); } +#else + /// asin(__z) [8.1.3]. + // Effects: Behaves the same as C99 function casin, defined + // in subclause 7.3.5.2. + template + inline std::complex<_Tp> + asin(const std::complex<_Tp>& __z) + { return __complex_asin(__z); } +#endif + + template + std::complex<_Tp> + __complex_atan(const std::complex<_Tp>& __z) + { + const _Tp __r2 = __z.real() * __z.real(); + const _Tp __x = _Tp(1.0) - __r2 - __z.imag() * __z.imag(); + + _Tp __num = __z.imag() + _Tp(1.0); + _Tp __den = __z.imag() - _Tp(1.0); + + __num = __r2 + __num * __num; + __den = __r2 + __den * __den; + + return std::complex<_Tp>(_Tp(0.5) * atan2(_Tp(2.0) * __z.real(), __x), + _Tp(0.25) * log(__num / __den)); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_atan(__complex__ float __z) + { return __builtin_catanf(__z); } + + inline __complex__ double + __complex_atan(__complex__ double __z) + { return __builtin_catan(__z); } + + inline __complex__ long double + __complex_atan(const __complex__ long double& __z) + { return __builtin_catanl(__z); } + + template + inline std::complex<_Tp> + atan(const std::complex<_Tp>& __z) + { return __complex_atan(__z.__rep()); } +#else + /// atan(__z) [8.1.4]. + // Effects: Behaves the same as C99 function catan, defined + // in subclause 7.3.5.3. + template + inline std::complex<_Tp> + atan(const std::complex<_Tp>& __z) + { return __complex_atan(__z); } +#endif + + template + std::complex<_Tp> + __complex_acosh(const std::complex<_Tp>& __z) + { + // Kahan's formula. + return _Tp(2.0) * std::log(std::sqrt(_Tp(0.5) * (__z + _Tp(1.0))) + + std::sqrt(_Tp(0.5) * (__z - _Tp(1.0)))); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_acosh(__complex__ float __z) + { return __builtin_cacoshf(__z); } + + inline __complex__ double + __complex_acosh(__complex__ double __z) + { return __builtin_cacosh(__z); } + + inline __complex__ long double + __complex_acosh(const __complex__ long double& __z) + { return __builtin_cacoshl(__z); } + + template + inline std::complex<_Tp> + acosh(const std::complex<_Tp>& __z) + { return __complex_acosh(__z.__rep()); } +#else + /// acosh(__z) [8.1.5]. + // Effects: Behaves the same as C99 function cacosh, defined + // in subclause 7.3.6.1. + template + inline std::complex<_Tp> + acosh(const std::complex<_Tp>& __z) + { return __complex_acosh(__z); } +#endif + + template + std::complex<_Tp> + __complex_asinh(const std::complex<_Tp>& __z) + { + std::complex<_Tp> __t((__z.real() - __z.imag()) + * (__z.real() + __z.imag()) + _Tp(1.0), + _Tp(2.0) * __z.real() * __z.imag()); + __t = std::sqrt(__t); + + return std::log(__t + __z); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_asinh(__complex__ float __z) + { return __builtin_casinhf(__z); } + + inline __complex__ double + __complex_asinh(__complex__ double __z) + { return __builtin_casinh(__z); } + + inline __complex__ long double + __complex_asinh(const __complex__ long double& __z) + { return __builtin_casinhl(__z); } + + template + inline std::complex<_Tp> + asinh(const std::complex<_Tp>& __z) + { return __complex_asinh(__z.__rep()); } +#else + /// asinh(__z) [8.1.6]. + // Effects: Behaves the same as C99 function casin, defined + // in subclause 7.3.6.2. + template + inline std::complex<_Tp> + asinh(const std::complex<_Tp>& __z) + { return __complex_asinh(__z); } +#endif + + template + std::complex<_Tp> + __complex_atanh(const std::complex<_Tp>& __z) + { + const _Tp __i2 = __z.imag() * __z.imag(); + const _Tp __x = _Tp(1.0) - __i2 - __z.real() * __z.real(); + + _Tp __num = _Tp(1.0) + __z.real(); + _Tp __den = _Tp(1.0) - __z.real(); + + __num = __i2 + __num * __num; + __den = __i2 + __den * __den; + + return std::complex<_Tp>(_Tp(0.25) * (log(__num) - log(__den)), + _Tp(0.5) * atan2(_Tp(2.0) * __z.imag(), __x)); + } + +#if _GLIBCXX_USE_C99_COMPLEX_TR1 + inline __complex__ float + __complex_atanh(__complex__ float __z) + { return __builtin_catanhf(__z); } + + inline __complex__ double + __complex_atanh(__complex__ double __z) + { return __builtin_catanh(__z); } + + inline __complex__ long double + __complex_atanh(const __complex__ long double& __z) + { return __builtin_catanhl(__z); } + + template + inline std::complex<_Tp> + atanh(const std::complex<_Tp>& __z) + { return __complex_atanh(__z.__rep()); } +#else + /// atanh(__z) [8.1.7]. + // Effects: Behaves the same as C99 function catanh, defined + // in subclause 7.3.6.3. + template + inline std::complex<_Tp> + atanh(const std::complex<_Tp>& __z) + { return __complex_atanh(__z); } +#endif + + template + inline _Tp + /// fabs(__z) [8.1.8]. + // Effects: Behaves the same as C99 function cabs, defined + // in subclause 7.3.8.1. + fabs(const std::complex<_Tp>& __z) + { return std::abs(__z); } + + /// Additional overloads [8.1.9]. + template + inline typename __gnu_cxx::__promote<_Tp>::__type + arg(_Tp __x) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; +#if (_GLIBCXX11_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) + return std::signbit(__x) ? __type(3.1415926535897932384626433832795029L) + : __type(); +#else + return std::arg(std::complex<__type>(__x)); +#endif + } + + template + _GLIBCXX_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type + imag(_Tp) + { return _Tp(); } + + template + inline typename __gnu_cxx::__promote<_Tp>::__type + norm(_Tp __x) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return __type(__x) * __type(__x); + } + + template + _GLIBCXX_CONSTEXPR inline typename __gnu_cxx::__promote<_Tp>::__type + real(_Tp __x) + { return __x; } + + template + inline std::complex::__type> + pow(const std::complex<_Tp>& __x, const _Up& __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return std::pow(std::complex<__type>(__x), __type(__y)); + } + + template + inline std::complex::__type> + pow(const _Tp& __x, const std::complex<_Up>& __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return std::pow(__type(__x), std::complex<__type>(__y)); + } + + template + inline std::complex::__type> + pow(const std::complex<_Tp>& __x, const std::complex<_Up>& __y) + { + typedef typename __gnu_cxx::__promote_2<_Tp, _Up>::__type __type; + return std::pow(std::complex<__type>(__x), + std::complex<__type>(__y)); + } + + // Forward declarations. + // DR 781. + template std::complex<_Tp> proj(const std::complex<_Tp>&); + + template + std::complex<_Tp> + __complex_proj(const std::complex<_Tp>& __z) + { + const _Tp __den = (__z.real() * __z.real() + + __z.imag() * __z.imag() + _Tp(1.0)); + + return std::complex<_Tp>((_Tp(2.0) * __z.real()) / __den, + (_Tp(2.0) * __z.imag()) / __den); + } + +#if _GLIBCXX_USE_C99_COMPLEX + inline __complex__ float + __complex_proj(__complex__ float __z) + { return __builtin_cprojf(__z); } + + inline __complex__ double + __complex_proj(__complex__ double __z) + { return __builtin_cproj(__z); } + + inline __complex__ long double + __complex_proj(const __complex__ long double& __z) + { return __builtin_cprojl(__z); } + + template + inline std::complex<_Tp> + proj(const std::complex<_Tp>& __z) + { return __complex_proj(__z.__rep()); } +#else + template + inline std::complex<_Tp> + proj(const std::complex<_Tp>& __z) + { return __complex_proj(__z); } +#endif + + template + inline std::complex::__type> + proj(_Tp __x) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return std::proj(std::complex<__type>(__x)); + } + + template + inline std::complex::__type> + conj(_Tp __x) + { + typedef typename __gnu_cxx::__promote<_Tp>::__type __type; + return std::complex<__type>(__x, -__type()); + } + +_GLIBCXX_END_NAMESPACE_VERSION + +#if __cplusplus > 201103L + +inline namespace literals { +inline namespace complex_literals { +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#define __cpp_lib_complex_udls 201309 + + constexpr std::complex + operator""if(long double __num) + { return std::complex{0.0F, static_cast(__num)}; } + + constexpr std::complex + operator""if(unsigned long long __num) + { return std::complex{0.0F, static_cast(__num)}; } + + constexpr std::complex + operator""i(long double __num) + { return std::complex{0.0, static_cast(__num)}; } + + constexpr std::complex + operator""i(unsigned long long __num) + { return std::complex{0.0, static_cast(__num)}; } + + constexpr std::complex + operator""il(long double __num) + { return std::complex{0.0L, __num}; } + + constexpr std::complex + operator""il(unsigned long long __num) + { return std::complex{0.0L, static_cast(__num)}; } + +_GLIBCXX_END_NAMESPACE_VERSION +} // inline namespace complex_literals +} // inline namespace literals + +#endif // C++14 + +} // namespace + +#endif // C++11 + +#endif /* _GLIBCXX_COMPLEX */ diff --git a/AH/STL/Fallback/cstddef b/AH/STL/Fallback/cstddef new file mode 100644 index 0000000..c6b0f9c --- /dev/null +++ b/AH/STL/Fallback/cstddef @@ -0,0 +1,191 @@ +// -*- C++ -*- forwarding header. + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file cstddef + * This is a Standard C++ Library file. You should @c \#include this file + * in your programs, rather than any of the @a *.h implementation files. + * + * This is the C++ version of the Standard C Library header @c stddef.h, + * and its contents are (mostly) the same as that header, but are all + * contained in the namespace @c std (except for names which are defined + * as macros in C). + */ + +// +// ISO C++ 14882: 18.1 Types +// + +#ifndef _GLIBCXX_CSTDDEF +#define _GLIBCXX_CSTDDEF 1 + +#pragma GCC system_header + +#undef __need_wchar_t +#undef __need_ptrdiff_t +#undef __need_size_t +#undef __need_NULL +#undef __need_wint_t +#include "bits/c++config.h" +#include + +#if __cplusplus >= 201103L +namespace std +{ + // We handle size_t, ptrdiff_t, and nullptr_t in c++config.h. + using ::max_align_t; +} +#endif + +#if __cplusplus >= 201703L +namespace std +{ +#define __cpp_lib_byte 201603 + + /// std::byte + enum class byte : unsigned char {}; + + template struct __byte_operand { }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; +#ifdef _GLIBCXX_USE_WCHAR_T + template<> struct __byte_operand { using __type = byte; }; +#endif + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; + template<> struct __byte_operand { using __type = byte; }; +#if defined(__GLIBCXX_TYPE_INT_N_0) + template<> struct __byte_operand<__GLIBCXX_TYPE_INT_N_0> + { using __type = byte; }; + template<> struct __byte_operand + { using __type = byte; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + template<> struct __byte_operand<__GLIBCXX_TYPE_INT_N_1> + { using __type = byte; }; + template<> struct __byte_operand + { using __type = byte; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + template<> struct __byte_operand<__GLIBCXX_TYPE_INT_N_2> + { using __type = byte; }; + template<> struct __byte_operand + { using __type = byte; }; +#endif + template + struct __byte_operand + : __byte_operand<_IntegerType> { }; + template + struct __byte_operand + : __byte_operand<_IntegerType> { }; + template + struct __byte_operand + : __byte_operand<_IntegerType> { }; + + template + using __byte_op_t = typename __byte_operand<_IntegerType>::__type; + + template + constexpr __byte_op_t<_IntegerType>& + operator<<=(byte& __b, _IntegerType __shift) noexcept + { return __b = byte(static_cast(__b) << __shift); } + + template + constexpr __byte_op_t<_IntegerType> + operator<<(byte __b, _IntegerType __shift) noexcept + { return byte(static_cast(__b) << __shift); } + + template + constexpr __byte_op_t<_IntegerType>& + operator>>=(byte& __b, _IntegerType __shift) noexcept + { return __b = byte(static_cast(__b) >> __shift); } + + template + constexpr __byte_op_t<_IntegerType> + operator>>(byte __b, _IntegerType __shift) noexcept + { return byte(static_cast(__b) >> __shift); } + + constexpr byte& + operator|=(byte& __l, byte __r) noexcept + { + return __l = + byte(static_cast(__l) | static_cast(__r)); + } + + constexpr byte + operator|(byte __l, byte __r) noexcept + { + return + byte(static_cast(__l) | static_cast(__r)); + } + + constexpr byte& + operator&=(byte& __l, byte __r) noexcept + { + return __l = + byte(static_cast(__l) & static_cast(__r)); + } + + constexpr byte + operator&(byte __l, byte __r) noexcept + { + return + byte(static_cast(__l) & static_cast(__r)); + } + + constexpr byte& + operator^=(byte& __l, byte __r) noexcept + { + return __l = + byte(static_cast(__l) ^ static_cast(__r)); + } + + constexpr byte + operator^(byte __l, byte __r) noexcept + { + return + byte(static_cast(__l) ^ static_cast(__r)); + } + + constexpr byte + operator~(byte __b) noexcept + { return byte(~static_cast(__b)); } + + template + constexpr _IntegerType + to_integer(__byte_op_t<_IntegerType> __b) noexcept + { return _IntegerType(__b); } + +} // namespace std +#endif + +#endif // _GLIBCXX_CSTDDEF diff --git a/AH/STL/Fallback/cstdint b/AH/STL/Fallback/cstdint new file mode 100644 index 0000000..95edf49 --- /dev/null +++ b/AH/STL/Fallback/cstdint @@ -0,0 +1,89 @@ +// -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/cstdint + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_CSTDINT +#define _GLIBCXX_CSTDINT 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "bits/c++0x_warning.h" +#else + +#include "bits/c++config.h" + +#if _GLIBCXX_HAVE_STDINT_H +# include +#endif + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 + +namespace std +{ + using ::int8_t; + using ::int16_t; + using ::int32_t; + using ::int64_t; + + using ::int_fast8_t; + using ::int_fast16_t; + using ::int_fast32_t; + using ::int_fast64_t; + + using ::int_least8_t; + using ::int_least16_t; + using ::int_least32_t; + using ::int_least64_t; + + using ::intmax_t; + using ::intptr_t; + + using ::uint8_t; + using ::uint16_t; + using ::uint32_t; + using ::uint64_t; + + using ::uint_fast8_t; + using ::uint_fast16_t; + using ::uint_fast32_t; + using ::uint_fast64_t; + + using ::uint_least8_t; + using ::uint_least16_t; + using ::uint_least32_t; + using ::uint_least64_t; + + using ::uintmax_t; + using ::uintptr_t; +} // namespace std + +#endif // _GLIBCXX_USE_C99_STDINT_TR1 + +#endif // C++11 + +#endif // _GLIBCXX_CSTDINT diff --git a/AH/STL/Fallback/cstdlib b/AH/STL/Fallback/cstdlib new file mode 100644 index 0000000..ff1daff --- /dev/null +++ b/AH/STL/Fallback/cstdlib @@ -0,0 +1,268 @@ +// -*- C++ -*- forwarding header. + +// Copyright (C) 1997-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/cstdlib + * This is a Standard C++ Library file. You should @c \#include this file + * in your programs, rather than any of the @a *.h implementation files. + * + * This is the C++ version of the Standard C Library header @c stdlib.h, + * and its contents are (mostly) the same as that header, but are all + * contained in the namespace @c std (except for names which are defined + * as macros in C). + */ + +// +// ISO C++ 14882: 20.4.6 C library +// + +#pragma GCC system_header + +#include "bits/c++config.h" + +#ifndef _GLIBCXX_CSTDLIB +#define _GLIBCXX_CSTDLIB 1 + +#if !_GLIBCXX_HOSTED +// The C standard does not require a freestanding implementation to +// provide . However, the C++ standard does still require +// -- but only the functionality mentioned in +// [lib.support.start.term]. + +#define EXIT_SUCCESS 0 +#define EXIT_FAILURE 1 + +namespace std +{ + extern "C" void abort(void) throw () _GLIBCXX_NORETURN; + extern "C" int atexit(void (*)(void)) throw (); + extern "C" void exit(int) throw () _GLIBCXX_NORETURN; +#if __cplusplus >= 201103L +# ifdef _GLIBCXX_HAVE_AT_QUICK_EXIT + extern "C" int at_quick_exit(void (*)(void)) throw (); +# endif +# ifdef _GLIBCXX_HAVE_QUICK_EXIT + extern "C" void quick_exit(int) throw() _GLIBCXX_NORETURN; +# endif +#endif +} // namespace std + +#else + +// Need to ensure this finds the C library's not a libstdc++ +// wrapper that might already be installed later in the include search path. +#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include_next +#undef _GLIBCXX_INCLUDE_NEXT_C_HEADERS +#include "bits/std_abs.h" + +// Get rid of those macros defined in in lieu of real functions. +#undef abort +#if __cplusplus >= 201703L && defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) +# undef aligned_alloc +#endif +#undef atexit +#if __cplusplus >= 201103L +# ifdef _GLIBCXX_HAVE_AT_QUICK_EXIT +# undef at_quick_exit +# endif +#endif +#undef atof +#undef atoi +#undef atol +#undef bsearch +#undef calloc +#undef div +#undef exit +#undef free +#undef getenv +#undef labs +#undef ldiv +#undef malloc +#undef mblen +#undef mbstowcs +#undef mbtowc +#undef qsort +#if __cplusplus >= 201103L +# ifdef _GLIBCXX_HAVE_QUICK_EXIT +# undef quick_exit +# endif +#endif +#undef rand +#undef realloc +#undef srand +#undef strtod +#undef strtol +#undef strtoul +#undef system +#undef wcstombs +#undef wctomb + +extern "C++" +{ +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + using ::div_t; + using ::ldiv_t; + + using ::abort; +#if __cplusplus >= 201703L && defined(_GLIBCXX_HAVE_ALIGNED_ALLOC) + using ::aligned_alloc; +#endif + using ::atexit; +#if __cplusplus >= 201103L +# ifdef _GLIBCXX_HAVE_AT_QUICK_EXIT + using ::at_quick_exit; +# endif +#endif + using ::atof; + using ::atoi; + using ::atol; + using ::bsearch; + using ::calloc; + using ::div; + using ::exit; + using ::free; + using ::getenv; + using ::labs; + using ::ldiv; + using ::malloc; +#ifdef _GLIBCXX_HAVE_MBSTATE_T + using ::mblen; + using ::mbstowcs; + using ::mbtowc; +#endif // _GLIBCXX_HAVE_MBSTATE_T + using ::qsort; +#if __cplusplus >= 201103L +# ifdef _GLIBCXX_HAVE_QUICK_EXIT + using ::quick_exit; +# endif +#endif + using ::rand; + using ::realloc; + using ::srand; + using ::strtod; + using ::strtol; + using ::strtoul; + using ::system; +#ifdef _GLIBCXX_USE_WCHAR_T + using ::wcstombs; + using ::wctomb; +#endif // _GLIBCXX_USE_WCHAR_T + +#ifndef __CORRECT_ISO_CPP_STDLIB_H_PROTO + inline ldiv_t + div(long __i, long __j) { return ldiv(__i, __j); } +#endif + + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#if _GLIBCXX_USE_C99_STDLIB + +#undef _Exit +#undef llabs +#undef lldiv +#undef atoll +#undef strtoll +#undef strtoull +#undef strtof +#undef strtold + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + using ::lldiv_t; +#endif +#if _GLIBCXX_USE_C99_CHECK || _GLIBCXX_USE_C99_DYNAMIC + extern "C" void (_Exit)(int) throw () _GLIBCXX_NORETURN; +#endif +#if !_GLIBCXX_USE_C99_DYNAMIC + using ::_Exit; +#endif + +#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + using ::llabs; + + inline lldiv_t + div(long long __n, long long __d) + { lldiv_t __q; __q.quot = __n / __d; __q.rem = __n % __d; return __q; } + + using ::lldiv; +#endif + +#if _GLIBCXX_USE_C99_LONG_LONG_CHECK || _GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + extern "C" long long int (atoll)(const char *) throw (); + extern "C" long long int + (strtoll)(const char * __restrict, char ** __restrict, int) throw (); + extern "C" unsigned long long int + (strtoull)(const char * __restrict, char ** __restrict, int) throw (); +#endif +#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + using ::atoll; + using ::strtoll; + using ::strtoull; +#endif + +#ifdef AH_USE_STRTOF + using ::strtof; + using ::strtold; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace __gnu_cxx + +namespace std +{ +#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + using ::__gnu_cxx::lldiv_t; +#endif + using ::__gnu_cxx::_Exit; +#if !_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC + using ::__gnu_cxx::llabs; + using ::__gnu_cxx::div; + using ::__gnu_cxx::lldiv; +#endif + using ::__gnu_cxx::atoll; +#ifdef AH_USE_STRTOF + using ::__gnu_cxx::strtof; +#endif + using ::__gnu_cxx::strtoll; + using ::__gnu_cxx::strtoull; +#ifdef AH_USE_STRTOF + using ::__gnu_cxx::strtold; +#endif +} // namespace std + +#endif // _GLIBCXX_USE_C99_STDLIB + +} // extern "C++" + +#endif // !_GLIBCXX_HOSTED + +#endif diff --git a/AH/STL/Fallback/debug/assertions.h b/AH/STL/Fallback/debug/assertions.h new file mode 100644 index 0000000..6b37d4b --- /dev/null +++ b/AH/STL/Fallback/debug/assertions.h @@ -0,0 +1,68 @@ +// Debugging support implementation -*- C++ -*- + +// Copyright (C) 2003-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file debug/assertions.h + * This file is a GNU debug extension to the Standard C++ Library. + */ + +#ifndef _GLIBCXX_DEBUG_ASSERTIONS_H +#define _GLIBCXX_DEBUG_ASSERTIONS_H 1 + +#ifndef _GLIBCXX_DEBUG + +# define _GLIBCXX_DEBUG_ASSERT(_Condition) +# define _GLIBCXX_DEBUG_PEDASSERT(_Condition) +# define _GLIBCXX_DEBUG_ONLY(_Statement) + +#endif + +#ifndef _GLIBCXX_ASSERTIONS +# define __glibcxx_requires_non_empty_range(_First,_Last) +# define __glibcxx_requires_nonempty() +# define __glibcxx_requires_subscript(_N) +#else + +// Verify that [_First, _Last) forms a non-empty iterator range. +# define __glibcxx_requires_non_empty_range(_First,_Last) \ + __glibcxx_assert(__builtin_expect(_First != _Last, true)) +# define __glibcxx_requires_subscript(_N) \ + __glibcxx_assert(__builtin_expect(_N < this->size(), true)) +// Verify that the container is nonempty +# define __glibcxx_requires_nonempty() \ + __glibcxx_assert(__builtin_expect(!this->empty(), true)) +#endif + +#ifdef _GLIBCXX_DEBUG +# define _GLIBCXX_DEBUG_ASSERT(_Condition) __glibcxx_assert(_Condition) + +# ifdef _GLIBCXX_DEBUG_PEDANTIC +# define _GLIBCXX_DEBUG_PEDASSERT(_Condition) _GLIBCXX_DEBUG_ASSERT(_Condition) +# else +# define _GLIBCXX_DEBUG_PEDASSERT(_Condition) +# endif + +# define _GLIBCXX_DEBUG_ONLY(_Statement) _Statement +#endif + +#endif // _GLIBCXX_DEBUG_ASSERTIONS diff --git a/AH/STL/Fallback/debug/debug.h b/AH/STL/Fallback/debug/debug.h new file mode 100644 index 0000000..72fe567 --- /dev/null +++ b/AH/STL/Fallback/debug/debug.h @@ -0,0 +1,125 @@ +// Debugging support implementation -*- C++ -*- + +// Copyright (C) 2003-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file debug/debug.h + * This file is a GNU debug extension to the Standard C++ Library. + */ + +#ifndef _GLIBCXX_DEBUG_MACRO_SWITCH_H +#define _GLIBCXX_DEBUG_MACRO_SWITCH_H 1 + +/** Macros and namespaces used by the implementation outside of debug + * wrappers to verify certain properties. The __glibcxx_requires_xxx + * macros are merely wrappers around the __glibcxx_check_xxx wrappers + * when we are compiling with debug mode, but disappear when we are + * in release mode so that there is no checking performed in, e.g., + * the standard library algorithms. +*/ + +#include "../debug/assertions.h" + +// Debug mode namespaces. + +/** + * @namespace std::__debug + * @brief GNU debug code, replaces standard behavior with debug behavior. + */ +namespace std +{ + namespace __debug { } +} + +/** @namespace __gnu_debug + * @brief GNU debug classes for public use. +*/ +namespace __gnu_debug +{ + using namespace std::__debug; +} + +#ifndef _GLIBCXX_DEBUG + +# define __glibcxx_requires_cond(_Cond,_Msg) +# define __glibcxx_requires_valid_range(_First,_Last) +# define __glibcxx_requires_sorted(_First,_Last) +# define __glibcxx_requires_sorted_pred(_First,_Last,_Pred) +# define __glibcxx_requires_sorted_set(_First1,_Last1,_First2) +# define __glibcxx_requires_sorted_set_pred(_First1,_Last1,_First2,_Pred) +# define __glibcxx_requires_partitioned_lower(_First,_Last,_Value) +# define __glibcxx_requires_partitioned_upper(_First,_Last,_Value) +# define __glibcxx_requires_partitioned_lower_pred(_First,_Last,_Value,_Pred) +# define __glibcxx_requires_partitioned_upper_pred(_First,_Last,_Value,_Pred) +# define __glibcxx_requires_heap(_First,_Last) +# define __glibcxx_requires_heap_pred(_First,_Last,_Pred) +# define __glibcxx_requires_string(_String) +# define __glibcxx_requires_string_len(_String,_Len) +# define __glibcxx_requires_irreflexive(_First,_Last) +# define __glibcxx_requires_irreflexive2(_First,_Last) +# define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred) +# define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred) + +#else + +# include + +# define __glibcxx_requires_cond(_Cond,_Msg) _GLIBCXX_DEBUG_VERIFY(_Cond,_Msg) +# define __glibcxx_requires_valid_range(_First,_Last) \ + __glibcxx_check_valid_range(_First,_Last) +# define __glibcxx_requires_sorted(_First,_Last) \ + __glibcxx_check_sorted(_First,_Last) +# define __glibcxx_requires_sorted_pred(_First,_Last,_Pred) \ + __glibcxx_check_sorted_pred(_First,_Last,_Pred) +# define __glibcxx_requires_sorted_set(_First1,_Last1,_First2) \ + __glibcxx_check_sorted_set(_First1,_Last1,_First2) +# define __glibcxx_requires_sorted_set_pred(_First1,_Last1,_First2,_Pred) \ + __glibcxx_check_sorted_set_pred(_First1,_Last1,_First2,_Pred) +# define __glibcxx_requires_partitioned_lower(_First,_Last,_Value) \ + __glibcxx_check_partitioned_lower(_First,_Last,_Value) +# define __glibcxx_requires_partitioned_upper(_First,_Last,_Value) \ + __glibcxx_check_partitioned_upper(_First,_Last,_Value) +# define __glibcxx_requires_partitioned_lower_pred(_First,_Last,_Value,_Pred) \ + __glibcxx_check_partitioned_lower_pred(_First,_Last,_Value,_Pred) +# define __glibcxx_requires_partitioned_upper_pred(_First,_Last,_Value,_Pred) \ + __glibcxx_check_partitioned_upper_pred(_First,_Last,_Value,_Pred) +# define __glibcxx_requires_heap(_First,_Last) \ + __glibcxx_check_heap(_First,_Last) +# define __glibcxx_requires_heap_pred(_First,_Last,_Pred) \ + __glibcxx_check_heap_pred(_First,_Last,_Pred) +# define __glibcxx_requires_string(_String) __glibcxx_check_string(_String) +# define __glibcxx_requires_string_len(_String,_Len) \ + __glibcxx_check_string_len(_String,_Len) +# define __glibcxx_requires_irreflexive(_First,_Last) \ + __glibcxx_check_irreflexive(_First,_Last) +# define __glibcxx_requires_irreflexive2(_First,_Last) \ + __glibcxx_check_irreflexive2(_First,_Last) +# define __glibcxx_requires_irreflexive_pred(_First,_Last,_Pred) \ + __glibcxx_check_irreflexive_pred(_First,_Last,_Pred) +# define __glibcxx_requires_irreflexive_pred2(_First,_Last,_Pred) \ + __glibcxx_check_irreflexive_pred2(_First,_Last,_Pred) + +# include + +#endif + +#endif // _GLIBCXX_DEBUG_MACRO_SWITCH_H diff --git a/AH/STL/Fallback/ext/alloc_traits.h b/AH/STL/Fallback/ext/alloc_traits.h new file mode 100644 index 0000000..c23aab9 --- /dev/null +++ b/AH/STL/Fallback/ext/alloc_traits.h @@ -0,0 +1,163 @@ +// Allocator traits -*- C++ -*- + +// Copyright (C) 2011-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file ext/alloc_traits.h + * This file is a GNU extension to the Standard C++ Library. + */ + +#ifndef _EXT_ALLOC_TRAITS_H +#define _EXT_ALLOC_TRAITS_H 1 + +#pragma GCC system_header + +#if __cplusplus >= 201103L +# include "../bits/move.h" +# include "../bits/alloc_traits.h" +#else +# include "../bits/allocator.h" // for __alloc_swap +#endif + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +/** + * @brief Uniform interface to C++98 and C++11 allocators. + * @ingroup allocators +*/ +template + struct __alloc_traits +#if __cplusplus >= 201103L + : std::allocator_traits<_Alloc> +#endif + { + typedef _Alloc allocator_type; +#if __cplusplus >= 201103L + typedef std::allocator_traits<_Alloc> _Base_type; + typedef typename _Base_type::value_type value_type; + typedef typename _Base_type::pointer pointer; + typedef typename _Base_type::const_pointer const_pointer; + typedef typename _Base_type::size_type size_type; + typedef typename _Base_type::difference_type difference_type; + // C++11 allocators do not define reference or const_reference + typedef value_type& reference; + typedef const value_type& const_reference; + using _Base_type::allocate; + using _Base_type::deallocate; + using _Base_type::construct; + using _Base_type::destroy; + using _Base_type::max_size; + + private: + template + using __is_custom_pointer + = std::__and_, + std::__not_>>; + + public: + // overload construct for non-standard pointer types + template + static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type + construct(_Alloc& __a, _Ptr __p, _Args&&... __args) + { + _Base_type::construct(__a, std::addressof(*__p), + std::forward<_Args>(__args)...); + } + + // overload destroy for non-standard pointer types + template + static typename std::enable_if<__is_custom_pointer<_Ptr>::value>::type + destroy(_Alloc& __a, _Ptr __p) + { _Base_type::destroy(__a, std::addressof(*__p)); } + + static _Alloc _S_select_on_copy(const _Alloc& __a) + { return _Base_type::select_on_container_copy_construction(__a); } + + static void _S_on_swap(_Alloc& __a, _Alloc& __b) + { std::__alloc_on_swap(__a, __b); } + + static constexpr bool _S_propagate_on_copy_assign() + { return _Base_type::propagate_on_container_copy_assignment::value; } + + static constexpr bool _S_propagate_on_move_assign() + { return _Base_type::propagate_on_container_move_assignment::value; } + + static constexpr bool _S_propagate_on_swap() + { return _Base_type::propagate_on_container_swap::value; } + + static constexpr bool _S_always_equal() + { return _Base_type::is_always_equal::value; } + + static constexpr bool _S_nothrow_move() + { return _S_propagate_on_move_assign() || _S_always_equal(); } + + template + struct rebind + { typedef typename _Base_type::template rebind_alloc<_Tp> other; }; +#else + + typedef typename _Alloc::pointer pointer; + typedef typename _Alloc::const_pointer const_pointer; + typedef typename _Alloc::value_type value_type; + typedef typename _Alloc::reference reference; + typedef typename _Alloc::const_reference const_reference; + typedef typename _Alloc::size_type size_type; + typedef typename _Alloc::difference_type difference_type; + + static pointer + allocate(_Alloc& __a, size_type __n) + { return __a.allocate(__n); } + + static void deallocate(_Alloc& __a, pointer __p, size_type __n) + { __a.deallocate(__p, __n); } + + template + static void construct(_Alloc& __a, pointer __p, const _Tp& __arg) + { __a.construct(__p, __arg); } + + static void destroy(_Alloc& __a, pointer __p) + { __a.destroy(__p); } + + static size_type max_size(const _Alloc& __a) + { return __a.max_size(); } + + static const _Alloc& _S_select_on_copy(const _Alloc& __a) { return __a; } + + static void _S_on_swap(_Alloc& __a, _Alloc& __b) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 431. Swapping containers with unequal allocators. + std::__alloc_swap<_Alloc>::_S_do_it(__a, __b); + } + + template + struct rebind + { typedef typename _Alloc::template rebind<_Tp>::other other; }; +#endif + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace __gnu_cxx + +#endif diff --git a/AH/STL/Fallback/ext/new_allocator.h b/AH/STL/Fallback/ext/new_allocator.h new file mode 100644 index 0000000..36b2966 --- /dev/null +++ b/AH/STL/Fallback/ext/new_allocator.h @@ -0,0 +1,172 @@ +// Allocator that wraps operator new -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file ext/new_allocator.h + * This file is a GNU extension to the Standard C++ Library. + */ + +#ifndef _NEW_ALLOCATOR_H +#define _NEW_ALLOCATOR_H 1 + +#include "../bits/c++config.h" +#include "../new" +#include "../bits/functexcept.h" +#include "../bits/move.h" +#if __cplusplus >= 201103L +#include "../type_traits" +#endif + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + using std::size_t; + using std::ptrdiff_t; + + /** + * @brief An allocator that uses global new, as per [20.4]. + * @ingroup allocators + * + * This is precisely the allocator defined in the C++ Standard. + * - all allocation calls operator new + * - all deallocation calls operator delete + * + * @tparam _Tp Type of allocated object. + */ + template + class new_allocator + { + public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef _Tp value_type; + + template + struct rebind + { typedef new_allocator<_Tp1> other; }; + +#if __cplusplus >= 201103L + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2103. propagate_on_container_move_assignment + typedef std::true_type propagate_on_container_move_assignment; +#endif + + new_allocator() _GLIBCXX_USE_NOEXCEPT { } + + new_allocator(const new_allocator&) _GLIBCXX_USE_NOEXCEPT { } + + template + new_allocator(const new_allocator<_Tp1>&) _GLIBCXX_USE_NOEXCEPT { } + + ~new_allocator() _GLIBCXX_USE_NOEXCEPT { } + + pointer + address(reference __x) const _GLIBCXX_NOEXCEPT + { return std::__addressof(__x); } + + const_pointer + address(const_reference __x) const _GLIBCXX_NOEXCEPT + { return std::__addressof(__x); } + + // NB: __n is permitted to be 0. The C++ standard says nothing + // about what the return value is when __n == 0. + pointer + allocate(size_type __n, const void* = static_cast(0)) + { + if (__n > this->max_size()) + __throw_bad_alloc(); + +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + std::align_val_t __al = std::align_val_t(alignof(_Tp)); + _Tp* __newres = static_cast<_Tp*>(::operator new(__n * sizeof(_Tp), __al)); + if (__newres == nullptr) + __throw_bad_alloc(); + return __newres; + } +#endif + _Tp* __newres = static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); + if (__newres == nullptr) + __throw_bad_alloc(); + return __newres; + } + + // __p is not permitted to be a null pointer. + void + deallocate(pointer __p, size_type) + { +#if __cpp_aligned_new + if (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__) + { + ::operator delete(__p, std::align_val_t(alignof(_Tp))); + return; + } +#endif + ::operator delete(__p); + } + + size_type + max_size() const _GLIBCXX_USE_NOEXCEPT + { return size_t(-1) / sizeof(_Tp); } + +#if __cplusplus >= 201103L + template + void + construct(_Up* __p, _Args&&... __args) + { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } + + template + void + destroy(_Up* __p) { __p->~_Up(); } +#else + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 402. wrong new expression in [some_] allocator::construct + void + construct(pointer __p, const _Tp& __val) + { ::new((void *)__p) _Tp(__val); } + + void + destroy(pointer __p) { __p->~_Tp(); } +#endif + }; + + template + inline bool + operator==(const new_allocator<_Tp>&, const new_allocator<_Tp>&) + { return true; } + + template + inline bool + operator!=(const new_allocator<_Tp>&, const new_allocator<_Tp>&) + { return false; } + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif diff --git a/AH/STL/Fallback/ext/numeric_traits.h b/AH/STL/Fallback/ext/numeric_traits.h new file mode 100644 index 0000000..0db711e --- /dev/null +++ b/AH/STL/Fallback/ext/numeric_traits.h @@ -0,0 +1,138 @@ +// -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License as published by the Free Software +// Foundation; either version 3, or (at your option) any later +// version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file ext/numeric_traits.h + * This file is a GNU extension to the Standard C++ Library. + */ + +#ifndef _EXT_NUMERIC_TRAITS +#define _EXT_NUMERIC_TRAITS 1 + +#pragma GCC system_header + +#include "../bits/cpp_type_traits.h" +#include "../ext/type_traits.h" + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Compile time constants for builtin types. + // Sadly std::numeric_limits member functions cannot be used for this. +#define __glibcxx_signed(_Tp) ((_Tp)(-1) < 0) +#define __glibcxx_digits(_Tp) \ + (sizeof(_Tp) * __CHAR_BIT__ - __glibcxx_signed(_Tp)) + +#define __glibcxx_min(_Tp) \ + (__glibcxx_signed(_Tp) ? (_Tp)1 << __glibcxx_digits(_Tp) : (_Tp)0) + +#define __glibcxx_max(_Tp) \ + (__glibcxx_signed(_Tp) ? \ + (((((_Tp)1 << (__glibcxx_digits(_Tp) - 1)) - 1) << 1) + 1) : ~(_Tp)0) + + template + struct __numeric_traits_integer + { + // Only integers for initialization of member constant. + static const _Value __min = __glibcxx_min(_Value); + static const _Value __max = __glibcxx_max(_Value); + + // NB: these two also available in std::numeric_limits as compile + // time constants, but is big and we avoid including it. + static const bool __is_signed = __glibcxx_signed(_Value); + static const int __digits = __glibcxx_digits(_Value); + }; + + template + const _Value __numeric_traits_integer<_Value>::__min; + + template + const _Value __numeric_traits_integer<_Value>::__max; + + template + const bool __numeric_traits_integer<_Value>::__is_signed; + + template + const int __numeric_traits_integer<_Value>::__digits; + +#undef __glibcxx_signed +#undef __glibcxx_digits +#undef __glibcxx_min +#undef __glibcxx_max + +#define __glibcxx_floating(_Tp, _Fval, _Dval, _LDval) \ + (std::__are_same<_Tp, float>::__value ? _Fval \ + : std::__are_same<_Tp, double>::__value ? _Dval : _LDval) + +#define __glibcxx_max_digits10(_Tp) \ + (2 + __glibcxx_floating(_Tp, __FLT_MANT_DIG__, __DBL_MANT_DIG__, \ + __LDBL_MANT_DIG__) * 643L / 2136) + +#define __glibcxx_digits10(_Tp) \ + __glibcxx_floating(_Tp, __FLT_DIG__, __DBL_DIG__, __LDBL_DIG__) + +#define __glibcxx_max_exponent10(_Tp) \ + __glibcxx_floating(_Tp, __FLT_MAX_10_EXP__, __DBL_MAX_10_EXP__, \ + __LDBL_MAX_10_EXP__) + + template + struct __numeric_traits_floating + { + // Only floating point types. See N1822. + static const int __max_digits10 = __glibcxx_max_digits10(_Value); + + // See above comment... + static const bool __is_signed = true; + static const int __digits10 = __glibcxx_digits10(_Value); + static const int __max_exponent10 = __glibcxx_max_exponent10(_Value); + }; + + template + const int __numeric_traits_floating<_Value>::__max_digits10; + + template + const bool __numeric_traits_floating<_Value>::__is_signed; + + template + const int __numeric_traits_floating<_Value>::__digits10; + + template + const int __numeric_traits_floating<_Value>::__max_exponent10; + + template + struct __numeric_traits + : public __conditional_type::__value, + __numeric_traits_integer<_Value>, + __numeric_traits_floating<_Value> >::__type + { }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#undef __glibcxx_floating +#undef __glibcxx_max_digits10 +#undef __glibcxx_digits10 +#undef __glibcxx_max_exponent10 + +#endif diff --git a/AH/STL/Fallback/ext/type_traits.h b/AH/STL/Fallback/ext/type_traits.h new file mode 100644 index 0000000..5c8c4c5 --- /dev/null +++ b/AH/STL/Fallback/ext/type_traits.h @@ -0,0 +1,221 @@ +// -*- C++ -*- + +// Copyright (C) 2005-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License as published by the Free Software +// Foundation; either version 3, or (at your option) any later +// version. + +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file ext/type_traits.h + * This file is a GNU extension to the Standard C++ Library. + */ + +#ifndef _EXT_TYPE_TRAITS +#define _EXT_TYPE_TRAITS 1 + +#pragma GCC system_header + +#include "../bits/c++config.h" +#include "../bits/cpp_type_traits.h" + +extern "C++" { + +namespace __gnu_cxx _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // Define a nested type if some predicate holds. + template + struct __enable_if + { }; + + template + struct __enable_if + { typedef _Tp __type; }; + + + // Conditional expression for types. If true, first, if false, second. + template + struct __conditional_type + { typedef _Iftrue __type; }; + + template + struct __conditional_type + { typedef _Iffalse __type; }; + + + // Given an integral builtin type, return the corresponding unsigned type. + template + struct __add_unsigned + { + private: + typedef __enable_if::__value, _Tp> __if_type; + + public: + typedef typename __if_type::__type __type; + }; + + template<> + struct __add_unsigned + { typedef unsigned char __type; }; + + template<> + struct __add_unsigned + { typedef unsigned char __type; }; + + template<> + struct __add_unsigned + { typedef unsigned short __type; }; + + template<> + struct __add_unsigned + { typedef unsigned int __type; }; + + template<> + struct __add_unsigned + { typedef unsigned long __type; }; + + template<> + struct __add_unsigned + { typedef unsigned long long __type; }; + + // Declare but don't define. + template<> + struct __add_unsigned; + + template<> + struct __add_unsigned; + + + // Given an integral builtin type, return the corresponding signed type. + template + struct __remove_unsigned + { + private: + typedef __enable_if::__value, _Tp> __if_type; + + public: + typedef typename __if_type::__type __type; + }; + + template<> + struct __remove_unsigned + { typedef signed char __type; }; + + template<> + struct __remove_unsigned + { typedef signed char __type; }; + + template<> + struct __remove_unsigned + { typedef short __type; }; + + template<> + struct __remove_unsigned + { typedef int __type; }; + + template<> + struct __remove_unsigned + { typedef long __type; }; + + template<> + struct __remove_unsigned + { typedef long long __type; }; + + // Declare but don't define. + template<> + struct __remove_unsigned; + + template<> + struct __remove_unsigned; + + + // For use in string and vstring. + template + inline bool + __is_null_pointer(_Type* __ptr) + { return __ptr == 0; } + + template + inline bool + __is_null_pointer(_Type) + { return false; } + +#if __cplusplus >= 201103L + inline bool + __is_null_pointer(std::nullptr_t) + { return true; } +#endif + + // For complex and cmath + template::__value> + struct __promote + { typedef double __type; }; + + // No nested __type member for non-integer non-floating point types, + // allows this type to be used for SFINAE to constrain overloads in + // and to only the intended types. + template + struct __promote<_Tp, false> + { }; + + template<> + struct __promote + { typedef long double __type; }; + + template<> + struct __promote + { typedef double __type; }; + + template<> + struct __promote + { typedef float __type; }; + + template::__type, + typename _Up2 = typename __promote<_Up>::__type> + struct __promote_2 + { + typedef __typeof__(_Tp2() + _Up2()) __type; + }; + + template::__type, + typename _Up2 = typename __promote<_Up>::__type, + typename _Vp2 = typename __promote<_Vp>::__type> + struct __promote_3 + { + typedef __typeof__(_Tp2() + _Up2() + _Vp2()) __type; + }; + + template::__type, + typename _Up2 = typename __promote<_Up>::__type, + typename _Vp2 = typename __promote<_Vp>::__type, + typename _Wp2 = typename __promote<_Wp>::__type> + struct __promote_4 + { + typedef __typeof__(_Tp2() + _Up2() + _Vp2() + _Wp2()) __type; + }; + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace +} // extern "C++" + +#endif diff --git a/AH/STL/Fallback/initializer_list b/AH/STL/Fallback/initializer_list new file mode 100644 index 0000000..af0116c --- /dev/null +++ b/AH/STL/Fallback/initializer_list @@ -0,0 +1,107 @@ +// std::initializer_list support -*- C++ -*- + +// Copyright (C) 2008-2017 Free Software Foundation, Inc. +// +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file initializer_list + * This is a Standard C++ Library header. + */ + +#ifndef _INITIALIZER_LIST +#define _INITIALIZER_LIST + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "bits/c++0x_warning.h" +#else // C++0x + +#pragma GCC visibility push(default) + +#include "bits/c++config.h" + +namespace std +{ + /// initializer_list + template + class initializer_list + { + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + typedef const _E* iterator; + typedef const _E* const_iterator; + + private: + iterator _M_array; + size_type _M_len; + + // The compiler can call a private constructor. + constexpr initializer_list(const_iterator __a, size_type __l) + : _M_array(__a), _M_len(__l) { } + + public: + constexpr initializer_list() noexcept + : _M_array(0), _M_len(0) { } + + // Number of elements. + constexpr size_type + size() const noexcept { return _M_len; } + + // First element. + constexpr const_iterator + begin() const noexcept { return _M_array; } + + // One past the last element. + constexpr const_iterator + end() const noexcept { return begin() + size(); } + }; + + /** + * @brief Return an iterator pointing to the first element of + * the initializer_list. + * @param __ils Initializer list. + */ + template + constexpr const _Tp* + begin(initializer_list<_Tp> __ils) noexcept + { return __ils.begin(); } + + /** + * @brief Return an iterator pointing to one past the last element + * of the initializer_list. + * @param __ils Initializer list. + */ + template + constexpr const _Tp* + end(initializer_list<_Tp> __ils) noexcept + { return __ils.end(); } +} + +#pragma GCC visibility pop + +#endif // C++11 + +#endif // _INITIALIZER_LIST diff --git a/AH/STL/Fallback/iterator b/AH/STL/Fallback/iterator new file mode 100644 index 0000000..e319e35 --- /dev/null +++ b/AH/STL/Fallback/iterator @@ -0,0 +1,70 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/iterator + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_ITERATOR +#define _GLIBCXX_ITERATOR 1 + +#pragma GCC system_header + +#include "bits/c++config.h" +#include "bits/stl_iterator_base_types.h" +#include "bits/stl_iterator_base_funcs.h" +#include "bits/stl_iterator.h" +// #include +// #include +// #include +// #include +#include "bits/range_access.h" + +#endif /* _GLIBCXX_ITERATOR */ diff --git a/AH/STL/Fallback/limits b/AH/STL/Fallback/limits new file mode 100644 index 0000000..7fccf98 --- /dev/null +++ b/AH/STL/Fallback/limits @@ -0,0 +1,1827 @@ +// The template and inlines for the numeric_limits classes. -*- C++ -*- + +// Copyright (C) 1999-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/limits + * This is a Standard C++ Library header. + */ + +// Note: this is not a conforming implementation. +// Written by Gabriel Dos Reis + +// +// ISO 14882:1998 +// 18.2.1 +// + +#ifndef _GLIBCXX_NUMERIC_LIMITS +#define _GLIBCXX_NUMERIC_LIMITS 1 + +#pragma GCC system_header + +#include "bits/c++config.h" + +// +// The numeric_limits<> traits document implementation-defined aspects +// of fundamental arithmetic data types (integers and floating points). +// From Standard C++ point of view, there are 14 such types: +// * integers +// bool (1) +// char, signed char, unsigned char, wchar_t (4) +// short, unsigned short (2) +// int, unsigned (2) +// long, unsigned long (2) +// +// * floating points +// float (1) +// double (1) +// long double (1) +// +// GNU C++ understands (where supported by the host C-library) +// * integer +// long long, unsigned long long (2) +// +// which brings us to 16 fundamental arithmetic data types in GNU C++. +// +// +// Since a numeric_limits<> is a bit tricky to get right, we rely on +// an interface composed of macros which should be defined in config/os +// or config/cpu when they differ from the generic (read arbitrary) +// definitions given here. +// + +// These values can be overridden in the target configuration file. +// The default values are appropriate for many 32-bit targets. + +// GCC only intrinsically supports modulo integral types. The only remaining +// integral exceptional values is division by zero. Only targets that do not +// signal division by zero in some "hard to ignore" way should use false. +#ifndef __glibcxx_integral_traps +# define __glibcxx_integral_traps true +#endif + +// float +// + +// Default values. Should be overridden in configuration files if necessary. + +#ifndef __glibcxx_float_has_denorm_loss +# define __glibcxx_float_has_denorm_loss false +#endif +#ifndef __glibcxx_float_traps +# define __glibcxx_float_traps false +#endif +#ifndef __glibcxx_float_tinyness_before +# define __glibcxx_float_tinyness_before false +#endif + +// double + +// Default values. Should be overridden in configuration files if necessary. + +#ifndef __glibcxx_double_has_denorm_loss +# define __glibcxx_double_has_denorm_loss false +#endif +#ifndef __glibcxx_double_traps +# define __glibcxx_double_traps false +#endif +#ifndef __glibcxx_double_tinyness_before +# define __glibcxx_double_tinyness_before false +#endif + +// long double + +// Default values. Should be overridden in configuration files if necessary. + +#ifndef __glibcxx_long_double_has_denorm_loss +# define __glibcxx_long_double_has_denorm_loss false +#endif +#ifndef __glibcxx_long_double_traps +# define __glibcxx_long_double_traps false +#endif +#ifndef __glibcxx_long_double_tinyness_before +# define __glibcxx_long_double_tinyness_before false +#endif + +// You should not need to define any macros below this point. + +#define __glibcxx_signed_b(T,B) ((T)(-1) < 0) + +#define __glibcxx_min_b(T,B) \ + (__glibcxx_signed_b (T,B) ? -__glibcxx_max_b (T,B) - 1 : (T)0) + +#define __glibcxx_max_b(T,B) \ + (__glibcxx_signed_b (T,B) ? \ + (((((T)1 << (__glibcxx_digits_b (T,B) - 1)) - 1) << 1) + 1) : ~(T)0) + +#define __glibcxx_digits_b(T,B) \ + (B - __glibcxx_signed_b (T,B)) + +// The fraction 643/2136 approximates log10(2) to 7 significant digits. +#define __glibcxx_digits10_b(T,B) \ + (__glibcxx_digits_b (T,B) * 643L / 2136) + +#define __glibcxx_signed(T) \ + __glibcxx_signed_b (T, sizeof(T) * __CHAR_BIT__) +#define __glibcxx_min(T) \ + __glibcxx_min_b (T, sizeof(T) * __CHAR_BIT__) +#define __glibcxx_max(T) \ + __glibcxx_max_b (T, sizeof(T) * __CHAR_BIT__) +#define __glibcxx_digits(T) \ + __glibcxx_digits_b (T, sizeof(T) * __CHAR_BIT__) +#define __glibcxx_digits10(T) \ + __glibcxx_digits10_b (T, sizeof(T) * __CHAR_BIT__) + +#define __glibcxx_max_digits10(T) \ + (2 + (T) * 643L / 2136) + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @brief Describes the rounding style for floating-point types. + * + * This is used in the std::numeric_limits class. + */ + enum float_round_style + { + round_indeterminate = -1, /// Intermediate. + round_toward_zero = 0, /// To zero. + round_to_nearest = 1, /// To the nearest representable value. + round_toward_infinity = 2, /// To infinity. + round_toward_neg_infinity = 3 /// To negative infinity. + }; + + /** + * @brief Describes the denormalization for floating-point types. + * + * These values represent the presence or absence of a variable number + * of exponent bits. This type is used in the std::numeric_limits class. + */ + enum float_denorm_style + { + /// Indeterminate at compile time whether denormalized values are allowed. + denorm_indeterminate = -1, + /// The type does not allow denormalized values. + denorm_absent = 0, + /// The type allows denormalized values. + denorm_present = 1 + }; + + /** + * @brief Part of std::numeric_limits. + * + * The @c static @c const members are usable as integral constant + * expressions. + * + * @note This is a separate class for purposes of efficiency; you + * should only access these members as part of an instantiation + * of the std::numeric_limits class. + */ + struct __numeric_limits_base + { + /** This will be true for all fundamental types (which have + specializations), and false for everything else. */ + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = false; + + /** The number of @c radix digits that be represented without change: for + integer types, the number of non-sign bits in the mantissa; for + floating types, the number of @c radix digits in the mantissa. */ + static _GLIBCXX_USE_CONSTEXPR int digits = 0; + + /** The number of base 10 digits that can be represented without change. */ + static _GLIBCXX_USE_CONSTEXPR int digits10 = 0; + +#if __cplusplus >= 201103L + /** The number of base 10 digits required to ensure that values which + differ are always differentiated. */ + static constexpr int max_digits10 = 0; +#endif + + /** True if the type is signed. */ + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + + /** True if the type is integer. */ + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; + + /** True if the type uses an exact representation. All integer types are + exact, but not all exact types are integer. For example, rational and + fixed-exponent representations are exact but not integer. */ + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; + + /** For integer types, specifies the base of the representation. For + floating types, specifies the base of the exponent representation. */ + static _GLIBCXX_USE_CONSTEXPR int radix = 0; + + /** The minimum negative integer such that @c radix raised to the power of + (one less than that integer) is a normalized floating point number. */ + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + + /** The minimum negative integer such that 10 raised to that power is in + the range of normalized floating point numbers. */ + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + + /** The maximum positive integer such that @c radix raised to the power of + (one less than that integer) is a representable finite floating point + number. */ + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + + /** The maximum positive integer such that 10 raised to that power is in + the range of representable finite floating point numbers. */ + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + /** True if the type has a representation for positive infinity. */ + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + + /** True if the type has a representation for a quiet (non-signaling) + Not a Number. */ + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + + /** True if the type has a representation for a signaling + Not a Number. */ + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + + /** See std::float_denorm_style for more information. */ + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm = denorm_absent; + + /** True if loss of accuracy is detected as a denormalization loss, + rather than as an inexact result. */ + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + /** True if-and-only-if the type adheres to the IEC 559 standard, also + known as IEEE 754. (Only makes sense for floating point types.) */ + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + + /** True if the set of values representable by the type is + finite. All built-in types are bounded, this member would be + false for arbitrary precision types. */ + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = false; + + /** True if the type is @e modulo. A type is modulo if, for any + operation involving +, -, or * on values of that type whose + result would fall outside the range [min(),max()], the value + returned differs from the true value by an integer multiple of + max() - min() + 1. On most machines, this is false for floating + types, true for unsigned integers, and true for signed integers. + See PR22200 about signed integers. */ + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + /** True if trapping is implemented for this type. */ + static _GLIBCXX_USE_CONSTEXPR bool traps = false; + + /** True if tininess is detected before rounding. (see IEC 559) */ + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + + /** See std::float_round_style for more information. This is only + meaningful for floating types; integer types will all be + round_toward_zero. */ + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style = + round_toward_zero; + }; + + /** + * @brief Properties of fundamental types. + * + * This class allows a program to obtain information about the + * representation of a fundamental type on a given platform. For + * non-fundamental types, the functions will return 0 and the data + * members will all be @c false. + */ + template + struct numeric_limits : public __numeric_limits_base + { + /** The minimum finite value, or for floating types with + denormalization, the minimum positive normalized value. */ + static _GLIBCXX_CONSTEXPR _Tp + min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The maximum finite value. */ + static _GLIBCXX_CONSTEXPR _Tp + max() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + +#if __cplusplus >= 201103L + /** A finite value x such that there is no other finite value y + * where y < x. */ + static constexpr _Tp + lowest() noexcept { return _Tp(); } +#endif + + /** The @e machine @e epsilon: the difference between 1 and the least + value greater than 1 that is representable. */ + static _GLIBCXX_CONSTEXPR _Tp + epsilon() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The maximum rounding error measurement (see LIA-1). */ + static _GLIBCXX_CONSTEXPR _Tp + round_error() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The representation of positive infinity, if @c has_infinity. */ + static _GLIBCXX_CONSTEXPR _Tp + infinity() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The representation of a quiet Not a Number, + if @c has_quiet_NaN. */ + static _GLIBCXX_CONSTEXPR _Tp + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The representation of a signaling Not a Number, if + @c has_signaling_NaN. */ + static _GLIBCXX_CONSTEXPR _Tp + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + + /** The minimum positive denormalized value. For types where + @c has_denorm is false, this is the minimum positive normalized + value. */ + static _GLIBCXX_CONSTEXPR _Tp + denorm_min() _GLIBCXX_USE_NOEXCEPT { return _Tp(); } + }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 559. numeric_limits + + template + struct numeric_limits + : public numeric_limits<_Tp> { }; + + template + struct numeric_limits + : public numeric_limits<_Tp> { }; + + template + struct numeric_limits + : public numeric_limits<_Tp> { }; + + // Now there follow 16 explicit specializations. Yes, 16. Make sure + // you get the count right. (18 in C++11 mode, with char16_t and char32_t.) + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 184. numeric_limits wording problems + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR bool + min() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_CONSTEXPR bool + max() _GLIBCXX_USE_NOEXCEPT { return true; } + +#if __cplusplus >= 201103L + static constexpr bool + lowest() noexcept { return min(); } +#endif + static _GLIBCXX_USE_CONSTEXPR int digits = 1; + static _GLIBCXX_USE_CONSTEXPR int digits10 = 0; +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR bool + epsilon() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_CONSTEXPR bool + round_error() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR bool + infinity() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_CONSTEXPR bool + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_CONSTEXPR bool + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_CONSTEXPR bool + denorm_min() _GLIBCXX_USE_NOEXCEPT { return false; } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + // It is not clear what it means for a boolean type to trap. + // This is a DR on the LWG issue list. Here, I use integer + // promotion semantics. + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR char + min() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_min(char); } + + static _GLIBCXX_CONSTEXPR char + max() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_max(char); } + +#if __cplusplus >= 201103L + static constexpr char + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (char); + static _GLIBCXX_USE_CONSTEXPR int digits10 = __glibcxx_digits10 (char); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = __glibcxx_signed (char); + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR char + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR char + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR + char infinity() _GLIBCXX_USE_NOEXCEPT { return char(); } + + static _GLIBCXX_CONSTEXPR char + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return char(); } + + static _GLIBCXX_CONSTEXPR char + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return char(); } + + static _GLIBCXX_CONSTEXPR char + denorm_min() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = !is_signed; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR signed char + min() _GLIBCXX_USE_NOEXCEPT { return -__SCHAR_MAX__ - 1; } + + static _GLIBCXX_CONSTEXPR signed char + max() _GLIBCXX_USE_NOEXCEPT { return __SCHAR_MAX__; } + +#if __cplusplus >= 201103L + static constexpr signed char + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (signed char); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (signed char); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR signed char + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR signed char + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR signed char + infinity() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR signed char + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR signed char + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR signed char + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR unsigned char + min() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned char + max() _GLIBCXX_USE_NOEXCEPT { return __SCHAR_MAX__ * 2U + 1; } + +#if __cplusplus >= 201103L + static constexpr unsigned char + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (unsigned char); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (unsigned char); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR unsigned char + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned char + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR unsigned char + infinity() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned char + quiet_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned char + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned char + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR wchar_t + min() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_min (wchar_t); } + + static _GLIBCXX_CONSTEXPR wchar_t + max() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_max (wchar_t); } + +#if __cplusplus >= 201103L + static constexpr wchar_t + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (wchar_t); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (wchar_t); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = __glibcxx_signed (wchar_t); + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR wchar_t + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR wchar_t + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR wchar_t + infinity() _GLIBCXX_USE_NOEXCEPT { return wchar_t(); } + + static _GLIBCXX_CONSTEXPR wchar_t + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return wchar_t(); } + + static _GLIBCXX_CONSTEXPR wchar_t + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return wchar_t(); } + + static _GLIBCXX_CONSTEXPR wchar_t + denorm_min() _GLIBCXX_USE_NOEXCEPT { return wchar_t(); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = !is_signed; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + +#if __cplusplus >= 201103L + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static constexpr bool is_specialized = true; + + static constexpr char16_t + min() noexcept { return __glibcxx_min (char16_t); } + + static constexpr char16_t + max() noexcept { return __glibcxx_max (char16_t); } + + static constexpr char16_t + lowest() noexcept { return min(); } + + static constexpr int digits = __glibcxx_digits (char16_t); + static constexpr int digits10 = __glibcxx_digits10 (char16_t); + static constexpr int max_digits10 = 0; + static constexpr bool is_signed = __glibcxx_signed (char16_t); + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr int radix = 2; + + static constexpr char16_t + epsilon() noexcept { return 0; } + + static constexpr char16_t + round_error() noexcept { return 0; } + + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + + static constexpr char16_t + infinity() noexcept { return char16_t(); } + + static constexpr char16_t + quiet_NaN() noexcept { return char16_t(); } + + static constexpr char16_t + signaling_NaN() noexcept { return char16_t(); } + + static constexpr char16_t + denorm_min() noexcept { return char16_t(); } + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = !is_signed; + + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr bool tinyness_before = false; + static constexpr float_round_style round_style = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static constexpr bool is_specialized = true; + + static constexpr char32_t + min() noexcept { return __glibcxx_min (char32_t); } + + static constexpr char32_t + max() noexcept { return __glibcxx_max (char32_t); } + + static constexpr char32_t + lowest() noexcept { return min(); } + + static constexpr int digits = __glibcxx_digits (char32_t); + static constexpr int digits10 = __glibcxx_digits10 (char32_t); + static constexpr int max_digits10 = 0; + static constexpr bool is_signed = __glibcxx_signed (char32_t); + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr int radix = 2; + + static constexpr char32_t + epsilon() noexcept { return 0; } + + static constexpr char32_t + round_error() noexcept { return 0; } + + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; + + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + + static constexpr char32_t + infinity() noexcept { return char32_t(); } + + static constexpr char32_t + quiet_NaN() noexcept { return char32_t(); } + + static constexpr char32_t + signaling_NaN() noexcept { return char32_t(); } + + static constexpr char32_t + denorm_min() noexcept { return char32_t(); } + + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = !is_signed; + + static constexpr bool traps = __glibcxx_integral_traps; + static constexpr bool tinyness_before = false; + static constexpr float_round_style round_style = round_toward_zero; + }; +#endif + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR short + min() _GLIBCXX_USE_NOEXCEPT { return -__SHRT_MAX__ - 1; } + + static _GLIBCXX_CONSTEXPR short + max() _GLIBCXX_USE_NOEXCEPT { return __SHRT_MAX__; } + +#if __cplusplus >= 201103L + static constexpr short + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (short); + static _GLIBCXX_USE_CONSTEXPR int digits10 = __glibcxx_digits10 (short); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR short + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR short + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR short + infinity() _GLIBCXX_USE_NOEXCEPT { return short(); } + + static _GLIBCXX_CONSTEXPR short + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return short(); } + + static _GLIBCXX_CONSTEXPR short + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return short(); } + + static _GLIBCXX_CONSTEXPR short + denorm_min() _GLIBCXX_USE_NOEXCEPT { return short(); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR unsigned short + min() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned short + max() _GLIBCXX_USE_NOEXCEPT { return __SHRT_MAX__ * 2U + 1; } + +#if __cplusplus >= 201103L + static constexpr unsigned short + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (unsigned short); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (unsigned short); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR unsigned short + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned short + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR unsigned short + infinity() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned short + quiet_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned short + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned short + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR int + min() _GLIBCXX_USE_NOEXCEPT { return -__INT_MAX__ - 1; } + + static _GLIBCXX_CONSTEXPR int + max() _GLIBCXX_USE_NOEXCEPT { return __INT_MAX__; } + +#if __cplusplus >= 201103L + static constexpr int + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (int); + static _GLIBCXX_USE_CONSTEXPR int digits10 = __glibcxx_digits10 (int); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR int + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR int + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR int + infinity() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR int + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR int + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR int + denorm_min() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR unsigned int + min() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned int + max() _GLIBCXX_USE_NOEXCEPT { return __INT_MAX__ * 2U + 1; } + +#if __cplusplus >= 201103L + static constexpr unsigned int + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (unsigned int); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (unsigned int); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR unsigned int + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned int + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR unsigned int + infinity() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned int + quiet_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned int + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned int + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR long + min() _GLIBCXX_USE_NOEXCEPT { return -__LONG_MAX__ - 1; } + + static _GLIBCXX_CONSTEXPR long + max() _GLIBCXX_USE_NOEXCEPT { return __LONG_MAX__; } + +#if __cplusplus >= 201103L + static constexpr long + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __glibcxx_digits (long); + static _GLIBCXX_USE_CONSTEXPR int digits10 = __glibcxx_digits10 (long); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR long + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR long + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR long + infinity() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long + denorm_min() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR unsigned long + min() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned long + max() _GLIBCXX_USE_NOEXCEPT { return __LONG_MAX__ * 2UL + 1; } + +#if __cplusplus >= 201103L + static constexpr unsigned long + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (unsigned long); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (unsigned long); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR unsigned long + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned long + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR unsigned long + infinity() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long + quiet_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR long long + min() _GLIBCXX_USE_NOEXCEPT { return -__LONG_LONG_MAX__ - 1; } + + static _GLIBCXX_CONSTEXPR long long + max() _GLIBCXX_USE_NOEXCEPT { return __LONG_LONG_MAX__; } + +#if __cplusplus >= 201103L + static constexpr long long + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (long long); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (long long); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR long long + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR long long + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR long long + infinity() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long long + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long long + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR long long + denorm_min() _GLIBCXX_USE_NOEXCEPT { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR unsigned long long + min() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned long long + max() _GLIBCXX_USE_NOEXCEPT { return __LONG_LONG_MAX__ * 2ULL + 1; } + +#if __cplusplus >= 201103L + static constexpr unsigned long long + lowest() noexcept { return min(); } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits + = __glibcxx_digits (unsigned long long); + static _GLIBCXX_USE_CONSTEXPR int digits10 + = __glibcxx_digits10 (unsigned long long); +#if __cplusplus >= 201103L + static constexpr int max_digits10 = 0; +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; + static _GLIBCXX_USE_CONSTEXPR int radix = 2; + + static _GLIBCXX_CONSTEXPR unsigned long long + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_CONSTEXPR unsigned long long + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; + + static _GLIBCXX_CONSTEXPR unsigned long long + infinity() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long long + quiet_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long long + signaling_NaN() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_CONSTEXPR unsigned long long + denorm_min() _GLIBCXX_USE_NOEXCEPT + { return static_cast(0); } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_toward_zero; + }; + +#if !defined(__STRICT_ANSI__) + +#define __INT_N(TYPE, BITSIZE, EXT, UEXT) \ + template<> \ + struct numeric_limits \ + { \ + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + min() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_min_b (TYPE, BITSIZE); } \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + max() _GLIBCXX_USE_NOEXCEPT { return __glibcxx_max_b (TYPE, BITSIZE); } \ + \ + static _GLIBCXX_USE_CONSTEXPR int digits \ + = BITSIZE - 1; \ + static _GLIBCXX_USE_CONSTEXPR int digits10 \ + = (BITSIZE - 1) * 643L / 2136; \ + \ + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; \ + static _GLIBCXX_USE_CONSTEXPR int radix = 2; \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } \ + \ + EXT \ + \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; \ + \ + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; \ + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; \ + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; \ + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm \ + = denorm_absent; \ + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + infinity() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + quiet_NaN() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + signaling_NaN() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR TYPE \ + denorm_min() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; \ + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; \ + \ + static _GLIBCXX_USE_CONSTEXPR bool traps \ + = __glibcxx_integral_traps; \ + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; \ + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style \ + = round_toward_zero; \ + }; \ + \ + template<> \ + struct numeric_limits \ + { \ + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + min() _GLIBCXX_USE_NOEXCEPT { return 0; } \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + max() _GLIBCXX_USE_NOEXCEPT \ + { return __glibcxx_max_b (unsigned TYPE, BITSIZE); } \ + \ + UEXT \ + \ + static _GLIBCXX_USE_CONSTEXPR int digits \ + = BITSIZE; \ + static _GLIBCXX_USE_CONSTEXPR int digits10 \ + = BITSIZE * 643L / 2136; \ + static _GLIBCXX_USE_CONSTEXPR bool is_signed = false; \ + static _GLIBCXX_USE_CONSTEXPR bool is_integer = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_exact = true; \ + static _GLIBCXX_USE_CONSTEXPR int radix = 2; \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + epsilon() _GLIBCXX_USE_NOEXCEPT { return 0; } \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + round_error() _GLIBCXX_USE_NOEXCEPT { return 0; } \ + \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent = 0; \ + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = 0; \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent = 0; \ + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = 0; \ + \ + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = false; \ + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = false; \ + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = false; \ + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm \ + = denorm_absent; \ + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = false; \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + infinity() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + quiet_NaN() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + signaling_NaN() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_CONSTEXPR unsigned TYPE \ + denorm_min() _GLIBCXX_USE_NOEXCEPT \ + { return static_cast(0); } \ + \ + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = false; \ + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; \ + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true; \ + \ + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_integral_traps; \ + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = false; \ + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style \ + = round_toward_zero; \ + }; + +#if __cplusplus >= 201103L + +#define __INT_N_201103(TYPE) \ + static constexpr TYPE \ + lowest() noexcept { return min(); } \ + static constexpr int max_digits10 = 0; + +#define __INT_N_U201103(TYPE) \ + static constexpr unsigned TYPE \ + lowest() noexcept { return min(); } \ + static constexpr int max_digits10 = 0; + +#else +#define __INT_N_201103(TYPE) +#define __INT_N_U201103(TYPE) +#endif + +#ifdef __GLIBCXX_TYPE_INT_N_0 + __INT_N(__GLIBCXX_TYPE_INT_N_0, __GLIBCXX_BITSIZE_INT_N_0, + __INT_N_201103 (__GLIBCXX_TYPE_INT_N_0), __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_0)) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_1 + __INT_N (__GLIBCXX_TYPE_INT_N_1, __GLIBCXX_BITSIZE_INT_N_1, + __INT_N_201103 (__GLIBCXX_TYPE_INT_N_1), __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_1)) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_2 + __INT_N (__GLIBCXX_TYPE_INT_N_2, __GLIBCXX_BITSIZE_INT_N_2, + __INT_N_201103 (__GLIBCXX_TYPE_INT_N_2), __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_2)) +#endif +#ifdef __GLIBCXX_TYPE_INT_N_3 + __INT_N (__GLIBCXX_TYPE_INT_N_3, __GLIBCXX_BITSIZE_INT_N_3, + __INT_N_201103 (__GLIBCXX_TYPE_INT_N_3), __INT_N_U201103 (__GLIBCXX_TYPE_INT_N_3)) +#endif + +#undef __INT_N +#undef __INT_N_201103 +#undef __INT_N_U201103 + +#endif + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR float + min() _GLIBCXX_USE_NOEXCEPT { return __FLT_MIN__; } + + static _GLIBCXX_CONSTEXPR float + max() _GLIBCXX_USE_NOEXCEPT { return __FLT_MAX__; } + +#if __cplusplus >= 201103L + static constexpr float + lowest() noexcept { return -__FLT_MAX__; } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __FLT_MANT_DIG__; + static _GLIBCXX_USE_CONSTEXPR int digits10 = __FLT_DIG__; +#if __cplusplus >= 201103L + static constexpr int max_digits10 + = __glibcxx_max_digits10 (__FLT_MANT_DIG__); +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; + static _GLIBCXX_USE_CONSTEXPR int radix = __FLT_RADIX__; + + static _GLIBCXX_CONSTEXPR float + epsilon() _GLIBCXX_USE_NOEXCEPT { return __FLT_EPSILON__; } + + static _GLIBCXX_CONSTEXPR float + round_error() _GLIBCXX_USE_NOEXCEPT { return 0.5F; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = __FLT_MIN_EXP__; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = __FLT_MIN_10_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = __FLT_MAX_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = __FLT_MAX_10_EXP__; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = __FLT_HAS_INFINITY__; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = __FLT_HAS_QUIET_NAN__; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = has_quiet_NaN; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = bool(__FLT_HAS_DENORM__) ? denorm_present : denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss + = __glibcxx_float_has_denorm_loss; + + static _GLIBCXX_CONSTEXPR float + infinity() _GLIBCXX_USE_NOEXCEPT { return __builtin_huge_valf(); } + + static _GLIBCXX_CONSTEXPR float + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nanf(""); } + + static _GLIBCXX_CONSTEXPR float + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nansf(""); } + + static _GLIBCXX_CONSTEXPR float + denorm_min() _GLIBCXX_USE_NOEXCEPT { return __FLT_DENORM_MIN__; } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 + = has_infinity && has_quiet_NaN && has_denorm == denorm_present; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_float_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before + = __glibcxx_float_tinyness_before; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_to_nearest; + }; + +#undef __glibcxx_float_has_denorm_loss +#undef __glibcxx_float_traps +#undef __glibcxx_float_tinyness_before + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR double + min() _GLIBCXX_USE_NOEXCEPT { return __DBL_MIN__; } + + static _GLIBCXX_CONSTEXPR double + max() _GLIBCXX_USE_NOEXCEPT { return __DBL_MAX__; } + +#if __cplusplus >= 201103L + static constexpr double + lowest() noexcept { return -__DBL_MAX__; } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __DBL_MANT_DIG__; + static _GLIBCXX_USE_CONSTEXPR int digits10 = __DBL_DIG__; +#if __cplusplus >= 201103L + static constexpr int max_digits10 + = __glibcxx_max_digits10 (__DBL_MANT_DIG__); +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; + static _GLIBCXX_USE_CONSTEXPR int radix = __FLT_RADIX__; + + static _GLIBCXX_CONSTEXPR double + epsilon() _GLIBCXX_USE_NOEXCEPT { return __DBL_EPSILON__; } + + static _GLIBCXX_CONSTEXPR double + round_error() _GLIBCXX_USE_NOEXCEPT { return 0.5; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = __DBL_MIN_EXP__; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = __DBL_MIN_10_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = __DBL_MAX_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = __DBL_MAX_10_EXP__; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = __DBL_HAS_INFINITY__; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = __DBL_HAS_QUIET_NAN__; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = has_quiet_NaN; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = bool(__DBL_HAS_DENORM__) ? denorm_present : denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss + = __glibcxx_double_has_denorm_loss; + + static _GLIBCXX_CONSTEXPR double + infinity() _GLIBCXX_USE_NOEXCEPT { return __builtin_huge_val(); } + + static _GLIBCXX_CONSTEXPR double + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nan(""); } + + static _GLIBCXX_CONSTEXPR double + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nans(""); } + + static _GLIBCXX_CONSTEXPR double + denorm_min() _GLIBCXX_USE_NOEXCEPT { return __DBL_DENORM_MIN__; } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 + = has_infinity && has_quiet_NaN && has_denorm == denorm_present; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_double_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before + = __glibcxx_double_tinyness_before; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style + = round_to_nearest; + }; + +#undef __glibcxx_double_has_denorm_loss +#undef __glibcxx_double_traps +#undef __glibcxx_double_tinyness_before + + /// numeric_limits specialization. + template<> + struct numeric_limits + { + static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true; + + static _GLIBCXX_CONSTEXPR long double + min() _GLIBCXX_USE_NOEXCEPT { return __LDBL_MIN__; } + + static _GLIBCXX_CONSTEXPR long double + max() _GLIBCXX_USE_NOEXCEPT { return __LDBL_MAX__; } + +#if __cplusplus >= 201103L + static constexpr long double + lowest() noexcept { return -__LDBL_MAX__; } +#endif + + static _GLIBCXX_USE_CONSTEXPR int digits = __LDBL_MANT_DIG__; + static _GLIBCXX_USE_CONSTEXPR int digits10 = __LDBL_DIG__; +#if __cplusplus >= 201103L + static _GLIBCXX_USE_CONSTEXPR int max_digits10 + = __glibcxx_max_digits10 (__LDBL_MANT_DIG__); +#endif + static _GLIBCXX_USE_CONSTEXPR bool is_signed = true; + static _GLIBCXX_USE_CONSTEXPR bool is_integer = false; + static _GLIBCXX_USE_CONSTEXPR bool is_exact = false; + static _GLIBCXX_USE_CONSTEXPR int radix = __FLT_RADIX__; + + static _GLIBCXX_CONSTEXPR long double + epsilon() _GLIBCXX_USE_NOEXCEPT { return __LDBL_EPSILON__; } + + static _GLIBCXX_CONSTEXPR long double + round_error() _GLIBCXX_USE_NOEXCEPT { return 0.5L; } + + static _GLIBCXX_USE_CONSTEXPR int min_exponent = __LDBL_MIN_EXP__; + static _GLIBCXX_USE_CONSTEXPR int min_exponent10 = __LDBL_MIN_10_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent = __LDBL_MAX_EXP__; + static _GLIBCXX_USE_CONSTEXPR int max_exponent10 = __LDBL_MAX_10_EXP__; + + static _GLIBCXX_USE_CONSTEXPR bool has_infinity = __LDBL_HAS_INFINITY__; + static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = __LDBL_HAS_QUIET_NAN__; + static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = has_quiet_NaN; + static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm + = bool(__LDBL_HAS_DENORM__) ? denorm_present : denorm_absent; + static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss + = __glibcxx_long_double_has_denorm_loss; + + static _GLIBCXX_CONSTEXPR long double + infinity() _GLIBCXX_USE_NOEXCEPT { return __builtin_huge_vall(); } + + static _GLIBCXX_CONSTEXPR long double + quiet_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nanl(""); } + + static _GLIBCXX_CONSTEXPR long double + signaling_NaN() _GLIBCXX_USE_NOEXCEPT { return __builtin_nansl(""); } + + static _GLIBCXX_CONSTEXPR long double + denorm_min() _GLIBCXX_USE_NOEXCEPT { return __LDBL_DENORM_MIN__; } + + static _GLIBCXX_USE_CONSTEXPR bool is_iec559 + = has_infinity && has_quiet_NaN && has_denorm == denorm_present; + static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true; + static _GLIBCXX_USE_CONSTEXPR bool is_modulo = false; + + static _GLIBCXX_USE_CONSTEXPR bool traps = __glibcxx_long_double_traps; + static _GLIBCXX_USE_CONSTEXPR bool tinyness_before = + __glibcxx_long_double_tinyness_before; + static _GLIBCXX_USE_CONSTEXPR float_round_style round_style = + round_to_nearest; + }; + +#undef __glibcxx_long_double_has_denorm_loss +#undef __glibcxx_long_double_traps +#undef __glibcxx_long_double_tinyness_before + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#undef __glibcxx_signed +#undef __glibcxx_min +#undef __glibcxx_max +#undef __glibcxx_digits +#undef __glibcxx_digits10 +#undef __glibcxx_max_digits10 + +#endif // _GLIBCXX_NUMERIC_LIMITS diff --git a/AH/STL/Fallback/memory b/AH/STL/Fallback/memory new file mode 100644 index 0000000..7985556 --- /dev/null +++ b/AH/STL/Fallback/memory @@ -0,0 +1,8 @@ +#ifndef _GLIBCXX_MEMORY +#define _GLIBCXX_MEMORY 1 + +#pragma GCC system_header + +#include "bits/unique_ptr.h" + +#endif \ No newline at end of file diff --git a/AH/STL/Fallback/new b/AH/STL/Fallback/new new file mode 100644 index 0000000..b3114cb --- /dev/null +++ b/AH/STL/Fallback/new @@ -0,0 +1,229 @@ +// The -*- C++ -*- dynamic memory management header. + +// Copyright (C) 1994-2017 Free Software Foundation, Inc. + +// This file is part of GCC. +// +// GCC is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// GCC is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file new + * This is a Standard C++ Library header. + * + * The header @c new defines several functions to manage dynamic memory and + * handling memory allocation errors; see + * http://gcc.gnu.org/onlinedocs/libstdc++/18_support/howto.html#4 for more. + */ + +#ifndef _NEW +#define _NEW + +#pragma GCC system_header + +#include "bits/c++config.h" +// #include + +#include // Arduino's version of the header + +#pragma GCC visibility push(default) + +extern "C++" { + +namespace std +{ +#if 0 + /** + * @brief Exception possibly thrown by @c new. + * @ingroup exceptions + * + * @c bad_alloc (or classes derived from it) is used to report allocation + * errors from the throwing forms of @c new. */ + class bad_alloc : public exception + { + public: + bad_alloc() throw() { } + + // This declaration is not useless: + // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 + virtual ~bad_alloc() throw(); + + // See comment in eh_exception.cc. + virtual const char* what() const throw(); + }; + +#if __cplusplus >= 201103L + class bad_array_new_length : public bad_alloc + { + public: + bad_array_new_length() throw() { }; + + // This declaration is not useless: + // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 + virtual ~bad_array_new_length() throw(); + + // See comment in eh_exception.cc. + virtual const char* what() const throw(); + }; +#endif + +#endif // 0 + +#if __cpp_aligned_new + enum class align_val_t: size_t {}; +#endif + +#if !defined(NEW_H) || defined(__AVR_ATmega4809__) || defined(ARDUINO_TEENSY2PP) // already defined in Arduino's version of + struct nothrow_t + { +#if __cplusplus >= 201103L + explicit nothrow_t() = default; +#endif + }; + + extern const nothrow_t nothrow; + + /** If you write your own error handler to be called by @c new, it must + * be of this type. */ + typedef void (*new_handler)(); + + /// Takes a replacement handler as the argument, returns the + /// previous handler. + new_handler set_new_handler(new_handler) throw(); + +#if __cplusplus >= 201103L + /// Return the current new handler. + new_handler get_new_handler() noexcept; +#endif +#endif // NEW_H +} // namespace std + +//@{ +#if !defined(NEW_H) || defined(__AVR_ATmega4809__) || defined(ARDUINO_TEENSY2PP) // already defined in Arduino's version of +/** These are replaceable signatures: + * - normal single new and delete (no arguments, throw @c bad_alloc on error) + * - normal array new and delete (same) + * - @c nothrow single new and delete (take a @c nothrow argument, return + * @c NULL on error) + * - @c nothrow array new and delete (same) + * + * Placement new and delete signatures (take a memory address argument, + * does nothing) may not be replaced by a user's program. +*/ +#ifndef __AVR_ATmega4809__ +void* operator new(std::size_t) _GLIBCXX_THROW (std::bad_alloc) + __attribute__((__externally_visible__)); +void* operator new[](std::size_t) _GLIBCXX_THROW (std::bad_alloc) + __attribute__((__externally_visible__)); +void operator delete(void*) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +void operator delete[](void*) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +#endif +#if __cpp_sized_deallocation +void operator delete(void*, std::size_t) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +void operator delete[](void*, std::size_t) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +#endif +void* operator new(std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +void* operator new[](std::size_t, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +void operator delete(void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +void operator delete[](void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT + __attribute__((__externally_visible__)); +#if __cpp_aligned_new +void* operator new(std::size_t, std::align_val_t) + __attribute__((__externally_visible__)); +void* operator new(std::size_t, std::align_val_t, const std::nothrow_t&) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void operator delete(void*, std::align_val_t) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void operator delete(void*, std::align_val_t, const std::nothrow_t&) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void* operator new[](std::size_t, std::align_val_t) + __attribute__((__externally_visible__)); +void* operator new[](std::size_t, std::align_val_t, const std::nothrow_t&) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void operator delete[](void*, std::align_val_t) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void operator delete[](void*, std::align_val_t, const std::nothrow_t&) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +#if __cpp_sized_deallocation +void operator delete(void*, std::size_t, std::align_val_t) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +void operator delete[](void*, std::size_t, std::align_val_t) + _GLIBCXX_USE_NOEXCEPT __attribute__((__externally_visible__)); +#endif // __cpp_sized_deallocation +#endif // __cpp_aligned_new + +// Default placement versions of operator new. +inline void* operator new(std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT +{ return __p; } +inline void* operator new[](std::size_t, void* __p) _GLIBCXX_USE_NOEXCEPT +{ return __p; } + +// Default placement versions of operator delete. +inline void operator delete (void*, void*) _GLIBCXX_USE_NOEXCEPT { } +inline void operator delete[](void*, void*) _GLIBCXX_USE_NOEXCEPT { } +#endif // NEW_H +//@} +} // extern "C++" + +#if __cplusplus > 201402L +#if __GNUC__ >= 7 +# define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1 +#elif defined __has_builtin +// For non-GNU compilers: +# if __has_builtin(__builtin_launder) +# define _GLIBCXX_HAVE_BUILTIN_LAUNDER 1 +# endif +#endif + +#ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER +namespace std +{ +#define __cpp_lib_launder 201606 + /// Pointer optimization barrier [ptr.launder] + template + constexpr _Tp* + launder(_Tp* __p) noexcept + { return __builtin_launder(__p); } + + // The program is ill-formed if T is a function type or + // (possibly cv-qualified) void. + + template + void launder(_Ret (*)(_Args...) _GLIBCXX_NOEXCEPT_QUAL) = delete; + template + void launder(_Ret (*)(_Args......) _GLIBCXX_NOEXCEPT_QUAL) = delete; + + void launder(void*) = delete; + void launder(const void*) = delete; + void launder(volatile void*) = delete; + void launder(const volatile void*) = delete; +} +#endif // _GLIBCXX_HAVE_BUILTIN_LAUNDER +#undef _GLIBCXX_HAVE_BUILTIN_LAUNDER +#endif // C++17 + +#pragma GCC visibility pop + +#endif diff --git a/AH/STL/Fallback/numeric b/AH/STL/Fallback/numeric new file mode 100644 index 0000000..4552372 --- /dev/null +++ b/AH/STL/Fallback/numeric @@ -0,0 +1,165 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/numeric + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_NUMERIC +#define _GLIBCXX_NUMERIC 1 + +#pragma GCC system_header + +#include "bits/c++config.h" +#include "bits/stl_iterator_base_types.h" +#include "bits/stl_numeric.h" + +#ifdef _GLIBCXX_PARALLEL +# include +#endif + +/** + * @defgroup numerics Numerics + * + * Components for performing numeric operations. Includes support for + * for complex number types, random number generation, numeric + * (n-at-a-time) arrays, generalized numeric algorithms, and special + * math functions. + */ + +#if __cplusplus >= 201402L +#include "type_traits" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +namespace __detail +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + // std::abs is not constexpr and doesn't support unsigned integers. + template + constexpr + enable_if_t<__and_, is_signed<_Tp>>::value, _Tp> + __abs_integral(_Tp __val) + { return __val < 0 ? -__val : __val; } + + template + constexpr + enable_if_t<__and_, is_unsigned<_Tp>>::value, _Tp> + __abs_integral(_Tp __val) + { return __val; } + + void __abs_integral(bool) = delete; + + template + constexpr common_type_t<_Mn, _Nn> + __gcd(_Mn __m, _Nn __n) + { + return __m == 0 ? __detail::__abs_integral(__n) + : __n == 0 ? __detail::__abs_integral(__m) + : __detail::__gcd(__n, __m % __n); + } + + /// Least common multiple + template + constexpr common_type_t<_Mn, _Nn> + __lcm(_Mn __m, _Nn __n) + { + return (__m != 0 && __n != 0) + ? (__detail::__abs_integral(__m) / __detail::__gcd(__m, __n)) + * __detail::__abs_integral(__n) + : 0; + } + +_GLIBCXX_END_NAMESPACE_VERSION +} + +_GLIBCXX_BEGIN_NAMESPACE_VERSION + +#if __cplusplus > 201402L + +#define __cpp_lib_gcd_lcm 201606 +// These were used in drafts of SD-6: +#define __cpp_lib_gcd 201606 +#define __cpp_lib_lcm 201606 + + /// Greatest common divisor + template + constexpr common_type_t<_Mn, _Nn> + gcd(_Mn __m, _Nn __n) + { + static_assert(is_integral<_Mn>::value, "gcd arguments are integers"); + static_assert(is_integral<_Nn>::value, "gcd arguments are integers"); + static_assert(!is_same<_Mn, bool>::value, "gcd arguments are not bools"); + static_assert(!is_same<_Nn, bool>::value, "gcd arguments are not bools"); + return __detail::__gcd(__m, __n); + } + + /// Least common multiple + template + constexpr common_type_t<_Mn, _Nn> + lcm(_Mn __m, _Nn __n) + { + static_assert(is_integral<_Mn>::value, "lcm arguments are integers"); + static_assert(is_integral<_Nn>::value, "lcm arguments are integers"); + static_assert(!is_same<_Mn, bool>::value, "lcm arguments are not bools"); + static_assert(!is_same<_Nn, bool>::value, "lcm arguments are not bools"); + return __detail::__lcm(__m, __n); + } + +#endif // C++17 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++14 + + +#endif /* _GLIBCXX_NUMERIC */ diff --git a/AH/STL/Fallback/optional b/AH/STL/Fallback/optional new file mode 100644 index 0000000..e640257 --- /dev/null +++ b/AH/STL/Fallback/optional @@ -0,0 +1,1054 @@ +// -*- C++ -*- + +// Copyright (C) 2013-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/optional + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_OPTIONAL +#define _GLIBCXX_OPTIONAL 1 + +#pragma GCC system_header + +#if __cplusplus >= 201703L + +#include "utility" +#include "type_traits" +// #include "stdexcept" +#include "new" +#include "initializer_list" +// #include "bits/functexcept.h" +#include "bits/functional_hash.h" +#include "bits/enable_special_members.h" + +#ifdef ARDUINO +#include +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + +#define __cpp_lib_optional 201603 + + template + class optional; + + /// Tag type to disengage optional objects. + struct nullopt_t + { + // Do not user-declare default constructor at all for + // optional_value = {} syntax to work. + // nullopt_t() = delete; + + // Used for constructing nullopt. + enum class _Construct { _Token }; + + // Must be constexpr for nullopt_t to be literal. + explicit constexpr nullopt_t(_Construct) { } + }; + + /// Tag to disengage optional objects. + inline constexpr nullopt_t nullopt { nullopt_t::_Construct::_Token }; + +#ifndef __AVR__ + /** + * @brief Exception class thrown when a disengaged optional object is + * dereferenced. + * @ingroup exceptions + */ + class bad_optional_access : public exception + { + public: + bad_optional_access() { } + virtual const char* what() const noexcept override + {return "bad optional access";} + + virtual ~bad_optional_access() noexcept = default; + }; + + void + __throw_bad_optional_access() + __attribute__((__noreturn__)); + + // XXX Does not belong here. + inline void + __throw_bad_optional_access() + { _GLIBCXX_THROW_OR_ABORT(bad_optional_access()); } +#else + +#define __throw_bad_optional_access() [] { \ + ERROR(F("Bad optional access"), 0x3874); \ +}() + +#endif + + // Payload for constexpr optionals. + template ::value + && is_trivially_move_constructible<_Tp>::value, + bool /*_ShouldProvideDestructor*/ = + is_trivially_destructible<_Tp>::value> + struct _Optional_payload + { + constexpr _Optional_payload() + : _M_empty() {} + + template + constexpr _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), + _M_engaged(true) + {} + + template + constexpr _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true) {} + + template struct __ctor_tag {}; + + constexpr _Optional_payload(__ctor_tag, + const _Tp& __other) + : _M_payload(__other), + _M_engaged(true) + {} + + constexpr _Optional_payload(__ctor_tag) + : _M_empty() + {} + + constexpr _Optional_payload(__ctor_tag, _Tp&& __other) + : _M_payload(std::move(__other)), + _M_engaged(true) + {} + + constexpr _Optional_payload(bool __engaged, + const _Optional_payload& __other) + : _Optional_payload(__engaged ? + _Optional_payload(__ctor_tag{}, + __other._M_payload) : + _Optional_payload(__ctor_tag{})) + {} + + constexpr _Optional_payload(bool __engaged, + _Optional_payload&& __other) + : _Optional_payload(__engaged + ? _Optional_payload(__ctor_tag{}, + std::move(__other._M_payload)) + : _Optional_payload(__ctor_tag{})) + {} + + using _Stored_type = remove_const_t<_Tp>; + struct _Empty_byte { }; + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged = false; + }; + + // Payload for non-constexpr optionals with non-trivial destructor. + template + struct _Optional_payload<_Tp, false, false> + { + constexpr _Optional_payload() + : _M_empty() {} + + template + constexpr _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), + _M_engaged(true) {} + + template + constexpr _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true) {} + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__other) + {} + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(std::move(__other)) + {} + + constexpr _Optional_payload(const _Optional_payload& __other) + { + if (__other._M_engaged) + this->_M_construct(__other._M_payload); + } + + constexpr _Optional_payload(_Optional_payload&& __other) + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_payload)); + } + + using _Stored_type = remove_const_t<_Tp>; + struct _Empty_byte { }; + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged = false; + + ~_Optional_payload() + { + if (_M_engaged) + _M_payload.~_Stored_type(); + } + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible<_Stored_type, _Args...>()) + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + }; + + // Payload for non-constexpr optionals with trivial destructor. + template + struct _Optional_payload<_Tp, false, true> + { + constexpr _Optional_payload() + : _M_empty() {} + + template + constexpr _Optional_payload(in_place_t, _Args&&... __args) + : _M_payload(std::forward<_Args>(__args)...), + _M_engaged(true) {} + + template + constexpr _Optional_payload(std::initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(__il, std::forward<_Args>(__args)...), + _M_engaged(true) {} + constexpr + _Optional_payload(bool __engaged, const _Optional_payload& __other) + : _Optional_payload(__other) + {} + + constexpr + _Optional_payload(bool __engaged, _Optional_payload&& __other) + : _Optional_payload(std::move(__other)) + {} + + constexpr _Optional_payload(const _Optional_payload& __other) + { + if (__other._M_engaged) + this->_M_construct(__other._M_payload); + } + + constexpr _Optional_payload(_Optional_payload&& __other) + { + if (__other._M_engaged) + this->_M_construct(std::move(__other._M_payload)); + } + + using _Stored_type = remove_const_t<_Tp>; + struct _Empty_byte { }; + union { + _Empty_byte _M_empty; + _Stored_type _M_payload; + }; + bool _M_engaged = false; + + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible<_Stored_type, _Args...>()) + { + ::new ((void *) std::__addressof(this->_M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + this->_M_engaged = true; + } + }; + + /** + * @brief Class template that holds the necessary state for @ref optional + * and that has the responsibility for construction and the special members. + * + * Such a separate base class template is necessary in order to + * conditionally enable the special members (e.g. copy/move constructors). + * Note that this means that @ref _Optional_base implements the + * functionality for copy and move assignment, but not for converting + * assignment. + * + * @see optional, _Enable_special_members + */ + template + class _Optional_base + { + private: + // Remove const to avoid prohibition of reusing object storage for + // const-qualified types in [3.8/9]. This is strictly internal + // and even optional itself is oblivious to it. + using _Stored_type = remove_const_t<_Tp>; + + public: + + // Constructors for disengaged optionals. + constexpr _Optional_base() noexcept + { } + + constexpr _Optional_base(nullopt_t) noexcept + { } + + // Constructors for engaged optionals. + template, bool> = false> + constexpr explicit _Optional_base(in_place_t, _Args&&... __args) + : _M_payload(in_place, + std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + constexpr explicit _Optional_base(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _M_payload(in_place, + __il, std::forward<_Args>(__args)...) + { } + + // Copy and move constructors. + constexpr _Optional_base(const _Optional_base& __other) + : _M_payload(__other._M_payload._M_engaged, + __other._M_payload) + { } + + constexpr _Optional_base(_Optional_base&& __other) + noexcept(is_nothrow_move_constructible<_Tp>()) + : _M_payload(__other._M_payload._M_engaged, + std::move(__other._M_payload)) + { } + + // Assignment operators. + _Optional_base& + operator=(const _Optional_base& __other) + { + if (this->_M_payload._M_engaged && __other._M_payload._M_engaged) + this->_M_get() = __other._M_get(); + else + { + if (__other._M_payload._M_engaged) + this->_M_construct(__other._M_get()); + else + this->_M_reset(); + } + + return *this; + } + + _Optional_base& + operator=(_Optional_base&& __other) + noexcept(__and_, + is_nothrow_move_assignable<_Tp>>()) + { + if (this->_M_payload._M_engaged && __other._M_payload._M_engaged) + this->_M_get() = std::move(__other._M_get()); + else + { + if (__other._M_payload._M_engaged) + this->_M_construct(std::move(__other._M_get())); + else + this->_M_reset(); + } + return *this; + } + // The following functionality is also needed by optional, hence the + // protected accessibility. + protected: + constexpr bool _M_is_engaged() const noexcept + { return this->_M_payload._M_engaged; } + + // The _M_get operations have _M_engaged as a precondition. + constexpr _Tp& + _M_get() noexcept + { return this->_M_payload._M_payload; } + + constexpr const _Tp& + _M_get() const noexcept + { return this->_M_payload._M_payload; } + + // The _M_construct operation has !_M_engaged as a precondition + // while _M_destruct has _M_engaged as a precondition. + template + void + _M_construct(_Args&&... __args) + noexcept(is_nothrow_constructible<_Stored_type, _Args...>()) + { + ::new (std::__addressof(this->_M_payload._M_payload)) + _Stored_type(std::forward<_Args>(__args)...); + this->_M_payload._M_engaged = true; + } + + void + _M_destruct() + { + this->_M_payload._M_engaged = false; + this->_M_payload._M_payload.~_Stored_type(); + } + + // _M_reset is a 'safe' operation with no precondition. + void + _M_reset() + { + if (this->_M_payload._M_engaged) + this->_M_destruct(); + } + + private: + _Optional_payload<_Tp> _M_payload; + }; + + template + class optional; + + template + using __converts_from_optional = + __or_&>, + is_constructible<_Tp, optional<_Up>&>, + is_constructible<_Tp, const optional<_Up>&&>, + is_constructible<_Tp, optional<_Up>&&>, + is_convertible&, _Tp>, + is_convertible&, _Tp>, + is_convertible&&, _Tp>, + is_convertible&&, _Tp>>; + + template + using __assigns_from_optional = + __or_&>, + is_assignable<_Tp&, optional<_Up>&>, + is_assignable<_Tp&, const optional<_Up>&&>, + is_assignable<_Tp&, optional<_Up>&&>>; + + /** + * @brief Class template for optional values. + */ + template + class optional + : private _Optional_base<_Tp>, + private _Enable_copy_move< + // Copy constructor. + is_copy_constructible<_Tp>::value, + // Copy assignment. + __and_, is_copy_assignable<_Tp>>::value, + // Move constructor. + is_move_constructible<_Tp>::value, + // Move assignment. + __and_, is_move_assignable<_Tp>>::value, + // Unique tag type. + optional<_Tp>> + { + static_assert(__and_<__not_, nullopt_t>>, + __not_, in_place_t>>, + __not_>>(), + "Invalid instantiation of optional"); + + private: + using _Base = _Optional_base<_Tp>; + + public: + using value_type = _Tp; + + constexpr optional() = default; + + constexpr optional(nullopt_t) noexcept + : _Base(nullopt) { } + + // Converting constructors for engaged optionals. + template , decay_t<_Up>>>, + __not_>>, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp> + >::value, bool> = true> + constexpr optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template , decay_t<_Up>>>, + __not_>>, + is_constructible<_Tp, _Up&&>, + __not_> + >::value, bool> = false> + explicit constexpr optional(_Up&& __t) + : _Base(std::in_place, std::forward<_Up>(__t)) { } + + template >, + is_constructible<_Tp, const _Up&>, + is_convertible, + __not_<__converts_from_optional<_Tp, _Up>> + >::value, bool> = true> + constexpr optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, const _Up&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>> + >::value, bool> = false> + explicit constexpr optional(const optional<_Up>& __t) + { + if (__t) + emplace(*__t); + } + + template >, + is_constructible<_Tp, _Up&&>, + is_convertible<_Up&&, _Tp>, + __not_<__converts_from_optional<_Tp, _Up>> + >::value, bool> = true> + constexpr optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template >, + is_constructible<_Tp, _Up&&>, + __not_>, + __not_<__converts_from_optional<_Tp, _Up>> + >::value, bool> = false> + explicit constexpr optional(optional<_Up>&& __t) + { + if (__t) + emplace(std::move(*__t)); + } + + template, bool> = false> + explicit constexpr optional(in_place_t, _Args&&... __args) + : _Base(std::in_place, std::forward<_Args>(__args)...) { } + + template&, + _Args&&...>, bool> = false> + explicit constexpr optional(in_place_t, + initializer_list<_Up> __il, + _Args&&... __args) + : _Base(std::in_place, __il, std::forward<_Args>(__args)...) { } + + // Assignment operators. + optional& + operator=(nullopt_t) noexcept + { + this->_M_reset(); + return *this; + } + + template + enable_if_t<__and_< + __not_, decay_t<_Up>>>, + is_constructible<_Tp, _Up>, + __not_<__and_, + is_same<_Tp, decay_t<_Up>>>>, + is_assignable<_Tp&, _Up>>::value, + optional&> + operator=(_Up&& __u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::forward<_Up>(__u); + else + this->_M_construct(std::forward<_Up>(__u)); + + return *this; + } + + template + enable_if_t<__and_< + __not_>, + is_constructible<_Tp, const _Up&>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, + optional&> + operator=(const optional<_Up>& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = *__u; + else + this->_M_construct(*__u); + } + else + { + this->_M_reset(); + } + return *this; + } + + template + enable_if_t<__and_< + __not_>, + is_constructible<_Tp, _Up>, + is_assignable<_Tp&, _Up>, + __not_<__converts_from_optional<_Tp, _Up>>, + __not_<__assigns_from_optional<_Tp, _Up>> + >::value, + optional&> + operator=(optional<_Up>&& __u) + { + if (__u) + { + if (this->_M_is_engaged()) + this->_M_get() = std::move(*__u); + else + this->_M_construct(std::move(*__u)); + } + else + { + this->_M_reset(); + } + + return *this; + } + + template + enable_if_t::value, _Tp&> + emplace(_Args&&... __args) + { + this->_M_reset(); + this->_M_construct(std::forward<_Args>(__args)...); + return this->_M_get(); + } + + template + enable_if_t&, + _Args&&...>::value, _Tp&> + emplace(initializer_list<_Up> __il, _Args&&... __args) + { + this->_M_reset(); + this->_M_construct(__il, std::forward<_Args>(__args)...); + return this->_M_get(); + } + + // Destructor is implicit, implemented in _Optional_base. + + // Swap. + void + swap(optional& __other) + noexcept(is_nothrow_move_constructible<_Tp>() + && is_nothrow_swappable_v<_Tp>) + { + using std::swap; + + if (this->_M_is_engaged() && __other._M_is_engaged()) + swap(this->_M_get(), __other._M_get()); + else if (this->_M_is_engaged()) + { + __other._M_construct(std::move(this->_M_get())); + this->_M_destruct(); + } + else if (__other._M_is_engaged()) + { + this->_M_construct(std::move(__other._M_get())); + __other._M_destruct(); + } + } + + // Observers. + constexpr const _Tp* + operator->() const + { return std::__addressof(this->_M_get()); } + + _Tp* + operator->() + { return std::__addressof(this->_M_get()); } + + constexpr const _Tp& + operator*() const& + { return this->_M_get(); } + + constexpr _Tp& + operator*()& + { return this->_M_get(); } + + constexpr _Tp&& + operator*()&& + { return std::move(this->_M_get()); } + + constexpr const _Tp&& + operator*() const&& + { return std::move(this->_M_get()); } + + constexpr explicit operator bool() const noexcept + { return this->_M_is_engaged(); } + + constexpr bool has_value() const noexcept + { return this->_M_is_engaged(); } + + constexpr const _Tp& + value() const& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), + this->_M_get()); + } + + constexpr _Tp& + value()& + { + return this->_M_is_engaged() + ? this->_M_get() + : (__throw_bad_optional_access(), + this->_M_get()); + } + + constexpr _Tp&& + value()&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), + std::move(this->_M_get())); + } + + constexpr const _Tp&& + value() const&& + { + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : (__throw_bad_optional_access(), + std::move(this->_M_get())); + } + + template + constexpr _Tp + value_or(_Up&& __u) const& + { + static_assert(__and_, + is_convertible<_Up&&, _Tp>>(), + "Cannot return value"); + + return this->_M_is_engaged() + ? this->_M_get() + : static_cast<_Tp>(std::forward<_Up>(__u)); + } + + template + _Tp + value_or(_Up&& __u) && + { + static_assert(__and_, + is_convertible<_Up&&, _Tp>>(), + "Cannot return value" ); + + return this->_M_is_engaged() + ? std::move(this->_M_get()) + : static_cast<_Tp>(std::forward<_Up>(__u)); + } + void reset() noexcept { this->_M_reset(); } + }; + + template + using __optional_relop_t = + enable_if_t::value, bool>; + + // Comparisons between optional values. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { + return static_cast(__lhs) == static_cast(__rhs) + && (!__lhs || *__lhs == *__rhs); + } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { + return static_cast(__lhs) != static_cast(__rhs) + || (static_cast(__lhs) && *__lhs != *__rhs); + } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { + return static_cast(__rhs) && (!__lhs || *__lhs < *__rhs); + } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { + return static_cast(__lhs) && (!__rhs || *__lhs > *__rhs); + } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { + return !__lhs || (static_cast(__rhs) && *__lhs <= *__rhs); + } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const optional<_Up>& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { + return !__rhs || (static_cast(__lhs) && *__lhs >= *__rhs); + } + + // Comparisons with nullopt. + template + constexpr bool + operator==(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator==(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + template + constexpr bool + operator!=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator!=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator<(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return false; } + + template + constexpr bool + operator<(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return static_cast(__rhs); } + + template + constexpr bool + operator>(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return static_cast(__lhs); } + + template + constexpr bool + operator>(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return false; } + + template + constexpr bool + operator<=(const optional<_Tp>& __lhs, nullopt_t) noexcept + { return !__lhs; } + + template + constexpr bool + operator<=(nullopt_t, const optional<_Tp>& /* __rhs */) noexcept + { return true; } + + template + constexpr bool + operator>=(const optional<_Tp>& /* __lhs */, nullopt_t) noexcept + { return true; } + + template + constexpr bool + operator>=(nullopt_t, const optional<_Tp>& __rhs) noexcept + { return !__rhs; } + + // Comparisons with value type. + template + constexpr auto + operator==(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() == declval<_Up>())> + { return __lhs && *__lhs == __rhs; } + + template + constexpr auto + operator==(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() == declval<_Tp>())> + { return __rhs && __lhs == *__rhs; } + + template + constexpr auto + operator!=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() != declval<_Up>())> + { return !__lhs || *__lhs != __rhs; } + + template + constexpr auto + operator!=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() != declval<_Tp>())> + { return !__rhs || __lhs != *__rhs; } + + template + constexpr auto + operator<(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() < declval<_Up>())> + { return !__lhs || *__lhs < __rhs; } + + template + constexpr auto + operator<(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() < declval<_Tp>())> + { return __rhs && __lhs < *__rhs; } + + template + constexpr auto + operator>(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() > declval<_Up>())> + { return __lhs && *__lhs > __rhs; } + + template + constexpr auto + operator>(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() > declval<_Tp>())> + { return !__rhs || __lhs > *__rhs; } + + template + constexpr auto + operator<=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() <= declval<_Up>())> + { return !__lhs || *__lhs <= __rhs; } + + template + constexpr auto + operator<=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() <= declval<_Tp>())> + { return __rhs && __lhs <= *__rhs; } + + template + constexpr auto + operator>=(const optional<_Tp>& __lhs, const _Up& __rhs) + -> __optional_relop_t() >= declval<_Up>())> + { return __lhs && *__lhs >= __rhs; } + + template + constexpr auto + operator>=(const _Up& __lhs, const optional<_Tp>& __rhs) + -> __optional_relop_t() >= declval<_Tp>())> + { return !__rhs || __lhs >= *__rhs; } + + // Swap and creation functions. + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2748. swappable traits for optionals + template + inline enable_if_t && is_swappable_v<_Tp>> + swap(optional<_Tp>& __lhs, optional<_Tp>& __rhs) + noexcept(noexcept(__lhs.swap(__rhs))) + { __lhs.swap(__rhs); } + + template + enable_if_t && is_swappable_v<_Tp>)> + swap(optional<_Tp>&, optional<_Tp>&) = delete; + + template + constexpr optional> + make_optional(_Tp&& __t) + { return optional> { std::forward<_Tp>(__t) }; } + + template + constexpr optional<_Tp> + make_optional(_Args&&... __args) + { return optional<_Tp> { in_place, std::forward<_Args>(__args)... }; } + + template + constexpr optional<_Tp> + make_optional(initializer_list<_Up> __il, _Args&&... __args) + { return optional<_Tp> { in_place, __il, std::forward<_Args>(__args)... }; } + + // Hash. + + template, + bool = __poison_hash<_Up>::__enable_hash_call> + struct __optional_hash_call_base + { + size_t + operator()(const optional<_Tp>& __t) const + noexcept(noexcept(hash<_Up>{}(*__t))) + { + // We pick an arbitrary hash for disengaged optionals which hopefully + // usual values of _Tp won't typically hash to. + constexpr size_t __magic_disengaged_hash = static_cast(-3333); + return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash; + } + }; + + template + struct __optional_hash_call_base<_Tp, _Up, false> {}; + + template + struct hash> + : private __poison_hash>, + public __optional_hash_call_base<_Tp> + { + using result_type = size_t; + using argument_type = optional<_Tp>; + }; + + /// @} + +#if __cpp_deduction_guides >= 201606 + template optional(_Tp) -> optional<_Tp>; +#endif + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++17 + +#endif // _GLIBCXX_OPTIONAL diff --git a/AH/STL/Fallback/tuple b/AH/STL/Fallback/tuple new file mode 100644 index 0000000..3a95f1d --- /dev/null +++ b/AH/STL/Fallback/tuple @@ -0,0 +1,1700 @@ +// -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/tuple + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_TUPLE +#define _GLIBCXX_TUPLE 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "bits/c++0x_warning.h" +#else + +#include "utility" +#include "array" +#include "bits/uses_allocator.h" +#include "bits/invoke.h" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @addtogroup utilities + * @{ + */ + + template + class tuple; + + template + struct __is_empty_non_tuple : is_empty<_Tp> { }; + + // Using EBO for elements that are tuples causes ambiguous base errors. + template + struct __is_empty_non_tuple> : false_type { }; + + // Use the Empty Base-class Optimization for empty, non-final types. + template + using __empty_not_final + = typename conditional<__is_final(_Tp), false_type, + __is_empty_non_tuple<_Tp>>::type; + + template::value> + struct _Head_base; + + template + struct _Head_base<_Idx, _Head, true> + : public _Head + { + constexpr _Head_base() + : _Head() { } + + constexpr _Head_base(const _Head& __h) + : _Head(__h) { } + + constexpr _Head_base(const _Head_base&) = default; + constexpr _Head_base(_Head_base&&) = default; + + template + constexpr _Head_base(_UHead&& __h) + : _Head(std::forward<_UHead>(__h)) { } + + _Head_base(allocator_arg_t, __uses_alloc0) + : _Head() { } + + template + _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) + : _Head(allocator_arg, *__a._M_a) { } + + template + _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) + : _Head(*__a._M_a) { } + + template + _Head_base(__uses_alloc0, _UHead&& __uhead) + : _Head(std::forward<_UHead>(__uhead)) { } + + template + _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) + : _Head(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) { } + + template + _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) + : _Head(std::forward<_UHead>(__uhead), *__a._M_a) { } + + static constexpr _Head& + _M_head(_Head_base& __b) noexcept { return __b; } + + static constexpr const _Head& + _M_head(const _Head_base& __b) noexcept { return __b; } + }; + + template + struct _Head_base<_Idx, _Head, false> + { + constexpr _Head_base() + : _M_head_impl() { } + + constexpr _Head_base(const _Head& __h) + : _M_head_impl(__h) { } + + constexpr _Head_base(const _Head_base&) = default; + constexpr _Head_base(_Head_base&&) = default; + + template + constexpr _Head_base(_UHead&& __h) + : _M_head_impl(std::forward<_UHead>(__h)) { } + + _Head_base(allocator_arg_t, __uses_alloc0) + : _M_head_impl() { } + + template + _Head_base(allocator_arg_t, __uses_alloc1<_Alloc> __a) + : _M_head_impl(allocator_arg, *__a._M_a) { } + + template + _Head_base(allocator_arg_t, __uses_alloc2<_Alloc> __a) + : _M_head_impl(*__a._M_a) { } + + template + _Head_base(__uses_alloc0, _UHead&& __uhead) + : _M_head_impl(std::forward<_UHead>(__uhead)) { } + + template + _Head_base(__uses_alloc1<_Alloc> __a, _UHead&& __uhead) + : _M_head_impl(allocator_arg, *__a._M_a, std::forward<_UHead>(__uhead)) + { } + + template + _Head_base(__uses_alloc2<_Alloc> __a, _UHead&& __uhead) + : _M_head_impl(std::forward<_UHead>(__uhead), *__a._M_a) { } + + static constexpr _Head& + _M_head(_Head_base& __b) noexcept { return __b._M_head_impl; } + + static constexpr const _Head& + _M_head(const _Head_base& __b) noexcept { return __b._M_head_impl; } + + _Head _M_head_impl; + }; + + /** + * Contains the actual implementation of the @c tuple template, stored + * as a recursive inheritance hierarchy from the first element (most + * derived class) to the last (least derived class). The @c Idx + * parameter gives the 0-based index of the element stored at this + * point in the hierarchy; we use it to implement a constant-time + * get() operation. + */ + template + struct _Tuple_impl; + + /** + * Recursive tuple implementation. Here we store the @c Head element + * and derive from a @c Tuple_impl containing the remaining elements + * (which contains the @c Tail). + */ + template + struct _Tuple_impl<_Idx, _Head, _Tail...> + : public _Tuple_impl<_Idx + 1, _Tail...>, + private _Head_base<_Idx, _Head> + { + template friend class _Tuple_impl; + + typedef _Tuple_impl<_Idx + 1, _Tail...> _Inherited; + typedef _Head_base<_Idx, _Head> _Base; + + static constexpr _Head& + _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr const _Head& + _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr _Inherited& + _M_tail(_Tuple_impl& __t) noexcept { return __t; } + + static constexpr const _Inherited& + _M_tail(const _Tuple_impl& __t) noexcept { return __t; } + + constexpr _Tuple_impl() + : _Inherited(), _Base() { } + + explicit + constexpr _Tuple_impl(const _Head& __head, const _Tail&... __tail) + : _Inherited(__tail...), _Base(__head) { } + + template::type> + explicit + constexpr _Tuple_impl(_UHead&& __head, _UTail&&... __tail) + : _Inherited(std::forward<_UTail>(__tail)...), + _Base(std::forward<_UHead>(__head)) { } + + constexpr _Tuple_impl(const _Tuple_impl&) = default; + + constexpr + _Tuple_impl(_Tuple_impl&& __in) + noexcept(__and_, + is_nothrow_move_constructible<_Inherited>>::value) + : _Inherited(std::move(_M_tail(__in))), + _Base(std::forward<_Head>(_M_head(__in))) { } + + template + constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UElements...>& __in) + : _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), + _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { } + + template + constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) + : _Inherited(std::move + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), + _Base(std::forward<_UHead> + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) + : _Inherited(__tag, __a), + _Base(__tag, __use_alloc<_Head>(__a)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Head& __head, const _Tail&... __tail) + : _Inherited(__tag, __a, __tail...), + _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } + + template::type> + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _UHead&& __head, _UTail&&... __tail) + : _Inherited(__tag, __a, std::forward<_UTail>(__tail)...), + _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(__head)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl& __in) + : _Inherited(__tag, __a, _M_tail(__in)), + _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl&& __in) + : _Inherited(__tag, __a, std::move(_M_tail(__in))), + _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + std::forward<_Head>(_M_head(__in))) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UElements...>& __in) + : _Inherited(__tag, __a, + _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), + _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + _Tuple_impl<_Idx, _UElements...>::_M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead, _UTails...>&& __in) + : _Inherited(__tag, __a, std::move + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), + _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead> + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } + + _Tuple_impl& + operator=(const _Tuple_impl& __in) + { + _M_head(*this) = _M_head(__in); + _M_tail(*this) = _M_tail(__in); + return *this; + } + + _Tuple_impl& + operator=(_Tuple_impl&& __in) + noexcept(__and_, + is_nothrow_move_assignable<_Inherited>>::value) + { + _M_head(*this) = std::forward<_Head>(_M_head(__in)); + _M_tail(*this) = std::move(_M_tail(__in)); + return *this; + } + + template + _Tuple_impl& + operator=(const _Tuple_impl<_Idx, _UElements...>& __in) + { + _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in); + _M_tail(*this) = _Tuple_impl<_Idx, _UElements...>::_M_tail(__in); + return *this; + } + + template + _Tuple_impl& + operator=(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) + { + _M_head(*this) = std::forward<_UHead> + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)); + _M_tail(*this) = std::move + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)); + return *this; + } + + protected: + void + _M_swap(_Tuple_impl& __in) + noexcept(__is_nothrow_swappable<_Head>::value + && noexcept(_M_tail(__in)._M_swap(_M_tail(__in)))) + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + _Inherited::_M_swap(_M_tail(__in)); + } + }; + + // Basis case of inheritance recursion. + template + struct _Tuple_impl<_Idx, _Head> + : private _Head_base<_Idx, _Head> + { + template friend class _Tuple_impl; + + typedef _Head_base<_Idx, _Head> _Base; + + static constexpr _Head& + _M_head(_Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + static constexpr const _Head& + _M_head(const _Tuple_impl& __t) noexcept { return _Base::_M_head(__t); } + + constexpr _Tuple_impl() + : _Base() { } + + explicit + constexpr _Tuple_impl(const _Head& __head) + : _Base(__head) { } + + template + explicit + constexpr _Tuple_impl(_UHead&& __head) + : _Base(std::forward<_UHead>(__head)) { } + + constexpr _Tuple_impl(const _Tuple_impl&) = default; + + constexpr + _Tuple_impl(_Tuple_impl&& __in) + noexcept(is_nothrow_move_constructible<_Head>::value) + : _Base(std::forward<_Head>(_M_head(__in))) { } + + template + constexpr _Tuple_impl(const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + constexpr _Tuple_impl(_Tuple_impl<_Idx, _UHead>&& __in) + : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) + : _Base(__tag, __use_alloc<_Head>(__a)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Head& __head) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), __head) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _UHead&& __head) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(__head)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), _M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl&& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + std::forward<_Head>(_M_head(__in))) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead>& __in) + : _Base(__use_alloc<_Head, _Alloc, _Head>(__a), + _Tuple_impl<_Idx, _UHead>::_M_head(__in)) { } + + template + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(__use_alloc<_Head, _Alloc, _UHead>(__a), + std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } + + _Tuple_impl& + operator=(const _Tuple_impl& __in) + { + _M_head(*this) = _M_head(__in); + return *this; + } + + _Tuple_impl& + operator=(_Tuple_impl&& __in) + noexcept(is_nothrow_move_assignable<_Head>::value) + { + _M_head(*this) = std::forward<_Head>(_M_head(__in)); + return *this; + } + + template + _Tuple_impl& + operator=(const _Tuple_impl<_Idx, _UHead>& __in) + { + _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); + return *this; + } + + template + _Tuple_impl& + operator=(_Tuple_impl<_Idx, _UHead>&& __in) + { + _M_head(*this) + = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); + return *this; + } + + protected: + void + _M_swap(_Tuple_impl& __in) + noexcept(__is_nothrow_swappable<_Head>::value) + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + } + }; + + // Concept utility functions, reused in conditionally-explicit + // constructors. + template + struct _TC + { + template + static constexpr bool _ConstructibleTuple() + { + return __and_...>::value; + } + + template + static constexpr bool _ImplicitlyConvertibleTuple() + { + return __and_...>::value; + } + + template + static constexpr bool _MoveConstructibleTuple() + { + return __and_...>::value; + } + + template + static constexpr bool _ImplicitlyMoveConvertibleTuple() + { + return __and_...>::value; + } + + template + static constexpr bool _NonNestedTuple() + { + return __and_<__not_, + typename remove_cv< + typename remove_reference<_SrcTuple>::type + >::type>>, + __not_>, + __not_> + >::value; + } + template + static constexpr bool _NotSameTuple() + { + return __not_, + typename remove_const< + typename remove_reference<_UElements...>::type + >::type>>::value; + } + }; + + template + struct _TC + { + template + static constexpr bool _ConstructibleTuple() + { + return false; + } + + template + static constexpr bool _ImplicitlyConvertibleTuple() + { + return false; + } + + template + static constexpr bool _MoveConstructibleTuple() + { + return false; + } + + template + static constexpr bool _ImplicitlyMoveConvertibleTuple() + { + return false; + } + + template + static constexpr bool _NonNestedTuple() + { + return true; + } + template + static constexpr bool _NotSameTuple() + { + return true; + } + }; + + /// Primary class template, tuple + template + class tuple : public _Tuple_impl<0, _Elements...> + { + typedef _Tuple_impl<0, _Elements...> _Inherited; + + // Used for constraining the default constructor so + // that it becomes dependent on the constraints. + template + struct _TC2 + { + static constexpr bool _DefaultConstructibleTuple() + { + return __and_...>::value; + } + static constexpr bool _ImplicitlyDefaultConstructibleTuple() + { + return __and_<__is_implicitly_default_constructible<_Elements>...> + ::value; + } + }; + + public: + template:: + _ImplicitlyDefaultConstructibleTuple(), + bool>::type = true> + constexpr tuple() + : _Inherited() { } + + template:: + _DefaultConstructibleTuple() + && + !_TC2<_Dummy>:: + _ImplicitlyDefaultConstructibleTuple(), + bool>::type = false> + explicit constexpr tuple() + : _Inherited() { } + + // Shortcut for the cases where constructors taking _Elements... + // need to be constrained. + template using _TCC = + _TC::value, + _Elements...>; + + template::template + _ConstructibleTuple<_Elements...>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=true> + constexpr tuple(const _Elements&... __elements) + : _Inherited(__elements...) { } + + template::template + _ConstructibleTuple<_Elements...>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=false> + explicit constexpr tuple(const _Elements&... __elements) + : _Inherited(__elements...) { } + + // Shortcut for the cases where constructors taking _UElements... + // need to be constrained. + template using _TMC = + _TC<(sizeof...(_Elements) == sizeof...(_UElements)) + && (_TC<(sizeof...(_UElements)==1), _Elements...>:: + template _NotSameTuple<_UElements...>()), + _Elements...>; + + // Shortcut for the cases where constructors taking tuple<_UElements...> + // need to be constrained. + template using _TMCT = + _TC<(sizeof...(_Elements) == sizeof...(_UElements)) + && !is_same, + tuple<_UElements...>>::value, + _Elements...>; + + template::template + _MoveConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=true> + constexpr tuple(_UElements&&... __elements) + : _Inherited(std::forward<_UElements>(__elements)...) { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && (sizeof...(_Elements) >= 1), + bool>::type=false> + explicit constexpr tuple(_UElements&&... __elements) + : _Inherited(std::forward<_UElements>(__elements)...) { } + + constexpr tuple(const tuple&) = default; + + constexpr tuple(tuple&&) = default; + + // Shortcut for the cases where constructors taking tuples + // must avoid creating temporaries. + template using _TNTC = + _TC::value && sizeof...(_Elements) == 1, + _Elements...>; + + template::template + _ConstructibleTuple<_UElements...>() + && _TMCT<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&>(), + bool>::type=true> + constexpr tuple(const tuple<_UElements...>& __in) + : _Inherited(static_cast&>(__in)) + { } + + template::template + _ConstructibleTuple<_UElements...>() + && !_TMCT<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&>(), + bool>::type=false> + explicit constexpr tuple(const tuple<_UElements...>& __in) + : _Inherited(static_cast&>(__in)) + { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && _TMCT<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=true> + constexpr tuple(tuple<_UElements...>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && !_TMCT<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=false> + explicit constexpr tuple(tuple<_UElements...>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } + + // Allocator-extended constructors. + + template + tuple(allocator_arg_t __tag, const _Alloc& __a) + : _Inherited(__tag, __a) { } + + template::template + _ConstructibleTuple<_Elements...>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>(), + bool>::type=true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + const _Elements&... __elements) + : _Inherited(__tag, __a, __elements...) { } + + template::template + _ConstructibleTuple<_Elements...>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_Elements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const _Elements&... __elements) + : _Inherited(__tag, __a, __elements...) { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && _TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + _UElements&&... __elements) + : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) + { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && !_TMC<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + _UElements&&... __elements) + : _Inherited(__tag, __a, std::forward<_UElements>(__elements)...) + { } + + template + tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) + : _Inherited(__tag, __a, static_cast(__in)) { } + + template + tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) + : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } + + template::template + _ConstructibleTuple<_UElements...>() + && _TMCT<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_UElements...>& __in) + : _Inherited(__tag, __a, + static_cast&>(__in)) + { } + + template::template + _ConstructibleTuple<_UElements...>() + && !_TMCT<_UElements...>::template + _ImplicitlyConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_UElements...>& __in) + : _Inherited(__tag, __a, + static_cast&>(__in)) + { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && _TMCT<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_UElements...>&& __in) + : _Inherited(__tag, __a, + static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) + { } + + template::template + _MoveConstructibleTuple<_UElements...>() + && !_TMCT<_UElements...>::template + _ImplicitlyMoveConvertibleTuple<_UElements...>() + && _TNTC<_Dummy>::template + _NonNestedTuple&&>(), + bool>::type=false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_UElements...>&& __in) + : _Inherited(__tag, __a, + static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) + { } + + tuple& + operator=(const tuple& __in) + { + static_cast<_Inherited&>(*this) = __in; + return *this; + } + + tuple& + operator=(tuple&& __in) + noexcept(is_nothrow_move_assignable<_Inherited>::value) + { + static_cast<_Inherited&>(*this) = std::move(__in); + return *this; + } + + template + typename + enable_if::type + operator=(const tuple<_UElements...>& __in) + { + static_cast<_Inherited&>(*this) = __in; + return *this; + } + + template + typename + enable_if::type + operator=(tuple<_UElements...>&& __in) + { + static_cast<_Inherited&>(*this) = std::move(__in); + return *this; + } + + void + swap(tuple& __in) + noexcept(noexcept(__in._M_swap(__in))) + { _Inherited::_M_swap(__in); } + }; + +#if __cpp_deduction_guides >= 201606 + template + tuple(_UTypes...) -> tuple<_UTypes...>; + template + tuple(pair<_T1, _T2>) -> tuple<_T1, _T2>; + template + tuple(allocator_arg_t, _Alloc, _UTypes...) -> tuple<_UTypes...>; + template + tuple(allocator_arg_t, _Alloc, pair<_T1, _T2>) -> tuple<_T1, _T2>; + template + tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) -> tuple<_UTypes...>; +#endif + + // Explicit specialization, zero-element tuple. + template<> + class tuple<> + { + public: + void swap(tuple&) noexcept { /* no-op */ } + // We need the default since we're going to define no-op + // allocator constructors. + tuple() = default; + // No-op allocator constructors. + template + tuple(allocator_arg_t, const _Alloc&) { } + template + tuple(allocator_arg_t, const _Alloc&, const tuple&) { } + }; + + /// Partial specialization, 2-element tuple. + /// Includes construction and assignment from a pair. + template + class tuple<_T1, _T2> : public _Tuple_impl<0, _T1, _T2> + { + typedef _Tuple_impl<0, _T1, _T2> _Inherited; + + public: + template , + __is_implicitly_default_constructible<_U2>> + ::value, bool>::type = true> + + constexpr tuple() + : _Inherited() { } + + template , + is_default_constructible<_U2>, + __not_< + __and_<__is_implicitly_default_constructible<_U1>, + __is_implicitly_default_constructible<_U2>>>> + ::value, bool>::type = false> + + explicit constexpr tuple() + : _Inherited() { } + + // Shortcut for the cases where constructors taking _T1, _T2 + // need to be constrained. + template using _TCC = + _TC::value, _T1, _T2>; + + template::template + _ConstructibleTuple<_T1, _T2>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type = true> + constexpr tuple(const _T1& __a1, const _T2& __a2) + : _Inherited(__a1, __a2) { } + + template::template + _ConstructibleTuple<_T1, _T2>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type = false> + explicit constexpr tuple(const _T1& __a1, const _T2& __a2) + : _Inherited(__a1, __a2) { } + + // Shortcut for the cases where constructors taking _U1, _U2 + // need to be constrained. + using _TMC = _TC; + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>() + && !is_same::type, + allocator_arg_t>::value, + bool>::type = true> + constexpr tuple(_U1&& __a1, _U2&& __a2) + : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>() + && !is_same::type, + allocator_arg_t>::value, + bool>::type = false> + explicit constexpr tuple(_U1&& __a1, _U2&& __a2) + : _Inherited(std::forward<_U1>(__a1), std::forward<_U2>(__a2)) { } + + constexpr tuple(const tuple&) = default; + + constexpr tuple(tuple&&) = default; + + template() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> + constexpr tuple(const tuple<_U1, _U2>& __in) + : _Inherited(static_cast&>(__in)) { } + + template() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(const tuple<_U1, _U2>& __in) + : _Inherited(static_cast&>(__in)) { } + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> + constexpr tuple(tuple<_U1, _U2>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(tuple<_U1, _U2>&& __in) + : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } + + template() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> + constexpr tuple(const pair<_U1, _U2>& __in) + : _Inherited(__in.first, __in.second) { } + + template() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(const pair<_U1, _U2>& __in) + : _Inherited(__in.first, __in.second) { } + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> + constexpr tuple(pair<_U1, _U2>&& __in) + : _Inherited(std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit constexpr tuple(pair<_U1, _U2>&& __in) + : _Inherited(std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + + // Allocator-extended constructors. + + template + tuple(allocator_arg_t __tag, const _Alloc& __a) + : _Inherited(__tag, __a) { } + + template::template + _ConstructibleTuple<_T1, _T2>() + && _TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type=true> + + tuple(allocator_arg_t __tag, const _Alloc& __a, + const _T1& __a1, const _T2& __a2) + : _Inherited(__tag, __a, __a1, __a2) { } + + template::template + _ConstructibleTuple<_T1, _T2>() + && !_TCC<_Dummy>::template + _ImplicitlyConvertibleTuple<_T1, _T2>(), + bool>::type=false> + + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const _T1& __a1, const _T2& __a2) + : _Inherited(__tag, __a, __a1, __a2) { } + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, _U1&& __a1, _U2&& __a2) + : _Inherited(__tag, __a, std::forward<_U1>(__a1), + std::forward<_U2>(__a2)) { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + _U1&& __a1, _U2&& __a2) + : _Inherited(__tag, __a, std::forward<_U1>(__a1), + std::forward<_U2>(__a2)) { } + + template + tuple(allocator_arg_t __tag, const _Alloc& __a, const tuple& __in) + : _Inherited(__tag, __a, static_cast(__in)) { } + + template + tuple(allocator_arg_t __tag, const _Alloc& __a, tuple&& __in) + : _Inherited(__tag, __a, static_cast<_Inherited&&>(__in)) { } + + template() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_U1, _U2>& __in) + : _Inherited(__tag, __a, + static_cast&>(__in)) + { } + + template() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_U1, _U2>& __in) + : _Inherited(__tag, __a, + static_cast&>(__in)) + { } + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, tuple<_U1, _U2>&& __in) + : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) + { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_U1, _U2>&& __in) + : _Inherited(__tag, __a, static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) + { } + + template() + && _TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, + const pair<_U1, _U2>& __in) + : _Inherited(__tag, __a, __in.first, __in.second) { } + + template() + && !_TMC::template + _ImplicitlyConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + const pair<_U1, _U2>& __in) + : _Inherited(__tag, __a, __in.first, __in.second) { } + + template() + && _TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = true> + tuple(allocator_arg_t __tag, const _Alloc& __a, pair<_U1, _U2>&& __in) + : _Inherited(__tag, __a, std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + + template() + && !_TMC::template + _ImplicitlyMoveConvertibleTuple<_U1, _U2>(), + bool>::type = false> + explicit tuple(allocator_arg_t __tag, const _Alloc& __a, + pair<_U1, _U2>&& __in) + : _Inherited(__tag, __a, std::forward<_U1>(__in.first), + std::forward<_U2>(__in.second)) { } + + tuple& + operator=(const tuple& __in) + { + static_cast<_Inherited&>(*this) = __in; + return *this; + } + + tuple& + operator=(tuple&& __in) + noexcept(is_nothrow_move_assignable<_Inherited>::value) + { + static_cast<_Inherited&>(*this) = std::move(__in); + return *this; + } + + template + tuple& + operator=(const tuple<_U1, _U2>& __in) + { + static_cast<_Inherited&>(*this) = __in; + return *this; + } + + template + tuple& + operator=(tuple<_U1, _U2>&& __in) + { + static_cast<_Inherited&>(*this) = std::move(__in); + return *this; + } + + template + tuple& + operator=(const pair<_U1, _U2>& __in) + { + this->_M_head(*this) = __in.first; + this->_M_tail(*this)._M_head(*this) = __in.second; + return *this; + } + + template + tuple& + operator=(pair<_U1, _U2>&& __in) + { + this->_M_head(*this) = std::forward<_U1>(__in.first); + this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second); + return *this; + } + + void + swap(tuple& __in) + noexcept(noexcept(__in._M_swap(__in))) + { _Inherited::_M_swap(__in); } + }; + + + /// class tuple_size + template + struct tuple_size> + : public integral_constant { }; + +#if __cplusplus > 201402L + template + inline constexpr size_t tuple_size_v = tuple_size<_Tp>::value; +#endif + + /** + * Recursive case for tuple_element: strip off the first element in + * the tuple and retrieve the (i-1)th element of the remaining tuple. + */ + template + struct tuple_element<__i, tuple<_Head, _Tail...> > + : tuple_element<__i - 1, tuple<_Tail...> > { }; + + /** + * Basis case for tuple_element: The first element is the one we're seeking. + */ + template + struct tuple_element<0, tuple<_Head, _Tail...> > + { + typedef _Head type; + }; + + /** + * Error case for tuple_element: invalid index. + */ + template + struct tuple_element<__i, tuple<>> + { + static_assert(__i < tuple_size>::value, + "tuple index is in range"); + }; + + template + constexpr _Head& + __get_helper(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept + { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } + + template + constexpr const _Head& + __get_helper(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept + { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } + + /// Return a reference to the ith element of a tuple. + template + constexpr __tuple_element_t<__i, tuple<_Elements...>>& + get(tuple<_Elements...>& __t) noexcept + { return std::__get_helper<__i>(__t); } + + /// Return a const reference to the ith element of a const tuple. + template + constexpr const __tuple_element_t<__i, tuple<_Elements...>>& + get(const tuple<_Elements...>& __t) noexcept + { return std::__get_helper<__i>(__t); } + + /// Return an rvalue reference to the ith element of a tuple rvalue. + template + constexpr __tuple_element_t<__i, tuple<_Elements...>>&& + get(tuple<_Elements...>&& __t) noexcept + { + typedef __tuple_element_t<__i, tuple<_Elements...>> __element_type; + return std::forward<__element_type&&>(std::get<__i>(__t)); + } + +#if __cplusplus > 201103L + +#define __cpp_lib_tuples_by_type 201304 + + template + constexpr _Head& + __get_helper2(_Tuple_impl<__i, _Head, _Tail...>& __t) noexcept + { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } + + template + constexpr const _Head& + __get_helper2(const _Tuple_impl<__i, _Head, _Tail...>& __t) noexcept + { return _Tuple_impl<__i, _Head, _Tail...>::_M_head(__t); } + + /// Return a reference to the unique element of type _Tp of a tuple. + template + constexpr _Tp& + get(tuple<_Types...>& __t) noexcept + { return std::__get_helper2<_Tp>(__t); } + + /// Return a reference to the unique element of type _Tp of a tuple rvalue. + template + constexpr _Tp&& + get(tuple<_Types...>&& __t) noexcept + { return std::forward<_Tp&&>(std::__get_helper2<_Tp>(__t)); } + + /// Return a const reference to the unique element of type _Tp of a tuple. + template + constexpr const _Tp& + get(const tuple<_Types...>& __t) noexcept + { return std::__get_helper2<_Tp>(__t); } +#endif + + // This class performs the comparison operations on tuples + template + struct __tuple_compare + { + static constexpr bool + __eq(const _Tp& __t, const _Up& __u) + { + return bool(std::get<__i>(__t) == std::get<__i>(__u)) + && __tuple_compare<_Tp, _Up, __i + 1, __size>::__eq(__t, __u); + } + + static constexpr bool + __less(const _Tp& __t, const _Up& __u) + { + return bool(std::get<__i>(__t) < std::get<__i>(__u)) + || (!bool(std::get<__i>(__u) < std::get<__i>(__t)) + && __tuple_compare<_Tp, _Up, __i + 1, __size>::__less(__t, __u)); + } + }; + + template + struct __tuple_compare<_Tp, _Up, __size, __size> + { + static constexpr bool + __eq(const _Tp&, const _Up&) { return true; } + + static constexpr bool + __less(const _Tp&, const _Up&) { return false; } + }; + + template + constexpr bool + operator==(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { + static_assert(sizeof...(_TElements) == sizeof...(_UElements), + "tuple objects can only be compared if they have equal sizes."); + using __compare = __tuple_compare, + tuple<_UElements...>, + 0, sizeof...(_TElements)>; + return __compare::__eq(__t, __u); + } + + template + constexpr bool + operator<(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { + static_assert(sizeof...(_TElements) == sizeof...(_UElements), + "tuple objects can only be compared if they have equal sizes."); + using __compare = __tuple_compare, + tuple<_UElements...>, + 0, sizeof...(_TElements)>; + return __compare::__less(__t, __u); + } + + template + constexpr bool + operator!=(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { return !(__t == __u); } + + template + constexpr bool + operator>(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { return __u < __t; } + + template + constexpr bool + operator<=(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { return !(__u < __t); } + + template + constexpr bool + operator>=(const tuple<_TElements...>& __t, + const tuple<_UElements...>& __u) + { return !(__t < __u); } + + // NB: DR 705. + template + constexpr tuple::__type...> + make_tuple(_Elements&&... __args) + { + typedef tuple::__type...> + __result_type; + return __result_type(std::forward<_Elements>(__args)...); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2275. Why is forward_as_tuple not constexpr? + template + constexpr tuple<_Elements&&...> + forward_as_tuple(_Elements&&... __args) noexcept + { return tuple<_Elements&&...>(std::forward<_Elements>(__args)...); } + + template + struct __make_tuple_impl; + + template + struct __make_tuple_impl<_Idx, tuple<_Tp...>, _Tuple, _Nm> + : __make_tuple_impl<_Idx + 1, + tuple<_Tp..., __tuple_element_t<_Idx, _Tuple>>, + _Tuple, _Nm> + { }; + + template + struct __make_tuple_impl<_Nm, tuple<_Tp...>, _Tuple, _Nm> + { + typedef tuple<_Tp...> __type; + }; + + template + struct __do_make_tuple + : __make_tuple_impl<0, tuple<>, _Tuple, std::tuple_size<_Tuple>::value> + { }; + + // Returns the std::tuple equivalent of a tuple-like type. + template + struct __make_tuple + : public __do_make_tuple::type>::type> + { }; + + // Combines several std::tuple's into a single one. + template + struct __combine_tuples; + + template<> + struct __combine_tuples<> + { + typedef tuple<> __type; + }; + + template + struct __combine_tuples> + { + typedef tuple<_Ts...> __type; + }; + + template + struct __combine_tuples, tuple<_T2s...>, _Rem...> + { + typedef typename __combine_tuples, + _Rem...>::__type __type; + }; + + // Computes the result type of tuple_cat given a set of tuple-like types. + template + struct __tuple_cat_result + { + typedef typename __combine_tuples + ::__type...>::__type __type; + }; + + // Helper to determine the index set for the first tuple-like + // type of a given set. + template + struct __make_1st_indices; + + template<> + struct __make_1st_indices<> + { + typedef std::_Index_tuple<> __type; + }; + + template + struct __make_1st_indices<_Tp, _Tpls...> + { + typedef typename std::_Build_index_tuple::type>::value>::__type __type; + }; + + // Performs the actual concatenation by step-wise expanding tuple-like + // objects into the elements, which are finally forwarded into the + // result tuple. + template + struct __tuple_concater; + + template + struct __tuple_concater<_Ret, std::_Index_tuple<_Is...>, _Tp, _Tpls...> + { + template + static constexpr _Ret + _S_do(_Tp&& __tp, _Tpls&&... __tps, _Us&&... __us) + { + typedef typename __make_1st_indices<_Tpls...>::__type __idx; + typedef __tuple_concater<_Ret, __idx, _Tpls...> __next; + return __next::_S_do(std::forward<_Tpls>(__tps)..., + std::forward<_Us>(__us)..., + std::get<_Is>(std::forward<_Tp>(__tp))...); + } + }; + + template + struct __tuple_concater<_Ret, std::_Index_tuple<>> + { + template + static constexpr _Ret + _S_do(_Us&&... __us) + { + return _Ret(std::forward<_Us>(__us)...); + } + }; + + /// tuple_cat + template...>::value>::type> + constexpr auto + tuple_cat(_Tpls&&... __tpls) + -> typename __tuple_cat_result<_Tpls...>::__type + { + typedef typename __tuple_cat_result<_Tpls...>::__type __ret; + typedef typename __make_1st_indices<_Tpls...>::__type __idx; + typedef __tuple_concater<__ret, __idx, _Tpls...> __concater; + return __concater::_S_do(std::forward<_Tpls>(__tpls)...); + } + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2301. Why is tie not constexpr? + /// tie + template + constexpr tuple<_Elements&...> + tie(_Elements&... __args) noexcept + { return tuple<_Elements&...>(__args...); } + + /// swap + template + inline +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + // Constrained free swap overload, see p0185r1 + typename enable_if<__and_<__is_swappable<_Elements>...>::value + >::type +#else + void +#endif + swap(tuple<_Elements...>& __x, tuple<_Elements...>& __y) + noexcept(noexcept(__x.swap(__y))) + { __x.swap(__y); } + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 + template + typename enable_if...>::value>::type + swap(tuple<_Elements...>&, tuple<_Elements...>&) = delete; +#endif + + // A class (and instance) which can be used in 'tie' when an element + // of a tuple is not required. + // _GLIBCXX14_CONSTEXPR + // 2933. PR for LWG 2773 could be clearer + struct _Swallow_assign + { + template + _GLIBCXX14_CONSTEXPR const _Swallow_assign& + operator=(const _Tp&) const + { return *this; } + }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2773. Making std::ignore constexpr + _GLIBCXX17_INLINE constexpr _Swallow_assign ignore{}; + + /// Partial specialization for tuples + template + struct uses_allocator, _Alloc> : true_type { }; + + // See stl_pair.h... + template + template + inline + pair<_T1, _T2>:: + pair(piecewise_construct_t, + tuple<_Args1...> __first, tuple<_Args2...> __second) + : pair(__first, __second, + typename _Build_index_tuple::__type(), + typename _Build_index_tuple::__type()) + { } + + template + template + inline + pair<_T1, _T2>:: + pair(tuple<_Args1...>& __tuple1, tuple<_Args2...>& __tuple2, + _Index_tuple<_Indexes1...>, _Index_tuple<_Indexes2...>) + : first(std::forward<_Args1>(std::get<_Indexes1>(__tuple1))...), + second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...) + { } + +#if __cplusplus > 201402L +# define __cpp_lib_apply 201603 + + template + constexpr decltype(auto) + __apply_impl(_Fn&& __f, _Tuple&& __t, index_sequence<_Idx...>) + { + return std::__invoke(std::forward<_Fn>(__f), + std::get<_Idx>(std::forward<_Tuple>(__t))...); + } + + template + constexpr decltype(auto) + apply(_Fn&& __f, _Tuple&& __t) + { + using _Indices = make_index_sequence>>; + return std::__apply_impl(std::forward<_Fn>(__f), + std::forward<_Tuple>(__t), + _Indices{}); + } + +#define __cpp_lib_make_from_tuple 201606 + + template + constexpr _Tp + __make_from_tuple_impl(_Tuple&& __t, index_sequence<_Idx...>) + { return _Tp(std::get<_Idx>(std::forward<_Tuple>(__t))...); } + + template + constexpr _Tp + make_from_tuple(_Tuple&& __t) + { + return __make_from_tuple_impl<_Tp>( + std::forward<_Tuple>(__t), + make_index_sequence>>{}); + } +#endif // C++17 + + /// @} + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++11 + +#endif // _GLIBCXX_TUPLE diff --git a/AH/STL/Fallback/type_traits b/AH/STL/Fallback/type_traits new file mode 100644 index 0000000..b7dfb3f --- /dev/null +++ b/AH/STL/Fallback/type_traits @@ -0,0 +1,3113 @@ +// C++11 -*- C++ -*- + +// Copyright (C) 2007-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file include/type_traits + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_TYPE_TRAITS +#define _GLIBCXX_TYPE_TRAITS 1 + +#pragma GCC system_header + +#if __cplusplus < 201103L +# include "bits/c++0x_warning.h" +#else + +#include "bits/c++config.h" + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 +# if defined (__UINT_LEAST16_TYPE__) && defined(__UINT_LEAST32_TYPE__) +namespace std +{ + typedef __UINT_LEAST16_TYPE__ uint_least16_t; + typedef __UINT_LEAST32_TYPE__ uint_least32_t; +} +# else +# include "cstdint" +# endif +#endif + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /** + * @defgroup metaprogramming Metaprogramming + * @ingroup utilities + * + * Template utilities for compile-time introspection and modification, + * including type classification traits, type property inspection traits + * and type transformation traits. + * + * @{ + */ + + /// integral_constant + template + struct integral_constant + { + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + constexpr operator value_type() const noexcept { return value; } +#if __cplusplus > 201103L + +#define __cpp_lib_integral_constant_callable 201304 + + constexpr value_type operator()() const noexcept { return value; } +#endif + }; + + template + constexpr _Tp integral_constant<_Tp, __v>::value; + + /// The type used as a compile-time boolean with true value. + typedef integral_constant true_type; + + /// The type used as a compile-time boolean with false value. + typedef integral_constant false_type; + + template + using __bool_constant = integral_constant; + +#if __cplusplus > 201402L +# define __cpp_lib_bool_constant 201505 + template + using bool_constant = integral_constant; +#endif + + // Meta programming helper types. + + template + struct conditional; + + template + struct __or_; + + template<> + struct __or_<> + : public false_type + { }; + + template + struct __or_<_B1> + : public _B1 + { }; + + template + struct __or_<_B1, _B2> + : public conditional<_B1::value, _B1, _B2>::type + { }; + + template + struct __or_<_B1, _B2, _B3, _Bn...> + : public conditional<_B1::value, _B1, __or_<_B2, _B3, _Bn...>>::type + { }; + + template + struct __and_; + + template<> + struct __and_<> + : public true_type + { }; + + template + struct __and_<_B1> + : public _B1 + { }; + + template + struct __and_<_B1, _B2> + : public conditional<_B1::value, _B2, _B1>::type + { }; + + template + struct __and_<_B1, _B2, _B3, _Bn...> + : public conditional<_B1::value, __and_<_B2, _B3, _Bn...>, _B1>::type + { }; + + template + struct __not_ + : public __bool_constant + { }; + +#if __cplusplus >= 201703L + +#define __cpp_lib_logical_traits 201510 + + template + struct conjunction + : __and_<_Bn...> + { }; + + template + struct disjunction + : __or_<_Bn...> + { }; + + template + struct negation + : __not_<_Pp> + { }; + + template + inline constexpr bool conjunction_v = conjunction<_Bn...>::value; + + template + inline constexpr bool disjunction_v = disjunction<_Bn...>::value; + + template + inline constexpr bool negation_v = negation<_Pp>::value; + +#endif // C++17 + + // For several sfinae-friendly trait implementations we transport both the + // result information (as the member type) and the failure information (no + // member type). This is very similar to std::enable_if, but we cannot use + // them, because we need to derive from them as an implementation detail. + + template + struct __success_type + { typedef _Tp type; }; + + struct __failure_type + { }; + + // Primary type categories. + + template + struct remove_cv; + + template + struct __is_void_helper + : public false_type { }; + + template<> + struct __is_void_helper + : public true_type { }; + + /// is_void + template + struct is_void + : public __is_void_helper::type>::type + { }; + + template + struct __is_integral_helper + : public false_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + +#ifdef _GLIBCXX_USE_WCHAR_T + template<> + struct __is_integral_helper + : public true_type { }; +#endif + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; + + // Conditionalizing on __STRICT_ANSI__ here will break any port that + // uses one of these types for size_t. +#if defined(__GLIBCXX_TYPE_INT_N_0) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_0> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_1> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_2> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) + template<> + struct __is_integral_helper<__GLIBCXX_TYPE_INT_N_3> + : public true_type { }; + + template<> + struct __is_integral_helper + : public true_type { }; +#endif + + /// is_integral + template + struct is_integral + : public __is_integral_helper::type>::type + { }; + + template + struct __is_floating_point_helper + : public false_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + + template<> + struct __is_floating_point_helper + : public true_type { }; + +#if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_FLOAT128) && !defined(__CUDACC__) + template<> + struct __is_floating_point_helper<__float128> + : public true_type { }; +#endif + + /// is_floating_point + template + struct is_floating_point + : public __is_floating_point_helper::type>::type + { }; + + /// is_array + template + struct is_array + : public false_type { }; + + template + struct is_array<_Tp[_Size]> + : public true_type { }; + + template + struct is_array<_Tp[]> + : public true_type { }; + + template + struct __is_pointer_helper + : public false_type { }; + + template + struct __is_pointer_helper<_Tp*> + : public true_type { }; + + /// is_pointer + template + struct is_pointer + : public __is_pointer_helper::type>::type + { }; + + /// is_lvalue_reference + template + struct is_lvalue_reference + : public false_type { }; + + template + struct is_lvalue_reference<_Tp&> + : public true_type { }; + + /// is_rvalue_reference + template + struct is_rvalue_reference + : public false_type { }; + + template + struct is_rvalue_reference<_Tp&&> + : public true_type { }; + + template + struct is_function; + + template + struct __is_member_object_pointer_helper + : public false_type { }; + + template + struct __is_member_object_pointer_helper<_Tp _Cp::*> + : public integral_constant::value> { }; + + /// is_member_object_pointer + template + struct is_member_object_pointer + : public __is_member_object_pointer_helper< + typename remove_cv<_Tp>::type>::type + { }; + + template + struct __is_member_function_pointer_helper + : public false_type { }; + + template + struct __is_member_function_pointer_helper<_Tp _Cp::*> + : public integral_constant::value> { }; + + /// is_member_function_pointer + template + struct is_member_function_pointer + : public __is_member_function_pointer_helper< + typename remove_cv<_Tp>::type>::type + { }; + + /// is_enum + template + struct is_enum + : public integral_constant + { }; + + /// is_union + template + struct is_union + : public integral_constant + { }; + + /// is_class + template + struct is_class + : public integral_constant + { }; + + /// is_function + template + struct is_function + : public false_type { }; + + template + struct is_function<_Res(_ArgTypes...) _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) volatile _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) volatile & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) volatile && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) volatile _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) volatile & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) volatile && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const volatile _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const volatile & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes...) const volatile && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const volatile _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const volatile & _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + + template + struct is_function<_Res(_ArgTypes......) const volatile && _GLIBCXX_NOEXCEPT_QUAL> + : public true_type { }; + +#define __cpp_lib_is_null_pointer 201309 + + template + struct __is_null_pointer_helper + : public false_type { }; + + template<> + struct __is_null_pointer_helper + : public true_type { }; + + /// is_null_pointer (LWG 2247). + template + struct is_null_pointer + : public __is_null_pointer_helper::type>::type + { }; + + /// __is_nullptr_t (extension). + template + struct __is_nullptr_t + : public is_null_pointer<_Tp> + { }; + + // Composite type categories. + + /// is_reference + template + struct is_reference + : public __or_, + is_rvalue_reference<_Tp>>::type + { }; + + /// is_arithmetic + template + struct is_arithmetic + : public __or_, is_floating_point<_Tp>>::type + { }; + + /// is_fundamental + template + struct is_fundamental + : public __or_, is_void<_Tp>, + is_null_pointer<_Tp>>::type + { }; + + /// is_object + template + struct is_object + : public __not_<__or_, is_reference<_Tp>, + is_void<_Tp>>>::type + { }; + + template + struct is_member_pointer; + + /// is_scalar + template + struct is_scalar + : public __or_, is_enum<_Tp>, is_pointer<_Tp>, + is_member_pointer<_Tp>, is_null_pointer<_Tp>>::type + { }; + + /// is_compound + template + struct is_compound + : public integral_constant::value> { }; + + template + struct __is_member_pointer_helper + : public false_type { }; + + template + struct __is_member_pointer_helper<_Tp _Cp::*> + : public true_type { }; + + /// is_member_pointer + template + struct is_member_pointer + : public __is_member_pointer_helper::type>::type + { }; + + // Utility to detect referenceable types ([defns.referenceable]). + + template + struct __is_referenceable + : public __or_, is_reference<_Tp>>::type + { }; + + template + struct __is_referenceable<_Res(_Args...) _GLIBCXX_NOEXCEPT_QUAL> + : public true_type + { }; + + template + struct __is_referenceable<_Res(_Args......) _GLIBCXX_NOEXCEPT_QUAL> + : public true_type + { }; + + // Type properties. + + /// is_const + template + struct is_const + : public false_type { }; + + template + struct is_const<_Tp const> + : public true_type { }; + + /// is_volatile + template + struct is_volatile + : public false_type { }; + + template + struct is_volatile<_Tp volatile> + : public true_type { }; + + /// is_trivial + template + struct is_trivial + : public integral_constant + { }; + + // is_trivially_copyable + template + struct is_trivially_copyable + : public integral_constant + { }; + + /// is_standard_layout + template + struct is_standard_layout + : public integral_constant + { }; + + /// is_pod + // Could use is_standard_layout && is_trivial instead of the builtin. + template + struct is_pod + : public integral_constant + { }; + + /// is_literal_type + template + struct is_literal_type + : public integral_constant + { }; + + /// is_empty + template + struct is_empty + : public integral_constant + { }; + + /// is_polymorphic + template + struct is_polymorphic + : public integral_constant + { }; + +#if __cplusplus >= 201402L +#define __cpp_lib_is_final 201402L + /// is_final + template + struct is_final + : public integral_constant + { }; +#endif + + /// is_abstract + template + struct is_abstract + : public integral_constant + { }; + + template::value> + struct __is_signed_helper + : public false_type { }; + + template + struct __is_signed_helper<_Tp, true> + : public integral_constant + { }; + + /// is_signed + template + struct is_signed + : public __is_signed_helper<_Tp>::type + { }; + + /// is_unsigned + template + struct is_unsigned + : public __and_, __not_>> + { }; + + + // Destructible and constructible type properties. + + template + struct add_rvalue_reference; + + /** + * @brief Utility to simplify expressions used in unevaluated operands + * @ingroup utilities + */ + template + typename add_rvalue_reference<_Tp>::type declval() noexcept; + + template + struct extent; + + template + struct remove_all_extents; + + template + struct __is_array_known_bounds + : public integral_constant::value > 0)> + { }; + + template + struct __is_array_unknown_bounds + : public __and_, __not_>> + { }; + + // In N3290 is_destructible does not say anything about function + // types and abstract types, see LWG 2049. This implementation + // describes function types as non-destructible and all complete + // object types as destructible, iff the explicit destructor + // call expression is wellformed. + struct __do_is_destructible_impl + { + template().~_Tp())> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_destructible_impl + : public __do_is_destructible_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template, + __is_array_unknown_bounds<_Tp>, + is_function<_Tp>>::value, + bool = __or_, is_scalar<_Tp>>::value> + struct __is_destructible_safe; + + template + struct __is_destructible_safe<_Tp, false, false> + : public __is_destructible_impl::type>::type + { }; + + template + struct __is_destructible_safe<_Tp, true, false> + : public false_type { }; + + template + struct __is_destructible_safe<_Tp, false, true> + : public true_type { }; + + /// is_destructible + template + struct is_destructible + : public __is_destructible_safe<_Tp>::type + { }; + + // is_nothrow_destructible requires that is_destructible is + // satisfied as well. We realize that by mimicing the + // implementation of is_destructible but refer to noexcept(expr) + // instead of decltype(expr). + struct __do_is_nt_destructible_impl + { + template + static integral_constant().~_Tp())> + __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_nt_destructible_impl + : public __do_is_nt_destructible_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template, + __is_array_unknown_bounds<_Tp>, + is_function<_Tp>>::value, + bool = __or_, is_scalar<_Tp>>::value> + struct __is_nt_destructible_safe; + + template + struct __is_nt_destructible_safe<_Tp, false, false> + : public __is_nt_destructible_impl::type>::type + { }; + + template + struct __is_nt_destructible_safe<_Tp, true, false> + : public false_type { }; + + template + struct __is_nt_destructible_safe<_Tp, false, true> + : public true_type { }; + + /// is_nothrow_destructible + template + struct is_nothrow_destructible + : public __is_nt_destructible_safe<_Tp>::type + { }; + + struct __do_is_default_constructible_impl + { + template + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_default_constructible_impl + : public __do_is_default_constructible_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template + struct __is_default_constructible_atom + : public __and_<__not_>, + __is_default_constructible_impl<_Tp>> + { }; + + template::value> + struct __is_default_constructible_safe; + + // The following technique is a workaround for a current core language + // restriction, which does not allow for array types to occur in + // functional casts of the form T(). Complete arrays can be default- + // constructed, if the element type is default-constructible, but + // arrays with unknown bounds are not. + template + struct __is_default_constructible_safe<_Tp, true> + : public __and_<__is_array_known_bounds<_Tp>, + __is_default_constructible_atom::type>> + { }; + + template + struct __is_default_constructible_safe<_Tp, false> + : public __is_default_constructible_atom<_Tp>::type + { }; + + /// is_default_constructible + template + struct is_default_constructible + : public __is_default_constructible_safe<_Tp>::type + { }; + + + // Implementation of is_constructible. + + // The hardest part of this trait is the binary direct-initialization + // case, because we hit into a functional cast of the form T(arg). + // This implementation uses different strategies depending on the + // target type to reduce the test overhead as much as possible: + // + // a) For a reference target type, we use a static_cast expression + // modulo its extra cases. + // + // b) For a non-reference target type we use a ::new expression. + struct __do_is_static_castable_impl + { + template(declval<_From>()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_static_castable_impl + : public __do_is_static_castable_impl + { + typedef decltype(__test<_From, _To>(0)) type; + }; + + template + struct __is_static_castable_safe + : public __is_static_castable_impl<_From, _To>::type + { }; + + // __is_static_castable + template + struct __is_static_castable + : public integral_constant::value)> + { }; + + // Implementation for non-reference types. To meet the proper + // variable definition semantics, we also need to test for + // is_destructible in this case. + // This form should be simplified by a single expression: + // ::delete ::new _Tp(declval<_Arg>()), see c++/51222. + struct __do_is_direct_constructible_impl + { + template()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_direct_constructible_impl + : public __do_is_direct_constructible_impl + { + typedef decltype(__test<_Tp, _Arg>(0)) type; + }; + + template + struct __is_direct_constructible_new_safe + : public __and_, + __is_direct_constructible_impl<_Tp, _Arg>> + { }; + + template + struct is_same; + + template + struct is_base_of; + + template + struct remove_reference; + + template, + is_function<_From>>>::value> + struct __is_base_to_derived_ref; + + template + struct is_constructible; + + // Detect whether we have a downcast situation during + // reference binding. + template + struct __is_base_to_derived_ref<_From, _To, true> + { + typedef typename remove_cv::type>::type __src_t; + typedef typename remove_cv::type>::type __dst_t; + typedef __and_<__not_>, + is_base_of<__src_t, __dst_t>, + __not_>> type; + static constexpr bool value = type::value; + }; + + template + struct __is_base_to_derived_ref<_From, _To, false> + : public false_type + { }; + + template, + is_rvalue_reference<_To>>::value> + struct __is_lvalue_to_rvalue_ref; + + // Detect whether we have an lvalue of non-function type + // bound to a reference-compatible rvalue-reference. + template + struct __is_lvalue_to_rvalue_ref<_From, _To, true> + { + typedef typename remove_cv::type>::type __src_t; + typedef typename remove_cv::type>::type __dst_t; + typedef __and_<__not_>, + __or_, + is_base_of<__dst_t, __src_t>>> type; + static constexpr bool value = type::value; + }; + + template + struct __is_lvalue_to_rvalue_ref<_From, _To, false> + : public false_type + { }; + + // Here we handle direct-initialization to a reference type as + // equivalent to a static_cast modulo overshooting conversions. + // These are restricted to the following conversions: + // a) A base class value to a derived class reference + // b) An lvalue to an rvalue-reference of reference-compatible + // types that are not functions + template + struct __is_direct_constructible_ref_cast + : public __and_<__is_static_castable<_Arg, _Tp>, + __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>, + __is_lvalue_to_rvalue_ref<_Arg, _Tp> + >>> + { }; + + template + struct __is_direct_constructible_new + : public conditional::value, + __is_direct_constructible_ref_cast<_Tp, _Arg>, + __is_direct_constructible_new_safe<_Tp, _Arg> + >::type + { }; + + template + struct __is_direct_constructible + : public __is_direct_constructible_new<_Tp, _Arg>::type + { }; + + // Since default-construction and binary direct-initialization have + // been handled separately, the implementation of the remaining + // n-ary construction cases is rather straightforward. We can use + // here a functional cast, because array types are excluded anyway + // and this form is never interpreted as a C cast. + struct __do_is_nary_constructible_impl + { + template()...))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_nary_constructible_impl + : public __do_is_nary_constructible_impl + { + typedef decltype(__test<_Tp, _Args...>(0)) type; + }; + + template + struct __is_nary_constructible + : public __is_nary_constructible_impl<_Tp, _Args...>::type + { + static_assert(sizeof...(_Args) > 1, + "Only useful for > 1 arguments"); + }; + + template + struct __is_constructible_impl + : public __is_nary_constructible<_Tp, _Args...> + { }; + + template + struct __is_constructible_impl<_Tp, _Arg> + : public __is_direct_constructible<_Tp, _Arg> + { }; + + template + struct __is_constructible_impl<_Tp> + : public is_default_constructible<_Tp> + { }; + + /// is_constructible + template + struct is_constructible + : public __is_constructible_impl<_Tp, _Args...>::type + { }; + + template::value> + struct __is_copy_constructible_impl; + + template + struct __is_copy_constructible_impl<_Tp, false> + : public false_type { }; + + template + struct __is_copy_constructible_impl<_Tp, true> + : public is_constructible<_Tp, const _Tp&> + { }; + + /// is_copy_constructible + template + struct is_copy_constructible + : public __is_copy_constructible_impl<_Tp> + { }; + + template::value> + struct __is_move_constructible_impl; + + template + struct __is_move_constructible_impl<_Tp, false> + : public false_type { }; + + template + struct __is_move_constructible_impl<_Tp, true> + : public is_constructible<_Tp, _Tp&&> + { }; + + /// is_move_constructible + template + struct is_move_constructible + : public __is_move_constructible_impl<_Tp> + { }; + + template + struct __is_nt_default_constructible_atom + : public integral_constant + { }; + + template::value> + struct __is_nt_default_constructible_impl; + + template + struct __is_nt_default_constructible_impl<_Tp, true> + : public __and_<__is_array_known_bounds<_Tp>, + __is_nt_default_constructible_atom::type>> + { }; + + template + struct __is_nt_default_constructible_impl<_Tp, false> + : public __is_nt_default_constructible_atom<_Tp> + { }; + + /// is_nothrow_default_constructible + template + struct is_nothrow_default_constructible + : public __and_, + __is_nt_default_constructible_impl<_Tp>> + { }; + + template + struct __is_nt_constructible_impl + : public integral_constant()...))> + { }; + + template + struct __is_nt_constructible_impl<_Tp, _Arg> + : public integral_constant(declval<_Arg>()))> + { }; + + template + struct __is_nt_constructible_impl<_Tp> + : public is_nothrow_default_constructible<_Tp> + { }; + + /// is_nothrow_constructible + template + struct is_nothrow_constructible + : public __and_, + __is_nt_constructible_impl<_Tp, _Args...>> + { }; + + template::value> + struct __is_nothrow_copy_constructible_impl; + + template + struct __is_nothrow_copy_constructible_impl<_Tp, false> + : public false_type { }; + + template + struct __is_nothrow_copy_constructible_impl<_Tp, true> + : public is_nothrow_constructible<_Tp, const _Tp&> + { }; + + /// is_nothrow_copy_constructible + template + struct is_nothrow_copy_constructible + : public __is_nothrow_copy_constructible_impl<_Tp> + { }; + + template::value> + struct __is_nothrow_move_constructible_impl; + + template + struct __is_nothrow_move_constructible_impl<_Tp, false> + : public false_type { }; + + template + struct __is_nothrow_move_constructible_impl<_Tp, true> + : public is_nothrow_constructible<_Tp, _Tp&&> + { }; + + /// is_nothrow_move_constructible + template + struct is_nothrow_move_constructible + : public __is_nothrow_move_constructible_impl<_Tp> + { }; + + template + class __is_assignable_helper + { + template() = declval<_Up1>())> + static true_type + __test(int); + + template + static false_type + __test(...); + + public: + typedef decltype(__test<_Tp, _Up>(0)) type; + }; + + /// is_assignable + template + struct is_assignable + : public __is_assignable_helper<_Tp, _Up>::type + { }; + + template::value> + struct __is_copy_assignable_impl; + + template + struct __is_copy_assignable_impl<_Tp, false> + : public false_type { }; + + template + struct __is_copy_assignable_impl<_Tp, true> + : public is_assignable<_Tp&, const _Tp&> + { }; + + /// is_copy_assignable + template + struct is_copy_assignable + : public __is_copy_assignable_impl<_Tp> + { }; + + template::value> + struct __is_move_assignable_impl; + + template + struct __is_move_assignable_impl<_Tp, false> + : public false_type { }; + + template + struct __is_move_assignable_impl<_Tp, true> + : public is_assignable<_Tp&, _Tp&&> + { }; + + /// is_move_assignable + template + struct is_move_assignable + : public __is_move_assignable_impl<_Tp> + { }; + + template + struct __is_nt_assignable_impl + : public integral_constant() = declval<_Up>())> + { }; + + /// is_nothrow_assignable + template + struct is_nothrow_assignable + : public __and_, + __is_nt_assignable_impl<_Tp, _Up>> + { }; + + template::value> + struct __is_nt_copy_assignable_impl; + + template + struct __is_nt_copy_assignable_impl<_Tp, false> + : public false_type { }; + + template + struct __is_nt_copy_assignable_impl<_Tp, true> + : public is_nothrow_assignable<_Tp&, const _Tp&> + { }; + + /// is_nothrow_copy_assignable + template + struct is_nothrow_copy_assignable + : public __is_nt_copy_assignable_impl<_Tp> + { }; + + template::value> + struct __is_nt_move_assignable_impl; + + template + struct __is_nt_move_assignable_impl<_Tp, false> + : public false_type { }; + + template + struct __is_nt_move_assignable_impl<_Tp, true> + : public is_nothrow_assignable<_Tp&, _Tp&&> + { }; + + /// is_nothrow_move_assignable + template + struct is_nothrow_move_assignable + : public __is_nt_move_assignable_impl<_Tp> + { }; + + /// is_trivially_constructible + template + struct is_trivially_constructible + : public __and_, integral_constant> + { }; + + /// is_trivially_default_constructible + template + struct is_trivially_default_constructible + : public is_trivially_constructible<_Tp>::type + { }; + + struct __do_is_implicitly_default_constructible_impl + { + template + static void __helper(const _Tp&); + + template + static true_type __test(const _Tp&, + decltype(__helper({}))* = 0); + + static false_type __test(...); + }; + + template + struct __is_implicitly_default_constructible_impl + : public __do_is_implicitly_default_constructible_impl + { + typedef decltype(__test(declval<_Tp>())) type; + }; + + template + struct __is_implicitly_default_constructible_safe + : public __is_implicitly_default_constructible_impl<_Tp>::type + { }; + + template + struct __is_implicitly_default_constructible + : public __and_, + __is_implicitly_default_constructible_safe<_Tp>> + { }; + + /// is_trivially_copy_constructible + template + struct is_trivially_copy_constructible + : public __and_, + integral_constant> + { }; + + /// is_trivially_move_constructible + template + struct is_trivially_move_constructible + : public __and_, + integral_constant> + { }; + + /// is_trivially_assignable + template + struct is_trivially_assignable + : public __and_, + integral_constant> + { }; + + /// is_trivially_copy_assignable + template + struct is_trivially_copy_assignable + : public __and_, + integral_constant> + { }; + + /// is_trivially_move_assignable + template + struct is_trivially_move_assignable + : public __and_, + integral_constant> + { }; + + /// is_trivially_destructible + template + struct is_trivially_destructible + : public __and_, integral_constant> + { }; + + + /// has_virtual_destructor + template + struct has_virtual_destructor + : public integral_constant + { }; + + + // type property queries. + + /// alignment_of + template + struct alignment_of + : public integral_constant { }; + + /// rank + template + struct rank + : public integral_constant { }; + + template + struct rank<_Tp[_Size]> + : public integral_constant::value> { }; + + template + struct rank<_Tp[]> + : public integral_constant::value> { }; + + /// extent + template + struct extent + : public integral_constant { }; + + template + struct extent<_Tp[_Size], _Uint> + : public integral_constant::value> + { }; + + template + struct extent<_Tp[], _Uint> + : public integral_constant::value> + { }; + + + // Type relations. + + /// is_same + template + struct is_same + : public false_type { }; + + template + struct is_same<_Tp, _Tp> + : public true_type { }; + + /// is_base_of + template + struct is_base_of + : public integral_constant + { }; + + template, is_function<_To>, + is_array<_To>>::value> + struct __is_convertible_helper + { typedef typename is_void<_To>::type type; }; + + template + class __is_convertible_helper<_From, _To, false> + { + template + static void __test_aux(_To1); + + template(std::declval<_From1>()))> + static true_type + __test(int); + + template + static false_type + __test(...); + + public: + typedef decltype(__test<_From, _To>(0)) type; + }; + + + /// is_convertible + template + struct is_convertible + : public __is_convertible_helper<_From, _To>::type + { }; + + + // Const-volatile modifications. + + /// remove_const + template + struct remove_const + { typedef _Tp type; }; + + template + struct remove_const<_Tp const> + { typedef _Tp type; }; + + /// remove_volatile + template + struct remove_volatile + { typedef _Tp type; }; + + template + struct remove_volatile<_Tp volatile> + { typedef _Tp type; }; + + /// remove_cv + template + struct remove_cv + { + typedef typename + remove_const::type>::type type; + }; + + /// add_const + template + struct add_const + { typedef _Tp const type; }; + + /// add_volatile + template + struct add_volatile + { typedef _Tp volatile type; }; + + /// add_cv + template + struct add_cv + { + typedef typename + add_const::type>::type type; + }; + +#if __cplusplus > 201103L + +#define __cpp_lib_transformation_trait_aliases 201304 + + /// Alias template for remove_const + template + using remove_const_t = typename remove_const<_Tp>::type; + + /// Alias template for remove_volatile + template + using remove_volatile_t = typename remove_volatile<_Tp>::type; + + /// Alias template for remove_cv + template + using remove_cv_t = typename remove_cv<_Tp>::type; + + /// Alias template for add_const + template + using add_const_t = typename add_const<_Tp>::type; + + /// Alias template for add_volatile + template + using add_volatile_t = typename add_volatile<_Tp>::type; + + /// Alias template for add_cv + template + using add_cv_t = typename add_cv<_Tp>::type; +#endif + + // Reference transformations. + + /// remove_reference + template + struct remove_reference + { typedef _Tp type; }; + + template + struct remove_reference<_Tp&> + { typedef _Tp type; }; + + template + struct remove_reference<_Tp&&> + { typedef _Tp type; }; + + template::value> + struct __add_lvalue_reference_helper + { typedef _Tp type; }; + + template + struct __add_lvalue_reference_helper<_Tp, true> + { typedef _Tp& type; }; + + /// add_lvalue_reference + template + struct add_lvalue_reference + : public __add_lvalue_reference_helper<_Tp> + { }; + + template::value> + struct __add_rvalue_reference_helper + { typedef _Tp type; }; + + template + struct __add_rvalue_reference_helper<_Tp, true> + { typedef _Tp&& type; }; + + /// add_rvalue_reference + template + struct add_rvalue_reference + : public __add_rvalue_reference_helper<_Tp> + { }; + +#if __cplusplus > 201103L + /// Alias template for remove_reference + template + using remove_reference_t = typename remove_reference<_Tp>::type; + + /// Alias template for add_lvalue_reference + template + using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; + + /// Alias template for add_rvalue_reference + template + using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; +#endif + + // Sign modifications. + + // Utility for constructing identically cv-qualified types. + template + struct __cv_selector; + + template + struct __cv_selector<_Unqualified, false, false> + { typedef _Unqualified __type; }; + + template + struct __cv_selector<_Unqualified, false, true> + { typedef volatile _Unqualified __type; }; + + template + struct __cv_selector<_Unqualified, true, false> + { typedef const _Unqualified __type; }; + + template + struct __cv_selector<_Unqualified, true, true> + { typedef const volatile _Unqualified __type; }; + + template::value, + bool _IsVol = is_volatile<_Qualified>::value> + class __match_cv_qualifiers + { + typedef __cv_selector<_Unqualified, _IsConst, _IsVol> __match; + + public: + typedef typename __match::__type __type; + }; + + // Utility for finding the unsigned versions of signed integral types. + template + struct __make_unsigned + { typedef _Tp __type; }; + + template<> + struct __make_unsigned + { typedef unsigned char __type; }; + + template<> + struct __make_unsigned + { typedef unsigned char __type; }; + + template<> + struct __make_unsigned + { typedef unsigned short __type; }; + + template<> + struct __make_unsigned + { typedef unsigned int __type; }; + + template<> + struct __make_unsigned + { typedef unsigned long __type; }; + + template<> + struct __make_unsigned + { typedef unsigned long long __type; }; + +#if defined(_GLIBCXX_USE_WCHAR_T) && !defined(__WCHAR_UNSIGNED__) + template<> + struct __make_unsigned : __make_unsigned<__WCHAR_TYPE__> + { }; +#endif + +#if defined(__GLIBCXX_TYPE_INT_N_0) + template<> + struct __make_unsigned<__GLIBCXX_TYPE_INT_N_0> + { typedef unsigned __GLIBCXX_TYPE_INT_N_0 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + template<> + struct __make_unsigned<__GLIBCXX_TYPE_INT_N_1> + { typedef unsigned __GLIBCXX_TYPE_INT_N_1 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + template<> + struct __make_unsigned<__GLIBCXX_TYPE_INT_N_2> + { typedef unsigned __GLIBCXX_TYPE_INT_N_2 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) + template<> + struct __make_unsigned<__GLIBCXX_TYPE_INT_N_3> + { typedef unsigned __GLIBCXX_TYPE_INT_N_3 __type; }; +#endif + + // Select between integral and enum: not possible to be both. + template::value, + bool _IsEnum = is_enum<_Tp>::value> + class __make_unsigned_selector; + + template + class __make_unsigned_selector<_Tp, true, false> + { + typedef __make_unsigned::type> __unsignedt; + typedef typename __unsignedt::__type __unsigned_type; + typedef __match_cv_qualifiers<_Tp, __unsigned_type> __cv_unsigned; + + public: + typedef typename __cv_unsigned::__type __type; + }; + + template + class __make_unsigned_selector<_Tp, false, true> + { + // With -fshort-enums, an enum may be as small as a char. + typedef unsigned char __smallest; + static const bool __b0 = sizeof(_Tp) <= sizeof(__smallest); + static const bool __b1 = sizeof(_Tp) <= sizeof(unsigned short); + static const bool __b2 = sizeof(_Tp) <= sizeof(unsigned int); + static const bool __b3 = sizeof(_Tp) <= sizeof(unsigned long); + typedef conditional<__b3, unsigned long, unsigned long long> __cond3; + typedef typename __cond3::type __cond3_type; + typedef conditional<__b2, unsigned int, __cond3_type> __cond2; + typedef typename __cond2::type __cond2_type; + typedef conditional<__b1, unsigned short, __cond2_type> __cond1; + typedef typename __cond1::type __cond1_type; + + typedef typename conditional<__b0, __smallest, __cond1_type>::type + __unsigned_type; + typedef __match_cv_qualifiers<_Tp, __unsigned_type> __cv_unsigned; + + public: + typedef typename __cv_unsigned::__type __type; + }; + + // Given an integral/enum type, return the corresponding unsigned + // integer type. + // Primary template. + /// make_unsigned + template + struct make_unsigned + { typedef typename __make_unsigned_selector<_Tp>::__type type; }; + + // Integral, but don't define. + template<> + struct make_unsigned; + + + // Utility for finding the signed versions of unsigned integral types. + template + struct __make_signed + { typedef _Tp __type; }; + + template<> + struct __make_signed + { typedef signed char __type; }; + + template<> + struct __make_signed + { typedef signed char __type; }; + + template<> + struct __make_signed + { typedef signed short __type; }; + + template<> + struct __make_signed + { typedef signed int __type; }; + + template<> + struct __make_signed + { typedef signed long __type; }; + + template<> + struct __make_signed + { typedef signed long long __type; }; + +#if defined(_GLIBCXX_USE_WCHAR_T) && defined(__WCHAR_UNSIGNED__) + template<> + struct __make_signed : __make_signed<__WCHAR_TYPE__> + { }; +#endif + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 + template<> + struct __make_signed : __make_signed + { }; + template<> + struct __make_signed : __make_signed + { }; +#endif + +#if defined(__GLIBCXX_TYPE_INT_N_0) + template<> + struct __make_signed + { typedef __GLIBCXX_TYPE_INT_N_0 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_1) + template<> + struct __make_signed + { typedef __GLIBCXX_TYPE_INT_N_1 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_2) + template<> + struct __make_signed + { typedef __GLIBCXX_TYPE_INT_N_2 __type; }; +#endif +#if defined(__GLIBCXX_TYPE_INT_N_3) + template<> + struct __make_signed + { typedef __GLIBCXX_TYPE_INT_N_3 __type; }; +#endif + + // Select between integral and enum: not possible to be both. + template::value, + bool _IsEnum = is_enum<_Tp>::value> + class __make_signed_selector; + + template + class __make_signed_selector<_Tp, true, false> + { + typedef __make_signed::type> __signedt; + typedef typename __signedt::__type __signed_type; + typedef __match_cv_qualifiers<_Tp, __signed_type> __cv_signed; + + public: + typedef typename __cv_signed::__type __type; + }; + + template + class __make_signed_selector<_Tp, false, true> + { + typedef typename __make_unsigned_selector<_Tp>::__type __unsigned_type; + + public: + typedef typename __make_signed_selector<__unsigned_type>::__type __type; + }; + + // Given an integral/enum type, return the corresponding signed + // integer type. + // Primary template. + /// make_signed + template + struct make_signed + { typedef typename __make_signed_selector<_Tp>::__type type; }; + + // Integral, but don't define. + template<> + struct make_signed; + +#if __cplusplus > 201103L + /// Alias template for make_signed + template + using make_signed_t = typename make_signed<_Tp>::type; + + /// Alias template for make_unsigned + template + using make_unsigned_t = typename make_unsigned<_Tp>::type; +#endif + + // Array modifications. + + /// remove_extent + template + struct remove_extent + { typedef _Tp type; }; + + template + struct remove_extent<_Tp[_Size]> + { typedef _Tp type; }; + + template + struct remove_extent<_Tp[]> + { typedef _Tp type; }; + + /// remove_all_extents + template + struct remove_all_extents + { typedef _Tp type; }; + + template + struct remove_all_extents<_Tp[_Size]> + { typedef typename remove_all_extents<_Tp>::type type; }; + + template + struct remove_all_extents<_Tp[]> + { typedef typename remove_all_extents<_Tp>::type type; }; + +#if __cplusplus > 201103L + /// Alias template for remove_extent + template + using remove_extent_t = typename remove_extent<_Tp>::type; + + /// Alias template for remove_all_extents + template + using remove_all_extents_t = typename remove_all_extents<_Tp>::type; +#endif + + // Pointer modifications. + + template + struct __remove_pointer_helper + { typedef _Tp type; }; + + template + struct __remove_pointer_helper<_Tp, _Up*> + { typedef _Up type; }; + + /// remove_pointer + template + struct remove_pointer + : public __remove_pointer_helper<_Tp, typename remove_cv<_Tp>::type> + { }; + + /// add_pointer + template, + is_void<_Tp>>::value> + struct __add_pointer_helper + { typedef _Tp type; }; + + template + struct __add_pointer_helper<_Tp, true> + { typedef typename remove_reference<_Tp>::type* type; }; + + template + struct add_pointer + : public __add_pointer_helper<_Tp> + { }; + +#if __cplusplus > 201103L + /// Alias template for remove_pointer + template + using remove_pointer_t = typename remove_pointer<_Tp>::type; + + /// Alias template for add_pointer + template + using add_pointer_t = typename add_pointer<_Tp>::type; +#endif + + template + struct __aligned_storage_msa + { + union __type + { + unsigned char __data[_Len]; + struct __attribute__((__aligned__)) { } __align; + }; + }; + + /** + * @brief Alignment type. + * + * The value of _Align is a default-alignment which shall be the + * most stringent alignment requirement for any C++ object type + * whose size is no greater than _Len (3.9). The member typedef + * type shall be a POD type suitable for use as uninitialized + * storage for any object whose size is at most _Len and whose + * alignment is a divisor of _Align. + */ + template::__type)> + struct aligned_storage + { + union type + { + unsigned char __data[_Len]; + struct __attribute__((__aligned__((_Align)))) { } __align; + }; + }; + + template + struct __strictest_alignment + { + static const size_t _S_alignment = 0; + static const size_t _S_size = 0; + }; + + template + struct __strictest_alignment<_Tp, _Types...> + { + static const size_t _S_alignment = + alignof(_Tp) > __strictest_alignment<_Types...>::_S_alignment + ? alignof(_Tp) : __strictest_alignment<_Types...>::_S_alignment; + static const size_t _S_size = + sizeof(_Tp) > __strictest_alignment<_Types...>::_S_size + ? sizeof(_Tp) : __strictest_alignment<_Types...>::_S_size; + }; + + /** + * @brief Provide aligned storage for types. + * + * [meta.trans.other] + * + * Provides aligned storage for any of the provided types of at + * least size _Len. + * + * @see aligned_storage + */ + template + struct aligned_union + { + private: + static_assert(sizeof...(_Types) != 0, "At least one type is required"); + + using __strictest = __strictest_alignment<_Types...>; + static const size_t _S_len = _Len > __strictest::_S_size + ? _Len : __strictest::_S_size; + public: + /// The value of the strictest alignment of _Types. + static const size_t alignment_value = __strictest::_S_alignment; + /// The storage. + typedef typename aligned_storage<_S_len, alignment_value>::type type; + }; + + template + const size_t aligned_union<_Len, _Types...>::alignment_value; + + // Decay trait for arrays and functions, used for perfect forwarding + // in make_pair, make_tuple, etc. + template::value, + bool _IsFunction = is_function<_Up>::value> + struct __decay_selector; + + // NB: DR 705. + template + struct __decay_selector<_Up, false, false> + { typedef typename remove_cv<_Up>::type __type; }; + + template + struct __decay_selector<_Up, true, false> + { typedef typename remove_extent<_Up>::type* __type; }; + + template + struct __decay_selector<_Up, false, true> + { typedef typename add_pointer<_Up>::type __type; }; + + /// decay + template + class decay + { + typedef typename remove_reference<_Tp>::type __remove_type; + + public: + typedef typename __decay_selector<__remove_type>::__type type; + }; + + template + class reference_wrapper; + + // Helper which adds a reference to a type when given a reference_wrapper + template + struct __strip_reference_wrapper + { + typedef _Tp __type; + }; + + template + struct __strip_reference_wrapper > + { + typedef _Tp& __type; + }; + + template + struct __decay_and_strip + { + typedef typename __strip_reference_wrapper< + typename decay<_Tp>::type>::__type __type; + }; + + + // Primary template. + /// Define a member typedef @c type only if a boolean constant is true. + template + struct enable_if + { }; + + // Partial specialization for true. + template + struct enable_if + { typedef _Tp type; }; + + template + using _Require = typename enable_if<__and_<_Cond...>::value>::type; + + // Primary template. + /// Define a member typedef @c type to one of two argument types. + template + struct conditional + { typedef _Iftrue type; }; + + // Partial specialization for false. + template + struct conditional + { typedef _Iffalse type; }; + + /// common_type + template + struct common_type; + + // Sfinae-friendly common_type implementation: + + struct __do_common_type_impl + { + template + static __success_type() + : std::declval<_Up>())>::type> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __common_type_impl + : private __do_common_type_impl + { + typedef decltype(_S_test<_Tp, _Up>(0)) type; + }; + + struct __do_member_type_wrapper + { + template + static __success_type _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __member_type_wrapper + : private __do_member_type_wrapper + { + typedef decltype(_S_test<_Tp>(0)) type; + }; + + template + struct __expanded_common_type_wrapper + { + typedef common_type type; + }; + + template + struct __expanded_common_type_wrapper<__failure_type, _Args...> + { typedef __failure_type type; }; + + template + struct common_type<_Tp> + { typedef typename decay<_Tp>::type type; }; + + template + struct common_type<_Tp, _Up> + : public __common_type_impl<_Tp, _Up>::type + { }; + + template + struct common_type<_Tp, _Up, _Vp...> + : public __expanded_common_type_wrapper>::type, _Vp...>::type + { }; + + /// The underlying type of an enum. + template + struct underlying_type + { + typedef __underlying_type(_Tp) type; + }; + + template + struct __declval_protector + { + static const bool __stop = false; + static typename add_rvalue_reference<_Tp>::type __delegate(); + }; + + template + inline typename add_rvalue_reference<_Tp>::type + declval() noexcept + { + static_assert(__declval_protector<_Tp>::__stop, + "declval() must not be used!"); + return __declval_protector<_Tp>::__delegate(); + } + + /// result_of + template + class result_of; + + // Sfinae-friendly result_of implementation: + +#define __cpp_lib_result_of_sfinae 201210 + + struct __invoke_memfun_ref { }; + struct __invoke_memfun_deref { }; + struct __invoke_memobj_ref { }; + struct __invoke_memobj_deref { }; + struct __invoke_other { }; + + // Associate a tag type with a specialization of __success_type. + template + struct __result_of_success : __success_type<_Tp> + { using __invoke_type = _Tag; }; + + // [func.require] paragraph 1 bullet 1: + struct __result_of_memfun_ref_impl + { + template + static __result_of_success().*std::declval<_Fp>())(std::declval<_Args>()...) + ), __invoke_memfun_ref> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __result_of_memfun_ref + : private __result_of_memfun_ref_impl + { + typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; + }; + + // [func.require] paragraph 1 bullet 2: + struct __result_of_memfun_deref_impl + { + template + static __result_of_success()).*std::declval<_Fp>())(std::declval<_Args>()...) + ), __invoke_memfun_deref> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __result_of_memfun_deref + : private __result_of_memfun_deref_impl + { + typedef decltype(_S_test<_MemPtr, _Arg, _Args...>(0)) type; + }; + + // [func.require] paragraph 1 bullet 3: + struct __result_of_memobj_ref_impl + { + template + static __result_of_success().*std::declval<_Fp>() + ), __invoke_memobj_ref> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __result_of_memobj_ref + : private __result_of_memobj_ref_impl + { + typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; + }; + + // [func.require] paragraph 1 bullet 4: + struct __result_of_memobj_deref_impl + { + template + static __result_of_success()).*std::declval<_Fp>() + ), __invoke_memobj_deref> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __result_of_memobj_deref + : private __result_of_memobj_deref_impl + { + typedef decltype(_S_test<_MemPtr, _Arg>(0)) type; + }; + + template + struct __result_of_memobj; + + template + struct __result_of_memobj<_Res _Class::*, _Arg> + { + typedef typename remove_cv::type>::type _Argval; + typedef _Res _Class::* _MemPtr; + typedef typename conditional<__or_, + is_base_of<_Class, _Argval>>::value, + __result_of_memobj_ref<_MemPtr, _Arg>, + __result_of_memobj_deref<_MemPtr, _Arg> + >::type::type type; + }; + + template + struct __result_of_memfun; + + template + struct __result_of_memfun<_Res _Class::*, _Arg, _Args...> + { + typedef typename remove_cv::type>::type _Argval; + typedef _Res _Class::* _MemPtr; + typedef typename conditional<__or_, + is_base_of<_Class, _Argval>>::value, + __result_of_memfun_ref<_MemPtr, _Arg, _Args...>, + __result_of_memfun_deref<_MemPtr, _Arg, _Args...> + >::type::type type; + }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2219. INVOKE-ing a pointer to member with a reference_wrapper + // as the object expression + + // Used by result_of, invoke etc. to unwrap a reference_wrapper. + template::type> + struct __inv_unwrap + { + using type = _Tp; + }; + + template + struct __inv_unwrap<_Tp, reference_wrapper<_Up>> + { + using type = _Up&; + }; + + template + struct __result_of_impl + { + typedef __failure_type type; + }; + + template + struct __result_of_impl + : public __result_of_memobj::type, + typename __inv_unwrap<_Arg>::type> + { }; + + template + struct __result_of_impl + : public __result_of_memfun::type, + typename __inv_unwrap<_Arg>::type, _Args...> + { }; + + // [func.require] paragraph 1 bullet 5: + struct __result_of_other_impl + { + template + static __result_of_success()(std::declval<_Args>()...) + ), __invoke_other> _S_test(int); + + template + static __failure_type _S_test(...); + }; + + template + struct __result_of_impl + : private __result_of_other_impl + { + typedef decltype(_S_test<_Functor, _ArgTypes...>(0)) type; + }; + + // __invoke_result (std::invoke_result for C++11) + template + struct __invoke_result + : public __result_of_impl< + is_member_object_pointer< + typename remove_reference<_Functor>::type + >::value, + is_member_function_pointer< + typename remove_reference<_Functor>::type + >::value, + _Functor, _ArgTypes... + >::type + { }; + + template + struct result_of<_Functor(_ArgTypes...)> + : public __invoke_result<_Functor, _ArgTypes...> + { }; + +#if __cplusplus >= 201402L + /// Alias template for aligned_storage + template::__type)> + using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; + + template + using aligned_union_t = typename aligned_union<_Len, _Types...>::type; + + /// Alias template for decay + template + using decay_t = typename decay<_Tp>::type; + + /// Alias template for enable_if + template + using enable_if_t = typename enable_if<_Cond, _Tp>::type; + + /// Alias template for conditional + template + using conditional_t = typename conditional<_Cond, _Iftrue, _Iffalse>::type; + + /// Alias template for common_type + template + using common_type_t = typename common_type<_Tp...>::type; + + /// Alias template for underlying_type + template + using underlying_type_t = typename underlying_type<_Tp>::type; + + /// Alias template for result_of + template + using result_of_t = typename result_of<_Tp>::type; +#endif // C++14 + + // __enable_if_t (std::enable_if_t for C++11) + template + using __enable_if_t = typename enable_if<_Cond, _Tp>::type; + + // __void_t (std::void_t for C++11) + template using __void_t = void; + +#if __cplusplus >= 201703L || !defined(__STRICT_ANSI__) // c++17 or gnu++11 +#define __cpp_lib_void_t 201411 + /// A metafunction that always yields void, used for detecting valid types. + template using void_t = void; +#endif + + /// Implementation of the detection idiom (negative case). + template class _Op, typename... _Args> + struct __detector + { + using value_t = false_type; + using type = _Default; + }; + + /// Implementation of the detection idiom (positive case). + template class _Op, + typename... _Args> + struct __detector<_Default, __void_t<_Op<_Args...>>, _Op, _Args...> + { + using value_t = true_type; + using type = _Op<_Args...>; + }; + + // Detect whether _Op<_Args...> is a valid type, use _Default if not. + template class _Op, + typename... _Args> + using __detected_or = __detector<_Default, void, _Op, _Args...>; + + // _Op<_Args...> if that is a valid type, otherwise _Default. + template class _Op, + typename... _Args> + using __detected_or_t + = typename __detected_or<_Default, _Op, _Args...>::type; + + /// @} group metaprogramming + + /** + * Use SFINAE to determine if the type _Tp has a publicly-accessible + * member type _NTYPE. + */ +#define _GLIBCXX_HAS_NESTED_TYPE(_NTYPE) \ + template> \ + struct __has_##_NTYPE \ + : false_type \ + { }; \ + template \ + struct __has_##_NTYPE<_Tp, __void_t> \ + : true_type \ + { }; + + template + struct __is_swappable; + + template + struct __is_nothrow_swappable; + + template + class tuple; + + template + struct __is_tuple_like_impl : false_type + { }; + + template + struct __is_tuple_like_impl> : true_type + { }; + + // Internal type trait that allows us to sfinae-protect tuple_cat. + template + struct __is_tuple_like + : public __is_tuple_like_impl::type>::type>::type + { }; + + template + inline + typename enable_if<__and_<__not_<__is_tuple_like<_Tp>>, + is_move_constructible<_Tp>, + is_move_assignable<_Tp>>::value>::type + swap(_Tp&, _Tp&) + noexcept(__and_, + is_nothrow_move_assignable<_Tp>>::value); + + template + inline + typename enable_if<__is_swappable<_Tp>::value>::type + swap(_Tp (&__a)[_Nm], _Tp (&__b)[_Nm]) + noexcept(__is_nothrow_swappable<_Tp>::value); + + namespace __swappable_details { + using std::swap; + + struct __do_is_swappable_impl + { + template(), std::declval<_Tp&>()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + struct __do_is_nothrow_swappable_impl + { + template + static __bool_constant< + noexcept(swap(std::declval<_Tp&>(), std::declval<_Tp&>())) + > __test(int); + + template + static false_type __test(...); + }; + + } // namespace __swappable_details + + template + struct __is_swappable_impl + : public __swappable_details::__do_is_swappable_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template + struct __is_nothrow_swappable_impl + : public __swappable_details::__do_is_nothrow_swappable_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template + struct __is_swappable + : public __is_swappable_impl<_Tp>::type + { }; + + template + struct __is_nothrow_swappable + : public __is_nothrow_swappable_impl<_Tp>::type + { }; + +#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 +#define __cpp_lib_is_swappable 201603 + /// Metafunctions used for detecting swappable types: p0185r1 + + /// is_swappable + template + struct is_swappable + : public __is_swappable_impl<_Tp>::type + { }; + + /// is_nothrow_swappable + template + struct is_nothrow_swappable + : public __is_nothrow_swappable_impl<_Tp>::type + { }; + +#if __cplusplus >= 201402L + /// is_swappable_v + template + _GLIBCXX17_INLINE constexpr bool is_swappable_v = + is_swappable<_Tp>::value; + + /// is_nothrow_swappable_v + template + _GLIBCXX17_INLINE constexpr bool is_nothrow_swappable_v = + is_nothrow_swappable<_Tp>::value; +#endif // __cplusplus >= 201402L + + namespace __swappable_with_details { + using std::swap; + + struct __do_is_swappable_with_impl + { + template(), std::declval<_Up>())), + typename + = decltype(swap(std::declval<_Up>(), std::declval<_Tp>()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + struct __do_is_nothrow_swappable_with_impl + { + template + static __bool_constant< + noexcept(swap(std::declval<_Tp>(), std::declval<_Up>())) + && + noexcept(swap(std::declval<_Up>(), std::declval<_Tp>())) + > __test(int); + + template + static false_type __test(...); + }; + + } // namespace __swappable_with_details + + template + struct __is_swappable_with_impl + : public __swappable_with_details::__do_is_swappable_with_impl + { + typedef decltype(__test<_Tp, _Up>(0)) type; + }; + + // Optimization for the homogenous lvalue case, not required: + template + struct __is_swappable_with_impl<_Tp&, _Tp&> + : public __swappable_details::__do_is_swappable_impl + { + typedef decltype(__test<_Tp&>(0)) type; + }; + + template + struct __is_nothrow_swappable_with_impl + : public __swappable_with_details::__do_is_nothrow_swappable_with_impl + { + typedef decltype(__test<_Tp, _Up>(0)) type; + }; + + // Optimization for the homogenous lvalue case, not required: + template + struct __is_nothrow_swappable_with_impl<_Tp&, _Tp&> + : public __swappable_details::__do_is_nothrow_swappable_impl + { + typedef decltype(__test<_Tp&>(0)) type; + }; + + /// is_swappable_with + template + struct is_swappable_with + : public __is_swappable_with_impl<_Tp, _Up>::type + { }; + + /// is_nothrow_swappable_with + template + struct is_nothrow_swappable_with + : public __is_nothrow_swappable_with_impl<_Tp, _Up>::type + { }; + +#if __cplusplus >= 201402L + /// is_swappable_with_v + template + _GLIBCXX17_INLINE constexpr bool is_swappable_with_v = + is_swappable_with<_Tp, _Up>::value; + + /// is_nothrow_swappable_with_v + template + _GLIBCXX17_INLINE constexpr bool is_nothrow_swappable_with_v = + is_nothrow_swappable_with<_Tp, _Up>::value; +#endif // __cplusplus >= 201402L + +#endif// c++1z or gnu++11 + + // __is_invocable (std::is_invocable for C++11) + + template + struct __is_invocable_impl : false_type { }; + + template + struct __is_invocable_impl<_Result, _Ret, __void_t> + : __or_, is_convertible>::type + { }; + + template + struct __is_invocable + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type + { }; + + template + constexpr bool __call_is_nt(__invoke_memfun_ref) + { + using _Up = typename __inv_unwrap<_Tp>::type; + return noexcept((std::declval<_Up>().*std::declval<_Fn>())( + std::declval<_Args>()...)); + } + + template + constexpr bool __call_is_nt(__invoke_memfun_deref) + { + return noexcept(((*std::declval<_Tp>()).*std::declval<_Fn>())( + std::declval<_Args>()...)); + } + + template + constexpr bool __call_is_nt(__invoke_memobj_ref) + { + using _Up = typename __inv_unwrap<_Tp>::type; + return noexcept(std::declval<_Up>().*std::declval<_Fn>()); + } + + template + constexpr bool __call_is_nt(__invoke_memobj_deref) + { + return noexcept((*std::declval<_Tp>()).*std::declval<_Fn>()); + } + + template + constexpr bool __call_is_nt(__invoke_other) + { + return noexcept(std::declval<_Fn>()(std::declval<_Args>()...)); + } + + template + struct __call_is_nothrow + : __bool_constant< + std::__call_is_nt<_Fn, _Args...>(typename _Result::__invoke_type{}) + > + { }; + + template + using __call_is_nothrow_ + = __call_is_nothrow<__invoke_result<_Fn, _Args...>, _Fn, _Args...>; + + // __is_nothrow_invocable (std::is_nothrow_invocable for C++11) + template + struct __is_nothrow_invocable + : __and_<__is_invocable<_Fn, _Args...>, + __call_is_nothrow_<_Fn, _Args...>>::type + { }; + + struct __nonesuch { + __nonesuch() = delete; + ~__nonesuch() = delete; + __nonesuch(__nonesuch const&) = delete; + void operator=(__nonesuch const&) = delete; + }; + +#if __cplusplus > 201402L +# define __cpp_lib_is_invocable 201703 + + /// std::invoke_result + template + struct invoke_result + : public __invoke_result<_Functor, _ArgTypes...> + { }; + + /// std::invoke_result_t + template + using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; + + /// std::is_invocable + template + struct is_invocable + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>::type + { }; + + /// std::is_invocable_r + template + struct is_invocable_r + : __is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>::type + { }; + + /// std::is_nothrow_invocable + template + struct is_nothrow_invocable + : __and_<__is_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, void>, + __call_is_nothrow_<_Fn, _ArgTypes...>>::type + { }; + + template + struct __is_nt_invocable_impl : false_type { }; + + template + struct __is_nt_invocable_impl<_Result, _Ret, + __void_t> + : __or_, + __and_, + is_nothrow_constructible<_Ret, typename _Result::type>>> + { }; + + /// std::is_nothrow_invocable_r + template + struct is_nothrow_invocable_r + : __and_<__is_nt_invocable_impl<__invoke_result<_Fn, _ArgTypes...>, _Ret>, + __call_is_nothrow_<_Fn, _ArgTypes...>>::type + { }; + + /// std::is_invocable_v + template + inline constexpr bool is_invocable_v = is_invocable<_Fn, _Args...>::value; + + /// std::is_nothrow_invocable_v + template + inline constexpr bool is_nothrow_invocable_v + = is_nothrow_invocable<_Fn, _Args...>::value; + + /// std::is_invocable_r_v + template + inline constexpr bool is_invocable_r_v + = is_invocable_r<_Fn, _Args...>::value; + + /// std::is_nothrow_invocable_r_v + template + inline constexpr bool is_nothrow_invocable_r_v + = is_nothrow_invocable_r<_Fn, _Args...>::value; +#endif // C++17 + +#if __cplusplus > 201402L +# define __cpp_lib_type_trait_variable_templates 201510L +template + inline constexpr bool is_void_v = is_void<_Tp>::value; +template + inline constexpr bool is_null_pointer_v = is_null_pointer<_Tp>::value; +template + inline constexpr bool is_integral_v = is_integral<_Tp>::value; +template + inline constexpr bool is_floating_point_v = is_floating_point<_Tp>::value; +template + inline constexpr bool is_array_v = is_array<_Tp>::value; +template + inline constexpr bool is_pointer_v = is_pointer<_Tp>::value; +template + inline constexpr bool is_lvalue_reference_v = + is_lvalue_reference<_Tp>::value; +template + inline constexpr bool is_rvalue_reference_v = + is_rvalue_reference<_Tp>::value; +template + inline constexpr bool is_member_object_pointer_v = + is_member_object_pointer<_Tp>::value; +template + inline constexpr bool is_member_function_pointer_v = + is_member_function_pointer<_Tp>::value; +template + inline constexpr bool is_enum_v = is_enum<_Tp>::value; +template + inline constexpr bool is_union_v = is_union<_Tp>::value; +template + inline constexpr bool is_class_v = is_class<_Tp>::value; +template + inline constexpr bool is_function_v = is_function<_Tp>::value; +template + inline constexpr bool is_reference_v = is_reference<_Tp>::value; +template + inline constexpr bool is_arithmetic_v = is_arithmetic<_Tp>::value; +template + inline constexpr bool is_fundamental_v = is_fundamental<_Tp>::value; +template + inline constexpr bool is_object_v = is_object<_Tp>::value; +template + inline constexpr bool is_scalar_v = is_scalar<_Tp>::value; +template + inline constexpr bool is_compound_v = is_compound<_Tp>::value; +template + inline constexpr bool is_member_pointer_v = is_member_pointer<_Tp>::value; +template + inline constexpr bool is_const_v = is_const<_Tp>::value; +template + inline constexpr bool is_volatile_v = is_volatile<_Tp>::value; +template + inline constexpr bool is_trivial_v = is_trivial<_Tp>::value; +template + inline constexpr bool is_trivially_copyable_v = + is_trivially_copyable<_Tp>::value; +template + inline constexpr bool is_standard_layout_v = is_standard_layout<_Tp>::value; +template + inline constexpr bool is_pod_v = is_pod<_Tp>::value; +template + inline constexpr bool is_literal_type_v = is_literal_type<_Tp>::value; +template + inline constexpr bool is_empty_v = is_empty<_Tp>::value; +template + inline constexpr bool is_polymorphic_v = is_polymorphic<_Tp>::value; +template + inline constexpr bool is_abstract_v = is_abstract<_Tp>::value; +template + inline constexpr bool is_final_v = is_final<_Tp>::value; +template + inline constexpr bool is_signed_v = is_signed<_Tp>::value; +template + inline constexpr bool is_unsigned_v = is_unsigned<_Tp>::value; +template + inline constexpr bool is_constructible_v = + is_constructible<_Tp, _Args...>::value; +template + inline constexpr bool is_default_constructible_v = + is_default_constructible<_Tp>::value; +template + inline constexpr bool is_copy_constructible_v = + is_copy_constructible<_Tp>::value; +template + inline constexpr bool is_move_constructible_v = + is_move_constructible<_Tp>::value; +template + inline constexpr bool is_assignable_v = is_assignable<_Tp, _Up>::value; +template + inline constexpr bool is_copy_assignable_v = is_copy_assignable<_Tp>::value; +template + inline constexpr bool is_move_assignable_v = is_move_assignable<_Tp>::value; +template + inline constexpr bool is_destructible_v = is_destructible<_Tp>::value; +template + inline constexpr bool is_trivially_constructible_v = + is_trivially_constructible<_Tp, _Args...>::value; +template + inline constexpr bool is_trivially_default_constructible_v = + is_trivially_default_constructible<_Tp>::value; +template + inline constexpr bool is_trivially_copy_constructible_v = + is_trivially_copy_constructible<_Tp>::value; +template + inline constexpr bool is_trivially_move_constructible_v = + is_trivially_move_constructible<_Tp>::value; +template + inline constexpr bool is_trivially_assignable_v = + is_trivially_assignable<_Tp, _Up>::value; +template + inline constexpr bool is_trivially_copy_assignable_v = + is_trivially_copy_assignable<_Tp>::value; +template + inline constexpr bool is_trivially_move_assignable_v = + is_trivially_move_assignable<_Tp>::value; +template + inline constexpr bool is_trivially_destructible_v = + is_trivially_destructible<_Tp>::value; +template + inline constexpr bool is_nothrow_constructible_v = + is_nothrow_constructible<_Tp, _Args...>::value; +template + inline constexpr bool is_nothrow_default_constructible_v = + is_nothrow_default_constructible<_Tp>::value; +template + inline constexpr bool is_nothrow_copy_constructible_v = + is_nothrow_copy_constructible<_Tp>::value; +template + inline constexpr bool is_nothrow_move_constructible_v = + is_nothrow_move_constructible<_Tp>::value; +template + inline constexpr bool is_nothrow_assignable_v = + is_nothrow_assignable<_Tp, _Up>::value; +template + inline constexpr bool is_nothrow_copy_assignable_v = + is_nothrow_copy_assignable<_Tp>::value; +template + inline constexpr bool is_nothrow_move_assignable_v = + is_nothrow_move_assignable<_Tp>::value; +template + inline constexpr bool is_nothrow_destructible_v = + is_nothrow_destructible<_Tp>::value; +template + inline constexpr bool has_virtual_destructor_v = + has_virtual_destructor<_Tp>::value; +template + inline constexpr size_t alignment_of_v = alignment_of<_Tp>::value; +template + inline constexpr size_t rank_v = rank<_Tp>::value; +template + inline constexpr size_t extent_v = extent<_Tp, _Idx>::value; +template + inline constexpr bool is_same_v = is_same<_Tp, _Up>::value; +template + inline constexpr bool is_base_of_v = is_base_of<_Base, _Derived>::value; +template + inline constexpr bool is_convertible_v = is_convertible<_From, _To>::value; + +#if __GNUC__ >= 7 +# define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1 +#elif defined(__is_identifier) +// For non-GNU compilers: +# if ! __is_identifier(__has_unique_object_representations) +# define _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP 1 +# endif +#endif + +#ifdef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP +# define __cpp_lib_has_unique_object_representations 201606 + /// has_unique_object_representations + template + struct has_unique_object_representations + : bool_constant<__has_unique_object_representations( + remove_cv_t> + )> + { }; + + template + inline constexpr bool has_unique_object_representations_v + = has_unique_object_representations<_Tp>::value; +#endif +#undef _GLIBCXX_HAVE_BUILTIN_HAS_UNIQ_OBJ_REP + +#if __GNUC__ >= 7 +# define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1 +#elif defined(__is_identifier) +// For non-GNU compilers: +# if ! __is_identifier(__is_aggregate) +# define _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE 1 +# endif +#endif + +#ifdef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE +#define __cpp_lib_is_aggregate 201703 + /// is_aggregate + template + struct is_aggregate + : bool_constant<__is_aggregate(remove_cv_t<_Tp>)> { }; + + /// is_aggregate_v + template + inline constexpr bool is_aggregate_v = is_aggregate<_Tp>::value; +#endif +#undef _GLIBCXX_HAVE_BUILTIN_IS_AGGREGATE + +#endif // C++17 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +#endif // C++11 + +#endif // _GLIBCXX_TYPE_TRAITS diff --git a/AH/STL/Fallback/utility b/AH/STL/Fallback/utility new file mode 100644 index 0000000..5879660 --- /dev/null +++ b/AH/STL/Fallback/utility @@ -0,0 +1,407 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996,1997 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/utility + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_UTILITY +#define _GLIBCXX_UTILITY 1 + +#pragma GCC system_header + +/** + * @defgroup utilities Utilities + * + * Components deemed generally useful. Includes pair, tuple, + * forward/move helpers, ratio, function object, metaprogramming and + * type traits, time, date, and memory functions. + */ + +#include "bits/c++config.h" +#include "bits/stl_relops.h" +#include "bits/stl_pair.h" + +#if __cplusplus >= 201103L + +#include "type_traits" +#include "bits/move.h" +#include "initializer_list" + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + + /// Finds the size of a given tuple type. + template + struct tuple_size; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2770. tuple_size specialization is not SFINAE compatible + +#if __cplusplus <= 201402L + template + struct __tuple_size_cv_impl { }; + + template + struct __tuple_size_cv_impl<_Tp, __void_t::value)>> + : integral_constant::value> { }; + + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2313. tuple_size should always derive from integral_constant + template + struct tuple_size : __tuple_size_cv_impl<_Tp> { }; + + template + struct tuple_size : __tuple_size_cv_impl<_Tp> { }; + + template + struct tuple_size : __tuple_size_cv_impl<_Tp> { }; +#else + template::type, + typename = typename enable_if::value>::type, + size_t = tuple_size<_Tp>::value> + using __enable_if_has_tuple_size = _Tp; + + template + struct tuple_size> + : public tuple_size<_Tp> { }; + + template + struct tuple_size> + : public tuple_size<_Tp> { }; + + template + struct tuple_size> + : public tuple_size<_Tp> { }; +#endif + + /// Gives the type of the ith element of a given tuple type. + template + struct tuple_element; + + // Duplicate of C++14's tuple_element_t for internal use in C++11 mode + template + using __tuple_element_t = typename tuple_element<__i, _Tp>::type; + + template + struct tuple_element<__i, const _Tp> + { + typedef typename add_const<__tuple_element_t<__i, _Tp>>::type type; + }; + + template + struct tuple_element<__i, volatile _Tp> + { + typedef typename add_volatile<__tuple_element_t<__i, _Tp>>::type type; + }; + + template + struct tuple_element<__i, const volatile _Tp> + { + typedef typename add_cv<__tuple_element_t<__i, _Tp>>::type type; + }; + +#if __cplusplus > 201103L +#define __cpp_lib_tuple_element_t 201402 + + template + using tuple_element_t = typename tuple_element<__i, _Tp>::type; +#endif + + // Various functions which give std::pair a tuple-like interface. + + /// Partial specialization for std::pair + template + struct __is_tuple_like_impl> : true_type + { }; + + /// Partial specialization for std::pair + template + struct tuple_size> + : public integral_constant { }; + + /// Partial specialization for std::pair + template + struct tuple_element<0, std::pair<_Tp1, _Tp2>> + { typedef _Tp1 type; }; + + /// Partial specialization for std::pair + template + struct tuple_element<1, std::pair<_Tp1, _Tp2>> + { typedef _Tp2 type; }; + + template + struct __pair_get; + + template<> + struct __pair_get<0> + { + template + static constexpr _Tp1& + __get(std::pair<_Tp1, _Tp2>& __pair) noexcept + { return __pair.first; } + + template + static constexpr _Tp1&& + __move_get(std::pair<_Tp1, _Tp2>&& __pair) noexcept + { return std::forward<_Tp1>(__pair.first); } + + template + static constexpr const _Tp1& + __const_get(const std::pair<_Tp1, _Tp2>& __pair) noexcept + { return __pair.first; } + }; + + template<> + struct __pair_get<1> + { + template + static constexpr _Tp2& + __get(std::pair<_Tp1, _Tp2>& __pair) noexcept + { return __pair.second; } + + template + static constexpr _Tp2&& + __move_get(std::pair<_Tp1, _Tp2>&& __pair) noexcept + { return std::forward<_Tp2>(__pair.second); } + + template + static constexpr const _Tp2& + __const_get(const std::pair<_Tp1, _Tp2>& __pair) noexcept + { return __pair.second; } + }; + + template + constexpr typename tuple_element<_Int, std::pair<_Tp1, _Tp2>>::type& + get(std::pair<_Tp1, _Tp2>& __in) noexcept + { return __pair_get<_Int>::__get(__in); } + + template + constexpr typename tuple_element<_Int, std::pair<_Tp1, _Tp2>>::type&& + get(std::pair<_Tp1, _Tp2>&& __in) noexcept + { return __pair_get<_Int>::__move_get(std::move(__in)); } + + template + constexpr const typename tuple_element<_Int, std::pair<_Tp1, _Tp2>>::type& + get(const std::pair<_Tp1, _Tp2>& __in) noexcept + { return __pair_get<_Int>::__const_get(__in); } + +#if __cplusplus > 201103L + +#define __cpp_lib_tuples_by_type 201304 + + template + constexpr _Tp& + get(pair<_Tp, _Up>& __p) noexcept + { return __p.first; } + + template + constexpr const _Tp& + get(const pair<_Tp, _Up>& __p) noexcept + { return __p.first; } + + template + constexpr _Tp&& + get(pair<_Tp, _Up>&& __p) noexcept + { return std::move(__p.first); } + + template + constexpr _Tp& + get(pair<_Up, _Tp>& __p) noexcept + { return __p.second; } + + template + constexpr const _Tp& + get(const pair<_Up, _Tp>& __p) noexcept + { return __p.second; } + + template + constexpr _Tp&& + get(pair<_Up, _Tp>&& __p) noexcept + { return std::move(__p.second); } + +#define __cpp_lib_exchange_function 201304 + + /// Assign @p __new_val to @p __obj and return its previous value. + template + inline _Tp + exchange(_Tp& __obj, _Up&& __new_val) + { return std::__exchange(__obj, std::forward<_Up>(__new_val)); } +#endif + + // Stores a tuple of indices. Used by tuple and pair, and by bind() to + // extract the elements in a tuple. + template struct _Index_tuple { }; + + // Concatenates two _Index_tuples. + template struct _Itup_cat; + + template + struct _Itup_cat<_Index_tuple<_Ind1...>, _Index_tuple<_Ind2...>> + { + using __type = _Index_tuple<_Ind1..., (_Ind2 + sizeof...(_Ind1))...>; + }; + + // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>. + template + struct _Build_index_tuple + : _Itup_cat::__type, + typename _Build_index_tuple<_Num - _Num / 2>::__type> + { }; + + template<> + struct _Build_index_tuple<1> + { + typedef _Index_tuple<0> __type; + }; + + template<> + struct _Build_index_tuple<0> + { + typedef _Index_tuple<> __type; + }; + +#if __cplusplus > 201103L + +#define __cpp_lib_integer_sequence 201304 + + /// Class template integer_sequence + template + struct integer_sequence + { + typedef _Tp value_type; + static constexpr size_t size() noexcept { return sizeof...(_Idx); } + }; + + template::__type> + struct _Make_integer_sequence; + + template + struct _Make_integer_sequence<_Tp, _Num, _Index_tuple<_Idx...>> + { + static_assert( _Num >= 0, + "Cannot make integer sequence of negative length" ); + + typedef integer_sequence<_Tp, static_cast<_Tp>(_Idx)...> __type; + }; + + /// Alias template make_integer_sequence + template + using make_integer_sequence + = typename _Make_integer_sequence<_Tp, _Num>::__type; + + /// Alias template index_sequence + template + using index_sequence = integer_sequence; + + /// Alias template make_index_sequence + template + using make_index_sequence = make_integer_sequence; + + /// Alias template index_sequence_for + template + using index_sequence_for = make_index_sequence; +#endif + +#if __cplusplus > 201402L + + struct in_place_t { + explicit in_place_t() = default; + }; + + inline constexpr in_place_t in_place{}; + + template struct in_place_type_t + { + explicit in_place_type_t() = default; + }; + + template + inline constexpr in_place_type_t<_Tp> in_place_type{}; + + template struct in_place_index_t + { + explicit in_place_index_t() = default; + }; + + template + inline constexpr in_place_index_t<_Idx> in_place_index{}; + + template + struct __is_in_place_type_impl : false_type + { }; + + template + struct __is_in_place_type_impl> : true_type + { }; + + template + struct __is_in_place_type + : public __is_in_place_type_impl<_Tp> + { }; + +#define __cpp_lib_as_const 201510 + template + constexpr add_const_t<_Tp>& as_const(_Tp& __t) noexcept { return __t; } + + template + void as_const(const _Tp&&) = delete; + +#endif // C++17 + +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace + +#endif + +#endif /* _GLIBCXX_UTILITY */ diff --git a/AH/STL/Fallback/vector b/AH/STL/Fallback/vector new file mode 100644 index 0000000..0f4f00a --- /dev/null +++ b/AH/STL/Fallback/vector @@ -0,0 +1,80 @@ +// -*- C++ -*- + +// Copyright (C) 2001-2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/* + * + * Copyright (c) 1994 + * Hewlett-Packard Company + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Hewlett-Packard Company makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * + * Copyright (c) 1996 + * Silicon Graphics Computer Systems, Inc. + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Silicon Graphics makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + */ + +/** @file include/vector + * This is a Standard C++ Library header. + */ + +#ifndef _GLIBCXX_VECTOR +#define _GLIBCXX_VECTOR 1 + +#pragma GCC system_header + +#include "bits/stl_algobase.h" +#include "bits/allocator.h" +#include "bits/stl_construct.h" +#include "bits/stl_uninitialized.h" +#include "bits/stl_vector.h" +#include "bits/stl_bvector.h" +#include "bits/range_access.h" + +#ifndef _GLIBCXX_EXPORT_TEMPLATE +# include "bits/vector.tcc" +#endif + +#ifdef _GLIBCXX_DEBUG +# include "../debug/vector" +#endif + +#ifdef _GLIBCXX_PROFILE +# include "../profile/vector" +#endif + +#endif /* _GLIBCXX_VECTOR */ diff --git a/AH/STL/README.md b/AH/STL/README.md new file mode 100644 index 0000000..d8fa5d1 --- /dev/null +++ b/AH/STL/README.md @@ -0,0 +1,2 @@ +The files in the `Fallback` folder are from the GCC 7.4.0 STL implementation, +with minimal modifications to get it to compile with Arduino. \ No newline at end of file diff --git a/AH/STL/algorithm b/AH/STL/algorithm new file mode 100644 index 0000000..3d6bae0 --- /dev/null +++ b/AH/STL/algorithm @@ -0,0 +1,16 @@ +#pragma once + +#include + + +#ifdef __AVR__ +#include + +#include "Fallback/algorithm" +#else +#include +#endif + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/array b/AH/STL/array new file mode 100644 index 0000000..79c2560 --- /dev/null +++ b/AH/STL/array @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/array" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/bitset b/AH/STL/bitset new file mode 100644 index 0000000..bab367c --- /dev/null +++ b/AH/STL/bitset @@ -0,0 +1,20 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/bitset" +#else +#include +#endif + +#include + +template +Print &operator<<(Print &os, const std::bitset &bs) { + for (size_t i = Nb; i-- > 0;) + os << (bs[i] ? '1' : '0'); + return os; +} \ No newline at end of file diff --git a/AH/STL/climits b/AH/STL/climits new file mode 100644 index 0000000..2cbd638 --- /dev/null +++ b/AH/STL/climits @@ -0,0 +1,11 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/climits" +#else +#include +#endif \ No newline at end of file diff --git a/AH/STL/cmath b/AH/STL/cmath new file mode 100644 index 0000000..2bd3376 --- /dev/null +++ b/AH/STL/cmath @@ -0,0 +1,61 @@ +#pragma once + +#include + + +#ifdef __AVR__ +#include + +#include "Fallback/cmath" +#else + +#include + +#if !defined(__clang__) && !defined(_GLIBCXX_USE_C99_MATH_TR1) +#pragma message("FMA math fix") +namespace std { + constexpr double + fma(double __x, double __y, double __z) + { return __builtin_fma(__x, __y, __z); } + + constexpr float + fma(float __x, float __y, float __z) + { return __builtin_fmaf(__x, __y, __z); } + + constexpr long double + fma(long double __x, long double __y, long double __z) + { return __builtin_fmal(__x, __y, __z); } + + constexpr float + round(float __x) + { return __builtin_roundf(__x); } + + constexpr double + round(double __x) + { return __builtin_round(__x); } + + constexpr long double + round(long double __x) + { return __builtin_roundl(__x); } + + template + constexpr typename __gnu_cxx::__enable_if<__is_integer<_Tp>::__value, + double>::__type + round(_Tp __x) + { return __builtin_round(__x); } + + constexpr float + hypot(float __x, float __y) + { return __builtin_hypotf(__x, __y); } + + constexpr double + hypot(double __x, double __y) + { return __builtin_hypot(__x, __y); } + + constexpr long double + hypot(long double __x, long double __y) + { return __builtin_hypotl(__x, __y); } +} +#endif + +#endif \ No newline at end of file diff --git a/AH/STL/complex b/AH/STL/complex new file mode 100644 index 0000000..7fbaf9e --- /dev/null +++ b/AH/STL/complex @@ -0,0 +1,20 @@ +#pragma once + +#include + + +#ifdef __AVR__ +#include + +#include "Fallback/complex" +#else +#include +#endif + +#include + +template +Print &operator<<(Print &os, const std::complex &x) { + USING_AH_NAMESPACE; + return os << '(' << x.real() << ',' << x.imag() << ')'; +} \ No newline at end of file diff --git a/AH/STL/cstddef b/AH/STL/cstddef new file mode 100644 index 0000000..7c1889e --- /dev/null +++ b/AH/STL/cstddef @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/cstddef" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/cstdint b/AH/STL/cstdint new file mode 100644 index 0000000..1d32a0a --- /dev/null +++ b/AH/STL/cstdint @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/cstdint" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/cstdlib b/AH/STL/cstdlib new file mode 100644 index 0000000..3105784 --- /dev/null +++ b/AH/STL/cstdlib @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/cstdlib" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/initializer_list b/AH/STL/initializer_list new file mode 100644 index 0000000..960548b --- /dev/null +++ b/AH/STL/initializer_list @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/initializer_list" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/iterator b/AH/STL/iterator new file mode 100644 index 0000000..897e57b --- /dev/null +++ b/AH/STL/iterator @@ -0,0 +1,12 @@ +#pragma once + +#include + + +#ifdef __AVR__ +#include + +#include "Fallback/iterator" +#else +#include +#endif \ No newline at end of file diff --git a/AH/STL/limits b/AH/STL/limits new file mode 100644 index 0000000..c30c8c4 --- /dev/null +++ b/AH/STL/limits @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/limits" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/memory b/AH/STL/memory new file mode 100644 index 0000000..ac94a8c --- /dev/null +++ b/AH/STL/memory @@ -0,0 +1,53 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/memory" +#else +#include +#endif + +BEGIN_AH_NAMESPACE + +#if __cplusplus > 201103L + +using std::make_unique; + +#else + + template + struct _MakeUniq + { typedef std::unique_ptr<_Tp> __single_object; }; + + template + struct _MakeUniq<_Tp[]> + { typedef std::unique_ptr<_Tp[]> __array; }; + + template + struct _MakeUniq<_Tp[_Bound]> + { struct __invalid_type { }; }; + + /// std::make_unique for single objects + template + inline typename _MakeUniq<_Tp>::__single_object + make_unique(_Args&&... __args) + { return std::unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); } + + /// std::make_unique for arrays of unknown bound + template + inline typename _MakeUniq<_Tp>::__array + make_unique(size_t __num) + { return std::unique_ptr<_Tp>( + new typename std::remove_extent<_Tp>::type[__num]()); } + + /// Disable std::make_unique for arrays of known bound + template + inline typename _MakeUniq<_Tp>::__invalid_type + make_unique(_Args&&...) = delete; + +#endif + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/new b/AH/STL/new new file mode 100644 index 0000000..625c16c --- /dev/null +++ b/AH/STL/new @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/new" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/numeric b/AH/STL/numeric new file mode 100644 index 0000000..528f565 --- /dev/null +++ b/AH/STL/numeric @@ -0,0 +1,11 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/numeric" +#else +#include +#endif \ No newline at end of file diff --git a/AH/STL/optional b/AH/STL/optional new file mode 100644 index 0000000..c74ed88 --- /dev/null +++ b/AH/STL/optional @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/optional" +#else +#if defined(__cpp_lib_optional) && __cpp_lib_optional >= 201603 +#include +#endif +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/tuple b/AH/STL/tuple new file mode 100644 index 0000000..9a7953c --- /dev/null +++ b/AH/STL/tuple @@ -0,0 +1,11 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/tuple" +#else +#include +#endif \ No newline at end of file diff --git a/AH/STL/type_traits b/AH/STL/type_traits new file mode 100644 index 0000000..1e0e76d --- /dev/null +++ b/AH/STL/type_traits @@ -0,0 +1,26 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include "Fallback/type_traits" +#else +#include +#endif + +namespace std { + +#if __cplusplus < 201402L +template +using enable_if_t = typename enable_if::type; + +#endif + +} // namespace std + +BEGIN_AH_NAMESPACE +template +struct type_identity { + using type = T; +}; +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/utility b/AH/STL/utility new file mode 100644 index 0000000..fd8bf61 --- /dev/null +++ b/AH/STL/utility @@ -0,0 +1,27 @@ +#pragma once + +#include + +#ifdef __AVR__ +#include + +#include "Fallback/utility" +#else +#include +#endif + +namespace std { + +#if __cplusplus < 201402L + +/// https://en.cppreference.com/w/cpp/utility/exchange +template +T exchange(T &obj, U &&new_value) { + T old_value = std::move(obj); + obj = std::forward(new_value); + return old_value; +} + +#endif + +} // namespace std \ No newline at end of file diff --git a/AH/STL/vector b/AH/STL/vector new file mode 100644 index 0000000..939e400 --- /dev/null +++ b/AH/STL/vector @@ -0,0 +1,15 @@ +#pragma once + +#ifdef __AVR__ +#include + +#include "Fallback/vector" +#else +#include +#endif + +#include + +BEGIN_AH_NAMESPACE + +END_AH_NAMESPACE \ No newline at end of file diff --git a/AH/STL/vector.cpp b/AH/STL/vector.cpp new file mode 100644 index 0000000..802d931 --- /dev/null +++ b/AH/STL/vector.cpp @@ -0,0 +1,12 @@ +#if defined(TEENSYDUINO) && !defined(AVR) && TEENSYDUINO < 153 +#include "vector" +#include + +namespace std { +void __throw_bad_alloc() { FATAL_ERROR(F("bad_alloc"), 0x6371); } + +void __throw_length_error(char const *e) { + FATAL_ERROR(F("length_error: ") << e, 0x6372); +} +} // namespace std +#endif \ No newline at end of file diff --git a/AH/Settings/NamespaceSettings.hpp b/AH/Settings/NamespaceSettings.hpp new file mode 100644 index 0000000..a81f387 --- /dev/null +++ b/AH/Settings/NamespaceSettings.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +#define USE_AH_NAMESPACE +#define AH_NAMESPACE_NAME AH + +// ========================================================================== // + +#ifdef USE_AH_NAMESPACE +#define BEGIN_AH_NAMESPACE \ + AH_DIAGNOSTIC_WERROR() \ + namespace AH_NAMESPACE_NAME { +#define END_AH_NAMESPACE \ + } \ + AH_DIAGNOSTIC_POP() +#define USING_AH_NAMESPACE using namespace AH_NAMESPACE_NAME +#else +#define BEGIN_AH_NAMESPACE +#define END_AH_NAMESPACE +#define USING_AH_NAMESPACE +#endif \ No newline at end of file diff --git a/AH/Settings/Settings.hpp b/AH/Settings/Settings.hpp new file mode 100644 index 0000000..6f65cff --- /dev/null +++ b/AH/Settings/Settings.hpp @@ -0,0 +1,36 @@ +#ifndef AH_SETTINGSWRAPPER_HPP +#error "Do not include this file directly, use the wrapper!" +#endif + +/** + * @file + * @brief All user settings and debugging options can be changed here. + * @ingroup AH_Settings + */ + +#include +#include +#include +#include +#include + +BEGIN_AH_NAMESPACE + +#ifndef DEBUG_OUT +#define DEBUG_OUT +#endif + +#define FATAL_ERRORS + +constexpr unsigned long defaultBaudRate = 115200; +constexpr uint8_t ADC_BITS = ADC_RESOLUTION; +constexpr uint8_t ANALOG_FILTER_SHIFT_FACTOR = 2; +using ANALOG_FILTER_TYPE = uint16_t; +constexpr unsigned long BUTTON_DEBOUNCE_TIME = 25; +constexpr unsigned long SELECT_LINE_DELAY = 10; +constexpr unsigned long LONG_PRESS_DELAY = 450; +constexpr unsigned long LONG_PRESS_REPEAT_DELAY = 200; +constexpr unsigned long FILTERED_INPUT_UPDATE_INTERVAL = 1000; +constexpr static Frequency SPI_MAX_SPEED = 8_MHz; + +END_AH_NAMESPACE diff --git a/AH/Settings/SettingsWrapper.hpp b/AH/Settings/SettingsWrapper.hpp new file mode 100644 index 0000000..73350b4 --- /dev/null +++ b/AH/Settings/SettingsWrapper.hpp @@ -0,0 +1,34 @@ +#ifndef AH_SETTINGSWRAPPER_HPP +#define AH_SETTINGSWRAPPER_HPP + +#include "NamespaceSettings.hpp" + +// ---- User Settings ---- // +// ======================= // +#include "Settings.hpp" + +AH_DIAGNOSTIC_WERROR() // Enable errors on warnings + +#define AH_IS_EMPTY_HELPER(x) x##1 +#define AH_IS_EMPTY(x) AH_IS_EMPTY_HELPER(x) == 1 + +#if AH_IS_EMPTY(DEBUG_OUT) +#undef DEBUG_OUT +#endif + +#ifndef ARDUINO +#ifdef DEBUG_OUT +#undef DEBUG_OUT +#ifndef NO_DEBUG_PRINTS +#define DEBUG_OUT std::cout +#endif +#endif +#endif + +AH_DIAGNOSTIC_POP() + +// ------- Debug ------- // +// ===================== // +#include + +#endif // AH_SETTINGSWRAPPER_HPP diff --git a/AH/Settings/Warnings.hpp b/AH/Settings/Warnings.hpp new file mode 100644 index 0000000..a2c3f10 --- /dev/null +++ b/AH/Settings/Warnings.hpp @@ -0,0 +1,53 @@ +#pragma once + +#if defined(__GNUC__) && !defined(__clang__) + +#if __GNUC__ >= 11 + +#define AH_DIAGNOSTIC_WERROR() \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wall\"") \ + _Pragma("GCC diagnostic error \"-Wextra\"") \ + _Pragma("GCC diagnostic ignored \"-Wc++0x-compat\"") \ + _Pragma("GCC diagnostic ignored \"-Wc++11-compat\"") +#define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") +#define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ + _Pragma("GCC diagnostic ignored \"-Wextra\"") \ + _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") _Pragma( \ + "GCC diagnostic ignored \"-Wunused-parameter\"") \ + _Pragma("GCC diagnostic warning \"-Wcast-function-type\"") \ + _Pragma("GCC diagnostic warning \"-Wdeprecated-copy\"") +/* For the last two: see https://github.com/PaulStoffregen/cores/issues/660 */ + +#elif __GNUC__ >= 5 + +#define AH_DIAGNOSTIC_WERROR() \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic error \"-Wall\"") \ + _Pragma("GCC diagnostic error \"-Wextra\"") \ + _Pragma("GCC diagnostic ignored \"-Wc++0x-compat\"") +#define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") +#define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ + _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wall\"") \ + _Pragma("GCC diagnostic ignored \"-Wextra\"") \ + _Pragma("GCC diagnostic ignored \"-Wsuggest-override\"") \ + _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") + +#else // __GNUC__ < 5 + +#define AH_DIAGNOSTIC_WERROR() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wattributes\"") +#define AH_DIAGNOSTIC_POP() _Pragma("GCC diagnostic pop") +#define AH_DIAGNOSTIC_EXTERNAL_HEADER() \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wunused-parameter\"") + +#endif + +#else + +#define AH_DIAGNOSTIC_WERROR() +#define AH_DIAGNOSTIC_POP() +#define AH_DIAGNOSTIC_EXTERNAL_HEADER() + +#endif \ No newline at end of file diff --git a/AH/Timing/MillisMicrosTimer.hpp b/AH/Timing/MillisMicrosTimer.hpp new file mode 100644 index 0000000..cfbb251 --- /dev/null +++ b/AH/Timing/MillisMicrosTimer.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include + +BEGIN_AH_NAMESPACE + +/// @addtogroup AH_Timing +/// @{ + +/// A function type that returns a time value. +using timefunction = unsigned long (*)(); + +/** + * @brief A class for easily managing timed events. A wrapper for "Blink + * Without Delay". + * + * @tparam time + * The time function to use. + */ +template +class Timer { + public: + /** + * @brief Constructor. + * @param interval + * The interval between two events. + */ + Timer(unsigned long interval) : interval(interval) { +#ifdef ARDUINO + begin(); +#endif + } + /// Initialize or reset the timer. The timer will fire immediately. + void begin() { previous = time() - interval; } + /// Initialize or reset the timer. The timer will fire after one period. + void beginNextPeriod() { previous = time(); } + /// Update the timer and return true if the event should fire. + explicit operator bool() { + auto now = time(); + if (now - previous >= interval) { + previous += interval; + return true; + } + return false; + } + + /// Get the interval of the timer. + unsigned long getInterval() const { return interval; } + /// Set the interval of the timer. + void setInterval(unsigned long interval) { this->interval = interval; } + + private: + unsigned long interval; + unsigned long previous = 0; +}; + +/// @} + +END_AH_NAMESPACE diff --git a/AH/Types/Frequency.hpp b/AH/Types/Frequency.hpp new file mode 100644 index 0000000..ab0e7a9 --- /dev/null +++ b/AH/Types/Frequency.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +BEGIN_AH_NAMESPACE + +/// Type-safe class for frequency values. +class Frequency { + public: + explicit constexpr Frequency(unsigned long hertz) : hertz(hertz) {} + constexpr operator unsigned long() const { return hertz; } + + private: + unsigned long hertz; +}; +constexpr Frequency operator"" _Hz(unsigned long long hz) { + return Frequency{(unsigned long)hz}; +} +constexpr Frequency operator"" _kHz(long double khz) { + return Frequency{(unsigned long)(khz * 1E3l)}; +} +constexpr Frequency operator"" _kHz(unsigned long long khz) { + return Frequency{(unsigned long)(khz * 1E3)}; +} +constexpr Frequency operator"" _MHz(long double mhz) { + return Frequency{(unsigned long)(mhz * 1E6l)}; +} +constexpr Frequency operator"" _MHz(unsigned long long mhz) { + return Frequency{(unsigned long)(mhz * 1E6)}; +} + +END_AH_NAMESPACE diff --git a/Banks/Bank.hpp b/Banks/Bank.hpp new file mode 100644 index 0000000..da407f1 --- /dev/null +++ b/Banks/Bank.hpp @@ -0,0 +1,169 @@ +/* ✔ */ + +#pragma once + +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class BankableMIDIInput; + +/// A class for changing the address of BankableMIDIOutput%s. +class OutputBank { + public: + /// Create a new OutputBank object. + /// + /// @param tracksPerBank + /// The number of addresses/tracks to skip for each bank setting. + /// Must be strictly positive. + /// @param initialSelection + /// The initial bank setting. + /// @param selectionOffset + /// The offset added to the bank setting before computing the + /// actual address offset. + OutputBank(uint8_t tracksPerBank = 1, setting_t initialSelection = 0, + int8_t selectionOffset = 0) + : tracksPerBank(tracksPerBank), bankSetting(initialSelection), + selectionOffset(selectionOffset) { + if (tracksPerBank == 0) + FATAL_ERROR(F("A Bank must have a non-zero number of tracks."), + 0x4573); + } + + /// Select the given bank setting. + /// + /// @param setting + /// The new setting to select (zero-based). + void select(setting_t setting) { bankSetting = setting; } + + /// Get the current bank setting (zero-based). + setting_t getSelection() const { return bankSetting; } + /// Get the offset of the bank setting. + int8_t getSelectionOffset() const { return selectionOffset; } + + /// Get the number of tracks per bank. + /// This is the number of addresses/tracks to skip for each bank setting. + uint8_t getTracksPerBank() const { return tracksPerBank; } + + /// The same as @ref getOffset, but for a given setting. + int8_t getOffsetOfSetting(setting_t s) const { + return (s + getSelectionOffset()) * getTracksPerBank(); + } + /// Get the address offset (number of banks times the index of the selected + /// bank after applying the offset) + int8_t getOffset() const { return getOffsetOfSetting(getSelection()); } + + private: + uint8_t tracksPerBank; + setting_t bankSetting; + int8_t selectionOffset; +}; + +/// Callback class for Bankable objects that need to be notified when the +/// active setting of their Bank changes. +class BankSettingChangeCallback + : public DoublyLinkable { + template + friend class Bank; + + private: + /// A function to be executed each time the bank setting changes. + /// Think of an LED that indicates whether a track is muted or not. If this + /// LED is bankable, let's say with 4 tracks per bank, 2 banks, and a base + /// address of 3, then this LED object keeps the state of tracks 3 and 7. + /// When the bank setting is 0, the LED displays the state of track 3, when + /// the bank setting is 1, the LED displays the state of track 7. + /// To know when to update the LED, this callback is used. + virtual void onBankSettingChange() {} +}; + +/// A class that groups @ref BankableMIDIOutputElements and +/// @ref BankableMIDIInputElements, and allows the user to change the addresses +/// of these elements. +/// +/// @see FAQ: @ref faq-change-address-runtime +/// @see FAQ: @ref faq-banks +/// +/// @tparam NumBanks +/// The number of banks. +template +class Bank : public Selectable, public OutputBank { + + public: + /// Construct a new Bank object. + /// + /// @param tracksPerBank + /// The number of addresses/tracks to skip for each bank setting. + /// Must be strictly positive. + /// @param initialSelection + /// The initial bank setting. + /// @param selectionOffset + /// The offset added to the bank setting before computing the + /// actual address offset. + Bank(uint8_t tracksPerBank = 1, setting_t initialSelection = 0, + int8_t selectionOffset = 0) + : Selectable(initialSelection), + OutputBank(tracksPerBank, initialSelection, selectionOffset) {} + + /// Select the given bank setting. + /// + /// All Bankable MIDI Input elements that were added to this bank will be + /// updated. + /// + /// @param bankSetting + /// The new setting to select. + void select(setting_t bankSetting) override; + + /// Get the number of banks. + constexpr static uint8_t getNumberOfBanks() { return NumBanks; } + + public: + /// Add a Bankable MIDI Input Element to the bank. + /// + /// @param bankable + /// The MIDI Input Element to be added. + void add(BankSettingChangeCallback *bankable); + + /// Remove a Bankable MIDI Input Element from the bank. + /// + /// @param bankable + /// The MIDI Input Element to be removed. + void remove(BankSettingChangeCallback *bankable); + + private: + /// A linked list of all Bankable MIDI Input Elements that have been added + /// to this bank, and that should be updated when the bank setting changes. + /// The list is updated automatically when Bankable MIDI Input Elements are + /// created or destroyed. + DoublyLinkedList inputBankables; +}; + +END_CS_NAMESPACE + +// ---------------------------- Implementations ----------------------------- // + +BEGIN_CS_NAMESPACE + +template +void Bank::add(BankSettingChangeCallback *bankable) { + inputBankables.append(bankable); +} + +template +void Bank::remove(BankSettingChangeCallback *bankable) { + inputBankables.remove(bankable); +} + +template +void Bank::select(setting_t bankSetting) { + bankSetting = this->validateSetting(bankSetting); + OutputBank::select(bankSetting); + for (BankSettingChangeCallback &e : inputBankables) + e.onBankSettingChange(); +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Banks/BankAddresses.hpp b/Banks/BankAddresses.hpp new file mode 100644 index 0000000..f2721af --- /dev/null +++ b/Banks/BankAddresses.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include "BankableAddresses.hpp" + +BEGIN_CS_NAMESPACE + +namespace Bankable { + +class SingleAddress : public OutputBankableMIDIAddress { + public: + SingleAddress(BaseOutputBankConfig config, MIDIAddress address) + : OutputBankableMIDIAddress(config), address(address) {} + + MIDIAddress getBaseAddress() const { return address; } + + MIDIAddress getActiveAddress() const { + return getBaseAddress() + getAddressOffset(); + } + + private: + MIDIAddress address; +}; + +template +class SingleAddressMultipleBanks { + public: + SingleAddressMultipleBanks(const Array &banks, + MIDIAddress address) + : banks(banks), address(address) {} + + MIDIAddress getBaseAddress() const { return address; } + + MIDIAddress getActiveAddress() const { + auto address = getBaseAddress(); + for (const OutputBankableMIDIAddress &bank : banks) + address += bank.getAddressOffset(); + return address; + } + + void lock() { + for (OutputBankableMIDIAddress &bank : banks) + bank.lock(); + } + + void unlock() { + for (OutputBankableMIDIAddress &bank : banks) + bank.unlock(); + } + + private: + Array banks; + MIDIAddress address; +}; + +class DualAddresses : public OutputBankableMIDIAddress { + public: + DualAddresses(BaseOutputBankConfig config, + const Array &addresses) + : OutputBankableMIDIAddress(config), first(addresses[0]), + second(addresses[1]) {} + + MIDIAddress getFirstBaseAddress() const { return first; } + MIDIAddress getSecondBaseAddress() const { return second; } + + MIDIAddress getFirstActiveAddress() const { + return getFirstBaseAddress() + getAddressOffset(); + } + MIDIAddress getSecondActiveAddress() const { + return getSecondBaseAddress() + getAddressOffset(); + } + + private: + MIDIAddress first, second; +}; + +template +class MatrixAddress : public OutputBankableMIDIAddress { + public: + MatrixAddress(BaseOutputBankConfig config, + const AddressMatrix &addresses, + MIDIChannelCable channelCN) + : OutputBankableMIDIAddress(config), addresses(addresses), + channelCN(channelCN) {} + + uint8_t getBaseAddress(uint8_t row, uint8_t col) const { + return addresses[row][col]; + } + + MIDIAddress getActiveAddress(uint8_t row, uint8_t col) const { + MIDIAddress address = {getBaseAddress(row, col), channelCN}; + return address + getAddressOffset(); + } + + private: + AddressMatrix addresses; + MIDIChannelCable channelCN; +}; + +namespace ManyAddresses { + +/** + * @tparam NumBanks + * The number of bank settings the bank has. + */ +template +class ManyAddresses : public ManyAddresses_Base { + public: + /** + * @brief Constructor. + * + * @param bank + * The bank to add this element to. + * @param addresses + * The list of alternative addresses. + */ + ManyAddresses(const Bank &bank, + const Array &addresses) + : ManyAddresses_Base(bank), addresses(addresses) {} + + MIDIAddress getActiveAddress() const { return addresses[getSelection()]; } + + private: + Array addresses; +}; + +/** + * @tparam NumBanks + * The number of bank settings the bank has. + */ +template +class DualManyAddresses : public ManyAddresses_Base { + public: + DualManyAddresses(const Bank &bank, + const Array2D &addresses) + : ManyAddresses_Base(bank), first {addresses[0]}, + second {addresses[1]} {} + + MIDIAddress getFirstActiveAddress() const { return first[getSelection()]; } + MIDIAddress getSecondActiveAddress() const { + return second[getSelection()]; + } + + private: + Array first, second; +}; + +template +class ManyMatrixAddresses : public ManyAddresses_Base { + public: + ManyMatrixAddresses( + const Bank &bank, + const Array, NumBanks> &addresses, + const Array &channelCNs) + : ManyAddresses_Base(bank), addresses(addresses), + channelCNs(channelCNs) {} + + MIDIAddress getActiveAddress(uint8_t row, uint8_t col) const { + return {addresses[getSelection()][row][col], + channelCNs[getSelection()]}; + } + + private: + Array, NumBanks> addresses; + Array channelCNs; +}; + +} // namespace ManyAddresses +} // namespace Bankable + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Banks/BankConfig.hpp b/Banks/BankConfig.hpp new file mode 100644 index 0000000..f154de3 --- /dev/null +++ b/Banks/BankConfig.hpp @@ -0,0 +1,84 @@ +/* ✔ */ + +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief An enumeration of the different bank types. + */ +enum BankType { + /** + * @brief Change the offset of the address (i.e. Controller number or + * Note number) of the element. + */ + ChangeAddress = 0, + CHANGE_ADDRESS CS_DEPREC("Use ChangeAddress instead") = ChangeAddress, + /** + * @brief Change the offset of the channel number of the element. + */ + ChangeChannel = 1, + CHANGE_CHANNEL CS_DEPREC("Use ChangeChannel instead") = ChangeChannel, + /** + * @brief Change the offset of the cable number of the element. + */ + ChangeCable = 2, + CHANGE_CABLENB CS_DEPREC("Use ChangeCable instead") = ChangeCable, +}; + +template +class Bank; +class OutputBank; + +template +struct OutputBankConfig; + +/** + * @brief A struct for selecting the bank of BankableMIDIInput%s and the + * bank type. + */ +template +class BaseBankConfig { + protected: + BaseBankConfig(Bank &bank, BankType type) : bank(bank), type(type) {} + + public: + Bank &bank; + const BankType type; +}; + +/// @copydoc BaseBankConfig +template +struct BankConfig : BaseBankConfig { + BankConfig(Bank &bank, BankType type = DefaultBankType) + : BaseBankConfig(bank, type) {} +}; + +/** + * @brief A struct for selecting the bank of BankableMIDIOutput%s and the + * bank type. + */ +class BaseOutputBankConfig { + protected: + BaseOutputBankConfig(OutputBank &bank, BankType type) + : bank(bank), type(type) {} + + public: + template + BaseOutputBankConfig(BaseBankConfig config) + : bank(config.bank), type(config.type) {} + + OutputBank &bank; + const BankType type; +}; + +/// @copydoc BaseOutputBankConfig +template +struct OutputBankConfig : BaseOutputBankConfig { + OutputBankConfig(OutputBank &bank, BankType type = DefaultBankType) + : BaseOutputBankConfig(bank, type) {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Banks/BankableAddresses.hpp b/Banks/BankableAddresses.hpp new file mode 100644 index 0000000..c90364f --- /dev/null +++ b/Banks/BankableAddresses.hpp @@ -0,0 +1,165 @@ +/* ✔ */ + +#pragma once + +#include "Bank.hpp" +#include "BankConfig.hpp" +#include + +BEGIN_CS_NAMESPACE + +/// Class for keeping track of the active bank, and allows locking of the +/// bank setting. +/// +/// @see @ref OutputBankableMIDIAddress +class OutputBankableMIDIAddress_Base { + protected: + /** + * @brief Constructor. + * + * @param bank + * The bank to add this element to. + */ + OutputBankableMIDIAddress_Base(const OutputBank &bank) : bank(bank) {} + + public: + /** + * @brief Get the actual bank setting (no matter whether the element is + * locked or not). + */ + setting_t getRawBankSetting() const { return bank.getSelection(); } + + /** + * @brief Get the bank setting. + * + * If the element is locked, the bank setting from the moment it was locked + * is returned. + */ + setting_t getSelection() const { + return lockedSetting == Unlocked ? getRawBankSetting() : lockedSetting; + } + + /** + * @brief Lock the bank setting. + * + * As long as it's locked, `getSelection` will return the current setting, + * independent from the actual bank setting. + */ + void lock() { + if (lockedSetting == Unlocked) + lockedSetting = getRawBankSetting(); + } + + /** + * @brief Unlock the bank setting. + * + * After unlocking, @ref getSelection will return the actual bank setting + * again. + */ + void unlock() { lockedSetting = Unlocked; } + + protected: + const OutputBank &bank; + + private: + constexpr static setting_t Unlocked = NoSetting; + setting_t lockedSetting = Unlocked; +}; + +/** + * @brief A base class for all MIDIOutputElement%s that can be banked. + * + * @note These elements don't have to be updated when the bank setting is + * changed, because they poll the bank setting each time they send a + * MIDI event. + * They are not added to the bank, they just keep a reference to the + * bank they're a part of. + * + * @note To prevent 'sticky' notes (i.e. a button is pressed, a note on is + * sent, the bank is changed, the button is released, and the note off + * is sent to a different address, causing the first note to keep on + * playing indefinitely), there must be a way to lock the bank setting + * while a note is playing. Then when it is no longer playing, the + * bank setting is unlocked. + */ +class OutputBankableMIDIAddress : public OutputBankableMIDIAddress_Base { + public: + /** + * @brief Create a new OutputBankableMIDIAddress object. + * + * @param bank + * The bank to add this element to. + * @param type + * What address type to change (address, channel or cable number). + */ + OutputBankableMIDIAddress(const OutputBank &bank, BankType type) + : OutputBankableMIDIAddress_Base(bank), type(type) {} + + /** + * @brief Create a new OutputBankableMIDIAddress object. + * + * @param config + * The bank and address type to change. + * + * @see OutputBankableMIDIAddress::OutputBankableMIDIAddress(Bank &, BankType) + */ + OutputBankableMIDIAddress(BaseOutputBankConfig config) + : OutputBankableMIDIAddress(config.bank, config.type) {} + + /** + * @brief Get the offset relative to the base address. + */ + RelativeMIDIAddress getAddressOffset(setting_t bankindex) const { + int8_t offset = bank.getOffsetOfSetting(bankindex); + switch (type) { + case ChangeAddress: return {offset, 0, 0}; + case ChangeChannel: return {0, offset, 0}; + case ChangeCable: return {0, 0, offset}; + default: return {}; + } + } + /** + * @brief Get the offset relative to the base address for the active bank. + */ + RelativeMIDIAddress getAddressOffset() const { + return getAddressOffset(getSelection()); + } + + private: + const BankType type; +}; + +/** + * @brief A base class for all MIDIOutputElement%s that can have one of many + * addresses. + * + * The bank setting determines the address that's being used. + * + * @note To prevent 'sticky' notes (i.e. a button is pressed, a note on is + * sent, the bank is changed, the button is released, and the note off + * is sent to a different address, causing the first note to keep on + * playing indefinitely), there must be a way to lock the bank setting + * while a note is playing. Then when it is no longer playing, the + * bank setting is unlocked. + * + * @invariant `getSelection` and `getRawBankSetting` always return a number in + * the half-open interval + * @f$ \left[0, \mathrm{bank.getNumberOfBanks()}\right) \cap + * \mathbb{N} @f$. + */ +class ManyAddresses_Base : public OutputBankableMIDIAddress_Base { + public: + /** + * @brief Constructor. + * + * @param bank + * The bank to add this element to. + * @tparam NumBanks + * The number of bank settings @p bank has. + */ + template + ManyAddresses_Base(const Bank &bank) + : OutputBankableMIDIAddress_Base(bank) {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Banks/Transposer.hpp b/Banks/Transposer.hpp new file mode 100644 index 0000000..81788a1 --- /dev/null +++ b/Banks/Transposer.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/// Class for transposing the address of @ref NoteButton and other MIDI elements. +template +class Transposer : public Bank { + public: + Transposer(int8_t step = 1) + : Bank(step, -MinTransposition, MinTransposition) { + static_assert(MinTransposition <= 0, + "Error: the minimum transposition must be negative"); + static_assert(MaxTransposition >= 0, + "Error: the maximum transposition must be positive"); + } + + /// Set the transposition. + /// @param tp + /// The new transposition in the range + /// [ @p MinTransposition, @p MaxTransposition ]. + /// @note The @ref Bank::select() method expects a zero-based argument, + /// which is cumbersome if the minimum transposition is nonzero. + void setTransposition(int8_t tp) { this->select(tp - MinTransposition); } + + /// Get the transposition. + int8_t getTransposition() const { + return this->getSelection() + MinTransposition; + } + + /// Get the transposition as a number of semitones. + int8_t getTranspositionSemitones() const { return this->getOffset(); } + + static constexpr setting_t N = MaxTransposition - MinTransposition + 1; + static constexpr setting_t NumBanks = N; +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..c2cb8ba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.13) + +add_library(cs_midi STATIC + AH/Debug/Debug.cpp + AH/Error/Exit.cpp + AH/PrintStream/PrintStream.cpp + AH/STL/vector.cpp + AH/Hardware/ExtendedInputOutput/ExtendedInputOutput.cpp + AH/Hardware/ExtendedInputOutput/ExtendedIOElement.cpp + AH/Hardware/Button.cpp + AH/Hardware/IncrementButton.cpp + AH/Hardware/IncrementDecrementButtons.cpp + Submodules/Encoder/AHEncoder.cpp + Control_Surface/Control_Surface_Class.cpp + MIDI_Senders/RelativeCCSender.cpp + Def/Cable.cpp + Def/Channel.cpp + Def/MIDIAddress.cpp + MIDI_Parsers/SerialMIDI_Parser.cpp + MIDI_Parsers/SysExBuffer.cpp + MIDI_Parsers/MIDI_MessageTypes.cpp + MIDI_Interfaces/MIDI_Interface.cpp + MIDI_Interfaces/MIDI_Pipes.cpp + MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.cpp + MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp + MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp +) + +target_include_directories(cs_midi PUBLIC + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(cs_midi PUBLIC + MIDI_NUM_CABLES=1 +) + +# pico_stdlib: needed by the library for millis/micros/gpio +# pico_btstack_ble: BTstack BLE headers + objects (linked PRIVATE to avoid +# propagating the full btstack source build to consumers) +# hardware_sync: save_and_disable_interrupts used by BTstackBackgroundBackend +target_link_libraries(cs_midi + PUBLIC pico_stdlib hardware_sync hardware_adc + PRIVATE pico_btstack_ble pico_btstack_cyw43 + pico_cyw43_arch_lwip_threadsafe_background +) + +target_compile_features(cs_midi PUBLIC cxx_std_17) diff --git a/Control_Surface/Control_Surface_Class.cpp b/Control_Surface/Control_Surface_Class.cpp new file mode 100644 index 0000000..276bbdc --- /dev/null +++ b/Control_Surface/Control_Surface_Class.cpp @@ -0,0 +1,199 @@ +#include "Control_Surface_Class.hpp" +#include +#include +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +using AH::ExtendedIOElement; + +Control_Surface_ &Control_Surface_::getInstance() { + static Control_Surface_ instance; + return instance; +} + +void Control_Surface_::begin() { + connectDefaultMIDI_Interface(); + + FilteredAnalog<>::setupADC(); + ExtendedIOElement::beginAll(); + Updatable::beginAll(); + MIDIOutputOnly::beginAll(); + MIDIInputElementNote::beginAll(); + MIDIInputElementKP::beginAll(); + MIDIInputElementCC::beginAll(); + MIDIInputElementPC::beginAll(); + MIDIInputElementCP::beginAll(); + MIDIInputElementPB::beginAll(); + MIDIInputElementSysEx::beginAll(); + Updatable<>::beginAll(); +} + +bool Control_Surface_::connectDefaultMIDI_Interface() { +#if !DISABLE_PIPES + if (hasSinkPipe() || hasSourcePipe()) + return false; + auto def = MIDI_Interface::getDefault(); + if (def == nullptr) { + FATAL_ERROR(F("No default MIDI Interface"), 0xF123); + return false; + } + *this << inpipe << *def; + *this >> outpipe >> *def; + return true; +#else + return MIDI_Interface::getDefault(); +#endif +} + +void Control_Surface_::disconnectMIDI_Interfaces() { +#if !DISABLE_PIPES + disconnectSinkPipes(); + disconnectSourcePipes(); +#endif +} + +void Control_Surface_::loop() { + ExtendedIOElement::updateAllBufferedInputs(); + Updatable<>::updateAll(); + updateMidiInput(); + updateInputs(); + ExtendedIOElement::updateAllBufferedOutputs(); +} + +void Control_Surface_::updateMidiInput() { +#if !DISABLE_PIPES + Updatable::updateAll(); +#else + if (auto iface = MIDI_Interface::getDefault()) { + MIDIReadEvent event = iface->read(); + while (event != MIDIReadEvent::NO_MESSAGE) { + MIDI_Interface::dispatchIncoming(iface, event); + switch (event) { + case MIDIReadEvent::CHANNEL_MESSAGE: + sinkMIDIfromPipe(iface->getChannelMessage()); + break; + case MIDIReadEvent::SYSEX_CHUNK: + case MIDIReadEvent::SYSEX_MESSAGE: + sinkMIDIfromPipe(iface->getSysExMessage()); + break; + case MIDIReadEvent::SYSCOMMON_MESSAGE: + sinkMIDIfromPipe(iface->getSysCommonMessage()); + break; + case MIDIReadEvent::REALTIME_MESSAGE: + sinkMIDIfromPipe(iface->getRealTimeMessage()); + break; + case MIDIReadEvent::NO_MESSAGE: break; + default: break; + } + event = iface->read(); + } + } +#endif +} + +#if !DISABLE_PIPES +void Control_Surface_::sendChannelMessageImpl(ChannelMessage msg) { + this->sourceMIDItoPipe(msg); +} +void Control_Surface_::sendSysExImpl(SysExMessage msg) { + this->sourceMIDItoPipe(msg); +} +void Control_Surface_::sendSysCommonImpl(SysCommonMessage msg) { + this->sourceMIDItoPipe(msg); +} +void Control_Surface_::sendRealTimeImpl(RealTimeMessage msg) { + this->sourceMIDItoPipe(msg); +} +#else +void Control_Surface_::sendChannelMessageImpl(ChannelMessage msg) { + if (auto def = MIDI_Interface::getDefault()) + def->send(msg); +} +void Control_Surface_::sendSysExImpl(SysExMessage msg) { + if (auto def = MIDI_Interface::getDefault()) + def->send(msg); +} +void Control_Surface_::sendSysCommonImpl(SysCommonMessage msg) { + if (auto def = MIDI_Interface::getDefault()) + def->send(msg); +} +void Control_Surface_::sendRealTimeImpl(RealTimeMessage msg) { + if (auto def = MIDI_Interface::getDefault()) + def->send(msg); +} +#endif + +void Control_Surface_::sinkMIDIfromPipe(ChannelMessage midimsg) { + if (channelMessageCallback && channelMessageCallback(midimsg)) + return; + + if (midimsg.getMessageType() == MIDIMessageType::ControlChange && + midimsg.getData1() == MIDI_CC::Reset_All_Controllers) { + MIDIInputElementCC::resetAll(); + MIDIInputElementCP::resetAll(); + } else if (midimsg.getMessageType() == MIDIMessageType::ControlChange && + midimsg.getData1() == MIDI_CC::All_Notes_Off) { + MIDIInputElementNote::resetAll(); + } else { + switch (midimsg.getMessageType()) { + case MIDIMessageType::None: break; + case MIDIMessageType::NoteOff: + case MIDIMessageType::NoteOn: + MIDIInputElementNote::updateAllWith(midimsg); + break; + case MIDIMessageType::KeyPressure: + MIDIInputElementKP::updateAllWith(midimsg); + break; + case MIDIMessageType::ControlChange: + MIDIInputElementCC::updateAllWith(midimsg); + break; + case MIDIMessageType::ProgramChange: + MIDIInputElementPC::updateAllWith(midimsg); + break; + case MIDIMessageType::ChannelPressure: + MIDIInputElementCP::updateAllWith(midimsg); + break; + case MIDIMessageType::PitchBend: + MIDIInputElementPB::updateAllWith(midimsg); + break; + default: break; + } + } +} + +void Control_Surface_::sinkMIDIfromPipe(SysExMessage msg) { + if (sysExMessageCallback && sysExMessageCallback(msg)) + return; + MIDIInputElementSysEx::updateAllWith(msg); +} + +void Control_Surface_::sinkMIDIfromPipe(SysCommonMessage msg) { + if (sysCommonMessageCallback && sysCommonMessageCallback(msg)) + return; +} + +void Control_Surface_::sinkMIDIfromPipe(RealTimeMessage rtMessage) { + if (realTimeMessageCallback && realTimeMessageCallback(rtMessage)) + return; +} + +void Control_Surface_::updateInputs() { + MIDIInputElementNote::updateAll(); + MIDIInputElementKP::updateAll(); + MIDIInputElementCC::updateAll(); + MIDIInputElementPC::updateAll(); + MIDIInputElementCP::updateAll(); + MIDIInputElementPB::updateAll(); + MIDIInputElementSysEx::updateAll(); +} + +#if CS_TRUE_CONTROL_SURFACE_INSTANCE +Control_Surface_ &Control_Surface = Control_Surface_::getInstance(); +#endif + +END_CS_NAMESPACE diff --git a/Control_Surface/Control_Surface_Class.hpp b/Control_Surface/Control_Surface_Class.hpp new file mode 100644 index 0000000..92f3b26 --- /dev/null +++ b/Control_Surface/Control_Surface_Class.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +using AH::FilteredAnalog; +using AH::NormalUpdatable; +using AH::Timer; +using AH::Updatable; + +class Control_Surface_ : public MIDI_Sender, + public TrueMIDI_SinkSource { + + friend class MIDI_Sender; + + public: + Control_Surface_(Control_Surface_ const &) = delete; + Control_Surface_ &operator=(Control_Surface_ const &) = delete; + static Control_Surface_ &getInstance(); + + private: + Control_Surface_() = default; + + public: + void begin(); + void loop(); + + bool connectDefaultMIDI_Interface(); + void disconnectMIDI_Interfaces(); + + void updateMidiInput(); + void updateInputs(); + + private: + void sendChannelMessageImpl(ChannelMessage); + void sendSysCommonImpl(SysCommonMessage); + void sendSysExImpl(SysExMessage); + void sendRealTimeImpl(RealTimeMessage); + void sendNowImpl() {} + + private: +#if !DISABLE_PIPES + void sinkMIDIfromPipe(ChannelMessage msg) override; + void sinkMIDIfromPipe(SysExMessage msg) override; + void sinkMIDIfromPipe(SysCommonMessage msg) override; + void sinkMIDIfromPipe(RealTimeMessage msg) override; +#else + void sinkMIDIfromPipe(ChannelMessage msg); + void sinkMIDIfromPipe(SysExMessage msg); + void sinkMIDIfromPipe(SysCommonMessage msg); + void sinkMIDIfromPipe(RealTimeMessage msg); +#endif + + public: + using ChannelMessageCallback = bool (*)(ChannelMessage); + using SysExMessageCallback = bool (*)(SysExMessage); + using SysCommonMessageCallback = bool (*)(SysCommonMessage); + using RealTimeMessageCallback = bool (*)(RealTimeMessage); + + void + setMIDIInputCallbacks(ChannelMessageCallback channelMessageCallback, + SysExMessageCallback sysExMessageCallback, + SysCommonMessageCallback sysCommonMessageCallback, + RealTimeMessageCallback realTimeMessageCallback) { + this->channelMessageCallback = channelMessageCallback; + this->sysExMessageCallback = sysExMessageCallback; + this->sysCommonMessageCallback = sysCommonMessageCallback; + this->realTimeMessageCallback = realTimeMessageCallback; + } + + private: + ChannelMessageCallback channelMessageCallback = nullptr; + SysExMessageCallback sysExMessageCallback = nullptr; + SysCommonMessageCallback sysCommonMessageCallback = nullptr; + RealTimeMessageCallback realTimeMessageCallback = nullptr; +#if !DISABLE_PIPES + MIDI_Pipe inpipe, outpipe; +#endif +}; + +#if CS_TRUE_CONTROL_SURFACE_INSTANCE +extern Control_Surface_ &Control_Surface; +#else +#define Control_Surface (Control_Surface_::getInstance()) +#endif + +END_CS_NAMESPACE diff --git a/Def/Cable.cpp b/Def/Cable.cpp new file mode 100644 index 0000000..6e84d43 --- /dev/null +++ b/Def/Cable.cpp @@ -0,0 +1,8 @@ +#include "Cable.hpp" +#include + +BEGIN_CS_NAMESPACE + +Print &operator<<(Print &os, Cable) { return os; } + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/Cable.hpp b/Def/Cable.hpp new file mode 100644 index 0000000..ee0bdb9 --- /dev/null +++ b/Def/Cable.hpp @@ -0,0 +1,154 @@ +/* ✔ */ + +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +/** + * A type-safe class for MIDI USB Cable numbers. + */ +class Cable { + public: + /** + * @brief Create a MIDI Cable object. + * + * @param zeroBasedCable + * The zero-based cable (0 is the first cable). + */ + explicit constexpr Cable(uint8_t zeroBasedCable) + : zeroBasedCable(zeroBasedCable) {} + + /** + * @brief Get the cable as an integer. + * + * @return The zero-based cable (0 is the first cable). + */ + constexpr uint8_t getRaw() const { return zeroBasedCable; } + + /** + * @brief Get the cable as an integer. + * + * @return The one-based cable (1 is the first cable). + */ + constexpr uint8_t getOneBased() const { return zeroBasedCable + 1; } + + /** + * @brief Create a cable. + * + * @param oneBasedCable + * The cable number (1 is the first cable). + */ + static constexpr Cable createCable(uint8_t oneBasedCable) { + return Cable {static_cast(oneBasedCable - 1)}; + } + + /** + * @brief Check if two cables are the same. + * + * @param rhs + * The other cable to compare this cable to. + */ + constexpr bool operator==(const Cable &rhs) const { + return this->zeroBasedCable == rhs.zeroBasedCable; + } + + /** + * @brief Check if two cables are the different. + * + * @param rhs + * The other cable to compare this cable to. + */ + constexpr bool operator!=(const Cable &rhs) const { + return this->zeroBasedCable != rhs.zeroBasedCable; + } + + /** + * @brief Add an offset. + * + * @param rhs + * The offset to add to this cable. + */ + Cable &operator+=(uint8_t rhs) { + this->zeroBasedCable += rhs; + return *this; + } + + /** + * @brief Add an offset to a cable. + * + * @param rhs + * The offset to add to the cable. + */ + Cable operator+(uint8_t rhs) const { + Cable copy = *this; + copy += rhs; + return copy; + } + + /** + * @brief Subtract an offset. + * + * @param rhs + * The offset to subtract from this cable. + */ + Cable &operator-=(uint8_t rhs) { + this->zeroBasedCable -= rhs; + return *this; + } + + /** + * @brief Subtract an offset from a cable. + * + * @param rhs + * The offset to subtract from the cable. + */ + Cable operator-(uint8_t rhs) const { + Cable copy = *this; + copy -= rhs; + return copy; + } + + private: + uint8_t zeroBasedCable : 4; +}; + +constexpr Cable Cable_1 = Cable::createCable(1); +constexpr Cable Cable_2 = Cable::createCable(2); +constexpr Cable Cable_3 = Cable::createCable(3); +constexpr Cable Cable_4 = Cable::createCable(4); +constexpr Cable Cable_5 = Cable::createCable(5); +constexpr Cable Cable_6 = Cable::createCable(6); +constexpr Cable Cable_7 = Cable::createCable(7); +constexpr Cable Cable_8 = Cable::createCable(8); +constexpr Cable Cable_9 = Cable::createCable(9); +constexpr Cable Cable_10 = Cable::createCable(10); +constexpr Cable Cable_11 = Cable::createCable(11); +constexpr Cable Cable_12 = Cable::createCable(12); +constexpr Cable Cable_13 = Cable::createCable(13); +constexpr Cable Cable_14 = Cable::createCable(14); +constexpr Cable Cable_15 = Cable::createCable(15); +constexpr Cable Cable_16 = Cable::createCable(16); + +constexpr Cable CABLE_1 CS_DEPREC("Use Cable_1 instead") = Cable_1; +constexpr Cable CABLE_2 CS_DEPREC("Use Cable_2 instead") = Cable_2; +constexpr Cable CABLE_3 CS_DEPREC("Use Cable_3 instead") = Cable_3; +constexpr Cable CABLE_4 CS_DEPREC("Use Cable_4 instead") = Cable_4; +constexpr Cable CABLE_5 CS_DEPREC("Use Cable_5 instead") = Cable_5; +constexpr Cable CABLE_6 CS_DEPREC("Use Cable_6 instead") = Cable_6; +constexpr Cable CABLE_7 CS_DEPREC("Use Cable_7 instead") = Cable_7; +constexpr Cable CABLE_8 CS_DEPREC("Use Cable_8 instead") = Cable_8; +constexpr Cable CABLE_9 CS_DEPREC("Use Cable_9 instead") = Cable_9; +constexpr Cable CABLE_10 CS_DEPREC("Use Cable_10 instead") = Cable_10; +constexpr Cable CABLE_11 CS_DEPREC("Use Cable_11 instead") = Cable_11; +constexpr Cable CABLE_12 CS_DEPREC("Use Cable_12 instead") = Cable_12; +constexpr Cable CABLE_13 CS_DEPREC("Use Cable_13 instead") = Cable_13; +constexpr Cable CABLE_14 CS_DEPREC("Use Cable_14 instead") = Cable_14; +constexpr Cable CABLE_15 CS_DEPREC("Use Cable_15 instead") = Cable_15; +constexpr Cable CABLE_16 CS_DEPREC("Use Cable_16 instead") = Cable_16; + +Print &operator<<(Print &, Cable); + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/Channel.cpp b/Def/Channel.cpp new file mode 100644 index 0000000..7023f40 --- /dev/null +++ b/Def/Channel.cpp @@ -0,0 +1,8 @@ +#include "Channel.hpp" +#include + +BEGIN_CS_NAMESPACE + +Print &operator<<(Print &os, Channel) { return os; } + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/Channel.hpp b/Def/Channel.hpp new file mode 100644 index 0000000..e9fb3f9 --- /dev/null +++ b/Def/Channel.hpp @@ -0,0 +1,156 @@ +/* ✔ */ + +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +/** + * A type-safe class for MIDI channels. + */ +class Channel { + public: + /** + * @brief Create a MIDI Channel object. + * + * @param zeroBasedChannel + * The zero-based channel (0 is the first channel). + */ + explicit constexpr Channel(uint8_t zeroBasedChannel) + : zeroBasedChannel(zeroBasedChannel) {} + + /** + * @brief Get the channel as an integer. + * + * @return The zero-based channel (0 is the first channel). + */ + constexpr uint8_t getRaw() const { return zeroBasedChannel; } + + /** + * @brief Get the channel as an integer. + * + * @return The one-based channel (1 is the first channel). + */ + constexpr uint8_t getOneBased() const { return zeroBasedChannel + 1; } + + /** + * @brief Create a channel. + * + * @param oneBasedChannel + * The channel number (1 is the first channel). + */ + static constexpr Channel createChannel(uint8_t oneBasedChannel) { + return Channel {uint8_t(oneBasedChannel - 1)}; + } + + /** + * @brief Check if two channels are the same. + * + * @param rhs + * The other channel to compare this channel to. + */ + constexpr bool operator==(const Channel &rhs) const { + return this->zeroBasedChannel == rhs.zeroBasedChannel; + } + + /** + * @brief Check if two channels are the different. + * + * @param rhs + * The other channel to compare this channel to. + */ + constexpr bool operator!=(const Channel &rhs) const { + return this->zeroBasedChannel != rhs.zeroBasedChannel; + } + + /** + * @brief Add an offset. + * + * @param rhs + * The offset to add to this channel. + */ + Channel &operator+=(uint8_t rhs) { + this->zeroBasedChannel += rhs; + return *this; + } + + /** + * @brief Add an offset to a channel. + * + * @param rhs + * The offset to add to the channel. + */ + Channel operator+(uint8_t rhs) const { + Channel copy = *this; + copy += rhs; + return copy; + } + + /** + * @brief Subtract an offset. + * + * @param rhs + * The offset to subtract from this channel. + */ + Channel &operator-=(uint8_t rhs) { + this->zeroBasedChannel -= rhs; + return *this; + } + + /** + * @brief Subtract an offset from a channel. + * + * @param rhs + * The offset to subtract from the channel. + */ + Channel operator-(uint8_t rhs) const { + Channel copy = *this; + copy -= rhs; + return copy; + } + + private: + uint8_t zeroBasedChannel : 4; +}; + +constexpr Channel Channel_1 = Channel::createChannel(1); +constexpr Channel Channel_2 = Channel::createChannel(2); +constexpr Channel Channel_3 = Channel::createChannel(3); +constexpr Channel Channel_4 = Channel::createChannel(4); +constexpr Channel Channel_5 = Channel::createChannel(5); +constexpr Channel Channel_6 = Channel::createChannel(6); +constexpr Channel Channel_7 = Channel::createChannel(7); +constexpr Channel Channel_8 = Channel::createChannel(8); +constexpr Channel Channel_9 = Channel::createChannel(9); +constexpr Channel Channel_10 = Channel::createChannel(10); +constexpr Channel Channel_11 = Channel::createChannel(11); +constexpr Channel Channel_12 = Channel::createChannel(12); +constexpr Channel Channel_13 = Channel::createChannel(13); +constexpr Channel Channel_14 = Channel::createChannel(14); +constexpr Channel Channel_15 = Channel::createChannel(15); +constexpr Channel Channel_16 = Channel::createChannel(16); + +#ifndef CHANNEL_1 // ArduinoCore-renesas defines this +constexpr Channel CHANNEL_1 CS_DEPREC("Use Channel_1 instead") = Channel_1; +constexpr Channel CHANNEL_2 CS_DEPREC("Use Channel_2 instead") = Channel_2; +constexpr Channel CHANNEL_3 CS_DEPREC("Use Channel_3 instead") = Channel_3; +constexpr Channel CHANNEL_4 CS_DEPREC("Use Channel_4 instead") = Channel_4; +constexpr Channel CHANNEL_5 CS_DEPREC("Use Channel_5 instead") = Channel_5; +constexpr Channel CHANNEL_6 CS_DEPREC("Use Channel_6 instead") = Channel_6; +constexpr Channel CHANNEL_7 CS_DEPREC("Use Channel_7 instead") = Channel_7; +constexpr Channel CHANNEL_8 CS_DEPREC("Use Channel_8 instead") = Channel_8; +constexpr Channel CHANNEL_9 CS_DEPREC("Use Channel_9 instead") = Channel_9; +constexpr Channel CHANNEL_10 CS_DEPREC("Use Channel_10 instead") = Channel_10; +constexpr Channel CHANNEL_11 CS_DEPREC("Use Channel_11 instead") = Channel_11; +constexpr Channel CHANNEL_12 CS_DEPREC("Use Channel_12 instead") = Channel_12; +constexpr Channel CHANNEL_13 CS_DEPREC("Use Channel_13 instead") = Channel_13; +constexpr Channel CHANNEL_14 CS_DEPREC("Use Channel_14 instead") = Channel_14; +constexpr Channel CHANNEL_15 CS_DEPREC("Use Channel_15 instead") = Channel_15; +constexpr Channel CHANNEL_16 CS_DEPREC("Use Channel_16 instead") = Channel_16; +#endif + +Print &operator<<(Print &, Channel); + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/Def.hpp b/Def/Def.hpp new file mode 100644 index 0000000..e7b4aef --- /dev/null +++ b/Def/Def.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include "Cable.hpp" +#include "Channel.hpp" +#include +#include +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +using ::ArduinoPin_t; +using AH::analog_t; +using AH::NO_PIN; +using AH::pin_t; +using AH::PinList; + +using MappingFunction = analog_t (*)(analog_t); + +using AH::Array; +using AH::Array2D; + +template +using AddressMatrix = Array2D; + +struct EncoderSwitchPinList { + EncoderSwitchPinList(uint8_t A, uint8_t B, pin_t switchPin) + : A(A), B(B), switchPin(switchPin) {} + EncoderSwitchPinList(uint8_t A, uint8_t B) + : A(A), B(B), switchPin(NO_PIN) {} + + uint8_t A; + uint8_t B; + pin_t switchPin; +}; + +struct EncoderPinList { + uint8_t A; + uint8_t B; +}; + +using setting_t = uint8_t; +constexpr setting_t NoSetting = + (std::numeric_limits::max() >> 1) + 1; + +struct Potentiometer {}; +struct MotorFader {}; +struct Display {}; + +struct PixelLocation { + int16_t x; + int16_t y; +}; + +END_CS_NAMESPACE diff --git a/Def/MIDIAddress.cpp b/Def/MIDIAddress.cpp new file mode 100644 index 0000000..530eb8b --- /dev/null +++ b/Def/MIDIAddress.cpp @@ -0,0 +1,53 @@ +#include "MIDIAddress.hpp" + +BEGIN_CS_NAMESPACE + +RelativeMIDIAddress &RelativeMIDIAddress::operator+=(RelativeMIDIAddress that) { + this->addresses.valid &= that.addresses.valid; + this->addresses.address += that.addresses.address; + this->addresses.channel += that.addresses.channel; + this->addresses.cableNumber += that.addresses.cableNumber; + return *this; +} + +MIDIAddress &MIDIAddress::operator+=(RelativeMIDIAddress rhs) { + this->addresses.valid &= rhs.addresses.valid; + this->addresses.address += rhs.addresses.address; + this->addresses.channel += rhs.addresses.channel; + this->addresses.cableNumber += rhs.addresses.cableNumber; + return *this; +} + +MIDIAddress &MIDIAddress::operator-=(RelativeMIDIAddress rhs) { + this->addresses.valid &= rhs.addresses.valid; + this->addresses.address -= rhs.addresses.address; + this->addresses.channel -= rhs.addresses.channel; + this->addresses.cableNumber -= rhs.addresses.cableNumber; + return *this; +} + +MIDIAddress MIDIAddress::operator+(RelativeMIDIAddress rhs) const { + MIDIAddress copy = *this; + copy += rhs; + return copy; +} + +MIDIAddress MIDIAddress::operator-(RelativeMIDIAddress rhs) const { + MIDIAddress copy = *this; + copy -= rhs; + return copy; +} + +bool MIDIAddress::matchAddressInRange(MIDIAddress toMatch, MIDIAddress base, + uint8_t length) { + bool valid = base.addresses.valid && toMatch.addresses.valid; + bool addressInRange = + base.addresses.address <= toMatch.addresses.address && + base.addresses.address + length > toMatch.addresses.address; + bool equalChannelAndCN = + base.addresses.channel == toMatch.addresses.channel && + base.addresses.cableNumber == toMatch.addresses.cableNumber; + return valid && addressInRange && equalChannelAndCN; +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/MIDIAddress.hpp b/Def/MIDIAddress.hpp new file mode 100644 index 0000000..8412e18 --- /dev/null +++ b/Def/MIDIAddress.hpp @@ -0,0 +1,360 @@ +#pragma once + +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/// A struct for saving a MIDI address consisting of a 7-bit address, a 4-bit +/// channel, and a 4-bit cable number. +/// A MIDI address can be marked "invalid". The MIDI sending functions +/// (@ref MIDI_Sender) will never send messages addressed to an invalid address. +struct __attribute__((packed)) RawMIDIAddress { + bool valid : 1; + uint8_t address : 7; + uint8_t channel : 4; + uint8_t cableNumber : 4; +}; + +/// A class for saving a MIDI channel and cable number. +/// A MIDI channel and cable number can be marked "invalid". +/// The MIDI sending functions (@ref MIDI_Sender) will never send messages +/// addressed to invalid channels or cables. +class MIDIChannelCable { + friend class MIDIAddress; + + public: + /// @name Constructors + /// @{ + + constexpr MIDIChannelCable() : addresses {0, 0, 0, 0} {} + constexpr MIDIChannelCable(Channel channel, Cable cableNumber = Cable_1) + : addresses {1, 0, channel.getRaw(), cableNumber.getRaw()} {} + + constexpr static MIDIChannelCable invalid() { return {}; } + + /// @} + + public: + /// @name Member access + /// @{ + + /// Get the channel [1, 16]. + constexpr Channel getChannel() const { return Channel {addresses.channel}; } + /// Get the channel as an integer [0, 15]. + constexpr uint8_t getRawChannel() const { return addresses.channel; } + + /// Get the cable number [Cable_1, Cable_16]. + constexpr Cable getCableNumber() const { + return Cable(addresses.cableNumber); + } + /// Get the cable number as an integer [0, 15]. + constexpr uint8_t getRawCableNumber() const { + return addresses.cableNumber; + } + + /// @} + + public: + /// @name Checks + /// @{ + + /// Check for equality: two addresses are equal if and only if they are both + /// valid addresses and the MIDI channel and MIDI USB cable number are + /// equal. + /// @note Invalid addresses are not equal nor inequal. + constexpr bool operator==(MIDIChannelCable rhs) const { + return this->addresses.valid && rhs.addresses.valid && + this->addresses.channel == rhs.addresses.channel && + this->addresses.cableNumber == rhs.addresses.cableNumber; + } + + /// Check for inequality: two addresses are not equal if and only if they + /// are both valid addresses and have a MIDI channel or MIDI USB cable + /// number that differs. + /// @note Invalid addresses are not equal nor inequal. + constexpr bool operator!=(MIDIChannelCable rhs) const { + return this->addresses.valid && rhs.addresses.valid && + !(this->addresses.channel == rhs.addresses.channel && + this->addresses.cableNumber == rhs.addresses.cableNumber); + } + + /// Check if the MIDI address is valid. + constexpr bool isValid() const { return addresses.valid; } + + /// Check if the MIDI address is valid. + /// @see isValid + constexpr explicit operator bool() const { return isValid(); } + + /// @} + + public: + /// @name Base functions for address pattern matching. + /// @{ + + /// Check if two addresses match (are equal). + static bool matchSingle(MIDIChannelCable toMatch, MIDIChannelCable base) { + return base == toMatch; + } + + /// @} + + protected: + constexpr MIDIChannelCable(RawMIDIAddress addresses) + : addresses(addresses) {} + + private: + RawMIDIAddress addresses; +}; + +/// A class for saving an offset to a MIDI address. +/// It can be added to a MIDIAddress. +class RelativeMIDIAddress { + friend class MIDIAddress; + + public: + constexpr RelativeMIDIAddress() : addresses {0, 0, 0, 0} {} + constexpr RelativeMIDIAddress(int deltaAddress, int deltaChannel = 0, + int deltaCableNumber = 0) + : addresses { + 1, + static_cast(deltaAddress), + static_cast(deltaChannel), + static_cast(deltaCableNumber), + } {} + constexpr bool isValid() const { return addresses.valid; } + + /// Compound addition. Element-wise addition, result is valid if both + /// operands were valid. + RelativeMIDIAddress &operator+=(RelativeMIDIAddress that); + + private: + RawMIDIAddress addresses; + static_assert(((-1) & 0x7F) == 0x7F, + "Negative numbers must be two's complement"); +}; + +/// A type-safe utility class for saving a MIDI address consisting of a 7-bit +/// address, a 4-bit channel, and a 4-bit cable number. +/// A MIDI address can be marked "invalid". The MIDI sending functions +/// (@ref MIDI_Sender) will never send messages addressed to invalid addresses. +/// +/// See @ref midi_md-midi-addresses "MIDI Tutorial: MIDI addresses" for a +/// tutorial on how to use MIDI addresses. +class MIDIAddress { + public: + /// @name Constructors + /// @{ + + /// Default constructor, creates an invalid address. + constexpr MIDIAddress() + : addresses { + 0, + 0, + 0, + 0, + } {} + + /** + * @brief Constructor. + * + * @param address + * The 7-bit MIDI address. Depending on the message type, this can + * be the MIDI note number, the number of the MIDI Control Change + * Controller, etc. + * Must be a number in the range [0, 127]. + * @param channelCN + * The MIDI Channel and the MIDI USB cable number. + */ + constexpr MIDIAddress(int address, MIDIChannelCable channelCN) + : addresses { + 1, + static_cast(address), + channelCN.getRawChannel(), + channelCN.getRawCableNumber(), + } {} // Deliberate overflow for negative numbers + + /** + * @brief Constructor. + * + * @param address + * The 7-bit MIDI address. + * Depending on the message type, this can be the MIDI note number, + * the number of the MIDI Control Change Controller, etc. + * Must be a number in the range [0, 127]. + * @param channel + * The MIDI Channel. + * Use the constants @ref Channel_1 through @ref Channel_16. + * @param cableNumber + * The MIDI USB cable number. + * Use the constants @ref Cable_1 through @ref Cable_16. + */ + constexpr MIDIAddress(int address, Channel channel = Channel_1, + Cable cableNumber = Cable_1) + : addresses { + 1, + static_cast(address), + channel.getRaw(), + cableNumber.getRaw(), + } {} // Deliberate overflow for negative numbers + + /** + * @brief Constructor. + * + * @param address + * The 7-bit MIDI address. + * Depending on the message type, this can be the MIDI note number, + * the number of the MIDI Control Change Controller, etc. + * Must be a number in the range [0, 127]. + * @param cableNumber + * The MIDI USB cable number. + * Use the constants @ref Cable_1 through @ref Cable_16. + */ + constexpr MIDIAddress(int address, Cable cableNumber) + : addresses { + 1, + static_cast(address), + 0, + cableNumber.getRaw(), + } {} // Deliberate overflow for negative numbers + + /** + * @brief Constructor. + * + * @param channel + * The MIDI Channel. + * Use the constants @ref Channel_1 through @ref Channel_16. + * @param cableNumber + * The MIDI USB cable number. + * Use the constants @ref Cable_1 through @ref Cable_16. + */ + constexpr MIDIAddress(Channel channel, Cable cableNumber = Cable_1) + : addresses { + 1, + 0, + channel.getRaw(), + cableNumber.getRaw(), + } {} + + /** + * @brief Constructor. + * + * @param address + * The MIDI Channel and the MIDI USB cable number. + */ + constexpr MIDIAddress(MIDIChannelCable address) + : addresses(address.addresses) {} + + /// Return an invalid address. + constexpr static MIDIAddress invalid() { return {}; } + + /// @} + + public: + /// @name Adding/subtracting offsets + /// @{ + + /// Add a relative offset to this address. + MIDIAddress &operator+=(RelativeMIDIAddress rhs); + + /// Subtract a relative offset from this address. + MIDIAddress &operator-=(RelativeMIDIAddress rhs); + + /// Add a relative offset. + MIDIAddress operator+(RelativeMIDIAddress rhs) const; + + /// Subtract a relative offset. + MIDIAddress operator-(RelativeMIDIAddress rhs) const; + + /// @} + + public: + /// @name Member access + /// @{ + + /// Get the address [0, 127]. + constexpr uint8_t getAddress() const { return addresses.address; } + + /// Get the channel [Channel_1, Channel_16] + constexpr Channel getChannel() const { return Channel {addresses.channel}; } + /// Get the channel as an integer [0, 15] + constexpr uint8_t getRawChannel() const { return addresses.channel; } + + /// Get the cable number [Cable_1, Cable_16]. + constexpr Cable getCableNumber() const { + return Cable(addresses.cableNumber); + } + /// Get the cable number as an integer [0, 15]. + constexpr uint8_t getRawCableNumber() const { + return addresses.cableNumber; + } + /// Get the channel and cable number. + constexpr MIDIChannelCable getChannelCable() const { return {addresses}; } + + /// @} + + public: + /// @name Checks + /// @{ + + /// Check for equality: two addresses are equal if and only if they are both + /// valid addresses and the MIDI address, MIDI channel and MIDI USB cable + /// number are equal. + /// @note Invalid addresses are not equal nor inequal. + constexpr bool operator==(MIDIAddress rhs) const { + return this->addresses.valid && rhs.addresses.valid && + this->addresses.address == rhs.addresses.address && + this->addresses.channel == rhs.addresses.channel && + this->addresses.cableNumber == rhs.addresses.cableNumber; + } + + /// Check for inequality: two addresses are not equal if and only if they + /// are both valid addresses and have a MIDI address, MIDI channel or MIDI + /// USB cable number that differs. + /// @note Invalid addresses are not equal nor inequal. + constexpr bool operator!=(MIDIAddress rhs) const { + return this->addresses.valid && rhs.addresses.valid && + !(this->addresses.address == rhs.addresses.address && + this->addresses.channel == rhs.addresses.channel && + this->addresses.cableNumber == rhs.addresses.cableNumber); + } + + /// Check if the MIDI address is valid. + constexpr bool isValid() const { return addresses.valid; } + + /// Check if the MIDI address is valid. + /// @see isValid + constexpr explicit operator bool() const { return isValid(); } + + /// @} + + public: + /// @name Base functions for address pattern matching. + /// @{ + + /// Check if two addresses match (are equal). + static bool matchSingle(MIDIAddress toMatch, MIDIAddress base) { + return base == toMatch; + } + + /// Check if an address falls within a range of MIDI addresses, starting + /// with address `base`, with a given length. + /// @retval true + /// `toMatch` and `base` are both valid addresses, + /// the MIDI address is within the given range, and the MIDI Channel + /// and MIDI USB Cable Number of `toMatch` and `base` are the same. + /// @retval false + /// Otherwise. + static bool matchAddressInRange(MIDIAddress toMatch, MIDIAddress base, + uint8_t length); + + /// @} + + private: + RawMIDIAddress addresses; +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Def/TypeTraits.hpp b/Def/TypeTraits.hpp new file mode 100644 index 0000000..b10a52c --- /dev/null +++ b/Def/TypeTraits.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include + +BEGIN_CS_NAMESPACE + +template +using void_t = void; + +template +struct has_method_begin : std::false_type {}; + +template +struct has_method_begin().begin())>> + : std::true_type {}; + +/// Calls the `begin()` method of `t` if that method exists. +template +typename std::enable_if::value>::type +begin_if_possible(T &t) { + t.begin(); +} + +template +typename std::enable_if::value>::type +begin_if_possible(T &) {} + +END_CS_NAMESPACE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..9cecc1d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/MIDI_Constants/Chords/Chords.hpp b/MIDI_Constants/Chords/Chords.hpp new file mode 100644 index 0000000..92e65e1 --- /dev/null +++ b/MIDI_Constants/Chords/Chords.hpp @@ -0,0 +1,76 @@ +#pragma once + +#include "Intervals.hpp" +#include +#include +#include + +BEGIN_CS_NAMESPACE + +class IChord { + public: + virtual ~IChord() = default; + virtual const int8_t *begin() const = 0; + virtual const int8_t *end() const = 0; +}; + +template +class Chord : public IChord { + public: + Chord(const Array &offsets) : offsets(offsets) {} + const int8_t *begin() const override { return offsets.begin(); } + const int8_t *end() const override { return offsets.end(); } + + template + Chord operator+(const Chord &rhs) const { + return {cat(this->getOffsets(), rhs.getOffsets())}; + } + + Chord operator+(int8_t rhs) const { + return *this + Chord<1> {{rhs}}; + } + + const Array getOffsets() const { return offsets; } + + private: + Array offsets; +}; + +/// @addtogroup MIDIConstants +/// @{ + +/// Predefined Chord constants. +namespace Chords { + +using namespace Intervals; + +const Chord<2> Major = {{M3, P5}}; +const Chord<2> MajorFirstInv = {{M3, P5 - P8}}; // First inversion +const Chord<2> MajorSecondInv = {{M3 - P8, P5 - P8}}; // Second inversion + +const Chord<2> Minor = {{m3, P5}}; +const Chord<2> MinorFirstInv = {{m3, P5 - P8}}; +const Chord<2> MinorSecondInv = {{m3 - P8, P5 - P8}}; + +const Chord<2> Diminished = {{m3, d5}}; +const Chord<2> Augmented = {{m3, m6}}; + +const Chord<3> DominantSeventh = {{M3, P5, m7}}; +const Chord<3> MajorSeventh = {{M3, P5, M7}}; + +} // namespace Chords + +/// Predefined Chord constants with bass notes. +namespace Bass { + +using namespace Intervals; + +const Chord<1> Single = {{-P8}}; +const Chord<2> Double = {{-P8, -2 * P8}}; +const Chord<3> Triple = {{-P8, -2 * P8, -3 * P8}}; + +} // namespace Bass + +/// @} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Constants/Chords/Intervals.hpp b/MIDI_Constants/Chords/Intervals.hpp new file mode 100644 index 0000000..53887d8 --- /dev/null +++ b/MIDI_Constants/Chords/Intervals.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace Intervals { + +constexpr int8_t P1 = 0; ///< Perfect unison +constexpr int8_t m2 = 1; ///< Minor second +constexpr int8_t M2 = 2; ///< Major second +constexpr int8_t m3 = 3; ///< Minor third +constexpr int8_t M3 = 4; ///< Major third +constexpr int8_t P4 = 5; ///< Perfect fourth +constexpr int8_t d5 = 6; ///< Diminished fifth +constexpr int8_t P5 = 7; ///< Perfect fifth +constexpr int8_t m6 = 8; ///< Minor sixth +constexpr int8_t M6 = 9; ///< Major sixth +constexpr int8_t m7 = 10; ///< Minor seventh +constexpr int8_t M7 = 11; ///< Major seventh +constexpr int8_t P8 = 12; ///< Perfect octave + +} // namespace Intervals diff --git a/MIDI_Constants/Control_Change.hpp b/MIDI_Constants/Control_Change.hpp new file mode 100644 index 0000000..b2138dd --- /dev/null +++ b/MIDI_Constants/Control_Change.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +/// @addtogroup MIDIConstants +/// @{ + +/** + * @brief Names and values for all MIDI Control Change Controller Numbers. + */ +namespace MIDI_CC { + +constexpr uint8_t Bank_Select = 0x00; +constexpr uint8_t Modulation_Wheel = 0x01; +constexpr uint8_t Breath_Controller = 0x02; +// 03 Undefined +constexpr uint8_t Foot_Controller = 0x04; +constexpr uint8_t Portamento_Time = 0x05; +constexpr uint8_t Data_Entry_MSB = 0x06; +constexpr uint8_t Channel_Volume = 0x07; +constexpr uint8_t Balance = 0x08; +// 09 Undefined +constexpr uint8_t Pan = 0x0A; +constexpr uint8_t Expression_Controller = 0x0B; +constexpr uint8_t Effect_Control_1 = 0x0C; +constexpr uint8_t Effect_Control_2 = 0x0D; +// 0E Undefined +// 0F Undefined +constexpr uint8_t General_Purpose_Controller_1 = 0x10; +constexpr uint8_t General_Purpose_Controller_2 = 0x11; +constexpr uint8_t General_Purpose_Controller_3 = 0x12; +constexpr uint8_t General_Purpose_Controller_4 = 0x13; +// 14-1F Undefined + +// LSB + +constexpr uint8_t Bank_Select_LSB = 0x20 + 0x00; +constexpr uint8_t Modulation_Wheel_LSB = 0x20 + 0x01; +constexpr uint8_t Breath_Controller_LSB = 0x20 + 0x02; +// 23 Undefined +constexpr uint8_t Foot_Controller_LSB = 0x20 + 0x04; +constexpr uint8_t Portamento_Time_LSB = 0x20 + 0x05; +constexpr uint8_t Data_Entry_MSB_LSB CS_DEPREC("Use Data_Entry_LSB instead") + = 0x20 + 0x06; +constexpr uint8_t Data_Entry_LSB = 0x20 + 0x06; +constexpr uint8_t Channel_Volume_LSB = 0x20 + 0x07; +constexpr uint8_t Balance_LSB = 0x20 + 0x08; +// 29 Undefined +constexpr uint8_t Pan_LSB = 0x20 + 0x0A; +constexpr uint8_t Expression_Controller_LSB = 0x20 + 0x0B; +constexpr uint8_t Effect_Control_1_LSB = 0x20 + 0x0C; +constexpr uint8_t Effect_Control_2_LSB = 0x20 + 0x0D; +// 2E Undefined +// 2F Undefined +constexpr uint8_t General_Purpose_Controller_1_LSB = 0x20 + 0x10; +constexpr uint8_t General_Purpose_Controller_2_LSB = 0x20 + 0x11; +constexpr uint8_t General_Purpose_Controller_3_LSB = 0x20 + 0x12; +constexpr uint8_t General_Purpose_Controller_4_LSB = 0x20 + 0x13; +// 34 - 3F Undefined + +constexpr uint8_t Damper_Pedal = 0x40; +constexpr uint8_t Portamento = 0x41; +constexpr uint8_t Sostenuto = 0x42; +constexpr uint8_t Soft_Pedal = 0x43; +constexpr uint8_t Legato_Footswitch = 0x44; +constexpr uint8_t Hold_2 = 0x45; +constexpr uint8_t Sound_Controller_1 = 0x46; +constexpr uint8_t Sound_Controller_2 = 0x47; +constexpr uint8_t Sound_Controller_3 = 0x48; +constexpr uint8_t Sound_Controller_4 = 0x49; +constexpr uint8_t Sound_Controller_5 = 0x4A; +constexpr uint8_t Sound_Controller_6 = 0x4B; +constexpr uint8_t Sound_Controller_7 = 0x4C; +constexpr uint8_t Sound_Controller_8 = 0x4D; +constexpr uint8_t Sound_Controller_9 = 0x4E; +constexpr uint8_t Sound_Controller_10 = 0x4F; +constexpr uint8_t General_Purpose_Controller_5 = 0x50; +constexpr uint8_t General_Purpose_Controller_6 = 0x51; +constexpr uint8_t General_Purpose_Controller_7 = 0x52; +constexpr uint8_t General_Purpose_Controller_8 = 0x53; +constexpr uint8_t Portamento_Control = 0x54; +// 55-57 Undefined + +constexpr uint8_t High_Resolution_Velocity_Prefix = 0x58; +// 59-5A Undefined + +constexpr uint8_t Effects_1 = 0x5B; +constexpr uint8_t Effects_2 = 0x5C; +constexpr uint8_t Effects_3 = 0x5D; +constexpr uint8_t Effects_4 = 0x5E; +constexpr uint8_t Effects_5 = 0x5F; + +constexpr uint8_t Data_Increment = 0x60; +constexpr uint8_t Data_Decrement = 0x61; + +constexpr uint8_t NRPN_LSB = 0x62; +constexpr uint8_t NRPN_MSB = 0x63; +constexpr uint8_t RPN_LSB = 0x64; +constexpr uint8_t RPN_MSB = 0x65; + +// Channel Mode Messages + +constexpr uint8_t All_Sound_Off = 0x78; +constexpr uint8_t Reset_All_Controllers = 0x79; +constexpr uint8_t Local_Control = 0x7A; +constexpr uint8_t All_Notes_Off = 0x7B; +constexpr uint8_t Omni_Mode_Off = 0x7C; +constexpr uint8_t Omni_Mode_On = 0x7D; +constexpr uint8_t Mono_Mode_On = 0x7E; +constexpr uint8_t Poly_Mode_On = 0x7F; + +} // namespace MIDI_CC + +/// @} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Constants/Notes.hpp b/MIDI_Constants/Notes.hpp new file mode 100644 index 0000000..9ce258d --- /dev/null +++ b/MIDI_Constants/Notes.hpp @@ -0,0 +1,80 @@ +/* ✔ */ + +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +/// @addtogroup MIDIConstants +/// @{ + +/// MIDI note names. +/// Uses the [Scientific Pitch Notation system](https://en.wikipedia.org/wiki/Scientific_pitch_notation), +/// where A4 is 440 Hz, and C-1 is 8.1758 Hz. +/// +/// |Octave| C |C♯/D♭| D |D♯/E♭| E | F |F♯/G♭| G |G♯/A♭| A |A♯/B♭| B | +/// |:-----|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:| +/// |-1 | 0| 1| 2| 3| 4| 5| 6| 7| 8| 9| 10| 11| +/// |0 | 12| 13| 14| 15| 16| 17| 18| 19| 20| 21| 22| 23| +/// |1 | 24| 25| 26| 27| 28| 29| 30| 31| 32| 33| 34| 35| +/// |2 | 36| 37| 38| 39| 40| 41| 42| 43| 44| 45| 46| 47| +/// |3 | 48| 49| 50| 51| 52| 53| 54| 55| 56| 57| 58| 59| +/// |4 | 60| 61| 62| 63| 64| 65| 66| 67| 68| 69| 70| 71| +/// |5 | 72| 73| 74| 75| 76| 77| 78| 79| 80| 81| 82| 83| +/// |6 | 84| 85| 86| 87| 88| 89| 90| 91| 92| 93| 94| 95| +/// |7 | 96| 97| 98| 99| 100| 101| 102| 103| 104| 105| 106| 107| +/// |8 | 108| 109| 110| 111| 112| 113| 114| 115| 116| 117| 118| 119| +namespace MIDI_Notes { + +class Note { + private: + int8_t base; + constexpr Note(int8_t base) : base(base) {} + + public: + constexpr int8_t operator()(int8_t octave = -1) const { + return base + 12 * (octave + 1); + } + constexpr int8_t operator[](int8_t octave) const { return (*this)(octave); } + + constexpr static Note(C)() { return Note {0}; } + constexpr static Note(Db)() { return Note {1}; } + constexpr static Note(D)() { return Note {2}; } + constexpr static Note(Eb)() { return Note {3}; } + constexpr static Note(E)() { return Note {4}; } + constexpr static Note(F)() { return Note {5}; } + constexpr static Note(Gb)() { return Note {6}; } + constexpr static Note(G)() { return Note {7}; } + constexpr static Note(Ab)() { return Note {8}; } + constexpr static Note(A)() { return Note {9}; } + constexpr static Note(Bb)() { return Note {10}; } + constexpr static Note(B)() { return Note {11}; } +}; + +constexpr Note C = (Note::C)(); ///< C (Do) +constexpr Note Db = (Note::Db)(); ///< C♯, D♭ (Do sharp, Re flat) +constexpr Note D = (Note::D)(); ///< D (Re) +constexpr Note Eb = (Note::Eb)(); ///< D♯, E♭ (Re sharp, Mi flat) +constexpr Note E = (Note::E)(); ///< E (Mi) +constexpr Note F = (Note::F)(); ///< F (Fa) +constexpr Note Gb = (Note::Gb)(); ///< F♯, G♭ (Fa sharp, Sol flat) +constexpr Note G = (Note::G)(); ///< G (Sol) +constexpr Note Ab = (Note::Ab)(); ///< G♯, A♭ (Sol sharp, La flat) +constexpr Note A = (Note::A)(); ///< A (La) +constexpr Note Bb = (Note::Bb)(); ///< A♯, B♭ (La sharp, Si flat) +constexpr Note B = (Note::B)(); ///< B (Si) + +CS_DEPREC("Instead of `MIDI_Notes::F_(4)`, use `MIDI_Notes::F[4]`") +constexpr Note F_ = (Note::F)(); ///< F (Fa) + +/// Get the MIDI note in the given octave. +CS_DEPREC("Instead of `note(C, 4)`, use `MIDI_Notes::C(4)`") +constexpr int8_t note(Note note, int8_t numOctave) { return note(numOctave); } + +} // namespace MIDI_Notes + +/// @} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Constants/Program_Change.hpp b/MIDI_Constants/Program_Change.hpp new file mode 100644 index 0000000..9ac282d --- /dev/null +++ b/MIDI_Constants/Program_Change.hpp @@ -0,0 +1,149 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +/// @addtogroup MIDIConstants +/// @{ + +/** + * @brief Names and values for all MIDI Control Change Controller Numbers. + */ +namespace MIDI_PC { + +constexpr uint8_t Acoustic_Grand_Piano = 0; // Acoustic Grand Piano +constexpr uint8_t Bright_Acoustic_Piano = 1; // Bright Acoustic Piano +constexpr uint8_t Electric_Grand_Piano = 2; // Electric Grand Piano +constexpr uint8_t HonkyTonk_Piano = 3; // Honky-tonk Piano +constexpr uint8_t Electric_Piano_1 = 4; // Electric Piano 1 +constexpr uint8_t Electric_Piano_2 = 5; // Electric Piano 2 +constexpr uint8_t Harpsichord = 6; // Harpsichord +constexpr uint8_t Clavi = 7; // Clavi +constexpr uint8_t Celesta = 8; // Celesta +constexpr uint8_t Glockenspiel = 9; // Glockenspiel +constexpr uint8_t Music_Box = 10; // Music Box +constexpr uint8_t Vibraphone = 11; // Vibraphone +constexpr uint8_t Marimba = 12; // Marimba +constexpr uint8_t Xylophone = 13; // Xylophone +constexpr uint8_t Tubular_Bells = 14; // Tubular Bells +constexpr uint8_t Dulcimer = 15; // Dulcimer +constexpr uint8_t Drawbar_Organ = 16; // Drawbar Organ +constexpr uint8_t Percussive_Organ = 17; // Percussive Organ +constexpr uint8_t Rock_Organ = 18; // Rock Organ +constexpr uint8_t Church_Organ = 19; // Church Organ +constexpr uint8_t Reed_Organ = 20; // Reed Organ +constexpr uint8_t Accordion = 21; // Accordion +constexpr uint8_t Harmonica = 22; // Harmonica +constexpr uint8_t Tango_Accordion = 23; // Tango Accordion +constexpr uint8_t Acoustic_Guitar_Nylon = 24; // Acoustic Guitar (nylon) +constexpr uint8_t Acoustic_Guitar_Steel = 25; // Acoustic Guitar (steel) +constexpr uint8_t Electric_Guitar_Jazz = 26; // Electric Guitar (jazz) +constexpr uint8_t Electric_Guitar_Clean = 27; // Electric Guitar (clean) +constexpr uint8_t Electric_Guitar_Muted = 28; // Electric Guitar (muted) +constexpr uint8_t Overdriven_Guitar = 29; // Overdriven Guitar +constexpr uint8_t Distortion_Guitar = 30; // Distortion Guitar +constexpr uint8_t Guitar_harmonics = 31; // Guitar harmonics +constexpr uint8_t Acoustic_Bass = 32; // Acoustic Bass +constexpr uint8_t Electric_Bass_Finger = 33; // Electric Bass (finger) +constexpr uint8_t Electric_Bass_Pick = 34; // Electric Bass (pick) +constexpr uint8_t Fretless_Bass = 35; // Fretless Bass +constexpr uint8_t Slap_Bass_1 = 36; // Slap Bass 1 +constexpr uint8_t Slap_Bass_2 = 37; // Slap Bass 2 +constexpr uint8_t Synth_Bass_1 = 38; // Synth Bass 1 +constexpr uint8_t Synth_Bass_2 = 39; // Synth Bass 2 +constexpr uint8_t Violin = 40; // Violin +constexpr uint8_t Viola = 41; // Viola +constexpr uint8_t Cello = 42; // Cello +constexpr uint8_t Contrabass = 43; // Contrabass +constexpr uint8_t Tremolo_Strings = 44; // Tremolo Strings +constexpr uint8_t Pizzicato_Strings = 45; // Pizzicato Strings +constexpr uint8_t Orchestral_Harp = 46; // Orchestral Harp +constexpr uint8_t Timpani = 47; // Timpani +constexpr uint8_t String_Ensemble_1 = 48; // String Ensemble 1 +constexpr uint8_t String_Ensemble_2 = 49; // String Ensemble 2 +constexpr uint8_t SynthStrings_1 = 50; // SynthStrings 1 +constexpr uint8_t SynthStrings_2 = 51; // SynthStrings 2 +constexpr uint8_t Choir_Aahs = 52; // Choir Aahs +constexpr uint8_t Voice_Oohs = 53; // Voice Oohs +constexpr uint8_t Synth_Voice = 54; // Synth Voice +constexpr uint8_t Orchestra_Hit = 55; // Orchestra Hit +constexpr uint8_t Trumpet = 56; // Trumpet +constexpr uint8_t Trombone = 57; // Trombone +constexpr uint8_t Tuba = 58; // Tuba +constexpr uint8_t Muted_Trumpet = 59; // Muted Trumpet +constexpr uint8_t French_Horn = 60; // French Horn +constexpr uint8_t Brass_Section = 61; // Brass Section +constexpr uint8_t SynthBrass_1 = 62; // SynthBrass 1 +constexpr uint8_t SynthBrass_2 = 63; // SynthBrass 2 +constexpr uint8_t Soprano_Sax = 64; // Soprano Sax +constexpr uint8_t Alto_Sax = 65; // Alto Sax +constexpr uint8_t Tenor_Sax = 66; // Tenor Sax +constexpr uint8_t Baritone_Sax = 67; // Baritone Sax +constexpr uint8_t Oboe = 68; // Oboe +constexpr uint8_t English_Horn = 69; // English Horn +constexpr uint8_t Bassoon = 70; // Bassoon +constexpr uint8_t Clarinet = 71; // Clarinet +constexpr uint8_t Piccolo = 72; // Piccolo +constexpr uint8_t Flute = 73; // Flute +constexpr uint8_t Recorder = 74; // Recorder +constexpr uint8_t Pan_Flute = 75; // Pan Flute +constexpr uint8_t Blown_Bottle = 76; // Blown Bottle +constexpr uint8_t Shakuhachi = 77; // Shakuhachi +constexpr uint8_t Whistle = 78; // Whistle +constexpr uint8_t Ocarina = 79; // Ocarina +constexpr uint8_t Lead_1 = 80; // Lead 1 (square) +constexpr uint8_t Lead_2 = 81; // Lead 2 (sawtooth) +constexpr uint8_t Lead_3 = 82; // Lead 3 (calliope) +constexpr uint8_t Lead_4 = 83; // Lead 4 (chiff) +constexpr uint8_t Lead_5 = 84; // Lead 5 (charang) +constexpr uint8_t Lead_6 = 85; // Lead 6 (voice) +constexpr uint8_t Lead_7 = 86; // Lead 7 (fifths) +constexpr uint8_t Lead_8 = 87; // Lead 8 (bass + lead) +constexpr uint8_t Pad_1 = 88; // Pad 1 (new age) +constexpr uint8_t Pad_2 = 89; // Pad 2 (warm) +constexpr uint8_t Pad_3 = 90; // Pad 3 (polysynth) +constexpr uint8_t Pad_4 = 91; // Pad 4 (choir) +constexpr uint8_t Pad_5 = 92; // Pad 5 (bowed) +constexpr uint8_t Pad_6 = 93; // Pad 6 (metallic) +constexpr uint8_t Pad_7 = 94; // Pad 7 (halo) +constexpr uint8_t Pad_8 = 95; // Pad 8 (sweep) +constexpr uint8_t FX_1 = 96; // FX 1 (rain) +constexpr uint8_t FX_2 = 97; // FX 2 (soundtrack) +constexpr uint8_t FX_3 = 98; // FX 3 (crystal) +constexpr uint8_t FX_4 = 99; // FX 4 (atmosphere) +constexpr uint8_t FX_5 = 100; // FX 5 (brightness) +constexpr uint8_t FX_6 = 101; // FX 6 (goblins) +constexpr uint8_t FX_7 = 102; // FX 7 (echoes) +constexpr uint8_t FX_8 = 103; // FX 8 (sci-fi) +constexpr uint8_t Sitar = 104; // Sitar +constexpr uint8_t Banjo = 105; // Banjo +constexpr uint8_t Shamisen = 106; // Shamisen +constexpr uint8_t Koto = 107; // Koto +constexpr uint8_t Kalimba = 108; // Kalimba +constexpr uint8_t Bag_Pipe = 109; // Bag pipe +constexpr uint8_t Fiddle = 110; // Fiddle +constexpr uint8_t Shanai = 111; // Shanai +constexpr uint8_t Tinkle_Bell = 112; // Tinkle Bell +constexpr uint8_t Agogo = 113; // Agogo +constexpr uint8_t Steel_Drums = 114; // Steel Drums +constexpr uint8_t Woodblock = 115; // Woodblock +constexpr uint8_t Taiko_Drum = 116; // Taiko Drum +constexpr uint8_t Melodic_Tom = 117; // Melodic Tom +constexpr uint8_t Synth_Drum = 118; // Synth Drum +constexpr uint8_t Reverse_Cymbal = 119; // Reverse Cymbal +constexpr uint8_t Guitar_Fret_Noise = 120; // Guitar Fret Noise +constexpr uint8_t Breath_Noise = 121; // Breath Noise +constexpr uint8_t Seashore = 122; // Seashore +constexpr uint8_t Bird_Tweet = 123; // Bird Tweet +constexpr uint8_t Telephone_Ring = 124; // Telephone Ring +constexpr uint8_t Helicopter = 125; // Helicopter +constexpr uint8_t Applause = 126; // Applause +constexpr uint8_t Gunshot = 127; // Gunshot + +} // namespace MIDI_PC + +/// @} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Inputs/BankableMIDIMatcherHelpers.hpp b/MIDI_Inputs/BankableMIDIMatcherHelpers.hpp new file mode 100644 index 0000000..e91eb97 --- /dev/null +++ b/MIDI_Inputs/BankableMIDIMatcherHelpers.hpp @@ -0,0 +1,231 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +namespace BankableMIDIMatcherHelpers { + +/** + * @brief Check whether a given address is within a range of given length + * starting from the given base address. + * + * @param tgt + * The address to check + * @param base + * The base address, start of the range. + * @param length + * The length of the range. + */ +inline bool inRange(uint8_t tgt, uint8_t base, uint8_t length) { + return (base <= tgt) && (tgt - base < length); +} + +/** + * @brief Check if the given address is part of the bank relative to the + * base address. + * + * Consider the following example: + * A Bank with 4 tracks per bank (T), 2 bank settings (N), + * and a base address of 3. + * + * ~~~ + * 0 1 2 3 4 5 6 7 8 9 10 11 12 ... + * ☐ ☐ ☐ ☒ ☐ ☐ ☐ ☒ ☐ ☐ ☐ ☐ ☐ ... + * ~~~ + * + * Addresses before the base adddress are not matched (0, 1, 2). + * Addresses after N * T are not matched (8, 9, 10, 11, 12). + * Addresses with a distance to the base address that is not a multiple of N + * are not matched (4, 5, 6). + * + * @param tgt + * The address to check. + * @param base + * The base address (the address of bank setting 0). + * @param bank + * The bank to match the address in. + * + * @note Equivalent to `matchBankableInRange(toMatch, base, 1)`. + */ +template +bool matchBankable(uint8_t tgt, uint8_t base, const Bank &bank) { + const uint8_t N = BankSize; + const uint8_t B = bank.getTracksPerBank(); + const int8_t F = bank.getSelectionOffset(); + const uint8_t m = tgt; + const uint8_t b = base; + uint8_t diff = m - b - F * B; + return m >= b + F * B && // + diff < N * B && // + diff % B == 0; +} + +/// @see @ref matchBankableInRange(MIDIAddress,MIDIAddress,BaseBankConfig,uint8_t) +template +bool matchBankableInRange(uint8_t tgt, uint8_t base, const Bank &bank, + uint8_t rangeLen) { + const uint8_t R = rangeLen; + const uint8_t N = BankSize; + const uint8_t B = bank.getTracksPerBank(); + const int8_t F = bank.getSelectionOffset(); + const uint8_t m = tgt; + const uint8_t b = base; + uint8_t diff = m - b - F * B; + return m >= b + F * B && // + diff < N * B && // + diff % B < R; +} + +/// @see @ref getRangeIndex(MIDIAddress,MIDIAddress,BaseBankConfig) +template +uint8_t getRangeIndex(uint8_t tgt, uint8_t base, const Bank &bank) { + const uint8_t B = bank.getTracksPerBank(); + const int8_t F = bank.getSelectionOffset(); + const uint8_t m = tgt; + const uint8_t b = base; + uint8_t diff = m - b - F * B; + return diff % B; +} + +/// @see @ref getBankIndex(MIDIAddress,MIDIAddress,BaseBankConfig) +template +uint8_t getBankIndex(uint8_t tgt, uint8_t base, const Bank &bank) { + const uint8_t B = bank.getTracksPerBank(); + const int8_t F = bank.getSelectionOffset(); + const uint8_t m = tgt; + const uint8_t b = base; + uint8_t diff = m - b - F * B; + return diff / B; +} + +/** + * @brief Check whether a given address is part of the bank relative to + * the base address. + * + * @param tgt + * The address to check. + * @param base + * The base address (the address of bank setting 0). + * @param config + * The bank configuration. + */ +template +bool matchBankable(MIDIAddress tgt, MIDIAddress base, + BaseBankConfig config) { + if (!tgt.isValid() || !base.isValid()) + return false; + switch (config.type) { + case BankType::ChangeAddress: { + return tgt.getChannel() == base.getChannel() && + tgt.getCableNumber() == base.getCableNumber() && + matchBankable(tgt.getAddress(), base.getAddress(), + config.bank); + } + case BankType::ChangeChannel: { + return tgt.getAddress() == base.getAddress() && + tgt.getCableNumber() == base.getCableNumber() && + matchBankable(tgt.getRawChannel(), base.getRawChannel(), + config.bank); + } + case BankType::ChangeCable: { + return tgt.getAddress() == base.getAddress() && + tgt.getChannel() == base.getChannel() && + matchBankable(tgt.getRawCableNumber(), + base.getRawCableNumber(), config.bank); + } + default: return false; // LCOV_EXCL_LINE + } +} + +/** + * @brief Check whether a given address is part of the bank relative to + * the base address and within a range with a given length. + * + * @param tgt + * The address to check. + * @param base + * The base address (the address of bank setting 0). + * @param config + * The bank configuration. + * @param length + * The length of the range. + */ +template +bool matchBankableInRange(MIDIAddress tgt, MIDIAddress base, + BaseBankConfig config, uint8_t length) { + if (!tgt.isValid() || !base.isValid()) + return false; + switch (config.type) { + case ChangeAddress: + return tgt.getChannel() == base.getChannel() && + tgt.getCableNumber() == base.getCableNumber() && + matchBankableInRange(tgt.getAddress(), base.getAddress(), + config.bank, length); + case ChangeChannel: + return inRange(tgt.getAddress(), base.getAddress(), length) && + tgt.getCableNumber() == base.getCableNumber() && + matchBankable(tgt.getRawChannel(), base.getRawChannel(), + config.bank); + case ChangeCable: + return inRange(tgt.getAddress(), base.getAddress(), length) && + tgt.getChannel() == base.getChannel() && + matchBankable(tgt.getRawCableNumber(), + base.getRawCableNumber(), config.bank); + default: return false; + } +} + +/** + * @brief Calculate the bank setting of a given MIDI address, relative to + * a base address. + * + * @param target + * The MIDI address to calculate the bank setting of. + * @param base + * The base address to compare it to (the address of bank setting 0). + * @param config + * The bank configuration to determine the index. + */ +template +uint8_t getBankIndex(MIDIAddress target, MIDIAddress base, + BaseBankConfig config) { + switch (config.type) { + case BankType::ChangeAddress: + return getBankIndex(target.getAddress(), base.getAddress(), + config.bank); + case BankType::ChangeChannel: + return getBankIndex(target.getRawChannel(), base.getRawChannel(), + config.bank); + case BankType::ChangeCable: + return getBankIndex(target.getRawCableNumber(), + base.getRawCableNumber(), config.bank); + default: return 0; // LCOV_EXCL_LINE + } +} + +/** + * @brief Calculate the index in the address range of a given MIDI address, + * relative to a base address. + * + * @param tgt + * The MIDI address to calculate the bank setting of. + * @param base + * The base address to compare it to (beginning of the range for bank + * setting 0). + * @param config + * The bank configuration to determine the index. + */ +template +uint8_t getRangeIndex(MIDIAddress tgt, MIDIAddress base, + BaseBankConfig config) { + return config.type == BankType::ChangeAddress + ? getRangeIndex(tgt.getAddress(), base.getAddress(), config.bank) + : tgt.getAddress() - base.getAddress(); +} + +} // namespace BankableMIDIMatcherHelpers + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Inputs/InterfaceMIDIInputElements.hpp b/MIDI_Inputs/InterfaceMIDIInputElements.hpp new file mode 100644 index 0000000..cc45b0a --- /dev/null +++ b/MIDI_Inputs/InterfaceMIDIInputElements.hpp @@ -0,0 +1,119 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +namespace Interfaces { + +/// Abstract interface for MIDI input elements that receive and store a 7-bit +/// value. +class IValue { + public: + /// @name Detecting changes + /// @{ + + /// Check if the value was updated since the last time the dirty flag was + /// cleared. + bool getDirty() const { return dirty; } + /// Clear the dirty flag. + void clearDirty() { dirty = false; } + + /// @} + + virtual uint8_t getValue() const = 0; + + protected: + bool dirty = true; +}; + +/// Abstract interface for MIDI input elements that receive and store a 14-bit +/// value. +class IValue14 { + public: + /// @name Detecting changes + /// @{ + + /// Check if the value was updated since the last time the dirty flag was + /// cleared. + bool getDirty() const { return dirty; } + /// Clear the dirty flag. + void clearDirty() { dirty = false; } + + /// @} + + virtual uint16_t getValue() const = 0; + + protected: + bool dirty = true; +}; + +namespace MCU { + +class IVPot { + public: + /// @name Detecting changes + /// @{ + + /// Check if the value was updated since the last time the dirty flag was + /// cleared. + bool getDirty() const { return dirty; } + /// Clear the dirty flag. + void clearDirty() { dirty = false; } + + /// @} + + virtual bool getCenterLed() const = 0; + virtual uint8_t getStartOn() const = 0; + virtual uint8_t getStartOff() const = 0; + + protected: + bool dirty = true; +}; + +/** + * @brief An abstract interface for VU meters. To allow for both floating + * point values and integers, all values are integers under the hood. + * + * Using floats instead integers would be a strange choice as LED bar VU meters + * have discrete levels. + * Continuous "analog" VU meters can use or override the `getFloatValue()` + * method. + */ +class IVU { + public: + IVU(uint8_t max, bool alwaysDirty = false) + : max(max), alwaysDirty(alwaysDirty) {} + + /// @name Detecting changes + /// @{ + + /// Check if the value was updated since the last time the dirty flag was + /// cleared. + bool getDirty() const { return dirty; } + /// Clear the dirty flag. + void clearDirty() { dirty = alwaysDirty; } + + /// @} + + /// Return the VU meter value as an integer. + virtual uint8_t getValue() = 0; + /// Return the overload status. + virtual bool getOverload() = 0; + /// Get the VU meter value as a floating point number. + virtual float getFloatValue() { return (float)getValue() / getMax(); } + /// Get the maximum value that this VU meter can return. + uint8_t getMax() const { return max; } + + protected: + uint8_t max; + bool alwaysDirty; + bool dirty = true; +}; + +} // namespace MCU + +} // namespace Interfaces + +END_CS_NAMESPACE diff --git a/MIDI_Inputs/LEDs/NoteCCKPLED.hpp b/MIDI_Inputs/LEDs/NoteCCKPLED.hpp new file mode 100644 index 0000000..5b735db --- /dev/null +++ b/MIDI_Inputs/LEDs/NoteCCKPLED.hpp @@ -0,0 +1,103 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class NoteCCKPLED : public MatchingMIDIInputElement { + public: + using Matcher = TwoByteMIDIMatcher; + using Parent = MatchingMIDIInputElement; + + NoteCCKPLED(pin_t ledPin, MIDIAddress address) + : Parent(address), ledPin(ledPin) {} + + private: + void handleUpdate(typename Matcher::Result match) override { + PinStatus_t state = match.value >= threshold ? HIGH : LOW; + AH::ExtIO::digitalWrite(ledPin, state); + } + + public: + void begin() override { + AH::ExtIO::pinMode(ledPin, OUTPUT); + AH::ExtIO::digitalWrite(ledPin, LOW); + } + + void reset() override { AH::ExtIO::digitalWrite(ledPin, LOW); } + + uint8_t getThreshold() const { return threshold; } + void setThreshold(uint8_t threshold) { this->threshold = threshold; } + + private: + pin_t ledPin; + uint8_t threshold = 0x01; +}; + +using NoteLED = NoteCCKPLED; +using CCLED = NoteCCKPLED; +using KPLED = NoteCCKPLED; + +namespace Bankable { + +template +class NoteCCKPLED : public NoteCCKPValue { + public: + using Parent = NoteCCKPValue; + using Matcher = typename Parent::Matcher; + + NoteCCKPLED(BankConfig config, pin_t ledPin, MIDIAddress address) + : Parent(config, address), ledPin(ledPin) {} + + protected: + void handleUpdate(typename Matcher::Result match) override { + bool newdirty = Parent::handleUpdateImpl(match); + if (newdirty) + display(); + this->dirty |= newdirty; + } + + void display() { + PinStatus_t state = getValue() >= threshold ? HIGH : LOW; + AH::ExtIO::digitalWrite(ledPin, state); + } + + public: + void begin() override { + AH::ExtIO::pinMode(ledPin, OUTPUT); + AH::ExtIO::digitalWrite(ledPin, LOW); + } + + void reset() override { + Parent::reset(); + AH::ExtIO::digitalWrite(ledPin, LOW); + } + + using Parent::getValue; + + uint8_t getThreshold() const { return threshold; } + void setThreshold(uint8_t threshold) { this->threshold = threshold; } + + protected: + void onBankSettingChange() override { + Parent::onBankSettingChange(); + display(); + } + + private: + pin_t ledPin; + uint8_t threshold = 0x01; +}; + +template +using NoteLED = NoteCCKPLED; +template +using CCLED = NoteCCKPLED; +template +using KPLED = NoteCCKPLED; + +} // namespace Bankable + +END_CS_NAMESPACE diff --git a/MIDI_Inputs/MIDIInputElement.hpp b/MIDI_Inputs/MIDIInputElement.hpp new file mode 100644 index 0000000..4a896bd --- /dev/null +++ b/MIDI_Inputs/MIDIInputElement.hpp @@ -0,0 +1,152 @@ +#pragma once + +#include +#include + +#include // Bank, BankSettingChangeCallback + +#include +#include + +BEGIN_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +/** + * @brief A class for objects that listen for incoming MIDI events. + * + * They can either update some kind of display, or they can just save the state. + */ +template +class MIDIInputElement : public AH::UpdatableCRTP> { + protected: + MIDIInputElement() = default; + + public: + virtual ~MIDIInputElement() = default; + + public: + using MessageType = + typename std::conditional::type; + + /// Initialize the input element. + virtual void begin() {} // LCOV_EXCL_LINE + + /// Reset the input element to its initial state. + virtual void reset() {} // LCOV_EXCL_LINE + + /// Update the value of the input element. Used for decaying VU meters etc. + virtual void update() {} // LCOV_EXCL_LINE + + /// Receive a new MIDI message and update the internal state. + virtual bool updateWith(MessageType midimsg) = 0; + + /// Update all + static bool updateAllWith(MessageType midimsg) { + for (auto &el : MIDIInputElement::updatables) { + if (el.updateWith(midimsg)) { + el.moveDown(); + return true; + } + } + return false; + } + + /// Update all + static void updateAll() { + MIDIInputElement::applyToAll(&MIDIInputElement::update); + } + + /// Begin all + static void beginAll() { + MIDIInputElement::applyToAll(&MIDIInputElement::begin); + } + + /// Reset all + static void resetAll() { + MIDIInputElement::applyToAll(&MIDIInputElement::reset); + } +}; + +// -------------------------------------------------------------------------- // + +/// The @ref MIDIInputElement base class is very general: you give it a MIDI +/// message, and it calls the `updateWith()` method with that message. Each +/// instance must then determine whether the message is meant for them or not. +/// This is often a very repetitive task, so that logic is best isolated in a +/// so-called “Matcher”. The Matcher looks at the MIDI message, checks if it +/// matches its MIDI address, for example, and if so, it extracts some data +/// (such as the MIDI velocity value from the message). Then it returns whether +/// it matched and the extra data as a “Matcher::Result” object. If the message +/// matched, that Result object is passed to the +/// @ref MatchingMIDIInputElement::handleUpdate() method, so it can be handled +/// there. +/// +/// @todo Pass the MIDI message to the @ref handleUpdate() method. +template +class MatchingMIDIInputElement : public MIDIInputElement { + protected: + MatchingMIDIInputElement(const Matcher &matcher) : matcher(matcher) {} + + public: + using MessageType = typename MIDIInputElement::MessageType; + + bool updateWith(MessageType midimsg) override { + auto match = matcher(midimsg); + if (match.match) + handleUpdate(match); + return match.match; + } + + virtual void handleUpdate(typename Matcher::Result match) = 0; + + protected: + Matcher matcher; +}; + +// -------------------------------------------------------------------------- // + +/// Similar to @ref MatchingMIDIInputElement, but for Bankable MIDI Input +/// Elements. +template +class BankableMatchingMIDIInputElement + : public MatchingMIDIInputElement, + public BankSettingChangeCallback { + friend class Bank; + + protected: + /// Create a new BankableMatchingMIDIInputElement object, and add it to the + /// bank. + BankableMatchingMIDIInputElement(const Matcher &matcher) + : MatchingMIDIInputElement(matcher) { + this->matcher.getBank().add(this); + } + + uint8_t getActiveBank() const { return this->matcher.getSelection(); } + + public: + /// Destructor: remove element from the bank. + virtual ~BankableMatchingMIDIInputElement() { + this->matcher.getBank().remove(this); + } +}; + +// -------------------------------------------------------------------------- // + +/// MIDI Input Element that listens for MIDI Note On/Off messages. +using MIDIInputElementNote = MIDIInputElement; +/// MIDI Input Element that listens for MIDI Key Pressure messages. +using MIDIInputElementKP = MIDIInputElement; +/// MIDI Input Element that listens for MIDI Control Change messages. +using MIDIInputElementCC = MIDIInputElement; +/// MIDI Input Element that listens for MIDI Program Change messages. +using MIDIInputElementPC = MIDIInputElement; +/// MIDI Input Element that listens for MIDI Channel Pressure messages. +using MIDIInputElementCP = MIDIInputElement; +/// MIDI Input Element that listens for MIDI Pitch Bend messages. +using MIDIInputElementPB = MIDIInputElement; +/// MIDI Input Element that listens for MIDI System Exclusive messages. +using MIDIInputElementSysEx = MIDIInputElement; + +END_CS_NAMESPACE diff --git a/MIDI_Inputs/MIDIInputElementMatchers.hpp b/MIDI_Inputs/MIDIInputElementMatchers.hpp new file mode 100644 index 0000000..5238225 --- /dev/null +++ b/MIDI_Inputs/MIDIInputElementMatchers.hpp @@ -0,0 +1,271 @@ +#pragma once + +#include "BankableMIDIMatcherHelpers.hpp" +#include "MIDIInputElement.hpp" + +BEGIN_CS_NAMESPACE + +/// @addtogroup MIDIInputMatchers +/// @{ + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 1 data byte, such as Channel Pressure +/// and Program Change. +struct OneByteMIDIMatcher { + OneByteMIDIMatcher(MIDIChannelCable address) : address(address) {} + + struct Result { + bool match; + uint8_t value; + }; + + Result operator()(ChannelMessage m) { + if (!MIDIChannelCable::matchSingle(m.getChannelCable(), address)) + return {false, 0}; + uint8_t value = m.data1; + return {true, value}; + } + + MIDIChannelCable address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control +/// Change, Key Pressure (but not Pitch Bend). Matches a single address. +struct TwoByteMIDIMatcher { + TwoByteMIDIMatcher(MIDIAddress address) : address(address) {} + + struct Result { + bool match; + uint8_t value; + }; + + Result operator()(ChannelMessage m) { + if (!MIDIAddress::matchSingle(m.getAddress(), address)) + return {false, 0}; + uint8_t value = + m.getMessageType() == MIDIMessageType::NoteOff ? 0 : m.getData2(); + return {true, value}; + } + + MIDIAddress address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI Pitch Bend messages. Matches a single address. +struct PitchBendMIDIMatcher { + PitchBendMIDIMatcher(MIDIChannelCable address) : address(address) {} + + struct Result { + bool match; + uint16_t value; + }; + + Result operator()(ChannelMessage m) { + if (!MIDIChannelCable::matchSingle(m.getChannelCable(), address)) + return {false, 0}; + uint16_t value = (m.data2 << 7) | m.data1; + return {true, value}; + } + + MIDIChannelCable address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control +/// Change, Key Pressure (but not Pitch Bend). Matches ranges of addresses on a +/// single channel and cable. +struct TwoByteRangeMIDIMatcher { + TwoByteRangeMIDIMatcher(MIDIAddress address, uint8_t length) + : address(address), length(length) {} + + struct Result { + bool match; + uint8_t value; + uint8_t index; + }; + + Result operator()(ChannelMessage m) { + if (!MIDIAddress::matchAddressInRange(m.getAddress(), address, length)) + return {false, 0, 0}; + uint8_t value = + m.getMessageType() == MIDIMessageType::NoteOff ? 0 : m.getData2(); + uint8_t index = m.getData1() - address.getAddress(); + return {true, value, index}; + } + + MIDIAddress address; + uint8_t length; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 1 data byte, such as Channel Pressure +/// and Program Change. Matches a single address over multiple banks. +template +struct BankableOneByteMIDIMatcher { + BankableOneByteMIDIMatcher( + BankConfig config, + MIDIChannelCable address) + : config(config), address(address) {} + + struct Result { + bool match; + uint8_t value; + uint8_t bankIndex; + }; + + Result operator()(ChannelMessage m) { + using BankableMIDIMatcherHelpers::getBankIndex; + using BankableMIDIMatcherHelpers::matchBankable; + if (!matchBankable(m.getChannelCable(), address, config)) + return {false, 0, 0}; + uint8_t value = m.data1; + uint8_t bankIndex = getBankIndex(m.getChannelCable(), address, config); + return {true, value, bankIndex}; + } + + Bank &getBank() { return config.bank; } + const Bank &getBank() const { return config.bank; } + BankType getBankType() const { return config.type; } + static constexpr setting_t getBankSize() { return BankSize; } + + /// Get the current bank setting. + /// @see @ref Bank::getSelection() + setting_t getSelection() const { return getBank().getSelection(); } + + BaseBankConfig config; + MIDIChannelCable address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control +/// Change, Key Pressure. Matches a single address over multiple banks. +template +struct BankableTwoByteMIDIMatcher { + BankableTwoByteMIDIMatcher(BankConfig config, MIDIAddress address) + : config(config), address(address) {} + + struct Result { + bool match; + uint8_t value; + uint8_t bankIndex; + }; + + Result operator()(ChannelMessage m) { + using BankableMIDIMatcherHelpers::getBankIndex; + using BankableMIDIMatcherHelpers::matchBankable; + if (!matchBankable(m.getAddress(), address, config)) + return {false, 0, 0}; + uint8_t value = + m.getMessageType() == MIDIMessageType::NoteOff ? 0 : m.getData2(); + uint8_t bankIndex = getBankIndex(m.getAddress(), address, config); + return {true, value, bankIndex}; + } + + Bank &getBank() { return config.bank; } + const Bank &getBank() const { return config.bank; } + BankType getBankType() const { return config.type; } + static constexpr setting_t getBankSize() { return BankSize; } + + /// Get the current bank setting. + /// @see @ref Bank::getSelection() + setting_t getSelection() const { return getBank().getSelection(); } + + BaseBankConfig config; + MIDIAddress address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI Pitch Bend messages. Matches a single address over multiple +/// banks. +template +struct BankablePitchBendMIDIMatcher { + BankablePitchBendMIDIMatcher( + BankConfig config, + MIDIChannelCable address) + : config(config), address(address) {} + + struct Result { + bool match; + uint16_t value; + uint8_t bankIndex; + }; + + Result operator()(ChannelMessage m) { + using BankableMIDIMatcherHelpers::getBankIndex; + using BankableMIDIMatcherHelpers::matchBankable; + if (!matchBankable(m.getChannelCable(), address, config)) + return {false, 0, 0}; + uint16_t value = (m.data2 << 7) | m.data1; + uint8_t bankIndex = getBankIndex(m.getChannelCable(), address, config); + return {true, value, bankIndex}; + } + + Bank &getBank() { return config.bank; } + const Bank &getBank() const { return config.bank; } + BankType getBankType() const { return config.type; } + static constexpr setting_t getBankSize() { return BankSize; } + + /// Get the current bank setting. + /// @see @ref Bank::getSelection() + setting_t getSelection() const { return getBank().getSelection(); } + + BaseBankConfig config; + MIDIChannelCable address; +}; + +// -------------------------------------------------------------------------- // + +/// Matcher for MIDI messages with 2 data bytes, such as Note On/Off, Control +/// Change, Key Pressure. Matches a range of addresses over multiple banks. +template +struct BankableTwoByteRangeMIDIMatcher { + /// Constructor. + BankableTwoByteRangeMIDIMatcher(BankConfig config, + MIDIAddress address, uint8_t length) + : config(config), address(address), length(length) {} + + struct Result { + bool match; + uint8_t value; + uint8_t bankIndex; + uint8_t index; + }; + + Result operator()(ChannelMessage m) { + using BankableMIDIMatcherHelpers::getBankIndex; + using BankableMIDIMatcherHelpers::getRangeIndex; + using BankableMIDIMatcherHelpers::matchBankableInRange; + if (!matchBankableInRange(m.getAddress(), address, config, length)) + return {false, 0, 0, 0}; + uint8_t value = m.getMessageType() == m.NoteOff ? 0 : m.getData2(); + uint8_t bankIndex = getBankIndex(m.getAddress(), address, config); + uint8_t rangeIndex = getRangeIndex(m.getAddress(), address, config); + return {true, value, bankIndex, rangeIndex}; + } + + Bank &getBank() { return config.bank; } + const Bank &getBank() const { return config.bank; } + static constexpr setting_t getBankSize() { return BankSize; } + + /// Get the current bank setting. + /// @see @ref Bank::getSelection() + setting_t getSelection() const { return config.bank.getSelection(); } + + BaseBankConfig config; + MIDIAddress address; + uint8_t length; +}; + +// -------------------------------------------------------------------------- // + +/// @} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Inputs/NoteCCKPRange.hpp b/MIDI_Inputs/NoteCCKPRange.hpp new file mode 100644 index 0000000..131c07d --- /dev/null +++ b/MIDI_Inputs/NoteCCKPRange.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include "MIDIInputElementMatchers.hpp" + +BEGIN_CS_NAMESPACE + +template +class NoteCCKPRange + : public MatchingMIDIInputElement { + public: + using Matcher = TwoByteRangeMIDIMatcher; + + NoteCCKPRange(MIDIAddress address) + : MatchingMIDIInputElement({address, RangeLen}) {} + + private: + bool handleUpdateImpl(typename Matcher::Result match) { + bool newdirty = values[match.index] != match.value; + values[match.index] = match.value; + return newdirty; + } + + void handleUpdate(typename Matcher::Result match) override { + dirty |= handleUpdateImpl(match); + } + + public: + uint8_t getValue(uint8_t index) const { return values[index]; } + + void reset() override { + values = {{}}; + dirty = true; + } + + bool getDirty() const { return dirty; } + void clearDirty() { dirty = false; } + + private: + AH::Array values = {{}}; + bool dirty = true; +}; + +template +using NoteRange = NoteCCKPRange; +template +using CCRange = NoteCCKPRange; +template +using KPRange = NoteCCKPRange; + +namespace Bankable { + +template +class NoteCCKPRange : public BankableMatchingMIDIInputElement< + Type, BankableTwoByteRangeMIDIMatcher> { + public: + using Matcher = BankableTwoByteRangeMIDIMatcher; + + NoteCCKPRange(BankConfig config, MIDIAddress address) + : BankableMatchingMIDIInputElement( + {config, address, RangeLen}) {} + + protected: + bool handleUpdateImpl(typename Matcher::Result match) { + bool newdirty = values[match.bankIndex][match.index] != match.value && + match.bankIndex == this->getActiveBank(); + values[match.bankIndex][match.index] = match.value; + return newdirty; + } + + void handleUpdate(typename Matcher::Result match) override { + dirty |= handleUpdateImpl(match); + } + + public: + uint8_t getValue(uint8_t index) const { + return values[this->getActiveBank()][index]; + } + uint8_t getValue(uint8_t bank, uint8_t index) const { + return values[bank][index]; + } + + void reset() override { + values = {{{}}}; + dirty = true; + } + + bool getDirty() const { return dirty; } + void clearDirty() { dirty = false; } + + protected: + void onBankSettingChange() override { dirty = true; } + + private: + AH::Array2D values = {{{}}}; + + protected: + bool dirty = true; +}; + +template +using NoteRange = NoteCCKPRange; +template +using CCRange = + NoteCCKPRange; +template +using KPRange = NoteCCKPRange; + +} // namespace Bankable + +END_CS_NAMESPACE diff --git a/MIDI_Inputs/NoteCCKPValue.hpp b/MIDI_Inputs/NoteCCKPValue.hpp new file mode 100644 index 0000000..0e34275 --- /dev/null +++ b/MIDI_Inputs/NoteCCKPValue.hpp @@ -0,0 +1,93 @@ +#pragma once + +#include "InterfaceMIDIInputElements.hpp" +#include "MIDIInputElementMatchers.hpp" + +BEGIN_CS_NAMESPACE + +template +class NoteCCKPValue : public MatchingMIDIInputElement, + public Interfaces::IValue { + public: + using Matcher = TwoByteMIDIMatcher; + + NoteCCKPValue(MIDIAddress address) + : MatchingMIDIInputElement(address) {} + + protected: + bool handleUpdateImpl(typename Matcher::Result match) { + bool newdirty = value != match.value; + value = match.value; + return newdirty; + } + + void handleUpdate(typename Matcher::Result match) override { + dirty |= handleUpdateImpl(match); + } + + public: + uint8_t getValue() const override { return value; } + + void reset() override { + value = 0; + dirty = true; + } + + private: + uint8_t value = 0; +}; + +using NoteValue = NoteCCKPValue; +using CCValue = NoteCCKPValue; +using KPValue = NoteCCKPValue; + +namespace Bankable { + +template +class NoteCCKPValue : public BankableMatchingMIDIInputElement< + Type, BankableTwoByteMIDIMatcher>, + public Interfaces::IValue { + public: + using Matcher = BankableTwoByteMIDIMatcher; + + NoteCCKPValue(BankConfig config, MIDIAddress address) + : BankableMatchingMIDIInputElement({config, address}) {} + + protected: + bool handleUpdateImpl(typename Matcher::Result match) { + bool newdirty = values[match.bankIndex] != match.value && + match.bankIndex == this->getActiveBank(); + values[match.bankIndex] = match.value; + return newdirty; + } + + void handleUpdate(typename Matcher::Result match) override { + dirty |= handleUpdateImpl(match); + } + + public: + uint8_t getValue() const override { return values[this->getActiveBank()]; } + uint8_t getValue(uint8_t bank) const { return values[bank]; } + + void reset() override { + values = {{}}; + dirty = true; + } + + protected: + void onBankSettingChange() override { dirty = true; } + + private: + AH::Array values = {{}}; +}; + +template +using NoteValue = NoteCCKPValue; +template +using CCValue = NoteCCKPValue; +template +using KPValue = NoteCCKPValue; + +} // namespace Bankable + +END_CS_NAMESPACE diff --git a/MIDI_Inputs/PBValue.hpp b/MIDI_Inputs/PBValue.hpp new file mode 100644 index 0000000..4bf911b --- /dev/null +++ b/MIDI_Inputs/PBValue.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include "InterfaceMIDIInputElements.hpp" +#include "MIDIInputElementMatchers.hpp" + +BEGIN_CS_NAMESPACE + +class PBValue : public MatchingMIDIInputElement, + public Interfaces::IValue14 { + public: + using Matcher = PitchBendMIDIMatcher; + + PBValue(MIDIChannelCable address) : MatchingMIDIInputElement(address) {} + + protected: + void handleUpdate(typename Matcher::Result match) override { + dirty |= value != match.value; + value = match.value; + } + + public: + uint16_t getValue() const override { return value; } + + void reset() override { + value = 0; + dirty = true; + } + + private: + uint16_t value = 0; +}; + +namespace Bankable { + +template +class PBValue + : public BankableMatchingMIDIInputElement< + MIDIMessageType::PitchBend, BankablePitchBendMIDIMatcher>, + public Interfaces::IValue14 { + public: + constexpr static auto MessageType = MIDIMessageType::PitchBend; + using Matcher = BankablePitchBendMIDIMatcher; + using Parent = BankableMatchingMIDIInputElement; + + PBValue(BankConfig config, + MIDIChannelCable address) + : Parent({config, address}) {} + + protected: + void handleUpdate(typename Matcher::Result match) override { + dirty |= values[match.bankIndex] != match.value && + match.bankIndex == this->getActiveBank(); + values[match.bankIndex] = match.value; + } + + public: + uint16_t getValue() const override { return values[this->getActiveBank()]; } + uint16_t getValue(uint8_t bank) const { return values[bank]; } + + void reset() override { + values = {{}}; + dirty = true; + } + + protected: + void onBankSettingChange() override { dirty = true; } + + private: + AH::Array values = {{}}; +}; + +} // namespace Bankable + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp b/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp new file mode 100644 index 0000000..2130212 --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BLEAPI.hpp @@ -0,0 +1,168 @@ +#pragma once + +/** + * @file + * Type definitions and callback interfaces for communication between the + * low-level BLE stacks and higher-level MIDI BLE backends. + */ + +#include + +#include "Util/compat.hpp" + +#include +#include + +BEGIN_CS_NAMESPACE + +/// Represents a handle to the connection to another device. +struct BLEConnectionHandle { + uint16_t conn = 0xFFFF; + explicit operator bool() const { return conn != 0xFFFF; } + +#if __cplusplus < 201402L + BLEConnectionHandle() = default; + BLEConnectionHandle(uint16_t conn) : conn {conn} {} +#endif +}; + +/// Represents a handle to a local GATT characteristic. +struct BLECharacteristicHandle { + uint16_t characteristic = 0xFFFF; + explicit operator bool() const { return characteristic != 0xFFFF; } + +#if __cplusplus < 201402L + BLECharacteristicHandle() = default; + BLECharacteristicHandle(uint16_t characteristic) + : characteristic {characteristic} {} +#endif +}; + +/// Non-owning, std::span-style read-only view of BLE data. +struct BLEDataView { + const uint8_t *data = nullptr; + uint16_t length = 0; + explicit operator bool() const { return length > 0; } + +#if __cplusplus < 201402L + BLEDataView() = default; + BLEDataView(const uint8_t *data, uint16_t length) + : data {data}, length {length} {} +#endif +}; + +/// Describes a byte buffer containing (part of) a BLE packet. +/// Packets can be stored across multiple buffers, in which case the first +/// first buffer has type `Packet` and subsequent buffers of the same packet +/// have the type `Continuation`. +enum class BLEDataType : uint8_t { + None = 0, ///< No buffers available. + Packet, ///< Buffer contains the start of a BLE packet. + Continuation, ///< Buffer contains a chunk of a BLE packet. +}; + +/// Callable that returns the next chunk of data from a BLE packet when called. +/// Uses type erasure with a static buffer (no dynamic memory allocations). +class BLEDataGenerator { + public: + /// Get the next chunk of data from the BLE packet. + /// Returns a chunk of size zero to indicate completion. + /// @pre This wrapper is not empty. + /// @pre There is still data available. Calling this function again after + /// the previous call returned an empty chunk is not allowed. + BLEDataView operator()(); + /// Release the resources of the underlying data generator. + void clear(); + /// Check if this wrapper contains an underlying data generator. + explicit operator bool() const { return instance; } + + /// Create an empty BLEDataGenerator. + BLEDataGenerator() = default; + /// Store a callable of type @p T and initialize it by @p args. + template + BLEDataGenerator(compat::in_place_type_t, Args &&...args); + /// Store a callable of type @p T (with cv qualifiers and references + /// removed) and initialize it by forwarding @p t. + template + BLEDataGenerator(compat::in_place_t, T &&t); + BLEDataGenerator(const BLEDataGenerator &) = delete; + BLEDataGenerator &operator=(const BLEDataGenerator &) = delete; + BLEDataGenerator(BLEDataGenerator &&other) noexcept; + BLEDataGenerator &operator=(BLEDataGenerator &&other) noexcept; + ~BLEDataGenerator() { clear(); } + + private: + /// Type-erased interface. + struct Iface; + /// Specific class that implements the type-erased interface, wrapping the + /// type @p T. + template + struct Impl; + /// Alignment of the buffer to allocate the underlying data generator. + using buffer_align_t = max_align_t; + /// Size of the buffer to allocate the underlying data generator. + static constexpr size_t capacity = 4 * sizeof(void *) - sizeof(Iface *); + /// Buffer used for allocation of the underlying data generator. + alignas(buffer_align_t) compat::byte storage[capacity]; + //// Type-erased pointer to the underlying data generator in @ref storage. + Iface *instance = nullptr; +}; + +/// Should a buffer of BLEData be consumed immediately inside of the callback, +/// or can we hold on to it and process it later? +enum class BLEDataLifetime { + /// Buffer is valid only during the callback. Do not keep any pointers to it. + ConsumeImmediately, + /// Buffer is valid for as long as the owning @ref BLEDataGenerator is not + /// resumed or destroyed. + Managed, +}; + +/// Defines the interface for callback functions registered by the low-level +/// BLE code. +/// @warning These functions may be called from different tasks/threads or +/// low-priority interrupt handlers. You cannot take locks, and you +/// need to synchronize appropriately (e.g. using `std::atomic` or +/// by using critical sections). +class MIDIBLEInstance { + public: + virtual ~MIDIBLEInstance() = default; + /// Called by the BLE stack when a connection is established. + virtual void handleConnect(BLEConnectionHandle conn_handle) = 0; + /// Called by the BLE stack when a connection is terminated. + virtual void handleDisconnect(BLEConnectionHandle conn_handle) = 0; + /// Called by the BLE stack when the maximum transmission unit for the + /// connection changes. + virtual void handleMTU(BLEConnectionHandle conn_handle, uint16_t mtu) = 0; + /// Called by the BLE stack when the central subscribes to receive + /// notifications for the MIDI GATT characteristic. + virtual void handleSubscribe(BLEConnectionHandle conn_handle, + BLECharacteristicHandle char_handle, + bool notify) = 0; + /// Called by the BLE stack when the central writes data to the MIDI GATT + /// characteristic. + virtual void handleData(BLEConnectionHandle conn_handle, + BLEDataGenerator &&data, + BLEDataLifetime lifetime) = 0; +}; + +/// Configuration options for the low-level BLE code. +struct BLESettings { + /// Device name (used for advertising) + const char *device_name = "Control Surface MIDI"; + /// Connection intervals as multiples of 1.25 milliseconds + /// (e.g.0x000C = 15 ms). + struct { + uint16_t minimum = 0x000C; + uint16_t maximum = 0x000C; + } connection_interval {}; + /// Set to true if you want the Arduino to always initiate the Bluetooth + /// bonding or secure connection. As a result, it will show up as a "paired" + /// device on your computer/phone/tablet. If set to false, security is still + /// supported, but the central device should take the initiative. + bool initiate_security = false; +}; + +END_CS_NAMESPACE + +#include "BLEAPI.ipp" diff --git a/MIDI_Interfaces/BLEMIDI/BLEAPI.ipp b/MIDI_Interfaces/BLEMIDI/BLEAPI.ipp new file mode 100644 index 0000000..a459d2a --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BLEAPI.ipp @@ -0,0 +1,87 @@ +#pragma once + +#include "BLEAPI.hpp" + +#include +#include +#include + +#include + +BEGIN_CS_NAMESPACE + +struct BLEDataGenerator::Iface { + virtual ~Iface() = default; + virtual BLEDataView next() = 0; + virtual Iface *move_into(void *storage) noexcept = 0; + + Iface(const Iface &) = delete; + Iface &operator=(const Iface &) = delete; + + protected: + Iface() = default; + Iface(Iface &&) = default; +}; + +template +struct BLEDataGenerator::Impl : Iface { + T inst; + template + Impl(Args &&...args) : inst {std::forward(args)...} {} +#if __cplusplus >= 201703L + BLEDataView next() override { return std::invoke(inst); } +#else + BLEDataView next() override { return inst(); } +#endif + Iface *move_into(void *storage) noexcept override { + return new (storage) Impl {std::move(*this)}; + } +}; + +inline BLEDataView BLEDataGenerator::operator()() { + assert(instance); + return instance->next(); +} + +inline void BLEDataGenerator::clear() { +#if __cplusplus >= 201402 + if (auto *inst = std::exchange(instance, nullptr)) + inst->~Iface(); +#else + if (instance) + instance->~Iface(); + instance = nullptr; +#endif +} + +template +BLEDataGenerator::BLEDataGenerator(compat::in_place_type_t, Args &&...args) { + static_assert(sizeof(Impl) <= sizeof(storage), ""); + static_assert(alignof(Impl) <= alignof(buffer_align_t), ""); + instance = new (storage) Impl {std::forward(args)...}; +} + +template +BLEDataGenerator::BLEDataGenerator(compat::in_place_t, T &&t) + : BLEDataGenerator( + compat::in_place_type::type>, + std::forward(t)) {} + +inline BLEDataGenerator::BLEDataGenerator(BLEDataGenerator &&other) noexcept { + if (other.instance) { + this->instance = other.instance->move_into(this->storage); + other.clear(); + } +} + +inline BLEDataGenerator & +BLEDataGenerator::operator=(BLEDataGenerator &&other) noexcept { + clear(); + if (other.instance) { + this->instance = other.instance->move_into(this->storage); + other.clear(); + } + return *this; +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.cpp b/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.cpp new file mode 100644 index 0000000..5fd469d --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.cpp @@ -0,0 +1,190 @@ +#include "BLEMIDIPacketBuilder.hpp" +#include + +BEGIN_CS_NAMESPACE + +template +bool BLEMIDIPacketBuilder::addImpl(uint8_t header, uint8_t data1, uint8_t data2, + uint16_t timestamp) { + initBuffer(timestamp); + + uint8_t timestampLSB = getTimestampLSB(timestamp); + + // If the header is the same as the previous message, use running status + if (header == runningHeader) { + // If the timestamp is the same, no need to send it again + if (timestampLSB == runningTimestamp) { + if (!hasSpaceFor(1 + ThreeBytes)) + return false; // Buffer full + buffer.push_back(data1); + if (ThreeBytes) + buffer.push_back(data2); + } + // Timestamp is different, send again + else { + if (!hasSpaceFor(2 + ThreeBytes)) + return false; // Buffer full + runningTimestamp = timestampLSB; + buffer.push_back(timestampLSB); + buffer.push_back(data1); + if (ThreeBytes) + buffer.push_back(data2); + } + } + // If the header is different, running status is not possible, send all + else { + if (!hasSpaceFor(3 + ThreeBytes)) + return false; // Buffer full + runningHeader = header; + runningTimestamp = timestampLSB; + buffer.push_back(timestampLSB); + buffer.push_back(header); + buffer.push_back(data1); + if (ThreeBytes) + buffer.push_back(data2); + } + return true; +} + +void BLEMIDIPacketBuilder::reset() { + buffer.resize(0); + runningHeader = 0; +} + +void BLEMIDIPacketBuilder::setCapacity(uint16_t capacity) { + if (capacity < 5) + ERROR(F("capacity less than 5 bytes"), 0x2005); // LCOV_EXCL_LINE + buffer.shrink_to_fit(); + buffer.reserve(capacity); +} + +bool BLEMIDIPacketBuilder::add3B(uint8_t header, uint8_t data1, uint8_t data2, + uint16_t timestamp) { + constexpr bool ThreeBytes = true; + return addImpl(header, data1, data2, timestamp); +} + +bool BLEMIDIPacketBuilder::add2B(uint8_t header, uint8_t data1, + uint16_t timestamp) { + constexpr bool ThreeBytes = false; + return addImpl(header, data1, 0, timestamp); +} + +bool BLEMIDIPacketBuilder::addRealTime(uint8_t rt, uint16_t timestamp) { + initBuffer(timestamp); + + if (!hasSpaceFor(2)) + return false; // Buffer full + + buffer.push_back(getTimestampLSB(timestamp)); + buffer.push_back(rt); + runningTimestamp = 0; // Re-send the timestamp next time + + return true; +} + +bool BLEMIDIPacketBuilder::addSysCommon(uint8_t num_data, uint8_t header, + uint8_t data1, uint8_t data2, + uint16_t timestamp) { + initBuffer(timestamp); + + uint8_t timestampLSB = getTimestampLSB(timestamp); + + if (!hasSpaceFor(2 + num_data)) + return false; // Buffer full + buffer.push_back(timestampLSB); + buffer.push_back(header); + if (num_data >= 1) + buffer.push_back(data1); + if (num_data >= 2) + buffer.push_back(data2); + runningTimestamp = 0; // Re-send the timestamp next time + + return true; +} + +bool BLEMIDIPacketBuilder::addSysEx(const uint8_t *&data, size_t &length, + uint16_t timestamp) { + initBuffer(timestamp); + + // We can't do anything with an empty message + if (length == 0) + return true; + + // If the first byte is a SysExStart byte we first have to write a + // timestamp + SysExStart. + if (*data == SysExStart) { + // We need space for at least the timestamp and a SysExStart + if (!hasSpaceFor(2)) + return false; // Buffer full + + // Normal running status is interrupted by SysEx + runningHeader = 0; + + const uint8_t timestampLSB = getTimestampLSB(timestamp); + + // Start of SysEx + buffer.push_back(timestampLSB); + buffer.push_back(SysExStart); + ++data; // First byte was added + --length; + } + + // Copy the rest of the data, and terminate the message if necessary + continueSysEx(data, length, timestamp); + return true; +} + +void BLEMIDIPacketBuilder::continueSysEx(const uint8_t *&data, size_t &length, + uint16_t timestamp) { + initBuffer(timestamp); + + if (length == 0) { + // Message was finished, no continuation + data = nullptr; + return; + } + + // Copy as much data as possible, but stop before the last byte, which + // could be a SysExEnd (and should be handled differently than data bytes) + while (length-- > 1 && buffer.size() < buffer.capacity()) + buffer.push_back(*data++); + + // If everything fit into the buffer + if (length == 0) { + // End of SysEx + if (*data == SysExEnd) { + if (hasSpaceFor(2)) { + buffer.push_back(getTimestampLSB(timestamp)); + buffer.push_back(SysExEnd); + // Message was finished, no continuation + data = nullptr; + } else { + // Send the SysExEnd byte next time + ++length; + } + } + // End of chunk but not end of SysEx + else { + if (hasSpaceFor(1)) { + buffer.push_back(*data); + // Message was finished, no continuation + data = nullptr; + } else { + // Send the last byte next time + ++length; + } + } + } + // If the while loop stopped because the buffer was full + else { + // data is not set to nullptr to let the caller know where to start + // sending the next continuation packet, + ++length; + } +} + +constexpr const uint8_t BLEMIDIPacketBuilder::SysExStart; +constexpr const uint8_t BLEMIDIPacketBuilder::SysExEnd; + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.hpp b/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.hpp new file mode 100644 index 0000000..6dd291d --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BLEMIDIPacketBuilder.hpp @@ -0,0 +1,237 @@ +#pragma once + +#include + +#include + +BEGIN_CS_NAMESPACE + +/// Class for building MIDI over Bluetooth Low Energy packets. +class BLEMIDIPacketBuilder { + private: + uint8_t runningHeader = 0; + uint8_t runningTimestamp = 0; + std::vector buffer = std::vector(0); + + constexpr static const uint8_t SysExStart = + static_cast(MIDIMessageType::SysExStart); + constexpr static const uint8_t SysExEnd = + static_cast(MIDIMessageType::SysExEnd); + + /// Check if the buffer has space left. + bool hasSpaceFor(size_t bytes) const { + return bytes <= size_t(buffer.capacity() - buffer.size()); + } + + /// Timestamp[0]: 0b10hh hhhh + constexpr static uint8_t getTimestampMSB(uint16_t timestamp) { + return ((timestamp >> 7) & 0x3F) | 0x80; + } + /// Timestamp[1]: 0b1lll llll + constexpr static uint8_t getTimestampLSB(uint16_t timestamp) { + return timestamp | 0x80; + } + + /// If this is the first byte/message in the packet, add the header + /// containing the 6 most significant bits of the timestamp + void initBuffer(uint16_t timestamp) { + if (buffer.empty()) + buffer.push_back(getTimestampMSB(timestamp)); + } + + /** + * @brief Try adding a 2-byte or 3-byte MIDI channel voice message to the + * packet. + * + * @tparam ThreeBytes + * Set to `true` for a 3-byte message, `false` for a 2-byte message. + * + * @param header + * MIDI status byte. + * @param data1 + * MIDI data byte 1. + * @param data2 + * MIDI data byte 2 (if `ThreeBytes == true`). + * @param timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + */ + template + bool addImpl(uint8_t header, uint8_t data1, uint8_t data2, + uint16_t timestamp); + + public: + BLEMIDIPacketBuilder(size_t capacity = 20) { buffer.reserve(capacity); } + + /// Reset the builder to start a new packet. + void reset(); + + /// Set the maximum capacity of the buffer. Set this to the MTU of the BLE + /// link minus three bytes (for notify overhead). + void setCapacity(uint16_t capacity); + + /// Get the size of the current packet. + uint16_t getSize() const { return buffer.size(); } + /// Get a pointer to the packet data buffer. + const uint8_t *getBuffer() const { return buffer.data(); } + /// Check if the packet buffer is empty. + bool empty() const { return buffer.empty(); } + + /// Return the packet as a vector of bytes. + const std::vector &getPacket() const { return buffer; } + + /** + * @brief Try adding a 3-byte MIDI channel voice message to the packet. + * + * @param header + * MIDI status byte. + * @param data1 + * MIDI data byte 1. + * @param data2 + * MIDI data byte 2. + * @param timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + */ + bool add3B(uint8_t header, uint8_t data1, uint8_t data2, + uint16_t timestamp); + + /** + * @brief Try adding a 2-byte MIDI channel voice message to the packet. + * + * @param header + * MIDI status byte. + * @param data1 + * MIDI data byte 1. + * @param timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + */ + bool add2B(uint8_t header, uint8_t data1, uint16_t timestamp); + + /** + * @brief Try adding a MIDI real-time message to the packet. + * + * @param rt + * MIDI real-time byte. + * @param timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + */ + bool addRealTime(uint8_t rt, uint16_t timestamp); + + /** + * @brief Try adding a MIDI system common message to the packet. + * + * @param num_data + * The number of data bytes (0, 1 or 2). + * @param header + * System common status byte. + * @param data1 + * MIDI data byte 1. + * @param data2 + * MIDI data byte 2. + * @param timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + */ + bool addSysCommon(uint8_t num_data, uint8_t header, uint8_t data1, + uint8_t data2, uint16_t timestamp); + + /** + * @brief Try adding (part of) a SysEx message to the packet. + * + * @param[in,out] data + * Pointer to the first byte of the SysEx message. + * At the end, this will point to the first byte to + * send in the next packet, or `nullptr` if the message was + * finished. + * @param[in,out] length + * The number of bytes in the SysEx message. + * At the end, this will be set to remaining number of + * bytes to send in the next packet. + * @param[in] timestamp + * 13-bit BLE-MIDI timestamp. + * + * @retval true + * Successfully added (part of) the message to the packet. + * @retval false + * Buffer is too full, send the current packet, reset the packet + * builder, and try again. + * + * If the message fits in a single packet, `length` is set to `0` (no + * remaining data bytes) and `data` is set to `nullptr`. + * + * For example: + * ~~~cpp + * BLEMIDIPacketBuilder packetbuilder; + * + * const uint8_t *data = (...); + * size_t length = (...); + * uint16_t timestamp = (...); + * + * if (!packetbuilder.addSysEx(data, length, timestamp)) { + * sendnow(packetbuilder.getBuffer(), packetbuilder.getSize()); + * packetbuilder.reset(); + * packetbuilder.addSysEx(data, length, timestamp) + * } + * while (data) { + * sendnow(packetbuilder.getBuffer(), packetbuilder.getSize()); + * packetbuilder.reset(); + * packetbuilder.continueSysEx(data, length, timestamp); + * } + * ~~~ + */ + bool addSysEx(const uint8_t *&data, size_t &length, uint16_t timestamp); + + /** + * @brief Add a SysEx continuation to the packet. + * + * @param[in,out] data + * Pointer to the first byte of the SysEx message to send + * in this continuation packet. + * At the end, this will point to the first byte to send in + * the next packet, or `nullptr` if the message was + * finished. + * @param[in,out] length + * The number of remaining bytes in the SysEx message. + * At the end, this will be set to remaining number of + * bytes to send in the next packet. + * @param[in] timestamp + * 13-bit BLE-MIDI timestamp. + * + * If the message can be completed in a single packet, `length` is set to + * `0` (no remaining data bytes) and `data` is set to `nullptr`. + * + * @see @ref addSysEx() + */ + void continueSysEx(const uint8_t *&data, size_t &length, + uint16_t timestamp); +}; + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/BLEMIDI/BLERingBuf.hpp b/MIDI_Interfaces/BLEMIDI/BLERingBuf.hpp new file mode 100644 index 0000000..c12cce6 --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BLERingBuf.hpp @@ -0,0 +1,163 @@ +#pragma once + +#include +#include + +#include + +#include + +BEGIN_CS_NAMESPACE + +template +struct NonatomicBLERingBufSize { + T value; + /// Alignment for size, and read/write pointers to avoid false sharing. + constexpr static size_t alignment = alignof(T); + T load_acquire() const { return value; } + void add_release(T t) { value += t; } + void sub_release(T t) { value -= t; } +}; + +/// Circular FIFO buffer for buffering BLE packet data. It supports both +/// complete BLE packets and packets split over multiple chunks. Full packets +/// that are added to the FIFO might be split up over multiple chunks. +/// @tparam Capacity +/// Buffer size (bytes). Note that the actual maximum data size may be +/// up to 6 bytes less because of data structure overhead. +/// @tparam SizeT +/// The type to use for the size of tbe buffer. Should be atomic if this +/// buffer is to be used as a SPSC queue between two threads. +/// See @ref NonatomicBLERingBufSize for an example. +template > +class BLERingBuf { + private: + struct Header { + uint16_t size : 14; + uint8_t type : 2; + Header() = default; + Header(uint16_t size, BLEDataType type) + : size {size}, type {static_cast(type)} {} + BLEDataType getType() const { return static_cast(type); } + }; + constexpr static uint_fast16_t header_size = sizeof(Header); + static_assert(header_size == 2, ""); + + constexpr static uint_fast16_t capacity = Capacity; + unsigned char buffer[capacity]; + alignas(SizeT::alignment) uint_fast16_t read_p = 0; + alignas(SizeT::alignment) uint_fast16_t write_p = header_size; + alignas(SizeT::alignment) SizeT size {header_size}; + + constexpr static uint_fast16_t ceil_h(uint_fast16_t i) { + return ((i + header_size - 1) / header_size) * header_size; + } + + public: + BLERingBuf() { + Header header {0, BLEDataType::None}; + static_assert(capacity % header_size == 0, ""); + std::memcpy(buffer, &header, header_size); + } + + /// Copy the given data into the buffer. May be split up into two chunks, + /// in which case the type will be set to @ref BLEDataType::Continuation + /// for the second chunk. + /// @retval false The buffer is full, nothing added to the buffer. + bool push(BLEDataView data, BLEDataType type = BLEDataType::Packet) { + if (type == BLEDataType::None) + return false; + uint_fast16_t loc_size = size.load_acquire(); + uint_fast16_t add_size = 0; + assert(loc_size <= capacity); + assert(write_p < capacity); + assert(write_p % header_size == 0); + // We need to write at least one header + uint_fast16_t expected_req_size = loc_size + data.length + header_size; + if (expected_req_size > capacity) + return false; // not enough space + // Contiguous size remaining (excluding header) + uint_fast16_t contig_size = capacity - write_p - header_size; + assert(contig_size < capacity); + // We may need to write a second header + uint_fast16_t worst_case_req_size = expected_req_size + header_size; + if (data.length > contig_size && worst_case_req_size > capacity) + return false; // not enough space + // Write the first header for the packet + uint16_t size_1 = std::min(contig_size, data.length); + Header header {size_1, type}; + std::memcpy(buffer + write_p, &header, sizeof(header)); + write_p += header_size; + add_size += header_size; + // Write first data + if (size_1 > 0) // avoid memcpy with nullptr + std::memcpy(buffer + write_p, data.data, size_1); + write_p += ceil_h(size_1); + add_size += ceil_h(size_1); + if (write_p == capacity) + write_p = 0; + // Now write the remainder at the beginning of the circular buffer + uint16_t size_2 = data.length - size_1; + if (size_2 > 0) { + // Write the continuation header + Header header {size_2, BLEDataType::Continuation}; + std::memcpy(buffer + write_p, &header, sizeof(header)); + write_p += header_size; + add_size += header_size; + // Write the remainder of the data + std::memcpy(buffer + write_p, data.data + size_1, size_2); + write_p += ceil_h(size_2); + add_size += ceil_h(size_2); + } + size.add_release(add_size); + return true; + } + + /// Get a view to the next chunk of data. The view remains valid until the + /// next call to @ref pop. + /// @retval BLEDataType::None + /// No data available. + /// @retval BLEDataType::Packet + /// The @p data output parameter points to the first chunk of a + /// packet. + /// @retval BLEDataType::Continuation + /// The @p data output parameter points to a chunk of continuation + /// data of the same packet. + BLEDataType pop(BLEDataView &data) { + uint_fast16_t loc_size = size.load_acquire(); + assert(loc_size >= header_size); + assert(read_p < capacity); + assert(read_p % header_size == 0); + // Read the old header + Header old_header; + std::memcpy(&old_header, buffer + read_p, sizeof(old_header)); + // If the previous chunk is the only thing left in the buffer + if (loc_size - header_size == ceil_h(old_header.size)) { + // If there is still actual data left in the buffer + if (old_header.getType() != BLEDataType::None) { + // Free the old data, preserving space for a header + read_p += ceil_h(old_header.size); + size.sub_release(ceil_h(old_header.size)); + // Write an empty header + Header header {0, BLEDataType::None}; + std::memcpy(buffer + read_p, &header, sizeof(header)); + } + data = {nullptr, 0}; + return BLEDataType::None; + } else { + // Otherwise, discard the old data and header + read_p += header_size + ceil_h(old_header.size); + size.sub_release(header_size + ceil_h(old_header.size)); + if (read_p == capacity) + read_p = 0; + // Read the next header + Header header; + std::memcpy(&header, buffer + read_p, sizeof(header)); + data = {buffer + read_p + header_size, header.size}; + return header.getType(); + } + } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp new file mode 100644 index 0000000..e663548 --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.cpp @@ -0,0 +1,65 @@ +#include + +#include "advertising.hpp" + +#include + +namespace cs::midi_ble_btstack { + +namespace { + +uint8_t adv_data[] { + // Flags general discoverable + 0x02, BLUETOOTH_DATA_TYPE_FLAGS, 0x06, + // Connection interval range + 0x05, BLUETOOTH_DATA_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE, 0x0c, 0x00, 0x0c, + 0x00, + // Service UUID + 0x11, BLUETOOTH_DATA_TYPE_COMPLETE_LIST_OF_128_BIT_SERVICE_CLASS_UUIDS, + 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7, 0x33, 0x4b, 0xe8, 0xed, + 0x5a, 0x0e, 0xb8, 0x03}; +static_assert(sizeof(adv_data) <= LE_ADVERTISING_DATA_SIZE); +uint8_t adv_rsp_data[LE_ADVERTISING_DATA_SIZE] { + // Name header + 0x15, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, + // Name value + 'C', 'o', 'n', 't', 'r', 'o', 'l', ' ', 'S', 'u', 'r', 'f', 'a', 'c', 'e', + ' ', 'M', 'I', 'D', 'I'}; +uint8_t adv_rsp_data_len() { return adv_rsp_data[0] + 1; } + +void set_adv_connection_interval(uint16_t min_itvl, uint16_t max_itvl) { + uint8_t *slave_itvl_range = adv_data + 5; + slave_itvl_range[0] = (min_itvl >> 0) & 0xFF; + slave_itvl_range[1] = (min_itvl >> 8) & 0xFF; + slave_itvl_range[2] = (max_itvl >> 0) & 0xFF; + slave_itvl_range[3] = (max_itvl >> 8) & 0xFF; +} + +void set_adv_name(const char *name) { + auto len = std::min(std::strlen(name), sizeof(adv_rsp_data) - 2); + uint8_t *adv_name_len = adv_rsp_data; + uint8_t *adv_name = adv_rsp_data + 2; + std::memcpy(adv_name, name, len); + *adv_name_len = static_cast(len + 1); +} + +} // namespace + +void le_midi_setup_adv(const BLESettings &ble_settings) { + set_adv_name(ble_settings.device_name); + set_adv_connection_interval(ble_settings.connection_interval.minimum, + ble_settings.connection_interval.maximum); + uint16_t adv_int_min = 0x0020; // 20 ms (multiple of 0.625ms) + uint16_t adv_int_max = 0x0040; // 40 ms (multiple of 0.625ms) + uint8_t adv_type = 0; + bd_addr_t null_addr {}; + uint8_t channel_map = 0x07; // All channels + uint8_t filter_policy = 0x00; // Allow any + gap_advertisements_set_params(adv_int_min, adv_int_max, adv_type, 0, + null_addr, channel_map, filter_policy); + gap_advertisements_set_data(sizeof(adv_data), adv_data); + gap_scan_response_set_data(adv_rsp_data_len(), adv_rsp_data); + gap_advertisements_enable(1); +} + +} // namespace cs::midi_ble_btstack \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/advertising.hpp b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.hpp new file mode 100644 index 0000000..381327f --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/advertising.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "../BLEAPI.hpp" + +namespace cs::midi_ble_btstack { + +void le_midi_setup_adv(const BLESettings &ble_settings); + +} // namespace cs::midi_ble_btstack diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp new file mode 100644 index 0000000..8905d49 --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.cpp @@ -0,0 +1,309 @@ +#define BTSTACK_FILE__ "gatt_midi.cpp" + +#include +#include +#include +#include +#include +#include + +#include + +#include "../BLEAPI.hpp" +#include "advertising.hpp" +#include "gatt_midi.h" +#include "hci_event_names.hpp" + +#include +#include + +namespace cs::midi_ble_btstack { + +namespace { + +constexpr uint16_t midi_char_value_handle = + ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_VALUE_HANDLE; +constexpr uint16_t midi_cccd_handle = + ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_CLIENT_CONFIGURATION_HANDLE; + +MIDIBLEInstance *instance = nullptr; +BLESettings settings; +btstack_packet_callback_registration_t hci_event_callback_registration; +btstack_packet_callback_registration_t sm_event_callback_registration; + +// callback/event functions + +// HCI_SUBEVENT_LE_CONNECTION_COMPLETE +void connection_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) { + if (!instance) + return; + if (hci_subevent_le_connection_complete_get_status(packet) != 0) + return; + uint16_t conn_handle = + hci_subevent_le_connection_complete_get_connection_handle(packet); + // Request bonding + if (settings.initiate_security) + sm_request_pairing(conn_handle); + // Update the connection parameters + uint16_t conn_latency = 0; + uint16_t supervision_timeout = 400; + gap_request_connection_parameter_update( + conn_handle, settings.connection_interval.minimum, + settings.connection_interval.maximum, conn_latency, + supervision_timeout); + instance->handleConnect(BLEConnectionHandle {conn_handle}); +} +// HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE +void connection_update_handler([[maybe_unused]] uint8_t *packet, + [[maybe_unused]] uint16_t size) { + DEBUGREF( // clang-format off + "Connection update: status=" + << hci_subevent_le_connection_update_complete_get_status(packet) + << ", connection interval=" + << hci_subevent_le_connection_update_complete_get_conn_interval(packet) + << ", connection latency=" + << hci_subevent_le_connection_update_complete_get_conn_latency(packet) + << ", supervision timeout=" + << hci_subevent_le_connection_update_complete_get_supervision_timeout(packet)); + // clang-format on +} +// HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST +void connection_param_req_handler([[maybe_unused]] uint8_t *packet, + [[maybe_unused]] uint16_t size) { + DEBUGREF( // clang-format off + "Connection parameter request: interval min=" + << hci_subevent_le_remote_connection_parameter_request_get_interval_min(packet) + << ", interval max=" + << hci_subevent_le_remote_connection_parameter_request_get_interval_max(packet) + << ", latency=" + << hci_subevent_le_remote_connection_parameter_request_get_latency(packet) + << ", timeout=" + << hci_subevent_le_remote_connection_parameter_request_get_timeout(packet)); + // clang-format on +} +// HCI_EVENT_LE_META +void le_packet_handler(uint8_t *packet, uint16_t size) { + uint8_t type = hci_event_le_meta_get_subevent_code(packet); + DEBUGREF("LE event: " << le_event_names[type] << " (0x" << hex << type + << dec << ")"); + switch (type) { + case HCI_SUBEVENT_LE_CONNECTION_COMPLETE: + connection_handler(packet, size); + break; + case HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE: + connection_update_handler(packet, size); + break; + case HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST: + connection_param_req_handler(packet, size); + break; + default: break; + } +} +// HCI_EVENT_LE_META +void gattservice_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) { + [[maybe_unused]] uint8_t type = + hci_event_gattservice_meta_get_subevent_code(packet); + DEBUGREF("GATT service event: " << gattservice_event_names[type] << " (0x" + << hex << type << dec << ")"); +} +// HCI_EVENT_DISCONNECTION_COMPLETE +void disconnect_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) { + assert(instance); + uint16_t conn_handle = + hci_event_disconnection_complete_get_connection_handle(packet); + instance->handleDisconnect(BLEConnectionHandle {conn_handle}); +} +// ATT_EVENT_MTU_EXCHANGE_COMPLETE +void mtu_exchange_complete_handler(uint8_t *packet, + [[maybe_unused]] uint16_t size) { + assert(instance); + uint16_t conn_handle = att_event_mtu_exchange_complete_get_handle(packet); + uint16_t mtu = att_event_mtu_exchange_complete_get_MTU(packet); + DEBUGREF("mtu=" << mtu); + instance->handleMTU(BLEConnectionHandle {conn_handle}, mtu); +} +// GATT_EVENT_MTU +void gatt_event_mtu_handler(uint8_t *packet, [[maybe_unused]] uint16_t size) { + assert(instance); + uint16_t conn_handle = gatt_event_mtu_get_handle(packet); + uint16_t mtu = gatt_event_mtu_get_MTU(packet); + instance->handleMTU(BLEConnectionHandle {conn_handle}, mtu); +} +// BTSTACK_EVENT_STATE +void btstack_event_state_handler(uint8_t *packet, + [[maybe_unused]] uint16_t size) { + if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) + return; + bd_addr_t local_addr; + gap_local_bd_addr(local_addr); + DEBUGREF("BTstack up and running on " << bd_addr_to_str(local_addr)); +} + +// Handles all HCI event packets. +void packet_handler(uint8_t packet_type, [[maybe_unused]] uint16_t channel, + uint8_t *packet, uint16_t size) { + if (packet_type != HCI_EVENT_PACKET) + return; + auto type = hci_event_packet_get_type(packet); + DEBUGREF("HCI event: " << hci_event_names[type] << " (0x" << hex << type + << dec << ")"); + switch (type) { + case HCI_EVENT_LE_META: le_packet_handler(packet, size); break; + case HCI_EVENT_GATTSERVICE_META: + gattservice_handler(packet, size); + break; + case HCI_EVENT_DISCONNECTION_COMPLETE: + disconnect_handler(packet, size); + break; + case SM_EVENT_JUST_WORKS_REQUEST: + sm_just_works_confirm( + sm_event_just_works_request_get_handle(packet)); + break; + case ATT_EVENT_MTU_EXCHANGE_COMPLETE: + mtu_exchange_complete_handler(packet, size); + break; + // TODO: what's the difference with the previous one? + case GATT_EVENT_MTU: gatt_event_mtu_handler(packet, size); break; + case BTSTACK_EVENT_STATE: + btstack_event_state_handler(packet, size); + break; + default: break; + } +} + +// ATT Client Read Callback for Dynamic Data +// - if buffer == NULL, don't copy data, just return size of value +// - if buffer != NULL, copy data and return number bytes copied +uint16_t att_read_callback([[maybe_unused]] hci_con_handle_t connection_handle, + uint16_t att_handle, + [[maybe_unused]] uint16_t offset, + [[maybe_unused]] uint8_t *buffer, + [[maybe_unused]] uint16_t buffer_size) { + if (att_handle == midi_char_value_handle) + return 0; // MIDI always responds with no data + return 0; +} + +int midi_cccd_write(hci_con_handle_t conn_handle, uint8_t *buffer, + [[maybe_unused]] uint16_t buffer_size) { + assert(instance); + bool notify = (little_endian_read_16(buffer, 0) & + GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION) != 0; + instance->handleSubscribe(BLEConnectionHandle {conn_handle}, + BLECharacteristicHandle {midi_char_value_handle}, + notify); + return 0; +} + +int midi_value_write(hci_con_handle_t conn_handle, uint8_t *buffer, + uint16_t buffer_size) { + assert(instance); + BLEDataView data {buffer, buffer_size}; + auto data_gen = [data {data}]() mutable { return std::exchange(data, {}); }; + instance->handleData( + BLEConnectionHandle {conn_handle}, + BLEDataGenerator {compat::in_place, std::move(data_gen)}, + BLEDataLifetime::ConsumeImmediately); + return 0; +} + +int att_write_callback(hci_con_handle_t conn_handle, uint16_t att_handle, + [[maybe_unused]] uint16_t transaction_mode, + uint16_t offset, uint8_t *buffer, uint16_t buffer_size) { + DEBUGREF("ATT write: handle=" << att_handle << ", offset=" << offset + << ", size=" << buffer_size); + // Only support regular writes (no prepared/long writes) + if (transaction_mode != ATT_TRANSACTION_MODE_NONE) + return ATT_ERROR_REQUEST_NOT_SUPPORTED; + // Only support writes without offset + if (offset != 0) + return ATT_ERROR_INVALID_OFFSET; + // Client configuration update + if (att_handle == midi_cccd_handle) + return midi_cccd_write(conn_handle, buffer, buffer_size); + // MIDI data received + else if (att_handle == midi_char_value_handle) + return midi_value_write(conn_handle, buffer, buffer_size); + return 0; +} + +void le_midi_setup(const BLESettings &ble_settings) { + l2cap_init(); + // setup SM: no input, no output + sm_init(); + sm_set_io_capabilities(IO_CAPABILITY_NO_INPUT_NO_OUTPUT); + sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION | + SM_AUTHREQ_BONDING); + // setup ATT server + att_server_init(profile_data, att_read_callback, att_write_callback); + // setup advertisements + le_midi_setup_adv(ble_settings); + // register for HCI events + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + // register for ATT events + att_server_register_packet_handler(packet_handler); + // register for SM events + sm_event_callback_registration.callback = &packet_handler; + sm_add_event_handler(&sm_event_callback_registration); +} + +template +btstack_context_callback_registration_t create_context_callback(F &f) { + btstack_context_callback_registration_t ret {}; + ret.callback = +[](void *context) { (*static_cast(context))(); }; + ret.context = &f; + return ret; +} + +} // namespace + +bool init(MIDIBLEInstance &instance, BLESettings settings) { + cs::midi_ble_btstack::instance = &instance; + cs::midi_ble_btstack::settings = settings; + le_midi_setup(settings); + hci_power_control(HCI_POWER_ON); + // btstack_run_loop_execute(); // not necessary in background mode + return true; +} + +void notify(BLEConnectionHandle conn_handle, + BLECharacteristicHandle char_handle, BLEDataView data) { + // DEBUGREF("[" << data.length << "] " + // << (AH::HexDump {data.data, data.length})); + [[maybe_unused]] const auto t0 = micros(); + // Don't bother sending empty packets + if (!data) + return; + // Flag to know when the can-send-now callback is done + volatile std::atomic_bool notify_done {false}; + // The following is executed in the BTstack can-send-now callback, so it is + // synchronized with the BTstack code + auto send = [&] { + DEBUGREF("notify " << micros() - t0); + att_server_notify(conn_handle.conn, char_handle.characteristic, + data.data, data.length); + DEBUGREF("notify done " << micros() - t0); + notify_done.store(true, std::memory_order_release); + }; + auto send_ctx = create_context_callback(send); + // The following is executed in the async_context, so it is synchronized + // with the BTstack code + auto run = [&] { + // Request can-send-now callback to be fired later + DEBUGREF("req send " << micros() - t0); + auto ret = att_server_request_to_send_notification(&send_ctx, + conn_handle.conn); + assert(ret == ERROR_CODE_SUCCESS); + }; + auto run_ctx = create_context_callback(run); + // Schedule the run callback on the BTstack thread, which will then schedule + // the send callback as soon as sending data is possible. + DEBUGREF("req main thread " << micros() - t0); + btstack_run_loop_execute_on_main_thread(&run_ctx); + // Wait for the can-send-now callback to clear the flag + while (!notify_done.load(std::memory_order_acquire)) tight_loop_contents(); + DEBUGREF("all done " << micros() - t0); +} + +} // namespace cs::midi_ble_btstack \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.h b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.h new file mode 100644 index 0000000..7e9cc4e --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.h @@ -0,0 +1,65 @@ + +// ~/pico-examples/build/pico_w/bt/gatt_midi/generated/gatt_midi.h generated from ~/pico-sdk/lib/btstack/example/gatt_midi.gatt for BTstack +// it needs to be regenerated when the .gatt file is updated. + +// To generate ~/pico-examples/build/pico_w/bt/gatt_midi/generated/gatt_midi.h: +// ~/pico-sdk/lib/btstack/tool/compile_gatt.py ~/pico-sdk/lib/btstack/example/gatt_midi.gatt ~/pico-examples/build/pico_w/bt/gatt_midi/generated/gatt_midi.h + +// att db format version 1 + +// binary attribute representation: +// - size in bytes (16), flags(16), handle (16), uuid (16/128), value(...) + +#include + +// Reference: https://en.cppreference.com/w/cpp/feature_test +#if __cplusplus >= 200704L +constexpr +#endif +const uint8_t profile_data[] = +{ + // ATT DB Version + 1, + + // 0x0001 PRIMARY_SERVICE-GATT_SERVICE + 0x0a, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x28, 0x01, 0x18, + // 0x0002 CHARACTERISTIC-GATT_DATABASE_HASH - READ + 0x0d, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x28, 0x02, 0x03, 0x00, 0x2a, 0x2b, + // 0x0003 VALUE CHARACTERISTIC-GATT_DATABASE_HASH - READ -'' + // READ_ANYBODY + 0x18, 0x00, 0x02, 0x00, 0x03, 0x00, 0x2a, 0x2b, 0x81, 0x7e, 0xe3, 0x3a, 0xc7, 0x7b, 0x2e, 0xcd, 0x01, 0x0a, 0x6c, 0xe7, 0xfb, 0xb9, 0xb9, 0x68, + // MIDI Service + // 0x0004 PRIMARY_SERVICE-03B80E5A-EDE8-4B33-A751-6CE34EC4C700 + 0x18, 0x00, 0x02, 0x00, 0x04, 0x00, 0x00, 0x28, 0x00, 0xc7, 0xc4, 0x4e, 0xe3, 0x6c, 0x51, 0xa7, 0x33, 0x4b, 0xe8, 0xed, 0x5a, 0x0e, 0xb8, 0x03, + // MIDI Characteristic + // 0x0005 CHARACTERISTIC-7772E5DB-3868-4112-A1A9-F2669D106BF3 - READ | WRITE_WITHOUT_RESPONSE | NOTIFY | DYNAMIC + 0x1b, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x28, 0x16, 0x06, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, + // 0x0006 VALUE CHARACTERISTIC-7772E5DB-3868-4112-A1A9-F2669D106BF3 - READ | WRITE_WITHOUT_RESPONSE | NOTIFY | DYNAMIC + // READ_ANYBODY, WRITE_ANYBODY + 0x16, 0x00, 0x06, 0x03, 0x06, 0x00, 0xf3, 0x6b, 0x10, 0x9d, 0x66, 0xf2, 0xa9, 0xa1, 0x12, 0x41, 0x68, 0x38, 0xdb, 0xe5, 0x72, 0x77, + // 0x0007 CLIENT_CHARACTERISTIC_CONFIGURATION + // READ_ANYBODY, WRITE_ANYBODY + 0x0a, 0x00, 0x0e, 0x01, 0x07, 0x00, 0x02, 0x29, 0x00, 0x00, + // END + 0x00, 0x00, +}; // total size 76 bytes + + +// +// list service handle ranges +// +#define ATT_SERVICE_GATT_SERVICE_START_HANDLE 0x0001 +#define ATT_SERVICE_GATT_SERVICE_END_HANDLE 0x0003 +#define ATT_SERVICE_GATT_SERVICE_01_START_HANDLE 0x0001 +#define ATT_SERVICE_GATT_SERVICE_01_END_HANDLE 0x0003 +#define ATT_SERVICE_03B80E5A_EDE8_4B33_A751_6CE34EC4C700_START_HANDLE 0x0004 +#define ATT_SERVICE_03B80E5A_EDE8_4B33_A751_6CE34EC4C700_END_HANDLE 0x0007 +#define ATT_SERVICE_03B80E5A_EDE8_4B33_A751_6CE34EC4C700_01_START_HANDLE 0x0004 +#define ATT_SERVICE_03B80E5A_EDE8_4B33_A751_6CE34EC4C700_01_END_HANDLE 0x0007 + +// +// list mapping between characteristics and handles +// +#define ATT_CHARACTERISTIC_GATT_DATABASE_HASH_01_VALUE_HANDLE 0x0003 +#define ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_VALUE_HANDLE 0x0006 +#define ATT_CHARACTERISTIC_7772E5DB_3868_4112_A1A9_F2669D106BF3_01_CLIENT_CONFIGURATION_HANDLE 0x0007 diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp new file mode 100644 index 0000000..b927a2e --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/gatt_midi.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include "../BLEAPI.hpp" + +namespace cs::midi_ble_btstack { + +bool init(MIDIBLEInstance &instance, BLESettings settings); +void notify(BLEConnectionHandle conn_handle, + BLECharacteristicHandle char_handle, BLEDataView data); + +} // namespace cs::midi_ble_btstack diff --git a/MIDI_Interfaces/BLEMIDI/BTstack/hci_event_names.hpp b/MIDI_Interfaces/BLEMIDI/BTstack/hci_event_names.hpp new file mode 100644 index 0000000..9a282af --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstack/hci_event_names.hpp @@ -0,0 +1,426 @@ +#pragma once + +namespace cs::midi_ble_btstack { + +constexpr const char *hci_event_names[256] { + "NOP", + "INQUIRY_COMPLETE", + "INQUIRY_RESULT", + "CONNECTION_COMPLETE", + "CONNECTION_REQUEST", + "DISCONNECTION_COMPLETE", + "AUTHENTICATION_COMPLETE", + "REMOTE_NAME_REQUEST_COMPLETE", + "ENCRYPTION_CHANGE", + "CHANGE_CONNECTION_LINK_KEY_COMPLETE", + "MASTER_LINK_KEY_COMPLETE", + "READ_REMOTE_SUPPORTED_FEATURES_COMPLETE", + "READ_REMOTE_VERSION_INFORMATION_COMPLETE", + "QOS_SETUP_COMPLETE", + "COMMAND_COMPLETE", + "COMMAND_STATUS", + "HARDWARE_ERROR", + "FLUSH_OCCURRED", + "ROLE_CHANGE", + "NUMBER_OF_COMPLETED_PACKETS", + "MODE_CHANGE", + "RETURN_LINK_KEYS", + "PIN_CODE_REQUEST", + "LINK_KEY_REQUEST", + "LINK_KEY_NOTIFICATION", + "LOOPBACK_COMMAND", + "DATA_BUFFER_OVERFLOW", + "MAX_SLOTS_CHANGED", + "READ_CLOCK_OFFSET_COMPLETE", + "CONNECTION_PACKET_TYPE_CHANGED", + "QOS_VIOLATION", + "(unknown)", + "PAGE_SCAN_REPETITION_MODE_CHANGE", + "FLOW_SPECIFICATION_COMPLETE", + "INQUIRY_RESULT_WITH_RSSI", + "READ_REMOTE_EXTENDED_FEATURES_COMPLETE", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "SYNCHRONOUS_CONNECTION_COMPLETE", + "SYNCHRONOUS_CONNECTION_CHANGED", + "SNIFF_SUBRATING", + "EXTENDED_INQUIRY_RESPONSE", + "ENCRYPTION_KEY_REFRESH_COMPLETE", + "IO_CAPABILITY_REQUEST", + "IO_CAPABILITY_RESPONSE", + "USER_CONFIRMATION_REQUEST", + "USER_PASSKEY_REQUEST", + "REMOTE_OOB_DATA_REQUEST", + "SIMPLE_PAIRING_COMPLETE", + "(unknown)", + "LINK_SUPERVISION_TIMEOUT_CHANGED", + "ENHANCED_FLUSH_COMPLETE", + "(unknown)", + "USER_PASSKEY_NOTIFICATION", + "KEYPRESS_NOTIFICATION", + "REMOTE_HOST_SUPPORTED_FEATURES", + "LE_META", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "NUMBER_OF_COMPLETED_DATA_BLOCKS", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "ENCRYPTION_CHANGE_V2", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "TRANSPORT_SLEEP_MODE", + "TRANSPORT_USB_INFO", + "BIS_CAN_SEND_NOW", + "CIS_CAN_SEND_NOW", + "TRANSPORT_READY", + "TRANSPORT_PACKET_SENT", + "SCO_CAN_SEND_NOW", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "GATT_EVENT_QUERY_COMPLETE", + "GATT_EVENT_SERVICE_QUERY_RESULT", + "GATT_EVENT_CHARACTERISTIC_QUERY_RESULT", + "GATT_EVENT_INCLUDED_SERVICE_QUERY_RESULT", + "GATT_EVENT_ALL_CHARACTERISTIC_DESCRIPTORS_QUERY_RESULT", + "GATT_EVENT_CHARACTERISTIC_VALUE_QUERY_RESULT", + "GATT_EVENT_LONG_CHARACTERISTIC_VALUE_QUERY_RESULT", + "GATT_EVENT_NOTIFICATION", + "GATT_EVENT_INDICATION", + "GATT_EVENT_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT", + "GATT_EVENT_LONG_CHARACTERISTIC_DESCRIPTOR_QUERY_RESULT", + "GATT_EVENT_MTU", + "GATT_EVENT_CAN_WRITE_WITHOUT_RESPONSE", + "GATT_EVENT_CONNECTED", + "GATT_EVENT_DISCONNECTED", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "ATT_EVENT_CONNECTED", + "ATT_EVENT_DISCONNECTED", + "ATT_EVENT_MTU_EXCHANGE_COMPLETE", + "ATT_EVENT_HANDLE_VALUE_INDICATION_COMPLETE", + "ATT_EVENT_CAN_SEND_NOW", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "BNEP_EVENT_SERVICE_REGISTERED", + "BNEP_EVENT_CHANNEL_OPENED", + "BNEP_EVENT_CHANNEL_CLOSED", + "BNEP_EVENT_CHANNEL_TIMEOUT", + "BNEP_EVENT_CAN_SEND_NOW", + "(unknown)", + "(unknown)", + "(unknown)", + "SM_EVENT_JUST_WORKS_REQUEST", + "SM_EVENT_PASSKEY_DISPLAY_NUMBER", + "SM_EVENT_PASSKEY_DISPLAY_CANCEL", + "SM_EVENT_PASSKEY_INPUT_NUMBER", + "SM_EVENT_NUMERIC_COMPARISON_REQUEST", + "SM_EVENT_IDENTITY_RESOLVING_STARTED", + "SM_EVENT_IDENTITY_RESOLVING_FAILED", + "SM_EVENT_IDENTITY_RESOLVING_SUCCEEDED", + "SM_EVENT_AUTHORIZATION_REQUEST", + "SM_EVENT_AUTHORIZATION_RESULT", + "SM_EVENT_KEYPRESS_NOTIFICATION", + "SM_EVENT_IDENTITY_CREATED", + "SM_EVENT_PAIRING_STARTED", + "SM_EVENT_PAIRING_COMPLETE", + "SM_EVENT_REENCRYPTION_STARTED", + "SM_EVENT_REENCRYPTION_COMPLETE", + "GAP_EVENT_SECURITY_LEVEL", + "GAP_EVENT_DEDICATED_BONDING_COMPLETED", + "GAP_EVENT_ADVERTISING_REPORT", + "GAP_EVENT_EXTENDED_ADVERTISING_REPORT", + "GAP_EVENT_INQUIRY_RESULT", + "GAP_EVENT_INQUIRY_COMPLETE", + "GAP_EVENT_RSSI_MEASUREMENT", + "GAP_EVENT_LOCAL_OOB_DATA", + "GAP_EVENT_PAIRING_STARTED", + "GAP_EVENT_PAIRING_COMPLETE", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "META_GAP", + "HSP_META", + "HFP_META", + "ANCS_META", + "AVDTP_META", + "AVRCP_META", + "GOEP_META", + "PBAP_META", + "HID_META", + "A2DP_META", + "HIDS_META", + "GATTSERVICE_META", + "BIP_META", + "MAP_META", + "MESH_META", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "VENDOR_SPECIFIC", +}; + +constexpr const char *gattservice_event_names[114] { + "(unknown)", + "CYCLING_POWER_START_CALIBRATION", + "CYCLING_POWER_BROADCAST_START", + "CYCLING_POWER_BROADCAST_STOP", + "BATTERY_SERVICE_CONNECTED", + "BATTERY_SERVICE_LEVEL", + "DEVICE_INFORMATION_DONE", + "DEVICE_INFORMATION_MANUFACTURER_NAME", + "DEVICE_INFORMATION_MODEL_NUMBER", + "DEVICE_INFORMATION_SERIAL_NUMBER", + "DEVICE_INFORMATION_HARDWARE_REVISION", + "DEVICE_INFORMATION_FIRMWARE_REVISION", + "DEVICE_INFORMATION_SOFTWARE_REVISION", + "DEVICE_INFORMATION_SYSTEM_ID", + "DEVICE_INFORMATION_IEEE_REGULATORY_CERTIFICATION", + "DEVICE_INFORMATION_PNP_ID", + "SCAN_PARAMETERS_SERVICE_CONNECTED", + "SPP_SERVICE_CONNECTED", + "SPP_SERVICE_DISCONNECTED", + "HID_SERVICE_CONNECTED", + "HID_REPORT", + "HID_INFORMATION", + "HID_PROTOCOL_MODE", + "HID_SERVICE_REPORTS_NOTIFICATION", + "SCAN_PARAMETERS_SERVICE_SCAN_INTERVAL_UPDATE", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "BASS_SERVER_SCAN_STOPPED", + "BASS_SERVER_SCAN_STARTED", + "BASS_SERVER_BROADCAST_CODE", + "BASS_SERVER_SOURCE_ADDED", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "BASS_SERVER_SOURCE_MODIFIED", + "BASS_SERVER_SOURCE_DELETED", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "BASS_CLIENT_CONNECTED", + "BASS_CLIENT_DISCONNECTED", + "BASS_CLIENT_SCAN_OPERATION_COMPLETE", + "BASS_NOTIFY_RECEIVE_STATE_BASE", + "BASS_CLIENT_NOTIFY_RECEIVE_STATE_SUBGROUP", + "BASS_CLIENT_NOTIFICATION_COMPLETE", + "BASS_CLIENT_SOURCE_OPERATION_COMPLETE", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "(unknown)", + "BASS_SERVER_CONNECTED", + "BASS_SERVER_DISCONNECTED", +}; + +constexpr const char *le_event_names[42] { + "(unknown)", + "HCI_SUBEVENT_LE_CONNECTION_COMPLETE", + "HCI_SUBEVENT_LE_ADVERTISING_REPORT", + "HCI_SUBEVENT_LE_CONNECTION_UPDATE_COMPLETE", + "HCI_SUBEVENT_LE_READ_REMOTE_FEATURES_COMPLETE", + "HCI_SUBEVENT_LE_LONG_TERM_KEY_REQUEST", + "HCI_SUBEVENT_LE_REMOTE_CONNECTION_PARAMETER_REQUEST", + "HCI_SUBEVENT_LE_DATA_LENGTH_CHANGE", + "HCI_SUBEVENT_LE_READ_LOCAL_P256_PUBLIC_KEY_COMPLETE", + "HCI_SUBEVENT_LE_GENERATE_DHKEY_COMPLETE", + "HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V1", + "HCI_SUBEVENT_LE_DIRECT_ADVERTISING_REPORT", + "HCI_SUBEVENT_LE_PHY_UPDATE_COMPLETE", + "HCI_SUBEVENT_LE_EXTENDED_ADVERTISING_REPORT", + "HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_ESTABLISHMENT", + "HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_REPORT", + "HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_LOST", + "HCI_SUBEVENT_LE_SCAN_TIMEOUT", + "HCI_SUBEVENT_LE_ADVERTISING_SET_TERMINATED", + "HCI_SUBEVENT_LE_SCAN_REQUEST_RECEIVED", + "HCI_SUBEVENT_LE_CHANNEL_SELECTION_ALGORITHM", + "HCI_SUBEVENT_LE_CONNECTIONLESS_IQ_REPORT", + "HCI_SUBEVENT_LE_CONNECTION_IQ_REPORT", + "HCI_SUBEVENT_LE_LE_CTE_REQUEST_FAILED", + "HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_SYNC_TRANSFER_RECEIVED", + "HCI_SUBEVENT_LE_CIS_ESTABLISHED", + "HCI_SUBEVENT_LE_CIS_REQUEST", + "HCI_SUBEVENT_LE_CREATE_BIG_COMPLETE", + "HCI_SUBEVENT_LE_TERMINATE_BIG_COMPLETE", + "HCI_SUBEVENT_LE_BIG_SYNC_ESTABLISHED", + "HCI_SUBEVENT_LE_BIG_SYNC_LOST", + "HCI_SUBEVENT_LE_REQUEST_PEER_SCA_COMPLETE", + "(unknown)", + "HCI_SUBEVENT_LE_TRANSMIT_POWER_REPORTING", + "HCI_SUBEVENT_LE_BIGINFO_ADVERTISING_REPORT", + "HCI_SUBEVENT_LE_SUBRATE_CHANGE", + "(unknown)", + "(unknown)", + "(unknown)", + "HCI_SUBEVENT_LE_PERIODIC_ADVERTISING_DATA_REQUEST", + "(unknown)", + "HCI_SUBEVENT_LE_ENHANCED_CONNECTION_COMPLETE_V2", +}; + +} // namespace cs::midi_ble_btstack diff --git a/MIDI_Interfaces/BLEMIDI/BTstackBackgroundBackend.hpp b/MIDI_Interfaces/BLEMIDI/BTstackBackgroundBackend.hpp new file mode 100644 index 0000000..0ed927c --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BTstackBackgroundBackend.hpp @@ -0,0 +1,135 @@ +#pragma once + +#include + +#include "BLEAPI.hpp" +#include "BTstack/gatt_midi.hpp" +#include "BufferedBLEMIDIParser.hpp" +#include "PollingBLEMIDISender.hpp" + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/// Raspberry Pi Pico BTstack background backend intended to be plugged into +/// @ref GenericBLEMIDI_Interface. +/// +/// @todo Implement BTstack timer-based sender timeouts. +class BTstackBackgroundBackend + : private PollingBLEMIDISender, + private MIDIBLEInstance { + private: + // Callbacks from the ArduinoBLE stack. + void handleConnect(BLEConnectionHandle conn_handle) override { + connected = conn_handle.conn; + } + void handleDisconnect(BLEConnectionHandle) override { + connected = subscribed = 0xFFFF; + } + void handleMTU(BLEConnectionHandle, uint16_t mtu) override { + Sender::updateMTU(mtu); + } + void handleSubscribe(BLEConnectionHandle, + BLECharacteristicHandle char_handle, + bool notify) override { + subscribed = notify ? char_handle.characteristic : 0xFFFF; + } + void handleData(BLEConnectionHandle, BLEDataGenerator &&data, + BLEDataLifetime) override { + while (true) { + BLEDataView packet = data(); + if (packet.length == 0) { + break; + } else if (!parser.pushPacket(packet)) { + DEBUGREF(F("BLE packet dropped, size: ") << packet.length); + break; + } + } + } + + private: + // We cannot use atomics here, because they might not be lock-free on the + // Pico's Cortex-M0+ cores. + static_assert(sizeof(sig_atomic_t) > sizeof(uint16_t)); + /// Are we connected to a BLE Central? + volatile sig_atomic_t connected = 0xFFFF; + /// Did the BLE Central subscribe to be notified for the MIDI characteristic? + volatile sig_atomic_t subscribed = 0xFFFF; + struct VolatileSize { + constexpr static size_t alignment = alignof(sig_atomic_t); + VolatileSize(sig_atomic_t value) : value {value} {} + volatile sig_atomic_t value; + sig_atomic_t load_acquire() const { + auto state = save_and_disable_interrupts(); // Probably overkill ... + auto t = value; + restore_interrupts(state); + std::atomic_signal_fence(std::memory_order_acquire); + return t; + } + void add_release(sig_atomic_t t) { + std::atomic_signal_fence(std::memory_order_release); + auto state = save_and_disable_interrupts(); + value += t; + restore_interrupts(state); + } + void sub_release(sig_atomic_t t) { + std::atomic_signal_fence(std::memory_order_release); + auto state = save_and_disable_interrupts(); + value -= t; + restore_interrupts(state); + } + }; + /// Contains incoming BLE MIDI data to be parsed. + BufferedBLEMIDIParser<1024, VolatileSize> parser; + + public: + using IncomingMIDIMessage = AnyMIDIMessage; + + /// Retrieve and remove a single incoming MIDI message from the buffer. + bool popMessage(IncomingMIDIMessage &incomingMessage) { + // This function is assumed to be polled regularly by the higher-level + // MIDI_Interface, so we check the sender's timer here. + auto lck = Sender::acquirePacket(); + Sender::releasePacketAndNotify(lck); + // Actually get a MIDI message from the buffer + return parser.popMessage(incomingMessage); + } + + public: + /// Initialize the BLE stack etc. + void begin(BLESettings ble_settings) { + midi_ble_btstack::init(*this, ble_settings); + Sender::begin(); + } + /// Deinitialize the BLE stack. + /// @todo Not yet implemented. + void end() {} + /// Returns true if we are connected to a BLE Central device. + bool isConnected() const { return connected != 0xFFFF; } + + private: + // Implement the interface for the BLE sender. + using Sender = PollingBLEMIDISender; + friend Sender; + /// Send the given MIDI BLE packet. + void sendData(BLEDataView data) { + if (connected != 0xFFFF && subscribed != 0xFFFF) + midi_ble_btstack::notify( + BLEConnectionHandle {static_cast(connected)}, + BLECharacteristicHandle {static_cast(subscribed)}, + data); + } + + public: + // Expose the necessary BLE sender functions. + using Sender::acquirePacket; + using Sender::forceMinMTU; + using Sender::getMinMTU; + using Sender::releasePacketAndNotify; + using Sender::sendNow; + using Sender::setTimeout; +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/BufferedBLEMIDIParser.hpp b/MIDI_Interfaces/BLEMIDI/BufferedBLEMIDIParser.hpp new file mode 100644 index 0000000..bd9e3cd --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/BufferedBLEMIDIParser.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include "BLERingBuf.hpp" +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/// FIFO buffer that you can push BLE packets into, and pop MIDI messages out of. +/// If @p SizeT is chosen to be atomic, one thread can push packets, and another +/// thread can pop MIDI messages, without additional synchronization. +template > +class BufferedBLEMIDIParser { + private: + /// Contains incoming data to be parsed. + BLERingBuf ble_buffer {}; + /// Parses the (chunked) BLE packet obtained from @ref ble_buffer. + BLEMIDIParser ble_parser {nullptr, 0}; + /// Parser for MIDI data extracted from the BLE packet by @ref ble_parser. + SerialMIDI_Parser parser {false}; + + public: + using IncomingMIDIMessage = AnyMIDIMessage; + + /// Add a new BLE packet or chunk to the buffer. + bool pushPacket(BLEDataView packet, + BLEDataType type = BLEDataType::Packet) { + return ble_buffer.push(packet, type); + } + + /// Retrieve and remove a single incoming MIDI message from the buffer. + bool popMessage(IncomingMIDIMessage &incomingMessage) { + // Try reading a MIDI message from the parser + auto try_read = [&] { + MIDIReadEvent event = parser.pull(ble_parser); + switch (event) { + case MIDIReadEvent::CHANNEL_MESSAGE: + incomingMessage = {parser.getChannelMessage(), + ble_parser.getTimestamp()}; + return true; + case MIDIReadEvent::SYSEX_CHUNK: // fallthrough + case MIDIReadEvent::SYSEX_MESSAGE: + incomingMessage = {parser.getSysExMessage(), + ble_parser.getTimestamp()}; + return true; + case MIDIReadEvent::REALTIME_MESSAGE: + incomingMessage = {parser.getRealTimeMessage(), + ble_parser.getTimestamp()}; + return true; + case MIDIReadEvent::SYSCOMMON_MESSAGE: + incomingMessage = {parser.getSysCommonMessage(), + ble_parser.getTimestamp()}; + return true; + case MIDIReadEvent::NO_MESSAGE: return false; + default: break; // LCOV_EXCL_LINE + } + return false; + }; + while (true) { + // Try reading a MIDI message from the current buffer + if (try_read()) + return true; // success, incomingMessage updated + // Get the next chunk of the BLE packet (if available) + BLEDataView chunk; + auto popped = ble_buffer.pop(chunk); + if (popped == BLEDataType::None) + return false; // no more BLE data available + else if (popped == BLEDataType::Continuation) + ble_parser.extend(chunk.data, chunk.length); // same BLE packet + else if (popped == BLEDataType::Packet) + ble_parser = {chunk.data, chunk.length}; // new BLE packet + } + } +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.hpp b/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.hpp new file mode 100644 index 0000000..1efe87f --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.hpp @@ -0,0 +1,79 @@ +#pragma once + +#include + +#include + +#include "BLEAPI.hpp" +#include + +BEGIN_CS_NAMESPACE + +/// Class that buffers MIDI BLE packets. +template +class PollingBLEMIDISender { + public: + PollingBLEMIDISender() = default; + PollingBLEMIDISender(const PollingBLEMIDISender &) = delete; + PollingBLEMIDISender &operator=(const PollingBLEMIDISender &) = delete; + ~PollingBLEMIDISender(); + + /// Initialize. + void begin(); + + /// RAII lock for access to the packet builder. + struct ProtectedBuilder; + /// Acquire exclusive access to the buffer. + /// @return A RAII wrapper that automatically releases the buffer upon + /// destruction. Just make sure you don't keep any pointers to the + /// `packet` member. + ProtectedBuilder acquirePacket(); + /// Release exclusive access to the buffer and notify the sender thread that + /// data is available. + void releasePacketAndNotify(ProtectedBuilder &lck); + + /// Sends the data immediately without waiting for the timeout. + void sendNow(ProtectedBuilder &lck); + + /// Set the maximum transmission unit of the Bluetooth link. Used to compute + /// the MIDI BLE packet size. + void updateMTU(uint16_t mtu); + /// Get the minimum MTU of all connected clients. + uint16_t getMinMTU() const { return min_mtu; } + /// Force the MTU to an artificially small value (used for testing). + void forceMinMTU(uint16_t mtu); + + /// Set the timeout, the number of milliseconds to buffer the outgoing MIDI + /// messages. + void setTimeout(std::chrono::milliseconds timeout); + + private: + /// Actually perform the BLE notification with the given data. + void sendData(BLEDataView) = delete; // should be implemented by subclass + + private: + /// View of the data to send + BLEMIDIPacketBuilder packet; + /// Timeout before the sender thread sends a packet. + /// @see @ref setTimeout() + unsigned long timeout {10}; + /// Time point when the packet was started. + unsigned long packet_start_time {0}; + + private: + /// The minimum MTU of all connected clients. + uint16_t min_mtu {23}; + /// Override the minimum MTU (0 means don't override, nonzero overrides if + /// it's smaller than the minimum MTU of the clients). + /// @see @ref forceMinMTU() + uint16_t force_min_mtu {515}; + + public: + struct ProtectedBuilder { + BLEMIDIPacketBuilder *packet; + }; +}; + +END_CS_NAMESPACE + +#include "PollingBLEMIDISender.ipp" diff --git a/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.ipp b/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.ipp new file mode 100644 index 0000000..b211576 --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/PollingBLEMIDISender.ipp @@ -0,0 +1,59 @@ +#include "PollingBLEMIDISender.hpp" + +#include + +BEGIN_CS_NAMESPACE + +template +PollingBLEMIDISender::~PollingBLEMIDISender() = default; + +template +void PollingBLEMIDISender::begin() {} + +template +auto PollingBLEMIDISender::acquirePacket() -> ProtectedBuilder { + if (packet.getSize() == 0) + packet_start_time = millis(); + return {&packet}; +} + +template +void PollingBLEMIDISender::releasePacketAndNotify(ProtectedBuilder &lck) { + if (lck.packet->getSize() > 0 && millis() - packet_start_time > timeout) + sendNow(lck); +} + +template +void PollingBLEMIDISender::sendNow(ProtectedBuilder &lck) { + BLEDataView data {lck.packet->getBuffer(), lck.packet->getSize()}; + if (data.length > 0) { + CRTP(Derived).sendData(data); + lck.packet->reset(); + lck.packet->setCapacity(min_mtu - 3); + } +} + +template +void PollingBLEMIDISender::updateMTU(uint16_t mtu) { + if (force_min_mtu == 0) + min_mtu = mtu; + else + min_mtu = std::min(force_min_mtu, mtu); + DEBUGFN(NAMEDVALUE(min_mtu)); + auto lck = acquirePacket(); + if (lck.packet->getSize() == 0) + lck.packet->setCapacity(min_mtu - 3); +} + +template +void PollingBLEMIDISender::forceMinMTU(uint16_t mtu) { + force_min_mtu = mtu; + updateMTU(min_mtu); +} + +template +void PollingBLEMIDISender::setTimeout(std::chrono::milliseconds timeout) { + this->timeout = timeout.count(); +} + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/BLEMIDI/Util/compat.hpp b/MIDI_Interfaces/BLEMIDI/Util/compat.hpp new file mode 100644 index 0000000..538275a --- /dev/null +++ b/MIDI_Interfaces/BLEMIDI/Util/compat.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +#if __cplusplus >= 201703L + +namespace compat { +using std::byte; +using std::in_place; +using std::in_place_t; +using std::in_place_type; +using std::in_place_type_t; +} // namespace compat + +#else + +namespace compat { +struct in_place_t { + explicit in_place_t() = default; +}; +static in_place_t in_place {}; +template +struct in_place_type_t { + explicit in_place_type_t() = default; +}; +template +static in_place_type_t in_place_type {}; +enum class byte : unsigned char {}; +} // namespace compat + +#endif + +#if __cplusplus >= 202002L + +namespace compat { +using std::remove_cvref; +} // namespace compat + +#else + +namespace compat { +template +struct remove_cvref { + using type = + typename std::remove_cv::type>::type; +}; +} // namespace compat + +#endif + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/GenericBLEMIDI_Interface.hpp b/MIDI_Interfaces/GenericBLEMIDI_Interface.hpp new file mode 100644 index 0000000..31ea604 --- /dev/null +++ b/MIDI_Interfaces/GenericBLEMIDI_Interface.hpp @@ -0,0 +1,115 @@ +#pragma once + +#include + +#include "BLEMIDI/BLEAPI.hpp" +#include "MIDI_Interface.hpp" + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief Bluetooth Low Energy MIDI Interface. + */ +template +class GenericBLEMIDI_Interface : public MIDI_Interface { + public: + template + GenericBLEMIDI_Interface(Args &&...args) + : backend {std::forward(args)...} {} + + private: + // MIDI send implementations + template + void sendImpl(L &lck, F add_to_buffer); + void sendChannelMessageImpl(ChannelMessage) override; + void sendSysCommonImpl(SysCommonMessage) override; + void sendSysExImpl(SysExMessage) override; + void sendRealTimeImpl(RealTimeMessage) override; + void sendNowImpl() override; + + private: +#if !DISABLE_PIPES + void handleStall() override { MIDI_Interface::handleStall(this); } +#ifdef DEBUG_OUT + const char *getName() const override { return "ble"; } +#endif +#endif + + public: + /// @name Initialization and polling + /// @{ + + /// Initialize the BLE hardware and start advertising as a MIDI over BLE + /// peripheral. + void begin() override; + /// @todo Currently not implemented. + void end(); + /// Poll the backend (if necessary) and invoke the callbacks for any + /// received MIDI messages, as well as sending them over the pipes connected + /// to this interface. + void update() override { MIDI_Interface::updateIncoming(this); } + /// Returns true if a BLE central is currently connected. + /// @note This is useful for e.g. turning on/off an LED or showing a + /// message to the user, but it's not all that useful for anything + /// else, because the connection could be terminated at any moment. + bool isConnected() const { return backend.isConnected(); } + + /// @} + + public: + /// @name Reading incoming MIDI messages + /// @{ + + /// Try reading and parsing a single incoming MIDI message. + /// @return Returns the type of the message read, or + /// `MIDIReadEvent::NO_MESSAGE` if no MIDI message was available. + MIDIReadEvent read(); + + /// Return the received channel voice message. + ChannelMessage getChannelMessage() const; + /// Return the received system common message. + SysCommonMessage getSysCommonMessage() const; + /// Return the received real-time message. + RealTimeMessage getRealTimeMessage() const; + /// Return the received system exclusive message. + SysExMessage getSysExMessage() const; + /// Get the BLE-MIDI timestamp of the latest MIDI message. + /// @note Invalid for SysEx chunks (except the last chunk of a message). + uint16_t getTimestamp() const; + + /// @} + + private: + /// Incoming message that can be from retrieved using the + /// `getChannelMessage()`, `getSysCommonMessage()`, `getRealTimeMessage()` + /// and `getSysExMessage()` methods. + typename Backend::IncomingMIDIMessage incomingMessage; + + public: + /// @name BLE configuration options + /// @{ + + /// Set the BLE device name. Must be called before @ref begin(). + /// Length is limited by the size of the BLE advertising packets. + void setName(const char *name); + /// Set the timeout, the number of milliseconds to buffer the outgoing MIDI + /// messages. A shorter timeout usually results in lower latency, but also + /// causes more overhead, because more packets might be required. + void setTimeout(std::chrono::milliseconds timeout) { + backend.setTimeout(timeout); + } + /// BLE backend configuration option. + BLESettings ble_settings; + + /// @} + + public: + /// Low-level BLE backend for sending and receiving MIDI over BLE packets. + Backend backend; +}; + +END_CS_NAMESPACE + +#include "GenericBLEMIDI_Interface.ipp" diff --git a/MIDI_Interfaces/GenericBLEMIDI_Interface.ipp b/MIDI_Interfaces/GenericBLEMIDI_Interface.ipp new file mode 100644 index 0000000..e5d8efe --- /dev/null +++ b/MIDI_Interfaces/GenericBLEMIDI_Interface.ipp @@ -0,0 +1,168 @@ +#include "GenericBLEMIDI_Interface.hpp" + +BEGIN_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +// The following section implements the MIDI sending functions. + +template +template +void GenericBLEMIDI_Interface::sendImpl(L &lck, F add_to_buffer) { + // BLE packets are sent asynchronously, so we need a lock to access the + // packet buffer + // assert(lck.lck.owns_lock()); + + // Try adding the message to the current packet + if (!add_to_buffer()) { + // If that doesn't work, flush the packet (send it now and wait until + // it is sent) + backend.sendNow(lck); + // And then add it to the (now emtpy) buffer + add_to_buffer(); + } + // Notify the sending thread that data has been added to the buffer + backend.releasePacketAndNotify(lck); +} + +template +void GenericBLEMIDI_Interface::sendChannelMessageImpl( + ChannelMessage msg) { + uint16_t timestamp = millis(); // BLE MIDI timestamp + auto lck = backend.acquirePacket(); + if (msg.hasTwoDataBytes()) { + sendImpl(lck, [&] { + return lck.packet->add3B(msg.header, msg.data1, msg.data2, + timestamp); + }); + } else { + sendImpl(lck, [&] { + return lck.packet->add2B(msg.header, msg.data1, timestamp); + }); + } +} + +template +void GenericBLEMIDI_Interface::sendRealTimeImpl(RealTimeMessage msg) { + uint16_t timestamp = millis(); // BLE MIDI timestamp + auto lck = backend.acquirePacket(); + sendImpl(lck, + [&] { return lck.packet->addRealTime(msg.message, timestamp); }); +} + +template +void GenericBLEMIDI_Interface::sendSysCommonImpl( + SysCommonMessage msg) { + uint16_t timestamp = millis(); // BLE MIDI timestamp + auto lck = backend.acquirePacket(); + sendImpl(lck, [&] { + return lck.packet->addSysCommon(msg.getNumberOfDataBytes(), msg.header, + msg.data1, msg.data2, timestamp); + }); +} + +template +void GenericBLEMIDI_Interface::sendSysExImpl(SysExMessage msg) { + uint16_t timestamp = millis(); // BLE MIDI timestamp + size_t length = msg.length; + const uint8_t *data = msg.data; + + // BLE packets are sent asynchronously, so we need a lock to access the + // packet buffer + auto lck = backend.acquirePacket(); + + // TODO: I have no idea why, but the last byte gets cut off when the LSB + // of the timestamp is 0x77 ... (Problem is probably in the BlueZ parser) + if ((timestamp & 0x77) == 0x77) + timestamp &= 0xFFFE; + + // Try adding at least the SysExStart header to the current packet + if (!lck.packet->addSysEx(data, length, timestamp)) { + // If that didn't fit, flush the packet + backend.sendNow(lck); + // Add the first part of the SysEx message to this packet + lck.packet->addSysEx(data, length, timestamp); + } + // As long as there's data to be sent in the next packet + while (data) { + // Send the previous (full) packet + backend.sendNow(lck); + // And add the next part of the SysEx message to a continuation packet + lck.packet->continueSysEx(data, length, timestamp); + } + // Notify the sending thread that data has been added to the buffer + backend.releasePacketAndNotify(lck); +} + +template +void GenericBLEMIDI_Interface::sendNowImpl() { + auto lck = backend.acquirePacket(); + backend.sendNow(lck); +} + +// -------------------------------------------------------------------------- // + +template +MIDIReadEvent GenericBLEMIDI_Interface::read() { + // Pop a new message from the queue + if (!backend.popMessage(incomingMessage)) + return MIDIReadEvent::NO_MESSAGE; + return incomingMessage.eventType; +} + +template +ChannelMessage GenericBLEMIDI_Interface::getChannelMessage() const { + return incomingMessage.eventType == MIDIReadEvent::CHANNEL_MESSAGE + ? incomingMessage.message.channelmessage + : ChannelMessage(0, 0, 0); +} + +template +SysCommonMessage +GenericBLEMIDI_Interface::getSysCommonMessage() const { + return incomingMessage.eventType == MIDIReadEvent::SYSCOMMON_MESSAGE + ? incomingMessage.message.syscommonmessage + : SysCommonMessage(0, 0, 0); +} + +template +RealTimeMessage GenericBLEMIDI_Interface::getRealTimeMessage() const { + return incomingMessage.eventType == MIDIReadEvent::REALTIME_MESSAGE + ? incomingMessage.message.realtimemessage + : RealTimeMessage(0); +} + +template +SysExMessage GenericBLEMIDI_Interface::getSysExMessage() const { + auto evt = incomingMessage.eventType; + bool hasSysEx = evt == MIDIReadEvent::SYSEX_MESSAGE || + evt == MIDIReadEvent::SYSEX_CHUNK; + return hasSysEx ? incomingMessage.message.sysexmessage + : SysExMessage(nullptr, 0); +} + +template +uint16_t GenericBLEMIDI_Interface::getTimestamp() const { + return incomingMessage.timestamp; +} + +// -------------------------------------------------------------------------- // + +template +void GenericBLEMIDI_Interface::setName(const char *name) { + ble_settings.device_name = name; +} + +template +void GenericBLEMIDI_Interface::begin() { + backend.begin(ble_settings); +} + +template +void GenericBLEMIDI_Interface::end() { + backend.end(); +} + +// -------------------------------------------------------------------------- // + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/MIDI_Callbacks.hpp b/MIDI_Interfaces/MIDI_Callbacks.hpp new file mode 100644 index 0000000..942e23f --- /dev/null +++ b/MIDI_Interfaces/MIDI_Callbacks.hpp @@ -0,0 +1,254 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class MIDI_Interface; + +// LCOV_EXCL_START + +/** + * @brief A class for callbacks from MIDI input. + */ +class MIDI_Callbacks { + public: + /// Callback for incoming MIDI Channel Messages (notes, control change, + /// pitch bend, etc.) + virtual void onChannelMessage(MIDI_Interface &, ChannelMessage) {} + /// Callback for incoming MIDI System Exclusive Messages. + virtual void onSysExMessage(MIDI_Interface &, SysExMessage) {} + /// Callback for incoming MIDI System Common Messages. + virtual void onSysCommonMessage(MIDI_Interface &, SysCommonMessage) {} + /// Callback for incoming MIDI Real-Time Messages. + virtual void onRealTimeMessage(MIDI_Interface &, RealTimeMessage) {} + + /// Destructor. + virtual ~MIDI_Callbacks() = default; +}; + +// LCOV_EXCL_STOP + +template +class FineGrainedMIDI_Callbacks : public MIDI_Callbacks { + protected: + /// @anchor FineGrainedMIDI_Callbacks_MIDI_Callback_Functions + /// @name MIDI Callback Functions + /// @{ + // clang-format off + void onNoteOff(Channel channel, uint8_t note, uint8_t velocity, Cable cable); + void onNoteOn(Channel channel, uint8_t note, uint8_t velocity, Cable cable); + void onKeyPressure(Channel channel, uint8_t note, uint8_t pressure, Cable cable); + void onControlChange(Channel channel, uint8_t controller, uint8_t value, Cable cable); + void onProgramChange(Channel channel, uint8_t program, Cable cable); + void onChannelPressure(Channel channel, uint8_t pressure, Cable cable); + void onPitchBend(Channel channel, uint16_t bend, Cable cable); + void onSystemExclusive(SysExMessage message); + void onTimeCodeQuarterFrame(uint8_t data, Cable cable); + void onSongPosition(uint16_t beats, Cable cable); + void onSongSelect(uint8_t songnumber, Cable cable); + void onTuneRequest(Cable cable); + void onClock(Cable cable); + void onStart(Cable cable); + void onContinue(Cable cable); + void onStop(Cable cable); + void onActiveSensing(Cable cable); + void onSystemReset(Cable cable); + // clang-format on + /// @} + + void onChannelMessage(MIDI_Interface &, ChannelMessage msg) override { + using MMT = MIDIMessageType; + switch (msg.getMessageType()) { + case MMT::None: break; + case MMT::NoteOff: + CRTP(Derived).onNoteOff(msg.getChannel(), msg.getData1(), + msg.getData2(), msg.getCable()); + break; + case MMT::NoteOn: + CRTP(Derived).onNoteOn(msg.getChannel(), msg.getData1(), + msg.getData2(), msg.getCable()); + break; + case MMT::KeyPressure: + CRTP(Derived).onKeyPressure(msg.getChannel(), msg.getData1(), + msg.getData2(), msg.getCable()); + break; + case MMT::ControlChange: + CRTP(Derived).onControlChange(msg.getChannel(), msg.getData1(), + msg.getData2(), msg.getCable()); + break; + case MMT::ProgramChange: + CRTP(Derived).onProgramChange(msg.getChannel(), msg.getData1(), + msg.getCable()); + break; + case MMT::ChannelPressure: + CRTP(Derived).onChannelPressure(msg.getChannel(), + msg.getData1(), msg.getCable()); + break; + case MMT::PitchBend: + CRTP(Derived).onPitchBend(msg.getChannel(), msg.getData14bit(), + msg.getCable()); + break; + case MMT::SysExStart: + case MMT::MTCQuarterFrame: + case MMT::SongPositionPointer: + case MMT::SongSelect: + case MMT::UndefinedSysCommon1: + case MMT::UndefinedSysCommon2: + case MMT::TuneRequest: + case MMT::SysExEnd: + case MMT::TimingClock: + case MMT::UndefinedRealTime1: + case MMT::Start: + case MMT::Continue: + case MMT::Stop: + case MMT::UndefinedRealTime2: + case MMT::ActiveSensing: + case MMT::SystemReset: + default: break; + } + } + + void onSysExMessage(MIDI_Interface &, SysExMessage msg) override { + CRTP(Derived).onSystemExclusive(msg); + } + + void onSysCommonMessage(MIDI_Interface &, SysCommonMessage msg) override { + using MMT = MIDIMessageType; + switch (msg.getMessageType()) { + case MMT::None: break; + case MMT::NoteOff: + case MMT::NoteOn: + case MMT::KeyPressure: + case MMT::ControlChange: + case MMT::ProgramChange: + case MMT::ChannelPressure: + case MMT::PitchBend: + case MMT::SysExStart: break; + case MMT::MTCQuarterFrame: + CRTP(Derived).onTimeCodeQuarterFrame(msg.getData1(), + msg.getCable()); + break; + case MMT::SongPositionPointer: + CRTP(Derived).onSongPosition(msg.getData14bit(), + msg.getCable()); + break; + case MMT::SongSelect: + CRTP(Derived).onSongSelect(msg.getData1(), msg.getCable()); + break; + case MMT::UndefinedSysCommon1: break; + case MMT::UndefinedSysCommon2: break; + case MMT::TuneRequest: + CRTP(Derived).onTuneRequest(msg.getCable()); + break; + case MMT::SysExEnd: + case MMT::TimingClock: + case MMT::UndefinedRealTime1: + case MMT::Start: + case MMT::Continue: + case MMT::Stop: + case MMT::UndefinedRealTime2: + case MMT::ActiveSensing: + case MMT::SystemReset: + default: break; + } + } + + void onRealTimeMessage(MIDI_Interface &, RealTimeMessage msg) override { + using MMT = MIDIMessageType; + switch (msg.getMessageType()) { + case MMT::None: break; + case MMT::NoteOff: + case MMT::NoteOn: + case MMT::KeyPressure: + case MMT::ControlChange: + case MMT::ProgramChange: + case MMT::ChannelPressure: + case MMT::PitchBend: + case MMT::SysExStart: + case MMT::MTCQuarterFrame: + case MMT::SongPositionPointer: + case MMT::SongSelect: + case MMT::UndefinedSysCommon1: + case MMT::UndefinedSysCommon2: + case MMT::TuneRequest: + case MMT::SysExEnd: break; + case MMT::TimingClock: CRTP(Derived).onClock(msg.getCable()); break; + case MMT::UndefinedRealTime1: break; + case MMT::Start: CRTP(Derived).onStart(msg.getCable()); break; + case MMT::Continue: CRTP(Derived).onContinue(msg.getCable()); break; + case MMT::Stop: CRTP(Derived).onStop(msg.getCable()); break; + case MMT::UndefinedRealTime2: break; + case MMT::ActiveSensing: + CRTP(Derived).onActiveSensing(msg.getCable()); + break; + case MMT::SystemReset: + CRTP(Derived).onSystemReset(msg.getCable()); + break; + default: break; + } + } + + /// @cond + + template + struct Dummy {}; + + template + static constexpr bool same_return_type_and_arguments(R1 (T1::*)(Args1...), + R2 (T2::*)(Args2...)) { + return std::is_same, Dummy>::value; + } + + public: + FineGrainedMIDI_Callbacks() { + // clang-format off + static_assert(std::is_base_of::value, "Invalid CRTP"); + static_assert(same_return_type_and_arguments(&Derived::onNoteOff, &FineGrainedMIDI_Callbacks::onNoteOff), "Incorrect signature for onNoteOff"); + static_assert(same_return_type_and_arguments(&Derived::onNoteOn, &FineGrainedMIDI_Callbacks::onNoteOn), "Incorrect signature for onNoteOn"); + static_assert(same_return_type_and_arguments(&Derived::onKeyPressure, &FineGrainedMIDI_Callbacks::onKeyPressure), "Incorrect signature for onKeyPressure"); + static_assert(same_return_type_and_arguments(&Derived::onControlChange, &FineGrainedMIDI_Callbacks::onControlChange), "Incorrect signature for onControlChange"); + static_assert(same_return_type_and_arguments(&Derived::onProgramChange, &FineGrainedMIDI_Callbacks::onProgramChange), "Incorrect signature for onProgramChange"); + static_assert(same_return_type_and_arguments(&Derived::onChannelPressure, &FineGrainedMIDI_Callbacks::onChannelPressure), "Incorrect signature for onChannelPressure"); + static_assert(same_return_type_and_arguments(&Derived::onPitchBend, &FineGrainedMIDI_Callbacks::onPitchBend), "Incorrect signature for onPitchBend"); + static_assert(same_return_type_and_arguments(&Derived::onSystemExclusive, &FineGrainedMIDI_Callbacks::onSystemExclusive), "Incorrect signature for onSystemExclusive"); + static_assert(same_return_type_and_arguments(&Derived::onTimeCodeQuarterFrame, &FineGrainedMIDI_Callbacks::onTimeCodeQuarterFrame), "Incorrect signature for onTimeCodeQuarterFrame"); + static_assert(same_return_type_and_arguments(&Derived::onSongPosition, &FineGrainedMIDI_Callbacks::onSongPosition), "Incorrect signature for onSongPosition"); + static_assert(same_return_type_and_arguments(&Derived::onSongSelect, &FineGrainedMIDI_Callbacks::onSongSelect), "Incorrect signature for onSongSelect"); + static_assert(same_return_type_and_arguments(&Derived::onTuneRequest, &FineGrainedMIDI_Callbacks::onTuneRequest), "Incorrect signature for onTuneRequest"); + static_assert(same_return_type_and_arguments(&Derived::onClock, &FineGrainedMIDI_Callbacks::onClock), "Incorrect signature for onClock"); + static_assert(same_return_type_and_arguments(&Derived::onStart, &FineGrainedMIDI_Callbacks::onStart), "Incorrect signature for onStart"); + static_assert(same_return_type_and_arguments(&Derived::onContinue, &FineGrainedMIDI_Callbacks::onContinue), "Incorrect signature for onContinue"); + static_assert(same_return_type_and_arguments(&Derived::onStop, &FineGrainedMIDI_Callbacks::onStop), "Incorrect signature for onStop"); + static_assert(same_return_type_and_arguments(&Derived::onActiveSensing, &FineGrainedMIDI_Callbacks::onActiveSensing), "Incorrect signature for onActiveSensing"); + static_assert(same_return_type_and_arguments(&Derived::onSystemReset, &FineGrainedMIDI_Callbacks::onSystemReset), "Incorrect signature for onSystemReset"); + // clang-format on + } + + /// @endcond +}; + +// clang-format off +template inline void FineGrainedMIDI_Callbacks::onNoteOff(Channel, uint8_t, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onNoteOn(Channel, uint8_t, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onKeyPressure(Channel, uint8_t, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onControlChange(Channel, uint8_t, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onProgramChange(Channel, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onChannelPressure(Channel, uint8_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onPitchBend(Channel, uint16_t, Cable) {} +template inline void FineGrainedMIDI_Callbacks::onSystemExclusive(SysExMessage) {} +template inline void FineGrainedMIDI_Callbacks::onTimeCodeQuarterFrame(uint8_t,Cable) {} +template inline void FineGrainedMIDI_Callbacks::onSongPosition(uint16_t,Cable) {} +template inline void FineGrainedMIDI_Callbacks::onSongSelect(uint8_t,Cable) {} +template inline void FineGrainedMIDI_Callbacks::onTuneRequest(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onClock(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onStart(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onContinue(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onStop(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onActiveSensing(Cable) {} +template inline void FineGrainedMIDI_Callbacks::onSystemReset(Cable) {} +// clang-format on + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/MIDI_Interface.cpp b/MIDI_Interfaces/MIDI_Interface.cpp new file mode 100644 index 0000000..04bc309 --- /dev/null +++ b/MIDI_Interfaces/MIDI_Interface.cpp @@ -0,0 +1,55 @@ +#include "MIDI_Interface.hpp" +#include "MIDI_Callbacks.hpp" + +BEGIN_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +// Managing the default MIDI interface + +MIDI_Interface::~MIDI_Interface() { + if (getDefault() == this) + DefaultMIDI_Interface = nullptr; +} + +void MIDI_Interface::setAsDefault() { DefaultMIDI_Interface = this; } + +#define DOWN_CAST static_cast + +MIDI_Interface *MIDI_Interface::getDefault() { + return DefaultMIDI_Interface == nullptr + ? DOWN_CAST(updatables.getLast()) + : DefaultMIDI_Interface; +} + +MIDI_Interface *MIDI_Interface::DefaultMIDI_Interface = nullptr; + +// -------------------------------------------------------------------------- // + +// Handling incoming MIDI events + +void MIDI_Interface::onChannelMessage(ChannelMessage message) { + sourceMIDItoPipe(message); + if (callbacks) + callbacks->onChannelMessage(*this, message); +} + +void MIDI_Interface::onSysExMessage(SysExMessage message) { + sourceMIDItoPipe(message); + if (callbacks) + callbacks->onSysExMessage(*this, message); +} + +void MIDI_Interface::onSysCommonMessage(SysCommonMessage message) { + sourceMIDItoPipe(message); + if (callbacks) + callbacks->onSysCommonMessage(*this, message); +} + +void MIDI_Interface::onRealTimeMessage(RealTimeMessage message) { + sourceMIDItoPipe(message); + if (callbacks) + callbacks->onRealTimeMessage(*this, message); +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Interfaces/MIDI_Interface.hpp b/MIDI_Interfaces/MIDI_Interface.hpp new file mode 100644 index 0000000..b36b72f --- /dev/null +++ b/MIDI_Interfaces/MIDI_Interface.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include "MIDI_Pipes.hpp" +#include "MIDI_Sender.hpp" +#include "MIDI_Staller.hpp" +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +constexpr auto MIDI_BAUD = 31250; + +class MIDI_Callbacks; + +/** + * @brief An abstract class for MIDI interfaces. + */ +class MIDI_Interface : public TrueMIDI_SinkSource, + public MIDI_Sender, + public AH::Updatable, + protected MIDIStaller { + protected: + MIDI_Interface() = default; + MIDI_Interface(MIDI_Interface &&) = default; + + public: + /// Destructor. + virtual ~MIDI_Interface(); + + /// Initialize the MIDI Interface. + void begin() override {} + /// Read the MIDI interface and call the callback if a message was received. + void update() override = 0; + + /// @name Default MIDI Interfaces + /// @{ + + /// Set this MIDI interface as the default interface. + void setAsDefault(); + /// Return the default MIDI interface. If the default MIDI interface was + /// configured explicitly using @ref setAsDefault(), that interface is + /// returned. If it wasn't set, or if that MIDI interface no longer exists, + /// this function returns the newest MIDI interface, the one that was + /// constructed most recently. If no MIDI interfaces exist, `nullptr` is + /// returned. + static MIDI_Interface *getDefault(); + + /// @} + + /// @name MIDI Input Callbacks + /// @{ + + /// Set the callbacks that will be called when a MIDI message is received. + /// @param cb + /// A pointer to the callback object. + void setCallbacks(MIDI_Callbacks *cb) { this->callbacks = cb; } + /// Set the callbacks that will be called when a MIDI message is received. + /// @param cb + /// A reference to the callback object. + void setCallbacks(MIDI_Callbacks &cb) { setCallbacks(&cb); } + + /// @} + + protected: + friend class MIDI_Sender; + /// Low-level function for sending a MIDI channel voice message. + virtual void sendChannelMessageImpl(ChannelMessage) = 0; + /// Low-level function for sending a MIDI system common message. + virtual void sendSysCommonImpl(SysCommonMessage) = 0; + /// Low-level function for sending a system exclusive MIDI message. + virtual void sendSysExImpl(SysExMessage) = 0; + /// Low-level function for sending a MIDI real-time message. + virtual void sendRealTimeImpl(RealTimeMessage) = 0; + /// Low-level function for sending any buffered outgoing MIDI messages. + virtual void sendNowImpl() = 0; + + public: +#if DISABLE_PIPES + virtual MIDIReadEvent read() = 0; + virtual ChannelMessage getChannelMessage() const = 0; + virtual SysCommonMessage getSysCommonMessage() const = 0; + virtual RealTimeMessage getRealTimeMessage() const = 0; + virtual SysExMessage getSysExMessage() const = 0; +#endif + + protected: +#if !DISABLE_PIPES + /// Accept an incoming MIDI Channel message from the source pipe. + void sinkMIDIfromPipe(ChannelMessage msg) override { send(msg); } + /// Accept an incoming MIDI System Exclusive message from the source pipe. + void sinkMIDIfromPipe(SysExMessage msg) override { send(msg); } + /// Accept an incoming MIDI System Common message from the source pipe. + void sinkMIDIfromPipe(SysCommonMessage msg) override { send(msg); } + /// Accept an incoming MIDI Real-Time message from the source pipe. + void sinkMIDIfromPipe(RealTimeMessage msg) override { send(msg); } +#endif + + protected: + /// Call the channel message callback and send the message to the sink pipe. + void onChannelMessage(ChannelMessage message); + /// Call the SysEx message callback and send the message to the sink pipe. + void onSysExMessage(SysExMessage message); + /// Call the System Common message callback and send the message to the sink + /// pipe. + void onSysCommonMessage(SysCommonMessage message); + /// Call the real-time message callback and send the message to the sink + /// pipe. + void onRealTimeMessage(RealTimeMessage message); + + public: + /// Read, parse and dispatch incoming MIDI messages on the given interface. + template + static void updateIncoming(MIDIInterface_t *iface); + /// Dispatch the given type of MIDI message from the given interface. + template + static void dispatchIncoming(MIDIInterface_t *iface, MIDIReadEvent event); +#if !DISABLE_PIPES + /// Un-stall the given MIDI interface. Assumes the interface has been + /// stalled because of a chunked SysEx messages. Waits until that message + /// is finished. + template + static void handleStall(MIDIInterface_t *self); + using MIDIStaller::handleStall; +#endif + + private: + MIDI_Callbacks *callbacks = nullptr; + + private: + static MIDI_Interface *DefaultMIDI_Interface; +}; + +template +void MIDI_Interface::updateIncoming(MIDIInterface_t *self) { +#if DISABLE_PIPES + MIDIReadEvent event = self->read(); + while (event != MIDIReadEvent::NO_MESSAGE) { + dispatchIncoming(self, event); + event = self->read(); + } +#else + MIDIReadEvent event = self->read(); + if (event == MIDIReadEvent::NO_MESSAGE) + return; + if (self->getStaller() == self) + self->unstall(self); + int16_t size_rem = 512 * 3 / 4; // Don't keep on reading for too long + bool chunked = false; // Whether there's an unterminated SysEx chunk + while (event != MIDIReadEvent::NO_MESSAGE) { + dispatchIncoming(self, event); + if (event == MIDIReadEvent::SYSEX_CHUNK) { + size_rem -= self->getSysExMessage().length; + chunked = true; + } else if (event == MIDIReadEvent::SYSEX_MESSAGE) { + size_rem -= self->getSysExMessage().length; + chunked = false; + } else { + size_rem -= 3; + } + if (size_rem < 0) + break; + event = self->read(); + } + if (chunked) + self->stall(self); +#endif + // TODO: add logic to detect MIDI messages such as (N)RPN that span over + // multiple channel voice messages and that shouldn't be interrupted. + // For short messages such as (N)RPN, I suggest waiting with a timeout. +} + +template +void MIDI_Interface::dispatchIncoming(MIDIInterface_t *self, + MIDIReadEvent event) { + switch (event) { + case MIDIReadEvent::CHANNEL_MESSAGE: + self->onChannelMessage(self->getChannelMessage()); + break; + case MIDIReadEvent::SYSEX_CHUNK: // fallthrough + case MIDIReadEvent::SYSEX_MESSAGE: + self->onSysExMessage(self->getSysExMessage()); + break; + case MIDIReadEvent::SYSCOMMON_MESSAGE: + self->onSysCommonMessage(self->getSysCommonMessage()); + break; + case MIDIReadEvent::REALTIME_MESSAGE: + self->onRealTimeMessage(self->getRealTimeMessage()); + break; + case MIDIReadEvent::NO_MESSAGE: break; // LCOV_EXCL_LINE + default: break; // LCOV_EXCL_LINE + } +} + +#if !DISABLE_PIPES +template +void MIDI_Interface::handleStall(MIDIInterface_t *self) { + const char *staller_name = self->getStallerName(); + DEBUGFN(F("Handling stall. Cause: ") << staller_name); + self->unstall(self); + + unsigned long startTime = millis(); + while (millis() - startTime < SYSEX_CHUNK_TIMEOUT) { + MIDIReadEvent event = self->read(); + dispatchIncoming(self, event); + if (event == MIDIReadEvent::SYSEX_CHUNK) + startTime = millis(); // reset timeout + else if (event == MIDIReadEvent::SYSEX_MESSAGE) + return; + } + DEBUGFN(F("Warning: Unable to un-stall pipes. Cause: ") << staller_name); + static_cast(staller_name); +} +#endif + +END_CS_NAMESPACE diff --git a/MIDI_Interfaces/MIDI_Pipes.cpp b/MIDI_Interfaces/MIDI_Pipes.cpp new file mode 100644 index 0000000..b5b8773 --- /dev/null +++ b/MIDI_Interfaces/MIDI_Pipes.cpp @@ -0,0 +1,367 @@ +#include +#if !DISABLE_PIPES + +#include "MIDI_Pipes.hpp" +#include "MIDI_Staller.hpp" +#include +#include + +#if defined(ESP32) || !defined(ARDUINO) +#include +#endif + +BEGIN_CS_NAMESPACE + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +void MIDI_Sink::connectSourcePipe(MIDI_Pipe *source) { + if (this->sourcePipe == nullptr) { + source->connectSink(this); + this->sourcePipe = source; + } else { + this->sourcePipe->connectSourcePipe(source); + } +} + +void MIDI_Sink::disconnectSourcePipes() { + if (sourcePipe != nullptr) { + sourcePipe->disconnectSourcePipes(); + sourcePipe->disconnect(); + sourcePipe = nullptr; + } +} + +void MIDI_Sink::disconnectSourcePipesShallow() { + if (sourcePipe != nullptr) { + sourcePipe->disconnectSink(); + sourcePipe = nullptr; + } +} + +bool MIDI_Sink::disconnect(TrueMIDI_Source &source) { + if (!hasSourcePipe()) + return false; + return sourcePipe->disconnect(source); +} + +MIDI_Sink::~MIDI_Sink() { disconnectSourcePipes(); } + +MIDI_Sink::MIDI_Sink(MIDI_Sink &&other) + : sourcePipe(std::exchange(other.sourcePipe, nullptr)) { + if (this->hasSourcePipe()) { + this->sourcePipe->disconnectSink(); + this->sourcePipe->connectSink(this); + } +} + +void MIDI_Sink::swap(MIDI_Sink &a, MIDI_Sink &b) { + std::swap(a.sourcePipe, b.sourcePipe); + if (a.hasSourcePipe()) { + a.sourcePipe->disconnectSink(); + a.sourcePipe->connectSink(&a); + } + if (b.hasSourcePipe()) { + b.sourcePipe->disconnectSink(); + b.sourcePipe->connectSink(&b); + } +} + +MIDI_Sink &MIDI_Sink::operator=(MIDI_Sink &&other) { + swap(*this, other); + return *this; +} + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +void MIDI_Source::connectSinkPipe(MIDI_Pipe *sink) { + if (this->sinkPipe == nullptr) { + sink->connectSource(this); + this->sinkPipe = sink; + } else { + this->sinkPipe->connectSinkPipe(sink); + } +} + +void MIDI_Source::disconnectSinkPipes() { + if (sinkPipe != nullptr) { + sinkPipe->disconnectSinkPipes(); + sinkPipe->disconnect(); + sinkPipe = nullptr; + } +} + +void MIDI_Source::disconnectSinkPipesShallow() { + if (sinkPipe != nullptr) { + sinkPipe->disconnectSource(); + sinkPipe = nullptr; + } +} + +bool MIDI_Source::disconnect(TrueMIDI_Sink &sink) { + if (!hasSinkPipe()) + return false; + return sinkPipe->disconnect(sink); +} + +MIDI_Source::MIDI_Source(MIDI_Source &&other) + : sinkPipe(std::exchange(other.sinkPipe, nullptr)) { + if (this->hasSinkPipe()) { + this->sinkPipe->disconnectSource(); + this->sinkPipe->connectSource(this); + } +} + +void MIDI_Source::swap(MIDI_Source &a, MIDI_Source &b) { + std::swap(a.sinkPipe, b.sinkPipe); + if (a.hasSinkPipe()) { + a.sinkPipe->disconnectSource(); + a.sinkPipe->connectSource(&a); + } + if (b.hasSinkPipe()) { + b.sinkPipe->disconnectSource(); + b.sinkPipe->connectSource(&b); + } +} + +MIDI_Source &MIDI_Source::operator=(MIDI_Source &&other) { + swap(*this, other); + return *this; +} + +MIDI_Source::~MIDI_Source() { disconnectSinkPipes(); } + +void MIDI_Source::sourceMIDItoPipe(ChannelMessage msg) { + if (sinkPipe != nullptr) { + handleStallers(); + sinkPipe->acceptMIDIfromSource(msg); + } +} +void MIDI_Source::sourceMIDItoPipe(SysExMessage msg) { + if (sinkPipe != nullptr) { + handleStallers(); + sinkPipe->acceptMIDIfromSource(msg); + } +} +void MIDI_Source::sourceMIDItoPipe(SysCommonMessage msg) { + if (sinkPipe != nullptr) { + handleStallers(); + sinkPipe->acceptMIDIfromSource(msg); + } +} +void MIDI_Source::sourceMIDItoPipe(RealTimeMessage msg) { + if (sinkPipe != nullptr) { + // Always send write to pipe, don't check if it's stalled or not + sinkPipe->acceptMIDIfromSource(msg); + } +} + +void MIDI_Source::stall(MIDIStaller *cause) { + if (hasSinkPipe()) + sinkPipe->stallDownstream(cause, this); + DEBUGFN(F("Stalled MIDI source. Cause: ") << getStallerName()); +} + +void MIDI_Source::unstall(MIDIStaller *cause) { + DEBUGFN(F("Un-stalling MIDI source. Cause: ") << getStallerName()); + if (hasSinkPipe()) + sinkPipe->unstallDownstream(cause, this); +} + +bool MIDI_Source::isStalled() const { + if (hasSinkPipe()) + return sinkPipe->isStalled(); + return false; +} + +MIDIStaller *MIDI_Source::getStaller() const { + if (hasSinkPipe()) + return sinkPipe->getStaller(); + return nullptr; +} + +const char *MIDI_Source::getStallerName() const { + return MIDIStaller::getNameNull(getStaller()); +} + +void MIDI_Source::handleStallers() const { + if (hasSinkPipe()) + sinkPipe->handleStallers(); +} + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +void MIDI_Pipe::connectSink(MIDI_Sink *sink) { + if (this->sink != nullptr) { + FATAL_ERROR(F("This pipe is already connected to a sink"), 0x9145); + return; // LCOV_EXCL_LINE + } + this->sink = sink; +} + +void MIDI_Pipe::disconnectSink() { this->sink = nullptr; } + +void MIDI_Pipe::connectSource(MIDI_Source *source) { + if (this->source != nullptr) { + FATAL_ERROR(F("This pipe is already connected to a source"), 0x9146); + return; // LCOV_EXCL_LINE + } + this->source = source; +} + +void MIDI_Pipe::disconnectSource() { this->source = nullptr; } + +void MIDI_Pipe::disconnect() { + if (hasSink() && hasThroughIn()) { + auto oldSink = sink; + auto oldThroughIn = getThroughIn(); + sink->disconnectSourcePipesShallow(); + this->disconnectSourcePipesShallow(); // disconnect throughIn + oldSink->connectSourcePipe(oldThroughIn); + } + if (hasSource() && hasThroughOut()) { + auto oldSource = source; + auto oldThroughOut = getThroughOut(); + source->disconnectSinkPipesShallow(); + this->disconnectSinkPipesShallow(); // disconnect throughOut + oldSource->connectSinkPipe(oldThroughOut); + } + if (hasSink()) + sink->disconnectSourcePipesShallow(); + + if (hasSource()) + source->disconnectSinkPipesShallow(); + + if (hasThroughIn() || hasThroughOut()) + FATAL_ERROR(F("Invalid state"), 0x9147); // LCOV_EXCL_LINE +} + +MIDI_Pipe::~MIDI_Pipe() { disconnect(); } + +void MIDI_Pipe::stallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) { + if (!sinkIsUnstalledOrStalledBy(cause)) { + FATAL_ERROR(F("Cannot stall pipe from ") + << MIDIStaller::getNameNull(cause) + << F(" because pipe is already stalled by ") + << MIDIStaller::getNameNull(sink_staller), + 0x6665); + } // LCOV_EXCL_LINE + sink_staller = cause; + if (hasThroughOut() && stallsrc == source) + getThroughOut()->stallDownstream(cause, this); + if (hasSink()) + sink->stallDownstream(cause, this); + if (hasSource() && source != stallsrc) { + // If our through output is stalled, that means our upstream is stalled + // as well by this staller. Unstall it first, and replace it by the new + // staller + if (through_staller != nullptr) + source->unstallUpstream(through_staller, this); + source->stallUpstream(cause, this); + } + if (hasThroughIn() && getThroughIn() != stallsrc) + getThroughIn()->stallUpstream(cause, this); +} + +void MIDI_Pipe::stallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) { + if (stallsrc == sink) { + // This cannot be a different cause, because then our sink would + // already have caught it in stallDownstream(). + sink_staller = cause; + if (hasSource()) + source->stallUpstream(cause, this); + if (hasThroughIn()) + getThroughIn()->stallUpstream(cause, this); + } else { + if (through_staller == nullptr) { + through_staller = cause; + if (hasSource()) + source->stallUpstream(cause, this); + } + } +} + +void MIDI_Pipe::unstallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) { + if (!sinkIsUnstalledOrStalledBy(cause)) { + FATAL_ERROR(F("Cannot unstall pipe from ") + << MIDIStaller::getNameNull(cause) + << F(" because pipe is stalled by ") + << MIDIStaller::getNameNull(sink_staller), + 0x6666); + } // LCOV_EXCL_LINE + this->sink_staller = nullptr; + if (hasThroughOut() && stallsrc == source) + getThroughOut()->unstallDownstream(cause, this); + if (hasSink()) + sink->unstallDownstream(cause, this); + if (hasSource() && source != stallsrc) { + source->unstallUpstream(cause, this); + // If the through output of this pipe is stalled, we cannot just unstall + // our upstream, we have to update it our through output staller + if (through_staller != nullptr) + source->stallUpstream(through_staller, this); + } + if (hasThroughIn() && getThroughIn() != stallsrc) + getThroughIn()->unstallUpstream(cause, this); +} + +void MIDI_Pipe::unstallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) { + if (stallsrc == sink) { + // This cannot be a different cause, because then our sink would + // already have caught it in unstallDownstream(). + sink_staller = nullptr; + if (hasSource()) + source->unstallUpstream(cause, this); + if (hasThroughIn()) + getThroughIn()->unstallUpstream(cause, this); + } else { + if (cause == through_staller) { + through_staller = nullptr; + if (hasSource()) + source->unstallUpstream(cause, this); + } + } +} + +const char *MIDI_Pipe::getSinkStallerName() const { + return MIDIStaller::getNameNull(sink_staller); +} + +const char *MIDI_Pipe::getThroughStallerName() const { + return MIDIStaller::getNameNull(through_staller); +} + +MIDIStaller *MIDI_Pipe::getStaller() const { + return sink_staller ? sink_staller : through_staller; +} + +const char *MIDI_Pipe::getStallerName() const { + return MIDIStaller::getNameNull(getStaller()); +} + +void MIDI_Pipe::handleStallers() const { + if (!isStalled()) + return; + if (sink_staller == eternal_stall || through_staller == eternal_stall) + FATAL_ERROR(F("Unable to unstall pipe (eternal stall)"), 0x4827); + uint8_t iterations = 10; + while (isStalled() && iterations-- > 0) { + if (sink_staller) + sink_staller->handleStall(); + if (through_staller) + through_staller->handleStall(); + } +} + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +const char *MIDIStaller::getNameNull(MIDIStaller *s) { + if (s == nullptr) + return "(null)"; + if (s == eternal_stall) + return "(eternal stall)"; + return s->getName(); +} + +END_CS_NAMESPACE + +#endif diff --git a/MIDI_Interfaces/MIDI_Pipes.hpp b/MIDI_Interfaces/MIDI_Pipes.hpp new file mode 100644 index 0000000..722f528 --- /dev/null +++ b/MIDI_Interfaces/MIDI_Pipes.hpp @@ -0,0 +1,737 @@ +#pragma once + +#include +#if !DISABLE_PIPES + +#include +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +struct MIDIStaller; +MIDIStaller *const eternal_stall = + reinterpret_cast(std::numeric_limits::max()); + +/** + * @addtogroup MIDI_Routing MIDI Routing + * @brief Operators and utilities for MIDI routing. + * + * Two or more MIDI interfaces can be connected + * using @ref MIDI_Pipe "MIDI Pipes". The simplest pipe just carries messages + * from the input interface to the output interface, but you can write rules for + * filtering out certain messages, changing the channel of some messages, etc. + * + * Allows you to use syntax like: + * + * ~~~cpp + * HardwareSerialMIDI_Interface + * midiA = Serial1, midiB = Serial2, midiC = Serial3; + * MIDI_PipeFactory<3> pipes; // Factory that can produce 3 pipes + * + * midiA >> pipes >> midiB; + * midiC >> pipes >> midiB; + * midiC << pipes << midiB; + * ~~~ + * + * Or for bidirectional connections: + * + * ~~~cpp + * HardwareSerialMIDI_Interface + * midiA = Serial1, midiB = Serial2, midiC = Serial3; + * BidirectionalMIDI_PipeFactory<2> pipes; // Factory that can produce 2 pipes + * + * midiA | pipes | midiB; + * midiA | pipes | midiC; + * ~~~ + * + * Have a look at the following examples on MIDI routing: + * + * - @ref MIDI_Pipes-Routing.ino + * - @ref Dual-MIDI-Interface.ino + * + * If you're interested how the pipes work, see the documentation for + * @ref MIDI_Pipe. + * + * @see @ref midi_md-routing (MIDI tutorial) + * + * @{ + */ + +class MIDI_Pipe; +class MIDI_Source; +class MIDI_Sink; +/// A MIDI_Sink that is not a MIDI_Pipe. +using TrueMIDI_Sink = MIDI_Sink; +/// A MIDI_Source that is not a MIDI_Pipe. +using TrueMIDI_Source = MIDI_Source; + +/// Receives MIDI messages from a MIDI pipe. +/// @see @ref MIDI_Routing +/// @see @ref midi_md-routing (MIDI tutorial) +class MIDI_Sink { + public: + /// Default constructor. + MIDI_Sink() = default; + + /// Copy constructor (copying not allowed). + MIDI_Sink(const MIDI_Sink &) = delete; + /// Copy assignment (copying not allowed). + MIDI_Sink &operator=(const MIDI_Sink &) = delete; + + /// Move constructor. + MIDI_Sink(MIDI_Sink &&other); + /// Move assignment. + MIDI_Sink &operator=(MIDI_Sink &&other); + + /// Destructor. + virtual ~MIDI_Sink(); + + /// @name Sending data over a MIDI Pipe + /// @{ + + /// Accept an incoming MIDI Channel message. + virtual void sinkMIDIfromPipe(ChannelMessage) = 0; + /// Accept an incoming MIDI System Exclusive message. + virtual void sinkMIDIfromPipe(SysExMessage) = 0; + /// Accept an incoming MIDI System Common message. + virtual void sinkMIDIfromPipe(SysCommonMessage) = 0; + /// Accept an incoming MIDI Real-Time message. + virtual void sinkMIDIfromPipe(RealTimeMessage) = 0; + + /// @} + + /// @name Connecting and disconnecting MIDI Pipes + /// @{ + + /// Fully connect a source pipe to this sink. + void connectSourcePipe(MIDI_Pipe *source); + /// Disconnect all source pipes that sink to this sink (recursively). + void disconnectSourcePipes(); + /// Disconnect the given source from this sink. Leaves other sources + /// connected. + /// Returns true if the source was found and disconnected, false if the + /// given source was not a direct or indirect source to this sink. + bool disconnect(TrueMIDI_Source &source); + bool disconnect(MIDI_Pipe &) = delete; + /// Check if this sink is connected to a source pipe. + bool hasSourcePipe() const { return sourcePipe != nullptr; } + /// Get a pointer to the pipe this sink is connected to, or `nullptr` if + /// not connected. + MIDI_Pipe *getSourcePipe() const { return sourcePipe; } + + /// @} + + private: + /// Base case for recursive stall function. + /// @see MIDI_Pipe::stallDownstream + virtual void stallDownstream(MIDIStaller *, MIDI_Source *) {} + /// Base case for recursive un-stall function. + /// @see MIDI_Pipe::unstallDownstream + virtual void unstallDownstream(MIDIStaller *, MIDI_Source *) {} + /// Base case for recursive function. + /// @see MIDI_Pipe::getFinalSink + virtual MIDI_Sink *getFinalSink() { return this; } + /// Disconnect only the first pipe connected to this sink. Leaves the + /// other pipes connected to the original pipe, which doesn't have a sink + /// anymore when this function finishes. + /// Used to disconnect a MIDI_Pipe while preserving the connections of its + /// “through” inputs. + void disconnectSourcePipesShallow(); + + protected: + MIDI_Pipe *sourcePipe = nullptr; + + friend class MIDI_Pipe; + + public: + static void swap(MIDI_Sink &a, MIDI_Sink &b); + friend void swap(MIDI_Sink &a, MIDI_Sink &b) { swap(a, b); } +}; + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +/// Class that can send MIDI messages to a MIDI pipe. +/// @see @ref MIDI_Routing +/// @see @ref midi_md-routing (MIDI tutorial) +class MIDI_Source { + public: + /// Default constructor. + MIDI_Source() = default; + + /// Copy constructor (copying not allowed). + MIDI_Source(const MIDI_Source &) = delete; + /// Copy assignment (copying not allowed). + MIDI_Source &operator=(const MIDI_Source &) = delete; + + /// Move constructor. + MIDI_Source(MIDI_Source &&other); + /// Move assignment. + MIDI_Source &operator=(MIDI_Source &&other); + + /// Destructor. + virtual ~MIDI_Source(); + + /// @name Sending data over a MIDI Pipe + /// @{ + + /// Send a MIDI Channel Message down the pipe. + void sourceMIDItoPipe(ChannelMessage); + /// Send a MIDI System Exclusive message down the pipe. + void sourceMIDItoPipe(SysExMessage); + /// Send a MIDI System Common message down the pipe. + void sourceMIDItoPipe(SysCommonMessage); + /// Send a MIDI Real-Time message down the pipe. + void sourceMIDItoPipe(RealTimeMessage); + + /// @} + + /// @name Stalling the sink pipes and exclusive access + /// @{ + + /// Stall this MIDI source. + /// This means that this becomes the only source that can sink to the sinks + /// connected to this source. Other sources have to wait until this source + /// un-stalls the pipe before they can send again. + /// @param cause + /// Pointer to the reason for this stall, can be called back to + /// un-stall the pipes. + void stall(MIDIStaller *cause = eternal_stall); + /// Un-stall the pipes connected to this source, so other sources + /// are allowed to send again. + /// @param cause + /// Pointer to the reason for the stall (this has to be the same one + /// that was used to stall). + void unstall(MIDIStaller *cause = eternal_stall); + /// Check if this source can write to the sinks it connects to. + bool isStalled() const; + /// Get a pointer to whatever is causing this MIDI source to be stalled. + /// There could be multiple stallers, this function just returns one. + MIDIStaller *getStaller() const; + /// Get the name of whatever is causing this MIDI source to be stalled. + /// There could be multiple stallers, this function just returns one. + const char *getStallerName() const; + /// Give the code that is stalling the MIDI sink pipes the opportunity to do + /// its job and un-stall the pipes. + void handleStallers() const; + + /// @} + + /// @name Connecting and disconnecting MIDI Pipes + /// @{ + + /// Fully connect a sink pipe to this source. + void connectSinkPipe(MIDI_Pipe *sink); + /// Disconnect all sink pipes that this source sinks to (recursively). + void disconnectSinkPipes(); + /// Disconnect the given sink from this source. Leaves other sinks + /// connected. + /// Returns true if the sink was found and disconnected, false if the + /// given sink was not a direct or indirect sink of this source. + bool disconnect(TrueMIDI_Sink &sink); + bool disconnect(MIDI_Pipe &) = delete; + /// Check if this source is connected to a sink pipe. + bool hasSinkPipe() const { return sinkPipe != nullptr; } + /// Get a pointer to the pipe this source is connected to, or `nullptr` if + /// not connected. + MIDI_Pipe *getSinkPipe() { return sinkPipe; } + + /// @} + + private: + /// Base case for recursive stall function. + /// @see MIDI_Pipe::stallUpstream + virtual void stallUpstream(MIDIStaller *, MIDI_Sink *) {} + /// Base case for recursive un-stall function. + /// @see MIDI_Pipe::unstallUpstream + virtual void unstallUpstream(MIDIStaller *, MIDI_Sink *) {} + /// Base case for recursive function. + /// @see MIDI_Pipe::getInitialSource + virtual MIDI_Source *getInitialSource() { return this; } + /// Disconnect only the first pipe connected to this source. Leaves the + /// other pipes connected to the original pipe, which doesn't have a source + /// anymore when this function finishes. + /// Used to disconnect a @ref MIDI_Pipe while preserving the connections of + /// its “through” outputs. + void disconnectSinkPipesShallow(); + + protected: + MIDI_Pipe *sinkPipe = nullptr; + + friend class MIDI_Pipe; + + public: + static void swap(MIDI_Source &a, MIDI_Source &b); + friend void swap(MIDI_Source &a, MIDI_Source &b) { swap(a, b); } +}; + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +/** + * @brief Class that routes MIDI messages from a MIDI_Source to a MIDI_Sink. + * + * A pipe has at least two, at most four connections. In the simplest case, a + * pipe just has a source and a sink. The source sends MIDI messages down the + * pipe, and the pipe sends them to the sink. A mapping or filter can be applied + * to the messages traveling down the pipe. + * + * To be able to connect multiple pipes to a single sink or source, a pipe also + * has a “through” output and a “through” input. Both are pipes, not sinks or + * sources. All data that comes from the source is sent to the “through” output + * as well, and all input that comes in from the “through” input is sent to the + * sink as well. The mapping or filter is not applied to the data going from/to + * the “through” connections. + * + * Merging data from multiple sources into a single sink can cause problems + * because messages can be interleaved (e.g. RPN/NRPN or chunked system + * exclusive messages). To circumvent this issue, a source can request exclusive + * access to the pipe it's connected to. This stalls all other pipes that sink + * into the same sinks as the exclusive source. + * When other sources try to send to a stalled pipe, this will automatically + * call back the source that originally stalled the pipes, so it can finish its + * message, and then un-stall the pipes so the other pipe can send its data. + * + * **Pipe model** + * + * ~~~ + * ╭────────────────> through out + * │ ┌────────┐ + * source >━━━━┷━┥ filter ┝━┯━━━> sink + * └────────┘ │ + * through in >─────────────────╯ + * ~~~ + * + * For example, if you have one source that should connect to two sinks, the + * configuration is as follows: + * + * ~~~ + * through out × ┌────────┐ + * ╭────────────────> >━━━━┷━┥ pipe 2 ┝━┯━━━> sink 2 + * │ ┌────────┐ └────────┘ × + * source >━━━━┷━┥ pipe 1 ┝━┯━━━━━━━━━━━━━━━━━━━━━━━━━━━> sink 1 + * └────────┘ × + * ~~~ + * + * If you have two sources that should connect to the same sink, a possible + * configuration is: + * + * ~~~ + * × ┌────────┐ + * source 1 >━━━━━━━━━━━━━━━━━━━━━━━━━━━━┷━┥ pipe 1 ┝━┯━━━> sink + * × ┌────────┐ └────────┘ │ + * source 2 >━━━━┷━┥ pipe 2 ┝━┯━━━> >─────────────────╯ + * └────────┘ × + * ~~~ + * + * Each connection between a source and a sink has its own pipe, and no two + * pipes are connected in series (only through the “through“ inputs/outputs). + * + * @see @ref MIDI_Routing + * @see @ref midi_md-routing (MIDI tutorial) + */ +class MIDI_Pipe : private MIDI_Sink, private MIDI_Source { + public: + /// Default constructor + MIDI_Pipe() = default; + + /// Copy constructor (copying not allowed). + MIDI_Pipe(const MIDI_Pipe &) = delete; + /// Copy assignment (copying not allowed). + MIDI_Pipe &operator=(const MIDI_Pipe &) = delete; + + /// Move constructor. + /// @todo Add move constructor. + MIDI_Pipe(MIDI_Pipe &&) = delete; + /// Move assignment. + /// @todo Add move assignment. + MIDI_Pipe &operator=(MIDI_Pipe &&) = delete; + + /// Destructor. + virtual ~MIDI_Pipe(); + + private: + /// @name Mapping and filtering + /// @{ + + /// Function that maps, edits or filters MIDI messages, and then forwards + /// them to the sink of the pipe. + /// The MIDI_Pipe base class just forwards the messages to the sink, but + /// you can override this method to create pipes that filter out some + /// messages, transposes notes, changes the channel, etc. + virtual void mapForwardMIDI(ChannelMessage msg) { sourceMIDItoSink(msg); } + /// @copydoc mapForwardMIDI + virtual void mapForwardMIDI(SysExMessage msg) { sourceMIDItoSink(msg); } + /// @copydoc mapForwardMIDI + virtual void mapForwardMIDI(SysCommonMessage msg) { sourceMIDItoSink(msg); } + /// @copydoc mapForwardMIDI + virtual void mapForwardMIDI(RealTimeMessage msg) { sourceMIDItoSink(msg); } + + /// @} + + public: + /// @name Dealing with stalled pipes + /// @{ + + /// Check if this pipe is stalled. + bool isStalled() const { return sink_staller || through_staller; } + /// Get the staller (cause of the stall) that causes the sink of this pipe + /// to be stalled. + /// This pipe could sink to more than one stalled sink, this function just + /// returns one of the causes. + MIDIStaller *getSinkStaller() const { return sink_staller; } + /// Get the name of the staller (cause of the stall) that causes the sink + /// of this pipe to be stalled. + const char *getSinkStallerName() const; + /// Get the staller (cause of the stall) that causes the “through” output + /// of this pipe to be stalled. + /// The “through” output of this pipe could sink to more than one stalled + /// sink, this function just returns one of the causes. + MIDIStaller *getThroughStaller() const { return through_staller; } + /// Get the name of the staller (cause of the stall) that causes the + /// “through” output of this pipe to be stalled. + const char *getThroughStallerName() const; + /// Get any staller: returns @ref getSinkStaller() if it's not null, + /// @ref getThroughStaller() otherwise. + MIDIStaller *getStaller() const; + /// Get the name of any staller. + /// @see getStaller + const char *getStallerName() const; + /// Returns true if this pipe is either not stalled at all, or if the pipe + /// is stalled by the given staller (cause). + /// @see getSinkStaller + bool sinkIsUnstalledOrStalledBy(MIDIStaller *cause) { + return sink_staller == nullptr || sink_staller == cause; + } + /// Returns true if this pipe is either not stalled at all, or if the pipe + /// is stalled by the given staller (cause). + /// @see getThroughStaller + bool throughIsUnstalledOrStalledBy(MIDIStaller *cause) { + return through_staller == nullptr || through_staller == cause; + } + + /// Give the code that is stalling the MIDI pipe the opportunity to do + /// its job and unstall the pipe. + void handleStallers() const; + + /// @} + + public: + /// @name Check connections + /// @{ + + /// Check if this pipe is connected to a sink. + bool hasSink() const { return sink != nullptr; } + /// Check if this pipe is connected to a source. + bool hasSource() const { return source != nullptr; } + /// Check if this pipe has a “through” output that sends all incoming + /// messages from the input (source) to another pipe. + bool hasThroughOut() const { return getThroughOut() != nullptr; } + /// Check if this pipe has a “through” input that merges all messages from + /// another pipe into the output (sink). + bool hasThroughIn() const { return getThroughIn() != nullptr; } + + /// @} + + public: + /// @name MIDI Pipe connection management and inspection + /// @{ + + /// Disconnect this pipe from all other pipes, sources and sinks. If the + /// “through” input and/or output were in use, they are reconnected to their + /// original sink and/or source respectively, their behavior doesn't change. + void disconnect(); + /// Disconnect the given sink from this pipe. The sink can be connected + /// directly, or via the “through” output. + /// Returns true if the sink was found and disconnected, false if the given + /// sink was not a direct or indirect sink of this pipe. + bool disconnect(TrueMIDI_Sink &sink) { + if (getFinalSink() == &sink) { + disconnect(); + return true; + } + if (hasThroughOut()) { + return getThroughOut()->disconnect(sink); + } + return false; + } + /// Disconnect the given source from this pipe. The source can be connected + /// directly, or via the “through” input. + /// Returns true if the source was found and disconnected, false if the + /// given source was not a direct or indirect source to this pipe. + bool disconnect(TrueMIDI_Source &source) { + if (getInitialSource() == &source) { + disconnect(); + return true; + } + if (hasThroughIn()) { + return getThroughIn()->disconnect(source); + } + return false; + } + bool disconnect(MIDI_Pipe &) = delete; + + /// Get the immediate source of this pipe. + MIDI_Source *getSource() const { return source; } + /// Get the immediate sink of this pipe. + MIDI_Sink *getSink() const { return sink; } + /// Get the pipe connected to the “through” output of this pipe. + MIDI_Pipe *getThroughOut() const { return MIDI_Source::sinkPipe; } + /// Get the pipe connected to the “through” input of this pipe. + MIDI_Pipe *getThroughIn() const { return MIDI_Sink::sourcePipe; } + + /// Get the sink this pipe eventually sinks to, following the chain + /// recursively. + MIDI_Sink *getFinalSink() override { + return hasSink() ? sink->getFinalSink() : nullptr; + } + /// Get the original source that sources to this pipe, following the chain + /// recursively. + MIDI_Source *getInitialSource() override { + return hasSource() ? source->getInitialSource() : nullptr; + } + + /// @} + + private: + /// @name Private functions to connect and disconnect sinks and sources + /// @{ + + /// Set the sink pointer to point to the given sink. Does not connect this + /// pipe to the sink. Initiate the connection from the sink. + void connectSink(MIDI_Sink *sink); + /// Set the sink pointer to null. Does not disconnect this pipe from the + /// sink. Initiate the disconnection from the sink. + void disconnectSink(); + /// Set the source pointer to point to the given source. Does not connect + /// this pipe to the source. Initiate the connection from the source. + void connectSource(MIDI_Source *source); + /// Set the source pointer to null. Does not disconnect this pipe from the + /// source. Initiate the disconnection from the source. + void disconnectSource(); + + /// @} + + protected: + /// Send the given MIDI message to the sink of this pipe. + /// Useful when overriding @ref mapForwardMIDI. + template + void sourceMIDItoSink(Message msg) { + if (hasSink()) + sink->sinkMIDIfromPipe(msg); + } + + protected: + /// Accept a MIDI message from the source, forward it to the “through” + /// output if necessary, map or filter the MIDI message if necessary, + /// and send it to the sink. This function transfers messages from a + /// @ref MIDI_Source to its @ref MIDI_Pipe. + template + void acceptMIDIfromSource(Message msg) { + if (hasThroughOut()) + getThroughOut()->acceptMIDIfromSource(msg); + mapForwardMIDI(msg); + } + + private: + /// Called when data arrives from an upstream pipe connected to our + /// “through” input, this function forwards it to the sink. + void sinkMIDIfromPipe(ChannelMessage msg) override { + sourceMIDItoSink(msg); + } + /// @copydoc sinkMIDIfromPipe + void sinkMIDIfromPipe(SysExMessage msg) override { sourceMIDItoSink(msg); } + /// @copydoc sinkMIDIfromPipe + void sinkMIDIfromPipe(SysCommonMessage msg) override { + sourceMIDItoSink(msg); + } + /// @copydoc sinkMIDIfromPipe + void sinkMIDIfromPipe(RealTimeMessage msg) override { + sourceMIDItoSink(msg); + } + + private: + /// @name Private functions to stall and un-stall pipes + /// @{ + + /// Stall this pipe and all other pipes further downstream (following the + /// path of the sink and the “through” output). Operates recursively until + /// the end of the chain is reached, and then continues upstream (using + /// @ref stallUpstream) to stall all pipes that connect to sources that + /// sink to the same sink as this pipe and its “through” output. + /// In short: stall all pipes that sink to the same sink as this pipe, and + /// then stall all pipes that source to this first set of pipes. + void stallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override; + /// Undoes the stalling by @ref stallDownstream. + void unstallDownstream(MIDIStaller *cause, MIDI_Source *stallsrc) override; + + /// Stall this pipe and all other pipes further upstream (following the + /// path of the "trough" input). Operates recursively until the end of the + /// chain is reached. This function is called in the second stage of + /// @ref stallDownstream. + void stallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override; + /// Undoes the stalling by @ref stallUpstream. + void unstallUpstream(MIDIStaller *cause, MIDI_Sink *stallsrc) override; + + /// @} + + private: + MIDI_Sink *sink = nullptr; + MIDI_Source *source = nullptr; + MIDIStaller *sink_staller = nullptr; + MIDIStaller *through_staller = nullptr; + + friend class MIDI_Sink; + friend class MIDI_Source; +}; + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +/// A struct that is both a TrueMIDI_Sink and a TrueMIDI_Source. +/// @see @ref MIDI_Routing +/// @see @ref midi_md-routing (MIDI tutorial) +struct TrueMIDI_SinkSource : TrueMIDI_Sink, TrueMIDI_Source {}; + +/// A bidirectional pipe consists of two unidirectional pipes. +/// @see @ref MIDI_Routing +/// @see @ref midi_md-routing (MIDI tutorial) +using BidirectionalMIDI_Pipe = std::pair; + +/// Connect a source to a pipe (`source >> pipe`). +inline MIDI_Pipe &operator>>(TrueMIDI_Source &source, MIDI_Pipe &pipe) { + source.connectSinkPipe(&pipe); + return pipe; +} + +/// Connect a pipe to a sink (`pipe >> sink`). +inline TrueMIDI_Sink &operator>>(MIDI_Pipe &pipe, TrueMIDI_Sink &sink) { + sink.connectSourcePipe(&pipe); + return sink; +} + +/// Connect a sink to a pipe (`sink << pipe`). +inline MIDI_Pipe &operator<<(TrueMIDI_Sink &sink, MIDI_Pipe &pipe) { + sink.connectSourcePipe(&pipe); + return pipe; +} + +/// Connect a pipe to a source (`pipe << source`). +inline TrueMIDI_Source &operator<<(MIDI_Pipe &pipe, TrueMIDI_Source &source) { + source.connectSinkPipe(&pipe); + return source; +} + +/// Don't connect two pipes to eachother. +MIDI_Pipe &operator<<(MIDI_Pipe &, MIDI_Pipe &) = delete; + +/// Connect a pipe to a sink+source (`pipe | source+sink`). +inline TrueMIDI_SinkSource &operator|(BidirectionalMIDI_Pipe &pipe, + TrueMIDI_SinkSource &sinksource) { + sinksource.connectSinkPipe(&pipe.first); + sinksource.connectSourcePipe(&pipe.second); + return sinksource; +} + +/// Connect a sink+source to a pipe (`source+sink | pipe`). +inline BidirectionalMIDI_Pipe &operator|(TrueMIDI_SinkSource &sinksource, + BidirectionalMIDI_Pipe &pipe) { + sinksource.connectSinkPipe(&pipe.second); + sinksource.connectSourcePipe(&pipe.first); + return pipe; +} + +// :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: // + +/** + * @brief Class that produces multiple MIDI_Pipe%s. + * + * @tparam N + * The maximum number of pipes it can produce. + * @tparam Pipe + * The type of pipes to produce. + * + * @see @ref MIDI_Routing + * @see @ref midi_md-routing (MIDI tutorial) + */ +template +struct MIDI_PipeFactory { + Pipe pipes[N]; + size_t index = 0; + + Pipe &getNext() { + if (index >= N) + FATAL_ERROR(F("Not enough pipes available"), 0x2459); + return pipes[index++]; + } + Pipe &operator[](size_t i) { return pipes[i]; } + const Pipe &operator[](size_t i) const { return pipes[i]; } +}; + +template +using BidirectionalMIDI_PipeFactory = + MIDI_PipeFactory; + +template +inline MIDI_Pipe &operator>>(TrueMIDI_Source &source, + MIDI_PipeFactory &pipe_fact) { + return source >> pipe_fact.getNext(); +} + +template +MIDI_Pipe &operator>>(MIDI_Pipe &, MIDI_PipeFactory &) = delete; + +template +inline TrueMIDI_Sink &operator>>(MIDI_PipeFactory &pipe_fact, + TrueMIDI_Sink &sink) { + return pipe_fact.getNext() >> sink; +} + +template +MIDI_Pipe &operator>>(MIDI_PipeFactory &, MIDI_Pipe &) = delete; + +template +inline MIDI_Pipe &operator<<(TrueMIDI_Sink &sink, + MIDI_PipeFactory &pipe_fact) { + return sink << pipe_fact.getNext(); +} + +template +inline TrueMIDI_Source &operator<<(MIDI_PipeFactory &pipe_fact, + TrueMIDI_Source &source) { + return pipe_fact.getNext() << source; +} + +template +inline TrueMIDI_SinkSource & +operator|(BidirectionalMIDI_PipeFactory &pipe_fact, + TrueMIDI_SinkSource &sinksource) { + return pipe_fact.getNext() | sinksource; +} + +template +inline BidirectionalMIDI_Pipe & +operator|(TrueMIDI_SinkSource &sinksource, + BidirectionalMIDI_PipeFactory &pipe_fact) { + return sinksource | pipe_fact.getNext(); +} + +/// @} + +END_CS_NAMESPACE + +#else + +BEGIN_CS_NAMESPACE + +struct TrueMIDI_Source { + template + void sourceMIDItoPipe(Args &&...) {} +}; +struct TrueMIDI_Sink {}; +struct TrueMIDI_SinkSource : TrueMIDI_Source, TrueMIDI_Sink {}; + +END_CS_NAMESPACE + +#endif \ No newline at end of file diff --git a/MIDI_Interfaces/MIDI_Sender.hpp b/MIDI_Interfaces/MIDI_Sender.hpp new file mode 100644 index 0000000..7b78460 --- /dev/null +++ b/MIDI_Interfaces/MIDI_Sender.hpp @@ -0,0 +1,179 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief Statically polymorphic template for classes that send MIDI messages. + */ +template +class MIDI_Sender { + public: + /// @name Sending MIDI Channel Voice messages + /// @{ + + /// Send a MIDI %Channel Voice message. + void send(ChannelMessage message); + + /** + * @brief Send a 3-byte MIDI %Channel Voice message. + * + * @param m + * MIDI message type. [0x80, 0xE0] + * @param c + * The MIDI channel. [1, 16] + * @param d1 + * The first data byte. [0, 127] + * @param d2 + * The second data byte. [0, 127] + * @param cable + * The MIDI Cable Number. [Cable_1, Cable_16] + */ + void sendChannelMessage(MIDIMessageType m, Channel c, uint8_t d1, + uint8_t d2, Cable cable = Cable_1); + + /** + * @brief Send a 2-byte MIDI %Channel Voice message. + * + * @param m + * MIDI message type. [0x80, 0xE0] + * @param c + * The MIDI channel. [1, 16] + * @param d1 + * The first data byte. [0, 127] + * @param cable + * The MIDI Cable Number. [1, 16] + */ + void sendChannelMessage(MIDIMessageType m, Channel c, uint8_t d1, + Cable cable = Cable_1); + + /// Send a MIDI Note On event. + void sendNoteOn(MIDIAddress address, uint8_t velocity); + /// Send a MIDI Note Off event. + void sendNoteOff(MIDIAddress address, uint8_t velocity); + /// Send a MIDI Key Pressure event. + void sendKeyPressure(MIDIAddress address, uint8_t pressure); + /// Send a MIDI Control Change event. + void sendControlChange(MIDIAddress address, uint8_t value); + /// Send a MIDI Program Change event. + void sendProgramChange(MIDIAddress address); + /// Send a MIDI Program Change event. + void sendProgramChange(MIDIChannelCable address, uint8_t value); + /// Send a MIDI %Channel Pressure event. + void sendChannelPressure(MIDIChannelCable address, uint8_t pressure); + /// Send a MIDI Pitch Bend event. + void sendPitchBend(MIDIChannelCable address, uint16_t value); + + /// @} + + /// @name Sending MIDI System Common messages + /// @{ + + /// Send a MIDI System Common message. + void send(SysCommonMessage message); + /// Send a MIDI System Common message. + void sendSysCommon(MIDIMessageType m, Cable cable = Cable_1); + /// Send a MIDI System Common message. + void sendSysCommon(MIDIMessageType m, uint8_t data1, Cable cable = Cable_1); + /// Send a MIDI System Common message. + void sendSysCommon(MIDIMessageType m, uint8_t data1, uint8_t data2, + Cable cable = Cable_1); + + /// Send a MIDI Time Code Quarter Frame. + void sendMTCQuarterFrame(uint8_t data, Cable cable = Cable_1); + /// Send a MIDI Time Code Quarter Frame. + void sendMTCQuarterFrame(uint8_t messageType, uint8_t values, + Cable cable = Cable_1); + /// Send a MIDI Song Position Pointer message. + void sendSongPositionPointer(uint16_t spp, Cable cable = Cable_1); + /// Send a MIDI Song Select message. + void sendSongSelect(uint8_t song, Cable cable = Cable_1); + /// Send a MIDI Tune Request. + void sendTuneRequest(Cable cable = Cable_1); + + /// @} + + /// @name Sending MIDI System Exclusive messages + /// @{ + + /// Send a MIDI System Exclusive message. + void send(SysExMessage message); + /// Send a MIDI System Exclusive message. + template + void sendSysEx(const uint8_t (&sysexdata)[N], Cable cable = Cable_1); + /// Send a MIDI System Exclusive message. + void sendSysEx(const uint8_t *data, uint16_t length, Cable cable = Cable_1); + + /// @} + + /// @name Sending MIDI Real-Time messages + /// @{ + + /// Send a MIDI Real-Time message. + void send(RealTimeMessage message); + /// Send a MIDI Real-Time message. + void sendRealTime(MIDIMessageType rt, Cable cable = Cable_1); + /// Send a MIDI Real-Time message. + void sendRealTime(uint8_t rt, Cable cable = Cable_1); + + /// Send a MIDI Timing Clock message. + void sendTimingClock(Cable cable = Cable_1); + /// Send a MIDI Start message. + void sendStart(Cable cable = Cable_1); + /// Send a MIDI Continue message. + void sendContinue(Cable cable = Cable_1); + /// Send a MIDI Stop message. + void sendStop(Cable cable = Cable_1); + /// Send a MIDI Active Sensing message. + void sendActiveSensing(Cable cable = Cable_1); + /// Send a MIDI System Reset message. + void sendSystemReset(Cable cable = Cable_1); + + /// @} + + /// @name Flushing the MIDI send buffer + /// @{ + + /// Causes all buffered messages to be sent immediately. + /// @note Doesn't necessarily wait until all data has been sent, it just + /// triggers the transmission, so everything will be transmitted as + /// soon as possible. + void sendNow(); + + /// @} + + /// @name Deprecated + /// @{ + + /// Send a MIDI Key Pressure event. + /// @deprecated Use @ref sendKeyPressure(MIDIAddress,uint8_t) instead + [[deprecated("Use sendKeyPressure() instead")]] void + sendKP(MIDIAddress address, uint8_t pressure); + /// Send a MIDI Control Change event. + /// @deprecated Use @ref sendControlChange(MIDIAddress,uint8_t) instead + [[deprecated("Use sendControlChange() instead")]] void + sendCC(MIDIAddress address, uint8_t value); + /// Send a MIDI Program Change event. + /// @deprecated Use @ref sendProgramChange(MIDIAddress) instead + [[deprecated("Use sendProgramChange() instead")]] void + sendPC(MIDIAddress address); + /// Send a MIDI Program Change event. + /// @deprecated Use @ref sendProgramChange(MIDIChannelCable,uint8_t) instead + [[deprecated("Use sendProgramChange() instead")]] void + sendPC(MIDIChannelCable address, uint8_t value); + /// Send a MIDI %Channel Pressure event. + /// @deprecated Use @ref sendChannelPressure(MIDIChannelCable,uint8_t) instead + [[deprecated("Use sendChannelPressure() instead")]] void + sendCP(MIDIChannelCable address, uint8_t pressure); + /// Send a MIDI Pitch Bend event. + /// @deprecated Use @ref sendPitchBend(MIDIChannelCable,uint16_t) instead + [[deprecated("Use sendPitchBend() instead")]] void + sendPB(MIDIChannelCable address, uint16_t value); + + /// @} +}; + +END_CS_NAMESPACE + +#include "MIDI_Sender.ipp" diff --git a/MIDI_Interfaces/MIDI_Sender.ipp b/MIDI_Interfaces/MIDI_Sender.ipp new file mode 100644 index 0000000..ee5f3d1 --- /dev/null +++ b/MIDI_Interfaces/MIDI_Sender.ipp @@ -0,0 +1,255 @@ +#include "MIDI_Sender.hpp" +#include + +BEGIN_CS_NAMESPACE + +template +void MIDI_Sender::sendChannelMessage(MIDIMessageType m, Channel c, + uint8_t d1, uint8_t d2, + Cable cable) { + send(ChannelMessage(m, c, d1, d2, cable)); +} + +template +void MIDI_Sender::sendChannelMessage(MIDIMessageType m, Channel c, + uint8_t d1, Cable cable) { + send(ChannelMessage(m, c, d1, 0, cable)); +} + +template +void MIDI_Sender::sendNoteOn(MIDIAddress address, uint8_t velocity) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::NoteOn, + address.getChannel(), + address.getAddress(), + uint8_t(velocity & 0x7F), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendNoteOff(MIDIAddress address, uint8_t velocity) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::NoteOff, + address.getChannel(), + address.getAddress(), + uint8_t(velocity & 0x7F), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendKeyPressure(MIDIAddress address, + uint8_t pressure) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::KeyPressure, + address.getChannel(), + address.getAddress(), + uint8_t(pressure & 0x7F), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendControlChange(MIDIAddress address, + uint8_t value) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::ControlChange, + address.getChannel(), + address.getAddress(), + uint8_t(value & 0x7F), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendProgramChange(MIDIChannelCable address, + uint8_t value) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::ProgramChange, + address.getChannel(), + uint8_t(value & 0x7F), + uint8_t(0x00), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendProgramChange(MIDIAddress address) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::ProgramChange, + address.getChannel(), + address.getAddress(), + uint8_t(0x00), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendChannelPressure(MIDIChannelCable address, + uint8_t pressure) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::ChannelPressure, + address.getChannel(), + uint8_t(pressure & 0x7F), + uint8_t(0x00), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::sendPitchBend(MIDIChannelCable address, + uint16_t value) { + if (address) + CRTP(Derived).sendChannelMessageImpl({ + MIDIMessageType::PitchBend, + address.getChannel(), + uint8_t((value >> 0) & 0x7F), + uint8_t((value >> 7) & 0x7F), + address.getCableNumber(), + }); +} +template +void MIDI_Sender::send(SysExMessage message) { + if (message.length > 0) + CRTP(Derived).sendSysExImpl(message); +} + +template +void MIDI_Sender::send(RealTimeMessage message) { + if (message.isValid()) + CRTP(Derived).sendRealTimeImpl(message); +} + +template +void MIDI_Sender::send(ChannelMessage message) { + if (message.hasValidChannelMessageHeader()) { + message.sanitize(); + CRTP(Derived).sendChannelMessageImpl(message); + } +} + +template +void MIDI_Sender::send(SysCommonMessage message) { + if (message.hasValidSystemCommonHeader()) { + message.sanitize(); + CRTP(Derived).sendSysCommonImpl(message); + } +} + +template +template +void MIDI_Sender::sendSysEx(const uint8_t (&sysexdata)[N], + Cable cable) { + send(SysExMessage(sysexdata, N, cable)); +} +template +void MIDI_Sender::sendSysEx(const uint8_t *data, uint16_t length, + Cable cable) { + send(SysExMessage(data, length, cable)); +} + +template +void MIDI_Sender::sendSysCommon(MIDIMessageType m, Cable cable) { + send(SysCommonMessage(m, cable)); +} +template +void MIDI_Sender::sendSysCommon(MIDIMessageType m, uint8_t data1, + Cable cable) { + send(SysCommonMessage(m, data1, cable)); +} +template +void MIDI_Sender::sendSysCommon(MIDIMessageType m, uint8_t data1, + uint8_t data2, Cable cable) { + send(SysCommonMessage(m, data1, data2, cable)); +} + +template +void MIDI_Sender::sendMTCQuarterFrame(uint8_t data, Cable cable) { + send(SysCommonMessage(MIDIMessageType::MTCQuarterFrame, data, cable)); +} +template +void MIDI_Sender::sendMTCQuarterFrame(uint8_t messageType, + uint8_t values, Cable cable) { + sendMTCQuarterFrame((messageType << 4) | values, cable); +} +template +void MIDI_Sender::sendSongPositionPointer(uint16_t spp, Cable cable) { + SysCommonMessage msg(MIDIMessageType::SongPositionPointer, cable); + msg.setData14bit(spp); + send(msg); +} +template +void MIDI_Sender::sendSongSelect(uint8_t song, Cable cable) { + send(SysCommonMessage(MIDIMessageType::SongSelect, song, cable)); +} +template +void MIDI_Sender::sendTuneRequest(Cable cable) { + send(SysCommonMessage(MIDIMessageType::TuneRequest, cable)); +} + +template +void MIDI_Sender::sendRealTime(MIDIMessageType rt, Cable cable) { + send(RealTimeMessage(rt, cable)); +} +template +void MIDI_Sender::sendRealTime(uint8_t rt, Cable cable) { + send(RealTimeMessage(rt, cable)); +} + +template +void MIDI_Sender::sendTimingClock(Cable cable) { + sendRealTime(MIDIMessageType::TimingClock, cable); +} +template +void MIDI_Sender::sendStart(Cable cable) { + sendRealTime(MIDIMessageType::Start, cable); +} +template +void MIDI_Sender::sendContinue(Cable cable) { + sendRealTime(MIDIMessageType::Continue, cable); +} +template +void MIDI_Sender::sendStop(Cable cable) { + sendRealTime(MIDIMessageType::Stop, cable); +} +template +void MIDI_Sender::sendActiveSensing(Cable cable) { + sendRealTime(MIDIMessageType::ActiveSensing, cable); +} +template +void MIDI_Sender::sendSystemReset(Cable cable) { + sendRealTime(MIDIMessageType::SystemReset, cable); +} + +template +void MIDI_Sender::sendNow() { + CRTP(Derived).sendNowImpl(); +} + +template +void MIDI_Sender::sendKP(MIDIAddress address, uint8_t pressure) { + sendKeyPressure(address, pressure); +} +template +void MIDI_Sender::sendCC(MIDIAddress address, uint8_t value) { + sendControlChange(address, value); +} +template +void MIDI_Sender::sendPC(MIDIAddress address) { + sendProgramChange(address); +} +template +void MIDI_Sender::sendPC(MIDIChannelCable address, uint8_t value) { + sendProgramChange(address, value); +} +template +void MIDI_Sender::sendCP(MIDIChannelCable address, uint8_t pressure) { + sendChannelPressure(address, pressure); +} +template +void MIDI_Sender::sendPB(MIDIChannelCable address, uint16_t value) { + sendPitchBend(address, value); +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Interfaces/MIDI_Staller.hpp b/MIDI_Interfaces/MIDI_Staller.hpp new file mode 100644 index 0000000..2c2cd6d --- /dev/null +++ b/MIDI_Interfaces/MIDI_Staller.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#if !DISABLE_PIPES + +#include // std::forward +#include + +BEGIN_CS_NAMESPACE + +/// Struct that can cause a MIDI_Pipe to be stalled. +struct MIDIStaller { + virtual ~MIDIStaller() = default; + /// Get the staller's name for debugging purposes. + virtual const char *getName() const { return ""; } + /// Call back that should finish any MIDI messages that are in progress, and + /// un-stall the pipe or MIDI source as quickly as possible. + virtual void handleStall() = 0; + + /// Get the staller's name for debugging purposes. Correctly deals with + /// null pointers or eternal stallers. + static const char *getNameNull(MIDIStaller *s); +}; + +/// Allocate a MIDIStaller that executes the given callback and deletes itself +/// when @ref MIDIStaller::handleStall is called. +/// @note Don't lose the pointer! If you never call `handleStall`, the memory +/// won't be deallocated. +template +auto makeMIDIStaller(Callback &&callback) -> MIDIStaller * { + + struct AutoCleanupMIDIStaller : MIDIStaller { + AutoCleanupMIDIStaller(Callback &&callback) + : callback(std::forward(callback)) {} + + void handleStall() override { + callback(this); + delete this; + } + + Callback callback; + }; + return new AutoCleanupMIDIStaller(std::forward(callback)); +} + +END_CS_NAMESPACE + +#else + +BEGIN_CS_NAMESPACE + +struct MIDIStaller {}; + +END_CS_NAMESPACE + +#endif \ No newline at end of file diff --git a/MIDI_Outputs/Abstract/EncoderState.hpp b/MIDI_Outputs/Abstract/EncoderState.hpp new file mode 100644 index 0000000..7097958 --- /dev/null +++ b/MIDI_Outputs/Abstract/EncoderState.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/// Class to keep track of relative position changes of rotary encoders. +template +class EncoderState { + private: + using SignedEnc_t = typename std::make_signed::type; + int16_t speedMultiply; + uint8_t pulsesPerStep; + int16_t remainder = 0; + Enc_t deltaOffset = 0; + + public: + EncoderState(int16_t speedMultiply, uint8_t pulsesPerStep) + : speedMultiply(speedMultiply), pulsesPerStep(pulsesPerStep) {} + + int16_t update(Enc_t encval) { + // If Enc_t is an unsigned type, integer overflow is well-defined, which + // is what we want when Enc_t is small and expected to overflow. + // However, we need it to be signed because we're interested in the + // delta. + Enc_t uDelta = encval - deltaOffset; + if (uDelta == 0) + return 0; + int16_t delta = static_cast(uDelta); + // Assumption: delta and speedMultiply are relatively small, so + // multiplication probably won't overflow. + int16_t multipliedDelta = delta * speedMultiply + remainder; + int16_t scaledDelta = multipliedDelta / pulsesPerStep; + remainder = multipliedDelta % pulsesPerStep; + deltaOffset += uDelta; + return scaledDelta; + } + void setSpeedMultiply(int16_t speedMultiply) { + // TODO: Is this correct? Is it necessary? What with negative speedMult? + remainder = remainder * speedMultiply / this->speedMultiply; + this->speedMultiply = speedMultiply; + } + int16_t getSpeedMultiply() const { return this->speedMultiply; } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp b/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp new file mode 100644 index 0000000..26429bb --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class GenericMIDIAbsoluteEncoder : public MIDIOutputElement { + public: + GenericMIDIAbsoluteEncoder(Enc &&encoder, MIDIAddress address, + int16_t speedMultiply, uint8_t pulsesPerStep, + const Sender &sender) + : encoder(std::forward(encoder)), address(address), + encstate(speedMultiply, pulsesPerStep), sender(sender) {} + + void begin() override { begin_if_possible(encoder); } + + void update() override { + auto encval = encoder.read(); + if (int16_t delta = encstate.update(encval)) { + int16_t oldValue = value; + int16_t newValue = oldValue + delta; + newValue = constrain(newValue, 0, maxValue); + if (oldValue != newValue) { + value = newValue; + forcedUpdate(); + } + } + } + + void forcedUpdate() { sender.send(value, address); } + + uint16_t getValue() const { return value; } + void setValue(uint16_t value) { this->value = value; } + static int16_t getMaxValue() { return maxValue; } + + void setSpeedMultiply(int16_t speedMultiply) { + encstate.setSpeedMultiply(speedMultiply); + } + int16_t getSpeedMultiply() const { return encstate.getSpeedMultiply(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddress(MIDIAddress address) { this->address = address; } + + int16_t resetPositionOffset() { + auto encval = encoder.read(); + return encstate.update(encval); + } + + private: + Enc encoder; + MIDIAddress address; + int16_t value = 0; + EncoderState encstate; + + constexpr static int16_t maxValue = uint16_t(1u << Sender::precision()) - 1; + + public: + Sender sender; +}; + +template +using MIDIAbsoluteEncoder = GenericMIDIAbsoluteEncoder; + +template +using BorrowedMIDIAbsoluteEncoder = + GenericMIDIAbsoluteEncoder; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIButton.hpp b/MIDI_Outputs/Abstract/MIDIButton.hpp new file mode 100644 index 0000000..c870116 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIButton.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIButton : public MIDIOutputElement { + public: + MIDIButton(pin_t pin, MIDIAddress address, const Sender &sender) + : button(pin), address(address), sender(sender) {} + + void begin() override { button.begin(); } + void update() override { + AH::Button::State state = button.update(); + if (state == AH::Button::Falling) { + sender.sendOn(address); + } else if (state == AH::Button::Rising) { + sender.sendOff(address); + } + } + + void invert() { button.invert(); } + AH::Button::State getButtonState() const { return button.getState(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddressUnsafe(MIDIAddress address) { this->address = address; } + + private: + AH::Button button; + MIDIAddress address; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIButtonLatched.hpp b/MIDI_Outputs/Abstract/MIDIButtonLatched.hpp new file mode 100644 index 0000000..cb8464c --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIButtonLatched.hpp @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIButtonLatched : public MIDIOutputElement { + protected: + MIDIButtonLatched(pin_t pin, MIDIAddress address, const Sender &sender) + : button(pin), address(address), sender(sender) {} + + public: + void begin() final override { button.begin(); } + void update() final override { + AH::Button::State state = button.update(); + if (state == AH::Button::Falling) + toggleState(); + } + + bool toggleState() { + setState(!getState()); + return getState(); + } + + bool getState() const { return state; } + + void setState(bool state) { + this->state = state; + state ? sender.sendOn(address) : sender.sendOff(address); + } + + void invert() { button.invert(); } + AH::Button::State getButtonState() const { return button.getState(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddressUnsafe(MIDIAddress address) { this->address = address; } + + private: + AH::Button button; + MIDIAddress address; + bool state = false; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIButtonLatching.hpp b/MIDI_Outputs/Abstract/MIDIButtonLatching.hpp new file mode 100644 index 0000000..6046541 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIButtonLatching.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIButtonLatching : public MIDIOutputElement { + protected: + MIDIButtonLatching(pin_t pin, MIDIAddress address, const Sender &sender) + : button(pin), address(address), sender(sender) {} + + public: + void begin() override { button.begin(); } + void update() override { + AH::Button::State state = button.update(); + if (state == AH::Button::Falling || state == AH::Button::Rising) { + sender.sendOn(address); + sender.sendOff(address); + } + } + + AH::Button::State getButtonState() const { return button.getState(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddress(MIDIAddress address) { this->address = address; } + + private: + AH::Button button; + MIDIAddress address; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp b/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp new file mode 100644 index 0000000..53e038c --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIButtonMatrix.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIButtonMatrix + : public MIDIOutputElement, + public AH::ButtonMatrix, + NumRows, NumCols> { + using ButtonMatrix = AH::ButtonMatrix; + friend class AH::ButtonMatrix; + + protected: + MIDIButtonMatrix(const PinList &rowPins, + const PinList &colPins, + const AddressMatrix &addresses, + MIDIChannelCable channelCN, const Sender &sender) + : ButtonMatrix(rowPins, colPins), addresses(addresses), + baseChannelCN(channelCN), sender(sender) {} + + public: + void begin() final override { ButtonMatrix::begin(); } + void update() final override { ButtonMatrix::update(); } + + MIDIAddress getAddress(uint8_t row, uint8_t col) const { + return {this->addresses[row][col], baseChannelCN}; + } + void setAddressUnsafe(uint8_t row, uint8_t col, uint8_t address) { + this->addresses[row][col] = address; + } + MIDIChannelCable getChannelCable() const { return this->baseChannelCN; } + void setChannelCableUnsafe(MIDIChannelCable bccn) { + this->baseChannelCN = bccn; + } + + private: + void onButtonChanged(uint8_t row, uint8_t col, bool state) { + int8_t address = addresses[row][col]; + if (state == LOW) + sender.sendOn({address, baseChannelCN}); + else + sender.sendOff({address, baseChannelCN}); + } + + AddressMatrix addresses; + MIDIChannelCable baseChannelCN; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIButtons.hpp b/MIDI_Outputs/Abstract/MIDIButtons.hpp new file mode 100644 index 0000000..4ca4530 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIButtons.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIButtons : public MIDIOutputElement { + protected: + MIDIButtons(const Array &buttons, + MIDIAddress baseAddress, RelativeMIDIAddress incrementAddress, + const Sender &sender) + : buttons(buttons), baseAddress(baseAddress), + incrementAddress(incrementAddress), sender(sender) {} + + public: + void begin() final override { + for (auto &button : buttons) + button.begin(); + } + void update() final override { + MIDIAddress address = baseAddress; + for (auto &button : buttons) { + AH::Button::State state = button.update(); + if (state == AH::Button::Falling) { + sender.sendOn(address); + } else if (state == AH::Button::Rising) { + sender.sendOff(address); + } + address += incrementAddress; + } + } + + AH::Button::State getButtonState(size_t index) const { + return buttons[index].getState(); + } + + MIDIAddress getBaseAddress() const { return this->baseAddress; } + void setBaseAddressUnsafe(MIDIAddress address) { + this->baseAddress = address; + } + RelativeMIDIAddress getIncrementAddress() const { + return this->incrementAddress; + } + void setIncrementAddressUnsafe(RelativeMIDIAddress address) { + this->incrementAddress = address; + } + + void invert() { + for (auto &button : buttons) + button.invert(); + } + + private: + Array buttons; + MIDIAddress baseAddress; + RelativeMIDIAddress incrementAddress; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIChordButton.hpp b/MIDI_Outputs/Abstract/MIDIChordButton.hpp new file mode 100644 index 0000000..f7419b4 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIChordButton.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIChordButton : public MIDIOutputElement { + public: + template + MIDIChordButton(pin_t pin, MIDIAddress address, Chord chord, + const Sender &sender) + : button(pin), address(address), + newChord(AH::make_unique>(std::move(chord))), + sender(sender) {} + + void begin() final override { button.begin(); } + void update() final override { + AH::Button::State state = button.update(); + MIDIAddress sendAddress = address; + if (state == AH::Button::Falling) { + if (newChord) + chord = std::move(newChord); + sender.sendOn(sendAddress); + for (int8_t offset : *chord) + sender.sendOn(sendAddress + offset); + } else if (state == AH::Button::Rising) { + sender.sendOff(sendAddress); + for (int8_t offset : *chord) + sender.sendOff(sendAddress + offset); + } + } + + void invert() { button.invert(); } + AH::Button::State getButtonState() const { return button.getState(); } + + template + void setChord(Chord chord) { + newChord = AH::make_unique>(std::move(chord)); + } + + MIDIAddress getAddress() const { return this->address; } + void setAddressUnsafe(MIDIAddress address) { this->address = address; } + + private: + AH::Button button; + MIDIAddress address; + std::unique_ptr chord; + std::unique_ptr newChord; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIFilteredAnalog.hpp b/MIDI_Outputs/Abstract/MIDIFilteredAnalog.hpp new file mode 100644 index 0000000..f9afcaa --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIFilteredAnalog.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIFilteredAnalog : public MIDIOutputElement { + protected: + MIDIFilteredAnalog(pin_t analogPin, MIDIAddress address, + const Sender &sender) + : filteredAnalog(analogPin), address(address), sender(sender) {} + + public: + void begin() final override { filteredAnalog.resetToCurrentValue(); } + + void update() final override { + if (filteredAnalog.update()) + forcedUpdate(); + } + + void forcedUpdate() { sender.send(filteredAnalog.getValue(), address); } + + void map(MappingFunction fn) { filteredAnalog.map(fn); } + void invert() { filteredAnalog.invert(); } + + analog_t getRawValue() const { return filteredAnalog.getRawValue(); } + static constexpr analog_t getMaxRawValue() { + return FilteredAnalog::getMaxRawValue(); + } + analog_t getValue() const { return filteredAnalog.getValue(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddress(MIDIAddress address) { this->address = address; } + + private: + using FilteredAnalog = AH::FilteredAnalog; + FilteredAnalog filteredAnalog; + MIDIAddress address; + + public: + Sender sender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIIncrementDecrementButtons.hpp b/MIDI_Outputs/Abstract/MIDIIncrementDecrementButtons.hpp new file mode 100644 index 0000000..87b15f1 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIIncrementDecrementButtons.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class MIDIIncrementDecrementButtons : public MIDIOutputElement { + protected: + MIDIIncrementDecrementButtons(const AH::IncrementDecrementButtons &buttons, + MIDIAddress address, uint8_t multiplier, + MIDIAddress resetAddress, + const RelativeSender &relativeSender, + const ResetSender &resetSender) + : buttons(buttons), address(address), multiplier(multiplier), + resetAddress(resetAddress), relativeSender(relativeSender), + resetSender(resetSender) {} + + public: + void begin() override { buttons.begin(); } + + void update() override { + using IncrDecrButtons = AH::IncrementDecrementButtons; + switch (buttons.update()) { + case IncrDecrButtons::Nothing: break; + case IncrDecrButtons::IncrementShort: + case IncrDecrButtons::IncrementLong: + case IncrDecrButtons::IncrementHold: + send(multiplier, address); + break; + case IncrDecrButtons::DecrementShort: + case IncrDecrButtons::DecrementLong: + case IncrDecrButtons::DecrementHold: + send(-multiplier, address); + break; + case IncrDecrButtons::Reset: reset(); break; + default: break; + } + } + + void send(long delta, MIDIAddress address) { + relativeSender.send(delta, address); + } + + void reset() { + if (resetAddress) { + resetSender.sendOn(resetAddress); + resetSender.sendOff(resetAddress); + } + } + + void invert() { buttons.invert(); } + + AH::IncrementDecrementButtons::State getButtonsState() const { + return buttons.getState(); + } + + MIDIAddress getAddress() const { return this->address; } + void setAddress(MIDIAddress address) { this->address = address; } + MIDIAddress getResetAddress() const { return this->resetAddress; } + void setResetAddress(MIDIAddress address) { this->resetAddress = address; } + + private: + AH::IncrementDecrementButtons buttons; + MIDIAddress address; + uint8_t multiplier; + MIDIAddress resetAddress; + + public: + RelativeSender relativeSender; + ResetSender resetSender; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIOutputElement.hpp b/MIDI_Outputs/Abstract/MIDIOutputElement.hpp new file mode 100644 index 0000000..0898126 --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIOutputElement.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +using MIDIOutputElement = AH::Updatable<>; + +class MIDIOutputOnly : public AH::UpdatableCRTP { + public: + virtual ~MIDIOutputOnly() = default; + virtual void begin() = 0; + static void beginAll() { applyToAll(&MIDIOutputOnly::begin); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp b/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp new file mode 100644 index 0000000..f034ace --- /dev/null +++ b/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp @@ -0,0 +1,58 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class GenericMIDIRotaryEncoder : public MIDIOutputElement { + public: + GenericMIDIRotaryEncoder(Enc &&encoder, MIDIAddress address, + int16_t speedMultiply, uint8_t pulsesPerStep, + const Sender &sender) + : encoder(std::forward(encoder)), address(address), + encstate(speedMultiply, pulsesPerStep), sender(sender) {} + + void begin() override { begin_if_possible(encoder); } + + void update() override { + auto encval = encoder.read(); + if (int16_t delta = encstate.update(encval)) { + sender.send(delta, address); + } + } + + void setSpeedMultiply(int16_t speedMultiply) { + encstate.setSpeedMultiply(speedMultiply); + } + int16_t getSpeedMultiply() const { return encstate.getSpeedMultiply(); } + + MIDIAddress getAddress() const { return this->address; } + void setAddress(MIDIAddress address) { this->address = address; } + + int16_t resetPositionOffset() { + auto encval = encoder.read(); + return encstate.update(encval); + } + + private: + Enc encoder; + MIDIAddress address; + EncoderState encstate; + + public: + Sender sender; +}; + +template +using MIDIRotaryEncoder = GenericMIDIRotaryEncoder; + +template +using BorrowedMIDIRotaryEncoder = GenericMIDIRotaryEncoder; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCAbsoluteEncoder.hpp b/MIDI_Outputs/CCAbsoluteEncoder.hpp new file mode 100644 index 0000000..9cca3f8 --- /dev/null +++ b/MIDI_Outputs/CCAbsoluteEncoder.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCAbsoluteEncoder : public MIDIAbsoluteEncoder { + public: + CCAbsoluteEncoder(AHEncoder &&encoder, MIDIAddress address, + int16_t multiplier = 1, uint8_t pulsesPerStep = 4) + : MIDIAbsoluteEncoder( + std::move(encoder), address, multiplier, pulsesPerStep, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCButton.hpp b/MIDI_Outputs/CCButton.hpp new file mode 100644 index 0000000..313068a --- /dev/null +++ b/MIDI_Outputs/CCButton.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCButton : public MIDIButton { + public: + CCButton(pin_t pin, MIDIAddress address, const DigitalCCSender &sender = {}) + : MIDIButton(pin, address, sender) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCButtonLatched.hpp b/MIDI_Outputs/CCButtonLatched.hpp new file mode 100644 index 0000000..47a9b9c --- /dev/null +++ b/MIDI_Outputs/CCButtonLatched.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCButtonLatched : public MIDIButtonLatched { + public: + CCButtonLatched(pin_t pin, MIDIAddress address, + const DigitalCCSender &sender = {}) + : MIDIButtonLatched {pin, address, sender} {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCButtonLatching.hpp b/MIDI_Outputs/CCButtonLatching.hpp new file mode 100644 index 0000000..0f98822 --- /dev/null +++ b/MIDI_Outputs/CCButtonLatching.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCButtonLatching : public MIDIButtonLatching { + public: + CCButtonLatching(pin_t pin, MIDIAddress address, + const DigitalCCSender &sender = {}) + : MIDIButtonLatching(pin, address, sender) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCButtonMatrix.hpp b/MIDI_Outputs/CCButtonMatrix.hpp new file mode 100644 index 0000000..e8ff158 --- /dev/null +++ b/MIDI_Outputs/CCButtonMatrix.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class CCButtonMatrix + : public MIDIButtonMatrix { + public: + CCButtonMatrix(const PinList &rowPins, + const PinList &colPins, + const AddressMatrix &controllers, + MIDIChannelCable channelCN, + const DigitalCCSender &sender = {}) + : MIDIButtonMatrix( + rowPins, colPins, controllers, channelCN, sender) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCButtons.hpp b/MIDI_Outputs/CCButtons.hpp new file mode 100644 index 0000000..892dbb6 --- /dev/null +++ b/MIDI_Outputs/CCButtons.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class CCButtons : public MIDIButtons { + public: + CCButtons(const Array &buttons, + MIDIAddress baseAddress, RelativeMIDIAddress incrementAddress, + const DigitalCCSender &sender = {}) + : MIDIButtons(buttons, baseAddress, + incrementAddress, sender) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCIncrementDecrementButtons.hpp b/MIDI_Outputs/CCIncrementDecrementButtons.hpp new file mode 100644 index 0000000..f9b2436 --- /dev/null +++ b/MIDI_Outputs/CCIncrementDecrementButtons.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +class CCIncrementDecrementButtons + : public MIDIIncrementDecrementButtons { + public: + CCIncrementDecrementButtons(const AH::IncrementDecrementButtons &buttons, + MIDIAddress address, uint8_t multiplier = 1, + MIDIAddress resetNote = MIDIAddress::invalid(), + const RelativeCCSender &relativeSender = {}, + const DigitalNoteSender &resetSender = {}) + : MIDIIncrementDecrementButtons(buttons, address, multiplier, resetNote, + relativeSender, resetSender) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCPotentiometer.hpp b/MIDI_Outputs/CCPotentiometer.hpp new file mode 100644 index 0000000..06bd7e0 --- /dev/null +++ b/MIDI_Outputs/CCPotentiometer.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCPotentiometer : public MIDIFilteredAnalog { + public: + CCPotentiometer(pin_t analogPin, MIDIAddress address) + : MIDIFilteredAnalog(analogPin, address, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/CCRotaryEncoder.hpp b/MIDI_Outputs/CCRotaryEncoder.hpp new file mode 100644 index 0000000..a6f976b --- /dev/null +++ b/MIDI_Outputs/CCRotaryEncoder.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class CCRotaryEncoder : public MIDIRotaryEncoder { + public: + CCRotaryEncoder(AHEncoder &&encoder, MIDIAddress address, + int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) + : MIDIRotaryEncoder( + std::move(encoder), address, speedMultiply, pulsesPerStep, {}) {} +}; + +class BorrowedCCRotaryEncoder + : public BorrowedMIDIRotaryEncoder { + public: + BorrowedCCRotaryEncoder(AHEncoder &encoder, MIDIAddress address, + int16_t speedMultiply = 1, + uint8_t pulsesPerStep = 4) + : BorrowedMIDIRotaryEncoder( + encoder, address, speedMultiply, pulsesPerStep, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteButton.hpp b/MIDI_Outputs/NoteButton.hpp new file mode 100644 index 0000000..e1eca16 --- /dev/null +++ b/MIDI_Outputs/NoteButton.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class NoteButton : public MIDIButton { + public: + NoteButton(pin_t pin, MIDIAddress address, uint8_t velocity = 0x7F) + : MIDIButton {pin, address, {velocity}} {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteButtonLatched.hpp b/MIDI_Outputs/NoteButtonLatched.hpp new file mode 100644 index 0000000..828b67e --- /dev/null +++ b/MIDI_Outputs/NoteButtonLatched.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class NoteButtonLatched : public MIDIButtonLatched { + public: + NoteButtonLatched(pin_t pin, MIDIAddress address, uint8_t velocity = 0x7F) + : MIDIButtonLatched {pin, address, {velocity}} {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteButtonLatching.hpp b/MIDI_Outputs/NoteButtonLatching.hpp new file mode 100644 index 0000000..40dcf11 --- /dev/null +++ b/MIDI_Outputs/NoteButtonLatching.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class NoteButtonLatching : public MIDIButtonLatching { + public: + NoteButtonLatching(pin_t pin, MIDIAddress address, uint8_t velocity = 0x7F) + : MIDIButtonLatching {pin, address, {velocity}} {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteButtonMatrix.hpp b/MIDI_Outputs/NoteButtonMatrix.hpp new file mode 100644 index 0000000..9d10aea --- /dev/null +++ b/MIDI_Outputs/NoteButtonMatrix.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class NoteButtonMatrix + : public MIDIButtonMatrix { + public: + NoteButtonMatrix(const PinList &rowPins, + const PinList &colPins, + const AddressMatrix ¬es, + MIDIChannelCable channelCN = {Channel_1, Cable_1}, + uint8_t velocity = 0x7F) + : MIDIButtonMatrix { + rowPins, colPins, notes, channelCN, {velocity}} {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteButtons.hpp b/MIDI_Outputs/NoteButtons.hpp new file mode 100644 index 0000000..fe8e35e --- /dev/null +++ b/MIDI_Outputs/NoteButtons.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class NoteButtons : public MIDIButtons { + public: + NoteButtons(const Array &buttons, + MIDIAddress baseAddress, RelativeMIDIAddress incrementAddress, + uint8_t velocity = 0x7F) + : MIDIButtons { + buttons, baseAddress, incrementAddress, {velocity}} {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/NoteChordButton.hpp b/MIDI_Outputs/NoteChordButton.hpp new file mode 100644 index 0000000..89de19e --- /dev/null +++ b/MIDI_Outputs/NoteChordButton.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class NoteChordButton : public MIDIChordButton { + public: + template + NoteChordButton(pin_t pin, MIDIAddress address, Chord chord, + uint8_t velocity = 0x7F) + : MIDIChordButton(pin, address, std::move(chord), + {velocity}) {} + + void setVelocity(uint8_t velocity) { this->sender.setVelocity(velocity); } + uint8_t getVelocity() const { return this->sender.getVelocity(); } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/PBAbsoluteEncoder.hpp b/MIDI_Outputs/PBAbsoluteEncoder.hpp new file mode 100644 index 0000000..9d1c000 --- /dev/null +++ b/MIDI_Outputs/PBAbsoluteEncoder.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class PBAbsoluteEncoder : public MIDIAbsoluteEncoder> { + public: + PBAbsoluteEncoder(AHEncoder &&encoder, MIDIChannelCable address, + int16_t multiplier = 1, uint8_t pulsesPerStep = 4) + : MIDIAbsoluteEncoder>( + std::move(encoder), address, multiplier, pulsesPerStep, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/PBPotentiometer.hpp b/MIDI_Outputs/PBPotentiometer.hpp new file mode 100644 index 0000000..739c89d --- /dev/null +++ b/MIDI_Outputs/PBPotentiometer.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class PBPotentiometer : public MIDIFilteredAnalog> { + public: + PBPotentiometer(pin_t analogPin, MIDIChannelCable address = Channel_1) + : MIDIFilteredAnalog(analogPin, address, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/PCButton.hpp b/MIDI_Outputs/PCButton.hpp new file mode 100644 index 0000000..3a01348 --- /dev/null +++ b/MIDI_Outputs/PCButton.hpp @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class PCButton : public MIDIButton { + public: + PCButton(pin_t pin, MIDIAddress address) : MIDIButton(pin, address, {}) {} +}; + +END_CS_NAMESPACE diff --git a/MIDI_Outputs/ProgramChanger.hpp b/MIDI_Outputs/ProgramChanger.hpp new file mode 100644 index 0000000..4818df3 --- /dev/null +++ b/MIDI_Outputs/ProgramChanger.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class ProgramChanger : public Selectable { + public: + ProgramChanger(const Array &programs, + MIDIChannelCable channelCN) + : programs(programs), channelCN(channelCN) {} + + void select(setting_t setting) override { + setting = this->validateSetting(setting); + Control_Surface.sendProgramChange(channelCN, programs[setting]); + } + + private: + Array programs; + MIDIChannelCable channelCN; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Parsers/AnyMIDI_Message.hpp b/MIDI_Parsers/AnyMIDI_Message.hpp new file mode 100644 index 0000000..3433fdf --- /dev/null +++ b/MIDI_Parsers/AnyMIDI_Message.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include "MIDIReadEvent.hpp" +#include "MIDI_MessageTypes.hpp" +#include + +BEGIN_CS_NAMESPACE + +/// MIDI message variant type (with timestamp). +struct AnyMIDIMessage { + MIDIReadEvent eventType = MIDIReadEvent::NO_MESSAGE; + union Message { + ChannelMessage channelmessage; + SysCommonMessage syscommonmessage; + RealTimeMessage realtimemessage; + SysExMessage sysexmessage; + + Message() : realtimemessage(0x00) {} + Message(ChannelMessage msg) : channelmessage(msg) {} + Message(SysCommonMessage msg) : syscommonmessage(msg) {} + Message(RealTimeMessage msg) : realtimemessage(msg) {} + Message(SysExMessage msg) : sysexmessage(msg) {} + } message; + uint16_t timestamp = 0xFFFF; + + AnyMIDIMessage() = default; + AnyMIDIMessage(ChannelMessage message, uint16_t timestamp) + : eventType(MIDIReadEvent::CHANNEL_MESSAGE), message(message), + timestamp(timestamp) {} + AnyMIDIMessage(SysCommonMessage message, uint16_t timestamp) + : eventType(MIDIReadEvent::SYSCOMMON_MESSAGE), message(message), + timestamp(timestamp) {} + AnyMIDIMessage(RealTimeMessage message, uint16_t timestamp) + : eventType(MIDIReadEvent::REALTIME_MESSAGE), message(message), + timestamp(timestamp) {} + AnyMIDIMessage(SysExMessage message, uint16_t timestamp) + : eventType(message.isLastChunk() ? MIDIReadEvent::SYSEX_MESSAGE + : MIDIReadEvent::SYSEX_CHUNK), + message(message), timestamp(timestamp) {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/BLEMIDIParser.hpp b/MIDI_Parsers/BLEMIDIParser.hpp new file mode 100644 index 0000000..7647c79 --- /dev/null +++ b/MIDI_Parsers/BLEMIDIParser.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief Class for parsing BLE-MIDI packets. It doesn't parse the actual MIDI + * messages, it just extracts the relevant MIDI data from the BLE + * packets. + * + * @ingroup MIDIParsers + */ +class BLEMIDIParser { + public: + BLEMIDIParser(const uint8_t *data, size_t length) + : data(data), end(data + length) { + // Need at least two bytes to be useful. + // Usually, we have header, timestamp and at least one MIDI byte, + // but a SysEx continuation could perhaps have only a header and a + // single data byte (this is not explicitly allowed by the spec, but + // handling this case requires no extra effort) + if (length < 2) { + this->data = end; + } + // First byte should be a header. If it's a data byte, discard packet. + else if (isData(data[0])) { + this->data = end; + } + // If the second byte is a data byte, this is a SysEx continuation + // packet + else if (isData(data[1])) { + this->timestamp = data[0] & 0x7F; + this->timestamp <<= 7; + this->data += 1; + } + // Otherwise, the second byte is a timestamp, so skip it + else { + this->timestamp = data[0] & 0x7F; + this->timestamp <<= 7; + this->timestamp |= data[1] & 0x7F; + this->data += 2; + } + } + + /// Extend the BLE packet with the given buffer. + /// @pre The previous buffer was fully consumed (@ref pull returned false). + /// @note This function should only be used for a single packet that spans + /// multiple buffers. If you want to parse a new packet, you should + /// create a new BLEMIDIParser instance. + void extend(const uint8_t *data, size_t length) { + this->data = data; + this->end = data + length; + } + + /// Get the next MIDI byte from the BLE packet (if available). + /// @return True if a byte was available, false otherwise. + bool pull(uint8_t &output) { + while (data != end) { + // Simply pass on all normal data bytes to the MIDI parser. + if (isData(*data)) { + output = *data++; + prevWasTimestamp = false; + return true; + } + // If it's not a data byte, it's either a timestamp byte or a + // MIDI status byte. + else { + // Timestamp bytes and MIDI status bytes should alternate. + prevWasTimestamp = !prevWasTimestamp; + // If the previous non-data byte was a timestamp, this one is + // a MIDI status byte, so send it to the MIDI parser. + if (!prevWasTimestamp) { + output = *data++; + return true; + } + // Otherwise it's a time stamp + else { + uint16_t timestampLow = *data++ & 0x7F; + // The BLE MIDI spec has the following to say about overflow: + // > Should the timestamp value of a subsequent MIDI message + // > in the same packet overflow/wrap (i.e., the + // > timestampLow is smaller than a preceding timestampLow), + // > the receiver is responsible for tracking this by + // > incrementing the timestampHigh by one (the incremented + // > value is not transmitted, only understood as a result + // > of the overflow condition). + if (timestampLow < (timestamp & 0x7F)) // overflow + timestamp += 0x80; + timestamp = (timestamp & 0x3F80) | timestampLow; + } + } + } + return false; + } + + uint16_t getTimestamp() const { return timestamp; } + + private: + const uint8_t *data; + const uint8_t *end; + bool prevWasTimestamp = true; + uint16_t timestamp = 0; + + private: + /// Check if the given byte is a data byte (and not a header, timestamp or + /// status byte). + static bool isData(uint8_t data) { return (data & (1 << 7)) == 0; } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Parsers/MIDIReadEvent.hpp b/MIDI_Parsers/MIDIReadEvent.hpp new file mode 100644 index 0000000..a93de71 --- /dev/null +++ b/MIDI_Parsers/MIDIReadEvent.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include +#include + +BEGIN_CS_NAMESPACE + +/// Values returned by the MIDI reading functions. +enum class MIDIReadEvent : uint8_t { + NO_MESSAGE = 0, ///< No new messages were received. + CHANNEL_MESSAGE = 1, ///< A MIDI Channel message was received. + SYSEX_MESSAGE = 2, ///< A MIDI System Exclusive message was received. + REALTIME_MESSAGE = 3, ///< A MIDI Real-Time message was received. + SYSEX_CHUNK = 4, ///< An incomplete System Exclusive message. + SYSCOMMON_MESSAGE = 5, ///< A MIDI System Common message was received. +}; + +inline FlashString_t enum_to_string(MIDIReadEvent evt) { + switch (evt) { + case MIDIReadEvent::NO_MESSAGE: return F("NO_MESSAGE"); + case MIDIReadEvent::CHANNEL_MESSAGE: return F("CHANNEL_MESSAGE"); + case MIDIReadEvent::SYSEX_MESSAGE: return F("SYSEX_MESSAGE"); + case MIDIReadEvent::REALTIME_MESSAGE: return F("REALTIME_MESSAGE"); + case MIDIReadEvent::SYSEX_CHUNK: return F("SYSEX_CHUNK"); + case MIDIReadEvent::SYSCOMMON_MESSAGE: return F("SYSCOMMON_MESSAGE"); + default: return F(""); + } +} + +inline Print &operator<<(Print &p, MIDIReadEvent evt) { + return p << enum_to_string(evt); +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/MIDI_MessageTypes.cpp b/MIDI_Parsers/MIDI_MessageTypes.cpp new file mode 100644 index 0000000..33de696 --- /dev/null +++ b/MIDI_Parsers/MIDI_MessageTypes.cpp @@ -0,0 +1,37 @@ +#include "MIDI_MessageTypes.hpp" +#include "Settings/NamespaceSettings.hpp" + +BEGIN_CS_NAMESPACE + +FlashString_t enum_to_string(MIDIMessageType m) { + using M = MIDIMessageType; + switch (m) { + case M::None: return F("None"); + case M::NoteOff: return F("NoteOff"); + case M::NoteOn: return F("NoteOn"); + case M::KeyPressure: return F("KeyPressure"); + case M::ControlChange: return F("ControlChange"); + case M::ProgramChange: return F("ProgramChange"); + case M::ChannelPressure: return F("ChannelPressure"); + case M::PitchBend: return F("PitchBend"); + case M::SysExStart: return F("SysExStart"); + case M::MTCQuarterFrame: return F("MTCQuarterFrame"); + case M::SongPositionPointer: return F("SongPositionPointer"); + case M::SongSelect: return F("SongSelect"); + case M::UndefinedSysCommon1: return F("UndefinedSysCommon1"); + case M::UndefinedSysCommon2: return F("UndefinedSysCommon2"); + case M::TuneRequest: return F("TuneRequest"); + case M::SysExEnd: return F("SysExEnd"); + case M::TimingClock: return F("TimingClock"); + case M::UndefinedRealTime1: return F("UndefinedRealTime1"); + case M::Start: return F("Start"); + case M::Continue: return F("Continue"); + case M::Stop: return F("Stop"); + case M::UndefinedRealTime2: return F("UndefinedRealTime2"); + case M::ActiveSensing: return F("ActiveSensing"); + case M::SystemReset: return F("SystemReset"); + default: return F(""); + } +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/MIDI_MessageTypes.hpp b/MIDI_Parsers/MIDI_MessageTypes.hpp new file mode 100644 index 0000000..337d0f9 --- /dev/null +++ b/MIDI_Parsers/MIDI_MessageTypes.hpp @@ -0,0 +1,419 @@ +#pragma once + +#include +#include // operator<< +#include // size_t +#include +#include + +#ifndef ARDUINO +#include +#endif + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +/// All possible MIDI status byte values (without channel). +enum class MIDIMessageType : uint8_t { + None = 0x00, ///< Special value that does not correspond to an actual + ///< message type. + /* Channel Voice Messages */ + NoteOff = 0x80, ///< Note Off Channel Voice message (3B). + NoteOn = 0x90, ///< Note On Channel Voice message (3B). + KeyPressure = 0xA0, ///< Key Pressure Channel Voice message (3B). + ControlChange = 0xB0, ///< Control Change Channel Voice message (3B). + ProgramChange = 0xC0, ///< Program Change Channel Voice message (2B). + ChannelPressure = 0xD0, ///< Channel Pressure Channel Voice message (2B). + PitchBend = 0xE0, ///< Pitch Bend Channel Voice message (3B). + + SysExStart = 0xF0, ///< Start of System Exclusive. + + /* System Common messages */ + MTCQuarterFrame = 0xF1, ///< MIDI Time Code Quarter Frame System Common + ///< message (2B). + SongPositionPointer = 0xF2, ///< Song Position Pointer System Common + ///< message (3B). + SongSelect = 0xF3, ///< Song Select System Common message (2B). + UndefinedSysCommon1 = 0xF4, ///< Undefined System Common message 0xF4 (1B). + UndefinedSysCommon2 = 0xF5, ///< Undefined System Common message 0xF5 (1B). + TuneRequest = 0xF6, ///< Tune Request System Common message (1B). + SysExEnd = 0xF7, ///< End of System Exclusive. + + /* System Real-Time messages */ + TimingClock = 0xF8, ///< Timing Clock System Real-Time message. + UndefinedRealTime1 = 0xF9, ///< Undefined System Real-Time message 0xF9. + Start = 0xFA, ///< Start System Real-Time message. + Continue = 0xFB, ///< Continue System Real-Time message. + Stop = 0xFC, ///< Stop System Real-Time message. + UndefinedRealTime2 = 0xFD, ///< Undefined System Real-Time message 0xFD. + ActiveSensing = 0xFE, ///< Active Sensing System Real-Time message. + SystemReset = 0xFF, ///< Reset System Real-Time message. + +// clang-format off +#ifndef DOXYGEN + NONE CS_DEPREC("Use None instead") = None, + NOTE_OFF CS_DEPREC("Use NoteOff instead") = NoteOff, + NOTE_ON CS_DEPREC("Use NoteOn instead") = NoteOn, + KEY_PRESSURE CS_DEPREC("Use KeyPressure instead") = KeyPressure, + CC CS_DEPREC("Use ControlChange instead") = ControlChange, + CONTROL_CHANGE CS_DEPREC("Use ControlChange instead") = ControlChange, + PROGRAM_CHANGE CS_DEPREC("Use ProgramChange instead") = ProgramChange, + CHANNEL_PRESSURE CS_DEPREC("Use ChannelPressure instead") = ChannelPressure, + PITCH_BEND CS_DEPREC("Use PitchBend instead") = PitchBend, + SYSEX_START CS_DEPREC("Use SysExStart instead") = SysExStart, + MTC_QUARTER_FRAME CS_DEPREC("Use MTCQuarterFrame instead") = MTCQuarterFrame, + SONG_POSITION_POINTER CS_DEPREC("Use SongPositionPointer instead") = SongPositionPointer, + SONG_SELECT CS_DEPREC("Use SongSelect instead") = SongSelect, + UNDEFINED_SYSCOMMON_1 CS_DEPREC("Use UndefinedSysCommon1 instead") = UndefinedSysCommon1, + UNDEFINED_SYSCOMMON_2 CS_DEPREC("Use UndefinedSysCommon2 instead") = UndefinedSysCommon2, + TUNE_REQUEST CS_DEPREC("Use TuneRequest instead") = TuneRequest, + SYSEX_END CS_DEPREC("Use SysExEnd instead") = SysExEnd, + TIMING_CLOCK CS_DEPREC("Use TimingClock instead") = TimingClock, + UNDEFINED_REALTIME_1 CS_DEPREC("Use UndefinedRealTime1 instead") = UndefinedRealTime1, + START CS_DEPREC("Use Start instead") = Start, + CONTINUE CS_DEPREC("Use Continue instead") = Continue, + STOP CS_DEPREC("Use Stop instead") = Stop, + UNDEFINED_REALTIME_2 CS_DEPREC("Use UndefinedRealTime2 instead") = UndefinedRealTime2, + ACTIVE_SENSING CS_DEPREC("Use ActiveSensing instead") = ActiveSensing, + SYSTEM_RESET CS_DEPREC("Use SystemReset instead") = SystemReset, +#endif // DOXYGEN + // clang-format on +}; + +/// MIDI USB Code Index Numbers. +/// +/// @see Table 4-1 in . +enum class MIDICodeIndexNumber : uint8_t { + MiscFunctionCodes = 0x0, + CableEvents = 0x1, + SystemCommon2B = 0x2, + SystemCommon3B = 0x3, + SysExStartCont = 0x4, + SystemCommon1B = 0x5, + SysExEnd1B = 0x5, + SysExEnd2B = 0x6, + SysExEnd3B = 0x7, + + NoteOff = 0x8, + NoteOn = 0x9, + KeyPressure = 0xA, + ControlChange = 0xB, + ProgramChange = 0xC, + ChannelPressure = 0xD, + PitchBend = 0xE, + + SingleByte = 0xF, +}; + +// -------------------------------------------------------------------------- // + +struct MIDIMessage { + /// Constructor. + MIDIMessage(uint8_t header, uint8_t data1, uint8_t data2, + Cable cable = Cable_1) + : header(header), data1(data1), data2(data2), cable(cable) {} + + /// Constructor. + MIDIMessage(MIDIMessageType header, uint8_t data1, uint8_t data2, + Cable cable = Cable_1) + : header(uint8_t(header)), data1(data1), data2(data2), cable(cable) {} + + uint8_t header; ///< MIDI status byte (message type and channel). + uint8_t data1; ///< First MIDI data byte + uint8_t data2; ///< First MIDI data byte + + Cable cable; ///< USB MIDI cable number; + + /// Check for equality. + bool operator==(MIDIMessage other) const { + return this->header == other.header && this->data1 == other.data1 && + this->data2 == other.data2 && this->cable == other.cable; + } + /// Check for inequality. + bool operator!=(MIDIMessage other) const { return !(*this == other); } + + /// Get the MIDI message type. + MIDIMessageType getMessageType() const { + if (hasValidChannelMessageHeader()) { + return static_cast(header & 0xF0); + } else { + return static_cast(header); + } + } + /// Set the MIDI message type. + /// @note Do not use this version for Channel Messages, it doesn't + /// correctly handle the channel. + void setMessageType(MIDIMessageType type) { + header = static_cast(type); + } + + /// Get the first data byte. + uint8_t getData1() const { return data1; } + /// Get the second data byte. + uint8_t getData2() const { return data2; } + /// Set the first data byte. + void setData1(uint8_t data) { data1 = data; } + /// Set the second data byte. + void setData2(uint8_t data) { data2 = data; } + + /// Get the MIDI USB cable number of the message. + Cable getCable() const { return cable; } + /// Set the MIDI USB cable number of the message. + void setCable(Cable cable) { this->cable = cable; } + + /// Check whether the header is a valid header for a channel message. + bool hasValidChannelMessageHeader() const { + return header >= (uint8_t(MIDIMessageType::NoteOff) | 0x00) && + header <= (uint8_t(MIDIMessageType::PitchBend) | 0x0F); + } + + /// Check whether the header is a valid header for a System Common message. + /// @note SysExEnd is considered a System Common message by the MIDI + /// Standard, SysExStart is not. + /// @note Reserved System Common messages are also considered valid System + /// Common messages. + bool hasValidSystemCommonHeader() const { + return (header & 0xF8) == 0xF0 && header != 0xF0; + } + + /// If Data 1 and Data 2 represent a single 14-bit number, you can use this + /// method to retrieve that number. + uint16_t getData14bit() const { + return data1 | (uint16_t(data2) << uint16_t(7)); + } + /// If Data 1 and Data 2 represent a single 14-bit number, you can use this + /// method to set that number. + void setData14bit(uint16_t data) { + data1 = (data >> 0) & 0x7F; + data2 = (data >> 7) & 0x7F; + } + + /// Make sure that the status byte has the most significant bit set and + /// the data bytes have the most significant bits cleared. + void sanitize() { + header |= 0x80; + data1 &= 0x7F; + data2 &= 0x7F; + } +}; + +struct ChannelMessage : MIDIMessage { + using MIDIMessage::MIDIMessage; + + /// Constructor. + ChannelMessage(MIDIMessageType type, Channel channel, uint8_t data1, + uint8_t data2 = 0x00, Cable cable = Cable_1) + : MIDIMessage(uint8_t(type) | channel.getRaw(), data1, data2, cable) {} + + explicit ChannelMessage(const MIDIMessage &msg) : MIDIMessage(msg) {} + + /// Get the MIDI message type. + MIDIMessageType getMessageType() const { + return static_cast(header & 0xF0); + } + /// Set the MIDI message type. + void setMessageType(MIDIMessageType type) { + header &= 0x0F; + header |= static_cast(type) & 0xF0; + } + + /// Get the MIDI channel of the message. + Channel getChannel() const { return Channel(header & 0x0F); } + /// Set the MIDI channel of the message. + void setChannel(Channel channel) { + header &= 0xF0; + header |= channel.getRaw(); + } + + /// Get the MIDI channel and cable number. + /// @note Valid for all MIDI Channel messages, including Channel Pressure + /// and Pitch Bend. + MIDIChannelCable getChannelCable() const { return {getChannel(), cable}; } + /// Get the MIDI address of this message, using `data1` as the address. + /// @note Don't use this for Channel Pressure or Pitch Bend messages, + /// as `data1` will have a different meaning in those cases. + MIDIAddress getAddress() const { return {data1, getChannelCable()}; } + + /// Check whether this message has one or two data bytes. + /// + /// - 2 data bytes: Note On/Off, Aftertouch, Control Change or Pitch Bend + /// - 1 data byte: Program Change or Channel Pressure + /// + /// Returns false if the header is a SysEx, Real-Time or System Common byte. + bool hasTwoDataBytes() const { + auto type = getMessageType(); + return type <= MIDIMessageType::ControlChange || + type == MIDIMessageType::PitchBend; + } + + constexpr static auto NoteOff = MIDIMessageType::NoteOff; + constexpr static auto NoteOn = MIDIMessageType::NoteOn; + constexpr static auto KeyPressure = MIDIMessageType::KeyPressure; + constexpr static auto ControlChange = MIDIMessageType::ControlChange; + constexpr static auto ProgramChange = MIDIMessageType::ProgramChange; + constexpr static auto ChannelPressure = MIDIMessageType::ChannelPressure; + constexpr static auto PitchBend = MIDIMessageType::PitchBend; +}; + +struct SysCommonMessage : MIDIMessage { + using MIDIMessage::MIDIMessage; + + /// Constructor. + SysCommonMessage(MIDIMessageType type, uint8_t data1 = 0x00, + uint8_t data2 = 0x00, Cable cable = Cable_1) + : MIDIMessage(type, data1, data2, cable) {} + /// Constructor. + SysCommonMessage(MIDIMessageType type, uint8_t data1, Cable cable) + : SysCommonMessage(type, data1, 0x00, cable) {} + /// Constructor. + SysCommonMessage(MIDIMessageType type, Cable cable) + : SysCommonMessage(type, 0x00, 0x00, cable) {} + + explicit SysCommonMessage(const MIDIMessage &msg) : MIDIMessage(msg) {} + + /// Get the MIDI message type. + MIDIMessageType getMessageType() const { + return static_cast(header); + } + + /// Get the number of data bytes of this type of System Common message. + uint8_t getNumberOfDataBytes() const { + if (getMessageType() == MIDIMessageType::SongPositionPointer) + return 2; + else if (getMessageType() <= MIDIMessageType::SongSelect) + return 1; + else + return 0; + } + + constexpr static auto MTCQuarterFrame = MIDIMessageType::MTCQuarterFrame; + constexpr static auto SongPositionPointer = + MIDIMessageType::SongPositionPointer; + constexpr static auto SongSelect = MIDIMessageType::SongSelect; + constexpr static auto UndefinedSysCommon1 = + MIDIMessageType::UndefinedSysCommon1; + constexpr static auto UndefinedSysCommon2 = + MIDIMessageType::UndefinedSysCommon2; + constexpr static auto TuneRequest = MIDIMessageType::TuneRequest; +}; + +struct SysExMessage { + /// Constructor. + SysExMessage() : data(nullptr), length(0), cable(Cable_1) {} + + /// Constructor. + SysExMessage(const uint8_t *data, uint16_t length, Cable cable = Cable_1) + : data(data), length(length), cable(cable.getRaw()) {} + + /// Constructor. + SysExMessage(const std::vector &vec, Cable cable = Cable_1) + : SysExMessage(vec.data(), vec.size(), cable) {} + + /// Constructor. + template + SysExMessage(const uint8_t (&array)[N], Cable cable = Cable_1) + : SysExMessage(array, N, cable) {} + + const uint8_t *data; + uint16_t length; + + Cable cable; + + bool operator==(SysExMessage other) const { + return this->length == other.length && this->cable == other.cable && + (this->length == 0 || + memcmp(this->data, other.data, length) == 0); + } + bool operator!=(SysExMessage other) const { return !(*this == other); } + + /// Get the MIDI USB cable number of the message. + Cable getCable() const { return cable; } + /// Set the MIDI USB cable number of the message. + void setCable(Cable cable) { this->cable = cable; } + + bool isFirstChunk() const { + return length >= 1 && data[0] == uint8_t(MIDIMessageType::SysExStart); + } + + bool isLastChunk() const { + return length >= 1 && + data[length - 1] == uint8_t(MIDIMessageType::SysExEnd); + } + + bool isCompleteMessage() const { return isFirstChunk() && isLastChunk(); } + + constexpr static auto SysExStart = MIDIMessageType::SysExStart; + constexpr static auto SysExEnd = MIDIMessageType::SysExEnd; +}; + +struct RealTimeMessage { + /// Constructor. + RealTimeMessage(uint8_t message, Cable cable = Cable_1) + : message(message), cable(cable.getRaw()) {} + + /// Constructor. + RealTimeMessage(MIDIMessageType message, Cable cable = Cable_1) + : message(uint8_t(message)), cable(cable.getRaw()) {} + + uint8_t message; + Cable cable; + + bool operator==(RealTimeMessage other) const { + return this->message == other.message && this->cable == other.cable; + } + bool operator!=(RealTimeMessage other) const { return !(*this == other); } + + /// Set the MIDI message type. + void setMessageType(MIDIMessageType type) { + message = static_cast(type); + } + /// Get the MIDI message type. + MIDIMessageType getMessageType() const { + return static_cast(message); + } + + /// Get the MIDI USB cable number of the message. + Cable getCable() const { return cable; } + /// Set the MIDI USB cable number of the message. + void setCable(Cable cable) { this->cable = cable; } + + /// Check whether the header is a valid header for a Real-Time message. + bool isValid() const { return message >= 0xF8; } + + constexpr static auto TimingClock = MIDIMessageType::TimingClock; + constexpr static auto UndefinedRealTime1 = + MIDIMessageType::UndefinedRealTime1; + constexpr static auto Start = MIDIMessageType::Start; + constexpr static auto Continue = MIDIMessageType::Continue; + constexpr static auto Stop = MIDIMessageType::Stop; + constexpr static auto UndefinedRealTime2 = + MIDIMessageType::UndefinedRealTime2; + constexpr static auto ActiveSensing = MIDIMessageType::ActiveSensing; + constexpr static auto RESET = MIDIMessageType::SystemReset; +}; + +#ifndef ARDUINO +inline std::ostream &operator<<(std::ostream &os, SysExMessage m) { + os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length) + << " (cable " << m.cable.getOneBased() << ")"; + return os; +} +#endif + +inline Print &operator<<(Print &os, SysExMessage m) { + os << "SysExMessage [" << m.length << "] " << AH::HexDump(m.data, m.length) + << " (cable " << m.cable.getOneBased() << ")"; + return os; +} + +FlashString_t enum_to_string(MIDIMessageType); +inline Print &operator<<(Print &os, MIDIMessageType m) { + return os << enum_to_string(m); +} + +END_CS_NAMESPACE diff --git a/MIDI_Parsers/MIDI_Parser.hpp b/MIDI_Parsers/MIDI_Parser.hpp new file mode 100644 index 0000000..ab65ae3 --- /dev/null +++ b/MIDI_Parsers/MIDI_Parser.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include "MIDIReadEvent.hpp" +#include "MIDI_MessageTypes.hpp" + +BEGIN_CS_NAMESPACE + +/// Base class for MIDI parsers. +class MIDI_Parser { + public: + /// Get the latest MIDI channel voice message. + ChannelMessage getChannelMessage() const { return ChannelMessage(midimsg); } + /// Get the latest MIDI system common message. + SysCommonMessage getSysCommonMessage() const { + return SysCommonMessage(midimsg); + } + /// Get the latest MIDI real-time message. + RealTimeMessage getRealTimeMessage() const { return rtmsg; } +#if IGNORE_SYSEX + /// Get the latest SysEx message. + SysExMessage getSysExMessage() const { return {nullptr, 0, Cable_1}; } +#endif + + protected: + MIDIMessage midimsg = {0x00, 0x00, 0x00}; + RealTimeMessage rtmsg = {0x00}; + + public: + /// Check if the given byte is a MIDI header/status byte. + static bool isStatus(uint8_t data) { return data & (1 << 7); } + /// Check if the given byte is a MIDI data byte. + static bool isData(uint8_t data) { return (data & (1 << 7)) == 0; } +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/SerialMIDI_Parser.cpp b/MIDI_Parsers/SerialMIDI_Parser.cpp new file mode 100644 index 0000000..6222422 --- /dev/null +++ b/MIDI_Parsers/SerialMIDI_Parser.cpp @@ -0,0 +1,229 @@ +#include "SerialMIDI_Parser.hpp" + +BEGIN_CS_NAMESPACE + +MIDIReadEvent SerialMIDI_Parser::handleRealTime(uint8_t midiByte) { + rtmsg.message = midiByte; + return MIDIReadEvent::REALTIME_MESSAGE; +} + +MIDIReadEvent SerialMIDI_Parser::handleNonRealTimeStatus(uint8_t midiByte) { +#if !IGNORE_SYSEX + // If a SysEx message was being received, and now we receive another + // status byte, the status byte should terminate the SysEx message + // first, and then we can handle the new status byte later. + bool untermSysEx = currentHeader == uint8_t(MIDIMessageType::SysExStart); + if (untermSysEx) { + // Handle this new status byte later (unless it's just a SysEx End + // byte, in which case we can just terminate it now). + if (midiByte != uint8_t(MIDIMessageType::SysExEnd)) + storeByte(midiByte); + // Terminate the SysEx message. + // Check if the SysEx buffer has enough space to store the end byte. + if (!hasSysExSpace()) { + // If not store the new status byte to handle it later, and + // return the chunk we have saved up to now. + storeByte(midiByte); + return MIDIReadEvent::SYSEX_CHUNK; + } + // Enough space is available in buffer, store the end byte and + // terminate the message. + addSysExByte(uint8_t(MIDIMessageType::SysExEnd)); + endSysEx(); + currentHeader = 0; + runningHeader = 0; + return MIDIReadEvent::SYSEX_MESSAGE; + } else +#endif + { + // Tune Request is a special System Common message of 1 byte. + if (midiByte == uint8_t(MIDIMessageType::TuneRequest)) { + midimsg.header = midiByte; + midimsg.data1 = 0; + midimsg.data2 = 0; + if (sysCommonCancelsRunningStatus) + runningHeader = 0; + currentHeader = 0; + return MIDIReadEvent::SYSCOMMON_MESSAGE; + } +#if !IGNORE_SYSEX + // If the new status byte is a SysExStart, reset the SysEx buffer + // and store the start byte. + else if (midiByte == uint8_t(MIDIMessageType::SysExStart)) { + startSysEx(); + addSysExByte(uint8_t(MIDIMessageType::SysExStart)); + runningHeader = 0; + currentHeader = midiByte; + return MIDIReadEvent::NO_MESSAGE; + } + // This should already have been handled by the if (untermSysEx) above. + else if (midiByte == uint8_t(MIDIMessageType::SysExEnd)) { + DEBUGREF(F("Unexpected SysEx End")); + return MIDIReadEvent::NO_MESSAGE; + } +#endif + // Otherwise, start a System Common or Channel message. + else { + // Save the newly received status byte. + currentHeader = midiByte; + // A new message starts, so we haven't received the second byte + // yet. + thirdByte = false; + return MIDIReadEvent::NO_MESSAGE; + } + } +} + +/* + * Relevant sources about MIDI running status: + * - MIDI 1.0 Detailed Specification: A-2 (pdf p.65): + * “cleared when a System Exclusive or Common status message is received” + * - BLE-MIDI: p.4 (pdf p.7): + * “System Common and System Real-Time messages do not cancel Running Status” + */ + +MIDIReadEvent SerialMIDI_Parser::handleStatus(uint8_t midiByte) { + // If it's a Real-Time message + if (midiByte >= uint8_t(MIDIMessageType::TimingClock)) { + return handleRealTime(midiByte); + } + // Normal header (channel message, system exclusive, system common): + else { + return handleNonRealTimeStatus(midiByte); + } +} + +MIDIReadEvent SerialMIDI_Parser::handleData(uint8_t midiByte) { + if (currentHeader == 0) { + // If we didn't receive a header, we can't do anything with this data + if (runningHeader == 0) { + DEBUGREF(F("Data byte ignored")); + return MIDIReadEvent::NO_MESSAGE; + } + // If we have an active running status, use that as the current header + currentHeader = runningHeader; + } + + midimsg.header = currentHeader; + + // If this is the third byte of three (second data byte) + if (thirdByte) { + // If it's a channel message + if (midimsg.hasValidChannelMessageHeader()) { + midimsg.data2 = midiByte; + // Next byte is either a header or the first data byte of the next + // message, so clear the thirdByte flag + thirdByte = false; + runningHeader = midimsg.header; + currentHeader = 0; + return MIDIReadEvent::CHANNEL_MESSAGE; + } + // If it's a system common message + else if (midimsg.hasValidSystemCommonHeader()) { + midimsg.data2 = midiByte; + thirdByte = false; + if (sysCommonCancelsRunningStatus) + runningHeader = 0; + currentHeader = 0; + return MIDIReadEvent::SYSCOMMON_MESSAGE; + } + } + + // If this is not the third byte of three, it's either the second byte + // (first data byte) of a channel or system common message, + // or a SysEx data byte + + // If it's a channel message + else if (midimsg.hasValidChannelMessageHeader()) { + // If it's a channel message with two data bytes + if (ChannelMessage(midimsg).hasTwoDataBytes()) { + midimsg.data1 = midiByte; + // We've received the second byte, expect the third byte next + thirdByte = true; + return MIDIReadEvent::NO_MESSAGE; + } + // If it's a channel message with one data byte + else { + midimsg.data1 = midiByte; + midimsg.data2 = 0; + runningHeader = midimsg.header; + currentHeader = 0; + // The message is finished + return MIDIReadEvent::CHANNEL_MESSAGE; + } + } + + // If it's a system common message + else if (midimsg.hasValidSystemCommonHeader()) { + // If it's a system common message with two data bytes + if (SysCommonMessage(midimsg).getNumberOfDataBytes() == 2) { + midimsg.data1 = midiByte; + // We've received the second byte, expect the third byte next + thirdByte = true; + return MIDIReadEvent::NO_MESSAGE; + } + // If it's a system common message with one data byte + else if (SysCommonMessage(midimsg).getNumberOfDataBytes() == 1) { + midimsg.data1 = midiByte; + midimsg.data2 = 0; + if (sysCommonCancelsRunningStatus) + runningHeader = 0; + currentHeader = 0; + // The message is finished + return MIDIReadEvent::SYSCOMMON_MESSAGE; + } + } + + // Otherwise, it's not a channel message + +#if !IGNORE_SYSEX + // If we're receiving a SysEx message, it's a SysEx data byte + else if (currentHeader == uint8_t(MIDIMessageType::SysExStart)) { + // Check if the SysEx buffer has enough space to store the data + if (!hasSysExSpace()) { + storeByte(midiByte); // Remember to add it next time + return MIDIReadEvent::SYSEX_CHUNK; + } + + addSysExByte(midiByte); + return MIDIReadEvent::NO_MESSAGE; + } +#endif // IGNORE_SYSEX + + DEBUGREF(F("Data byte after invalid header")); // LCOV_EXCL_LINE + runningHeader = 0; // LCOV_EXCL_LINE + currentHeader = 0; // LCOV_EXCL_LINE + return MIDIReadEvent::NO_MESSAGE; // LCOV_EXCL_LINE +} + +MIDIReadEvent SerialMIDI_Parser::feed(uint8_t midiByte) { + // DEBUGREF(hex << NAMEDVALUE(midiByte) << dec); + + // If it's a status byte (first byte of a message) + if (isStatus(midiByte)) { + return handleStatus(midiByte); + } + // If it's a data byte + else { + return handleData(midiByte); + } +} + +MIDIReadEvent SerialMIDI_Parser::resume() { + if (!hasStoredByte()) + return MIDIReadEvent::NO_MESSAGE; + + uint8_t midiByte = popStoredByte(); + +#if !IGNORE_SYSEX + // If a SysEx message was in progress + if (currentHeader == uint8_t(MIDIMessageType::SysExStart)) { + // Reset the buffer for the next chunk + startSysEx(); + } +#endif + + return feed(midiByte); +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/SerialMIDI_Parser.hpp b/MIDI_Parsers/SerialMIDI_Parser.hpp new file mode 100644 index 0000000..c8aabc6 --- /dev/null +++ b/MIDI_Parsers/SerialMIDI_Parser.hpp @@ -0,0 +1,113 @@ +#pragma once + +#include "MIDI_Parser.hpp" +#include "SysExBuffer.hpp" + +BEGIN_CS_NAMESPACE + +/** + * @brief Parser for Serial MIDI streams (and BLE-MIDI). + * + * @ingroup MIDIParsers + */ +class SerialMIDI_Parser : public MIDI_Parser { + public: + SerialMIDI_Parser(bool sysCommonCancelsRunningStatus = true) + : sysCommonCancelsRunningStatus(sysCommonCancelsRunningStatus) {} + + /** + * @brief Parse one incoming MIDI message. + * @param puller + * The source of MIDI bytes. + * @return The type of MIDI message available, or + * `MIDIReadEvent::NO_MESSAGE` if `puller` ran out of bytes before + * a complete message was parsed. + */ + template + MIDIReadEvent pull(BytePuller &&puller); + + protected: + /// Feed a new byte to the parser. + MIDIReadEvent feed(uint8_t midibyte); + /// Resume the parser with the previously stored and unhandled byte. + MIDIReadEvent resume(); + +#if !IGNORE_SYSEX + public: + /// Get the latest SysEx message. + SysExMessage getSysExMessage() const { + return {sysexbuffer.getBuffer(), sysexbuffer.getLength()}; + } + + protected: + void addSysExByte(uint8_t data) { sysexbuffer.add(data); } + bool hasSysExSpace() const { return sysexbuffer.hasSpaceLeft(); } + void startSysEx() { sysexbuffer.start(); } + void endSysEx() { sysexbuffer.end(); } + + SysExBuffer sysexbuffer; +#endif + + protected: + MIDIReadEvent handleRealTime(uint8_t midiByte); + MIDIReadEvent handleNonRealTimeStatus(uint8_t midiByte); + MIDIReadEvent handleStatus(uint8_t midiByte); + MIDIReadEvent handleData(uint8_t midiByte); + + protected: + /// Store a byte to parse later. This is used when the SysEx buffer is full, + /// for example. The byte cannot be added to the buffer now, so store it to + /// add it the next time the parser is updated. + void storeByte(uint8_t midiByte) { storedByte = midiByte; } + /// Check whether there's a stored byte. If this is the case, this byte + /// should be parsed before reading a new byte. + bool hasStoredByte() const { return storedByte != 0xFF; } + /// Get the stored byte. Afterwards, @ref hasStoredByte will return false. + uint8_t popStoredByte() { + uint8_t t = storedByte; + storedByte = 0xFF; + return t; + } + + public: + /// Clear the running status header for MIDI Channel messages. + /// Internal method. + void cancelRunningStatus() { runningHeader = 0; } + + private: + /// Accounts for running status differences between MIDI 1.0 and BLE-MIDI. + bool sysCommonCancelsRunningStatus; + /// Flag that remembers that the next data byte will be the third byte of + /// a message. + bool thirdByte = false; + /// Current header (not necessarily running), contains the header of the + /// message that's currently being received. As soon as the message is + /// complete, it is set to zero. + uint8_t currentHeader = 0; + /// Running status header. + uint8_t runningHeader = 0; + /// @see @ref storeByte + uint8_t storedByte = 0xFF; +}; + +template +inline MIDIReadEvent SerialMIDI_Parser::pull(BytePuller &&puller) { + // First try resuming the parser, we might have a stored byte that has to + // be parsed first. + MIDIReadEvent evt = resume(); + if (evt != MIDIReadEvent::NO_MESSAGE) + return evt; + + // If resumption didn't produce a message, read new bytes from the input and + // parse them until either we get a message, or until the input runs out of + // new bytes. + uint8_t midiByte; + while (puller.pull(midiByte)) { + evt = feed(midiByte); + if (evt != MIDIReadEvent::NO_MESSAGE) + return evt; + } + return MIDIReadEvent::NO_MESSAGE; +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/SysExBuffer.cpp b/MIDI_Parsers/SysExBuffer.cpp new file mode 100644 index 0000000..95491b0 --- /dev/null +++ b/MIDI_Parsers/SysExBuffer.cpp @@ -0,0 +1,36 @@ +#include "SysExBuffer.hpp" +#include + +BEGIN_CS_NAMESPACE + +void SysExBuffer::start() { + length = 0; // if the previous message wasn't finished, overwrite it + receiving = true; +} + +void SysExBuffer::end() { receiving = false; } + +void SysExBuffer::add(uint8_t data) { + buffer[length] = data; + ++length; +} + +void SysExBuffer::add(const uint8_t *data, uint8_t len) { + memcpy(buffer + length, data, len); + length += len; +} + +bool SysExBuffer::hasSpaceLeft(uint8_t amount) const { + bool avail = length <= SYSEX_BUFFER_SIZE - amount; + if (!avail) + DEBUG(F("SysEx: Buffer full (") << amount << ')'); + return avail; +} + +bool SysExBuffer::isReceiving() const { return receiving; } + +const uint8_t *SysExBuffer::getBuffer() const { return buffer; } + +uint16_t SysExBuffer::getLength() const { return length; } + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/SysExBuffer.hpp b/MIDI_Parsers/SysExBuffer.hpp new file mode 100644 index 0000000..0d43fe1 --- /dev/null +++ b/MIDI_Parsers/SysExBuffer.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief Helper for storing the System Exclusive messages being received by + * a MIDI parser. + * + * @ingroup MIDIParsers + */ +class SysExBuffer { + private: + uint8_t buffer[SYSEX_BUFFER_SIZE]; + uint16_t length = 0; + bool receiving = false; + + public: + /// Start a new SysEx message. + void start(); + /// Finish the current SysEx message. + void end(); + /// Add a byte to the current SysEx message. + void add(uint8_t data); + /// Add multiple bytes to the current SysEx message. + void add(const uint8_t *data, uint8_t len); + /// Check if the buffer has at least `amount` bytes of free space available. + bool hasSpaceLeft(uint8_t amount = 1) const; + /// Check if the buffer is receiving a SysEx message. + bool isReceiving() const; + /// Get a pointer to the buffer. + const uint8_t *getBuffer() const; + /// Get the length of the SysEx message in the buffer. + uint16_t getLength() const; +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Parsers/USBMIDI_Parser.hpp b/MIDI_Parsers/USBMIDI_Parser.hpp new file mode 100644 index 0000000..e4d4b88 --- /dev/null +++ b/MIDI_Parsers/USBMIDI_Parser.hpp @@ -0,0 +1,126 @@ +#include "MIDI_Parser.hpp" +#include "SysExBuffer.hpp" +#include + +#ifdef MIDI_NUM_CABLES +#define USB_MIDI_NUMBER_OF_CABLES MIDI_NUM_CABLES +#elif defined(USB_MIDI4_SERIAL) || defined(USB_MIDI4) +#define USB_MIDI_NUMBER_OF_CABLES 4 +#elif defined(USB_MIDI16_AUDIO_SERIAL) || defined(USB_MIDI16_SERIAL) || \ + defined(USB_MIDI16) +// TODO: || defined(USB_EVERYTHING) +#define USB_MIDI_NUMBER_OF_CABLES 16 +#elif defined(ARDUINO_ARCH_RP2040) +#define USB_MIDI_NUMBER_OF_CABLES 16 +#elif !defined(ARDUINO) || defined(DOXYGEN) +#define USB_MIDI_NUMBER_OF_CABLES 16 +#else +#define USB_MIDI_NUMBER_OF_CABLES 1 +#endif + +BEGIN_CS_NAMESPACE + +/** + * @brief Parser for MIDI over USB packets. + * + * @ingroup MIDIParsers + */ +class USBMIDI_Parser : public MIDI_Parser { + public: + using MIDIUSBPacket_t = AH::Array; + + /** + * @brief Parse one incoming MIDI message. + * @param puller + * The source of MIDI USB packets. + * @return The type of MIDI message available, or + * `MIDIReadEvent::NO_MESSAGE` if `puller` ran out of packets + * before a complete message was parsed. + */ + template + MIDIReadEvent pull(BytePuller &&puller); + + protected: + /// Feed a new packet to the parser. + MIDIReadEvent feed(MIDIUSBPacket_t packet); + /// Resume the parser with the previously stored and unhandled packet. + MIDIReadEvent resume(); + + public: +#if !IGNORE_SYSEX + /// Get the latest SysEx message. + SysExMessage getSysExMessage() const { + return { + sysexbuffers[activeCable.getRaw()].getBuffer(), + sysexbuffers[activeCable.getRaw()].getLength(), + activeCable, + }; + } +#endif + + protected: + MIDIReadEvent handleChannelMessage(MIDIUSBPacket_t packet, Cable cable); + MIDIReadEvent handleSingleByte(MIDIUSBPacket_t packet, Cable cable); + MIDIReadEvent handleSysExStartCont(MIDIUSBPacket_t packet, Cable cable); + template + MIDIReadEvent handleSysExEnd(MIDIUSBPacket_t packet, Cable cable); + MIDIReadEvent handleSysCommon(MIDIUSBPacket_t packet, Cable cable); + + protected: +#if !IGNORE_SYSEX + void startSysEx(Cable cable) { sysexbuffers[cable.getRaw()].start(); } + void endSysEx(Cable cable) { + sysexbuffers[cable.getRaw()].end(); + activeCable = cable; + } + void endSysExChunk(Cable cable) { activeCable = cable; } + bool hasSysExSpace(Cable cable, uint8_t amount) const { + return sysexbuffers[cable.getRaw()].hasSpaceLeft(amount); + } + void addSysExByte(Cable cable, uint8_t data) { + sysexbuffers[cable.getRaw()].add(data); + } + void addSysExBytes(Cable cable, const uint8_t *data, uint8_t len) { + sysexbuffers[cable.getRaw()].add(data, len); + } + bool receivingSysEx(Cable cable) const { + return sysexbuffers[cable.getRaw()].isReceiving(); + } + + void storePacket(MIDIUSBPacket_t packet) { storedPacket = packet; } + bool hasStoredPacket() const { return storedPacket[0] != 0x00; } + MIDIUSBPacket_t popStoredPacket() { + MIDIUSBPacket_t t = storedPacket; + storedPacket[0] = 0x00; + return t; + } + + Cable activeCable = Cable_1; + + private: + SysExBuffer sysexbuffers[USB_MIDI_NUMBER_OF_CABLES] = {}; + MIDIUSBPacket_t storedPacket = {{ 0x00 }}; +#endif +}; + +template +inline MIDIReadEvent USBMIDI_Parser::pull(BytePuller &&puller) { + // First try resuming the parser, we might have a stored packet that has to + // be parsed first. + MIDIReadEvent evt = resume(); + if (evt != MIDIReadEvent::NO_MESSAGE) + return evt; + + // If resumption didn't produce a message, read new packets from the input + // and parse them until either we get a message, or until the input runs out + // of new packets. + MIDIUSBPacket_t midiPacket; + while (puller.pull(midiPacket)) { + evt = feed(midiPacket); + if (evt != MIDIReadEvent::NO_MESSAGE) + return evt; + } + return MIDIReadEvent::NO_MESSAGE; +} + +END_CS_NAMESPACE \ No newline at end of file diff --git a/MIDI_Senders/ContinuousCCSender.hpp b/MIDI_Senders/ContinuousCCSender.hpp new file mode 100644 index 0000000..8ee98e1 --- /dev/null +++ b/MIDI_Senders/ContinuousCCSender.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +class ContinuousCCSender { + public: + void send(uint8_t value, MIDIAddress address) { + Control_Surface.sendControlChange(address, value); + } + constexpr static uint8_t precision() { return 7; } +}; + +template +class ContinuousCCSender14 { + public: + void send(uint16_t value, MIDIAddress address) { + value = AH::increaseBitDepth<14, precision(), uint16_t>(value); + Control_Surface.sendControlChange(address + 0x00, (value >> 7) & 0x7F); + Control_Surface.sendControlChange(address + 0x20, (value >> 0) & 0x7F); + } + + constexpr static uint8_t precision() { + static_assert(INPUT_PRECISION_BITS <= 14, + "Maximum resolution is 14 bits"); + return INPUT_PRECISION_BITS; + } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/DigitalCCSender.hpp b/MIDI_Senders/DigitalCCSender.hpp new file mode 100644 index 0000000..e861b99 --- /dev/null +++ b/MIDI_Senders/DigitalCCSender.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +class DigitalCCSender { + public: + DigitalCCSender(uint8_t onValue = 0x7F, uint8_t offValue = 0x00) + : onValue(onValue), offValue(offValue) {} + + void sendOn(MIDIAddress address) { + Control_Surface.sendControlChange(address, onValue); + } + void sendOff(MIDIAddress address) { + Control_Surface.sendControlChange(address, offValue); + } + + uint8_t getOnValue() const { return this->onValue; } + void setOnValue(uint8_t onValue) { this->onValue = onValue; } + uint8_t getOffValue() const { return this->offValue; } + void setOffValue(uint8_t offValue) { this->offValue = offValue; } + + private: + uint8_t onValue; + uint8_t offValue; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/DigitalNoteSender.hpp b/MIDI_Senders/DigitalNoteSender.hpp new file mode 100644 index 0000000..f2e4a20 --- /dev/null +++ b/MIDI_Senders/DigitalNoteSender.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +class DigitalNoteSender { + public: + DigitalNoteSender(uint8_t velocity = 0x7F) : velocity(velocity) {} + + void sendOn(MIDIAddress address) { + Control_Surface.sendNoteOn(address, getVelocity()); + } + void sendOff(MIDIAddress address) { + Control_Surface.sendNoteOff(address, 0x7F); + } + + void setVelocity(uint8_t velocity) { this->velocity = velocity; } + uint8_t getVelocity() const { return this->velocity; } + + private: + uint8_t velocity; +}; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/PitchBendSender.hpp b/MIDI_Senders/PitchBendSender.hpp new file mode 100644 index 0000000..fa08592 --- /dev/null +++ b/MIDI_Senders/PitchBendSender.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +class PitchBendSender { + public: + static void send(uint16_t value, MIDIAddress address) { + value = AH::increaseBitDepth<14, precision(), uint16_t>(value); + MIDIChannelCable channelCN = address.getChannelCable(); + Control_Surface.sendPitchBend(channelCN, value); + } + + constexpr static uint8_t precision() { + static_assert(INPUT_PRECISION_BITS <= 14, + "Maximum pitch bend resolution is 14 bits"); + return INPUT_PRECISION_BITS; + } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/ProgramChangeSender.hpp b/MIDI_Senders/ProgramChangeSender.hpp new file mode 100644 index 0000000..aecd78f --- /dev/null +++ b/MIDI_Senders/ProgramChangeSender.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +class ProgramChangeSender { + public: + void sendOn(MIDIAddress address) { + Control_Surface.sendProgramChange(address); + } + void sendOff(MIDIAddress address) { (void)address; } +}; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/RelativeCCSender.cpp b/MIDI_Senders/RelativeCCSender.cpp new file mode 100644 index 0000000..c9a091e --- /dev/null +++ b/MIDI_Senders/RelativeCCSender.cpp @@ -0,0 +1,7 @@ +#include "RelativeCCSender.hpp" + +BEGIN_CS_NAMESPACE + +relativeCCmode RelativeCCSender::mode = TWOS_COMPLEMENT; + +END_CS_NAMESPACE diff --git a/MIDI_Senders/RelativeCCSender.hpp b/MIDI_Senders/RelativeCCSender.hpp new file mode 100644 index 0000000..6182a77 --- /dev/null +++ b/MIDI_Senders/RelativeCCSender.hpp @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +enum relativeCCmode { + TWOS_COMPLEMENT, + BINARY_OFFSET, + SIGN_MAGNITUDE, + NEXT_ADDRESS = 4, + REAPER_RELATIVE_1 = TWOS_COMPLEMENT, + REAPER_RELATIVE_2 = BINARY_OFFSET, + REAPER_RELATIVE_3 = SIGN_MAGNITUDE, + TRACKTION_RELATIVE = TWOS_COMPLEMENT, + MACKIE_CONTROL_RELATIVE = SIGN_MAGNITUDE, + KORG_KONTROL_INC_DEC_1 = NEXT_ADDRESS, +}; + +class RelativeCCSender { + public: + static uint8_t toTwosComplement7bit(int8_t value) { return value & 0x7F; } + static uint8_t toBinaryOffset7bit(int8_t value) { return value + 64; } + static uint8_t toSignedMagnitude7bit(int8_t value) { + uint8_t mask = value >> 7; + uint8_t abs = (value + mask) ^ mask; + uint8_t sign = mask & 0b01000000; + return (abs & 0b00111111) | sign; + } + + static uint8_t mapRelativeCC(int8_t value) { + switch (mode) { + case TWOS_COMPLEMENT: return toTwosComplement7bit(value); + case BINARY_OFFSET: return toBinaryOffset7bit(value); + case SIGN_MAGNITUDE: return toSignedMagnitude7bit(value); + case NEXT_ADDRESS: return value < 0 ? -value : value; + default: return 0; + } + } + + static void send(long delta, MIDIAddress address) { + if (delta < 0 && mode == NEXT_ADDRESS) + address = address + 1; + while (delta != 0) { + long thisDelta = constrain(delta, -15, 15); + uint8_t msgVal = mapRelativeCC(thisDelta); + Control_Surface.sendControlChange(address, msgVal); + delta -= thisDelta; + } + } + + static void setMode(relativeCCmode mode) { RelativeCCSender::mode = mode; } + + private: + static relativeCCmode mode; +}; + +END_CS_NAMESPACE diff --git a/Selectors/EncoderSelector.hpp b/Selectors/EncoderSelector.hpp new file mode 100644 index 0000000..26093d7 --- /dev/null +++ b/Selectors/EncoderSelector.hpp @@ -0,0 +1,86 @@ +#pragma once + +#include "Selector.hpp" +#include +#include +#include + +#include + +BEGIN_CS_NAMESPACE + +template +class GenericEncoderSelector : public GenericSelector { + using Parent = GenericSelector; + + public: + GenericEncoderSelector(Selectable &selectable, const Callback &callback, + const EncoderSwitchPinList &pins, + int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap) + : GenericSelector {selectable, callback}, + encoder {pins.A, pins.B}, switchPin(pins.switchPin), + pulsesPerStep(pulsesPerStep), wrap(wrap) {} + + void begin() override { + Parent::begin(); + if (switchPin != NO_PIN) + AH::ExtIO::pinMode(switchPin, INPUT_PULLUP); + begin_if_possible(encoder); + } + + void update() override { + Parent::update(); + // TODO: use EncoderState + long currentPosition = encoder.read(); + long difference = (currentPosition - previousPosition) / pulsesPerStep; + if (difference) { + previousPosition += difference * pulsesPerStep; + if (difference > 0) + while (difference-- > 0) + this->increment(wrap); + else + while (difference++ < 0) + this->decrement(wrap); + } + + if (switchPin != NO_PIN) { + bool currentState = AH::ExtIO::digitalRead(switchPin); + if (previousSwitchState == HIGH && currentState == LOW) { + // TODO: invert? + this->reset(); + } + previousSwitchState = currentState; + } + } + + private: + AHEncoder encoder; + pin_t switchPin; + int8_t pulsesPerStep; + Wrap wrap; + + long previousPosition = 0; + bool previousSwitchState = HIGH; +}; + +// -------------------------------------------------------------------------- // + +/** + * @brief Selector that reads from a rotary encoder. + * + * @ingroup Selectors + * + * @tparam N + * The number of settings. + */ +template +class EncoderSelector : public GenericEncoderSelector { + public: + EncoderSelector(Selectable &selectable, const EncoderSwitchPinList &pins, + int8_t pulsesPerStep = 4, Wrap wrap = Wrap::Wrap) + : GenericEncoderSelector { + selectable, {}, pins, pulsesPerStep, wrap, + } {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/IncrementDecrementSelector.hpp b/Selectors/IncrementDecrementSelector.hpp new file mode 100644 index 0000000..4b4b624 --- /dev/null +++ b/Selectors/IncrementDecrementSelector.hpp @@ -0,0 +1,82 @@ +#pragma once + +#include "Selector.hpp" +#include + +BEGIN_CS_NAMESPACE + +template +class GenericIncrementDecrementSelector : public GenericSelector { + using Parent = GenericSelector; + + public: + GenericIncrementDecrementSelector( + Selectable &selectable, const Callback &callback, + const AH::IncrementDecrementButtons &buttons, Wrap wrap = Wrap::Wrap) + : GenericSelector {selectable, callback}, buttons(buttons), + wrap(wrap) {} + + void begin() override { + Parent::begin(); + buttons.begin(); + } + + void update() override { + Parent::update(); + using IncrDecrButtons = AH::IncrementDecrementButtons; + switch (buttons.update()) { + case IncrDecrButtons::Nothing: break; + case IncrDecrButtons::IncrementShort: // fallthrough + case IncrDecrButtons::IncrementLong: // fallthrough + case IncrDecrButtons::IncrementHold: this->increment(wrap); break; + case IncrDecrButtons::DecrementShort: // fallthrough + case IncrDecrButtons::DecrementLong: // fallthrough + case IncrDecrButtons::DecrementHold: this->decrement(wrap); break; + case IncrDecrButtons::Reset: this->reset(); break; + default: break; + } + } + + /// @see @ref AH::Button::invert() + void invert() { buttons.invert(); } + + AH::IncrementDecrementButtons::State getButtonsState() const { + return buttons.getState(); + } + + private: + AH::IncrementDecrementButtons buttons; + Wrap wrap; +}; + +// -------------------------------------------------------------------------- // + +/** + * @brief Selector with two buttons (one to increment, one to decrement). + * + * Pressing two buttons simultaneously resets to the default setting. + * + * @htmlonly + * + * @endhtmlonly + * + * @ingroup Selectors + * + * @tparam N + * The number of settings. + */ +template +class IncrementDecrementSelector : public GenericIncrementDecrementSelector { + public: + IncrementDecrementSelector(Selectable &selectable, + const AH::IncrementDecrementButtons &buttons, + Wrap wrap = Wrap::Wrap) + : GenericIncrementDecrementSelector { + selectable, + {}, + buttons, + wrap, + } {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/IncrementSelector.hpp b/Selectors/IncrementSelector.hpp new file mode 100644 index 0000000..8e6898f --- /dev/null +++ b/Selectors/IncrementSelector.hpp @@ -0,0 +1,74 @@ +#pragma once + +#include "Selector.hpp" +#include + +BEGIN_CS_NAMESPACE + +template +class GenericIncrementSelector : public GenericSelector { + using Parent = GenericSelector; + + public: + GenericIncrementSelector(Selectable &selectable, + const Callback &callback, + const AH::IncrementButton &button) + : GenericSelector {selectable, callback}, button(button) {} + + void begin() override { + Parent::begin(); + button.begin(); + } + + void update() override { + Parent::update(); + switch (button.update()) { + case AH::IncrementButton::Nothing: break; + case AH::IncrementButton::IncrementShort: // fallthrough + case AH::IncrementButton::IncrementLong: // fallthrough + case AH::IncrementButton::IncrementHold: + this->increment(Wrap::Wrap); + break; + case AH::IncrementButton::ReleasedShort: break; + case AH::IncrementButton::ReleasedLong: break; + default: break; + } + } + + AH::IncrementButton::State getButtonState() const { + return button.getState(); + } + + /// @see @ref AH::Button::invert() + void invert() { button.invert(); } + + private: + AH::IncrementButton button; +}; + +// -------------------------------------------------------------------------- // + +/** + * @brief Selector with one button that increments the selection. + * + * @htmlonly + * + * @endhtmlonly + * + * @ingroup Selectors + * + * @tparam N + * The number of settings. + */ +template +class IncrementSelector : virtual public GenericIncrementSelector { + public: + IncrementSelector(Selectable &selectable, + const AH::IncrementButton &button) + : GenericIncrementSelector {selectable, {}, button} {} + + IncrementSelector(Selectable &selectable, const AH::Button &button) + : GenericIncrementSelector {selectable, {}, button} {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/LEDs/SelectorLEDs.hpp b/Selectors/LEDs/SelectorLEDs.hpp new file mode 100644 index 0000000..cd908be --- /dev/null +++ b/Selectors/LEDs/SelectorLEDs.hpp @@ -0,0 +1,218 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class SelectorLEDsCallback { + public: + SelectorLEDsCallback(const PinList &ledPins) : ledPins(ledPins) {} + + /// Initialize. + void begin() { + for (pin_t pin : ledPins) { + AH::ExtIO::pinMode(pin, OUTPUT); + AH::ExtIO::digitalWrite(pin, LOW); + } + } + + /// Refresh, called periodically. + void update() {} + + /// Called when the setting changes. + void update(setting_t oldSetting, setting_t newSetting) { + AH::ExtIO::digitalWrite(ledPins[oldSetting], LOW); + AH::ExtIO::digitalWrite(ledPins[newSetting], HIGH); + } + + private: + PinList ledPins; +}; + +class SelectorSingleLEDCallback { + public: + SelectorSingleLEDCallback(pin_t ledPin) : ledPin(ledPin) {} + + /// Initialize. + void begin() { AH::ExtIO::pinMode(ledPin, OUTPUT); } + + /// Refresh, called periodically. + void update() {} + + /// Called when the setting changes. + void update(setting_t oldSetting, setting_t newSetting) { + (void)oldSetting; + AH::ExtIO::digitalWrite(ledPin, newSetting == 0 ? LOW : HIGH); + } + + private: + pin_t ledPin; +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief EncoderSelector + * This version displays the setting using LEDs. + * @details @copydetails EncoderSelector + * @ingroup SelectorsLEDs + */ +template +class EncoderSelectorLEDs + : public GenericEncoderSelector> { + public: + EncoderSelectorLEDs(Selectable &selectable, + const EncoderSwitchPinList &pins, + const PinList &ledPins, int8_t pulsesPerStep = 4, + Wrap wrap = Wrap::Wrap) + : GenericEncoderSelector> { + selectable, {ledPins}, pins, pulsesPerStep, wrap, + } {} +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief IncrementDecrementSelector + * This version displays the setting using LEDs. + * @details @copydetails IncrementDecrementSelector + * @ingroup SelectorsLEDs + */ +template +class IncrementDecrementSelectorLEDs + : public GenericIncrementDecrementSelector> { + public: + IncrementDecrementSelectorLEDs(Selectable &selectable, + const AH::IncrementDecrementButtons &buttons, + const PinList &ledPins, + Wrap wrap = Wrap::Wrap) + : GenericIncrementDecrementSelector> { + selectable, + {ledPins}, + buttons, + wrap, + } {} +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief IncrementSelector + * This version displays the setting using LEDs. + * @details @copydetails IncrementSelector + * @ingroup SelectorsLEDs + */ +template +class IncrementSelectorLEDs + : public GenericIncrementSelector> { + public: + IncrementSelectorLEDs(Selectable &selectable, const AH::Button &button, + const PinList &ledPins) + : GenericIncrementSelector> { + selectable, {ledPins}, button} {} +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief ManyButtonsSelector + * This version displays the setting using LEDs. + * @details @copydetails ManyButtonsSelector + * @ingroup SelectorsLEDs + */ +template +class ManyButtonsSelectorLEDs + : public GenericManyButtonsSelector> { + public: + ManyButtonsSelectorLEDs(Selectable &selectable, + const PinList &buttonPins, + const PinList &ledPins) + : GenericManyButtonsSelector> { + selectable, + {ledPins}, + buttonPins, + } {} +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief ProgramChangeSelector + * This version displays the setting using LEDs. + * @details @copydetails ProgramChangeSelector + * @ingroup SelectorsLEDs + */ +template +class ProgramChangeSelectorLEDs + : public GenericProgramChangeSelector> { + public: + ProgramChangeSelectorLEDs(Selectable &selectable, + MIDIChannelCable address, + const PinList &ledPins) + : GenericProgramChangeSelector> { + selectable, + {ledPins}, + address, + } {} +}; + +END_CS_NAMESPACE + +// -------------------------------------------------------------------------- // + +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief @copybrief SwitchSelector + * This version displays the setting using LEDs. + * @details @copydetails SwitchSelector + * @ingroup SelectorsLEDs + */ +class SwitchSelectorLED + : public GenericSwitchSelector { + public: + SwitchSelectorLED(Selectable<2> &selectable, const AH::Button &button, + pin_t ledPin) + : GenericSwitchSelector { + selectable, + {ledPin}, + button, + } {} +}; + +END_CS_NAMESPACE diff --git a/Selectors/ManyButtonsSelector.hpp b/Selectors/ManyButtonsSelector.hpp new file mode 100644 index 0000000..7c33e67 --- /dev/null +++ b/Selectors/ManyButtonsSelector.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include "Selector.hpp" +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class GenericManyButtonsSelector : public GenericSelector { + using Parent = GenericSelector; + + public: + GenericManyButtonsSelector(Selectable &selectable, + const Callback &callback, + const PinList &buttonPins) + : GenericSelector {selectable, callback}, + buttons(AH::copyAs(buttonPins)) {} + + void begin() override { + Parent::begin(); + for (auto &btn : buttons) + btn.begin(); + } + + void update() override { + Parent::update(); + for (setting_t i = 0; i < N; i++) + if (buttons[i].update() == AH::Button::Falling && + buttons[this->get()].getState() != AH::Button::Pressed) + this->set(i); + } + + void invert() { + for (auto &btn : buttons) + btn.invert(); + } + + private: + AH::Array buttons; +}; + +// -------------------------------------------------------------------------- // + +/** + * @brief Selector that reads from @f$ N @f$ buttons. + * + * Pressing the @f$ n @f$-th button selects the @f$ n @f$-th setting. + * + * @htmlonly + * + * @endhtmlonly + * + * @ingroup Selectors + * + * @tparam N + * The number of settings. + */ +template +class ManyButtonsSelector : public GenericManyButtonsSelector { + public: + ManyButtonsSelector(Selectable &selectable, const PinList &buttonPins) + : GenericManyButtonsSelector { + selectable, + {}, + buttonPins, + } {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/ProgramChangeSelector.hpp b/Selectors/ProgramChangeSelector.hpp new file mode 100644 index 0000000..c7b3b22 --- /dev/null +++ b/Selectors/ProgramChangeSelector.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template +class GenericProgramChangeSelector + : public GenericSelector, + public MatchingMIDIInputElement { + public: + using Matcher = OneByteMIDIMatcher; + using Parent = + MatchingMIDIInputElement; + + GenericProgramChangeSelector(Selectable &selectable, + const Callback &callback, + MIDIChannelCable address) + : GenericSelector {selectable, callback}, Parent(address) { + } + + void begin() override { GenericSelector::begin(); } + + void reset() override { GenericSelector::reset(); } + + void handleUpdate(typename Matcher::Result match) override { + uint8_t program = match.value; + if (program < N) { + this->set(program); + } else { + DEBUGFN(F("Warning: Received Program Change to program 0x") + << hex << program << dec + << F(", which is not smaller than the number of settings (") + << N << ')'); + } + } +}; + +/** + * @brief Selector that listens for MIDI Program Change events on a given + * MIDI Channel, and uses the program number as its selection. + * + * @tparam N + * The number of settings. The maximum program number is @f$ N - 1 @f$. + * @ingroup Selectors + */ +template +class ProgramChangeSelector : public GenericProgramChangeSelector { + public: + ProgramChangeSelector(Selectable &selectable, MIDIChannelCable address) + : GenericProgramChangeSelector {selectable, {}, address} {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/Selectable.hpp b/Selectors/Selectable.hpp new file mode 100644 index 0000000..29e2f8c --- /dev/null +++ b/Selectors/Selectable.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include + +BEGIN_CS_NAMESPACE + +template // TODO: check bounds here? +class Selectable { + protected: + Selectable(setting_t initialSelection = 0) + : initialSelection(initialSelection) {} + + public: + virtual void select(setting_t setting) = 0; + + static setting_t validateSetting(setting_t setting) { + static_assert(std::is_unsigned::value, + "Error: setting_t should be an unsigned integer type."); + if (setting >= N) { + ERROR(F("Error: Setting ") + << setting + << F(" is not less than the number of settings (") << N + << ')', + 0xFFFE); + return N - 1; + } + return setting; + } + + setting_t getInitialSelection() const { return initialSelection; } + + void setInitialSelection(setting_t initialSelection) { + this->initialSelection = validateSetting(initialSelection); + } + + private: + setting_t initialSelection; +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/Selector.hpp b/Selectors/Selector.hpp new file mode 100644 index 0000000..c200751 --- /dev/null +++ b/Selectors/Selector.hpp @@ -0,0 +1,160 @@ +#pragma once + +#include "Selectable.hpp" +#include +#include +#include + +BEGIN_CS_NAMESPACE + +/** + * @brief An enumeration to set the behavior of selectors that are incremented + * (decremented) beyond their maximum (minimum) setting. + */ +enum class Wrap : bool { + Clamp = false, ///< When the maximum (minimum) setting is reached, + ///< clamp to the maximum (minimum) setting. + Wrap = true, ///< When the maximum (minimum) setting is reached, + ///< wrap around to the minimum (maximum) setting. + NoWrap = false, +}; + +/// A callback for the GenericSelector class that does nothing. +struct EmptySelectorCallback { + /// Initialize. + void begin() {} + /// Refresh, called periodically. + void update() {} + /// Called when the setting changes. + void update(setting_t oldSetting, setting_t newSetting) { + (void)oldSetting, (void)newSetting; + } +}; + +/// Base class for all Selectors exposing the `get` method, so it can be used +/// by display elements etc, without having to provide the full generic type. +/// +/// A `set` method is not provided, because that would require either more +/// virtual functions, or a rather large refactoring. +class SelectorBase { + protected: + /// Constructor. + SelectorBase() = default; + + public: + /// Get the current selection/setting. + setting_t get() const { return setting; } + + protected: + /// The selection of the selector. It is saved in the selector as well as + /// the selectable, because you need it in order to implement + /// increment/decrement methods. + setting_t setting = 0; +}; + +template +class GenericSelector : public SelectorBase, public AH::Updatable<> { + public: + /** + * @brief Constructor. + * + * @param selectable + * The selectable object to manage. When the value of the selector + * changes, it changes the selection of this selectable. + * @param callback + * The callback to call when the value changes. Used for (visual) + * feedback from the selector (e.g. LEDs or some different kind of + * display). + */ + GenericSelector(Selectable &selectable, const Callback &callback) + : selectable(selectable), callback(callback) {} + + void begin() override { + callback.begin(); + reset(); + } + + void update() override { callback.update(); } + + /// Reset the selection to the initial selection. + void reset() { + setting_t initialSelection = selectable.getInitialSelection(); + selectable.select(initialSelection); + callback.update(initialSelection, initialSelection); + this->setting = initialSelection; + } + + /** + * @brief Select the given selection + * + * @param newSetting + * The new setting to select [0, N-1]. + */ + void set(setting_t newSetting) { + newSetting = selectable.validateSetting(newSetting); + selectable.select(newSetting); + if (get() != newSetting) { + callback.update(get(), newSetting); + this->setting = newSetting; + } + } + + /** + * @brief Add one to the setting, wrap around or clamp, depending on the + * parameter, if the new setting would be out of range. + * + * @param wrap + * Wrap or clamp if the new setting would be out of range. + */ + void increment(Wrap wrap) { + setting_t setting = this->get(); + setting++; + if (setting == N) { + if (wrap == Wrap::Wrap) + setting = 0; + else + return; + } + this->set(setting); + } + + /** + * @brief Subtract one from the setting, wrap around or clamp, depending + * on the parameter, if the new setting would be out of range. + * + * @param wrap + * Wrap or clamp if the new setting would be out of range. + */ + void decrement(Wrap wrap) { + setting_t setting = this->get(); + if (setting == 0) { + if (wrap == Wrap::Wrap) + setting = N; + else + return; + } + setting--; + this->set(setting); + } + + private: + Selectable &selectable; + + public: + Callback callback; +}; + +/** + * @brief A Selector with an empty callback. + * + * @tparam N + * The number of possible settings. + */ +template +class Selector : public GenericSelector { + public: + /// Constructor + Selector(Selectable &selectable) : GenericSelector {selectable, {}} {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Selectors/SwitchSelector.hpp b/Selectors/SwitchSelector.hpp new file mode 100644 index 0000000..2f515ef --- /dev/null +++ b/Selectors/SwitchSelector.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "Selector.hpp" +#include + +BEGIN_CS_NAMESPACE + +template +class GenericSwitchSelector : public GenericSelector<2, Callback> { + using Parent = GenericSelector<2, Callback>; + + public: + GenericSwitchSelector(Selectable<2> &selectable, const Callback &callback, + const AH::Button &button) + : GenericSelector<2, Callback>(selectable, callback), button(button) {} + + void begin() override { + Parent::begin(); + button.begin(); + } + + void update() override { + Parent::update(); + AH::Button::State state = button.update(); + if (state == AH::Button::Falling) + this->set(1); + else if (state == AH::Button::Rising) + this->set(0); + } + + AH::Button::State getButtonState() const { return button.getState(); } + + /// @see @ref AH::Button::invert() + void invert() { button.invert(); } + + private: + AH::Button button; +}; + +/** + * @brief Selector that selects one of two settings, based on the state of a + * toggle or momentary switch. + * + * @htmlonly + * + * @endhtmlonly + * + * @ingroup Selectors + */ +class SwitchSelector : public GenericSwitchSelector<> { + public: + SwitchSelector(Selectable<2> &selectable, const AH::Button &button) + : GenericSwitchSelector<> { + selectable, + {}, + button, + } {} +}; + +END_CS_NAMESPACE \ No newline at end of file diff --git a/Settings/NamespaceSettings.hpp b/Settings/NamespaceSettings.hpp new file mode 100644 index 0000000..053d9c3 --- /dev/null +++ b/Settings/NamespaceSettings.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include + +#define USE_CS_NAMESPACE +#define CS_NAMESPACE_NAME cs + +// ========================================================================== // + +#ifdef USE_CS_NAMESPACE +#define BEGIN_CS_NAMESPACE \ + AH_DIAGNOSTIC_WERROR() \ + namespace CS_NAMESPACE_NAME { +#define END_CS_NAMESPACE \ + } \ + AH_DIAGNOSTIC_POP() +#define USING_CS_NAMESPACE using namespace CS_NAMESPACE_NAME +#else +#define BEGIN_CS_NAMESPACE +#define END_CS_NAMESPACE +#define USING_CS_NAMESPACE +#endif + +#if __cplusplus >= 201402L && \ + (!defined(__GNUC__) || __GNUC__ > 6 || defined(__clang__)) +#define CS_DEPREC(msg) [[deprecated(msg)]] +#elif (defined(__GNUC__) && __GNUC__ > 6) || defined(__clang__) +#define CS_DEPREC(msg) __attribute__((deprecated(msg))) +#else +#define CS_DEPREC(...) +#endif \ No newline at end of file diff --git a/Settings/Settings.hpp b/Settings/Settings.hpp new file mode 100644 index 0000000..9692eb2 --- /dev/null +++ b/Settings/Settings.hpp @@ -0,0 +1,27 @@ +#ifndef CS_SETTINGSWRAPPER_HPP +#error "Do not include this file directly, use the wrapper!" +#endif + +#include "NamespaceSettings.hpp" +#include +#include + +BEGIN_CS_NAMESPACE + +constexpr unsigned long VU_PEAK_DECAY_TIME = 300; +constexpr unsigned long VU_PEAK_HOLD_TIME = 400; +constexpr bool VU_PEAK_SMOOTH_DECAY = true; +constexpr uint8_t NOTE_VELOCITY_THRESHOLD = 1; + +#define IGNORE_SYSEX 0 +#define NO_SYSEX_OUTPUT 0 + +constexpr uint16_t SYSEX_BUFFER_SIZE = 128; +constexpr unsigned long SYSEX_CHUNK_TIMEOUT = 500; +constexpr unsigned long HAIRLESS_BAUD = 115200; +constexpr uint8_t MAX_FPS = 60; + +#define CS_TRUE_CONTROL_SURFACE_INSTANCE 1 +#define DISABLE_PIPES 0 + +END_CS_NAMESPACE diff --git a/Settings/SettingsWrapper.hpp b/Settings/SettingsWrapper.hpp new file mode 100644 index 0000000..43005b3 --- /dev/null +++ b/Settings/SettingsWrapper.hpp @@ -0,0 +1,15 @@ +#ifndef CS_SETTINGSWRAPPER_HPP +#define CS_SETTINGSWRAPPER_HPP + +// ---- User Settings ---- // +// ======================= // +#include "NamespaceSettings.hpp" +#include "Settings.hpp" + +#ifndef MIDI_NUM_CABLES +#define MIDI_NUM_CABLES 1 +#endif + +#include + +#endif // CS_SETTINGSWRAPPER_HPP diff --git a/Submodules/Encoder/AHEncoder.cpp b/Submodules/Encoder/AHEncoder.cpp new file mode 100644 index 0000000..b198028 --- /dev/null +++ b/Submodules/Encoder/AHEncoder.cpp @@ -0,0 +1,102 @@ +#include "AHEncoder.hpp" + +#include +#include "hardware/gpio.h" + +BEGIN_CS_NAMESPACE + +AHEncoder::AHEncoder(uint8_t pinA, uint8_t pinB) + : pins {pinA, pinB}, + direct_pins {direct_pin_read(pinA), direct_pin_read(pinB)} {} + +AHEncoder::AHEncoder(AHEncoder &&other) + : pins(other.pins), direct_pins(other.direct_pins) { + if (other.interrupts_in_use) + return; // can't move from initialized encoder +} + +AHEncoder &AHEncoder::operator=(AHEncoder &&other) { + swap(*this, other); + return *this; +} + +void swap(AHEncoder &a, AHEncoder &b) { + std::swap(a.interrupts_in_use, b.interrupts_in_use); + std::swap(a.pins, b.pins); + noInterrupts(); + std::swap(a.state, b.state); + std::swap(a.direct_pins, b.direct_pins); + std::swap(a.position, b.position); + if (a.interrupts_in_use > 0) { + AHEncoder::instance_table[a.pins[0]] = &a; + AHEncoder::instance_table[a.pins[1]] = &a; + } + if (b.interrupts_in_use > 0) { + AHEncoder::instance_table[b.pins[0]] = &b; + AHEncoder::instance_table[b.pins[1]] = &b; + } + interrupts(); +} + +AHEncoder::~AHEncoder() { end(); } + +void AHEncoder::begin() { + if (interrupts_in_use > 0) + return; + pinMode(pins[0], INPUT_PULLUP); + pinMode(pins[1], INPUT_PULLUP); + sleep_ms(2); + + uint8_t s = 0; + if (direct_pins[0].read()) + s |= 1; + if (direct_pins[1].read()) + s |= 2; + state = s; + + attachInterruptCtx(pins[0]); + attachInterruptCtx(pins[1]); +} + +void AHEncoder::end() { + if (interrupts_in_use > 0) { + detachInterruptCtx(pins[0]); + detachInterruptCtx(pins[1]); + } +} + +static bool gpio_callback_registered = false; + +void encoder_gpio_callback(uint gpio, uint32_t) { + if (gpio < CS_ENCODER_ARGLIST_SIZE) { + if (auto *enc = AHEncoder::instance_table[gpio]) + enc->update(); + } +} + +void AHEncoder::attachInterruptCtx(uint8_t pin) { + if (instance_table[pin] != nullptr) + return; + instance_table[pin] = this; + ++interrupts_in_use; + + if (!gpio_callback_registered) { + gpio_set_irq_enabled_with_callback( + pin, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, + encoder_gpio_callback); + gpio_callback_registered = true; + } else { + gpio_set_irq_enabled(pin, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, + true); + } +} + +void AHEncoder::detachInterruptCtx(uint8_t pin) { + gpio_set_irq_enabled(pin, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, false); + --interrupts_in_use; + instance_table[pin] = nullptr; +} + +AHEncoder *AHEncoder::instance_table[CS_ENCODER_ARGLIST_SIZE] {}; + +END_CS_NAMESPACE diff --git a/Submodules/Encoder/AHEncoder.hpp b/Submodules/Encoder/AHEncoder.hpp new file mode 100644 index 0000000..1907495 --- /dev/null +++ b/Submodules/Encoder/AHEncoder.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "AtomicPosition.hpp" +#include "DirectPinRead.hpp" +#include "NumInterrupts.hpp" +#include +#include + +BEGIN_CS_NAMESPACE + +#define CS_ENCODER_ISR_ATTR +#define CS_ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT + +class AHEncoder { + public: + AHEncoder(uint8_t pinA, uint8_t pinB); + AHEncoder(const AHEncoder &) = delete; + AHEncoder &operator=(const AHEncoder &) = delete; + AHEncoder(AHEncoder &&other); + AHEncoder &operator=(AHEncoder &&other); + ~AHEncoder(); + + void begin(); + void end(); + + int32_t read(); + int32_t readAndReset(int32_t newpos = 0); + void write(int32_t p); + + private: + AH::Array pins; + uint8_t interrupts_in_use = 0; + uint8_t state = 0; + AH::Array direct_pins; + AtomicPosition position {0}; + + void update(); + void attachInterruptCtx(uint8_t pin); + void detachInterruptCtx(uint8_t pin); + + static AHEncoder *instance_table[CS_ENCODER_ARGLIST_SIZE]; + friend void swap(AHEncoder &a, AHEncoder &b); + friend void encoder_gpio_callback(unsigned int, uint32_t); +}; + +END_CS_NAMESPACE + +#include "AHEncoder.ipp" diff --git a/Submodules/Encoder/AHEncoder.ipp b/Submodules/Encoder/AHEncoder.ipp new file mode 100644 index 0000000..2cc00ad --- /dev/null +++ b/Submodules/Encoder/AHEncoder.ipp @@ -0,0 +1,63 @@ +#pragma once + +#include "AHEncoder.hpp" + +BEGIN_CS_NAMESPACE + +inline int32_t AHEncoder::read() { + if (interrupts_in_use < 2) + update(); + return position.get(); +} + +inline int32_t AHEncoder::readAndReset(int32_t newpos) { + if (interrupts_in_use < 2) + update(); + return position.xchg(newpos); +} + +inline void AHEncoder::write(int32_t p) { + if (interrupts_in_use < 2) + update(); + position.set(p); +} + +// new new old old +// pin2 pin1 pin2 pin1 Result +// 0 0 0 1 +1 +// 0 0 1 0 -1 +// 0 0 1 1 +2 +// 0 1 0 0 -1 +// 0 1 1 0 -2 +// 0 1 1 1 +1 +// 1 0 0 0 +1 +// 1 0 0 1 -2 +// 1 0 1 1 -1 +// 1 1 0 0 +2 +// 1 1 0 1 -1 +// 1 1 1 0 +1 + +inline void AHEncoder::update() { + uint8_t s = state & 0b11; + if (direct_pins[0].read()) + s |= 4; + if (direct_pins[1].read()) + s |= 8; + state = (s >> 2); + switch (s) { + case 1: + case 7: + case 8: + case 14: position.add_isr(1); return; + case 2: + case 4: + case 11: + case 13: position.add_isr(-1); return; + case 3: + case 12: position.add_isr(2); return; + case 6: + case 9: position.add_isr(-2); return; + } +} + +END_CS_NAMESPACE diff --git a/Submodules/Encoder/AtomicPosition.hpp b/Submodules/Encoder/AtomicPosition.hpp new file mode 100644 index 0000000..ff511a4 --- /dev/null +++ b/Submodules/Encoder/AtomicPosition.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +BEGIN_CS_NAMESPACE + +template +struct AtomicPosition { + using type = T; + std::atomic value {}; + + AtomicPosition(T t) : value {t} {} + AtomicPosition(const AtomicPosition &o) : AtomicPosition {o.get()} {} + AtomicPosition(AtomicPosition &&o) : AtomicPosition {o.get()} {} + AtomicPosition &operator=(const AtomicPosition &o) { + this->set(o.get()); + return *this; + } + AtomicPosition &operator=(AtomicPosition &&o) { + this->set(o.get()); + return *this; + } + + constexpr static std::memory_order mo_rlx = std::memory_order_relaxed; + void add(type other) { value.fetch_add(other, mo_rlx); } + type get() const { return value.load(mo_rlx); } + void set(type other) { value.store(other, mo_rlx); } + type xchg(type other) { return value.exchange(other, mo_rlx); } + void add_isr(type other) { add(other); } +}; + +END_CS_NAMESPACE diff --git a/Submodules/Encoder/DirectPinRead.hpp b/Submodules/Encoder/DirectPinRead.hpp new file mode 100644 index 0000000..11cb16a --- /dev/null +++ b/Submodules/Encoder/DirectPinRead.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include +#include + +BEGIN_CS_NAMESPACE + +struct DirectPinRead { + const volatile uint32_t *in_reg; + uint32_t bitmask; + bool read() const { return *in_reg & bitmask; } +}; + +inline DirectPinRead direct_pin_read(ArduinoPin_t pin) { + return {&sio_hw->gpio_in, uint32_t(1) << pin}; +} + +END_CS_NAMESPACE diff --git a/Submodules/Encoder/NumInterrupts.hpp b/Submodules/Encoder/NumInterrupts.hpp new file mode 100644 index 0000000..f05d246 --- /dev/null +++ b/Submodules/Encoder/NumInterrupts.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +BEGIN_CS_NAMESPACE + +// RP2350 — every GPIO can generate interrupts +#ifndef CORE_NUM_INTERRUPT +#define CORE_NUM_INTERRUPT 48 +#endif + +END_CS_NAMESPACE diff --git a/cs_midi.h b/cs_midi.h new file mode 100644 index 0000000..d50edeb --- /dev/null +++ b/cs_midi.h @@ -0,0 +1,78 @@ +#pragma once + +// cs_midi.h — Control Surface library for pico-sdk +// Extracted from tttapa/Control-Surface (GPL-3.0) + +// Platform +#include + +// MIDI message types & parsers +#include + +// MIDI address types +#include +#include +#include +#include + +// MIDI constants +#include +#include +#include +#include + +// MIDI interfaces +#include +#include +#include + +// Control Surface singleton +#include + +// Banks & selectors +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// MIDI output elements +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// MIDI input elements +#include +#include +#include +#include + +// Encoder +#include + +BEGIN_CS_NAMESPACE + +using BluetoothMIDI_Interface = + GenericBLEMIDI_Interface; + +END_CS_NAMESPACE diff --git a/platform/pico_shim.h b/platform/pico_shim.h new file mode 100644 index 0000000..cc845c7 --- /dev/null +++ b/platform/pico_shim.h @@ -0,0 +1,236 @@ +#pragma once + +// pico_shim.h — pico-sdk replacements for Arduino primitives +// Used by cs-midi, extracted from tttapa/Control-Surface (GPL-3.0) + +#include +#include +#include +#include +#include +#include + +#include "pico/stdlib.h" +#include "pico/time.h" +#include "hardware/gpio.h" + +// --------------------------------------------------------------------------- +// Number format bases (Arduino constants) +// --------------------------------------------------------------------------- + +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +// --------------------------------------------------------------------------- +// Time +// --------------------------------------------------------------------------- + +static inline unsigned long millis() { + return (unsigned long)to_ms_since_boot(get_absolute_time()); +} + +static inline unsigned long micros() { + return (unsigned long)to_us_since_boot(get_absolute_time()); +} + +static inline void delay(unsigned long ms) { + sleep_ms(ms); +} + +// --------------------------------------------------------------------------- +// Flash strings (identity on ARM — unified address space) +// --------------------------------------------------------------------------- + +struct __FlashStringHelper; +#define F(x) (reinterpret_cast(x)) +using FlashString_t = const __FlashStringHelper *; + +#define PROGMEM +#define pgm_read_byte_near(ptr) (*((const uint8_t *)(ptr))) +#define pgm_read_ptr_near(ptr) ((void *)*(ptr)) + +// --------------------------------------------------------------------------- +// Print / Printable +// --------------------------------------------------------------------------- + +class Printable; + +class Print { + public: + virtual ~Print() = default; + virtual size_t write(uint8_t) = 0; + virtual size_t write(const uint8_t *buf, size_t len) { + size_t n = 0; + while (len--) n += write(*buf++); + return n; + } + size_t write(const char *str) { + if (!str) return 0; + return write((const uint8_t *)str, std::strlen(str)); + } + virtual void flush() {} + + // print: strings + size_t print(const __FlashStringHelper *s) { + return write(reinterpret_cast(s)); + } + size_t print(const char *s) { return write(s); } + size_t print(char c) { return write((uint8_t)c); } + + // print: integers + size_t print(long n, int base = DEC) { + if (base == DEC && n < 0) { + size_t t = write('-'); + return t + printUnsigned((unsigned long)(-n), base); + } + return printUnsigned((unsigned long)n, base); + } + size_t print(int n, int base = DEC) { return print((long)n, base); } + size_t print(unsigned long n, int base = DEC) { + return printUnsigned(n, base); + } + size_t print(unsigned int n, int base = DEC) { + return print((unsigned long)n, base); + } + size_t print(unsigned char n, int base = DEC) { + return print((unsigned long)n, base); + } + + // print: float/double + size_t print(double d, int prec = 2) { + char buf[32]; + std::snprintf(buf, sizeof(buf), "%.*f", prec, d); + return write(buf); + } + + // print: bool + size_t print(bool b) { return print(b ? "true" : "false"); } + + // print: Printable + size_t print(const Printable &p); + + // println + size_t println() { return write("\r\n"); } + template + size_t println(T v) { size_t n = print(v); return n + println(); } + template + size_t println(T v, int fmt) { size_t n = print(v, fmt); return n + println(); } + + private: + size_t printUnsigned(unsigned long n, int base) { + char buf[8 * sizeof(long) + 1]; + char *p = buf + sizeof(buf) - 1; + *p = '\0'; + if (n == 0) { *--p = '0'; } + else { + while (n > 0) { + uint8_t d = n % base; + *--p = d < 10 ? '0' + d : 'A' + d - 10; + n /= base; + } + } + return write(p); + } +}; + +class Printable { + public: + virtual ~Printable() = default; + virtual size_t printTo(Print &p) const = 0; +}; + +inline size_t Print::print(const Printable &p) { return p.printTo(*this); } + +// --------------------------------------------------------------------------- +// Macros +// --------------------------------------------------------------------------- + +#ifndef constrain +#define constrain(amt, low, high) \ + ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) +#endif + +#define HIGH 0x1 +#define LOW 0x0 +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 +#define LED_BUILTIN 25 + +typedef bool boolean; + +// --------------------------------------------------------------------------- +// GPIO — real implementations via pico-sdk +// --------------------------------------------------------------------------- + +static inline void pinMode(uint8_t pin, uint8_t mode) { + gpio_init(pin); + if (mode == OUTPUT) + gpio_set_dir(pin, GPIO_OUT); + else { + gpio_set_dir(pin, GPIO_IN); + if (mode == INPUT_PULLUP) + gpio_pull_up(pin); + } +} + +static inline void digitalWrite(uint8_t pin, uint8_t val) { + gpio_put(pin, val); +} + +static inline int digitalRead(uint8_t pin) { + return gpio_get(pin) ? HIGH : LOW; +} + +// --------------------------------------------------------------------------- +// ADC +// --------------------------------------------------------------------------- + +#include "hardware/adc.h" + +#define NUM_DIGITAL_PINS 48 +#define NUM_ANALOG_INPUTS 8 + +static inline int analogRead(uint8_t pin) { + // GPIO 26-29 = ADC 0-3 on RP2350 + uint8_t ch = pin; + if (pin >= 26) ch = pin - 26; + adc_select_input(ch); + return (int)adc_read(); +} + +static inline void analogReadResolution(int) {} + +static inline void analogWrite(uint8_t, int) {} + +// --------------------------------------------------------------------------- +// Shift register +// --------------------------------------------------------------------------- + +#define MSBFIRST 1 +#define LSBFIRST 0 + +static inline void shiftOut(uint8_t dataPin, uint8_t clockPin, + uint8_t bitOrder, uint8_t val) { + for (uint8_t i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + gpio_put(dataPin, (val >> i) & 1); + else + gpio_put(dataPin, (val >> (7 - i)) & 1); + gpio_put(clockPin, 1); + gpio_put(clockPin, 0); + } +} + +// --------------------------------------------------------------------------- +// Misc +// --------------------------------------------------------------------------- + +static inline void yield() {} + +static inline void cli() { __asm volatile("cpsid i"); } +static inline void sei() { __asm volatile("cpsie i"); } +#define noInterrupts() cli() +#define interrupts() sei()