diff --git a/.buckconfig b/.buckconfig new file mode 100644 index 000000000..e69de29bb diff --git a/.buckjavaargs b/.buckjavaargs new file mode 100644 index 000000000..9d822a717 --- /dev/null +++ b/.buckjavaargs @@ -0,0 +1,2 @@ +-Dfile.encoding=UTF-8 +-Dsun.jnu.encoding=UTF-8 diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000..447cf6938 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,11 @@ +If you are submitting a feature request, please preface the title with [feature request]. +If you are submitting a bug report, please fill in the following details. + +## Issue description + +Provide a short description. + +## Code example + +Please try to provide a minimal example to repro the bug. +Error messages and stack traces are also helpful. diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md new file mode 100644 index 000000000..841389ef7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -0,0 +1,36 @@ +--- +name: "\U0001F41B Bug Report" +about: Submit a bug report to help us improve LabGraph + +--- + +## ๐Ÿ› Bug + + + +## To Reproduce + +Steps to reproduce the behavior: + +1. +1. +1. + + + +## Expected behavior + + + +## Environment + +``` + + - LabGraph Version (e.g., 1.0): + - OS (e.g., Linux/Mac/Windows): + - Python version: + - Any other relevant information: + +## Additional context + + diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 000000000..7c406eb36 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,9 @@ +--- +name: "\U0001F4DA Documentation" +about: Report an issue related to https://github.com/facebookresearch/labgraph/tree/master/docs + +--- + +## ๐Ÿ“š Documentation + + diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 000000000..fba4bcd77 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,24 @@ +--- +name: "\U0001F680Feature Request" +about: Submit a proposal/request for a new LabGraph feature + +--- + +## ๐Ÿš€ Feature + + +## Motivation + + + +## Pitch + + + +## Alternatives + + + +## Additional context + + diff --git a/.github/ISSUE_TEMPLATE/questions-help-support.md b/.github/ISSUE_TEMPLATE/questions-help-support.md new file mode 100644 index 000000000..1de21231d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/questions-help-support.md @@ -0,0 +1,7 @@ +--- +name: "โ“Questions/Help/Support" +about: Do you need support? We have resources. + +--- + +## โ“ Questions and Help diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..54a3f7ab8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,33 @@ +## Description + +Please include a summary of the feature or issue being fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. + +Fixes #(issue) + +## Type of change + +Please delete options that are not relevant. + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +## Feature/Issue validation/testing + +Please describe the tests [UT/IT] that you ran to verify your changes and relevent result summary. Provide instructions so it can be reproduced. +Please also list any relevant details for your test configuration. + +- [ ] Test A +- [ ] Test B + +- Unit Test / Integration Test (UT/IT) execution results + +- Logs + +## Checklist: + +- [ ] Have you added tests that prove your fix is effective or that this feature works? +- [ ] New and existing unit tests pass locally with these changes? +- [ ] Has code been commented, particularly in hard-to-understand areas? +- [ ] Have you made corresponding changes to the documentation? diff --git a/BUCK b/BUCK new file mode 100644 index 000000000..44395a20a --- /dev/null +++ b/BUCK @@ -0,0 +1,264 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +load("//:DEFS", "PLATFORM") + +cthulhu_srcs = [ + "Cthulhu/src/Aligner.cpp", + "Cthulhu/src/AlignerMeta.cpp", + "Cthulhu/src/BufferTypes.cpp", + "Cthulhu/src/Clock.cpp", + "Cthulhu/src/Context.cpp", + "Cthulhu/src/Dispatcher.cpp", + "Cthulhu/src/MemoryPoolLocalImpl.cpp", + "Cthulhu/src/QueueingAligner.cpp", + "Cthulhu/src/PerformanceMonitor.cpp", + "Cthulhu/src/RawDynamic.cpp", + "Cthulhu/src/Serialization.cpp", + "Cthulhu/src/StreamConfigEquality.cpp", + "Cthulhu/src/StreamInterface.cpp", + "Cthulhu/src/StreamType.cpp", + "Cthulhu/src/SubAligner.cpp", + "Cthulhu/src/SubAlignerImpl.cpp", + "Cthulhu/src/TypeHelpers.cpp", +] + +cthulhu_public_hdrs = [ + "Cthulhu/include/cthulhu/Aligner.h", + "Cthulhu/include/cthulhu/AlignerMeta.h", + "Cthulhu/include/cthulhu/BufferTypes.h", + "Cthulhu/include/cthulhu/Clock.h", + "Cthulhu/include/cthulhu/ClockManagerInterface.h", + "Cthulhu/include/cthulhu/Context.h", + "Cthulhu/include/cthulhu/ContextImpl.h", + "Cthulhu/include/cthulhu/ContextImpl_details.h", + "Cthulhu/include/cthulhu/ContextRegistryInterface.h", + "Cthulhu/include/cthulhu/Dispatcher.h", + "Cthulhu/include/cthulhu/FieldData.h", + "Cthulhu/include/cthulhu/ForceCleanable.h", + "Cthulhu/include/cthulhu/Framework.h", + "Cthulhu/include/cthulhu/FrameworkBase.h", + "Cthulhu/include/cthulhu/LogDisabling.h", + "Cthulhu/include/cthulhu/MemoryPoolInterface.h", + "Cthulhu/include/cthulhu/PerformanceMonitor.h", + "Cthulhu/include/cthulhu/QueueingAligner.h", + "Cthulhu/include/cthulhu/RawDynamic.h", + "Cthulhu/include/cthulhu/Serialization.h", + "Cthulhu/include/cthulhu/StreamConfigEquality.h", + "Cthulhu/include/cthulhu/StreamInterface.h", + "Cthulhu/include/cthulhu/StreamRegistryInterface.h", + "Cthulhu/include/cthulhu/StreamType.h", + "Cthulhu/include/cthulhu/SubAligner.h", + "Cthulhu/include/cthulhu/TypeHelpers.h", + "Cthulhu/include/cthulhu/TypeRegistryInterface.h", + "Cthulhu/include/cthulhu/VulkanUtil.h", +] + +cxx_library( + name="CthulhuCore", + preferred_linkage="static", + srcs=cthulhu_srcs, + public_include_directories=["Cthulhu/include"], + exported_headers=cthulhu_public_hdrs, + deps=[ + "//logging:logging", + "//third-party/boost:boost", + ], + link_whole=True, + visibility=["PUBLIC"], +) + +cxx_library( + name="CthulhuVulkanUtilStub", + preferred_linkage="static", + srcs=["Cthulhu/src/VulkanUtil.cpp"], + deps=[":CthulhuCore"], +) + +cthulhu_private_local_hdrs = [ + "Cthulhu/src/ClockLocal.h", + "Cthulhu/src/ClockManagerLocal.h", + "Cthulhu/src/ContextRegistryLocal.h", + "Cthulhu/src/MemoryPoolLocal.h", + "Cthulhu/src/StreamRegistryLocal.h", + "Cthulhu/src/TypeRegistryLocal.h", +] + +cthulhu_local_srcs = [ + "Cthulhu/src/ClockLocal.cpp", + "Cthulhu/src/ClockManagerLocal.cpp", + "Cthulhu/src/ContextRegistryLocal.cpp", + "Cthulhu/src/MemoryPoolLocal.cpp", + "Cthulhu/src/StreamRegistryLocal.cpp", + "Cthulhu/src/TypeRegistryLocal.cpp", +] + +cxx_library( + name="CthulhuLocalComponents", + preferred_linkage="static", + srcs=cthulhu_local_srcs, + public_include_directories=["Cthulhu/include"], + link_whole=True, + raw_headers=cthulhu_private_local_hdrs, + deps=[":CthulhuCore", ":CthulhuVulkanUtilStub"], +) + +cthulhu_private_ipc_hdrs = [ + "Cthulhu/src/AuditorIPC.h", + "Cthulhu/src/ClockIPC.h", + "Cthulhu/src/ClockManagerIPC.h", + "Cthulhu/src/ContextRegistryIPC.h", + "Cthulhu/src/IPCEssentials.h", + "Cthulhu/src/MemoryPoolIPC.h", + "Cthulhu/src/MemoryPoolIPCHybrid.h", + "Cthulhu/src/StreamInterfaceIPC.h", + "Cthulhu/src/StreamRegistryIPC.h", + "Cthulhu/src/StreamRegistryIPCHybrid.h", + "Cthulhu/src/TypeRegistryIPC.h", + "Cthulhu/src/boost/interprocess/android_shared_memory.hpp", + "Cthulhu/src/boost/interprocess/managed_android_shared_memory.hpp", + "Cthulhu/src/boost/interprocess/detail/managed_open_or_create_impl_ashmem.hpp", +] + +cthulhu_ipc_srcs = [ + "Cthulhu/src/AuditorIPC.cpp", + "Cthulhu/src/ClockIPC.cpp", + "Cthulhu/src/ClockManagerIPC.cpp", + "Cthulhu/src/ContextRegistryIPC.cpp", + "Cthulhu/src/FrameworkIPCHybrid.cpp", + "Cthulhu/src/MemoryPoolIPC.cpp", + "Cthulhu/src/MemoryPoolIPCHybrid.cpp", + "Cthulhu/src/StreamInterfaceIPC.cpp", + "Cthulhu/src/StreamRegistryIPCHybrid.cpp", + "Cthulhu/src/TypeRegistryIPC.cpp", +] + +cxx_library( + name="CthulhuIPCHybridBase", + preferred_linkage="static", + srcs=cthulhu_ipc_srcs, + include_directories=["Cthulhu"], + link_whole=True, + exported_preprocessor_flags=["-DCTHULHU_FRAMEWORK_IPCHYBRID"], + raw_headers=cthulhu_private_ipc_hdrs, + deps=[ + ":CthulhuCore", + ":CthulhuLocalComponents", + "//third-party/boost:boost", + "//third-party/boost:boost_date_time", + "//third-party/boost:boost_thread", + ], +) + +cxx_library( + name="CthulhuIPCHybrid", + preferred_linkage="static", + link_whole=True, + srcs=[ + "Cthulhu/src/FrameworkInstance.cpp", + ], + exported_linker_flags={ + "linux": ["-lrt", "-lpthread"], + "win": ["/IGNORE:4217"], + }.get(PLATFORM, []), + deps=[":CthulhuIPCHybridBase"], + visibility=["PUBLIC"], +) + +cxx_library( + name="bindings_core", + preferred_linkage="static", + srcs=[ + "Cthulhu/modules/pythonbindings/core.cpp", + "Cthulhu/modules/pythonbindings/cuda_util.cpp", + ], + public_include_directories=["Cthulhu/modules/pythonbindings/include"], + raw_headers=[ + "Cthulhu/modules/pythonbindings/include/cthulhu/bindings/core.h", + "Cthulhu/modules/pythonbindings/include/cthulhu/bindings/cuda_util.h", + ], + deps=[ + ":CthulhuCore", + "//third-party/pybind11:pybind11", + ], +) + +cxx_library( + name="cthulhubindings", + preferred_linkage="shared", + srcs=["Cthulhu/modules/pythonbindings/module.cpp"], + compiler_flags=["-fvisibility=hidden", "-DCTHULHU_EXTERNAL=1"], + deps=[ + ":bindings_core", + ":CthulhuIPCHybrid", + "//third-party/pybind11:pybind11", + ], +) + +cxx_library( + name="labgraph_cpp", + preferred_linkage="static", + srcs=[ + "labgraph/cpp/Node.cpp", + ], + public_include_directories=["labgraph/cpp/include"], + exported_headers=[ + "labgraph/cpp/include/labgraph/bindings.h", + "labgraph/cpp/include/labgraph/Node.h", + "labgraph/cpp/include/labgraph/NodeImpl.h", + ], + deps=[ + ":CthulhuCore", + "//third-party/pybind11:pybind11", + ], + link_whole=True, + visibility=["PUBLIC"], +) + +cxx_library( + name="labgraph_cpp_bindings", + preferred_linkage="shared", + srcs=["labgraph/cpp/bindings.cpp"], + public_include_directories=["labgraph/cpp/include"], + exported_headers=[ + "labgraph/cpp/include/labgraph/bindings.h", + ], + deps=[ + "//third-party/pybind11:pybind11", + ":labgraph_cpp", + ":CthulhuIPCHybrid", + ], + link_style="static" if PLATFORM == "win" else "static_pic", + visibility=["PUBLIC"], + compiler_flags=["-fvisibility=hidden"], + soname="labgraph_cpp.$(ext)", +) + +cxx_library( + name="MyCPPNodes", + srcs=[ + "labgraph/cpp/tests/MyCPPSink.cpp", + "labgraph/cpp/tests/MyCPPSource.cpp", + "labgraph/cpp/tests/bindings.cpp", + ], + headers=[ + "labgraph/cpp/tests/MyCPPSink.h", + "labgraph/cpp/tests/MyCPPSource.h", + "labgraph/cpp/tests/TestSample.h", + ], + deps=[ + ":labgraph_cpp", + ":CthulhuCore", + ":CthulhuIPCHybrid", + "//third-party/pybind11:pybind11", + ], + soname="MyCPPNodes.$(ext)", + compiler_flags=["-fvisibility=hidden"], + link_style="static" if PLATFORM == "win" else "static_pic", +) + +cxx_binary( + name="CthulhuIPCClean", + srcs=["Cthulhu/ipc_cleanup.cpp"], + deps=[":CthulhuIPCHybrid"], +) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..e69de29bb diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..83f431e8f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,80 @@ +# Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic +address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a +professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies within all project spaces, and it also applies when +an individual is representing the project or its community in public spaces. +Examples of representing a project or community include using an official +project e-mail address, posting via an official social media account, or acting +as an appointed representative at an online or offline event. Representation of +a project may be further defined and clarified by project maintainers. + +This Code of Conduct also applies outside the project spaces when there is a +reasonable belief that an individual's behavior may have a negative impact on +the project or its community. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..5c6a23200 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Contributing to LabGraph +We want to make contributing to this project as easy and transparent as +possible. + +## Pull Requests +We actively welcome your pull requests. + +1. Fork the repo and create your branch from `main`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. +5. Make sure your code lints. +6. If you haven't already, complete the Contributor License Agreement ("CLA"). + +## Contributor License Agreement ("CLA") +In order to accept your pull request, we need you to submit a CLA. You only need +to do this once to work on any of Facebook's open source projects. + +Complete your CLA here: + +## Issues +We use GitHub issues to track public bugs. Please ensure your description is +clear and has sufficient instructions to be able to reproduce the issue. + +Facebook has a [bounty program](https://www.facebook.com/whitehat/) for the safe +disclosure of security bugs. In those cases, please go through the process +outlined on that page and do not file a public issue. + +## License +By contributing to MIT License, you agree that your contributions will be licensed +under the LICENSE file in the root directory of this source tree. diff --git a/Cthulhu/include/cthulhu/Aligner.h b/Cthulhu/include/cthulhu/Aligner.h new file mode 100644 index 000000000..1419db299 --- /dev/null +++ b/Cthulhu/include/cthulhu/Aligner.h @@ -0,0 +1,123 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +#include +#include + +namespace cthulhu { + +using AlignerSampleCallback = std::function&)>; +using AlignerConfigCallback = std::function&)>; +using AlignerSamplesMetaCallback = std::function; +using AlignerConfigsMetaCallback = std::function; + +// Thread policies are: +// - THREAD_NEUTRAL: Aligner/Dispatcher do not spawn any new threads. For example, the thread that +// calls sampleCallback will also call alignedCallback +// - SINGLE_THREADED: Aligner/Dispatcher spawns a new thread. For example, the thread that calls +// sampleCallback will not call alignedCallback, this will be a new thread +enum class ThreadPolicy : uint8_t { THREAD_NEUTRAL = 0, SINGLE_THREADED = 1 }; + +class AlignerBase { + public: + AlignerBase(ThreadPolicy threadPolicy = ThreadPolicy::THREAD_NEUTRAL); + virtual ~AlignerBase(); + + // These registration function is not thread safe, and should be + // followed by a call to finalize() + virtual void registerConsumer(StreamInterface* si, int index) = 0; + + void setCallback(const AlignerSampleCallback& callback); + void setConfigCallback(const AlignerConfigCallback& callback); + void setSamplesMetaCallback(const AlignerSamplesMetaCallback& callback); + void setConfigsMetaCallback(const AlignerConfigsMetaCallback& callback); + + // This should be called once all consumers are registered + // align() should only be called once we are finalized, and + // we cannot be un-finalized (the transition is uni-directional) + void finalize(); + + // Clear the aligner's internal sample state, if any. + // + // This is an optional method, and aligner users may not call clear(). + virtual void clear() { /* Default implementation does nothing */ + } + + protected: + virtual void align() = 0; + virtual void sampleCallback(size_t idx, const StreamSample& sample) = 0; + virtual bool configCallback(size_t idx, const StreamConfig& config) = 0; + + void initThread(); + void killThread(); + + void alignedCallback(const std::vector& samples); + bool alignedConfigCallback(const std::vector& configs); + void alignedSamplesMetaCallback(const AlignerSamplesMeta& meta); + void alignedConfigsMetaCallback(const AlignerConfigsMeta& meta); + + bool hasSampleCallback() const; + + AlignerSampleCallback callback_ = nullptr; + AlignerConfigCallback ccallback_ = nullptr; + AlignerSamplesMetaCallback smcallback_ = nullptr; + AlignerConfigsMetaCallback cmcallback_ = nullptr; + + ThreadPolicy policy_; + std::thread thread_; + std::promise stopSignal_; + bool thread_is_alive_ = false; + + bool inhibitSampleCallback_ = false; + + std::atomic finalized_; +}; // class AlignerBase + +enum class AlignerMode : uint32_t { TIMESTAMP = 0, SEQUENCE = 1 }; + +class Aligner : public AlignerBase { + public: + Aligner( + size_t queueSize = 1, + ThreadPolicy threadPolicy = ThreadPolicy::THREAD_NEUTRAL, + AlignerMode mode = AlignerMode::TIMESTAMP, + double thresholdSeconds = 0.005); + + virtual ~Aligner(); + + protected: + virtual void align() override; + virtual void sampleCallback(size_t idx, const StreamSample& sample) override; + virtual bool configCallback(size_t idx, const StreamConfig& config) override; + + public: + virtual void registerConsumer(StreamInterface* si, int index) override; + + protected: + void checkConfig(const std::vector& samples); + void execute(const std::vector& samples); + + struct StreamQueue { + std::queue samples; + std::deque> configs; + uint32_t latestSequence = 0; + std::unique_ptr consumer; + StreamID id; + }; + + std::vector queues_; + size_t queueSize_; + // This enables multi-threaded access to the queues_ via sampleCallback. The public functions + // are not thread-safe. + std::mutex queueMutex_; + double threshold_; + std::function comparison_; + bool configured_ = false; +}; // class Aligner + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/AlignerMeta.h b/Cthulhu/include/cthulhu/AlignerMeta.h new file mode 100644 index 000000000..e9d75de06 --- /dev/null +++ b/Cthulhu/include/cthulhu/AlignerMeta.h @@ -0,0 +1,41 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include + +namespace cthulhu { + +struct AlignerStreamMeta { + cthulhu::StreamID streamID; + uint32_t subSampleSize; +}; + +using AlignerConfigsMeta = std::vector; + +struct AlignerReferenceMeta { + double timestamp; + uint32_t sequenceNumber; + uint32_t subSampleOffset; // In sub-samples + uint32_t numSubSamples; // In sub-samples +}; + +struct AlignerSampleMeta { + double timestamp; + double duration; + std::vector references; +}; + +using AlignerSamplesMeta = std::vector; + +void serialize(const AlignerConfigsMeta& input, std::ostringstream& output); + +void serialize(const AlignerSamplesMeta& input, std::ostringstream& output); + +void deserialize(std::istringstream& input, AlignerConfigsMeta& output); + +void deserialize(std::istringstream& input, AlignerSamplesMeta& output); + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/BufferTypes.h b/Cthulhu/include/cthulhu/BufferTypes.h new file mode 100644 index 000000000..0eec0fdf8 --- /dev/null +++ b/Cthulhu/include/cthulhu/BufferTypes.h @@ -0,0 +1,77 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +namespace cthulhu { + +enum class BufferType : uint8_t { + NULL_BUFFER, + CPU, + GPU, +}; + +using CpuBuffer = std::shared_ptr; + +struct GpuBufferData { + uint64_t handle = 0; + uint32_t size = 0; + uint32_t memoryTypeIndex = 0; +}; + +/** + * A GPU Buffer is a ref-counted pointer to an opaque + * platform-specific Vulkan exported memory handle type. + * It contains a convenience function for mapping to an equivalent + * host memory buffer with shared reference count. + */ +class GpuBuffer : public std::shared_ptr { + public: + GpuBuffer() = default; + GpuBuffer( + GpuBufferData* ptr, + const std::function& deleter, + const CpuBuffer& CpuBuffer) + : std::shared_ptr(ptr, deleter), CpuBuffer_(CpuBuffer) {} + + // GPU Buffers may be host-visible, and can be mapped or copied to + // the CPU address space as needed. + CpuBuffer mapped() const; + + private: + // The function used to map to a CpuBuffer + CpuBuffer CpuBuffer_; +}; + +/** + * Common storage for either CPU or GPU based buffers. + */ +struct AnyBuffer { + AnyBuffer() = default; + + AnyBuffer(const BufferType& _type); + + AnyBuffer(const CpuBuffer& buffer); + + AnyBuffer(const GpuBuffer& buffer); + + AnyBuffer& operator=(const CpuBuffer& buffer); + + AnyBuffer& operator=(const GpuBuffer& buffer); + + // Will automatically cast to a CpuBuffer, by mapping a GpuBuffer + // if needed. + operator CpuBuffer() const; + + // Returns true if data is not a nullptr. + operator bool() const; + + std::variant data; + BufferType type = BufferType::NULL_BUFFER; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/Clock.h b/Cthulhu/include/cthulhu/Clock.h new file mode 100644 index 000000000..6d4198c75 --- /dev/null +++ b/Cthulhu/include/cthulhu/Clock.h @@ -0,0 +1,67 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace cthulhu { + +enum class ClockEvent : uint32_t { + START = 0, + PAUSE = 1, + RTF_UPDATE = 2, + JUMP = 3, +}; + +using ClockEventCallback = std::function; + +// This encapsulates a real/simulated clock. +class ClockInterface { + public: + ClockInterface(){}; + virtual ~ClockInterface() = default; + + virtual double getTime() = 0; + + virtual bool isSimulated() const = 0; + + void listenEvents(const ClockEventCallback& cb) { + listeners_.push_back(cb); + }; + + protected: + // this function updates latestTime of the clock + virtual void updateTime() = 0; + + // This function is used to guarantee that latestTime_ that is returned is always monotonically + // increasing, even when pause() and getTime() are called in different threads simultaneously + virtual void updateLatestTime(double desired, double reference, bool enableBackwards = false) = 0; + + double getWallTime() const; + + std::vector listeners_; +}; + +// Controllable interface for a simulated clock +class ControllableClockInterface { + public: + ControllableClockInterface() {} + virtual ~ControllableClockInterface() = default; + + // Starts running the clock from a specified time + // If no time is specified, it starts from the latest time at + // which the clock was paused + virtual bool start(double time = -1.) = 0; + + // Pauses the clock + virtual void pause() = 0; + + // Can only be called while in the paused state + virtual bool setRealtimeFactor(double rtf) = 0; + + // Can only be called while in the paused state + virtual bool setTime(double time) = 0; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/ClockManagerInterface.h b/Cthulhu/include/cthulhu/ClockManagerInterface.h new file mode 100644 index 000000000..1e4b5f479 --- /dev/null +++ b/Cthulhu/include/cthulhu/ClockManagerInterface.h @@ -0,0 +1,42 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#include +#include +#include + +namespace cthulhu { + +class ClockAuthority; + +enum class ClockManagerState : uint8_t { + UNKNOWN = 0, + REAL = 1, + SIM = 2, +}; + +class ClockManagerInterface : public ForceCleanable, public LogDisabling { + public: + virtual const std::shared_ptr controlClock( + const std::string& contextName) = 0; + virtual const std::shared_ptr clock() = 0; + + virtual ~ClockManagerInterface() = default; + + protected: + // A simulated clock must have an owning context. This is the interface for + // creating a simulated clock, and specifying that owner + virtual void setClockAuthority( + bool simTime = false, + const std::string& authorizedContext = "") = 0; + + ClockManagerState state_; + + friend class ClockAuthority; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/Context.h b/Cthulhu/include/cthulhu/Context.h new file mode 100644 index 000000000..411fab243 --- /dev/null +++ b/Cthulhu/include/cthulhu/Context.h @@ -0,0 +1,566 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include + +namespace cthulhu { + +// Convenience function for wrapping a universal reference into a unique pointer +// Useful for taking move-only node classes and getting them into unique_ptrs +template +std::unique_ptr ptrWrap(T&& obj) { + return std::make_unique(std::forward(obj)); +} + +template +TypeInfoInterfacePtr sampleType() { + auto type = Framework::instance().typeRegistry()->findSampleType(typeid(T)); + if (!type) { + auto str = "Failed to lookup type in registry: " + std::string(typeid(T).name()); + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + return type; +} + +// Forward Declaration +class Context; + +class NodeBase { + public: + NodeBase() = default; + explicit NodeBase(bool initialized) : initialized_(initialized) {} + virtual ~NodeBase() = default; + // Users can check this bool on child classes (Subscriber, Transformer, etc) to ensure they didn't + // have some error during initialization (such as a stream existing already). + bool isInitialized() { + return initialized_; + } + + private: + bool initialized_ = false; +}; +using NodePtr = std::unique_ptr; + +// This is a handle for a basic subscriber (single input, no output) node. It can only +// be constructed by a Context +class Subscriber : public NodeBase { + public: + Subscriber& operator=(Subscriber&& other) = delete; + Subscriber(Subscriber&& other) = default; + + Subscriber& operator=(const Subscriber& other) = delete; + Subscriber(const Subscriber& other) = delete; + + virtual ~Subscriber() = default; + + private: + explicit Subscriber(const StreamIDView& id, std::unique_ptr consumer) + : NodeBase(true), consumer_(std::move(consumer)), id_(id){}; + Subscriber(const StreamIDView& id) : id_(id){}; + std::unique_ptr consumer_; + StreamIDView id_; + friend class Context; +}; +using SubscriberPtr = std::unique_ptr; + +// This is a handle for a basic transformer (single input, single output) node. It can only +// be constructed by a Context +class Transformer : public NodeBase { + public: + Transformer& operator=(Transformer&& other) = delete; + Transformer(Transformer&& other) = default; + + Transformer& operator=(const Transformer& other) = delete; + Transformer(const Transformer& other) = delete; + + virtual ~Transformer() { + // Must delete the consumer before the producer to prevent the consumer thread from + // accessing the producer after it's deleted + consumer_.reset(); + producer_.reset(); + }; + + private: + explicit Transformer( + const StreamIDView& in, + const StreamIDView& out, + std::unique_ptr consumer, + std::unique_ptr producer) + : NodeBase(true), + consumer_(std::move(consumer)), + producer_(std::move(producer)), + in_(in), + out_(out){}; + Transformer(const StreamIDView& in, const StreamIDView& out) : in_(in), out_(out){}; + std::unique_ptr consumer_; + std::unique_ptr producer_; + StreamIDView in_; + StreamIDView out_; + friend class Context; +}; +using TransformerPtr = std::unique_ptr; + +// This is a handle for a basic publisher (no input, single output) node. It can only +// be constructed by a Context +class Publisher : public NodeBase { + public: + // Publish a sample on the stream + template + bool publish(const T& sample); + + // Configure the stream + template + bool configure(const T& configuration); + + inline bool isActive() const { + return producer_ && producer_->isActive(); + }; + + inline bool isConfigured() const { + return producer_ && producer_->config(); + }; + + // Allocate a sample for the stream from the sample pool + template + T allocateSample(uint32_t numSubSamples = 1) const; + + Publisher& operator=(Publisher&& other) = delete; + Publisher(Publisher&& other) = default; + virtual ~Publisher() = default; + + private: + explicit Publisher(const StreamIDView& id, std::unique_ptr producer) + : NodeBase(true), producer_(std::move(producer)), id_(id){}; + Publisher(const StreamIDView& id) : id_(id){}; + std::unique_ptr producer_; + StreamIDView id_; + friend class Context; +}; +using PublisherPtr = std::unique_ptr; + +// This is a handle for a complex subscriber (multi input, no output) node. It can only +// be constructed by a Context +class MultiSubscriber : public NodeBase { + public: + MultiSubscriber& operator=(MultiSubscriber&& other) = delete; + MultiSubscriber(MultiSubscriber&& other) = default; + + MultiSubscriber& operator=(const MultiSubscriber& other) = delete; + MultiSubscriber(const MultiSubscriber& other) = delete; + + virtual ~MultiSubscriber() = default; + + private: + explicit MultiSubscriber( + const std::vector& ids, + std::unique_ptr aligner) + : NodeBase(true), aligner_(std::move(aligner)), ids_(ids){}; + MultiSubscriber(const std::vector& ids) : ids_(ids){}; + std::unique_ptr aligner_; + const std::vector ids_; + friend class Context; +}; +using MultiSubscriberPtr = std::unique_ptr; + +// This is a handle for a complex transformer (multi input, multi output) node. It can only +// be constructed by a Context +class MultiTransformer : public NodeBase { + public: + MultiTransformer& operator=(MultiTransformer&& other) = delete; + MultiTransformer(MultiTransformer&& other) = default; + + MultiTransformer& operator=(const MultiTransformer& other) = delete; + MultiTransformer(const MultiTransformer& other) = delete; + + virtual ~MultiTransformer() { + // Must delete the aligner before the dispatcher to prevent the aligner thread from + // accessing the producers on the dispatcher after they're deleted + aligner_.reset(); + dispatcher_.reset(); + }; + + private: + explicit MultiTransformer( + const std::vector& in, + const std::vector& out, + std::unique_ptr aligner, + std::unique_ptr dispatcher) + : NodeBase(true), + aligner_(std::move(aligner)), + dispatcher_(std::move(dispatcher)), + in_(in), + out_(out){}; + MultiTransformer(const std::vector& in, const std::vector& out) + : in_(in), out_(out){}; + std::unique_ptr aligner_; + std::unique_ptr dispatcher_; + const std::vector in_; + const std::vector out_; + friend class Context; +}; +using MultiTransformerPtr = std::unique_ptr; + +// This is a handle for a complex publisher (no input, multi output) node. It can only +// be constructed by a Context +class MultiPublisher : public NodeBase { + public: + // Publish samples on all streams + template + bool publish(const T&... samples); + + // Configure one of the streams, by index corresponding to the constructed order + template + bool configure(const T& configuration, uint32_t streamNum); + + // Allocate a sample for one of the streams from the sample pool + template + T allocateSample(uint32_t streamNum, uint32_t numSubSamples = 1) const; + + MultiPublisher(MultiPublisher&&) = default; + MultiPublisher& operator=(MultiPublisher&&) = delete; + + MultiPublisher(const MultiPublisher&) = delete; + MultiPublisher& operator=(const MultiPublisher&) = delete; + + virtual ~MultiPublisher() = default; + + private: + explicit MultiPublisher( + const std::vector& ids, + std::unique_ptr dispatcher) + : NodeBase(true), dispatcher_(std::move(dispatcher)), ids_(ids){}; + MultiPublisher(const std::vector& ids) : ids_(ids){}; + std::unique_ptr dispatcher_; + const std::vector ids_; + friend class Context; +}; +using MultiPublisherPtr = std::unique_ptr; + +enum class ConsumerType : uint8_t { SYNC = 0, ASYNC = 1 }; + +enum class ProducerType : uint8_t { SYNC = 0, ASYNC = 1 }; + +enum class AlignerType : uint8_t { SYNC = 0, ASYNC = 1, CUSTOM = 2 }; + +enum class DispatcherType : uint8_t { SYNC = 0, ASYNC = 1, CUSTOM = 2 }; + +struct SubscriberOptions { + ConsumerType consumerType = ConsumerType::SYNC; +}; + +struct PublisherOptions { + ProducerType producerType = ProducerType::SYNC; +}; + +struct TransformerOptions { + ConsumerType consumerType = ConsumerType::SYNC; + ProducerType producerType = ProducerType::SYNC; +}; + +struct MultiSubscriberOptions { + AlignerType alignerType = AlignerType::SYNC; + std::unique_ptr alignerPtr; +}; + +struct MultiTransformerOptions { + AlignerType alignerType = AlignerType::SYNC; + DispatcherType dispatcherType = DispatcherType::SYNC; + std::unique_ptr alignerPtr; + std::unique_ptr dispatcherPtr; +}; + +// Class provided as a wrapper around StreamConfig to provide the setConfig() and getConfig() +// methods so templates don't break +class DefaultStreamConfig { + public: + DefaultStreamConfig() {} + DefaultStreamConfig(const StreamConfig& config) : config_(config) {} + + const StreamConfig& getConfig() const { + return config_; + } + + void setConfig(const StreamConfig& config) { + config_ = config; + }; + + private: + StreamConfig config_; +}; + +// This is the API for interfacing with the Cthulhu Framework. It requires a context name, so that +// all interactions with the singleton Framework can be associated with a named context (e.g. a set +// of Nodes owned by the same functionality e.g. HW) It provides template construction functions for +// producing Nodes of different flavors by interfacing with the Stream Registry in the Framework. +class Context { + public: + explicit Context(const std::string& name, bool private_ns = false) + : ctx_(Framework::instance().contextRegistry()->registerContext(name, private_ns)), + name_(name), + private_ns_(private_ns) {} + + Context(const Context& other) + : ctx_(Framework::instance().contextRegistry()->registerContext( + other.name_, + other.private_ns_)), + name_(other.name_), + private_ns_(other.private_ns_) {} + + Context(Context&& other) + : ctx_(other.ctx_), name_(std::move(other.name_)), private_ns_(other.private_ns_) { + other.ctx_ = nullptr; + } + + Context& operator=(const Context& other) { + if (&other != this) { + name_ = other.name_; + private_ns_ = other.private_ns_; + // Free the current context and then make a new one. + Framework::instance().contextRegistry()->removeContext(ctx_); + ctx_ = Framework::instance().contextRegistry()->registerContext(name_, private_ns_); + } + + return *this; + } + + Context& operator=(Context&& other) { + name_ = std::move(other.name_); + private_ns_ = other.private_ns_; + ctx_ = other.ctx_; + other.ctx_ = nullptr; + + return *this; + } + + virtual ~Context() { + if (ctx_ != nullptr) { // Might have become nulled if context is moved + Framework::instance().contextRegistry()->removeContext(ctx_); + } + } + + inline StreamID applyNamespace(const StreamID& streamID) const { + StreamID result = streamID; + if (private_ns_) { + result = name_ + "/" + streamID; + } + return result; + } + + const std::string& name() const { + return name_; + } + + bool isPrivate() const { + return private_ns_; + } + + // Returns true if this stream ID is part of this context. + // If this is not a private context, it always returns false. + bool isInContext(const StreamID& streamID) const { + return isPrivate() && streamID.size() > name_.size() && + streamID.substr(0, name_.size()) == name_; + } + + // Template for constructing a subscriber + template + Subscriber subscribe( + const StreamID& streamID, + const std::function& sampleCallback, + const std::function& configCallback = nullptr, + SubscriberOptions options = SubscriberOptions()) const; + + // Subscribe to a stream generically (untemplated) + // A "specialization" of subscribe() is provided for T = StreamSample, U = StreamConfig. This case + // handles users wishing to subscribe to generic data coming on the stream. The stream must + // already exist, or an exception is thrown. Actually providing this as a template specialization + // doesn't seem to be working correctly. + // + // Unsuccessful repro: https://our.internmc.facebook.com/intern/paste/P122967679/ + Subscriber subscribeGeneric( + const StreamID& streamID, + const std::function& sampleCallback, + const std::function& configCallback = nullptr, + SubscriberOptions options = SubscriberOptions()) const; + + // Subscribe to a stream generically (untemplated) with given type name. + // As with the templated subscribe(...) calls, this will work even if the + // stream doesn't already exist. + Subscriber subscribeGeneric( + const StreamID& streamID, + const std::string& typeName, + const std::function& sampleCallback, + const std::function& configCallback = nullptr, + SubscriberOptions options = SubscriberOptions()) const; + + // Template for constructing a transformer + template + Transformer transform( + const StreamID& inputID, + const StreamID& outputID, + const std::function& sampleCallback, + const std::function& configGenerator, + TransformerOptions options = TransformerOptions()) const; + template + Transformer transform( + const StreamID& inputID, + const StreamID& outputID, + const std::function& sampleCallback, + const std::function& configCallback, + TransformerOptions options = TransformerOptions()) const; + template < + typename T, + typename U, + typename W = DefaultStreamConfig, + typename X = DefaultStreamConfig> + Transformer transform( + const StreamID& inputID, + const StreamID& outputID, + const std::function& sampleCallback, + const std::function& configCallback = nullptr, + TransformerOptions options = TransformerOptions()) const; + + // Template for constructing a publisher + template + Publisher advertise(const StreamID& streamID, PublisherOptions options = PublisherOptions()) + const; + // Alternatively, construct a publisher by just specifying the typeID for the stream. + Publisher advertise( + const StreamID& streamID, + const uint32_t typeID, + PublisherOptions options = PublisherOptions()) const; + // Alternatively, construct a publisher by just specifying the type name for the stream. + Publisher advertise( + const StreamID& streamID, + const std::string& typeName, + PublisherOptions options = PublisherOptions()) const; + + // Template for constructing a multi-subscriber statically + template + MultiSubscriber subscribe( + const std::array& streamIDs, + const std::function& callback, + const std::function& configCallback = nullptr, + MultiSubscriberOptions options = MultiSubscriberOptions()) const; + + // Template for constructing a multi-subscriber dynamically + template + MultiSubscriber subscribe( + const std::vector>& streamIDs, + const std::function& callback, + const std::function& configCallback = nullptr, + MultiSubscriberOptions options = MultiSubscriberOptions()) const; + template + MultiSubscriber subscribe( + const std::vector& streamIDs, + const std::function& callback, + const std::function& configCallback = nullptr, + MultiSubscriberOptions options = MultiSubscriberOptions()) const; + + // Template for constructing a generic multisubscriber dynamically. Static usage not supported. + // Grouped callbacks are also not supported. The aligner meta callbacks are taken explicitly since + // the user is probably more likely to care about them if subscribing generically. + MultiSubscriber subscribeGeneric( + const std::vector& streamIDs, + const std::function&)>& sampleCallback, + const std::function&)>& configCallback = nullptr, + const AlignerSamplesMetaCallback& samplesMetaCallback = nullptr, + const AlignerConfigsMetaCallback& configsMetaCallback = nullptr, + MultiSubscriberOptions options = MultiSubscriberOptions()) const; + + // Template for constructing a multi-transformer dynamically + template + MultiTransformer transform( + const std::vector>& inputIDs, + const std::vector>& outputIDs, + const std::function& sampleCallback, + const std::function& configCallback = nullptr, + MultiTransformerOptions options = MultiTransformerOptions()) const; + + // Template for constructing a multi-publisher statically + template + MultiPublisher advertise(const std::array& streamIDs) const; + + // Template for constructing a multi-publisher dynamically + template + MultiPublisher advertise(const std::vector>& streamIDs) const; + template + MultiPublisher advertise(const std::vector& streamIDs) const; + + // Clock-Control API. Non-controllable clocks can be accessed with cthulhu::clock() + inline const std::shared_ptr getClockControl() const { + return Framework::instance().clockManager()->controlClock(name_); + }; + + private: + ContextInfoInterface* ctx_; + std::string name_; + bool private_ns_; +}; + +inline static const std::shared_ptr clock() { + return Framework::instance().clockManager()->clock(); +}; + +// This free function is provided as a replacement for isInContext, to avoid users creating a +// separate context (and locking a mutex or two) just to check some membership. It is identical to +// the following: +// +// const auto ctx = Context(name, private_ns); +// const auto in_context = ctx.isInContext(stream_id); +inline static bool +isStreamInContext(std::string_view stream_id, std::string_view name, bool private_ns) { + return private_ns && stream_id.size() > name.size() && stream_id.substr(0, name.size()) == name; +} + +// A configuration for streams that work with sample field on content block (SFoCB) samples +// +// SFoCB samples allocate their sample fields in a content block. In order to broadcast the +// size of that content block (sometimes called the 'payload' in implementation details), we need a +// configuration to carry the size. SFoCB config is a configuration for a SFoCB sample type. +// Use this to configure your SFoCB-sample-carrying stream. +// +// It is a user error if this is paired with a sample that's NOT using SFoCB. +class SFoCBConfig { + public: + // Type tag for invoking the templated SFoCB constructor + template + struct SampleType {}; + + // Construct a SFoCBConfig that identifies samples for the type Sample. + template + SFoCBConfig(SampleType) + : SFoCBConfig(Framework::instance().typeRegistry()->findSampleType(typeid(Sample))) {} + + // Construct a SFoCBConfig that identifies samples for the samples associated with the type ID + SFoCBConfig(const uint32_t typeID); + // Construct a SFoCBConfig that identifies samples for the samples associated with the type name + SFoCBConfig(const std::string& typeName); + + // + // Rest are implementation details that need to be public to play well + // with rest of Cthulhu. + // + SFoCBConfig(const StreamConfig& config) : config_(config) {} + + inline const StreamConfig& getConfig() const { + return config_; + } + + inline void setConfig(const StreamConfig& config) { + config_ = config; + }; + + private: + SFoCBConfig(const TypeInfoInterfacePtr); + StreamConfig config_; +}; + +} // namespace cthulhu + +#include "ContextImpl.h" diff --git a/Cthulhu/include/cthulhu/ContextImpl.h b/Cthulhu/include/cthulhu/ContextImpl.h new file mode 100644 index 000000000..d7b936b0b --- /dev/null +++ b/Cthulhu/include/cthulhu/ContextImpl.h @@ -0,0 +1,678 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include + +#include "ContextImpl_details.h" + +namespace cthulhu { + +template +bool Publisher::publish(const T& sample) { + if (!producer_ || !producer_->isActive() || + !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + XR_LOGCW( + "Cthulhu", + "Publish failed. Producer is {}null, Producer is {}active. Sample type is {}defined.", + producer_ ? "NOT " : "", + (producer_ && producer_->isActive()) ? "" : "NOT ", + !Framework::instance().typeRegistry()->findSampleType(typeid(T)) ? "NOT " : ""); + return false; + } + producer_->produceSample(sample.getSample()); + return true; +}; + +// Specialization provided for generic StreamSample. We trust the user knows what they're doing here +// since it's impossible to check for type match. +template <> +bool Publisher::publish(const StreamSample& sample); + +template +bool Publisher::configure(const T& configuration) { + if (!producer_) { + return false; + } + producer_->configureStream(configuration.getConfig()); + return true; +}; + +// Specialization provided for generic StreamConfig. We trust the user knows what they're doing here +// since it's impossible to check for type match. +template <> +bool Publisher::configure(const StreamConfig& configuration); + +template +T Publisher::allocateSample(uint32_t numSubSamples) const { + if (!producer_ || !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + auto str = "Attempted to allocate sample on an invalid publisher."; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + return details::allocateSampleHelper(producer_->config(), id_, numSubSamples); +}; + +template +bool MultiPublisher::publish(const T&... args) { + std::vector samplesUnflat(ids_.size()); + bool success = details::SampleUncaster::uncast(samplesUnflat, 0, args...); + dispatcher_->dispatchSamples(samplesUnflat); + return success; +}; + +template +bool MultiPublisher::configure(const T& configuration, uint32_t streamNum) { + if (!dispatcher_) { + return false; + } + const StreamConfig& config = configuration.getConfig(); + dispatcher_->configureStream(config, streamNum); + return true; +}; + +template +T MultiPublisher::allocateSample(uint32_t streamNum, uint32_t numSubSamples) const { + if (!dispatcher_) { + auto str = "Attempted to allocate sample on an invalid multi-publisher."; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (streamNum >= ids_.size()) { + auto str = "Attempted to allocate sample on an invalid publisher."; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + return details::allocateSampleHelper( + dispatcher_->streamConfig(streamNum), ids_[streamNum], numSubSamples); +}; + +template +Subscriber Context::subscribe( + const StreamID& streamIDRaw, + const std::function& sampleCallback, + const std::function& configCallback, + SubscriberOptions options) const { + StreamID streamID = applyNamespace(streamIDRaw); + static_assert( + std::is_constructible::value, + "Context::subscribe requires that sample type T is constructed with const StreamSample&"); + static_assert( + std::is_constructible::value, + "Context::subscribe requires that configuration type U is constructed with const StreamConfig&"); + // Make sure the stream is valid + if (!std::is_same::value && + !Framework::instance().typeRegistry()->isValidStreamType(typeid(T), typeid(U))) { + auto str = "Stream/Config Mismatch"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Get Types + auto type = sampleType(); + + // Make sure we're not trying to use a configCallback on a basic stream + if (type->isBasic() && configCallback != nullptr) { + auto str = "Attempted to provide config callback on basic stream type"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Create Callbacks + SampleCallback scallback = [sampleCallback](const StreamSample& sample) -> void { + const T data(sample); + sampleCallback(data); + }; + ConfigCallback ccallback = [configCallback](const StreamConfig& config) -> bool { + const U streamConfig(config); + return configCallback(streamConfig); + }; + if (configCallback == nullptr) { + ccallback = nullptr; + } + + // Get Streams from Registry + StreamDescription desc{streamID, type->typeID()}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (type->typeID() != si->description().type()) { + // Type mismatch detected + XR_LOGCW( + "Cthulhu", "Type mismatch detected [{}, {}]", type->typeID(), si->description().type()); + return Subscriber(si->description().id()); + } + + // Create Consumer + std::unique_ptr consumer( + new StreamConsumer(si, scallback, ccallback, options.consumerType == ConsumerType::ASYNC)); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register single subscriber against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + const auto& sid = si->description().id(); + ctx_->registerSubscriber(std::vector{sid}); + return Subscriber(sid, std::move(consumer)); +}; + +template +Transformer Context::transform( + const StreamID& inputID, + const StreamID& outputID, + const std::function& sampleCallback, + const std::function& configAcceptor, + TransformerOptions options) const { + auto type = sampleType(); + + if (!type->isBasic()) { + auto str = "Attempted to ignore config on non-basic stream type"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + std::function configCallback = + [configAcceptor](const W& input, DefaultStreamConfig&) -> bool { + return configAcceptor(input); + }; + return transform(inputID, outputID, sampleCallback, configCallback, std::move(options)); +}; + +template +Transformer Context::transform( + const StreamID& inputID, + const StreamID& outputID, + const std::function& sampleCallback, + const std::function& configGenerator, + TransformerOptions options) const { + auto type = sampleType(); + + if (!type->isBasic()) { + auto str = "Attempted to ignore config on non-basic stream type"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + std::function configCallback = + [configGenerator](const DefaultStreamConfig&, X& output) -> bool { + return configGenerator(output); + }; + return transform(inputID, outputID, sampleCallback, configCallback, std::move(options)); +}; + +template +Transformer Context::transform( + const StreamID& inputIDRaw, + const StreamID& outputIDRaw, + const std::function& sampleCallback, + const std::function& configCallback, + TransformerOptions options) const { + StreamID inputID = applyNamespace(inputIDRaw); + StreamID outputID = applyNamespace(outputIDRaw); + static_assert( + std::is_constructible::value, + "Context::transform requires that sample type T is constructed with const StreamSample&"); + static_assert( + std::is_constructible::value, + "Context::transform requires that configuration type W is constructed with const StreamConfig&"); + + // Make sure the streams are valid + if ((!std::is_same::value && + !Framework::instance().typeRegistry()->isValidStreamType(typeid(T), typeid(W))) || + (!std::is_same::value && + !Framework::instance().typeRegistry()->isValidStreamType(typeid(U), typeid(X)))) { + auto str = "Stream/Config Mismatch"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Get Types + auto typeIn = sampleType(); + + StreamDescription descIn{inputID, typeIn->typeID()}; + auto siIn = Framework::instance().streamRegistry()->registerStream(descIn); + auto typeOut = sampleType(); + + // Get Stream from Registry + StreamDescription descOut{outputID, typeOut->typeID()}; + auto siOut = Framework::instance().streamRegistry()->registerStream(descOut); + if (typeIn->typeID() != siIn->description().type() || + typeOut->typeID() != siOut->description().type()) { + // Type mismatch detected + XR_LOGCW( + "Cthulhu", + "Type mismatch detected [{}, {}] [{}, {}]", + typeIn, + siIn->description().type(), + typeOut, + siOut->description().type()); + return Transformer(siIn->description().id(), siOut->description().id()); + } + + // Create Producer + std::unique_ptr producer( + new StreamProducer(siOut, options.producerType == ProducerType::ASYNC)); + + // Create Callbacks + auto scallback = [sampleCallback, + producer = producer.get(), + &inID = siIn->description().id(), + &outID = siOut->description().id()](const StreamSample& in) -> void { + const T inData(in); + if (!producer->config()) { + XR_LOGCW("Cthulhu", "Transformer callback not executing, output stream not configured."); + return; + } + U outData = details::allocateSampleHelper(producer->config(), outID); + // TBD: What to do if callback needs to determine numSubSamples? + sampleCallback(inData, outData); + + auto& out = outData.getSample(); + out.metadata->history.emplace(inID, in.metadata); + producer->produceSample(out); + }; + ConfigCallback ccallback = [configCallback, + producer = producer.get()](const StreamConfig& in) -> bool { + const W inData(in); + X outData; + bool success = configCallback(inData, outData); + if (!success) { + return false; + } + const StreamConfig& out = outData.getConfig(); + producer->configureStream(out); + return true; + }; + if (configCallback == nullptr) { + ccallback = nullptr; + } + + // Create Consumer + std::unique_ptr consumer( + new StreamConsumer(siIn, scallback, ccallback, options.consumerType == ConsumerType::ASYNC)); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register single transformer against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + const auto& inId = siIn->description().id(); + const auto& outId = siOut->description().id(); + ctx_->registerTransformer(std::vector{inId}, std::vector{outId}); + return Transformer(inId, outId, std::move(consumer), std::move(producer)); +}; + +template +Publisher Context::advertise(const StreamID& streamIDRaw, PublisherOptions options) const { + return advertise(streamIDRaw, sampleType()->typeID(), options); +}; + +template +MultiSubscriber Context::subscribe( + const std::array& streamIDs, + const std::function& callback, + const std::function& configCallback, + MultiSubscriberOptions options) const { + // Create Aligner + auto aligner = details::alignerFromOptions(options.alignerType, std::move(options.alignerPtr)); + + // Get Types and Validate + std::array types; + details::SampleTypesStatic::template getTypes<0>(types); + std::array basicStreams; + for (unsigned long i = 0; i < N; ++i) { + auto type = Framework::instance().typeRegistry()->findTypeID(types[i]); + if (!type) { + auto str = "Attempted to lookup unregistered typeID: " + std::to_string(types[i]); + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + basicStreams[i] = type->isBasic(); + } + + // Create Callbacks and Register in Aligner + std::function&, const T&...)> callbackAppended = + [callback](const std::vector&, const T&... args) -> void { callback(args...); }; + AlignerSampleCallback cb = details::generateAlignerCallback<0>(callbackAppended); + aligner->setCallback(cb); + if (configCallback != nullptr) { + std::function&, const U&...)> configCallbackAppended = + [configCallback](const std::vector&, const U&... args) -> bool { + return configCallback(args...); + }; + AlignerConfigCallback ccb = + details::generateAlignerConfigCallback<0>(configCallbackAppended, basicStreams); + aligner->setConfigCallback(ccb); + } + + // Get Streams from Registry and Load in Aligner + std::vector streamIDsVec; + streamIDsVec.reserve(N); + for (unsigned long i = 0; i < N; i++) { + StreamID streamID = applyNamespace(streamIDs[i]); + auto type = Framework::instance().typeRegistry()->findTypeID(types[i]); + StreamDescription desc{streamID, types[i]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (types[i] != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", types[i], si->description().type()); + return MultiSubscriber(streamIDsVec); + } + streamIDsVec.push_back(StreamIDView(si->description().id())); + aligner->registerConsumer(si, i); + } + aligner->finalize(); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register multi subscriber against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + ctx_->registerSubscriber(streamIDsVec); + return MultiSubscriber(streamIDsVec, std::move(aligner)); +}; + +template +MultiSubscriber Context::subscribe( + const std::vector>& streamIDs, + const std::function& callback, + const std::function& configCallback, + MultiSubscriberOptions options) const { + // Flatten StreamIDs + std::vector streamIDsFlat; + std::vector groups(streamIDs.size()); + for (int groupIdx = 0; groupIdx < streamIDs.size(); ++groupIdx) { + std::vector streamIDsNS(streamIDs[groupIdx].size()); + for (int elemIdx = 0; elemIdx < streamIDs[groupIdx].size(); ++elemIdx) { + streamIDsNS[elemIdx] = applyNamespace(streamIDs[groupIdx][elemIdx]); + } + groups[groupIdx] = streamIDs[groupIdx].size(); + streamIDsFlat.insert(streamIDsFlat.end(), streamIDsNS.begin(), streamIDsNS.end()); + } + + // Get Types + std::vector types(streamIDsFlat.size(), 0); + details::SampleTypesDynamic::getTypes(groups, 0, 0, types); + std::vector basicStreams(streamIDsFlat.size()); + for (size_t i = 0; i < basicStreams.size(); ++i) { + auto type = Framework::instance().typeRegistry()->findTypeID(types[i]); + if (!type) { + auto str = "Attempted to lookup unregistered typeID: " + std::to_string(types[i]); + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + basicStreams[i] = type->isBasic(); + } + + // Create Aligner + auto aligner = details::alignerFromOptions(options.alignerType, std::move(options.alignerPtr)); + + // Create Callbacks and Register in Aligner + std::function&, const T&...)> callbackAppended = + [callback](const std::vector&, const T&... args) -> void { callback(args...); }; + AlignerSampleCallback cb = details::generateAlignerCallback<0>(0, groups, callbackAppended); + aligner->setCallback(cb); + if (configCallback != nullptr) { + std::function&, const U&...)> configCallbackAppended = + [configCallback](const std::vector&, const U&... args) -> bool { + return configCallback(args...); + }; + AlignerConfigCallback ccb = + details::generateAlignerConfigCallback<0>(0, groups, configCallbackAppended, basicStreams); + aligner->setConfigCallback(ccb); + } + + // Get Streams from Registry and Load in Aligner + std::vector streamIDsVec; + streamIDsVec.reserve(streamIDsFlat.size()); + for (unsigned long i = 0; i < streamIDsFlat.size(); i++) { + auto type = Framework::instance().typeRegistry()->findTypeID(types[i]); + StreamDescription desc{streamIDsFlat[i], types[i]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (types[i] != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", types[i], si->description().type()); + return MultiSubscriber(streamIDsVec); + } + streamIDsVec.push_back(StreamIDView(si->description().id())); + aligner->registerConsumer(si, i); + } + aligner->finalize(); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register multi subscriber against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + ctx_->registerSubscriber(streamIDsVec); + return MultiSubscriber(streamIDsVec, std::move(aligner)); +}; + +template +MultiSubscriber Context::subscribe( + const std::vector& streamIDs, + const std::function& callback, + const std::function& configCallback, + MultiSubscriberOptions options) const { + std::vector> streamIDsGrouped(1); + streamIDsGrouped[0] = streamIDs; + return subscribe(streamIDsGrouped, callback, configCallback, std::move(options)); +}; + +template +MultiTransformer Context::transform( + const std::vector>& inputIDs, + const std::vector>& outputIDs, + const std::function& sampleCallback, + const std::function& configCallback, + MultiTransformerOptions options) const { + // Flatten StreamIDs + std::vector inputIDsFlat; + std::vector outputIDsFlat; + std::vector groups(inputIDs.size() + outputIDs.size()); + for (int groupIdx = 0; groupIdx < groups.size(); ++groupIdx) { + if (groupIdx < inputIDs.size()) { + std::vector inputIDsNS(inputIDs[groupIdx].size()); + for (int elemIdx = 0; elemIdx < inputIDs[groupIdx].size(); ++elemIdx) { + inputIDsNS[elemIdx] = applyNamespace(inputIDs[groupIdx][elemIdx]); + } + groups[groupIdx] = inputIDs[groupIdx].size(); + inputIDsFlat.insert(inputIDsFlat.end(), inputIDsNS.begin(), inputIDsNS.end()); + } else { + int modIdx = groupIdx - inputIDs.size(); + std::vector outputIDsNS(outputIDs[modIdx].size()); + for (int elemIdx = 0; elemIdx < outputIDs[modIdx].size(); ++elemIdx) { + outputIDsNS[elemIdx] = applyNamespace(outputIDs[modIdx][elemIdx]); + } + groups[groupIdx] = outputIDs[modIdx].size(); + outputIDsFlat.insert(outputIDsFlat.end(), outputIDsNS.begin(), outputIDsNS.end()); + } + } + + // Get Types + std::vector allTypes(inputIDsFlat.size() + outputIDsFlat.size(), 0); + details::SampleTypesDynamic::getTypes(groups, 0, 0, allTypes); + std::vector basicStreams(allTypes.size()); + for (size_t i = 0; i < basicStreams.size(); ++i) { + auto type = Framework::instance().typeRegistry()->findTypeID(allTypes[i]); + if (!type) { + auto str = "Attempted to lookup unregistered typeID: " + std::to_string(allTypes[i]); + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + basicStreams[i] = type->isBasic(); + } + + // Create Aligner + auto aligner = details::alignerFromOptions(options.alignerType, std::move(options.alignerPtr)); + + // Create Dispatcher + auto dispatcher = std::make_unique(); + + // Create Callbacks and Register in Aligner + std::function&, + const std::vector&, + std::vector&, + T&...)> + callbackAppended = [sampleCallback]( + const std::vector&, + const std::vector&, + std::vector&, + T&... args) -> void { sampleCallback(args...); }; + + AlignerSampleCallback cb = details::generateAlignerCallback<0>( + dispatcher.get(), 0, 0, inputIDsFlat, outputIDsFlat, groups, callbackAppended); + aligner->setCallback(cb); + + if (configCallback != nullptr) { + std::function&, std::vector&, U&...)> + configCallbackAppended = [configCallback]( + const std::vector&, + std::vector&, + U&... args) -> bool { return configCallback(args...); }; + + AlignerConfigCallback ccb = details::generateAlignerConfigCallback<0>( + dispatcher.get(), 0, 0, outputIDsFlat.size(), groups, configCallbackAppended, basicStreams); + aligner->setConfigCallback(ccb); + } + + // Get Input Streams from Registry and Load into Aligner + std::vector inputIDsVec; + inputIDsVec.reserve(inputIDsFlat.size()); + std::vector outputIDsVec; + outputIDsVec.reserve(outputIDsFlat.size()); + for (unsigned long i = 0; i < inputIDsFlat.size(); i++) { + StreamDescription desc{inputIDsFlat[i], allTypes[i]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (allTypes[i] != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", allTypes[i], si->description().type()); + return MultiTransformer(inputIDsVec, outputIDsVec); + } + inputIDsVec.push_back(StreamIDView(si->description().id())); + aligner->registerConsumer(si, i); + } + + // Get Output Streams from Registry and Load into Dispatcher + for (unsigned long i = 0; i < outputIDsFlat.size(); i++) { + StreamDescription desc{outputIDsFlat[i], allTypes[i + inputIDsFlat.size()]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (allTypes[i + inputIDsFlat.size()] != si->description().type()) { + // Type mismatch detected + XR_LOGCW( + "Cthulhu", + "Out Type mismatch detected [{}, {}]", + allTypes[i + inputIDsFlat.size()], + si->description().type()); + return MultiTransformer(inputIDsVec, outputIDsVec); + } + outputIDsVec.push_back(StreamIDView(si->description().id())); + dispatcher->registerProducer(si); + } + aligner->finalize(); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register multi transformer against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + + ctx_->registerTransformer(inputIDsVec, outputIDsVec); + return MultiTransformer(inputIDsVec, outputIDsVec, std::move(aligner), std::move(dispatcher)); +}; + +template +MultiPublisher Context::advertise(const std::array& streamIDs) const { + // Create Dispatcher + std::unique_ptr dispatcher = std::make_unique(); + + // Get Types + std::array types; + details::SampleTypesStatic::template getTypes<0>(types); + + // Get Streams from Registry and Load in Dispatcher + std::vector streamIDsVec; + streamIDsVec.reserve(N); + for (unsigned long i = 0; i < N; i++) { + StreamID streamID = applyNamespace(streamIDs[i]); + StreamDescription desc{streamID, types[i]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (types[i] != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", types[i], si->description().type()); + return MultiPublisher(streamIDsVec); + } + streamIDsVec.push_back(StreamIDView(si->description().id())); + dispatcher->registerProducer(si); + } + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register multi publisher against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + ctx_->registerPublisher(streamIDsVec); + return MultiPublisher(streamIDsVec, std::move(dispatcher)); +}; + +template +MultiPublisher Context::advertise(const std::vector>& streamIDs) const { + // Flatten StreamIDs + std::vector streamIDsFlat; + std::vector groups(streamIDs.size()); + for (int groupIdx = 0; groupIdx < streamIDs.size(); ++groupIdx) { + std::vector streamIDsNS(streamIDs[groupIdx].size()); + for (int elemIdx = 0; elemIdx < streamIDs[groupIdx].size(); ++elemIdx) { + streamIDsNS[elemIdx] = applyNamespace(streamIDs[groupIdx][elemIdx]); + } + groups[groupIdx] = streamIDs[groupIdx].size(); + streamIDsFlat.insert(streamIDsFlat.end(), streamIDsNS.begin(), streamIDsNS.end()); + } + + // Create Dispatcher + std::unique_ptr dispatcher = std::make_unique(); + + // Get Types + std::vector types(streamIDsFlat.size()); + details::SampleTypesDynamic::getTypes(groups, 0, 0, types); + + // Get Streams from Registry and Load in Dispatcher + std::vector streamIDsVec; + streamIDsVec.reserve(streamIDsFlat.size()); + for (unsigned long i = 0; i < streamIDsFlat.size(); i++) { + StreamDescription desc{streamIDsFlat[i], types[i]}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (types[i] != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "P Type mismatch detected [{}, {}]", types[i], si->description().type()); + return MultiPublisher(streamIDsVec); + } + streamIDsVec.push_back(StreamIDView(si->description().id())); + dispatcher->registerProducer(si); + } + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register multi publisher against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + ctx_->registerPublisher(streamIDsVec); + return MultiPublisher(streamIDsVec, std::move(dispatcher)); +}; + +template +MultiPublisher Context::advertise(const std::vector& streamIDs) const { + std::vector> streamIDsGrouped(1); + streamIDsGrouped[0] = streamIDs; + return advertise(streamIDsGrouped); +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/ContextImpl_details.h b/Cthulhu/include/cthulhu/ContextImpl_details.h new file mode 100644 index 000000000..8d3227411 --- /dev/null +++ b/Cthulhu/include/cthulhu/ContextImpl_details.h @@ -0,0 +1,1117 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +namespace details { + +// This is a utility for allocating a sample from the Framework. +template +T allocateSampleHelper( + const StreamConfig* const config, + const StreamIDView& id, + uint32_t numSubSamples = 1) { + static_assert( + std::is_base_of_v, + "cthulhu::details::allocateSampleHelper only supports types that subclas cthulhu::AutoStreamSample"); + + if (!config) { + auto str = "Attempted to allocate sample on an unconfigured stream."; + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + const bool hasSamplesInContentBlock = cthulhu::Framework::instance() + .typeRegistry() + ->findSampleType(typeid(T)) + ->hasSamplesInContentBlock(); + + size_t payloadSize = config->sampleSizeInBytes * numSubSamples; + StreamSample uncastedSample; + uncastedSample.payload = Framework::instance().memoryPool()->getBufferFromPool(id, payloadSize); + uncastedSample.numberOfSubSamples = numSubSamples; + + return T{uncastedSample, hasSamplesInContentBlock}; +}; + +// This helper class gets the size of an object if it is an array, othersize returns size 1 +template +struct ArraySize; +template +struct ArraySize> { + static size_t const size = N; +}; +// Default case if its not an array +template +struct ArraySize { + static size_t const size = 1; +}; + +// This helper class is used to resize an object if it is a vector, otherwise assert that +// the resize operation is to size 1 +template +struct ResizeHelper; +template +struct ResizeHelper> { + static void resize(std::vector& arg, size_t size) { + arg.resize(size); + }; +}; +template +struct ResizeHelper { + static void resize(T& arg, size_t size) { + assert(size == 1); + }; +}; + +// Similar to ResizeHelper, but this can be used on a Sample Type to both resize the +// vector and allocate a sample, given its StreamID. +template +struct ResizeAllocHelper; +template +struct ResizeAllocHelper> { + static void resize( + std::vector& arg, + size_t size, + Dispatcher* dispatcher, + unsigned long idx, + const std::vector& ids) { + arg.resize(size); + for (const auto& id : ids) { + arg[idx] = details::allocateSampleHelper(dispatcher->streamConfig(idx), id); + idx++; + } + }; +}; +template +struct ResizeAllocHelper { + static void resize( + T& arg, + size_t size, + Dispatcher* dispatcher, + unsigned long idx, + const std::vector& ids) { + assert(size == 1); + arg = details::allocateSampleHelper(dispatcher->streamConfig(idx), ids[0]); + }; +}; + +// These cast generic samples to typed samples statically (for sizes known at compile time) +template +void sampleCaster( + const std::vector& samples, + std::array& castedSamples) { + if (samples.size() < (offset + groupSize - 1)) { + throw std::exception(); + } + for (unsigned long i = 0; i < groupSize; i++) { + const auto& sample = samples[offset + i]; + castedSamples[i].setSample(sample); + } +}; +template +void sampleCaster(const std::vector& samples, T& castedSample) { + if (samples.size() < (offset)) { + throw std::exception(); + } + const auto& sample = samples[offset]; + castedSample.setSample(sample); +}; + +// These cast generic samples to typed samples dynamically (for sizes known at run time) +template +void sampleCaster( + unsigned long offset, + unsigned long groupSize, + const std::vector& samples, + std::vector& castedSamples) { + // Resize the castedSamples output here, since this is where we can be sure + // that they are a vector type + castedSamples.resize(groupSize); + if (samples.size() < (offset + groupSize - 1)) { + throw std::exception(); + } + for (unsigned long i = 0; i < groupSize; i++) { + const auto& sample = samples[offset + i]; + castedSamples[i].setSample(sample); + } +}; +template +void sampleCaster( + unsigned long offset, + unsigned long groupSize, + const std::vector& samples, + T& castedSample) { + if (groupSize != 1 || samples.size() < offset) { + throw std::exception(); + } + const auto& sample = samples[offset]; + castedSample.setSample(sample); +}; + +// These cast generic configs to typed configs statically (for sizes known at compile time) +template +void configCaster( + const std::vector& configs, + std::array& castedConfigs, + unsigned long skipOffset) { + if (configs.size() < (offset + groupSize - 1)) { + throw std::exception(); + } + for (unsigned long i = 0; i < groupSize; i++) { + const auto& config = configs[offset + skipOffset + i]; + castedConfigs[i].setConfig(config); + } +}; +template +void configCaster( + const std::vector& configs, + T& castedConfig, + unsigned long skipOffset) { + if (configs.size() < (offset)) { + throw std::exception(); + } + const auto& config = configs[offset + skipOffset]; + castedConfig.setConfig(config); +}; + +// These cast generic configs to typed configs dynamically (for sizes known at run time) +template +void configCaster( + unsigned long offset, + unsigned long groupSize, + const std::vector& configs, + std::vector& castedConfigs) { + // Resize the castedConfigs output here, since this is where we can be sure + // that they are a vector type + castedConfigs.resize(groupSize); + if (configs.size() < (offset + groupSize - 1)) { + throw std::exception(); + } + for (unsigned long i = 0; i < groupSize; i++) { + const auto& config = configs[offset + i]; + castedConfigs[i].setConfig(config); + } +}; +template +void configCaster( + unsigned long offset, + unsigned long groupSize, + const std::vector& configs, + T& castedConfig) { + if (groupSize != 1 || configs.size() < offset) { + throw std::exception(); + } + const auto& config = configs[offset]; + castedConfig.setConfig(config); +}; + +// These uncast typed samples to generic samples dynamically (for sizes known at run time) +// Variadic templates allow for this to be called on parameter groupings of vectors and regular +// samples TBD: Would need to add support for array types in order to directly publish an array +// object +template +struct SampleUncaster; +template +struct SampleUncaster> { + static bool uncast( + std::vector& samplesUnflat, + unsigned long offset, + const std::vector& samples) { + if (samplesUnflat.size() != offset + samples.size() || + !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + return false; + } + for (unsigned long i = 0; i < samples.size(); i++) { + const StreamSample& streamSamp = samples[i].getSample(); + samplesUnflat[offset + i] = streamSamp; + } + + return true; + }; +}; +template +struct SampleUncaster { + static bool + uncast(std::vector& samplesUnflat, unsigned long offset, const T& sample) { + if (samplesUnflat.size() != (offset + 1) || + !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + return false; + } + const StreamSample& streamSamp = sample.getSample(); + samplesUnflat[offset] = streamSamp; + + return true; + }; +}; +template +struct SampleUncaster, other...> { + static bool uncast( + std::vector& samplesUnflat, + unsigned long offset, + const std::vector& samples, + const other&... others) { + if (samplesUnflat.size() < offset + samples.size() || + !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + return false; + } + for (unsigned long i = 0; i < samples.size(); i++) { + const StreamSample& streamSamp = samples[i].getSample(); + samplesUnflat[offset + i] = streamSamp; + } + + return SampleUncaster::uncast(samplesUnflat, offset + samples.size(), others...); + }; +}; +template +struct SampleUncaster { + static bool uncast( + std::vector& samplesUnflat, + unsigned long offset, + const T& sample, + const other&... others) { + if (samplesUnflat.size() <= offset || + !Framework::instance().typeRegistry()->findSampleType(typeid(T))) { + return false; + } + const StreamSample& streamSamp = sample.getSample(); + samplesUnflat[offset] = streamSamp; + + return SampleUncaster::uncast(samplesUnflat, offset + 1, others...); + }; +}; + +// These uncast typed configs to generic configs dynamically (for sizes known at run time) +// Variadic templates allow for this to be called on parameter groupings of vectors and regular +// samples. The variadic form is currently not used in MultiPublisher, since the configure() +// function configures one stream at a time +template +struct ConfigUncaster; +template +struct ConfigUncaster> { + static bool uncast( + std::vector& configsUnflat, + unsigned long offset, + const std::vector& configs) { + if (configsUnflat.size() != offset + configs.size() || + !Framework::instance().typeRegistry()->findConfigType(typeid(T))) { + return false; + } + for (unsigned long i = 0; i < configs.size(); i++) { + const StreamConfig streamConf(configs[i].getConfig()); + configsUnflat[offset + i] = streamConf; + } + + return true; + }; +}; +template +struct ConfigUncaster { + static bool + uncast(std::vector& configsUnflat, unsigned long offset, const T& config) { + if (configsUnflat.size() != (offset + 1) || + !Framework::instance().typeRegistry()->findConfigType(typeid(T))) { + return false; + } + const StreamConfig streamConf(config.getConfig()); + configsUnflat[offset] = streamConf; + + return true; + }; +}; +template +struct ConfigUncaster, other...> { + static bool uncast( + std::vector& configsUnflat, + unsigned long offset, + const std::vector& configs, + const other&... others) { + if (configsUnflat.size() < offset + configs.size() || + !Framework::instance().typeRegistry()->findConfigType(typeid(T))) { + return false; + } + for (unsigned long i = 0; i < configs.size(); i++) { + const StreamConfig streamConf(configs[i].getConfig()); + configsUnflat[offset + i] = streamConf; + } + + return ConfigUncaster::uncast(configsUnflat, offset + configs.size(), others...); + }; +}; +template +struct ConfigUncaster { + static bool uncast( + std::vector& configsUnflat, + unsigned long offset, + const T& config, + const other&... others) { + if (configsUnflat.size() <= offset || + !Framework::instance().typeRegistry()->findConfigType(typeid(T))) { + return false; + } + const StreamConfig streamConf(config.getConfig()); + configsUnflat[offset] = streamConf; + + return ConfigUncaster::uncast(configsUnflat, offset + 1, others...); + }; +}; + +// Gets the typeid's of a parameter pack mixing regular and vector types +template +struct SampleTypesDynamicHelper { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long i = 0; i < groups[groupNumber]; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } + return; + } +}; +template +struct SampleTypesDynamicHelper> { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long in = 0; in < groups[groupNumber]; in++) { + types[offset + in] = + Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } + return; + } +}; +template +struct SampleTypesDynamicHelper> { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long in = 0; in < groups[groupNumber]; in++) { + types[offset + in] = + Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } + return; + } +}; + +template +struct SampleTypesDynamic; +template +struct SampleTypesDynamic { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + SampleTypesDynamicHelper::getTypes(groups, groupNumber, offset, types); + } +}; +template +struct SampleTypesDynamic { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + SampleTypesDynamicHelper::getTypes(groups, groupNumber, offset, types); + SampleTypesDynamic::getTypes( + groups, groupNumber + 1, offset + groups[groupNumber], types); + } +}; + +// Gets the typeid's of a parameter pack mixing regular and vector types +template +struct ConfigTypesDynamicHelper { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long i = 0; i < groups[groupNumber]; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } + return; + } +}; +template +struct ConfigTypesDynamicHelper> { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long in = 0; in < groups[groupNumber]; in++) { + types[offset + in] = + Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } + return; + } +}; +template +struct ConfigTypesDynamicHelper> { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + if (groups.size() <= groupNumber || groups[groupNumber] + offset > types.size()) { + throw std::exception(); + } + for (unsigned long in = 0; in < groups[groupNumber]; in++) { + types[offset + in] = + Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } + return; + } +}; + +template +struct ConfigTypesDynamic; +template +struct ConfigTypesDynamic { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + ConfigTypesDynamicHelper::getTypes(groups, groupNumber, offset, types); + } +}; +template +struct ConfigTypesDynamic { + static void getTypes( + const std::vector& groups, + unsigned long groupNumber, + unsigned long offset, + std::vector& types) { + ConfigTypesDynamicHelper::getTypes(groups, groupNumber, offset, types); + ConfigTypesDynamic::getTypes( + groups, groupNumber + 1, offset + groups[groupNumber], types); + } +}; + +// Gets the typeid's of a parameter pack mixing regular and array types +template +struct SampleTypesStatic; +template +struct SampleTypesStatic> { + template + static void getTypes(std::array& types) { + static_assert((offset + N) <= M, "SampleTypesStatic::getTypes out of bounds"); + for (unsigned long i = 0; i < N; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } + } +}; +template +struct SampleTypesStatic { + template + static void getTypes(std::array& types) { + static_assert(offset <= M, "SampleTypesStatic::getTypes out of bounds"); + types[offset] = Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } +}; +template +struct SampleTypesStatic, other...> { + template + static void getTypes(std::array& types) { + static_assert((offset + N) <= M, "SampleTypesStatic::getTypes out of bounds"); + for (unsigned long i = 0; i < N; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + } + return SampleTypesStatic::getTypes(types); + } +}; +template +struct SampleTypesStatic { + template + static void getTypes(std::array& types) { + static_assert(offset <= M, "SampleTypesStatic::getTypes out of bounds"); + types[offset] = Framework::instance().typeRegistry()->findSampleType(typeid(T))->typeID(); + return SampleTypesStatic::getTypes(types); + } +}; + +// Gets the typeid's of a parameter pack mixing regular and array types +template +struct ConfigTypesStatic; +template +struct ConfigTypesStatic { + template + static void getTypes(std::array& types) { + static_assert(offset <= M, "ConfigTypesStatic::getTypes out of bounds"); + types[offset] = Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } +}; +template +struct ConfigTypesStatic> { + template + static void getTypes(std::array& types) { + static_assert((offset + N) <= M, "ConfigTypesStatic::getTypes out of bounds"); + for (unsigned long i = 0; i < N; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } + } +}; +template +struct ConfigTypesStatic, other...> { + template + static void getTypes(std::array& types) { + static_assert((offset + N) <= M, "ConfigTypesStatic::getTypes out of bounds"); + for (unsigned long i = 0; i < N; i++) { + types[offset + i] = Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + } + return ConfigTypesStatic::getTypes(types); + } +}; +template +struct ConfigTypesStatic { + template + static void getTypes(std::array& types) { + static_assert(offset <= M, "ConfigTypesStatic::getTypes out of bounds"); + types[offset] = Framework::instance().typeRegistry()->findConfigType(typeid(T))->typeID(); + return ConfigTypesStatic::getTypes(types); + } +}; + +// Generate Aligner Sample Callbacks using Compile-time groupings +template +AlignerSampleCallback generateAlignerCallback( + const std::function&, const T&)>& callback) { + AlignerSampleCallback alignerCallback = + [callback](const std::vector& samples) -> void { + T castedSamples; + sampleCaster(samples, castedSamples); + callback(samples, castedSamples); + }; + return alignerCallback; +}; +template +AlignerSampleCallback generateAlignerCallback( + const std::function&, const T&, const other&...)>& + callback) { + std::function&, const other&...)> callbackReduced = + [callback](const std::vector& samples, const other&... args) -> void { + T castedSamples; + sampleCaster(samples, castedSamples); + callback(samples, castedSamples, args...); + }; + return generateAlignerCallback::size>(callbackReduced); +}; + +// Generate Aligner Sample Callbacks using Run-time groupings +template +AlignerSampleCallback generateAlignerCallback( + unsigned long offset, + const std::vector& groupSizes, + const std::function&, const T&)>& callback) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + AlignerSampleCallback alignerCallback = [callback, offset, groupSize = groupSizes[groupNumber]]( + const std::vector& samples) -> void { + T castedSamples; + sampleCaster(offset, groupSize, samples, castedSamples); + callback(samples, castedSamples); + }; + if (groupSizes.size() != groupNumber + 1) { + throw std::exception(); + } + return alignerCallback; +}; +template +AlignerSampleCallback generateAlignerCallback( + unsigned long offset, + const std::vector& groupSizes, + const std::function&, const T&, const other&...)>& + callback) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + std::function&, const other&...)> callbackReduced = + [callback, offset, groupSize = groupSizes[groupNumber]]( + const std::vector& samples, const other&... args) -> void { + T castedSamples; + sampleCaster(offset, groupSize, samples, castedSamples); + callback(samples, castedSamples, args...); + }; + return generateAlignerCallback( + offset + groupSizes[groupNumber], groupSizes, callbackReduced); +}; + +// Generate Transformer-Aligner Sample Callbacks using Run-time groupings +template +AlignerSampleCallback generateAlignerCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + const std::vector& inputIDs, + const std::vector& outputIDs, + const std::vector& groupSizes, + const std::function&, + const std::vector&, + std::vector&, + T&)>& callback) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + AlignerSampleCallback callbackReduced = + [dispatcher, + inputIDs, + outputIDs, + callback, + outputOffset, + groupSize = groupSizes[groupNumber]](const std::vector& samplesIn) -> void { + T castedSamples; + ResizeAllocHelper::resize(castedSamples, groupSize, dispatcher, outputOffset, outputIDs); + std::vector samplesOut(outputIDs.size()); + callback(outputIDs, samplesIn, samplesOut, castedSamples); + SampleUncaster::uncast(samplesOut, outputOffset, castedSamples); + for (auto& sampleOut : samplesOut) { + for (size_t inputIdx = 0; inputIdx < samplesIn.size(); ++inputIdx) { + sampleOut.metadata->history.emplace(inputIDs[inputIdx], samplesIn[inputIdx].metadata); + } + } + dispatcher->dispatchSamples(samplesOut); + }; + return callbackReduced; +}; +template +AlignerSampleCallback generateAlignerCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + const std::vector& inputIDs, + const std::vector& outputIDs, + const std::vector& groupSizes, + const std::function&, + const std::vector&, + std::vector&, + const T&, + other&...)>& callback) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + std::function&, + const std::vector&, + std::vector&, + other&...)> + callbackReduced = [callback, inputOffset, groupSize = groupSizes[groupNumber]]( + const std::vector& _outputIDs, + const std::vector& samplesIn, + std::vector& samplesOut, + other&... args) -> void { + T castedSamples; + sampleCaster(inputOffset, groupSize, samplesIn, castedSamples); + callback(_outputIDs, samplesIn, samplesOut, castedSamples, args...); + }; + return generateAlignerCallback( + dispatcher, + inputOffset + groupSizes[groupNumber], + outputOffset, + inputIDs, + outputIDs, + groupSizes, + callbackReduced); +}; +template +AlignerSampleCallback generateAlignerCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + const std::vector& inputIDs, + const std::vector& outputIDs, + const std::vector& groupSizes, + const std::function&, + const std::vector&, + std::vector&, + T&, + other&...)>& callback) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + std::function&, + const std::vector&, + std::vector&, + other&...)> + callbackReduced = [dispatcher, callback, outputOffset, groupSize = groupSizes[groupNumber]]( + const std::vector& _outputIDs, + const std::vector& samplesIn, + std::vector& samplesOut, + other&... args) -> void { + T castedSamples; + ResizeAllocHelper::resize(castedSamples, groupSize, dispatcher, outputOffset, _outputIDs); + callback(_outputIDs, samplesIn, samplesOut, castedSamples, args...); + SampleUncaster::uncast(samplesOut, outputOffset, castedSamples); + }; + return generateAlignerCallback( + dispatcher, + inputOffset, + outputOffset + groupSizes[groupNumber], + inputIDs, + outputIDs, + groupSizes, + callbackReduced); +}; + +// Generate Aligner Config Callbacks using Compile-time groupings +// Handle the case of a null config callback +template +AlignerConfigCallback generateAlignerConfigCallback( + const std::function&, const T&)>& callback, + const std::array& skipStreams, + unsigned long skipOffset = 0) { + while (skipStreams[offset + skipOffset]) { + skipOffset++; + if (skipStreams.size() <= offset + skipOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + } + AlignerConfigCallback alignerCallback = + [callback, skipOffset](const std::vector& configs) -> bool { + T castedConfigs; + configCaster(configs, castedConfigs, skipOffset); + return callback(configs, castedConfigs); + }; + return alignerCallback; +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + const std::function&)>& callback, + const std::array& skipStreams, + unsigned long skipOffset = 0) { + AlignerConfigCallback alignerCallback = [](const std::vector& configs) -> bool { + return false; + }; + return alignerCallback; +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + const std::function&, const T&, const other&...)>& + callback, + const std::array& skipStreams, + unsigned long skipOffset = 0) { + while (skipStreams[offset + skipOffset]) { + skipOffset++; + if (skipStreams.size() <= offset + skipOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + } + std::function&, const other&...)> callbackReduced = + [callback, skipOffset]( + const std::vector& configs, const other&... args) -> bool { + T castedConfigs; + configCaster(configs, castedConfigs, skipOffset); + return callback(configs, castedConfigs, args...); + }; + return generateAlignerConfigCallback::size>( + callbackReduced, skipStreams, skipOffset); +}; + +// Generate Aligner Config Callbacks using Run-time groupings +// Handle the case of a null config callback +template +AlignerConfigCallback generateAlignerConfigCallback( + unsigned long offset, + const std::vector& groupSizes, + const std::function&, const T&)>& callback, + const std::vector& skipStreams) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + if (skipStreams.size() <= offset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[offset]) { + offset += groupSizes[groupNumber]; + } + AlignerConfigCallback alignerCallback = [callback, offset, groupSize = groupSizes[groupNumber]]( + const std::vector& configs) -> bool { + T castedConfigs; + configCaster(offset, groupSize, configs, castedConfigs); + return callback(configs, castedConfigs); + }; + if (groupSizes.size() != groupNumber + 1) { + throw std::exception(); + } + return alignerCallback; +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + unsigned long offset, + const std::vector& groupSizes, + const std::function&)>& callback, + const std::vector& skipStreams) { + AlignerConfigCallback alignerCallback = [](const std::vector& configs) -> bool { + return false; + }; + return alignerCallback; +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + unsigned long offset, + const std::vector& groupSizes, + const std::function&, const T&, const other&...)>& + callback, + const std::vector& skipStreams) { + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + if (skipStreams.size() <= offset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[offset]) { + offset += groupSizes[groupNumber]; + } + std::function&, const other&...)> callbackReduced = + [callback, offset, groupSize = groupSizes[groupNumber]]( + const std::vector& configs, const other&... args) -> bool { + T castedConfigs; + configCaster(offset, groupSize, configs, castedConfigs); + return callback(configs, castedConfigs, args...); + }; + return generateAlignerConfigCallback( + offset + groupSizes[groupNumber], groupSizes, callbackReduced, skipStreams); +}; + +// Generate Transformer-Aligner Config Callbacks using Run-time groupings +// Handle the case with single input set, no outputs +template +AlignerConfigCallback generateAlignerConfigCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + size_t outSize, + const std::vector& groupSizes, + const std::function< + bool(const std::vector&, std::vector&, const T&)>& callback, + const std::vector& skipStreams) { + if (skipStreams.size() <= inputOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[inputOffset]) { + inputOffset += groupSizes[groupNumber]; + } + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + AlignerConfigCallback callbackReduced = + [dispatcher, callback, inputOffset, groupSize = groupSizes[groupNumber], outSize]( + const std::vector& configsIn) -> bool { + T castedConfigs; + configCaster(inputOffset, groupSize, configsIn, castedConfigs); + std::vector configsOut(outSize); + if (!callback(configsIn, configsOut, castedConfigs)) { + return false; + } + dispatcher->dispatchConfigs(configsOut); + return true; + }; + return callbackReduced; +}; +// Handle the case of a null config callback +template +AlignerConfigCallback generateAlignerConfigCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + size_t outSize, + const std::vector& groupSizes, + const std::function&, std::vector&, T&)>& + callback, + const std::vector& skipStreams) { + if (skipStreams.size() <= outputOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[outputOffset]) { + outputOffset += groupSizes[groupNumber]; + } + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + AlignerConfigCallback callbackReduced = + [dispatcher, outSize, callback, outputOffset, groupSize = groupSizes[groupNumber]]( + const std::vector& configsIn) -> bool { + T castedConfigs; + ResizeHelper::resize(castedConfigs, groupSize); + std::vector configsOut(outSize); + if (!callback(configsIn, configsOut, castedConfigs)) { + return false; + } + ConfigUncaster::uncast(configsOut, outputOffset, castedConfigs); + dispatcher->dispatchConfigs(configsOut); + return true; + }; + return callbackReduced; +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + size_t outSize, + const std::vector& groupSizes, + const std::function< + bool(const std::vector&, std::vector&, const T&, other&...)>& + callback, + const std::vector& skipStreams) { + if (skipStreams.size() <= inputOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[inputOffset]) { + inputOffset += groupSizes[groupNumber]; + } + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + std::function&, std::vector&, other&...)> + callbackReduced = [callback, inputOffset, groupSize = groupSizes[groupNumber]]( + const std::vector& configsIn, + std::vector& configsOut, + other&... args) -> bool { + T castedConfigs; + configCaster(inputOffset, groupSize, configsIn, castedConfigs); + return callback(configsIn, configsOut, castedConfigs, args...); + }; + return generateAlignerConfigCallback( + dispatcher, + inputOffset + groupSizes[groupNumber], + outputOffset, + outSize, + groupSizes, + callbackReduced, + skipStreams); +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + size_t outSize, + const std::vector& groupSizes, + const std::function&, + std::vector&, + T&, + other&...)>& callback, + const std::vector& skipStreams) { + if (skipStreams.size() <= outputOffset) { + auto str = "Too many configs in Node callback"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + if (skipStreams[outputOffset]) { + outputOffset += groupSizes[groupNumber]; + } + if (groupNumber >= groupSizes.size()) { + throw std::exception(); + } + std::function&, T&, other&...)> callbackReduced = + [dispatcher, callback, outputOffset, groupSize = groupSizes[groupNumber]]( + const std::vector& configsIn, + std::vector& configsOut, + other&... args) -> bool { + T castedConfigs; + ResizeHelper::resize(castedConfigs, groupSize); + if (!callback(configsIn, configsOut, castedConfigs, args...)) { + return false; + } + ConfigUncaster::uncast(configsOut, outputOffset, castedConfigs); + return true; + }; + return generateAlignerConfigCallback( + dispatcher, + inputOffset, + outputOffset + groupSizes[groupNumber], + outSize, + groupSizes, + callbackReduced, + skipStreams); +}; +template +AlignerConfigCallback generateAlignerConfigCallback( + Dispatcher* dispatcher, + unsigned long inputOffset, + unsigned long outputOffset, + size_t outSize, + const std::vector& groupSizes, + const std::function&, std::vector&)>& + callback, + const std::vector& skipStreams) { + AlignerConfigCallback callbackReduced = [](const std::vector& configsIn) -> bool { + return false; + }; + return callbackReduced; +}; + +inline std::unique_ptr alignerFromOptions( + const AlignerType& type, + std::unique_ptr pointer) { + switch (type) { + case AlignerType::SYNC: { + XR_LOGCW_IF( + pointer != nullptr, + "Cthulhu", + "A custom aligner was supplied, but default SYNC aligner is being used instead!"); + return std::make_unique(1, ThreadPolicy::THREAD_NEUTRAL); + } + case AlignerType::ASYNC: { + XR_LOGCW_IF( + pointer != nullptr, + "Cthulhu", + "A custom aligner was supplied, but default ASYNC aligner is being used instead!"); + return std::make_unique(10, ThreadPolicy::SINGLE_THREADED); + } + case AlignerType::CUSTOM: + // No move necessary, this'll be done automatically by the compiler + return pointer; + } + auto str = "Unhandled aligner type"; + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); +} + +} // namespace details + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/ContextRegistryInterface.h b/Cthulhu/include/cthulhu/ContextRegistryInterface.h new file mode 100644 index 000000000..ea3c4f1db --- /dev/null +++ b/Cthulhu/include/cthulhu/ContextRegistryInterface.h @@ -0,0 +1,84 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +namespace cthulhu { + +// ContextInfoInterface provides a handle into data about a specific context +// +// The handle should be used by contexts to update information about their publications and +// subscriptions. Other users will only be given a ConstPtr which can only be used to query +// information about the context, not update it. +class ContextInfoInterface { + public: + virtual ~ContextInfoInterface() = default; + + virtual std::string name() const = 0; + virtual bool isPrivateNamespace() const = 0; + + // Returns some unique identifier for the process that created this context. This value doesn't + // need to necessarily be a PID, just needs to be guaranteed to be consistent across a process. + virtual int getPid() const = 0; + + // A context may be marked as invalid if it was e.g. destructed by the owning process. The + // Registry implementation can choose to keep track of invalid contexts, indicated by this flag. + virtual bool getValid() const = 0; + + // Each context can register multiple subscribers, publishers, or transformers, and can + // have multiple streams associated with each call. The output from these 3 methods + // returns that information as nested vectors, in the order the individual calls + // (subscribe, advertise, transform) were made. + using RegistrationGroup = std::vector; + virtual std::vector subscriptions() const = 0; + virtual std::vector publications() const = 0; + virtual std::vector> transformations() const = 0; + + virtual void registerSubscriber(const std::vector& streams) = 0; + virtual void registerPublisher(const std::vector& streams) = 0; + virtual void registerTransformer( + const std::vector& inputs, + const std::vector& outputs) = 0; + + // Convenience overloads since Context uses StreamIDViews all over the place + virtual void registerSubscriber(const std::vector& views) = 0; + virtual void registerPublisher(const std::vector& views) = 0; + virtual void registerTransformer( + const std::vector& input_views, + const std::vector& output_views) = 0; +}; +using ContextInfoInterfaceConstPtr = std::shared_ptr; + +class ContextRegistryInterface : public ForceCleanable, public LogDisabling { + public: + virtual ~ContextRegistryInterface() = default; + + // Register a new context, and return a handle to it + // + // Additional information (subscriber info, etc) should be registered through the + // returned handle. The caller (context) should not free the returned handle as it is + // managed by the ContextRegistry. + virtual ContextInfoInterface* registerContext(std::string_view name, bool private_ns = false) = 0; + + // Remove an existing context from the registry, if it exists + // + // Only pointers returned by registerContext() should be passed to removeContext(). + virtual void removeContext(ContextInfoInterface* handle) = 0; + + // Return a vector of handles to all context information + // + // This method exists primarily for consumers. Implementations may choose to return a + // copy of data, or return a const pointer to persistent memory. In the latter case, + // repeatedly calling methods of ContextInfoInterface will return updated information. + // However, in either case, to obtain information about new contexts, this method will + // need to be called again. + // + // This method takes a parameter, all, indicating that the Registry implementation should return + // all contexts it currently knows about. The return value in both cases may be the same, or the + // contexts returned by setting all=true may be a superset of all=false. + virtual std::vector contexts(bool all = false) const = 0; +}; +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/Dispatcher.h b/Cthulhu/include/cthulhu/Dispatcher.h new file mode 100644 index 000000000..f87ff6ef7 --- /dev/null +++ b/Cthulhu/include/cthulhu/Dispatcher.h @@ -0,0 +1,38 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +class Dispatcher { + public: + Dispatcher(){}; + + virtual ~Dispatcher() = default; + + // Non-copyable + Dispatcher(const Dispatcher&) = delete; + Dispatcher& operator=(const Dispatcher&) = delete; + + // Movable + Dispatcher(Dispatcher&&); + Dispatcher& operator=(Dispatcher&&); + + void registerProducer(StreamInterface* si); + + void dispatchSamples(const std::vector& samples); + void dispatchConfigs(std::vector& configs); + + void configureStream(const StreamConfig& config, uint32_t streamNumber); + + const StreamConfig* streamConfig(uint32_t streamNumber); + + protected: + using IdentifiedProducer = std::pair>; + std::vector producers_; + +}; // class Dispatcher + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/FieldData.h b/Cthulhu/include/cthulhu/FieldData.h new file mode 100644 index 000000000..29a0bd6e3 --- /dev/null +++ b/Cthulhu/include/cthulhu/FieldData.h @@ -0,0 +1,41 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace cthulhu { + +struct Field { + uint32_t offset = 0; + uint32_t size = 0; + std::string typeName; + uint32_t numElements = 0; + + // Describes whether or not a field is dynamically-sized. + // If it is, the 'offset' member describes its allocation + // in an array of dynamically-sized arrays. Otherwise, 'offset' + // describes its offset in the parameters block. + bool isDynamic = false; + + friend bool operator==(const Field& left, const Field& right) { + return (left.offset == right.offset) && (left.size == right.size) && + (left.typeName == right.typeName) && (left.numElements == right.numElements) && + (left.isDynamic == right.isDynamic); + } + + friend bool operator!=(const Field& left, const Field& right) { + return !(left == right); + } + +}; // namespace cthulhu + +// Some consumers need to be able to iterate in sorted order. +using FieldData = std::map; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/ForceCleanable.h b/Cthulhu/include/cthulhu/ForceCleanable.h new file mode 100644 index 000000000..1e2a7d3a7 --- /dev/null +++ b/Cthulhu/include/cthulhu/ForceCleanable.h @@ -0,0 +1,18 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +namespace cthulhu { + +class ForceCleanable { + public: + virtual ~ForceCleanable() = default; + virtual inline void forceClean() { + force_clean_ = true; + } + + protected: + bool force_clean_ = false; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/Framework.h b/Cthulhu/include/cthulhu/Framework.h new file mode 100644 index 000000000..3690a15dc --- /dev/null +++ b/Cthulhu/include/cthulhu/Framework.h @@ -0,0 +1,122 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace cthulhu { + +struct FrameworkStorage; +class FrameworkInstance; + +class Framework { + public: + static Framework& instance(); + + // Non-copyable + Framework(const Framework&) = delete; + Framework& operator=(const Framework&) = delete; + + virtual ~Framework(); + + inline void cleanup(bool force = false, bool logging = true) { + if (force) { + if (clockManager_) { + clockManager_->forceClean(); + } + if (streamRegistry_) { + streamRegistry_->forceClean(); + } + if (memoryPool_) { + memoryPool_->forceClean(); + } + if (typeRegistry_) { + typeRegistry_->forceClean(); + } + if (contextRegistry_) { + contextRegistry_->forceClean(); + } + } + if (!logging) { + if (clockManager_) { + clockManager_->disableLogging(); + } + if (streamRegistry_) { + streamRegistry_->disableLogging(); + } + if (memoryPool_) { + memoryPool_->disableLogging(); + } + if (typeRegistry_) { + typeRegistry_->disableLogging(); + } + if (contextRegistry_) { + contextRegistry_->disableLogging(); + } + } + clockManager_.reset(); + streamRegistry_.reset(); + memoryPool_.reset(); + typeRegistry_.reset(); + contextRegistry_.reset(); + } + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(); + + // Throw an exception if the current framework is not valid + // + // Mostly internal check run during blocking sequences, but available for use by consumers + // if desired. + static void validate(); + + inline ClockManagerInterface* clockManager() { + return clockManager_.get(); + } + + inline MemoryPoolInterface* memoryPool() { + return memoryPool_.get(); + } + + inline StreamRegistryInterface* streamRegistry() { + return streamRegistry_.get(); + } + + inline TypeRegistryInterface* typeRegistry() { + return typeRegistry_.get(); + } + + inline ContextRegistryInterface* contextRegistry() { + return contextRegistry_.get(); + } + + protected: + std::shared_ptr clockManager_; + std::shared_ptr memoryPool_; + std::shared_ptr streamRegistry_; + std::shared_ptr typeRegistry_; + std::shared_ptr contextRegistry_; + + private: + Framework(); + + std::unique_ptr storage_; + + friend class FrameworkInstance; +}; + +struct FrameworkCleanedUpException : public std::exception {}; +struct MemoryPoolInvalidException : public std::exception {}; + +} // namespace cthulhu + +#include diff --git a/Cthulhu/include/cthulhu/FrameworkBase.h b/Cthulhu/include/cthulhu/FrameworkBase.h new file mode 100644 index 000000000..23b0d5ef3 --- /dev/null +++ b/Cthulhu/include/cthulhu/FrameworkBase.h @@ -0,0 +1,77 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +// On construction, registers a type in the Framework +template +class TypeLoader : public FieldObserver { + public: + TypeLoader(const std::string& typeName) { + // Create each type once to register its fields + sampleType sample; + configType config; + + TypeDefinition definition; + definition.typeName = typeName; + definition.sampleParameterSize = sample.getSize(); + definition.configParameterSize = config.getSize(); + definition.sampleNumberDynamicFields = sample.getDynamicFieldCount(); + definition.configNumberDynamicFields = config.getDynamicFieldCount(); + definition.sampleFields = fieldData(); + definition.configFields = fieldData(); + definition.hasContentBlock = hasContentBlock(); + definition.hasSamplesInContentBlock = hasFieldsInContentBlock(); + definition.sampleType = typeid(sampleType); + definition.configType = typeid(configType); + + Framework::instance().typeRegistry()->registerType(std::move(definition)); + }; +}; + +// On construction, registers a type in the Framework w/o a ConfigType +template +class TypeLoaderBasic : public FieldObserver { + public: + TypeLoaderBasic(const std::string& typeName) { + // Create each type once to register its fields + sampleType sample; + + TypeDefinition definition; + definition.typeName = typeName; + definition.sampleParameterSize = sample.getSize(); + definition.sampleNumberDynamicFields = sample.getDynamicFieldCount(); + definition.sampleFields = fieldData(); + definition.hasContentBlock = hasContentBlock(); + definition.hasSamplesInContentBlock = hasFieldsInContentBlock(); + definition.sampleType = typeid(sampleType); + + Framework::instance().typeRegistry()->registerType(std::move(definition)); + }; +}; + +// On construction, specifies the clock to be used by the framework. +// Before construction, requested clocks will return nullptr. +class ClockAuthority { + public: + // Use simTime to specify that simulated time will be used by the Framework. + // With simulated time, an owning Cthulhu context can and must control the + // clock. + ClockAuthority(bool simTime = false, const std::string& owner = "") { + Framework::instance().clockManager()->setClockAuthority(simTime, owner); + }; +}; + +} // namespace cthulhu + +#define CTHULHU_REGISTER_STREAM_TYPE(typeName, sampleType, configType) \ + cthulhu::FieldOffsets sampleType::offsets_; \ + cthulhu::FieldOffsets configType::offsets_; \ + cthulhu::TypeLoader typeName(#typeName); + +#define CTHULHU_REGISTER_BASIC_STREAM_TYPE(typeName, sampleType) \ + cthulhu::FieldOffsets sampleType::offsets_; \ + cthulhu::TypeLoaderBasic typeName(#typeName); diff --git a/Cthulhu/include/cthulhu/LogDisabling.h b/Cthulhu/include/cthulhu/LogDisabling.h new file mode 100644 index 000000000..544a5eaa1 --- /dev/null +++ b/Cthulhu/include/cthulhu/LogDisabling.h @@ -0,0 +1,18 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +namespace cthulhu { + +class LogDisabling { + public: + virtual ~LogDisabling() = default; + virtual inline void disableLogging() { + log_enabled_ = false; + } + + protected: + bool log_enabled_ = true; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/MemoryPoolInterface.h b/Cthulhu/include/cthulhu/MemoryPoolInterface.h new file mode 100644 index 000000000..39d29d850 --- /dev/null +++ b/Cthulhu/include/cthulhu/MemoryPoolInterface.h @@ -0,0 +1,37 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include +#include + +namespace cthulhu { + +class MemoryPoolInterface : public ForceCleanable, public LogDisabling { + public: + virtual ~MemoryPoolInterface() = default; + + // Provides thread-safe access to the Sample Pool + // A StreamID is provided, and the Framework transparently allocated a memory buffer from the + // appropriate pool (local or shared) based on stream linkages with other processes + virtual CpuBuffer getBufferFromPool(const StreamIDView& id, size_t nrBytes) = 0; + + // Equivalent to getBufferFromPool, but will request a GPU-backed buffer. + virtual GpuBuffer getGpuBufferFromPool(size_t nrBytes, bool device_local) = 0; + + // Returns true if the provided pointer could have been returned as a buffer from this + // memory pool. + virtual bool isBufferFromPool(const AnyBuffer& buf) const = 0; + + // signal all connected processes that this section is no longer valid + virtual void invalidate() = 0; + + // indicates whether this section is valid for use + virtual bool isValid() const = 0; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/PerformanceMonitor.h b/Cthulhu/include/cthulhu/PerformanceMonitor.h new file mode 100644 index 000000000..a9b6eb788 --- /dev/null +++ b/Cthulhu/include/cthulhu/PerformanceMonitor.h @@ -0,0 +1,37 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +namespace cthulhu { + +// PerformanceSummary holds the summary statistics computed by PerformanceMonitor. +struct PerformanceSummary { + std::optional> minRuntime; + std::optional> meanRuntime; + std::optional> maxRuntime; + std::chrono::duration totalRuntime; + uint64_t numCalls = 0; + uint64_t numSamplesDropped = 0; +}; + +// PerformanceMonitor provides a way to measure the timing of callbacks and update +// some rolling statistics on those timings. +struct PerformanceMonitor { + using ClockType = std::chrono::high_resolution_clock; + + void startMeasurement(); + void endMeasurement(); + void sampleDropped(); + PerformanceSummary getSummary(); + + private: + std::optional startTime_; + PerformanceSummary summary_; + std::mutex summaryMutex_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/QueueingAligner.h b/Cthulhu/include/cthulhu/QueueingAligner.h new file mode 100644 index 000000000..39838a4cd --- /dev/null +++ b/Cthulhu/include/cthulhu/QueueingAligner.h @@ -0,0 +1,37 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +class QueueingAligner : public AlignerBase { + public: + QueueingAligner(const float& outputRate); + virtual ~QueueingAligner(); + virtual void registerConsumer(StreamInterface* si, int index) override; + + protected: + virtual void align() override; + virtual void sampleCallback(size_t idx, const StreamSample& sample) override; + virtual bool configCallback(size_t idx, const StreamConfig& config) override; + + private: + float outputRate_; + + struct StreamQueue { + std::deque samples; + StreamConfig config; + bool hasConfig = false; + uint32_t latestSequence = 0; + std::unique_ptr consumer; + StreamID id; + }; + std::vector queues_; + std::mutex queueMutex_; + + bool configured_ = false; +}; // class QueueingAligner + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/RawDynamic.h b/Cthulhu/include/cthulhu/RawDynamic.h new file mode 100644 index 000000000..463ce5580 --- /dev/null +++ b/Cthulhu/include/cthulhu/RawDynamic.h @@ -0,0 +1,118 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +#include + +namespace cthulhu { + +// RawDynamic is a generic holder around dynamically-sized data. +// The data may be viewed as any vector of T, or as a string view. +// RawDynamic remembers a variant of the element type by tracking +// the element size. +// +// RawDynamic is templated over the raw memory representation. By +// default, it's a shared pointer. RawDynamic may be templated with +// an IPC smart pointer variant. +template +class RawDynamic { + public: + RawDynamic() = default; + RawDynamic(RawDynamic&&) = default; + RawDynamic& operator=(RawDynamic&&) = default; + RawDynamic(const RawDynamic&) = default; + RawDynamic& operator=(const RawDynamic&) = default; + + // Note: ctor only valid for CpuBuffer Raw type argument + template + explicit RawDynamic(const std::vector& vec) + : elementCount(vec.size()), elementSize(sizeof(T)), raw(getBuffer()) { + static_assert(std::is_pod_v, "RawDynamic will only work well with POD elements!"); + std::memcpy(raw.get(), vec.data(), size()); + } + + // Note: ctor only valid for CpuBuffer Raw type argument + explicit RawDynamic( + std::string_view str, + size_t elementSize = sizeof(std::string_view::value_type)) + : elementCount(str.size() / elementSize), elementSize(elementSize), raw(getBuffer()) { + std::memcpy(raw.get(), str.data(), size()); + } + + // Note: ctor only valid for CpuBuffer Raw type argument + explicit RawDynamic(CpuBuffer& buf, size_t count); + + inline size_t size() const { + return elementCount * elementSize; + } + + // Returns a string view of the memory, regardless of whether or not the raw dynamic + // was constructed with a string. + const std::string_view asString() const { + return std::string_view(reinterpret_cast(raw.get()), size()); + } + + // Returns a copy of the data represented as a vector of Ts. + template + std::vector copyAs() const { + const T* begin = reinterpret_cast(raw.get()); + const T* end = begin + (size() / sizeof(T)); + return std::vector(begin, end); + } + + friend bool operator==(const RawDynamic& lhs, const RawDynamic& rhs) { + if ((nullptr == lhs.raw) && (nullptr == rhs.raw)) { + return true; + } + return lhs.raw && rhs.raw && (lhs.elementCount == rhs.elementCount) && + (lhs.elementSize == rhs.elementSize) && + (0 == std::memcmp(lhs.raw.get(), rhs.raw.get(), lhs.size())); + } + + friend bool operator!=(const RawDynamic& lhs, const RawDynamic& rhs) { + return !(lhs == rhs); + } + + explicit operator bool() const { + return (nullptr != raw); + } + + // Courtesy of Jo Boccara + // https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ + // + // I'm hiding this clone() function when we're not using a standard CpuBuffer as + // the backing memory because we don't have a way to use the correct allocator otherwise. + template >> + RawDynamic clone() const { + RawDynamic copy; + copy.elementCount = elementCount; + copy.elementSize = elementSize; + copy.raw = getBuffer(); + std::memcpy(copy.raw.get(), raw.get(), size()); + + return copy; + } + + // Total number of elements of the raw data + size_t elementCount = 0; + // Single element size of the raw data + size_t elementSize = 0; + // The raw data + Raw raw; + + private: + CpuBuffer getBuffer() const; +}; + +using SharedRawDynamicArray = std::shared_ptr>; +static inline SharedRawDynamicArray makeSharedRawDynamicArray(size_t count) { + return std::shared_ptr>( + new RawDynamic<>[count](), std::default_delete[]>()); +} + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/Serialization.h b/Cthulhu/include/cthulhu/Serialization.h new file mode 100644 index 000000000..c8245f873 --- /dev/null +++ b/Cthulhu/include/cthulhu/Serialization.h @@ -0,0 +1,228 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#include + +#include + +#include + +namespace cthulhu { + +namespace details { +void serializeDynamicFields( + const SharedRawDynamicArray& dynamicParameters, + int numDynFields, + int& offset, + uint8_t* result); + +void deserializeDynamicFields( + SharedRawDynamicArray& dynamicParameters, + int numDynFields, + int& offset, + const uint8_t* source); +} // namespace details + +/** + * Compute a checksum for a type definition, based on its sample type. + * The checksum can be used to validate across processes/machines that the + * layout for a given type matches. + * Returns -1 on failure, otherwise returns the checksum. + */ +template +int typeChecksum() { + auto sampleTypeInfo = Framework::instance().typeRegistry()->findSampleType(typeid(SampleType)); + if (!sampleTypeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't compute checksum for type info, failed to find sample type in registry: ", + typeid(SampleType).name()); + return -1; + } + + std::stringstream ss; + ss << sampleTypeInfo->typeName(); + ss << sampleTypeInfo->isBasic(); + ss << sampleTypeInfo->hasContentBlock(); + ss << sampleTypeInfo->hasSamplesInContentBlock(); + + auto addFields = [&ss](const FieldData& fields) -> void { + for (const auto& field : fields) { + ss << field.first; + ss << field.second.offset; + ss << field.second.size; + ss << field.second.typeName; + ss << field.second.numElements; + ss << field.second.isDynamic; + } + }; + + addFields(sampleTypeInfo->configFields()); + addFields(sampleTypeInfo->sampleFields()); + + boost::crc_32_type result; + result.process_bytes(ss.str().data(), ss.str().length()); + + return result.checksum(); +} + +/** + * Serialize a Stream Config into a flat array of bytes + */ +std::vector serializeConfig(const std::string& typeName, const StreamConfig& config); + +/** + * Serialize a Stream Config into a flat array of bytes + */ +template +std::vector serializeConfig(const ConfigType& config) { + auto typeInfo = Framework::instance().typeRegistry()->findConfigType(typeid(ConfigType)); + if (!typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't serialize config, failed to find type in registry: ", + typeid(ConfigType).name()); + return std::vector{}; + } + + return serializeConfig(typeInfo->typeName(), config.getConfig()); +} + +/** + * Deserialize a Stream Config from a flat array of bytes + */ +StreamConfig deserializeConfig(const std::string& typeName, const uint8_t* config); + +inline StreamConfig deserializeConfig( + const std::string& typeName, + const std::vector& config) { + return deserializeConfig(typeName, config.data()); +} + +/** + * Deserialize a Stream Config from a flat array of bytes + */ +template +ConfigType deserializeConfig(const std::vector& config) { + auto typeInfo = Framework::instance().typeRegistry()->findConfigType(typeid(ConfigType)); + if (!typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't deserialize config, failed to find type in registry: ", + typeid(ConfigType).name()); + return ConfigType(); + } + + return deserializeConfig(typeInfo->typeName(), config); +} + +/** + * Serialize a Stream Sample into a flat array of bytes, using the current Config for non-basic + * streams. + */ +std::vector serializeSample( + const std::string& typeName, + const StreamSample& sample, + const StreamConfig* const config = nullptr); + +/** + * Serialize a Stream Sample into a flat array of bytes, using the current Config for non-basic + * streams. + */ +template +std::vector serializeSample( + const SampleType& sample, + const ConfigType* const config = nullptr) { + std::vector result; + auto typeInfo = Framework::instance().typeRegistry()->findSampleType(typeid(SampleType)); + if (!typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't serialize sample, failed to find type in registry: ", + typeid(SampleType).name()); + return result; + } + + if (!typeInfo->isBasic()) { + if (!config) { + XR_LOGCE( + "Cthulhu", + "Couldn't serialize sample for non-basic type without a corresponding config: ", + typeid(SampleType).name()); + return result; + } + auto configTypeInfo = Framework::instance().typeRegistry()->findConfigType(typeid(ConfigType)); + if (configTypeInfo != typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't serialize sample for with non-matching config. Sample type was: ", + typeid(SampleType).name()); + return result; + } + } + + const StreamConfig* streamConfigPtr = nullptr; + if constexpr (!std::is_same_v) { + streamConfigPtr = (config ? &config->getConfig() : nullptr); + } + return serializeSample(typeInfo->typeName(), sample.getSample(), streamConfigPtr); +} + +/** + * Deserialize a Stream Sample from a flat array of bytes, using the current Config for non-basic + * streams. + */ +StreamSample deserializeSample( + const std::string& typeName, + const uint8_t* sample, + const StreamConfig* const config = nullptr); + +inline StreamSample deserializeSample( + const std::string& typeName, + const std::vector& sample, + const StreamConfig* const config = nullptr) { + return deserializeSample(typeName, sample.data(), config); +} + +/** + * Deserialize a Stream Sample from a flat array of bytes, using the current Config for non-basic + * streams. + */ +template +SampleType deserializeSample( + const std::vector& sample, + const ConfigType* const config = nullptr) { + SampleType result; + auto typeInfo = Framework::instance().typeRegistry()->findSampleType(typeid(SampleType)); + if (!typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't deserialize sample, failed to find type in registry: ", + typeid(SampleType).name()); + return result; + } + + if (!typeInfo->isBasic()) { + auto configTypeInfo = Framework::instance().typeRegistry()->findConfigType(typeid(ConfigType)); + if (configTypeInfo != typeInfo) { + XR_LOGCE( + "Cthulhu", + "Couldn't deserialize sample for with non-matching config. Sample type was: ", + typeid(SampleType).name()); + return result; + } + } + + const StreamConfig* streamConfigPtr = nullptr; + if constexpr (!std::is_same_v) { + streamConfigPtr = (config ? &config->getConfig() : nullptr); + } + + return deserializeSample(typeInfo->typeName(), sample, streamConfigPtr); +} + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/StreamConfigEquality.h b/Cthulhu/include/cthulhu/StreamConfigEquality.h new file mode 100644 index 000000000..854c6bd3d --- /dev/null +++ b/Cthulhu/include/cthulhu/StreamConfigEquality.h @@ -0,0 +1,17 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace cthulhu { + +// Returns whether two StreamConfigs are equal given the type information of the stream associated +// with the config type that these StreamConfigs back. +bool streamConfigsEqual( + const StreamConfig& lhs, + const StreamConfig& rhs, + const TypeInfoInterface& stream_type_info); + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/StreamInterface.h b/Cthulhu/include/cthulhu/StreamInterface.h new file mode 100644 index 000000000..acdcd8631 --- /dev/null +++ b/Cthulhu/include/cthulhu/StreamInterface.h @@ -0,0 +1,329 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace cthulhu { + +// StreamID is a string identifier that uniquely identifies a Stream +using StreamID = std::string; + +// We started work on Cthulhu before we had C++17. We maintained our own +// lightweight version of std::string_view, called StreamIDView. But, now +// that we have C++17, and we've used the features throughout Cthulhu, it +// makes sense for us to use std::string_view. +using StreamIDView = std::string_view; + +// A description of a stream holds both the StreamID and a type enum. +// These are used by the Framework's internal API when requesting a Stream from the Registry. +// When the Framework constructs a StreamInterface in the Registry, the Description will be passed +// to it, and it will be owned by the StreamInterface. There should only be two StreamID instances +// in the system: 1: the mapping in the Registry and 2: the Description held by the StreamInterface. +// All other usages should be SteamIDView's derived from this Description. +// For this reason, the StreamID and type can never be modified. +class StreamDescription { + private: + const StreamID id_; + const uint32_t type_; + + public: + // Construct from a StreamID and a type + StreamDescription(const StreamID& id, uint32_t type) : id_(id), type_(type){}; + + // Get a read-only StreamID + inline const StreamID& id() const { + return id_; + }; + + // Get a read-only type + inline const uint32_t& type() const { + return type_; + }; +}; + +// This is a header providing the basic metadata associated with a sample. +struct SampleHeader { + double timestamp; + uint32_t sequenceNumber; +}; + +// This is an additional header providing processing timing of Nodes in producing a Sample. +// It should only be auto-populated by the Framework +using ProcessingStamps = std::map; + +struct SampleMetadata; + +using SampleHistory = std::map>; + +// The full metadata contains the sample header, processing stamps, and history pointers +// to the metadata of input samples. These pointers can be traced to obtain a full history +// of information that went into producing the sample, as well as the processing timing. +struct SampleMetadata { + // Basic metadata + SampleHeader header; + + // User-determined processing stamps + ProcessingStamps processingStamps; + + // Pointers to metadata from ancestors + SampleHistory history; +}; + +// A Stream Sample contains metadata and a payload. +// Both are to be created by buffers from the Sample Pool +struct StreamSample { + StreamSample(); + + // The full historical metadata of the sample + std::shared_ptr metadata; + + // This is the bulk content block data. Can be CPU or GPU. + AnyBuffer payload; + // This specifies how many repeating subsamples are represented within the content block + uint32_t numberOfSubSamples = 0; + + // This carries any lighter-weight data fields + CpuBuffer parameters; + + // This carries any dynamically-sized parameters + SharedRawDynamicArray dynamicParameters; +}; + +// When adding new fields to StreamConfig, make sure to modify StreamConfigEquality.h/.cpp +struct StreamConfig { + StreamConfig() = default; + StreamConfig(CpuBuffer parameterData) : parameters(parameterData) {} + StreamConfig(size_t staticFieldSize, size_t dynamicFieldSize) { + if (staticFieldSize > 0) { + parameters = CpuBuffer(new uint8_t[staticFieldSize](), std::default_delete()); + } + if (dynamicFieldSize > 0) { + dynamicParameters = makeSharedRawDynamicArray(dynamicFieldSize); + } + } + + double nominalSampleRate = 0.0; + uint32_t sampleSizeInBytes = 1; + + // This carries customizable data fields + CpuBuffer parameters; + + // This carries any dynamically-sized parameters + SharedRawDynamicArray dynamicParameters; +}; + +using SampleCallback = std::function; +using ConfigCallback = std::function; + +struct DataVariant { + enum class Type { SAMPLE, CONFIG, INVALID } type = Type::INVALID; + StreamSample sample; + StreamConfig config; +}; + +// Forward Declaration +class StreamInterface; + +// This is the interface to be used for producing signals on a stream. +// It is constructed with a pointer to a StreamInterface which lives in the Stream +// Registry and thus has process lifetime. It will hook-in to the stream interface as +// the producer, which will fail if the StreamInterface already has a producer. Ownership +// of this producer will be transferred from the Context to a created Node (Publisher or +// Transformer) +class StreamProducer { + public: + // Attempts to hook into the StreamInterface + explicit StreamProducer(StreamInterface* si, bool async = false); + + // Unhook's from the StreamInterface (if it was hooked successfully on construction) + virtual ~StreamProducer(); + + // These are the signals that can be sent to the StreamInterface + + // This sends a sample to active Consumers + void produceSample(const StreamSample& sample) const; + + // Configuration will move the StreamConfig onto the interface, which + // will be provided to active Consumers, or eventually hooked Consumers + void configureStream(const StreamConfig& config) const; + + // This gets the current configuration for the stream + const StreamConfig* config() const; + + // This will return false if the Producer was constructed on a Stream with an existing Producer + inline bool isActive() const { + return producedStream_ != nullptr; + }; + + protected: + StreamInterface* producedStream_ = nullptr; + + bool async_; + + std::thread thread_; + std::promise stopSignal_; + mutable std::mutex queueMutex_; + mutable std::queue queue_; + static constexpr int MAX_QUEUE_SIZE = 100; +}; + +// This is the interface to be used for consuming signals on a stream. +// It is constructed with a pointer to a StreamInterface which lives in the Stream +// Registry and thus has process lifetime. It will hook-in to the StreamInterface as a +// consumer, which will never fail (no limit on the number of consumers on a stream). The callback +// function for each signal must be specified on construction. Only the SampleCallback is required. +// The public signal receive functions shall be called by the StreamInterface that was hooked. +class StreamConsumer { + public: + // Hooks into the StreamInterface and stores callbacks + explicit StreamConsumer( + StreamInterface* si, + SampleCallback callback, + ConfigCallback configCallback = nullptr, + bool async = false); + + // Unhooks from the StreamInterface + virtual ~StreamConsumer(); + + // These are the signals that can be received from the StreamInterface + + // Calls the sample callback + void consumeSample(const StreamSample& sample) const; + + // Calls the configuration callback (if set). If one already exists on the stream, + // it will be immediately called on hookConsumer (in the constructor). The configCallback_ + // is set in the initializer list prior to hookConsumer, so this is just fine. + void receiveConfig(const StreamConfig& config) const; + + PerformanceSummary getPerformanceSummary() const; + + uint64_t getQueueCapacity() const; + void setQueueCapacity(uint64_t capacity); + + protected: + StreamInterface* consumedStream_ = nullptr; + SampleCallback callback_; + ConfigCallback configCallback_; + + mutable bool inhibitSampleCallback_ = false; + + bool async_; + + std::thread thread_; + std::promise stopSignal_; + mutable PerformanceMonitor performanceMonitor_; + mutable std::mutex queueMutex_; + mutable std::queue queue_; + uint64_t queueCapacity_; + static constexpr uint64_t DEFAULT_QUEUE_CAPACITY = 10; +}; + +// This is the interface used to represent a stream. A single instance for each stream lives in the +// Stream Registry within a process. Producers/Consumers and constructed that hook-in to the stream, +// and Producers call a set of signal interface functions. These signal functions pass the signal on +// to all hooked-in Consumers. Signals and hooks are locked and thread-safe, so new references can +// be hooked-in concurrently with signaling. +class StreamInterface { + public: + // Constructs given a description, which cannot be changed + explicit StreamInterface(const StreamDescription& desc) : description_(desc){}; + // This won't have ownership of any of the hooked producers or consumers. But it + // only exists in the Singleton Registry, so it will live longer than any of them + virtual ~StreamInterface() = default; + + // Gets the read-only description + inline const StreamDescription& description() const { + return description_; + }; + + // Sets the paused flag to on/off + inline void setPaused(bool paused) { + paused_ = paused; + }; + + // Non-copyable. Only one should exist, sitting in the Registry + StreamInterface(const StreamInterface& other) = delete; + StreamInterface& operator=(const StreamInterface& other) = delete; + + // Move-constructable, only for insertion into the Registry + StreamInterface(StreamInterface&& other) + : description_(other.description_), config_(other.config_), paused_(other.paused_) { + std::lock_guard lock(other.timed_mutex_); + producer_ = std::move(other.producer_); + consumers_ = std::move(other.consumers_); + }; + // Non move assignable, shouldn't be needed + StreamInterface& operator=(StreamInterface&& other) = delete; + + const StreamProducer* producer() const { + return producer_; + }; + const std::vector consumers() const { + return consumers_; + }; + + const StreamConfig& config() const { + return config_; + }; + + inline bool isConfigured() const { + return configured_; + }; + + protected: + // Signal interfaces, should only be called by the producer + // These lock the mutex to ensure that consumers are not hooked/unhooked while sending signals. + // Additional signals can be added, along with flavors of Producer/Consumer that can use them + virtual bool sendSample(const StreamSample& sample) = 0; + virtual bool configure(const StreamConfig& config) = 0; + + // Hook, unhook functions, should only be called by Producer/Consumer constructors/destructors + // These lock the mutex to modify the set of consumers and producer + virtual bool hookProducer(const StreamProducer* const producer) = 0; + virtual void hookConsumer(const StreamConsumer* const consumer) = 0; + virtual void removeProducer(const StreamProducer* const producer) = 0; + virtual void removeConsumer(const StreamConsumer* const consumer) = 0; + + const StreamDescription description_; + + // The latest config sits on the interface, so it can be pushed to any new Consumers + StreamConfig config_; + + // This holds the reference to the producer, so it knows who is responsible for sending signals. + const StreamProducer* producer_ = nullptr; + + // This holders the references to all consumers, so it knows where to send signals + std::vector consumers_; + + // Used to lock the producer/consumers + // Timed to allow timeouts during IPC deadlocks + mutable std::timed_mutex timed_mutex_; + + // Flag for whether to inhibit signals, not locked by mutex. Defaults to non-paused + bool paused_ = false; + + bool configured_ = false; + + // Friend these classes to restrict hook/unhook and signaling APIs + friend class StreamProducer; + friend class StreamConsumer; +}; // class StreamInterface + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/StreamRegistryInterface.h b/Cthulhu/include/cthulhu/StreamRegistryInterface.h new file mode 100644 index 000000000..a9d2c709e --- /dev/null +++ b/Cthulhu/include/cthulhu/StreamRegistryInterface.h @@ -0,0 +1,32 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +namespace cthulhu { + +class StreamRegistryInterface : public ForceCleanable, public LogDisabling { + public: + virtual ~StreamRegistryInterface() = default; + + // Provides access to the Stream Registry + // A description is provided. If the stream does not exist, it constructs + // one in the registry and provides a pointer to it. If the stream exists, + // a pointer to the existing is returned. This function is thread-safe. + virtual StreamInterface* registerStream(const StreamDescription& desc) = 0; + + // Provides read-only access to the Stream Registry + // Returns nullptr if the requested stream does not exist + virtual StreamInterface* getStream(const StreamID& id) = 0; + + // Other Functionality to expose + virtual void printStreamInfo() const {} + + // Function for getting all registered StreamID's for a type + virtual std::vector streamsOfTypeID(uint32_t typeID) const = 0; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/StreamType.h b/Cthulhu/include/cthulhu/StreamType.h new file mode 100644 index 000000000..76f70a9ee --- /dev/null +++ b/Cthulhu/include/cthulhu/StreamType.h @@ -0,0 +1,686 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace cthulhu { + +class AutoStreamConfig; +class AutoStreamSample; + +// These base classes allow data accessors to perform non-const access +// to the underlying data for set functions. +class ConfigAccessor { + protected: + StreamConfig& config(AutoStreamConfig* wrapper); +}; + +class SampleAccessor { + protected: + StreamSample& sample(AutoStreamSample* wrapper); +}; + +class SampleSize : public ConfigAccessor { + public: + SampleSize(AutoStreamConfig* wrapper); + + uint32_t get() const; + + operator const uint32_t&() const; + + void set(const uint32_t& value); + + SampleSize& operator=(const uint32_t& value); + + SampleSize(const SampleSize&) = delete; + SampleSize& operator=(const SampleSize&) = delete; + + private: + AutoStreamConfig* wrapper_; +}; + +class AutoStreamConfig { + public: + cthulhu::SampleSize sampleSizeInBytes{this}; + + // This function will be called to auto-update sampleSizeInBytes every time any field + // is updated + virtual uint32_t computeSampleSize() const { + return 0; + }; + + const StreamConfig& getConfig() const; + + void setConfig(const StreamConfig& config); + + // No copies + AutoStreamConfig(const AutoStreamConfig& other) = delete; + AutoStreamConfig& operator=(const AutoStreamConfig& other) = delete; + AutoStreamConfig(AutoStreamConfig&& other) = delete; + AutoStreamConfig& operator=(AutoStreamConfig&& other) = delete; + + virtual ~AutoStreamConfig(); + + protected: + // Do not use; construct your AutoStreamConfig subclass instead. + explicit AutoStreamConfig(size_t staticFieldSize, size_t dynamicFieldSize); + explicit AutoStreamConfig(const StreamConfig& config); + + StreamConfig config_; + friend class ConfigAccessor; +}; + +class AutoStreamSample { + public: + AutoStreamSample(const AutoStreamSample& other) = delete; + AutoStreamSample& operator=(const AutoStreamSample& other) = delete; + + virtual ~AutoStreamSample(); + + const StreamSample& getSample() const; + + void setSample(const StreamSample& sample); + + protected: + // Do not use; construct a AutoStreamSample subclass instead. + explicit AutoStreamSample(size_t size, size_t numberDynamicFields); + AutoStreamSample(const StreamSample& sample, size_t size, size_t numberDynamicFields); + + StreamSample sample_; + friend class SampleAccessor; +}; + +namespace details { +// Type tag for a POD type in a config field. These are allocated in the parameters block and have +// normal field descriptors +struct pod_type {}; +// Type tag for dynamically-sized config field data. These are allocated on the free store, +// accessible by the StreamConfig itself. They're managed behind a RawDynamic. +struct dynamic_type {}; + +template +struct dynamic_parameters; + +template <> +struct dynamic_parameters { + static auto get(AutoStreamConfig* wrapper) + -> decltype(wrapper->getConfig().dynamicParameters.get()) { + return wrapper->getConfig().dynamicParameters.get(); + } +}; + +template <> +struct dynamic_parameters { + static auto get(AutoStreamSample* wrapper) + -> decltype(wrapper->getSample().dynamicParameters.get()) { + return wrapper->getSample().dynamicParameters.get(); + } +}; + +// The DynamicConfigField is specialized for dynamically-sized types. +// See the specializations below for more information. +template +class DynamicField; + +// DynamicFields for strings. +// Inputs: const std::string_view +// Outputs: const std::string_view which reference the underlying memory +template +class DynamicField { + public: + DynamicField(const std::string& fieldName, Wrapper* wrapper) + : fieldOffset_(Base::template registerField(fieldName, details::dynamic_type())), + wrapper_(wrapper) {} + + DynamicField& operator=(const DynamicField&) = delete; + + const std::string_view get() const { + const RawDynamic<>& rawDynamic = *(dynamic_parameters::get(wrapper_) + fieldOffset_); + return rawDynamic.asString(); + } + + size_t size() const { + const RawDynamic<>& rawDynamic = *(dynamic_parameters::get(wrapper_) + fieldOffset_); + return rawDynamic.size(); + } + + char* ptr() { + return reinterpret_cast( + (dynamic_parameters::get(wrapper_) + fieldOffset_)->raw.get()); + } + + void set(const std::string_view str) { + *(dynamic_parameters::get(wrapper_) + fieldOffset_) = + (str.empty()) ? RawDynamic<>() : RawDynamic<>(str); + } + + void setPtr(std::shared_ptr& ptr, size_t count) { + *(dynamic_parameters::get(wrapper_) + fieldOffset_) = RawDynamic<>(ptr, count); + } + + operator const std::string_view() const { + return get(); + } + + DynamicField& operator=(const std::string_view str) { + set(str); + return *this; + } + + bool operator==(const DynamicField& that) const { + return (this->get()) == (that.get()); + } + + bool operator!=(const DynamicField& that) const { + return !(this->operator==(that)); + } + + private: + size_t fieldOffset_; + Wrapper* wrapper_; +}; + +// DynamicFields for vectors. +// Inputs: const std::vector& +// Outputs: std::vector which copies the underlying memory +template +class DynamicField, Base, Wrapper> { + public: + DynamicField(const std::string& fieldName, Wrapper* wrapper) + : fieldOffset_( + Base::template registerField>(fieldName, details::dynamic_type())), + wrapper_(wrapper) {} + + DynamicField& operator=(const DynamicField&) = delete; + + std::vector get() const { + const RawDynamic<>& rawDynamic = *(dynamic_parameters::get(wrapper_) + fieldOffset_); + return rawDynamic.template copyAs(); + } + + size_t size() const { + const RawDynamic<>& rawDynamic = *(dynamic_parameters::get(wrapper_) + fieldOffset_); + return rawDynamic.size() / sizeof(T); + } + + T* ptr() { + return reinterpret_cast( + (dynamic_parameters::get(wrapper_) + fieldOffset_)->raw.get()); + } + + const T* ptr() const { + return reinterpret_cast( + (dynamic_parameters::get(wrapper_) + fieldOffset_)->raw.get()); + } + + void set(const std::vector& vec) { + *(dynamic_parameters::get(wrapper_) + fieldOffset_) = + (vec.empty()) ? RawDynamic<>() : RawDynamic<>(vec); + } + + void setPtr(std::shared_ptr& ptr, size_t count) { + *(dynamic_parameters::get(wrapper_) + fieldOffset_) = RawDynamic<>(ptr, count); + } + + operator std::vector() const { + return get(); + } + + DynamicField& operator=(const std::vector& vec) { + set(vec); + return *this; + } + + bool operator==(const DynamicField, Base, Wrapper>& other) const { + // Don't compare get()s, since it allocates + const auto& lhs = *(dynamic_parameters::get(this->wrapper_) + this->fieldOffset_); + const auto& rhs = *(dynamic_parameters::get(other.wrapper_) + other.fieldOffset_); + return (lhs == rhs); + } + + bool operator!=(const DynamicField, Base, Wrapper>& that) const { + return !(this->operator==(that)); + } + + private: + size_t fieldOffset_; + Wrapper* wrapper_; +}; + +template +struct element_of { + using type = T; +}; + +template +struct element_of> { + using type = T; +}; + +template +struct element_of { + using type = T; +}; + +template +using element_of_t = typename element_of::type; + +} // namespace details + +template +using DynamicConfigField = details::DynamicField; + +template +using DynamicSampleField = details::DynamicField; + +template +class ConfigField : public ConfigAccessor { + static_assert( + std::is_pod_v, + "ConfigField only works for POD types; try DynamicConfigField for something fancier"); + + public: + ConfigField(const std::string& fieldName, AutoStreamConfig* wrapper) + : fieldOffset_(Base::template registerField(fieldName, details::pod_type())), + wrapper_(wrapper) {} + + const T& get() const { + return *reinterpret_cast(wrapper_->getConfig().parameters.get() + fieldOffset_); + } + + operator const T&() const { + return get(); + } + + void set(const T& value) { + *reinterpret_cast(config(wrapper_).parameters.get() + fieldOffset_) = value; + config(wrapper_).sampleSizeInBytes = wrapper_->computeSampleSize(); + } + + ConfigField& operator=(const T& value) { + set(value); + return *this; + } + + bool operator==(const ConfigField& that) const { + return (this->get()) == (that.get()); + } + + bool operator!=(const ConfigField& that) const { + return !(this->operator==(that)); + } + + details::element_of_t* ptr() { + return reinterpret_cast*>( + wrapper_->getConfig().parameters.get() + fieldOffset_); + } + + const details::element_of_t* ptr() const { + return reinterpret_cast*>( + wrapper_->getConfig().parameters.get() + fieldOffset_); + } + + private: + size_t fieldOffset_; + AutoStreamConfig* wrapper_; +}; + +class SampleRate : public ConfigAccessor { + public: + SampleRate(AutoStreamConfig* wrapper); + + const double& get() const; + + operator const double&() const; + + void set(const double& value); + + SampleRate& operator=(const double& value); + + SampleRate& operator=(const SampleRate&) = delete; + SampleRate(const SampleRate&) = delete; + + private: + AutoStreamConfig* wrapper_; +}; + +template +class ContentBlock; + +template +class SampleField : public SampleAccessor { + static_assert(std::is_pod_v, "SampleField only works for POD types!"); + + public: + SampleField(const std::string& fieldName, AutoStreamSample* wrapper) + : fieldOffset_(Base::template registerField(fieldName, details::pod_type())), + wrapper_(wrapper), + block_(nullptr), + type_(typeid(T)) {} + + // Overload signals that this sample field resides in a content block + SampleField(const std::string& fieldName, const ContentBlock& block) + : fieldOffset_(Base::template registerField(fieldName, details::pod_type())), + wrapper_(nullptr), + block_(&block), + type_(typeid(T)) { + Base::samplesInContentBlock(); + } + + const T& get() const { + return *reinterpret_cast(accessor(0) + fieldOffset_); + } + + operator const T&() const { + return *reinterpret_cast(accessor(0) + fieldOffset_); + } + + void set(const T& value) { + *reinterpret_cast(accessor(0) + fieldOffset_) = value; + } + + SampleField& operator=(const T& value) { + *reinterpret_cast(accessor(0) + fieldOffset_) = value; + return *this; + } + + const T& operator[](size_t idx) const { + if (!block_) + throw std::logic_error("Do not use element access for non-SFoCB types"); + else if (idx >= block_->numberSubSamples()) + throw std::out_of_range("SampleField element access out of range"); + return *reinterpret_cast(accessor(idx) + fieldOffset_); + } + + T& operator[](size_t idx) { + if (!block_) + throw std::logic_error("Do not use element access for non-SFoCB types"); + else if (idx >= block_->numberSubSamples()) + throw std::out_of_range("SampleField element access out of range"); + return *reinterpret_cast(accessor(idx) + fieldOffset_); + } + + details::element_of_t* ptr() { + return reinterpret_cast*>(accessor(0) + fieldOffset_); + } + + const details::element_of_t* ptr() const { + return reinterpret_cast*>(accessor(0) + fieldOffset_); + } + + private: + uint8_t* accessor(size_t batch) const { + if (block_) { + return ((CpuBuffer)block_->get()).get() + (batch * Base::getSize()); + } else { + return wrapper_->getSample().parameters.get(); + } + } + + size_t fieldOffset_; + // Pointers are mutually exclusive + AutoStreamSample* wrapper_ = nullptr; + const ContentBlock* block_ = nullptr; + std::type_index type_; +}; + +class HeaderTimestamp : public SampleAccessor { + public: + HeaderTimestamp(AutoStreamSample* wrapper); + + const double& get() const; + + operator const double&() const; + + void set(const double& value); + + HeaderTimestamp& operator=(const double& value); + + HeaderTimestamp& operator=(const HeaderTimestamp&) = delete; + HeaderTimestamp(const HeaderTimestamp&) = delete; + + private: + AutoStreamSample* wrapper_; +}; + +class HeaderSequence : public SampleAccessor { + public: + HeaderSequence(AutoStreamSample* wrapper); + + uint32_t get() const; + + operator const uint32_t&() const; + + void set(const uint32_t& value); + + HeaderSequence& operator=(const uint32_t& value); + + HeaderSequence& operator=(const HeaderSequence&) = delete; + HeaderSequence(const HeaderSequence&) = delete; + + private: + AutoStreamSample* wrapper_; +}; + +class ProcessingTimestamp : public SampleAccessor { + public: + ProcessingTimestamp(const std::string& stampName, AutoStreamSample* wrapper); + + const double& get() const; + + operator const double&() const; + + void set(const double& value); + + ProcessingTimestamp& operator=(const double& value); + + ProcessingTimestamp& operator=(const ProcessingTimestamp&) = delete; + ProcessingTimestamp(const ProcessingTimestamp&) = delete; + + private: + const std::string stampName_; + AutoStreamSample* wrapper_; +}; + +template +class ContentBlock : public SampleAccessor { + public: + ContentBlock(AutoStreamSample* wrapper) { + wrapper_ = wrapper; + Base::registerContent(); + } + + const AnyBuffer& get() const { + return wrapper_->getSample().payload; + } + + operator const AnyBuffer&() const { + return wrapper_->getSample().payload; + } + + void set(const AnyBuffer& value, uint32_t numberSubSamples = 1) { + sample(wrapper_).payload = value; + sample(wrapper_).numberOfSubSamples = numberSubSamples; + } + + ContentBlock& operator=(const AnyBuffer& value) { + sample(wrapper_).payload = value; + return *this; + } + + const uint32_t& numberSubSamples() const { + return wrapper_->getSample().numberOfSubSamples; + } + + void setNumberSubSamples(uint32_t numberSubSamples) { + sample(wrapper_).numberOfSubSamples = numberSubSamples; + } + + private: + AutoStreamSample* wrapper_; +}; + +template +class FieldsBegin { + public: + FieldsBegin() { + if (Base::offsets_.ready) { + return; + } + Base::offsets_.lock.lock(); + if (Base::offsets_.ready) { + Base::offsets_.lock.unlock(); + } + } +}; + +template +class FieldsEnd { + public: + FieldsEnd() { + if (Base::offsets_.ready) { + return; + } + Base::offsets_.ready = true; + Base::offsets_.lock.unlock(); + } +}; + +class FieldObserver { + protected: + template + static FieldData fieldData() { + return Type::offsets_.data; + } + template + bool hasContentBlock() { + return Type::offsets_.hasContentBlock; + } + template + bool hasFieldsInContentBlock() { + return Type::offsets_.hasSamplesInContentBlock; + } +}; + +struct FieldOffsets { + FieldOffsets() : ready(false), hasContentBlock(false), hasSamplesInContentBlock(false) {} + std::atomic ready; + std::atomic hasContentBlock; + std::atomic hasSamplesInContentBlock; + + std::mutex lock; + size_t currentOffset = 0; + size_t currentDynamicOffset = 0; + FieldData data; +}; + +#define CTHULHU_AUTOSTREAM_REGISTER_FIELD(Type) \ + template \ + static size_t registerField(const std::string& fieldName, ::cthulhu::details::pod_type) { \ + if (offsets_.ready) { \ + return offsets_.data[fieldName].offset; \ + } \ + offsets_.data[fieldName].isDynamic = false; \ + offsets_.data[fieldName].offset = offsets_.currentOffset; \ + offsets_.data[fieldName].size = sizeof(fieldType); \ + static_assert(std::is_pod::value, "Cthulhu field must be POD"); \ + offsets_.data[fieldName].typeName = cthulhu::typeName(); \ + offsets_.data[fieldName].numElements = cthulhu::typeSize(); \ + offsets_.currentOffset += sizeof(fieldType); \ + return offsets_.data[fieldName].offset; \ + }; \ + \ + template \ + static size_t registerField(const std::string& fieldName, ::cthulhu::details::dynamic_type) { \ + if (!offsets_.ready) { \ + offsets_.data[fieldName].isDynamic = true; \ + offsets_.data[fieldName].offset = offsets_.currentDynamicOffset; \ + ++offsets_.currentDynamicOffset; \ + offsets_.data[fieldName].typeName = cthulhu::typeName(); \ + offsets_.data[fieldName].size = sizeof(typename fieldType::value_type); \ + } \ + return offsets_.data[fieldName].offset; \ + } \ + \ + private: \ + static cthulhu::FieldOffsets offsets_; \ + friend class cthulhu::FieldsBegin; \ + friend class cthulhu::FieldsEnd; \ + friend class cthulhu::FieldObserver + +#define CTHULHU_AUTOSTREAM_REGISTER_CONTENT(Type) \ + static void registerContent() { \ + offsets_.hasContentBlock = true; \ + } \ + friend class cthulhu::ContentBlock + +#define CTHULHU_AUTOSTREAM_GET_SIZE() \ + static inline size_t getSize() { \ + return offsets_.currentOffset; \ + } + +#define CTHULHU_AUTOSTREAM_GET_DYNAMIC_FIELD_COUNT() \ + static inline size_t getDynamicFieldCount() { \ + return offsets_.currentDynamicOffset; \ + } + +#define CTHULHU_AUTOSTREAM_SAMPLES_IN_CONTENT(Type) \ + static void samplesInContentBlock() { \ + offsets_.hasSamplesInContentBlock = true; \ + } + +#define CTHULHU_AUTOSTREAM_CONFIG(Type) \ + CTHULHU_AUTOSTREAM_GET_SIZE() \ + CTHULHU_AUTOSTREAM_GET_DYNAMIC_FIELD_COUNT() \ + Type() : cthulhu::AutoStreamConfig(getSize(), getDynamicFieldCount()) {} \ + Type(const cthulhu::StreamConfig& config) : cthulhu::AutoStreamConfig(config) { \ + config_.sampleSizeInBytes = computeSampleSize(); \ + } \ + Type(const Type& other) : Type(other.config_) {} \ + Type& operator=(const Type& other) { \ + config_ = other.config_; \ + return *this; \ + } \ + Type clone() const { \ + auto copy = *this; \ + copy.config_ = cthulhu::StreamConfig(getSize(), getDynamicFieldCount()); \ + copy.config_.nominalSampleRate = config_.nominalSampleRate; \ + copy.config_.sampleSizeInBytes = config_.sampleSizeInBytes; \ + std::memcpy(copy.config_.parameters.get(), config_.parameters.get(), getSize()); \ + for (size_t i = 0; i < getDynamicFieldCount(); ++i) { \ + copy.config_.dynamicParameters.get()[i] = config_.dynamicParameters.get()[i].clone(); \ + } \ + return copy; \ + } \ + virtual ~Type() = default; \ + CTHULHU_AUTOSTREAM_REGISTER_FIELD(Type) + +#define CTHULHU_AUTOSTREAM_SAMPLE(Type) \ + CTHULHU_AUTOSTREAM_GET_SIZE() \ + CTHULHU_AUTOSTREAM_GET_DYNAMIC_FIELD_COUNT() \ + CTHULHU_AUTOSTREAM_SAMPLES_IN_CONTENT(Type) \ + explicit Type(bool skipParameters = false) \ + : cthulhu::AutoStreamSample(skipParameters ? 0U : getSize(), getDynamicFieldCount()) {} \ + Type(const cthulhu::StreamSample& sample, bool skipParameters = false) \ + : cthulhu::AutoStreamSample( \ + sample, skipParameters ? 0U : getSize(), getDynamicFieldCount()) {} \ + Type(const Type& other) : cthulhu::AutoStreamSample(other.sample_, 0U, 0U) {} \ + Type& operator=(const Type& other) { \ + sample_ = other.sample_; \ + return *this; \ + } \ + virtual ~Type() = default; \ + CTHULHU_AUTOSTREAM_REGISTER_FIELD(Type); \ + CTHULHU_AUTOSTREAM_REGISTER_CONTENT(Type) + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/SubAligner.h b/Cthulhu/include/cthulhu/SubAligner.h new file mode 100644 index 000000000..724a1fd55 --- /dev/null +++ b/Cthulhu/include/cthulhu/SubAligner.h @@ -0,0 +1,225 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include + +namespace cthulhu { + +namespace subaligner { +class Aligner; +struct StreamInterface; +struct Manifest; +} // namespace subaligner + +class SubAligner : public AlignerBase { + public: + struct StreamSettings { + // Offset the input stream by this value (in seconds) + double timeOffset = 0.0; + // Flag for whether to install a metronome for the stream, default true + bool useMetronome = true; + }; + + SubAligner( + const std::vector& settings = std::vector(), + const ThreadPolicy& threadPolicy = ThreadPolicy::SINGLE_THREADED); + virtual ~SubAligner(); + + // By default, all streams will use metronomes unless settings have been set. + // Use this to change that default + void setDefaultMetronome(bool value); + + // This will apply a specific stream setting based on the StreamID, if used. This + // will override any settings that are based on the pin ordering + void setStreamSettingHint(const StreamID& id, const StreamSettings& settings); + + // Select primary stream (e.g. stream that is choosing the alignment time spans) + // + // Must be called after all streams have been registered. May be changed during alignment. + void setPrimaryAlignmentStream(const StreamID& id, double maxLatencySeconds); + + virtual void registerConsumer(StreamInterface* si, int index) override; + + // Returns the largest latency offset specified across all stream settings + double getMaxLatencyOffset() const; + // Returns true if the stream ID is a registered stream + bool isRegistered(const StreamID&) const; + + protected: + // Note: The currently implementation of align() is not thread-safe with + // itself, multiple concurrent calls will run into trouble if we ever try to support + // a MULTI_THREADED mode for the aligner. + virtual void align() override; + virtual void sampleCallback(size_t idx, const StreamSample& sample) override; + virtual bool configCallback(size_t idx, const StreamConfig& config) override; + virtual void clear() override; + + // This is data stored for a stream, which is coupled to a specific aligner context + struct ContextStreamData { + // The config data for the stream within this context + StreamConfig config; + // Samples, indexed in the sequence domain of the context (starting with sequenceIn for each + // sample fed to the context) + std::unordered_map sampleMap; + // Lock for the sampleMap and interface (feed) + std::mutex streamMutex; + // The interface to the SubAlignerImpl for this stream + subaligner::StreamInterface* interface; + // The next sample sequence number for the stream in this context. + uint32_t sequenceIn = 0; + }; + + // A sample finalization strategy that relies on user-selection of a primary stream + // + // When this is the finalization strategy, we will finalize samples that have timestamps + // outside of the primary stream's latest sample + a maximum latency. Moreover, we will + // outright reject samples that are older than the primary stream's latest sample, plus + // latency. + // + // Example: + // Suppose the primary stream's latest timestamp is 3.14. Our maximum latency is 0.5. + // We will finalize and reject the samples of all streams that are older than + // 3.14 - 0.5 = 2.64 seconds. + class PrimarySelection { + public: + PrimarySelection(StreamID streamID, int index, double maxLatencySeconds) + : maxLatencySeconds(maxLatencySeconds), streamID_(std::move(streamID)), index_(index) {} + + // Returns the index of the primary stream selection + int getIndex() const noexcept { + return index_; + } + + inline const StreamID& getStreamID() const noexcept { + return streamID_; + } + + // Sets the reference timestamp to be used with isWithinTolerance + inline void setReference(double referenceTimestamp) noexcept { + referenceTimestamp_ = referenceTimestamp - maxLatencySeconds; + } + + // Returns true if the supplied timestamp is within the time of tolerance + // for new samples. + inline bool isWithinTolerance(double timestamp) const noexcept { + return timestamp >= referenceTimestamp_; + } + + // A relative time (seconds) that describes how much latency we'll + // tolerate + double maxLatencySeconds; + + private: + // Primary stream ID + StreamID streamID_; + // Index of the primary stream + int index_; + // The timestamp we use as our reference for what's considered too + // old to align. Accounts for the max latency. + double referenceTimestamp_; + }; + // A simpler finalization strategy that relies on a global, maximum latency (seconds). + // + // When a sample arrives with timestamp T, we tell the aligner to finalize any data that arrives + // before T - GlobalMaxLatency. + using GlobalMaxLatency = double; + // The finalization strategy. + std::variant finalizeStrategy_ = GlobalMaxLatency(0.5); + + // A new aligner must be constructed for each new configuration + struct AlignerContext { + // The pointer to the Implementation for the context + std::unique_ptr impl; + // References to context-specific data for each stream. Indexed by the same ordering as in + // SubAligner::streams_ + std::map streams; + // Lock for the impl (enroll, align, finalize) and streams + std::mutex implMutex; + // Reverse lookup from Impl's idx to ours (this is probably always trivial out == in + std::map lookupIndex; + // Flag for whether the context has been configured. Can only be configured once. + bool configured = false; + }; + + // The SubAlignerImpl is built with the underlying assumption that sample rates, etc. do not + // change. But Cthulhu allows streams to be dynamically reconfigured. This is supported by + // creating new contexts in which the SubAlignerImpl is accessed, such that newly configured + // streams start using a new instance. + std::map contexts_; + + // You should lock this when modifying the contexts_ and streams_ + std::mutex globalMutex_; + + struct GlobalStreamData { + // The unique ID for the stream + StreamID streamID; + // The consumer on which samples and configuration should be sent + std::unique_ptr consumer; + // The context actively being used by this stream + int activeContext = -1; + // The next sequence number to apply to output samples + uint32_t sequenceOut = 0; + }; + + // This is data for each input stream that is useful regardless of the impl context that is active + std::vector streams_; + + void enroll( + size_t idx, + const StreamConfig& config, + AlignerContext& context, + const std::lock_guard& globalMutexLock); + + void processManifests( + const std::vector& manifests, + const std::lock_guard& globalMutexLock, + AlignerContext& context); + + // This holds the index to the most recently created context + // Samples received on streams will automatically update to using this latest context. + int latestContext_ = -1; + + // Latency in seconds at which old records are cleared from the queues + // This is a nominal value, but if the primary stream has a nominal sample + // rate, this will automatically adjust to 0.5*sampleRate_primary + max(timeOffsets) + static constexpr double maxLatencyFraction_ = 2.5; + + // Settings for each stream (optional) + std::vector settings_; + + // Hints for settings that override any others based on the stream ID + std::map settingHints_; + + bool defaultUseMetronome_ = false; + +}; // class AlignerBase + +// Implements various primary alignment stream selection approaches +class PrimaryAlignmentStream { + public: + struct Election { + StreamID streamID; + double maxLatencySeconds = 0.0; + }; + + // Elects the best image stream to be the primary alignment stream + // + // streamIDs may describe a stream of any type; the implementation will filter + // the streamIDs to those that describe image streams. Then, the implementation looks at + // all published image configurations. It selects one of the slowest streams, and defines + // a maximum latency (seconds) based on the frame rate. + // + // If there is no election, returns an empty optional. If the user specifies a streamID that + // is unknown to the aligner, throws a runtime exception, since we could not run a valid election. + static std::optional bestImageStream( + const SubAligner&, + const std::vector& streamIDs, + double maxLatencyFraction = 2.5); +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/TypeHelpers.h b/Cthulhu/include/cthulhu/TypeHelpers.h new file mode 100644 index 000000000..dc200b5b5 --- /dev/null +++ b/Cthulhu/include/cthulhu/TypeHelpers.h @@ -0,0 +1,103 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include + +namespace cthulhu { + +template +std::string typeString(); + +#define TYPE_STRING_DECLARE(x) \ + template <> \ + std::string typeString(); + +TYPE_STRING_DECLARE(bool) +TYPE_STRING_DECLARE(char) +TYPE_STRING_DECLARE(double) +TYPE_STRING_DECLARE(float) +TYPE_STRING_DECLARE(int64_t) +TYPE_STRING_DECLARE(uint64_t) +TYPE_STRING_DECLARE(int32_t) +TYPE_STRING_DECLARE(uint32_t) +TYPE_STRING_DECLARE(int16_t) +TYPE_STRING_DECLARE(uint16_t) +TYPE_STRING_DECLARE(int8_t) +TYPE_STRING_DECLARE(uint8_t) + +template ::value>::type* = nullptr> +std::string typeStringFilter() { + return typeString::type>(); +} + +template < + class T, + typename std::enable_if::value && !std::is_enum::value>::type* = nullptr> +std::string typeStringFilter() { + return typeString(); +} + +template +struct ArrayTrait; + +template +struct ArrayTrait { + using type = T; + static constexpr size_t size = 1; +}; + +template +struct ArrayTrait { + using type = T; + static constexpr size_t size = N; +}; + +template +struct ArrayTrait> { + using type = T; + static constexpr size_t size = N; +}; + +template +struct ArrayTrait { + using type = T; + static constexpr size_t size = N * M; +}; + +template +struct ArrayTrait, N>> { + using type = T; + static constexpr size_t size = N * M; +}; + +template +struct ArrayTrait> { + using type = T; + // size intentionally skipped; you should never see that it's missing... + // Dynamically-sized types are handled differently. We cannot know their size + // at compile time. Hence, there's no size to expose here. +}; + +template <> +struct ArrayTrait { + using type = std::string::value_type; + // size intentionally skipped; you should never see that it's missing... + // Dynamically-sized types are handled differently. We cannot know their size + // at compile time. Hence, there's no size to expose here. +}; + +template +std::string typeName() { + return typeStringFilter::type>(); +} + +template +size_t typeSize() { + return ArrayTrait::size; +} + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/TypeRegistryInterface.h b/Cthulhu/include/cthulhu/TypeRegistryInterface.h new file mode 100644 index 000000000..d59eb6f8a --- /dev/null +++ b/Cthulhu/include/cthulhu/TypeRegistryInterface.h @@ -0,0 +1,71 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +namespace cthulhu { + +class TypeInfoInterface { + public: + virtual ~TypeInfoInterface() = default; + + virtual std::string typeName() const = 0; + virtual uint32_t typeID() const = 0; + virtual bool isBasic() const = 0; + virtual size_t sampleParameterSize() const = 0; + virtual size_t configParameterSize() const = 0; + virtual size_t sampleNumberDynamicFields() const = 0; + virtual size_t configNumberDynamicFields() const = 0; + virtual const FieldData& sampleFields() const = 0; + virtual const FieldData& configFields() const = 0; + virtual bool hasContentBlock() const = 0; + virtual bool hasSamplesInContentBlock() const = 0; +}; +using TypeInfoInterfacePtr = std::shared_ptr; + +struct TypeDefinition { + std::string typeName; + std::type_index sampleType = typeid(nullptr); + std::optional configType = std::nullopt; + size_t sampleParameterSize = 0; + size_t configParameterSize = 0; + size_t sampleNumberDynamicFields = 0; + size_t configNumberDynamicFields = 0; + FieldData sampleFields; + FieldData configFields; + bool hasContentBlock = false; + bool hasSamplesInContentBlock = false; +}; + +class TypeRegistryInterface : public ForceCleanable, public LogDisabling { + public: + virtual ~TypeRegistryInterface() = default; + + virtual TypeInfoInterfacePtr findSampleType(const std::type_index& sampleType) const = 0; + virtual TypeInfoInterfacePtr findConfigType(const std::type_index& configType) const = 0; + virtual TypeInfoInterfacePtr findTypeName(const std::string& typeName) const = 0; + virtual TypeInfoInterfacePtr findTypeID(uint32_t typeID) const = 0; + + virtual std::vector typeNames() const = 0; + + inline bool isValidStreamType( + const std::type_index& sampleType, + const std::type_index& configType) const { + if (!findConfigType(configType) || !findSampleType(sampleType)) { + return false; + } + return findSampleType(sampleType)->typeID() == findConfigType(configType)->typeID(); + }; + + virtual void registerType(TypeDefinition) = 0; +}; + +} // namespace cthulhu diff --git a/Cthulhu/include/cthulhu/VulkanUtil.h b/Cthulhu/include/cthulhu/VulkanUtil.h new file mode 100644 index 000000000..768c52b8c --- /dev/null +++ b/Cthulhu/include/cthulhu/VulkanUtil.h @@ -0,0 +1,48 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace cthulhu { + +struct VulkanUtilState; + +class VulkanUtil { + public: + VulkanUtil(); + virtual ~VulkanUtil(); + + VulkanUtil(const VulkanUtil& other) = delete; + VulkanUtil& operator=(const VulkanUtil& other) = delete; + + // Allocates an external memory handle for a given number of bytes. + // It always comes from host visible memory, and only supports linear buffers. + // It returns both an opaque platform-agnostic handle, and the memory type index + // which was used when memory was allocated. Returns 0 for the handle when fails. + std::pair allocate(uint32_t nrBytes, bool deviceLocal); + + // Should be called on an external memory handle by the last process + // to release the memory. On some platforms, this won't actually do anything. + void free(uint64_t handle); + + // Maps an external memory handle to a local memory address, with automated cleanup + // Every process should hold on to one of these to ensure the underlying memory resource + // isn't released, as on some platforms the handle itself does not hold a reference once + // imported. Returns nullptr when fails. + std::shared_ptr map(uint64_t handle, uint32_t nrBytes, uint32_t memoryTypeIndex); + + // Returns true if Vulkan is available, otherwise this tool won't do anything. + bool isActive() const; + + bool isDeviceLocal(uint32_t memoryTypeIndex) const; + + private: + // Hides all Vulkan-specific data storage from the public interface + VulkanUtilState* state_ = nullptr; + + bool isActive_ = false; +}; // class VulkanAllocator + +} // namespace cthulhu diff --git a/Cthulhu/ipc_cleanup.cpp b/Cthulhu/ipc_cleanup.cpp new file mode 100644 index 000000000..23d323b7e --- /dev/null +++ b/Cthulhu/ipc_cleanup.cpp @@ -0,0 +1,24 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#define DEFAULT_LOG_CHANNEL "CthulhuIPCClean" +#include +#include + +int main(int argc, char** argv) { + for (int argIdx = 0; argIdx < argc; argIdx++) { + if ("--hard" == std::string_view(argv[argIdx])) { + XR_LOGW("Nuking Cthulhu shared memory. This will reset Cthulhu for all users."); + if (!cthulhu::Framework::nuke()) { + XR_LOGW("Failed to nuke Cthulhu shared memory."); + return 1; + } else { + XR_LOGI("Nuked Cthulhu shared memory."); + return 0; + } + } + } + XR_LOGW("Cleaning up Cthulhu shared memory."); + cthulhu::Framework::instance().cleanup(true); + XR_LOGI("Cleaned up Cthulhu shared memory."); + return 0; +} diff --git a/Cthulhu/modules/pythonbindings/core.cpp b/Cthulhu/modules/pythonbindings/core.cpp new file mode 100644 index 000000000..b70671b1b --- /dev/null +++ b/Cthulhu/modules/pythonbindings/core.cpp @@ -0,0 +1,344 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include +#include + +#include + +namespace py = pybind11; + +namespace cthulhu { + +namespace core { + +void bindings(py::module_& m) { + m.doc() = "cthulhubindings: lower-level bindings to Cthulhu"; + + py::class_>( + m, "ContextInfo") + .def_property_readonly("name", &cthulhu::ContextInfoInterface::name) + .def_property_readonly("private_ns", &cthulhu::ContextInfoInterface::isPrivateNamespace) + .def_property_readonly("pid", &cthulhu::ContextInfoInterface::getPid) + .def_property_readonly("valid", &cthulhu::ContextInfoInterface::getValid) + .def_property_readonly("subscriptions", &cthulhu::ContextInfoInterface::subscriptions) + .def_property_readonly("publications", &cthulhu::ContextInfoInterface::publications) + .def_property_readonly("transformations", &cthulhu::ContextInfoInterface::transformations) + .def("__repr__", [](const cthulhu::ContextInfoInterface& ctx) { + std::ostringstream output; + output << ""; + return output.str(); + }); + + py::class_(m, "ContextRegistry") + .def("contexts", &cthulhu::PyContextRegistry::contexts, py::arg("all") = false); + + m.def("contextRegistry", []() -> std::optional { + if (cthulhu::Framework::instance().contextRegistry()) { + return cthulhu::PyContextRegistry(cthulhu::Framework::instance().contextRegistry()); + } + return {}; + }); + + py::class_(m, "Field") + .def(py::init()) + .def(py::init()) + .def_readwrite("offset", &cthulhu::Field::offset) + .def_readwrite("size", &cthulhu::Field::size) + .def_readwrite("typeName", &cthulhu::Field::typeName) + .def_readwrite("numElements", &cthulhu::Field::numElements) + .def_readwrite("isDynamic", &cthulhu::Field::isDynamic) + .def("__eq__", [](const cthulhu::Field& left, const cthulhu::Field& right) { + return left == right; + }); + + py::class_(m, "TypeDefinition") + .def(py::init<>()) + .def_readwrite("typeName", &cthulhu::TypeDefinition::typeName) + // Skip sampleType; can't be expressed in Python + // Skip configType; can't be expressed in Python + .def_readwrite("sampleParameterSize", &cthulhu::TypeDefinition::sampleParameterSize) + .def_readwrite("configParameterSize", &cthulhu::TypeDefinition::configParameterSize) + .def_readwrite( + "sampleNumberDynamicFields", &cthulhu::TypeDefinition::sampleNumberDynamicFields) + .def_readwrite( + "configNumberDynamicFields", &cthulhu::TypeDefinition::configNumberDynamicFields) + .def_readwrite("sampleFields", &cthulhu::TypeDefinition::sampleFields) + .def_readwrite("configFields", &cthulhu::TypeDefinition::configFields) + .def_readwrite("hasContentBlock", &cthulhu::TypeDefinition::hasContentBlock) + .def_readwrite( + "hasSamplesInContentBlock", &cthulhu::TypeDefinition::hasSamplesInContentBlock); + + py::class_>(m, "TypeInfo") + .def_property_readonly("hasContentBlock", &cthulhu::TypeInfoInterface::hasContentBlock) + .def_property_readonly( + "hasSamplesInContentBlock", &cthulhu::TypeInfoInterface::hasSamplesInContentBlock) + .def_property_readonly("typeName", &cthulhu::TypeInfoInterface::typeName) + .def_property_readonly("typeID", &cthulhu::TypeInfoInterface::typeID) + .def_property_readonly("isBasic", &cthulhu::TypeInfoInterface::isBasic) + .def_property_readonly( + "sampleParameterSize", &cthulhu::TypeInfoInterface::sampleParameterSize) + .def_property_readonly( + "configParameterSize", &cthulhu::TypeInfoInterface::configParameterSize) + .def_property_readonly("sampleFields", &cthulhu::TypeInfoInterface::sampleFields) + .def_property_readonly("configFields", &cthulhu::TypeInfoInterface::configFields); + + py::class_(m, "TypeRegistry") + .def("findTypeName", &cthulhu::PyTypeRegistry::findTypeName) + .def("findTypeID", &cthulhu::PyTypeRegistry::findTypeID) + .def("typeNames", &cthulhu::PyTypeRegistry::typeNames) + .def("registerType", &cthulhu::PyTypeRegistry::registerType); + + m.def("typeRegistry", []() -> std::optional { + if (cthulhu::Framework::instance().typeRegistry()) { + return cthulhu::PyTypeRegistry(cthulhu::Framework::instance().typeRegistry()); + } + return {}; + }); + + py::class_(m, "CpuBuffer", py::buffer_protocol()) + .def_buffer([](cthulhu::PyCpuBuffer& b) -> py::buffer_info { + return py::buffer_info( + b.data(), + sizeof(uint8_t), + py::format_descriptor::format(), + 1, + {b.size()}, + {sizeof(uint8_t)}); + }) + .def("__len__", &cthulhu::PyCpuBuffer::size) + .def_static( + "new", + [](size_t size) -> PyCpuBuffer { + return cthulhu::PyCpuBuffer( + std::shared_ptr(new uint8_t[size]{0}, std::default_delete()), + size); + }) + .def(py::init([](py::buffer b) { + py::buffer_info info = b.request(); + // Create a non-owning pointer that just captures and holds a buffer reference + return cthulhu::PyCpuBuffer( + std::shared_ptr((uint8_t*)info.ptr, [b](uint8_t* ptr) {}), + (size_t)(info.shape[0] * info.itemsize)); + })) + .def("toAny", &cthulhu::PyCpuBuffer::toAny); + + py::class_(m, "GpuBuffer") + .def("mapped", &cthulhu::PyGpuBuffer::mapped) + .def("handle", &cthulhu::PyGpuBuffer::handle) + .def("size", &cthulhu::PyGpuBuffer::size) + .def("memoryTypeIndex", &cthulhu::PyGpuBuffer::memoryTypeIndex) + .def("toCuda", &cthulhu::PyGpuBuffer::toCuda) + .def("toAny", &cthulhu::PyGpuBuffer::toAny); + + py::class_(m, "AnyBuffer") + .def("cpuBuffer", &cthulhu::PyAnyBuffer::cpuBuffer) + .def("gpuBuffer", &cthulhu::PyAnyBuffer::gpuBuffer); + + py::class_(m, "MemoryPool") + .def("getBufferFromPool", &cthulhu::PyMemoryPool::getBufferFromPool) + .def("getGpuBufferFromPool", &cthulhu::PyMemoryPool::getGpuBufferFromPool); + + m.def("memoryPool", []() -> std::optional { + if (cthulhu::Framework::instance().memoryPool()) { + return cthulhu::PyMemoryPool(cthulhu::Framework::instance().memoryPool()); + } + return {}; + }); + + py::class_(m, "StreamDescription") + .def(py::init()) + .def_property_readonly("id", &cthulhu::StreamDescription::id) + .def_property_readonly("type", &cthulhu::StreamDescription::type); + + py::class_(m, "StreamInterface") + .def_property_readonly("description", &cthulhu::PyStreamInterface::description); + + py::class_(m, "StreamConfig") + .def(py::init()) + .def_property( + "nominalSampleRate", + &cthulhu::PyStreamConfig::getNominalSampleRate, + &cthulhu::PyStreamConfig::setNominalSampleRate) + .def_property( + "sampleSizeInBytes", + &cthulhu::PyStreamConfig::getSampleSizeInBytes, + &cthulhu::PyStreamConfig::setSampleSizeInBytes) + .def_property( + "parameters", + &cthulhu::PyStreamConfig::getParameters, + &cthulhu::PyStreamConfig::setParameters); + + py::class_(m, "SampleHeader") + .def_readwrite("timestamp", &cthulhu::SampleHeader::timestamp) + .def_readwrite("sequenceNumber", &cthulhu::SampleHeader::sequenceNumber); + + py::class_(m, "SampleMetadata") + .def_property( + "header", &cthulhu::PySampleMetadata::getHeader, &cthulhu::PySampleMetadata::setHeader) + .def_property( + "processingStamps", + &cthulhu::PySampleMetadata::getProcessingStamps, + &cthulhu::PySampleMetadata::setProcessingStamps) + .def_property( + "history", + &cthulhu::PySampleMetadata::getHistory, + &cthulhu::PySampleMetadata::setHistory); + + py::class_(m, "DynamicParameters") + .def("__getitem__", &cthulhu::PyDynamicParameters::getDynamicParameter) + .def("__setitem__", &cthulhu::PyDynamicParameters::setDynamicParameter); + + py::class_(m, "StreamSample") + .def(py::init()) + .def_property( + "metadata", &cthulhu::PyStreamSample::getMetadata, &cthulhu::PyStreamSample::setMetadata) + .def_property( + "numberOfSubSamples", + &cthulhu::PyStreamSample::getNumberOfSubSamples, + &cthulhu::PyStreamSample::setNumberOfSubSamples) + .def_property( + "payload", &cthulhu::PyStreamSample::getPayload, &cthulhu::PyStreamSample::setPayload) + .def_property( + "parameters", + &cthulhu::PyStreamSample::getParameters, + &cthulhu::PyStreamSample::setParameters) + .def_property( + "dynamicParameters", + &cthulhu::PyStreamSample::getDynamicParameters, + &cthulhu::PyStreamSample::setDynamicParameters); + + py::class_(m, "StreamConsumer") + .def( + py::init< + cthulhu::PyStreamInterface, + cthulhu::PySampleCallback, + cthulhu::PyConfigCallback, + bool>(), + py::arg("si"), + py::arg("sampleCb"), + py::arg("configCb") = nullptr, + py::arg("async") = false) + .def("close", &cthulhu::PyStreamConsumer::close) + .def_property_readonly("closed", &cthulhu::PyStreamConsumer::isClosed) + .def("get_performance_summary", &cthulhu::PyStreamConsumer::getPerformanceSummary) + .def_property( + "queue_capacity", + &cthulhu::PyStreamConsumer::getQueueCapacity, + &cthulhu::PyStreamConsumer::setQueueCapacity) + .def("__bool__", [](const cthulhu::PyStreamConsumer& cons) -> bool { + return !cons.isClosed(); + }); + + py::class_(m, "StreamProducer") + .def(py::init(), py::arg("si"), py::arg("async") = false) + .def("close", &cthulhu::PyStreamProducer::close) + .def_property_readonly("closed", &cthulhu::PyStreamProducer::isClosed) + .def_property_readonly("config", &cthulhu::PyStreamProducer::getConfig) + .def("produceSample", &cthulhu::PyStreamProducer::produceSample) + .def("configureStream", &cthulhu::PyStreamProducer::configureStream) + .def("__bool__", [](const cthulhu::PyStreamProducer& prod) -> bool { + return !prod.isClosed(); + }); + + py::class_(m, "StreamRegistry") + .def("registerStream", &cthulhu::PyStreamRegistry::registerStream) + .def("getStream", &cthulhu::PyStreamRegistry::getStream) + .def("printStreamInfo", &cthulhu::PyStreamRegistry::printStreamInfo) + .def("streamsOfTypeID", &cthulhu::PyStreamRegistry::streamsOfTypeID); + + m.def("streamRegistry", []() -> std::optional { + if (cthulhu::Framework::instance().streamRegistry()) { + return cthulhu::PyStreamRegistry(cthulhu::Framework::instance().streamRegistry()); + } + return {}; + }); + + py::enum_(m, "ClockEvent") + .value("START", cthulhu::ClockEvent::START) + .value("PAUSE", cthulhu::ClockEvent::PAUSE) + .value("RTF_UPDATE", cthulhu::ClockEvent::RTF_UPDATE) + .value("JUMP", cthulhu::ClockEvent::JUMP) + .export_values(); + + py::class_>(m, "Clock") + .def("getTime", &cthulhu::ClockInterface::getTime) + .def("isSimulated", &cthulhu::ClockInterface::isSimulated) + .def("listenEvents", &cthulhu::ClockInterface::listenEvents); + + py::class_< + cthulhu::ControllableClockInterface, + std::shared_ptr>(m, "ControllableClock") + .def("start", &cthulhu::ControllableClockInterface::start) + .def("pause", &cthulhu::ControllableClockInterface::pause) + .def("setRealtimeFactor", &cthulhu::ControllableClockInterface::setRealtimeFactor) + .def("setTime", &cthulhu::ControllableClockInterface::setTime); + + py::class_(m, "ClockManager") + .def("controlClock", &cthulhu::PyClockManager::controlClock) + .def("clock", &cthulhu::PyClockManager::clock); + + py::class_(m, "ClockAuthority") + .def(py::init()); + + m.def("clockManager", []() -> std::optional { + if (cthulhu::Framework::instance().clockManager()) { + return cthulhu::PyClockManager(cthulhu::Framework::instance().clockManager()); + } + return {}; + }); + + py::enum_(m, "ThreadPolicy") + .value("THREAD_NEUTRAL", cthulhu::ThreadPolicy::THREAD_NEUTRAL) + .value("SINGLE_THREADED", cthulhu::ThreadPolicy::SINGLE_THREADED) + .export_values(); + + py::enum_(m, "AlignerMode") + .value("TIMESTAMP", cthulhu::AlignerMode::TIMESTAMP) + .value("SEQUENCE", cthulhu::AlignerMode::SEQUENCE) + .export_values(); + + py::class_(m, "Aligner") + .def(py::init()) + .def(py::init()) + .def("registerConsumer", &cthulhu::PyAligner::pyRegisterConsumer) + .def("setCallback", &cthulhu::PyAligner::setCallback) + .def("setConfigCallback", &cthulhu::PyAligner::setConfigCallback) + .def("setSamplesMetaCallback", &cthulhu::PyAligner::setSamplesMetaCallback) + .def("setConfigsMetaCallback", &cthulhu::PyAligner::setConfigsMetaCallback) + .def("finalize", &cthulhu::PyAligner::finalize) + .def("setAlignCallback", &cthulhu::PyAligner::setAlignCallback); + + py::class_(m, "ImageBuffer", py::buffer_protocol()) + .def_buffer([](cthulhu::PyImageBuffer& b) -> py::buffer_info { + return py::buffer_info( + b.data(), + sizeof(uint8_t), + py::format_descriptor::format(), + 2, + {b.height(), b.width()}, + {sizeof(uint8_t) * b.stride(), sizeof(uint8_t)}); + }) + .def( + "__len__", + [](const cthulhu::PyImageBuffer& img) -> size_t { return img.width() * img.height(); }) + .def_property_readonly("width", &cthulhu::PyImageBuffer::width) + .def_property_readonly("height", &cthulhu::PyImageBuffer::height); + + py::class_(m, "PerformanceSummary") + .def_readonly("min_runtime", &cthulhu::PerformanceSummary::minRuntime) + .def_readonly("mean_runtime", &cthulhu::PerformanceSummary::meanRuntime) + .def_readonly("max_runtime", &cthulhu::PerformanceSummary::maxRuntime) + .def_readonly("total_runtime", &cthulhu::PerformanceSummary::totalRuntime) + .def_readonly("num_calls", &cthulhu::PerformanceSummary::numCalls) + .def_readonly("num_samples_dropped", &cthulhu::PerformanceSummary::numSamplesDropped); + + py::enum_(m, "BufferType", py::arithmetic()) + .value("NULL_BUFFER", cthulhu::BufferType::NULL_BUFFER) + .value("CPU", cthulhu::BufferType::CPU) + .value("GPU", cthulhu::BufferType::GPU); +} +} // namespace core +} // namespace cthulhu diff --git a/Cthulhu/modules/pythonbindings/cuda_util.cpp b/Cthulhu/modules/pythonbindings/cuda_util.cpp new file mode 100644 index 000000000..aa6287f25 --- /dev/null +++ b/Cthulhu/modules/pythonbindings/cuda_util.cpp @@ -0,0 +1,81 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#ifdef _WIN32 +#include +#endif + +#ifdef CTHULHU_HAS_CUDA +#include +#endif + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +CudaUtil::~CudaUtil() { + for (auto& handle : cudaHandleCache_) { + free(handle.second.first, handle.second.second); + } +} + +uint64_t CudaUtil::mapExternalMemoryHandle(uint64_t handle, uint32_t allocatedSize) { +#ifdef CTHULHU_HAS_CUDA + if (cudaHandleCache_.find(handle) != cudaHandleCache_.end()) { + return cudaHandleCache_[handle].first; + } + + // import memory + cudaExternalMemoryHandleDesc memDesc = {}; +#ifdef _WIN32 + memDesc.type = cudaExternalMemoryHandleTypeOpaqueWin32; + memDesc.handle.win32.handle = (HANDLE)handle; +#else + memDesc.type = cudaExternalMemoryHandleTypeOpaqueFd; + memDesc.handle.fd = (int)handle; +#endif + memDesc.size = allocatedSize; + + cudaExternalMemory_t externalMem{}; + if (auto ret = cudaImportExternalMemory(&externalMem, &memDesc); ret != cudaSuccess) { + XR_LOGW("Cannot import external memory {}, error code: {}", handle, std::to_string(ret)); + return 0; + } + cudaExternalMemoryBufferDesc externalMemBufferDesc = {}; + externalMemBufferDesc.offset = 0; + externalMemBufferDesc.size = memDesc.size; + externalMemBufferDesc.flags = 0; + uint8_t* ptr = nullptr; + if (auto ret = + cudaExternalMemoryGetMappedBuffer((void**)&ptr, externalMem, &externalMemBufferDesc); + ret != cudaSuccess) { + XR_LOGW("Cannot map external memory {}, error code: {}", handle, std::to_string(ret)); + return 0; + } + + // Cache the result + std::pair result = {(uint64_t)ptr, (uint64_t)externalMem}; + cudaHandleCache_[handle] = result; + + return result.first; +#else + XR_LOGW("Failed to map external memory handle to CUDA. CUDA support was not included in build."); + return 0; +#endif +} + +void CudaUtil::free(uint64_t mappedHandle, uint64_t externalMem) { +#ifdef CTHULHU_HAS_CUDA + cudaDestroyExternalMemory((cudaExternalMemory_t)externalMem); + cudaFree((uint8_t*)mappedHandle); +#endif +} + +CudaUtil& CudaUtil::instance() { + static CudaUtil util; + return util; +} + +} // namespace cthulhu diff --git a/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/core.h b/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/core.h new file mode 100644 index 000000000..98e314bfc --- /dev/null +++ b/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/core.h @@ -0,0 +1,698 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace cthulhu { + +class PyContextRegistry { + public: + PyContextRegistry(cthulhu::ContextRegistryInterface* impl) : impl_(impl) {} + + auto contexts(bool all = false) const { + return impl_->contexts(all); + } + + private: + const ContextRegistryInterface* impl_; +}; + +class PyTypeRegistry { + public: + PyTypeRegistry(cthulhu::TypeRegistryInterface* impl) : impl_(impl) {} + ~PyTypeRegistry() = default; + + TypeInfoInterfacePtr findTypeName(const std::string& typeName) const { + return impl_->findTypeName(typeName); + } + + TypeInfoInterfacePtr findTypeID(uint32_t typeID) const { + return impl_->findTypeID(typeID); + } + + std::vector typeNames() const { + return impl_->typeNames(); + } + + void registerType(TypeDefinition definition) { + // Python users can't specify C++ std:type_index, which means they can't + // flip the switch to say that a stream type has or doesn't have a config. + // We'll do that for them. If the definition has non-empty type fields, we + // assume that there's a config type, and we'll flip the optional to a valid, + // yet empty, type index. + if (!definition.configFields.empty()) { + definition.configType = typeid(nullptr); + } + impl_->registerType(std::move(definition)); + } + + private: + TypeRegistryInterface* impl_; +}; + +class PyAnyBuffer; + +class PyCpuBuffer { + public: + PyCpuBuffer() : PyCpuBuffer(nullptr, 0U) {} + PyCpuBuffer(const CpuBuffer& data, size_t size) : data_(data), size_(size) {} + PyCpuBuffer(CpuBuffer&& data, size_t size) : data_(std::move(data)), size_(size) {} + PyCpuBuffer(const RawDynamic<>& rd) : data_(rd.raw), size_(rd.size()) {} + ~PyCpuBuffer() = default; + + uint8_t* data() { + return data_.get(); + } + + size_t size() const { + return size_; + } + + CpuBuffer dataRef() const { + return data_; + } + + RawDynamic<> toRawDynamic() const { + RawDynamic<> rd; + rd.raw = dataRef(); + rd.elementSize = sizeof(uint8_t); + rd.elementCount = size(); + return rd; + } + + inline PyAnyBuffer toAny() const; + + private: + CpuBuffer data_; + size_t size_; +}; + +class PyGpuBuffer { + public: + PyGpuBuffer() : PyGpuBuffer(GpuBuffer(), 0U) {} + PyGpuBuffer(const GpuBuffer& data, size_t size) : data_(data), size_(size) {} + PyGpuBuffer(GpuBuffer&& data, size_t size) : data_(std::move(data)), size_(size) {} + ~PyGpuBuffer() = default; + + uint64_t handle() const { + if (!data_) { + return 0; + } + return data_.get()->handle; + } + + PyCpuBuffer mapped() const { + CpuBuffer mapped(data_.mapped()); + return PyCpuBuffer(mapped, mapped ? size_ : 0U); + } + + size_t size() const { + return size_; + } + + uint32_t memoryTypeIndex() const { + if (!data_) { + return 0; + } + return data_.get()->memoryTypeIndex; + } + + GpuBuffer dataRef() const { + return data_; + } + + /** + * Note: This produces a handle that can be used with PyCUDA. However, + * we have found that pycuda.driver.memcpy_htod fails when using this handle. + * Therefore, it should only be used for device-to-device transfers. When + * copying CPU data to this buffer from python, instead the user should + * access it as a CpuBuffer. + */ + uint64_t toCuda() const { + return CudaUtil::instance().mapExternalMemoryHandle(data_->handle, size_); + } + + inline PyAnyBuffer toAny() const; + + private: + GpuBuffer data_; + size_t size_; +}; + +class PyAnyBuffer { + public: + PyAnyBuffer() = default; + PyAnyBuffer(const AnyBuffer& data, size_t size) : data_(data), size_(size) {} + PyAnyBuffer(AnyBuffer&& data, size_t size) : data_(std::move(data)), size_(size) {} + ~PyAnyBuffer() = default; + + PyAnyBuffer& operator=(const PyCpuBuffer& other) { + data_ = other.dataRef(); + size_ = other.size(); + return *this; + } + + size_t size() const { + return size_; + } + + PyCpuBuffer cpuBuffer() const { + if (data_.type == BufferType::CPU) { + return PyCpuBuffer(std::get(data_.data), size_); + } else if (data_.type == BufferType::GPU) { + CpuBuffer mapped = std::get(data_.data).mapped(); + return PyCpuBuffer(mapped, mapped ? size_ : 0U); + } + return PyCpuBuffer(); + } + + PyGpuBuffer gpuBuffer() const { + if (data_.type == BufferType::GPU) { + return PyGpuBuffer(std::get(data_.data), size_); + } + return PyGpuBuffer(); + } + + AnyBuffer dataRef() const { + return data_; + } + + private: + AnyBuffer data_; + size_t size_; +}; + +PyAnyBuffer PyCpuBuffer::toAny() const { + return PyAnyBuffer(data_, size_); +} + +PyAnyBuffer PyGpuBuffer::toAny() const { + return PyAnyBuffer(data_, size_); +} + +class PyMemoryPool { + public: + PyMemoryPool(MemoryPoolInterface* impl) : impl_(impl) {} + ~PyMemoryPool() = default; + + PyCpuBuffer getBufferFromPool(const std::string& id, size_t nrBytes) { + return PyCpuBuffer(impl_->getBufferFromPool(id, nrBytes), nrBytes); + } + + PyGpuBuffer getGpuBufferFromPool(size_t nrBytes, bool deviceLocal) { + return PyGpuBuffer(impl_->getGpuBufferFromPool(nrBytes, deviceLocal), nrBytes); + } + + private: + MemoryPoolInterface* impl_; +}; + +class PyStreamConsumer; +class PyStreamProducer; +class PyAligner; + +class PyStreamInterface { + public: + PyStreamInterface(StreamInterface* impl) : impl_(impl) {} + ~PyStreamInterface() = default; + + const StreamDescription& description() const { + return impl_->description(); + } + + private: + StreamInterface* impl_; + + friend class PyStreamConsumer; + friend class PyStreamProducer; + friend class PyAligner; +}; + +class PyStreamConfig { + public: + PyStreamConfig() {} + PyStreamConfig(PyCpuBuffer buffer) : size_(buffer.size()) { + config_.parameters = buffer.dataRef(); + } + PyStreamConfig(const StreamConfig& config, size_t size) : config_(config), size_(size) {} + + PyStreamConfig(const PyStreamConfig&) = default; + PyStreamConfig& operator=(const PyStreamConfig&) = default; + + const double& getNominalSampleRate() { + return config_.nominalSampleRate; + } + void setNominalSampleRate(const double& value) { + config_.nominalSampleRate = value; + } + + const uint32_t& getSampleSizeInBytes() { + return config_.sampleSizeInBytes; + } + void setSampleSizeInBytes(const uint32_t& value) { + config_.sampleSizeInBytes = value; + } + + PyCpuBuffer getParameters() { + return PyCpuBuffer(config_.parameters, size_); + } + void setParameters(const PyCpuBuffer& value) { + size_ = value.size(); + config_.parameters = value.dataRef(); + } + + const StreamConfig& getConfig() const { + return config_; + } + + private: + StreamConfig config_; + size_t size_ = 0; + + friend class PyStreamProducer; +}; + +class PySampleMetadata; + +using PySampleHistory = std::map; + +class PyStreamSample; + +class PySampleMetadata { + public: + PySampleMetadata(const std::shared_ptr& data) : data_(data) {} + ~PySampleMetadata() = default; + + const SampleHeader& getHeader() { + return data_->header; + } + void setHeader(const SampleHeader& value) { + data_->header = value; + } + + const ProcessingStamps& getProcessingStamps() { + return data_->processingStamps; + } + void setProcessingStamps(const ProcessingStamps& value) { + data_->processingStamps = value; + } + + const PySampleHistory getHistory() { + PySampleHistory result; + for (const auto& item : data_->history) { + auto st = std::string(item.first); + result.emplace(st, PySampleMetadata(item.second)); + } + return result; + } + void setHistory(const PySampleHistory& value) { + data_->history.clear(); + for (const auto& item : value) { + data_->history[item.first] = item.second.data_; + } + } + + private: + std::shared_ptr data_; + + friend class PyStreamSample; +}; + +class PyDynamicParameters { + public: + PyDynamicParameters(const StreamSample& sample) : sample_(sample) {} + + PyCpuBuffer getDynamicParameter(const size_t index) const { + RawDynamic<> rd = *(sample_.dynamicParameters.get() + index); + return PyCpuBuffer(rd); + } + + void setDynamicParameter(const size_t index, const PyCpuBuffer& buffer) { + auto rdPtr = sample_.dynamicParameters.get() + index; + *rdPtr = buffer.toRawDynamic(); + } + + private: + StreamSample sample_; +}; + +class PyStreamSample { + public: + PyStreamSample() {} + PyStreamSample(const StreamSample& sample, size_t payloadSize, size_t parameterSize) + : sample_(sample), payloadSize_(payloadSize), parameterSize_(parameterSize) {} + ~PyStreamSample() = default; + + PySampleMetadata getMetadata() { + return PySampleMetadata(sample_.metadata); + } + void setMetadata(const PySampleMetadata& value) { + sample_.metadata = value.data_; + } + + std::optional getPayload() { + if (payloadSize_ == 0 || !sample_.payload) { + return std::nullopt; + } + return PyAnyBuffer(sample_.payload, payloadSize_); + } + void setPayload(const PyAnyBuffer& value) { + payloadSize_ = value.size(); + sample_.payload = value.dataRef(); + } + + const uint32_t& getNumberOfSubSamples() { + return sample_.numberOfSubSamples; + } + void setNumberOfSubSamples(const uint32_t& value) { + sample_.numberOfSubSamples = value; + } + + std::optional getParameters() { + if (!sample_.parameters) { + return std::nullopt; + } + return PyCpuBuffer(sample_.parameters, parameterSize_); + } + void setParameters(const PyCpuBuffer& value) { + parameterSize_ = value.size(); + sample_.parameters = value.dataRef(); + } + + std::optional getDynamicParameters() { + if (!sample_.dynamicParameters) { + return std::nullopt; + } + return PyDynamicParameters(sample_); + } + + void setDynamicParameters(std::vector& buffers) { + sample_.dynamicParameters = makeSharedRawDynamicArray(buffers.size()); + PyDynamicParameters dp(sample_); + for (size_t i = 0; i < buffers.size(); i++) { + PyCpuBuffer buffer = buffers[i]; + dp.setDynamicParameter(i, buffer); + } + } + + private: + StreamSample sample_; + size_t payloadSize_ = 0; + size_t parameterSize_ = 0; + + friend class PyStreamProducer; +}; + +using PySampleCallback = std::function; +using PyConfigCallback = std::function; + +class PyStreamConsumer { + public: + PyStreamConsumer( + const PyStreamInterface& si, + const PySampleCallback& sampleCb, + const PyConfigCallback& configCb, + bool async) { + pybind11::gil_scoped_release unlock; + + auto typeInfo = + Framework::instance().typeRegistry()->findTypeID(si.impl_->description().type()); + auto typeName = typeInfo->typeName(); + + const auto sampleParameterSize = typeInfo->sampleParameterSize(); + + // SFoCB samples require a configuration to propagate the sample size, + // even if they're basic streams. Cache the sample size here. + // + // TODO there might be a better way to do this. However, the branch + // below is general for all SFoCB types. + if (typeInfo->hasSamplesInContentBlock()) { + sampleSizeInBytes_.store(sampleParameterSize); + } + + consumer_ = std::make_unique( + si.impl_, + [this, sampleCb, sampleParameterSize](const StreamSample& sample) -> void { + PyStreamSample pysample( + sample, sample.numberOfSubSamples * sampleSizeInBytes_.load(), sampleParameterSize); + pybind11::gil_scoped_acquire lock; + sampleCb(pysample); + }, + configCb ? std::function( + [this, + configCb, + configParameterSize = + Framework::instance() + .typeRegistry() + ->findTypeID(si.impl_->description().type()) + ->configParameterSize()](const StreamConfig& config) -> bool { + sampleSizeInBytes_.store(config.sampleSizeInBytes); + PyStreamConfig pyconfig(config, configParameterSize); + pybind11::gil_scoped_acquire lock; + return configCb(pyconfig); + }) + : nullptr, + async); + } + + void close() { + pybind11::gil_scoped_release release; + consumer_.reset(); + } + + bool isClosed() const { + return nullptr == consumer_; + } + + PerformanceSummary getPerformanceSummary() const { + return consumer_->getPerformanceSummary(); + } + + uint64_t getQueueCapacity() const { + return consumer_->getQueueCapacity(); + } + + void setQueueCapacity(uint64_t capacity) { + consumer_->setQueueCapacity(capacity); + } + + ~PyStreamConsumer() { + close(); + } + + private: + std::atomic sampleSizeInBytes_; + std::unique_ptr consumer_; +}; + +class PyStreamProducer { + public: + PyStreamProducer(const PyStreamInterface& si, bool async) + : producer_(std::in_place, si.impl_, async), si_(si.impl_) {} + + void produceSample(const PyStreamSample& sample) const { + if (isClosed()) + throw std::runtime_error("StreamProducer is closed"); + + StreamSample sampleOut = sample.sample_; + // Determine the number of subsamples from the payload size + sampleOut.numberOfSubSamples = sample.payloadSize_ / si_->config().sampleSizeInBytes; + + producer_->produceSample(sampleOut); + } + + void configureStream(const PyStreamConfig& config) { + if (isClosed()) + throw std::runtime_error("StreamProducer is closed"); + + config_ = config; + producer_->configureStream(config.config_); + } + + void close() { + pybind11::gil_scoped_release release; + producer_.reset(); + } + + bool isClosed() const { + return !producer_.has_value(); + } + + ~PyStreamProducer() { + close(); + } + + const PyStreamConfig& getConfig() const { + return config_; + } + + private: + std::optional producer_; + StreamInterface* si_ = nullptr; + PyStreamConfig config_; +}; + +class PyStreamRegistry { + public: + PyStreamRegistry(StreamRegistryInterface* impl) : impl_(impl) {} + ~PyStreamRegistry() = default; + + PyStreamInterface registerStream(const StreamDescription& desc) { + return PyStreamInterface(impl_->registerStream(desc)); + } + + std::optional getStream(const std::string& id) { + StreamInterface* si = impl_->getStream(id); + return si ? std::make_optional(si) : std::nullopt; + } + + void printStreamInfo() { + impl_->printStreamInfo(); + } + + std::vector streamsOfTypeID(uint32_t typeID) { + return impl_->streamsOfTypeID(typeID); + } + + private: + StreamRegistryInterface* impl_; +}; + +class PyClockManager { + public: + PyClockManager(ClockManagerInterface* impl) : impl_(impl) {} + ~PyClockManager() = default; + + const std::shared_ptr controlClock(const std::string& contextName) { + return impl_->controlClock(contextName); + } + + const std::shared_ptr clock() { + return impl_->clock(); + } + + private: + ClockManagerInterface* impl_; +}; + +class PyAligner : public Aligner { + public: + PyAligner( + size_t queueSize = 1, + ThreadPolicy threadPolicy = ThreadPolicy::THREAD_NEUTRAL, + AlignerMode mode = AlignerMode::TIMESTAMP) + : Aligner(queueSize, threadPolicy, mode){}; + virtual ~PyAligner() = default; + + void pyRegisterConsumer(const PyStreamInterface& si, int index) { + registerConsumer(si.impl_, index); + } + + void setAlignCallback(const std::function>& queues, + std::vector& samples)>& alignCallback) { + alignCallback_ = alignCallback; + } + + virtual void align() override { + // Just execute the standard behavior if we haven't been given a callback + if (!alignCallback_) { + Aligner::align(); + } + + if (!finalized_) { + return; + } + std::vector samples; + samples.reserve(queues_.size()); + { + std::lock_guard lock(queueMutex_); + + std::map> queues; + for (const auto& queue : queues_) { + queues[queue.id] = queue.samples; + } + + if (!alignCallback_(queues, samples)) { + return; + } + + // Check to see if this set of samples should have a new config + checkConfig(samples); + } + + execute(samples); + } + + private: + std::function>& queues, + std::vector& samples)> + alignCallback_; +}; + +class PyImageBuffer { + public: + PyImageBuffer() : PyImageBuffer(nullptr, 0U, 0U, 0U, 0U) {} + PyImageBuffer( + std::shared_ptr data, + size_t width, + size_t height, + size_t stride, + size_t offset) + : buffer_(std::move(data)), + width_(width), + height_(height), + stride_(stride), + offset_(offset) {} + + PyImageBuffer(PyImageBuffer&&) = default; + PyImageBuffer& operator=(PyImageBuffer&&) = default; + + PyImageBuffer(const PyImageBuffer&) = delete; + PyImageBuffer& operator=(const PyImageBuffer&) = delete; + + ~PyImageBuffer() = default; + + uint8_t* data() { + return (buffer_) ? (buffer_.get() + offset_) : nullptr; + } + + size_t width() const { + return width_; + } + + size_t height() const { + return height_; + } + + size_t stride() const { + return stride_; + } + + explicit operator bool() const { + return (nullptr != buffer_); + } + + private: + std::shared_ptr buffer_; + size_t width_; + size_t height_; + size_t stride_; + size_t offset_; +}; + +// Bindings entrypoint +namespace core { +void bindings(pybind11::module&); +} + +} // namespace cthulhu diff --git a/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/cuda_util.h b/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/cuda_util.h new file mode 100644 index 000000000..511bbc7c0 --- /dev/null +++ b/Cthulhu/modules/pythonbindings/include/cthulhu/bindings/cuda_util.h @@ -0,0 +1,27 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +namespace cthulhu { + +class CudaUtil { + public: + ~CudaUtil(); + uint64_t mapExternalMemoryHandle(uint64_t handle, uint32_t allocationSize); + static CudaUtil& instance(); + + private: + CudaUtil() = default; + void free(uint64_t mappedHandle, uint64_t externalMemory); + + /** + * Cache the imported handles, because it takes several milliseconds to do. + */ + std::map> cudaHandleCache_; +}; // class CudaUtil + +} // namespace cthulhu diff --git a/Cthulhu/modules/pythonbindings/module.cpp b/Cthulhu/modules/pythonbindings/module.cpp new file mode 100644 index 000000000..b0ccd6980 --- /dev/null +++ b/Cthulhu/modules/pythonbindings/module.cpp @@ -0,0 +1,46 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#ifndef CTHULHU_EXTERNAL +#include +#endif + +#include +#include + +#ifndef CTHULHU_EXTERNAL +#include +#endif + +namespace py = pybind11; + +PYBIND11_MODULE(cthulhubindings, m) { + cthulhu::core::bindings(m); + +#ifndef CTHULHU_EXTERNAL + cthulhu::common_types::bindings(m); + log_utils::registerBindingsForXRInit(m); + + m.def( + "compute_sample_size", + [](const cthulhu::PyStreamConfig& cfg, const std::string& typeName) -> uint32_t { + if (auto dispatcher = + cthulhu::common_types::computeSampleSizeDispatch(cfg.getConfig(), typeName); + dispatcher) { + return dispatcher()->computeSampleSize(); + } else { + throw std::runtime_error( + "The computeSampleSize associated with type " + typeName + " is not available"); + } + }); + + py::cpp_function cleanup_callback([](py::handle weakref) { + cthulhu::Framework::instance().cleanup(); + weakref.dec_ref(); + }); + + // Call cleanup with a weakref to a sentinel object on the bindings via a callback. + // This ensures cleanup happens early enough for the Vulkan API to still be loaded. + m.def("_sentinel", []() -> void {}); + (void)py::weakref(m.attr("_sentinel"), cleanup_callback).release(); +#endif +} diff --git a/Cthulhu/src/Aligner.cpp b/Cthulhu/src/Aligner.cpp new file mode 100644 index 000000000..e4ca0c5d0 --- /dev/null +++ b/Cthulhu/src/Aligner.cpp @@ -0,0 +1,252 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +AlignerBase::AlignerBase(ThreadPolicy threadPolicy) : policy_(threadPolicy), finalized_(false) {} + +void AlignerBase::initThread() { + if (policy_ == ThreadPolicy::SINGLE_THREADED && !thread_is_alive_) { + thread_ = std::thread( + [this](std::future signal) -> void { + while (signal.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout) { + this->align(); + } + }, + stopSignal_.get_future()); + thread_is_alive_ = true; + } +} + +void AlignerBase::killThread() { + if (policy_ == ThreadPolicy::SINGLE_THREADED && thread_is_alive_) { + stopSignal_.set_value(); + while (!thread_.joinable()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + thread_.join(); + thread_is_alive_ = false; + } +} + +AlignerBase::~AlignerBase() { + killThread(); +} + +void AlignerBase::setCallback(const AlignerSampleCallback& callback) { + callback_ = callback; +} + +void AlignerBase::setConfigCallback(const AlignerConfigCallback& ccallback) { + ccallback_ = ccallback; +} + +void AlignerBase::setSamplesMetaCallback(const AlignerSamplesMetaCallback& smcallback) { + smcallback_ = smcallback; +} + +void AlignerBase::setConfigsMetaCallback(const AlignerConfigsMetaCallback& cmcallback) { + cmcallback_ = cmcallback; +} + +void AlignerBase::alignedCallback(const std::vector& samples) { + if (callback_) { + callback_(samples); + } +} + +bool AlignerBase::alignedConfigCallback(const std::vector& configs) { + if (ccallback_) { + return ccallback_(configs); + } + return true; +} + +void AlignerBase::alignedSamplesMetaCallback(const AlignerSamplesMeta& meta) { + if (smcallback_) { + return smcallback_(meta); + } +} + +void AlignerBase::alignedConfigsMetaCallback(const AlignerConfigsMeta& meta) { + if (cmcallback_) { + return cmcallback_(meta); + } +} + +void AlignerBase::finalize() { + finalized_ = true; +} + +bool AlignerBase::hasSampleCallback() const { + return (nullptr != callback_); +} + +Aligner::Aligner( + size_t queueSize, + ThreadPolicy threadPolicy, + AlignerMode mode, + double thresholdSeconds) + : AlignerBase(threadPolicy), queueSize_(queueSize), threshold_(thresholdSeconds) { + if (mode == AlignerMode::TIMESTAMP) { + comparison_ = [this](const StreamSample& sample1, const StreamSample& sample2) -> bool { + return std::fabs(sample1.metadata->header.timestamp - sample2.metadata->header.timestamp) < + this->threshold_; + }; + } else if (mode == AlignerMode::SEQUENCE) { + comparison_ = [](const StreamSample& sample1, const StreamSample& sample2) -> bool { + return sample1.metadata->header.sequenceNumber == sample2.metadata->header.sequenceNumber; + }; + } + initThread(); +} + +Aligner::~Aligner() { + queues_.clear(); + killThread(); +} + +void Aligner::registerConsumer(StreamInterface* si, int index) { + if (finalized_) { + XR_LOGE("Attempted to register a consumer after being finalized."); + return; + } + // We have to lock the queue mutex if we want to modify the queues_ structure, + // since we could possibly be receiving data on another stream which needs + // to be accessing its queue. Since calls to registerConsumer() are called from + // a single thread, access to the properties of the queue for this particular index + // are safe since the thread that will access this specific queue is not started until + // construction of StreamConsumer. + { + std::lock_guard lock(queueMutex_); + if (queues_.size() <= index) { + queues_.resize(index + 1); + } + } + SampleCallback callback = [this, index](const StreamSample& sample) -> void { + sampleCallback(index, sample); + }; + ConfigCallback ccallback = [this, index](const StreamConfig& config) -> bool { + return configCallback(index, config); + }; + queues_[index].id = si->description().id(); + queues_[index].consumer = std::make_unique(si, callback, ccallback); +} + +void Aligner::checkConfig(const std::vector& samples) { + // Check to see if this set of samples should have a new config + bool updateConfig = !configured_; + size_t idx = 0; + for (auto& queue : queues_) { + while (queue.configs.size() > 1 && + queue.configs[1].first < samples[idx].metadata->header.sequenceNumber) { + updateConfig = true; + queue.configs.pop_front(); + } + ++idx; + } + if (updateConfig) { + std::vector configs; + configs.reserve(queues_.size()); + AlignerConfigsMeta meta; + meta.reserve(queues_.size()); + for (const auto& queue : queues_) { + if (queue.configs.empty()) { + break; + } + configs.push_back(queue.configs.front().second); + meta.push_back(AlignerStreamMeta{queue.id, queue.configs.front().second.sampleSizeInBytes}); + } + if (configs.size() == queues_.size()) { + inhibitSampleCallback_ = !alignedConfigCallback(configs); + configured_ = true; + alignedConfigsMetaCallback(meta); + } + } +} + +void Aligner::execute(const std::vector& samples) { + if (!inhibitSampleCallback_) { + // Produce aligned metadata + AlignerSamplesMeta meta(samples.size()); + for (size_t i = 0; i < samples.size(); i++) { + meta[i].timestamp = samples[i].metadata->header.timestamp; + meta[i].references.resize(1); + meta[i].references[0].sequenceNumber = samples[i].metadata->header.sequenceNumber; + meta[i].references[0].subSampleOffset = 0; + meta[i].references[0].numSubSamples = samples[i].numberOfSubSamples; + } + alignedSamplesMetaCallback(meta); + + alignedCallback(samples); + } +} + +void Aligner::sampleCallback(size_t idx, const StreamSample& sample) { + { + std::lock_guard lock(queueMutex_); + queues_[idx].latestSequence = sample.metadata->header.sequenceNumber; + queues_[idx].samples.push(sample); + + if (queues_[idx].samples.size() > queueSize_) { + queues_[idx].samples.pop(); + } + } + if (policy_ == ThreadPolicy::THREAD_NEUTRAL) { + align(); + } +} + +void Aligner::align() { + if (!finalized_) { + return; + } + std::vector samples; + samples.reserve(queues_.size()); + { + std::lock_guard lock(queueMutex_); + const StreamSample* refSample = nullptr; + + for (auto& queue : queues_) { + if (queue.samples.empty()) { + return; + } + + if (refSample == nullptr) { + refSample = &queue.samples.front(); + continue; + } + + if (!comparison_(*refSample, queue.samples.front())) { + return; + } + } + + if (refSample == nullptr) { + return; + } + + for (auto& queue : queues_) { + samples.push_back(queue.samples.front()); + queue.samples.pop(); + } + + // Check to see if this set of samples should have a new config + checkConfig(samples); + } + + execute(samples); +} + +bool Aligner::configCallback(size_t idx, const StreamConfig& config) { + std::lock_guard lock(queueMutex_); + queues_[idx].configs.push_back( + std::pair(queues_[idx].latestSequence, config)); + return true; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/AlignerMeta.cpp b/Cthulhu/src/AlignerMeta.cpp new file mode 100644 index 000000000..6fab994cf --- /dev/null +++ b/Cthulhu/src/AlignerMeta.cpp @@ -0,0 +1,63 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +namespace cthulhu { + +void serialize(const AlignerConfigsMeta& input, std::ostringstream& output) { + uint32_t size = input.size(); + output.write((char*)&size, sizeof(uint32_t)); + for (const auto& in : input) { + uint8_t length = in.streamID.length(); + output.write((char*)&length, sizeof(uint8_t)); + output.write((char*)&(in.streamID[0]), in.streamID.length()); + output.write((char*)&in.subSampleSize, sizeof(uint32_t)); + } +} + +void serialize(const AlignerSamplesMeta& input, std::ostringstream& output) { + uint32_t size = input.size(); + output.write((char*)&size, sizeof(uint32_t)); + for (const auto& in : input) { + output.write((char*)&in.timestamp, sizeof(double)); + uint32_t refs = in.references.size(); + output.write((char*)&refs, sizeof(uint32_t)); + for (const auto& ref : in.references) { + output.write((char*)&ref.sequenceNumber, sizeof(uint32_t)); + output.write((char*)&ref.subSampleOffset, sizeof(uint32_t)); + output.write((char*)&ref.numSubSamples, sizeof(uint32_t)); + } + } +} + +void deserialize(std::istringstream& input, AlignerConfigsMeta& output) { + uint32_t size; + input.read((char*)&size, sizeof(uint32_t)); + output.resize(size); + for (uint32_t in = 0; in < size; ++in) { + uint8_t length; + input.read((char*)&length, sizeof(uint8_t)); + output[in].streamID.resize(length); + input.read((char*)&(output[in].streamID[0]), length); + input.read((char*)&(output[in].subSampleSize), sizeof(uint32_t)); + } +} + +void deserialize(std::istringstream& input, AlignerSamplesMeta& output) { + uint32_t size; + input.read((char*)&size, sizeof(uint32_t)); + output.resize(size); + for (uint32_t in = 0; in < size; ++in) { + input.read((char*)&output[in].timestamp, sizeof(double)); + uint32_t refs; + input.read((char*)&refs, sizeof(uint32_t)); + output[in].references.resize(refs); + for (uint32_t ref = 0; ref < refs; ++ref) { + input.read((char*)&(output[in].references[ref].sequenceNumber), sizeof(uint32_t)); + input.read((char*)&(output[in].references[ref].subSampleOffset), sizeof(uint32_t)); + input.read((char*)&(output[in].references[ref].numSubSamples), sizeof(uint32_t)); + } + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/AuditorIPC.cpp b/Cthulhu/src/AuditorIPC.cpp new file mode 100644 index 000000000..be4c9b8df --- /dev/null +++ b/Cthulhu/src/AuditorIPC.cpp @@ -0,0 +1,43 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "AuditorIPC.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#ifndef _WIN32 +#include +#endif + +namespace cthulhu { + +#ifdef _WIN32 +AuditorIPC::Process::Process() : processId_{GetCurrentProcessId()} {} + +bool AuditorIPC::Process::isSelf() const { + return processId_ == GetCurrentProcessId(); +} + +bool AuditorIPC::Process::isAlive() const { + DWORD exitCode; + bool alive = false; + HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, processId_); + if (hProcess != NULL) { + alive = GetExitCodeProcess(hProcess, &exitCode) && exitCode == STILL_ACTIVE; + CloseHandle(hProcess); + } + return alive; +} +#else +AuditorIPC::Process::Process() : pid_{getpid()} {} + +bool AuditorIPC::Process::isSelf() const { + return pid_ == getpid(); +} + +bool AuditorIPC::Process::isAlive() const { + return kill(pid_, 0) >= 0; +} +#endif + +} // namespace cthulhu diff --git a/Cthulhu/src/AuditorIPC.h b/Cthulhu/src/AuditorIPC.h new file mode 100644 index 000000000..d3ac95030 --- /dev/null +++ b/Cthulhu/src/AuditorIPC.h @@ -0,0 +1,53 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#ifdef _WIN32 +#include +#endif +#include + +#include "IPCEssentials.h" + +#include + +namespace cthulhu { + +struct AuditorIPC { + struct Process { + Process(); + + bool isAlive() const; + bool isSelf() const; + + inline uint64_t pid() const { +#ifdef _WIN32 + return processId_; +#else + return pid_; +#endif + } + +#ifdef _WIN32 + DWORD processId_; +#else + pid_t pid_; +#endif + }; + + typedef boost::interprocess::allocator + ProcessVectorAllocType; + + typedef boost::interprocess::vector ProcessVectorType; + + AuditorIPC(ManagedSHM::segment_manager* mgr) : processes(mgr) {} + + bool invalid = false; + MutexIPC mutex; + + // Maintain a vector of processes using the pool + // When this empties, the process should cleanup framework + ProcessVectorType processes; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/BufferTypes.cpp b/Cthulhu/src/BufferTypes.cpp new file mode 100644 index 000000000..8afaf0bfd --- /dev/null +++ b/Cthulhu/src/BufferTypes.cpp @@ -0,0 +1,49 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +namespace cthulhu { + +CpuBuffer GpuBuffer::mapped() const { + return CpuBuffer_; +} + +AnyBuffer::operator CpuBuffer() const { + if (type == BufferType::CPU) { + return std::get(data); + } else if (type == BufferType::GPU) { + return std::get(data).mapped(); + } + return nullptr; +} + +AnyBuffer::operator bool() const { + if (type == BufferType::CPU) { + return (bool)std::get(data); + } else if (type == BufferType::GPU) { + return (bool)std::get(data); + } + return false; +} + +AnyBuffer& AnyBuffer::operator=(const CpuBuffer& buffer) { + data = buffer; + type = BufferType::CPU; + return *this; +} + +AnyBuffer& AnyBuffer::operator=(const GpuBuffer& buffer) { + data = buffer; + type = BufferType::GPU; + return *this; +} + +AnyBuffer::AnyBuffer(const BufferType& _type) : type(_type) {} + +AnyBuffer::AnyBuffer(const CpuBuffer& buffer) : data(buffer), type(BufferType::CPU) {} + +AnyBuffer::AnyBuffer(const GpuBuffer& buffer) : data(buffer), type(BufferType::GPU) {} + +} // namespace cthulhu diff --git a/Cthulhu/src/Clock.cpp b/Cthulhu/src/Clock.cpp new file mode 100644 index 000000000..fb5c7abe8 --- /dev/null +++ b/Cthulhu/src/Clock.cpp @@ -0,0 +1,16 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +namespace cthulhu { + +double ClockInterface::getWallTime() const { + const auto now = std::chrono::high_resolution_clock::now(); + const auto seconds = + std::chrono::duration(now.time_since_epoch()); + return seconds.count(); +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockIPC.cpp b/Cthulhu/src/ClockIPC.cpp new file mode 100644 index 000000000..f349f5387 --- /dev/null +++ b/Cthulhu/src/ClockIPC.cpp @@ -0,0 +1,183 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ClockIPC.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +namespace cthulhu { + +ClockIPC::ClockIPC(ClockIPCData* data, bool simTime) : data_(data), simTime_(simTime) {} + +ClockIPC::~ClockIPC() = default; + +double ClockIPC::getTime() { + if (simTime_) { + if (!data_->paused) + // advance time + updateTime(); + return data_->latestTime; + } + return getWallTime(); +} + +void ClockIPC::updateTime() { + double reference = data_->latestTime; + double wall = getWallTime(); + updateLatestTime( + data_->realtimeFactor * (wall - data_->wallStartTime) + data_->offset, reference); +} + +void ClockIPC::updateLatestTime(double desired, double reference, bool enableBackwards) { + double latest; + do { + latest = data_->latestTime; + if (latest < reference) { + break; + } + if ((enableBackwards && latest == desired) || (!enableBackwards && latest > desired)) { + break; + } + } while (!data_->latestTime.compare_exchange_weak(latest, desired)); +} + +ControllableClockIPC::ControllableClockIPC(ClockIPCData* data) + : ClockIPC(data, true), localControl_(false) { + thread_ = std::thread( + [this](std::future signal) -> void { + uint32_t latestEvent = 0; + while (signal.wait_for(std::chrono::microseconds(0)) == std::future_status::timeout) { + if (latestEvent < this->data_->signal_count) { + int eventNumber; + ClockEvent event; + { + ScopedLockIPC lock(this->data_->signal_lock); + eventNumber = this->data_->signal_count; + event = this->data_->event; + } + for (const auto& listener : this->listeners_) { + listener(event); + } + if (eventNumber != latestEvent + 1) { + XR_LOGW("ClockIPC - Missed events between {} and {}", latestEvent, eventNumber); + } + latestEvent = eventNumber; + } + ScopedLockIPC lock(this->data_->signal_lock); + this->data_->signal_update.timed_wait( + lock, boost::get_system_time() + boost::posix_time::milliseconds(1)); + } + }, + stopSignal_.get_future()); +} + +ControllableClockIPC::~ControllableClockIPC() { + setControlLocal(); +} + +void ControllableClockIPC::setControlLocal() { + if (localControl_) { + return; + } + stopSignal_.set_value(); + if (thread_.joinable()) { + thread_.join(); + } + localControl_ = true; +} + +bool ControllableClockIPC::start(double time) { + if (!simTime_) { + XR_LOGI("Could not start clock, using real time."); + return false; + } + double reference = data_->latestTime; + if (!data_->paused) { + XR_LOGI("Could not start clock that is currently running."); + return false; + } + + updateLatestTime(time, reference, true); + + data_->wallStartTime = getWallTime(); + if (time >= 0.) { + data_->offset = time; + for (const auto& listener : listeners_) { + listener(ClockEvent::JUMP); + } + signalEventIPC(ClockEvent::JUMP); + } else { + data_->offset = data_->latestTime; + } + data_->paused = false; + for (const auto& listener : listeners_) { + listener(ClockEvent::START); + } + signalEventIPC(ClockEvent::START); + return true; +} + +void ControllableClockIPC::pause() { + // sanity checks + if (!simTime_) { + XR_LOGI("Could not pause clock, using real time."); + return; + } + if (data_->paused) { + XR_LOGW("Could not pause clock while already paused"); + return; + } + // make sure to update time to the moment of pausing it + updateTime(); + // inform listeners + data_->paused = true; + for (const auto& listener : listeners_) { + listener(ClockEvent::PAUSE); + } + signalEventIPC(ClockEvent::PAUSE); +} + +bool ControllableClockIPC::setRealtimeFactor(double rtf) { + if (!simTime_) { + XR_LOGW("Could not set clock real time factor, using real time."); + return false; + } + if (!data_->paused) { + XR_LOGW("Could not set clock real time factor while running"); + return false; + } + data_->realtimeFactor = rtf; + for (const auto& listener : listeners_) { + listener(ClockEvent::RTF_UPDATE); + } + signalEventIPC(ClockEvent::RTF_UPDATE); + return true; +} + +bool ControllableClockIPC::setTime(double time) { + if (!simTime_) { + XR_LOGW("Could not set clock time, using real time."); + return false; + } + double reference = data_->latestTime; + if (!data_->paused) { + XR_LOGW("Could not set clock time while running"); + return false; + } + updateLatestTime(time, reference, true); + for (const auto& listener : listeners_) { + listener(ClockEvent::JUMP); + } + signalEventIPC(ClockEvent::JUMP); + return true; +} + +void ControllableClockIPC::signalEventIPC(const ClockEvent& event) { + ScopedLockIPC lock(data_->signal_lock); + data_->event = event; + data_->signal_count++; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockIPC.h b/Cthulhu/src/ClockIPC.h new file mode 100644 index 000000000..a24a62a12 --- /dev/null +++ b/Cthulhu/src/ClockIPC.h @@ -0,0 +1,86 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include "IPCEssentials.h" + +#include +#include +#include + +namespace cthulhu { + +struct ClockIPCData { + ClockIPCData() { + reset(); + } + + // Note: initialize all members in reset() + bool paused; + std::atomic latestTime; + double realtimeFactor; + double offset; // offset of the output time at start + double wallStartTime; // beginning of the time axis in wall time + + // These are used to signal events through IPC + uint32_t signal_count; + ConditionIPC signal_update; + mutable MutexIPC signal_lock; + ClockEvent event; + + // Resets the clock data stored in IPC + // + // If there are multiple references to this data, you should hold + // the signal_lock before calling this method. + void reset() { + paused = true; + latestTime = 0.0; + realtimeFactor = 1.0; + offset = 0.0; + wallStartTime = 0.0; + signal_count = 0; + } +}; + +class ClockIPC : public ClockInterface { + public: + ClockIPC(ClockIPCData* data, bool simTime = false); + virtual ~ClockIPC(); + + virtual double getTime() override; + + virtual inline bool isSimulated() const override { + return simTime_; + } + + protected: + virtual void updateTime() override; + + virtual void updateLatestTime(double desired, double reference, bool enableBackwards = false) + override; + + ClockIPCData* data_; + bool simTime_; +}; + +class ControllableClockIPC : public ControllableClockInterface, public ClockIPC { + public: + ControllableClockIPC(ClockIPCData* data); + virtual ~ControllableClockIPC(); + + void setControlLocal(); + + virtual bool start(double time = -1.) override; + virtual void pause() override; + virtual bool setRealtimeFactor(double rtf) override; + virtual bool setTime(double time) override; + + private: + void signalEventIPC(const ClockEvent& event); + bool localControl_; + std::thread thread_; + std::promise stopSignal_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockLocal.cpp b/Cthulhu/src/ClockLocal.cpp new file mode 100644 index 000000000..f4ee9cc0e --- /dev/null +++ b/Cthulhu/src/ClockLocal.cpp @@ -0,0 +1,115 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ClockLocal.h" + +#include + +namespace cthulhu { + +double ClockLocal::getTime() { + if (simTime_) { + if (!paused_) + updateTime(); + return latestTime_; + } + return getWallTime(); +} + +void ClockLocal::updateTime() { + double reference = latestTime_; + double wall = getWallTime(); + updateLatestTime(realtimeFactor_ * (wall - wallStartTime_) + offset_, reference); +} + +void ClockLocal::updateLatestTime(double desired, double reference, bool enableBackwards) { + double latest; + do { + latest = latestTime_; + if (latest < reference) { + break; + } + if ((enableBackwards && latest == desired) || (!enableBackwards && latest > desired)) { + break; + } + } while (!latestTime_.compare_exchange_weak(latest, desired)); +} + +bool ControllableClockLocal::start(double time) { + if (!simTime_) { + XR_LOGCI("Cthulhu", "Could not start clock, using real time."); + return false; + } + double reference = latestTime_; + if (!paused_) { + XR_LOGCI("Cthulhu", "Could not start clock that is currently running."); + return false; + } + + updateLatestTime(time, reference, true); + + wallStartTime_ = getWallTime(); + if (time >= 0.) { + offset_ = time; + for (const auto& listener : listeners_) { + listener(ClockEvent::JUMP); + } + } else { + offset_ = latestTime_; + } + paused_ = false; + for (const auto& listener : listeners_) { + listener(ClockEvent::START); + } + return true; +} + +void ControllableClockLocal::pause() { + if (!simTime_) { + XR_LOGCI("Cthulhu", "Could not pause clock, using real time."); + return; + } + if (paused_) { + XR_LOGCW("Cthulhu", "Could not pause clock while already paused"); + return; + } + updateTime(); + paused_ = true; + for (const auto& listener : listeners_) { + listener(ClockEvent::PAUSE); + } +} + +bool ControllableClockLocal::setRealtimeFactor(double rtf) { + if (!simTime_) { + XR_LOGCW("Cthulhu", "Could not set clock real time factor, using real time."); + return false; + } + if (!paused_) { + XR_LOGCW("Cthulhu", "Could not set clock real time factor while running"); + return false; + } + realtimeFactor_ = rtf; + for (const auto& listener : listeners_) { + listener(ClockEvent::RTF_UPDATE); + } + return true; +} + +bool ControllableClockLocal::setTime(double time) { + if (!simTime_) { + XR_LOGCW("Cthulhu", "Could not set clock time, using real time."); + return false; + } + double reference = latestTime_; + if (!paused_) { + XR_LOGCW("Cthulhu", "Could not set clock time while running"); + return false; + } + updateLatestTime(time, reference, true); + for (const auto& listener : listeners_) { + listener(ClockEvent::JUMP); + } + return true; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockLocal.h b/Cthulhu/src/ClockLocal.h new file mode 100644 index 000000000..7cf31c1e0 --- /dev/null +++ b/Cthulhu/src/ClockLocal.h @@ -0,0 +1,46 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include + +namespace cthulhu { + +class ClockLocal : public ClockInterface { + public: + ClockLocal(bool simTime = false) : simTime_(simTime), paused_(simTime_), latestTime_(0.) {} + virtual ~ClockLocal() = default; + + virtual double getTime() override; + + virtual inline bool isSimulated() const override { + return simTime_; + } + + protected: + virtual void updateTime() override; + virtual void updateLatestTime(double desired, double reference, bool enableBackwards = false) + override; + + bool simTime_; + bool paused_; + double realtimeFactor_ = 1.; + double offset_ = 0.0; // offset of the output time from the wallStartTime + double wallStartTime_ = 0.0; // beginning of the time axis in wall time + std::atomic latestTime_; +}; + +class ControllableClockLocal : public ControllableClockInterface, public ClockLocal { + public: + ControllableClockLocal() : ClockLocal(true) {} + virtual ~ControllableClockLocal() = default; + + virtual bool start(double time = -1.) override; + virtual void pause() override; + virtual bool setRealtimeFactor(double rtf) override; + virtual bool setTime(double time) override; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockManagerIPC.cpp b/Cthulhu/src/ClockManagerIPC.cpp new file mode 100644 index 000000000..169b0c3c3 --- /dev/null +++ b/Cthulhu/src/ClockManagerIPC.cpp @@ -0,0 +1,105 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ClockManagerIPC.h" + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +const std::shared_ptr ClockManagerIPC::controlClock( + const std::string& contextName) { + if (!data_->clockOwnerContext.empty() && + contextName.compare(data_->clockOwnerContext.c_str()) == 0) { + auto control_clock = std::dynamic_pointer_cast(clock()); + control_clock->setControlLocal(); + return control_clock; + } + XR_LOGCW( + "Cthulhu", "Could not provide a controllable clock to non-owning context {}", contextName); + return std::shared_ptr(); +} + +const std::shared_ptr ClockManagerIPC::clock() { + if (state_ == ClockManagerState::UNKNOWN) { + return std::shared_ptr(); + } + if (!clock_handle_) { + if (state_ == ClockManagerState::REAL) { + clock_handle_ = std::make_shared(&data_->clock); + } else { + clock_handle_ = std::make_shared(&data_->clock); + } + } + return clock_handle_; +} + +void ClockManagerIPC::setClockAuthority(bool simTime, const std::string& authorizedContext) { + ScopedLockIPC lock(data_->lock); + if (!data_->clockOwnerContext.empty() && + authorizedContext.compare(data_->clockOwnerContext.c_str()) != 0) { + XR_LOGE("Clock authority context mismatch with shared memory."); + } + data_->clockOwnerContext = authorizedContext.c_str(); + ClockManagerState newState = simTime ? ClockManagerState::SIM : ClockManagerState::REAL; + if (data_->state != ClockManagerState::UNKNOWN && data_->state != newState) { + XR_LOGE("Clock authority type mismatch with shared memory."); + } + data_->state = newState; + state_ = newState; +} + +ClockManagerIPC::ClockManagerIPC(ManagedSHM* shm) : shm_(shm) { + data_ = shm_->find_or_construct("ClockManager")(shm_->get_segment_manager()); + + if (data_ == nullptr) { + auto str = "Failed to open clock manager in shared memory."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + + // We're using an atomic in shared memory... it needs to be lock free. + // The C++ standard does not guarantee this, so its up to the compiler. + if (!std::atomic_is_lock_free(&data_->clock.latestTime)) { + auto str = "Cthulhu IPC requires that atomic be implemented lock-free."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + + ScopedLockIPC lock(data_->lock); + data_->reference_count++; + state_ = data_->state; +} + +bool ClockManagerIPC::nuke(ManagedSHM* shm) { + shm->destroy("ClockManager"); + return true; +} + +ClockManagerIPC::~ClockManagerIPC() { + if (clock_handle_.use_count() > 1 && log_enabled_) { + XR_LOGE("ClockManagerIPC - cleaning up while references to the clock are still out there!"); + } + + clock_handle_ = std::shared_ptr(); + + if (data_) { + ScopedLockIPC lock(data_->lock); + data_->reference_count--; + if (data_->reference_count == 0 || force_clean_) { + data_->reference_count = 0; + data_->clockOwnerContext.clear(); + data_->state = ClockManagerState::UNKNOWN; + data_->clock.reset(); + if (log_enabled_) { + XR_LOGD("Cleaning up ipc clock manager."); + } + } else if (log_enabled_) { + XR_LOGD("Not cleaning ipc clock manager, still references: {}", data_->reference_count); + } + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockManagerIPC.h b/Cthulhu/src/ClockManagerIPC.h new file mode 100644 index 000000000..6888d380b --- /dev/null +++ b/Cthulhu/src/ClockManagerIPC.h @@ -0,0 +1,55 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include "ClockIPC.h" + +#include + +namespace cthulhu { + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + ContextIPC; + +struct ClockManagerIPCData { + public: + ClockManagerIPCData(const CharAllocatorIPC& alloc) : clockOwnerContext(alloc) {} + + ContextIPC clockOwnerContext; + MutexIPC lock; + ClockIPCData clock; + uint32_t reference_count = 0; + ClockManagerState state = ClockManagerState::UNKNOWN; +}; + +class ClockManagerIPC : public ClockManagerInterface { + public: + ClockManagerIPC(ManagedSHM* shm); + + virtual ~ClockManagerIPC(); + + virtual const std::shared_ptr controlClock( + const std::string& contextName) override; + + virtual const std::shared_ptr clock() override; + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(ManagedSHM* shm); + + protected: + virtual void setClockAuthority(bool simTime = false, const std::string& authorizedContext = "") + override; + + private: + ManagedSHM* shm_; + + ClockManagerIPCData* data_ = nullptr; + + mutable std::shared_ptr clock_handle_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockManagerLocal.cpp b/Cthulhu/src/ClockManagerLocal.cpp new file mode 100644 index 000000000..34a7ed317 --- /dev/null +++ b/Cthulhu/src/ClockManagerLocal.cpp @@ -0,0 +1,28 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ClockManagerLocal.h" + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +const std::shared_ptr ClockManagerLocal::controlClock( + const std::string& contextName) { + if (!clockOwnerContext_.empty() && contextName.compare(clockOwnerContext_) == 0) { + return std::dynamic_pointer_cast(clock()); + } + XR_LOGCW( + "Cthulhu", "Could not provide a controllable clock to non-owning context {}", contextName); + return std::shared_ptr(); +} + +void ClockManagerLocal::setClockAuthority(bool simTime, const std::string& authorizedContext) { + assert(clockOwnerContext_.empty()); + clockOwnerContext_ = authorizedContext; + state_ = simTime ? ClockManagerState::SIM : ClockManagerState::REAL; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ClockManagerLocal.h b/Cthulhu/src/ClockManagerLocal.h new file mode 100644 index 000000000..1279f725e --- /dev/null +++ b/Cthulhu/src/ClockManagerLocal.h @@ -0,0 +1,42 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include "ClockLocal.h" + +#include + +namespace cthulhu { + +class ClockManagerLocal : public ClockManagerInterface { + public: + virtual const std::shared_ptr controlClock( + const std::string& contextName) override; + + inline virtual const std::shared_ptr clock() override { + if (state_ == ClockManagerState::UNKNOWN) { + return std::shared_ptr(); + } + if (!clock_) { + if (state_ == ClockManagerState::REAL) { + clock_ = std::make_shared(); + } else { + clock_ = std::make_shared(); + } + } + return clock_; + }; + + virtual ~ClockManagerLocal() = default; + + protected: + virtual void setClockAuthority(bool simTime = false, const std::string& authorizedContext = "") + override; + + private: + // The Clock + std::shared_ptr clock_; + std::string clockOwnerContext_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/Context.cpp b/Cthulhu/src/Context.cpp new file mode 100644 index 000000000..53068a710 --- /dev/null +++ b/Cthulhu/src/Context.cpp @@ -0,0 +1,281 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +Subscriber Context::subscribeGeneric( + const StreamID& streamIDRaw, + const std::function& sampleCallback, + const std::function& configCallback, + SubscriberOptions options) const { + StreamID streamID = applyNamespace(streamIDRaw); + + // When subscribing generically, the stream must exist already. If the stream does not exist, + // there's no way to just subscribe generically since there wouldn't be any type information. + // Throw an exception if the stream does not exist. + auto* stream = Framework::instance().streamRegistry()->getStream(streamID); + if (stream == nullptr) { + // Choose to return an inactive Subscriber here rather than throw an exception, since this a + // user error and not an error with Cthulhu. + XR_LOGCW( + "Cthulhu", + "Attempted to register generic single subscriber without topic {} existing already", + streamID); + return Subscriber(streamID); + } + + // Make sure we're not trying to use a configCallback on a basic stream + const auto typeID = stream->description().type(); + const auto typeInfo = Framework::instance().typeRegistry()->findTypeID(typeID); + if (typeInfo->isBasic() && configCallback != nullptr) { + // This is still user error, but an exception is thrown here to maintain consistency with the + // config callback checks in the rest of the Cthulhu codebase. + auto str = "Attempted to provide config callback on basic stream type"; + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Now that the callbacks match the stream, add a StreamConsumer for it. We can directly pass the + // callbacks that we received from the caller since no type conversions need to happen. + std::unique_ptr consumer(new StreamConsumer( + stream, sampleCallback, configCallback, options.consumerType == ConsumerType::ASYNC)); + + // Finally, register against the context registry and return a new subscriber. + if (ctx_ == nullptr) { + const auto err = "Attempted to register generic single subscriber against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + const auto& sid = stream->description().id(); + ctx_->registerSubscriber(std::vector{sid}); + return Subscriber(sid, std::move(consumer)); +} + +Subscriber Context::subscribeGeneric( + const StreamID& streamIDRaw, + const std::string& typeName, + const std::function& sampleCallback, + const std::function& configCallback, + SubscriberOptions options) const { + StreamID streamID = applyNamespace(streamIDRaw); + + // Get Type + auto type = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!type) { + auto str = "Failed to lookup type in registry: " + std::string(typeName); + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Make sure we're not trying to use a configCallback on a basic stream + if (type->isBasic() && configCallback != nullptr) { + auto str = "Attempted to provide config callback on basic stream type"; + XR_LOGCW("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + + // Get Streams from Registry + StreamDescription desc{streamID, type->typeID()}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (type->typeID() != si->description().type()) { + // Type mismatch detected + XR_LOGCW( + "Cthulhu", + "Type mismatch detected [stream ID: {}; Requested type ID: {} ({}). Actual type ID: {}]", + streamID, + type->typeID(), + type->typeName(), + si->description().type()); + return Subscriber(si->description().id()); + } + + // Now that the callbacks match the stream, add a StreamConsumer for it. We can directly pass the + // callbacks that we received from the caller since no type conversions need to happen. + std::unique_ptr consumer(new StreamConsumer( + si, sampleCallback, configCallback, options.consumerType == ConsumerType::ASYNC)); + + // Finally, register against the context registry and return a new subscriber. + if (ctx_ == nullptr) { + const auto err = + "Attempted to register generic single subscriber with type name against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + const auto& sid = si->description().id(); + ctx_->registerSubscriber(std::vector{sid}); + return Subscriber(sid, std::move(consumer)); +} + +MultiSubscriber Context::subscribeGeneric( + const std::vector& streamIDs, + const std::function&)>& sampleCallback, + const std::function&)>& configCallback, + const AlignerSamplesMetaCallback& samplesMetaCallback, + const AlignerConfigsMetaCallback& configsMetaCallback, + MultiSubscriberOptions options) const { + // Apply namespace to all streamIDs + std::vector streamIDs_ns; + streamIDs_ns.reserve(streamIDs.size()); + for (const auto& id : streamIDs) { + streamIDs_ns.emplace_back(applyNamespace(id)); + } + + // Ensure that all streamIDs exist already, and that they're all non-basic. Streams must exist + // since they cannot be created without type information, and they must all be non-basic to allow + // configurations to get propagated correctly with the default aligner. + std::vector streams; + streams.reserve(streamIDs_ns.size()); + for (const auto& streamID : streamIDs_ns) { + auto* stream = Framework::instance().streamRegistry()->getStream(streamID); + // Ensure stream exists + if (stream == nullptr) { + // Choose to return an inactive MultiSubscriber here rather than throw an exception, since + // this is a user error and not an error with Cthulhu. + XR_LOGCW( + "Cthulhu", + "{}", + "Attempted to register generic multi subscriber without topic {} existing already.", + streamID); + // Need to create a vector of StreamIDViews since there's no StreamID vector constructor. + std::vector streamIDs_view; + streamIDs_view.reserve(streamIDs.size()); + for (const auto& id : streamIDs) { + streamIDs_view.emplace_back(id); + } + return MultiSubscriber(streamIDs_view); + } + + const auto typeID = stream->description().type(); + const auto typeInfo = Framework::instance().typeRegistry()->findTypeID(typeID); + if (typeInfo->isBasic() && (configCallback != nullptr || configsMetaCallback != nullptr)) { + // This is still user error, but an exception is thrown here to maintain consistency with the + // config callback checks in the rest of the Cthulhu codebase. + auto str = "Found a basic stream when given config callback"; + XR_LOGCE("Cthulhu", "{}", str); + throw std::runtime_error(str); + } + streams.push_back(stream); + } + + // Hook up the aligner using the options provided by the user. + auto aligner = details::alignerFromOptions(options.alignerType, std::move(options.alignerPtr)); + aligner->setCallback(sampleCallback); + aligner->setConfigCallback(configCallback); + aligner->setSamplesMetaCallback(samplesMetaCallback); + aligner->setConfigsMetaCallback(configsMetaCallback); + + std::vector streamID_views; + streamID_views.reserve(streamIDs_ns.size()); + for (size_t i = 0; i < streamIDs_ns.size(); ++i) { + aligner->registerConsumer(streams[i], i); + streamID_views.push_back(streams[i]->description().id()); + } + aligner->finalize(); + + // Finally, register against the context registry and return a new multi subscriber. + if (ctx_ == nullptr) { + const auto err = "Attempted to register generic multi subscriber against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + ctx_->registerSubscriber(streamID_views); + return MultiSubscriber(streamID_views, std::move(aligner)); +} + +Publisher Context::advertise( + const StreamID& streamIDRaw, + const uint32_t typeID, + PublisherOptions options) const { + StreamID streamID = applyNamespace(streamIDRaw); + + // Get Stream from Registry + StreamDescription desc{streamID, typeID}; + auto si = Framework::instance().streamRegistry()->registerStream(desc); + if (typeID != si->description().type()) { + // Type mismatch detected + XR_LOGCW("Cthulhu", "Type mismatch detected [{}, {}]", typeID, si->description().type()); + return Publisher(si->description().id()); + } + + // Create Producer + std::unique_ptr producer( + new StreamProducer(si, ProducerType::ASYNC == options.producerType)); + + // Return Node + if (ctx_ == nullptr) { + const auto err = "Attempted to register single publisher against null context"; + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + const auto& sid = si->description().id(); + ctx_->registerPublisher(std::vector{sid}); + return Publisher(sid, std::move(producer)); +} + +Publisher Context::advertise( + const StreamID& streamIDRaw, + const std::string& typeName, + PublisherOptions options) const { + auto typeInfo = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!typeInfo) { + const auto err = std::string("Attempted to register stream with unrecognized type name \"") + + typeName + std::string("\""); + XR_LOGCE("Cthulhu", "{}", err); + throw std::runtime_error(err); + } + + return advertise(streamIDRaw, typeInfo->typeID(), options); +} + +template <> +bool Publisher::publish(const StreamSample& sample) { + if (!producer_ || !producer_->isActive()) { + XR_LOGCW( + "Cthulhu", + "Publish failed. Producer is {}null, Producer is {}active.", + producer_ ? "NOT " : "", + (producer_ && producer_->isActive()) ? "" : "NOT "); + } + + producer_->produceSample(sample); + return true; +} + +template <> +bool Publisher::configure(const StreamConfig& configuration) { + if (!producer_) { + return false; + } + + producer_->configureStream(configuration); + return true; +} + +SFoCBConfig::SFoCBConfig(const uint32_t typeID) try + : SFoCBConfig(Framework::instance().typeRegistry()->findTypeID(typeID)) { +} catch (...) { + XR_LOGE("No type info found with type ID '{}'", typeID); + throw; +} + +SFoCBConfig::SFoCBConfig(const std::string& typeName) try + : SFoCBConfig(Framework::instance().typeRegistry()->findTypeName(typeName)) { +} catch (...) { + // TODO(ianmcintyre) this failes to compile, and I don't know why... + // XR_LOGE("No type info found with type name {}", typeName); + throw; +} + +SFoCBConfig::SFoCBConfig(const TypeInfoInterfacePtr typeInfo) { + if (!typeInfo) { + throw std::runtime_error("Cthulhu type info not found!"); + } else { + config_.sampleSizeInBytes = typeInfo->sampleParameterSize(); + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ContextRegistryIPC.cpp b/Cthulhu/src/ContextRegistryIPC.cpp new file mode 100644 index 000000000..842808248 --- /dev/null +++ b/Cthulhu/src/ContextRegistryIPC.cpp @@ -0,0 +1,250 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ContextRegistryIPC.h" +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +std::string ContextInfoIPCHandle::name() const { + return std::string(data_->name_.data(), data_->name_.size()); +} + +bool ContextInfoIPCHandle::isPrivateNamespace() const { + return data_->private_ns_; +} + +int ContextInfoIPCHandle::getPid() const { + return data_->pid_; +} + +bool ContextInfoIPCHandle::getValid() const { + return data_->valid_.load(std::memory_order_acquire); +} + +void ContextInfoIPCHandle::setValid(bool valid) { + data_->valid_.store(valid, std::memory_order_release); +} + +std::vector ContextInfoIPCHandle::subscriptions() const { + ScopedLockIPC lock(data_->mutex); + + std::vector out_subs; + out_subs.reserve(data_->subscriptions_.size()); + for (const auto& sub : data_->subscriptions_) { + auto& out_sub = out_subs.emplace_back(); + out_sub.reserve(sub.size()); + for (const auto& s : sub) { + out_sub.emplace_back(s.c_str()); + } + } + + return out_subs; +} + +std::vector ContextInfoIPCHandle::publications() const { + ScopedLockIPC lock(data_->mutex); + + std::vector out_pubs; + out_pubs.reserve(data_->publications_.size()); + for (const auto& pub : data_->publications_) { + auto& out_pub = out_pubs.emplace_back(); + out_pub.reserve(pub.size()); + for (const auto& p : pub) { + out_pub.emplace_back(p.c_str()); + } + } + + return out_pubs; +} + +std::vector< + std::pair> +ContextInfoIPCHandle::transformations() const { + ScopedLockIPC lock(data_->mutex); + std::vector< + std::pair> + out_tfs; + out_tfs.reserve(data_->transformations_.size()); + + for (const auto& [inputs, outputs] : data_->transformations_) { + auto& [out_inputs, out_outputs] = out_tfs.emplace_back(); + out_inputs.reserve(inputs.size()); + out_outputs.reserve(outputs.size()); + for (const auto& input : inputs) { + out_inputs.emplace_back(input.c_str()); + } + for (const auto& output : outputs) { + out_outputs.emplace_back(output.c_str()); + } + } + + return out_tfs; +} + +void ContextInfoIPCHandle::registerSubscriber(const std::vector& streams) { + ScopedLockIPC lock(data_->mutex); + auto& back = data_->subscriptions_.emplace_back(alloc_); + for (const auto& stream : streams) { + back.emplace_back(stream.c_str(), alloc_); + } +} + +void ContextInfoIPCHandle::registerPublisher(const std::vector& streams) { + ScopedLockIPC lock(data_->mutex); + auto& back = data_->publications_.emplace_back(alloc_); + for (const auto& stream : streams) { + back.emplace_back(stream.c_str(), alloc_); + } +} + +void ContextInfoIPCHandle::registerTransformer( + const std::vector& inputs, + const std::vector& outputs) { + ScopedLockIPC lock(data_->mutex); + auto& [first, second] = data_->transformations_.emplace_back(alloc_, alloc_); + for (const auto& input : inputs) { + first.emplace_back(input.c_str(), alloc_); + } + + for (const auto& output : outputs) { + second.emplace_back(output.c_str(), alloc_); + } +} + +void ContextInfoIPCHandle::registerSubscriber(const std::vector& views) { + ScopedLockIPC lock(data_->mutex); + auto& back = data_->subscriptions_.emplace_back(alloc_); + for (const auto& view : views) { + back.emplace_back(view.data(), alloc_); + } +} + +void ContextInfoIPCHandle::registerPublisher(const std::vector& views) { + ScopedLockIPC lock(data_->mutex); + auto& back = data_->publications_.emplace_back(alloc_); + for (const auto& view : views) { + back.emplace_back(view.data(), alloc_); + } +} + +void ContextInfoIPCHandle::registerTransformer( + const std::vector& input_views, + const std::vector& output_views) { + ScopedLockIPC lock(data_->mutex); + auto& [first, second] = data_->transformations_.emplace_back(alloc_, alloc_); + for (const auto& input : input_views) { + first.emplace_back(input.data(), alloc_); + } + + for (const auto& output : output_views) { + second.emplace_back(output.data(), alloc_); + } +} + +ContextRegistryIPC::ContextRegistryIPC(ManagedSHM* shm) : shm_(shm) { + registryData_ = shm_->find_or_construct("ContextRegistry")( + shm_->get_segment_manager()); + + if (registryData_ == nullptr) { + const auto str = "Failed to open context registry in shared memory."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + + ScopedLockIPC lock(registryData_->mutex); + registryData_->referenceCount++; + XR_LOGD("reference count is now {}", registryData_->referenceCount); +} + +bool ContextRegistryIPC::nuke(ManagedSHM* shm) { + shm->destroy("ContextRegistry"); + return true; +} + +ContextRegistryIPC::~ContextRegistryIPC() { + if (registryData_) { + ScopedLockIPC lock(registryData_->mutex); + registryData_->referenceCount--; + if (registryData_->referenceCount == 0 || force_clean_) { + registryData_->referenceCount = 0; + registryData_->contexts.clear(); + if (log_enabled_) { + XR_LOGD("Cleaning up ipc context registry."); + } + } else { + if (log_enabled_) { + XR_LOGD( + "Not cleaning ipc context registry, still references: {}", + registryData_->referenceCount); + } + } + } +} + +ContextInfoInterface* ContextRegistryIPC::registerContext(std::string_view name, bool private_ns) { + ScopedLockIPC lock(registryData_->mutex); + + auto& back = registryData_->contexts.emplace_back(name, private_ns, shm_->get_segment_manager()); + ++registryData_->valid_contexts; // Need to track valid size separately to avoid looping. + XR_LOGD( + "adding context {}, {}, up to {} valid contexts out of {}", + std::string(name), + static_cast(&back), + registryData_->valid_contexts, + registryData_->contexts.size()); + + auto& handle = handles_.emplace_back(&back, shm_->get_segment_manager()); + return &handle; +} + +void ContextRegistryIPC::removeContext(ContextInfoInterface* handle) { + auto* ipc_handle = static_cast(handle); + ScopedLockIPC lock(registryData_->mutex); + + bool matched = false; + for (auto& ctx : registryData_->contexts) { + if (&ctx == ipc_handle->data_) { + ipc_handle->setValid(false); // Use the convenient handle we've been given + --registryData_->valid_contexts; + matched = true; + } + } + if (!matched) { + XR_LOGE("no match found for context {}", static_cast(ipc_handle->data_)); + return; + } + + XR_LOGD( + "removed context {} ({}), down to {} valid contexts out of {}", + ipc_handle->name(), + static_cast(ipc_handle->data_), + registryData_->valid_contexts, + registryData_->contexts.size()); + + // Rather than removing the context, as below, we simply mark the context as invalid. This keeps + // slightly more contexts stored in memory, but has the advantage of being able to handle badly + // behaving programs which don't keep contexts around permanently. Uncomment the following lines + // to completely remove the context instead. + // registryData_->contexts.remove_if([ipc_handle](auto& ctx) { + // return &ctx == ipc_handle->data_; + // }); + ipc_handle->data_ = nullptr; // Null the handle just in case someone decides to use it again +} + +// Identical implementation to allContexts(), but only returns valid contexts instead of all. +std::vector ContextRegistryIPC::contexts(bool all) const { + ScopedLockIPC lock(registryData_->mutex); + + std::vector out; + out.reserve(registryData_->contexts.size()); + for (auto& ctx : registryData_->contexts) { + if (all || ctx.valid_) { + out.emplace_back(new ContextInfoIPCHandle(&ctx, shm_->get_segment_manager())); + } + } + + return out; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ContextRegistryIPC.h b/Cthulhu/src/ContextRegistryIPC.h new file mode 100644 index 000000000..f559d3eef --- /dev/null +++ b/Cthulhu/src/ContextRegistryIPC.h @@ -0,0 +1,136 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include "IPCEssentials.h" + +#include +#include +#include +#include + +#include +#include + +namespace cthulhu { + +using SegmentManager = ManagedSHM::segment_manager; +using VoidAllocatorIPC = boost::interprocess::allocator; + +using StreamIDIPCAllocator = boost::interprocess::allocator; +using VectorStreamIDIPC = boost::interprocess::vector; +using VectorStreamIDIPCAllocator = + boost::interprocess::allocator; +using VectorVectorStreamIDIPC = + boost::interprocess::vector; + +using PairVectorVectorStreamIDIPC = std::pair; +using PairVectorVectorStreamIDIPCAllocator = + boost::interprocess::allocator; +using VectorPairVectorVectorStreamIDIPC = + boost::interprocess::vector; + +// Forward declare to use as friend in ContextInfoIPCHandle +class ContextRegistryIPC; + +struct ContextInfoIPCData { + StreamIDIPC name_; + bool private_ns_; + // PID is tracked to be able to differentiate between processes. There should be some more + // sophistication somewhere which allows the determination of IPC vs threading, but that may not + // belong here. + int pid_; + + // Store whether the IPC data is still valid. In some cases, Contexts are treated as ephemeral, + // which will normally remove the data from the registry. This is good default behavior, and what + // we want to tend towards, but keeping the data around so it's possible to either see history, or + // see what broken nodes have done, is important. + static_assert(std::atomic_bool::is_always_lock_free, "bool must be lock free!"); + std::atomic_bool valid_; + + mutable MutexIPC mutex; + VectorVectorStreamIDIPC publications_; + VectorVectorStreamIDIPC subscriptions_; + VectorPairVectorVectorStreamIDIPC transformations_; + + ContextInfoIPCData(std::string_view name, bool private_ns, const VoidAllocatorIPC& alloc) + : name_(name.data(), name.size(), alloc), + private_ns_(private_ns), + pid_(boost::interprocess::ipcdetail::get_current_process_id()), + valid_(true), + publications_(alloc), + subscriptions_(alloc), + transformations_(alloc) {} +}; + +class ContextInfoIPCHandle : public ContextInfoInterface { + public: + ContextInfoIPCHandle(ContextInfoIPCData* data, const VoidAllocatorIPC& alloc) + : data_(data), alloc_(alloc) {} + virtual ~ContextInfoIPCHandle() = default; + + std::string name() const override; + bool isPrivateNamespace() const override; + int getPid() const override; + bool getValid() const override; + void setValid(bool valid); + + std::vector subscriptions() const override; + std::vector publications() const override; + std::vector> transformations() const override; + + void registerSubscriber(const std::vector& streams) override; + void registerPublisher(const std::vector& streams) override; + void registerTransformer( + const std::vector& inputs, + const std::vector& outputs) override; + + void registerSubscriber(const std::vector& views) override; + void registerPublisher(const std::vector& views) override; + void registerTransformer( + const std::vector& input_views, + const std::vector& output_views) override; + + private: + ContextInfoIPCData* data_; + VoidAllocatorIPC alloc_; + + friend class ContextRegistryIPC; +}; + +using ContextInfoAllocType = + boost::interprocess::allocator; +using ContextInfoList = boost::interprocess::list; + +struct ContextRegistryIPCData { + MutexIPC mutex; + ContextInfoList contexts; + size_t valid_contexts = 0; + + // Must only be updated with mutex held + uint32_t referenceCount = 0; + + ContextRegistryIPCData(const VoidAllocatorIPC& alloc) : contexts(alloc) {} +}; + +class ContextRegistryIPC : public ContextRegistryInterface { + public: + ContextRegistryIPC(ManagedSHM* shm); + virtual ~ContextRegistryIPC(); + + ContextInfoInterface* registerContext(std::string_view name, bool private_ns = false) override; + void removeContext(ContextInfoInterface* handle) override; + std::vector contexts(bool all = false) const override; + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(ManagedSHM* shm); + + private: + ContextRegistryIPCData* registryData_ = nullptr; + std::list handles_; // These are the handles we've issued + ManagedSHM* shm_; +}; +} // namespace cthulhu diff --git a/Cthulhu/src/ContextRegistryLocal.cpp b/Cthulhu/src/ContextRegistryLocal.cpp new file mode 100644 index 000000000..137985eb5 --- /dev/null +++ b/Cthulhu/src/ContextRegistryLocal.cpp @@ -0,0 +1,42 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "ContextRegistryLocal.h" + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +ContextInfoInterface* ContextRegistryLocal::registerContext( + std::string_view name, + bool private_ns) { + // Return a raw pointer to the ContextInfoLocal. This is acceptable as the context info will be + // in scope for the lifetime of the Context. Doesn't matter if there's duplicates. + return contexts_.emplace_back(new ContextInfoLocal(name, private_ns)).get(); +} + +void ContextRegistryLocal::removeContext(ContextInfoInterface* handle) { + auto it = std::remove_if( + contexts_.begin(), contexts_.end(), [handle](auto& p) { return p.get() == handle; }); + + if (it == contexts_.end()) { // no elems removed + XR_LOGE("no elements removed"); + throw std::runtime_error("no elements removed"); + } + contexts_.erase(it, contexts_.end()); +} + +std::vector ContextRegistryLocal::contexts( + bool /* all unused */) const { + std::vector ret; + ret.reserve(contexts_.size()); + for (const auto& ctx : contexts_) { + // Copy construct the context info and store it in a new pointer + ret.emplace_back(new ContextInfoLocal(*ctx)); + } + return ret; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/ContextRegistryLocal.h b/Cthulhu/src/ContextRegistryLocal.h new file mode 100644 index 000000000..6f665c277 --- /dev/null +++ b/Cthulhu/src/ContextRegistryLocal.h @@ -0,0 +1,117 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +class ContextInfoLocal : public ContextInfoInterface { + public: + virtual ~ContextInfoLocal() = default; + + ContextInfoLocal(std::string_view name, bool private_ns) : name_(name), private_ns_(private_ns) {} + + inline std::string name() const override { + return name_; + } + + inline bool isPrivateNamespace() const override { + return private_ns_; + } + + inline int getPid() const override { + // This is local, so we don't have any IPC to worry about, and thus PID of 0 is fine. + return 0; + } + + inline bool getValid() const override { + // We remove contexts when they're destructed, so any contexts that can call this method are + // necessarily valid. + return true; + } + + inline std::vector subscriptions() const override { + return subscriptions_; + } + + inline std::vector publications() const override { + return publications_; + } + + inline std::vector> transformations() + const override { + return transformations_; + } + + inline void registerSubscriber(const std::vector& streams) override { + subscriptions_.emplace_back(streams); + } + + inline void registerPublisher(const std::vector& streams) override { + publications_.emplace_back(streams); + } + + inline void registerTransformer( + const std::vector& inputs, + const std::vector& outputs) override { + transformations_.emplace_back(inputs, outputs); + } + + inline void registerSubscriber(const std::vector& views) override { + // Copy from each of the views into a new StreamID + auto& streams = subscriptions_.emplace_back(); + streams.reserve(views.size()); + for (const auto& view : views) { + streams.emplace_back(view); + } + } + + inline void registerPublisher(const std::vector& views) override { + // Copy from each of the views into a new StreamID + auto& streams = publications_.emplace_back(); + streams.reserve(views.size()); + for (const auto& view : views) { + streams.emplace_back(view); + } + } + + inline virtual void registerTransformer( + const std::vector& input_views, + const std::vector& output_views) override { + auto& [inputs, outputs] = transformations_.emplace_back(); + + inputs.reserve(input_views.size()); + for (const auto& view : input_views) { + inputs.emplace_back(view); + } + + outputs.reserve(output_views.size()); + for (const auto& view : output_views) { + outputs.emplace_back(view); + } + } + + private: + std::string name_; + bool private_ns_; + std::vector subscriptions_; + std::vector publications_; + std::vector< + std::pair> + transformations_; +}; + +class ContextRegistryLocal : public ContextRegistryInterface { + public: + virtual ~ContextRegistryLocal() = default; + + ContextInfoInterface* registerContext(std::string_view name, bool private_ns = false) override; + void removeContext(ContextInfoInterface* handle) override; + std::vector contexts(bool all = false) const override; + + private: + std::vector> contexts_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/Dispatcher.cpp b/Cthulhu/src/Dispatcher.cpp new file mode 100644 index 000000000..0cccbff07 --- /dev/null +++ b/Cthulhu/src/Dispatcher.cpp @@ -0,0 +1,68 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +Dispatcher::Dispatcher(Dispatcher&& other) { + for (auto& producer : other.producers_) { + producers_.push_back(IdentifiedProducer(producer.first, std::move(producer.second))); + } +} + +Dispatcher& Dispatcher::operator=(Dispatcher&& other) { + for (auto& producer : other.producers_) { + producers_.push_back(IdentifiedProducer(producer.first, std::move(producer.second))); + } + return *this; +} + +void Dispatcher::registerProducer(StreamInterface* si) { + producers_.push_back( + IdentifiedProducer(si->description().id(), std::make_unique(si))); +}; + +void Dispatcher::dispatchSamples(const std::vector& samples) { + if (samples.size() != producers_.size()) { + throw std::exception(); + } + for (size_t i = 0; i < producers_.size(); i++) { + if (!producers_[i].second->isActive()) { + continue; + } + producers_[i].second->produceSample(samples[i]); + } +}; + +void Dispatcher::dispatchConfigs(std::vector& configs) { + if (configs.size() != producers_.size()) { + throw std::exception(); + } + for (size_t i = 0; i < producers_.size(); i++) { + if (!producers_[i].second->isActive()) { + continue; + } + producers_[i].second->configureStream(configs[i]); + } +}; + +void Dispatcher::configureStream(const StreamConfig& config, uint32_t streamNumber) { + if (streamNumber >= producers_.size()) { + XR_LOGW("Dispatcher - Attempted to configure a stream with invalid streamNumber. Ignoring."); + return; + } + producers_[streamNumber].second->configureStream(std::move(config)); +}; + +const StreamConfig* Dispatcher::streamConfig(uint32_t streamNumber) { + if (streamNumber >= producers_.size()) { + XR_LOGW("Dispatcher - Attempted to configure a stream with invalid streamNumber. Ignoring."); + return nullptr; + } + return producers_[streamNumber].second->config(); +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/FrameworkIPCHybrid.cpp b/Cthulhu/src/FrameworkIPCHybrid.cpp new file mode 100644 index 000000000..787e0d314 --- /dev/null +++ b/Cthulhu/src/FrameworkIPCHybrid.cpp @@ -0,0 +1,130 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +// IPC Hybrid Targets +#include "ClockManagerIPC.h" +#include "ContextRegistryIPC.h" +#include "MemoryPoolIPCHybrid.h" +#include "StreamRegistryIPCHybrid.h" +#include "TypeRegistryIPC.h" + +// Local targets +#include "ClockManagerLocal.h" +#include "ContextRegistryLocal.h" +#include "MemoryPoolLocal.h" +#include "StreamRegistryLocal.h" +#include "TypeRegistryLocal.h" + +#include + +#ifdef _WIN32 +#define DLLIMPORT __declspec(dllimport) +#else +#define DLLIMPORT +#endif + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +const static char* DEFAULT_SHM_NAME = "CthulhuSHM"; +const static char* SHM_NAME_ENV_VAR = "CTHULHU_SHM_NAME"; + +const static char* DISABLE_SHARED_MEMORY_ENV_VAR = "CTHULHU_DISABLE_SHARED_MEMORY"; +const static char* ENABLE_AUDITOR_ENV_VAR = "CTHULHU_ENABLE_AUDITOR"; + +static std::string shm_name() { + return std::getenv(SHM_NAME_ENV_VAR) ? std::getenv(SHM_NAME_ENV_VAR) : DEFAULT_SHM_NAME; +} + +extern DLLIMPORT Framework* getFramework(); + +struct FrameworkStorage { + FrameworkStorage() + : shmName(shm_name()), + sharedMemory(boost::interprocess::open_or_create, shmName.c_str(), shmSize) { + if (std::strcmp(shmName.c_str(), DEFAULT_SHM_NAME) != 0) { + XR_LOGD("Using non-default shared memory name: {}", shmName); + } else { + XR_LOGD("Using default shared memory name: {}", shmName); + } + } + const std::string shmName; + const size_t shmSize = 500 * 1024 * 1024; + const size_t shmGPUSize = 500 * 1024 * 1024; + ManagedSHM sharedMemory; +}; + +Framework& Framework::instance() { + return *getFramework(); +} + +Framework::Framework() : storage_(nullptr) { + if (!std::getenv(DISABLE_SHARED_MEMORY_ENV_VAR)) { + bool enableAuditor = std::getenv(ENABLE_AUDITOR_ENV_VAR) != nullptr; + bool memoryValid = false; + while (!memoryValid) { + storage_.reset(new FrameworkStorage()); + memoryPool_ = std::make_unique( + &storage_->sharedMemory, storage_->shmSize, storage_->shmGPUSize, enableAuditor); + if (memoryPool_->isValid()) { + memoryValid = true; + } else { + // we must destroy the pool before nuking to prevent segfaults in destruction + memoryPool_.reset(); + nuke(); + } + } + clockManager_ = std::make_unique(&storage_->sharedMemory); + contextRegistry_ = std::make_unique(&storage_->sharedMemory); + typeRegistry_ = std::make_unique(&storage_->sharedMemory); + streamRegistry_ = std::make_unique( + dynamic_cast(memoryPool_.get()), + typeRegistry_.get(), + &storage_->sharedMemory); + } else { + memoryPool_ = std::make_unique(); + clockManager_ = std::make_unique(); + typeRegistry_ = std::make_unique(); + streamRegistry_ = std::make_unique(); + contextRegistry_ = std::make_unique(); + } +} + +bool Framework::nuke() { +#if !defined(_WIN32) && !defined(__ANDROID__) + std::string name(shm_name()); + if (!boost::interprocess::shared_memory_object::remove(name.c_str())) { + try { + boost::interprocess::shared_memory_object exists( + boost::interprocess::open_only, name.c_str(), boost::interprocess::read_only); + } catch (boost::interprocess::interprocess_exception e) { + return e.get_error_code() == boost::interprocess::not_found_error; + } + return false; // this can only succeed if the section still exists + } + return true; +#else + FrameworkStorage storage; + return StreamRegistryIPCHybrid::nuke(&storage.sharedMemory) && + TypeRegistryIPC::nuke(&storage.sharedMemory) && + ContextRegistryIPC::nuke(&storage.sharedMemory) && + ClockManagerIPC::nuke(&storage.sharedMemory) && + MemoryPoolIPCHybrid::nuke(&storage.sharedMemory); +#endif +} + +void Framework::validate() { + auto memoryPool = Framework::instance().memoryPool(); + if (memoryPool != nullptr && !Framework::instance().memoryPool()->isValid()) { + throw std::runtime_error("Framework is not valid"); + } +} + +Framework::~Framework() { + cleanup(false, false); +} + +} // namespace cthulhu diff --git a/Cthulhu/src/FrameworkInstance.cpp b/Cthulhu/src/FrameworkInstance.cpp new file mode 100644 index 000000000..769459646 --- /dev/null +++ b/Cthulhu/src/FrameworkInstance.cpp @@ -0,0 +1,23 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#ifdef _WIN32 +#define DLLEXPORT __declspec(dllexport) +#else +#define DLLEXPORT +#endif + +namespace cthulhu { + +class FrameworkInstance { + public: + Framework framework; +}; + +extern DLLEXPORT Framework* getFramework() { + static FrameworkInstance finstance; + return &(finstance.framework); +} + +} // namespace cthulhu diff --git a/Cthulhu/src/IPCEssentials.h b/Cthulhu/src/IPCEssentials.h new file mode 100644 index 000000000..78d8fe747 --- /dev/null +++ b/Cthulhu/src/IPCEssentials.h @@ -0,0 +1,115 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +// Boost interpeocess uses date_time, which needs separable compilation +// Interprocess doesn't need this part of date_time, so disable +#define BOOST_DATE_TIME_NO_LIB + +// If anyone else has included interprocess_mutex.hpp, +// we must stop them. These changes need to be applied. +#if defined(BOOST_INTERPROCESS_MUTEX_HPP) +#error Must include Cthulhu's IPCEssentials.h before boost's interprocess_mutex.hpp +#endif + +#ifdef _WIN32 +// Note: By default, boost will use spin_mutex on Windows, which +// is much slower than native windows mutex. It uses atomic CAS +// on a shared address repeatedly until it works, which isn't +// great for performance +#include +#undef BOOST_INTERPROCESS_FORCE_GENERIC_EMULATION + +#include +#elif defined(__ANDROID__) +#define BOOST_INTERPROCESS_BUGGY_POSIX_PROCESS_SHARED +#include "boost/interprocess/managed_android_shared_memory.hpp" +#else +#include +#endif + +#include +#include +#include +#include +#include + +#if defined(__APPLE__) // T74434280 +#include +#include +#endif + +#include + +namespace cthulhu { + +// Sync types +using MutexIPC = boost::interprocess::interprocess_mutex; +using ConditionIPC = boost::interprocess::interprocess_condition; +using ScopedLockIPC = boost::interprocess::scoped_lock; + +// Shmem types +#ifdef _WIN32 +using ManagedSHM = boost::interprocess::managed_windows_shared_memory; +#elif defined(__ANDROID__) +using ManagedSHM = boost::interprocess::managed_android_shared_memory; +#elif defined(__APPLE__) // T74434280 +using ManagedSHM = boost::interprocess::basic_managed_shared_memory< + char, + boost::interprocess::simple_seq_fit, + boost::interprocess::iset_index>; +#else +using ManagedSHM = boost::interprocess::managed_shared_memory; +#endif + +using CharAllocatorIPC = boost::interprocess::allocator; +using StreamIDIPC = + boost::interprocess::basic_string, CharAllocatorIPC>; + +struct MemoryPoolIPC; +struct MemoryPoolGPUIPC; + +// Ptr types +using PtrAllocatorIPC = boost::interprocess::allocator; + +class ReclaimerIPC { + public: + typedef typename boost::intrusive::pointer_traits< + typename ManagedSHM::segment_manager::void_pointer>::template rebind_pointer::type + pointer; + + private: + boost::interprocess::offset_ptr host; + std::ptrdiff_t offset; + + public: + ReclaimerIPC(boost::interprocess::offset_ptr phost, std::ptrdiff_t off) + : host(phost), offset(off) {} + + void operator()(const pointer& p); +}; + +using GpuBufferDataWithPID = std::pair; + +class ReclaimerGPUIPC { + public: + typedef typename boost::intrusive:: + pointer_traits::template rebind_pointer< + GpuBufferDataWithPID>::type pointer; + + private: + boost::interprocess::offset_ptr host; + std::ptrdiff_t offset; + + public: + ReclaimerGPUIPC(boost::interprocess::offset_ptr phost, std::ptrdiff_t off) + : host(phost), offset(off) {} + + void operator()(const pointer& p); +}; + +using SharedPtrIPC = boost::interprocess::shared_ptr; +using SharedPtrGPUIPC = + boost::interprocess::shared_ptr; + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolIPC.cpp b/Cthulhu/src/MemoryPoolIPC.cpp new file mode 100644 index 000000000..d60bae941 --- /dev/null +++ b/Cthulhu/src/MemoryPoolIPC.cpp @@ -0,0 +1,39 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "MemoryPoolIPC.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#ifndef _WIN32 +#include +#endif + +namespace cthulhu { + +void ReclaimerIPC::operator()(const pointer& p) { + host->reclaim(offset); +} + +void MemoryPoolIPC::reclaim(std::ptrdiff_t off) { + size_t size = 0; + { + ScopedLockIPC lock(sizes_mutex); + const auto it = sizes.find(off); + if (it != sizes.cend()) + size = it->second; + } + { + ScopedLockIPC lock(buffers_mutex); + auto it = buffers.find(size); + if (it != buffers.end()) { + it->second.push_back(off); + } + } +} + +void ReclaimerGPUIPC::operator()(const pointer& p) { + host->reclaim(offset); +} + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolIPC.h b/Cthulhu/src/MemoryPoolIPC.h new file mode 100644 index 000000000..fb4bfa03b --- /dev/null +++ b/Cthulhu/src/MemoryPoolIPC.h @@ -0,0 +1,49 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#ifdef _WIN32 +#include +#endif +#include + +#include "IPCEssentials.h" + +#include +#include + +namespace cthulhu { + +struct MemoryPoolIPC { + friend class ReclaimerIPC; + friend class ReclaimerGPUIPC; + + typedef boost::interprocess::allocator + PtrVectorAllocType; + typedef boost::interprocess::vector PtrVectorType; + + typedef boost::interprocess:: + allocator, ManagedSHM::segment_manager> + BufferMapAllocType; + typedef boost::interprocess::map, BufferMapAllocType> + BufferMapType; + + typedef boost::interprocess::allocator, ManagedSHM::segment_manager> + SizeMapAllocType; + typedef boost::interprocess::map, SizeMapAllocType> SizeMapType; + + MemoryPoolIPC(ManagedSHM::segment_manager* mgr) : buffers(mgr), sizes(mgr) {} + + BufferMapType buffers; + MutexIPC buffers_mutex; + + SizeMapType sizes; + MutexIPC sizes_mutex; + + std::atomic allocated; + + private: + void reclaim(std::ptrdiff_t off); +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolIPCHybrid.cpp b/Cthulhu/src/MemoryPoolIPCHybrid.cpp new file mode 100644 index 000000000..3262ebc2a --- /dev/null +++ b/Cthulhu/src/MemoryPoolIPCHybrid.cpp @@ -0,0 +1,484 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "MemoryPoolIPCHybrid.h" + +#include "MemoryPoolLocalImpl.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace cthulhu { + +namespace { + +const char* const MEMORY_POOL_NAME = "MemoryPool"; +const char* const MEMORY_POOL_GPU_NAME = "MemoryPoolGPU"; +const char* const MEMORY_POOL_GPU_DEVICE_LOCAL_NAME = "MemoryPoolGPUDeviceLocal"; +const char* const AUDITOR_NAME = "Auditor"; + +} // namespace + +MemoryPoolIPCHybrid::MemoryPoolIPCHybrid( + ManagedSHM* shm, + size_t shmSize, + size_t shmGPUSize, + bool enableAuditor) + : shmSize_(shmSize), + shmGPUSize_(shmGPUSize), + memoryPool_(new MemoryPool()), + shm_(shm), + stopSignal_{false} { + pool_ = shm_->find_or_construct(MEMORY_POOL_NAME)(shm_->get_segment_manager()); + poolGPU_ = + shm_->find_or_construct(MEMORY_POOL_GPU_NAME)(shm_->get_segment_manager()); + poolGPUDeviceLocal_ = shm_->find_or_construct(MEMORY_POOL_GPU_DEVICE_LOCAL_NAME)( + shm_->get_segment_manager()); + auditor_ = shm_->find_or_construct(AUDITOR_NAME)(shm_->get_segment_manager()); + + vulkanUtil_.reset(new VulkanUtil()); + + // Setup auditing + ScopedLockIPC lock(auditor_->mutex); + if (audit()) { + auditor_->processes.emplace_back(); + if (enableAuditor) { + auditorThread_ = std::thread([this]() { + while (!stopSignal_.load()) { + std::this_thread::yield(); + + ScopedLockIPC lock(auditor_->mutex); + if (!audit()) { + if (!Framework::nuke()) { + XR_LOGE("Could not nuke framework"); + } + invalidate(); + break; + } + } + }); + } + } else { + invalidate(); + } +} + +bool MemoryPoolIPCHybrid::nuke(ManagedSHM* shm) { + shm->destroy(MEMORY_POOL_NAME); + shm->destroy(MEMORY_POOL_GPU_NAME); + shm->destroy(MEMORY_POOL_GPU_DEVICE_LOCAL_NAME); + shm->destroy(AUDITOR_NAME); + return true; +} + +bool MemoryPoolIPCHybrid::audit() const { + return isValid() && processesAlive(); +} + +bool MemoryPoolIPCHybrid::isValid() const { + return !auditor_->invalid; +} + +bool MemoryPoolIPCHybrid::processesAlive() const { + auto& processes = auditor_->processes; + for (auto it = processes.begin(); it != processes.end(); ++it) { + if (!it->isAlive()) { + return false; + } + } + return true; +} + +void MemoryPoolIPCHybrid::invalidate() { + auditor_->invalid = true; +} + +MemoryPoolIPCHybrid::~MemoryPoolIPCHybrid() { + ptrs_.clear(); + + // Stop the auditing thread + stopSignal_.store(true); + if (auditorThread_.joinable()) { + auditorThread_.join(); + } + + ScopedLockIPC lock(auditor_->mutex); + + // Deregister our own process from the auditor + auto& processes = auditor_->processes; + for (auto it = processes.begin(); it != processes.end(); ++it) { + if (it->isSelf()) { + processes.erase(it); + break; + } + } + + if (force_clean_) { + processes.clear(); + } + + if (auditor_->processes.empty()) { + invalidate(); + + // CPU Cleanup + ScopedLockIPC lock1(pool_->buffers_mutex); + ScopedLockIPC lock2(pool_->sizes_mutex); + for (auto& size : pool_->sizes) { + pool_->allocated -= size.second; + } + for (auto& buffers : pool_->buffers) { + for (auto& buffer : buffers.second) { + shm_->destroy_ptr(shm_->get_address_from_handle(buffer)); + } + } + pool_->buffers.clear(); + pool_->sizes.clear(); + } + + // Release local GPU handle caches + handlesGPU_.clear(); + gpuMappedBuffers_.clear(); + + // Cleanup the GPU pools if we have any + bool clearAllocations = auditor_->processes.empty(); + if (poolGPU_) { + cleanPool(poolGPU_, clearAllocations); + } + if (poolGPUDeviceLocal_) { + cleanPool(poolGPUDeviceLocal_, clearAllocations); + } + + // Delete any locally duplicated GPU handles + for (auto& handle : gpuHandleProcMap_) { + vulkanUtil_->free(handle.second); + } +} + +CpuBuffer MemoryPoolIPCHybrid::getBufferFromPool(const StreamIDView& id, size_t nrBytes) { + if ((activatedStreams_.find(id) == activatedStreams_.end()) || + (activatedStreams_.find(id) != activatedStreams_.end() && activatedStreams_[id])) { + auto shm = requestSHM(nrBytes); + if (!shm) { + XR_LOGE_EVERY_N( + 100, + "MemoryPoolIPCHybrid - Failed to get shared memory buffer for [{}] bytes. Allocated locally.", + nrBytes); + return memoryPool_->request(nrBytes); + } + return shm; + } + return memoryPool_->request(nrBytes); +} + +bool MemoryPoolIPCHybrid::findBuffer( + size_t nrBytes, + boost::interprocess::offset_ptr pool, + std::ptrdiff_t& offset_ptr_out, + GpuBufferDataWithPID*& ptr_out) { + ScopedLockIPC lock(pool->buffers_mutex); + auto buffer_it = pool->buffers.find(nrBytes); + if (buffer_it == pool->buffers.cend()) { + buffer_it = pool->buffers + .emplace( + nrBytes, + MemoryPoolIPC::PtrVectorType( + MemoryPoolIPC::PtrVectorAllocType(shm_->get_segment_manager()))) + .first; + } + + auto& ptrlist = buffer_it->second; + // Iterate through the list until we find one that originated from our process. + // Note: It may be useful to restructure our GPU pool to make it faster to find + // buffers originating from our process. +#ifdef _WIN32 + uint64_t ourPid = (uint64_t)GetCurrentProcessId(); +#else + uint64_t ourPid = (uint64_t)getpid(); +#endif + auto it = ptrlist.begin(); + while (it != ptrlist.end()) { + auto bufferPtr = reinterpret_cast(shm_->get_address_from_handle(*it)); + if (bufferPtr->second == ourPid) { + ptr_out = bufferPtr; + offset_ptr_out = *it; + it = ptrlist.erase(it); + return true; + } else { + ++it; + } + } + return false; +} + +GpuBuffer MemoryPoolIPCHybrid::getGpuBufferFromPool(size_t nrBytes, bool deviceLocal) { + if (!vulkanUtil_->isActive()) { + XR_LOGW("Failed to generate GPU Buffer. Vulkan is not active."); + return GpuBuffer(); + } + + std::ptrdiff_t offset_ptr = 0; + GpuBufferDataWithPID* ptr = nullptr; + + // Check to see if we already have a buffer of this size + boost::interprocess::offset_ptr pool = + deviceLocal ? poolGPUDeviceLocal_ : poolGPU_; + if (!findBuffer(nrBytes, pool, offset_ptr, ptr)) { + // Make a new buffer + ScopedLockIPC lock(pool->sizes_mutex); + if (deviceLocal) { + XR_LOGT_EVERY_N( + 10, "MemoryPoolIPCHybrid - Num GPU Device Local bytes allocated: ", pool->allocated); + } else { + XR_LOGT_EVERY_N(10, "MemoryPoolIPCHybrid - Num GPU bytes allocated: ", pool->allocated); + } + if (pool->allocated + nrBytes < shmGPUSize_) { + auto vulkanAllocation = vulkanUtil_->allocate(nrBytes, deviceLocal); + if (vulkanAllocation.first == 0) { + XR_LOGW("Failed to allocate vulkan buffer of size {}.", nrBytes); + return GpuBuffer(); + } + // Store a local map of the external memory, which adds a reference for the local process + gpuMappedBuffers_[vulkanAllocation.first] = + vulkanUtil_->map(vulkanAllocation.first, nrBytes, vulkanAllocation.second); +#ifdef _WIN32 + uint64_t pid = (uint64_t)GetCurrentProcessId(); +#else + uint64_t pid = (uint64_t)getpid(); +#endif + // Put the handle in shared memory + ptr = shm_->construct(boost::interprocess::anonymous_instance)(); + ptr->first.handle = vulkanAllocation.first; + ptr->first.size = nrBytes; + ptr->first.memoryTypeIndex = vulkanAllocation.second; + ptr->second = pid; + offset_ptr = shm_->get_handle_from_address(ptr); + pool->allocated += nrBytes; + pool->sizes.emplace(offset_ptr, nrBytes); + } else { + XR_LOGW( + "Failed to allocate GPU buffer of size {}. Max GPU memory size {} reached.", + nrBytes, + shmGPUSize_); + return GpuBuffer(); + } + } + + std::lock_guard lock(memoryMutex_); + + // Construct the shared shared pointer + SharedPtrGPUIPC& buffer = + *shm_->construct(boost::interprocess::anonymous_instance)( + ptr, PtrAllocatorIPC(shm_->get_segment_manager()), ReclaimerGPUIPC(pool, offset_ptr)); + + // Store the mapping to it + handlesGPU_.emplace(ptr->first.handle, buffer); + + shm_->destroy_ptr(&buffer); + + // Return a local pointer + return GpuBuffer( + &ptr->first, + [this](GpuBufferData* handlePtr) { this->destroyLocal(handlePtr); }, + deviceLocal ? CpuBuffer() : gpuMappedBuffers_[ptr->first.handle]); +} + +CpuBuffer MemoryPoolIPCHybrid::requestSHM(size_t nrBytes) { + std::ptrdiff_t offset_ptr = 0; + uint8_t* ptr = nullptr; + + // Check to see if we already have a buffer of this size + { + ScopedLockIPC lock(pool_->buffers_mutex); + auto buffer_it = pool_->buffers.find(nrBytes); + if (buffer_it == pool_->buffers.cend()) { + buffer_it = pool_->buffers + .emplace( + nrBytes, + MemoryPoolIPC::PtrVectorType( + MemoryPoolIPC::PtrVectorAllocType(shm_->get_segment_manager()))) + .first; + } + + auto& ptrlist = buffer_it->second; + if (!ptrlist.empty()) { + offset_ptr = ptrlist.back(); + ptr = reinterpret_cast(shm_->get_address_from_handle(offset_ptr)); + ptrlist.pop_back(); + } + } + + // Make a new buffer if needed + if (!ptr) { + ScopedLockIPC lock(pool_->sizes_mutex); + XR_LOGT_EVERY_N(100, "MemoryPoolIPCHybrid - Num shared bytes allocated: {}", pool_->allocated); + if (pool_->allocated + nrBytes < shmSize_ * MAX_SHM_USAGE_FRAC) { + ptr = shm_->construct(boost::interprocess::anonymous_instance)[nrBytes](); + offset_ptr = shm_->get_handle_from_address(ptr); + pool_->allocated += nrBytes; + pool_->sizes.emplace(offset_ptr, nrBytes); + } else { + return std::shared_ptr(); + } + } + + std::lock_guard lock(memoryMutex_); + + // Construct the shared shared pointer + SharedPtrIPC& buffer = *shm_->construct(boost::interprocess::anonymous_instance)( + ptr, PtrAllocatorIPC(shm_->get_segment_manager()), ReclaimerIPC(pool_, offset_ptr)); + + // Store the mapping to it + ptrs_.emplace(ptr, buffer); + + shm_->destroy_ptr(&buffer); + + // Return a local pointer + return CpuBuffer(ptr, [this](uint8_t* ptr) { this->destroyLocal(ptr); }); +} + +void MemoryPoolIPCHybrid::activateStream(const StreamIDView& streamID, bool active) { + activatedStreams_[streamID] = active; +} + +SharedPtrIPC MemoryPoolIPCHybrid::convert(const CpuBuffer& ptr) const { + std::lock_guard lock(memoryMutex_); + if (ptrs_.find(ptr.get()) != ptrs_.end()) { + return ptrs_.at(ptr.get()); + } + return SharedPtrIPC(); +} + +SharedPtrGPUIPC MemoryPoolIPCHybrid::convert(const GpuBuffer& ptr) const { + std::lock_guard lock(memoryMutex_); + if (handlesGPU_.find(ptr->handle) != handlesGPU_.end()) { + return handlesGPU_.at(ptr->handle); + } + return SharedPtrGPUIPC(); +} + +CpuBuffer MemoryPoolIPCHybrid::createLocal(const SharedPtrIPC& buffer) { + std::lock_guard lock(memoryMutex_); + auto pointer = buffer.get().get(); + ptrs_[pointer] = buffer; + return CpuBuffer(pointer, [this](uint8_t* ptr) { this->destroyLocal(ptr); }); +} + +void MemoryPoolIPCHybrid::destroyLocal(uint8_t* ptr) { + std::lock_guard lock(memoryMutex_); + ptrs_.erase(ptr); +} + +GpuBuffer MemoryPoolIPCHybrid::createLocal(const SharedPtrGPUIPC& buffer) { + std::lock_guard lock(memoryMutex_); + auto pointer = buffer.get().get(); + auto handle = pointer->first.handle; + + uint64_t newHandle = 0; + + if (gpuHandleProcMap_.find(handle) == gpuHandleProcMap_.end()) { + // Clone the handle into our process +#ifdef _WIN32 + uint64_t ourPID = (uint64_t)GetCurrentProcessId(); + HANDLE currentProcHandle = OpenProcess(PROCESS_ALL_ACCESS, true, ourPID); + HANDLE otherProcHandle = OpenProcess(PROCESS_DUP_HANDLE, false, pointer->second); + HANDLE tempHandle; + auto dupResult = DuplicateHandle( + otherProcHandle, + (HANDLE)handle, + currentProcHandle, + &tempHandle, + 0, + false, + DUPLICATE_SAME_ACCESS); + CloseHandle(currentProcHandle); + CloseHandle(otherProcHandle); + if (!dupResult) { + XR_LOGW( + "Failed to duplicate handle {} to process {}. GPU buffer failed to load to this process.", + handle, + ourPID); + return GpuBuffer(); + } + newHandle = (uint64_t)tempHandle; +#else + char fdPath[64]; // actual maximal length: 37 for 64bit systems + snprintf(fdPath, sizeof(fdPath), "/proc/%d/fd/%d", (int)pointer->second, (int)handle); + newHandle = open(fdPath, O_RDWR); // TBD: Are these sufficient permissions? +#endif + } else { + newHandle = gpuHandleProcMap_[handle]; + } + + gpuHandleProcMap_[handle] = newHandle; + + handlesGPU_[newHandle] = buffer; + + // Map to the CPU in this process if we haven't seen this before + if (gpuMappedBuffers_.find(newHandle) == gpuMappedBuffers_.end()) { + gpuMappedBuffers_[newHandle] = + vulkanUtil_->map(newHandle, pointer->first.size, pointer->first.memoryTypeIndex); + } + + return GpuBuffer( + new GpuBufferData{newHandle, pointer->first.size, pointer->first.memoryTypeIndex}, + [this](GpuBufferData* ptr) { + this->destroyLocal(ptr); + delete ptr; + }, + gpuMappedBuffers_[newHandle]); +} + +void MemoryPoolIPCHybrid::destroyLocal(GpuBufferData* handlePtr) { + std::lock_guard lock(memoryMutex_); + handlesGPU_.erase(handlePtr->handle); +} + +SharedPtrIPC MemoryPoolIPCHybrid::getBufferFromSharedPoolDirect(size_t nrBytes) { + return convert(requestSHM(nrBytes)); +} + +bool MemoryPoolIPCHybrid::isBufferFromPool(const AnyBuffer& buf) const { + return convert(buf); +} + +void MemoryPoolIPCHybrid::cleanPool( + boost::interprocess::offset_ptr pool, + bool clearAllocations) { + ScopedLockIPC lock1(pool->buffers_mutex); + ScopedLockIPC lock2(pool->sizes_mutex); + + // Regardless of reference count, clear out all buffers originating from this process. + // No-one else will try to recycle these buffers, and the underlying resource + // of any in-flight buffers will be preserved through their lifetimes. + if (vulkanUtil_->isActive()) { + AuditorIPC::Process ownProc; + uint64_t ourPid = ownProc.pid(); + for (auto& buffers : pool->buffers) { + for (auto& buffer : buffers.second) { + GpuBufferDataWithPID data = + *reinterpret_cast(shm_->get_address_from_handle(buffer)); + if (data.second == ourPid) { + vulkanUtil_->free(data.first.handle); + shm_->destroy_ptr(shm_->get_address_from_handle(buffer)); + } + } + } + } + pool->buffers.clear(); + + if (clearAllocations) { + for (auto& size : pool->sizes) { + pool->allocated -= size.second; + } + pool->sizes.clear(); + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolIPCHybrid.h b/Cthulhu/src/MemoryPoolIPCHybrid.h new file mode 100644 index 000000000..450f26afa --- /dev/null +++ b/Cthulhu/src/MemoryPoolIPCHybrid.h @@ -0,0 +1,116 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#include "AuditorIPC.h" +#include "MemoryPoolIPC.h" + +#include +#include + +namespace cthulhu { + +class MemoryPool; +struct MemoryPoolIPC; + +class MemoryPoolIPCHybrid : public MemoryPoolInterface { + public: + MemoryPoolIPCHybrid(ManagedSHM* shm, size_t shmSize, size_t shmGPUSize, bool enableAuditor); + virtual ~MemoryPoolIPCHybrid(); + + virtual CpuBuffer getBufferFromPool(const StreamIDView& id, size_t nrBytes) override; + + virtual GpuBuffer getGpuBufferFromPool(size_t nrBytes, bool deviceLocal) override; + + virtual bool isBufferFromPool(const AnyBuffer& buf) const override; + + // Gets the underlying IPC shared pointer for a local pointer + // Returns null if the pointer did not come from this pool of shared memory buffers + SharedPtrIPC convert(const CpuBuffer& ptr) const; + SharedPtrGPUIPC convert(const GpuBuffer& ptr) const; + + CpuBuffer createLocal(const SharedPtrIPC& buffer); + GpuBuffer createLocal(const SharedPtrGPUIPC& buffer); + + // Toggles whether a particular stream will actively allocate data from shared memory + // for IPC. If false, it will use local memory buffers. + void activateStream(const StreamIDView& streamID, bool active); + + SharedPtrIPC getBufferFromSharedPoolDirect(size_t nrBytes); + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(ManagedSHM* shm); + + // Test whether the current section has not been invalidated, and that all of the + // connected processes are still alive. + // + // This will return true if the current state of the pool is valid. + bool isValid() const override; + + // Mark this section as killed + // + // This serves as an indication to any attached processes that the section is no longer + // valid and should be disconnected from as soon as possible, with no further interactions. + void invalidate() override; + + private: + // when audit fails, this section is toast + bool audit() const; + + bool processesAlive() const; + + void destroyLocal(uint8_t* ptr); + void destroyLocal(GpuBufferData* ptr); + + void cleanPool(boost::interprocess::offset_ptr pool, bool clearAllocations); + + bool findBuffer( + size_t nrBytes, + boost::interprocess::offset_ptr pool, + std::ptrdiff_t& offset_ptr_out, + GpuBufferDataWithPID*& ptr_out); + + CpuBuffer requestSHM(size_t nrBytes); + + boost::interprocess::offset_ptr killSignal_; + + boost::interprocess::offset_ptr pool_; + std::unordered_map ptrs_; + + boost::interprocess::offset_ptr poolGPU_; + boost::interprocess::offset_ptr poolGPUDeviceLocal_; + std::unordered_map gpuHandleProcMap_; + std::unordered_map handlesGPU_; + std::unordered_map> gpuMappedBuffers_; + + size_t shmSize_; + uint64_t shmGPUSize_; + + std::unique_ptr memoryPool_; + mutable std::mutex memoryMutex_; + + ManagedSHM* shm_; + + std::map activatedStreams_; + + // The auditor shared object and associated local data. + // This should be moved out of memory pool and into its own object + // in FrameworkIPCHybrid + boost::interprocess::offset_ptr auditor_; + std::thread auditorThread_; + std::atomic stopSignal_; + + std::unique_ptr vulkanUtil_; + + // The percentage of Cthulhu's shared memory that is permitted to be occupied + // by the memory pool. + static constexpr float MAX_SHM_USAGE_FRAC = 0.9; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolLocal.cpp b/Cthulhu/src/MemoryPoolLocal.cpp new file mode 100644 index 000000000..b9cec66b2 --- /dev/null +++ b/Cthulhu/src/MemoryPoolLocal.cpp @@ -0,0 +1,111 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "MemoryPoolLocal.h" + +#include "MemoryPoolLocalImpl.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +MemoryPoolLocal::MemoryPoolLocal() + : memoryPool_(new MemoryPool()), allocatedGPU_(0), allocatedMaxGPU_(500 * 1024 * 1024) { + vulkanUtil_.reset(new VulkanUtil()); +} + +MemoryPoolLocal::~MemoryPoolLocal() { + // Cleanup GPU Pool + for (auto& GpuBufferSizeClass : GpuBuffers_) { + for (auto& GpuBuffer : GpuBufferSizeClass.second) { + vulkanUtil_->free(GpuBuffer.handle); + } + } +} + +CpuBuffer MemoryPoolLocal::getBufferFromPool(const StreamIDView& id, size_t nrBytes) { + return memoryPool_->request(nrBytes); +}; + +GpuBuffer MemoryPoolLocal::getGpuBufferFromPool(size_t nrBytes, bool deviceLocal) { + if (!vulkanUtil_->isActive()) { + XR_LOGW("Failed to generate GPU Buffer. Vulkan is not active."); + return GpuBuffer(); + } + + // Try to find an existing buffer + GpuBufferData existing; + if (findBufferData(nrBytes, deviceLocal ? GpuDeviceLocalBuffers_ : GpuBuffers_, existing)) { + return createGpuBuffer(existing); + } + + if (allocatedMaxGPU_ <= allocatedGPU_ + nrBytes) { + XR_LOGW("Failed to allocate GPU buffer, reached allocated max: {}", allocatedMaxGPU_); + return GpuBuffer(); + } + + // Allocate a new buffer + auto vulkanAllocation = vulkanUtil_->allocate(nrBytes, deviceLocal); + if (vulkanAllocation.first == 0) { + return GpuBuffer(); + } + GpuBufferData result; + result.handle = vulkanAllocation.first; + result.size = nrBytes; + result.memoryTypeIndex = vulkanAllocation.second; + + allocatedGPU_ += nrBytes; + + // Store a local map of the external memory, which adds a reference for the local process + if (!deviceLocal) { + gpuMappedBuffers_[vulkanAllocation.first] = + vulkanUtil_->map(vulkanAllocation.first, nrBytes, vulkanAllocation.second); + } + + return createGpuBuffer(result); +} + +void MemoryPoolLocal::reclaimGPU(const GpuBufferData* ptr) { + { + std::lock_guard lock(GpuBuffersMutex_); + bool deviceLocal = vulkanUtil_->isDeviceLocal(ptr->memoryTypeIndex); + auto bufferIt = + deviceLocal ? GpuDeviceLocalBuffers_.find(ptr->size) : GpuBuffers_.find(ptr->size); + auto& bufferList = bufferIt->second; + bufferList.push_back(*ptr); + } +} + +bool MemoryPoolLocal::isBufferFromPool(const AnyBuffer& buf) const { + return true; +} + +size_t MemoryPoolLocal::getMaxSizeBytes() const noexcept { + return MemoryPool::ALLOCATED_MAX_BYTES; +} + +GpuBuffer MemoryPoolLocal::createGpuBuffer(const GpuBufferData& data) { + return GpuBuffer( + new GpuBufferData(data), + [this](const GpuBufferData* ptr) -> void { reclaimGPU(ptr); }, + vulkanUtil_->isDeviceLocal(data.memoryTypeIndex) ? CpuBuffer() + : gpuMappedBuffers_[data.handle]); +} + +bool MemoryPoolLocal::findBufferData(size_t nrBytes, GpuBuffers& buffers, GpuBufferData& out) { + std::lock_guard lock(GpuBuffersMutex_); + auto bufferIt = buffers.find(nrBytes); + if (bufferIt == buffers.cend()) { + bufferIt = buffers.emplace(nrBytes, std::vector()).first; + } + + auto& bufferList = bufferIt->second; + if (!bufferList.empty()) { + out = bufferList.back(); + bufferList.pop_back(); + return true; + } + return false; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolLocal.h b/Cthulhu/src/MemoryPoolLocal.h new file mode 100644 index 000000000..8428b5b56 --- /dev/null +++ b/Cthulhu/src/MemoryPoolLocal.h @@ -0,0 +1,55 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include + +namespace cthulhu { + +class MemoryPool; + +class MemoryPoolLocal : public MemoryPoolInterface { + public: + MemoryPoolLocal(); + virtual ~MemoryPoolLocal(); + + virtual CpuBuffer getBufferFromPool(const StreamIDView& id, size_t nrBytes) override; + virtual GpuBuffer getGpuBufferFromPool(size_t nrBytes, bool device_local) override; + virtual bool isBufferFromPool(const AnyBuffer& buf) const override; + + // Returns the maximum size of the memory pool + size_t getMaxSizeBytes() const noexcept; + + virtual void invalidate() override {} + + virtual bool isValid() const override { + return true; + } + + private: + typedef std::map> GpuBuffers; + + void reclaimGPU(const GpuBufferData* ptr); + + bool findBufferData(size_t nrBytes, GpuBuffers& buffers, GpuBufferData& out); + + GpuBuffer createGpuBuffer(const GpuBufferData& data); + + // CPU Memory Pool + std::unique_ptr memoryPool_; + + // GPU Memory Pool + std::unique_ptr vulkanUtil_; + + GpuBuffers GpuBuffers_; + GpuBuffers GpuDeviceLocalBuffers_; + std::mutex GpuBuffersMutex_; + std::unordered_map> gpuMappedBuffers_; + std::atomic allocatedGPU_; + const size_t allocatedMaxGPU_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolLocalImpl.cpp b/Cthulhu/src/MemoryPoolLocalImpl.cpp new file mode 100644 index 000000000..5b852c089 --- /dev/null +++ b/Cthulhu/src/MemoryPoolLocalImpl.cpp @@ -0,0 +1,137 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "MemoryPoolLocalImpl.h" + +namespace cthulhu { + +MemoryPool::Reclaimer::Reclaimer(MemoryPool* _host, const std::shared_ptr& _sentinel) + : host(_host), sentinel(_sentinel) {} + +void MemoryPool::Reclaimer::operator()(void* ptr) const { + // sentinel.expired would return true if the shared_ptr out of which this weak_ptr + // is constructed has been deleted. This call is guaranteed to be thread-safe by the + // standard. The deconstruction of the sentinel in the buffer pool instance takes + // place before any other book-keeping entities are deleted. In case of expiration, + // we simply call operator delete[]; otherwise, we request the host to reclaim. + + if (sentinel.expired()) { + delete[] static_cast(ptr); + } else { + host->reclaim(ptr); + } +} + +std::shared_ptr MemoryPool::request(size_t nrBytes) { + void* ptr = nullptr; + + { + // First of all, we look into the existent pool of buffers of the requested size + // to see if there is anything directly usable; if false, a container of pointers + // is created. In either case, we attempt to pull one of those allocated buffers + // from the pool (which automatically fails if it is just created). + + std::lock_guard lock(storeMutex_); + auto store_it = store_.find(nrBytes); + if (store_it == store_.end()) { + store_it = + store_ + .emplace( + std::piecewise_construct, std::forward_as_tuple(nrBytes), std::forward_as_tuple()) + .first; + } + + auto& ptrlist = store_it->second; + if (!ptrlist.empty()) { + ptr = ptrlist.back(); + ptrlist.pop_back(); + } + } + + // Now, if ptr is still null, we would need to allocate some new space for it. + // This should only happen if the FIFO is not being dequeued promptly. We check + // to see if allocating more space to lead to exceeding the byte limitation, + // and attempt to shrink the buffer pool if necessary. An attempt is then made + // to invoke operator new to get some space from the system, and the size lookup + // table is updated accordingly. + + if (!ptr) { + if (allocated_ + nrBytes > allocatedMax_) + shrink(); + if (allocated_ + nrBytes <= allocatedMax_) { + if ((ptr = new (std::nothrow) MemoryPool::ByteType[nrBytes]{0})) { + allocated_ += nrBytes; + { + std::lock_guard lock(sizesMutex_); + sizes_.emplace(reinterpret_cast(ptr), nrBytes); + } + } + } + } + + return std::shared_ptr(static_cast(ptr), Reclaimer(this, sentinel_)); +} + +void MemoryPool::reclaim(void* ptr) { + // This method is called from the reclaimer to recycle the pointer + // (and its associated memory space, of course) to the memory pool. + // No action is taken if this pointer is not allocated by this pool. + + size_t size = 0; + { + std::lock_guard lock(sizesMutex_); + const auto it = sizes_.find(reinterpret_cast(ptr)); + if (it != sizes_.cend()) + size = it->second; + } + { + std::lock_guard lock(storeMutex_); + store_[size].push_back(ptr); + } +} + +size_t MemoryPool::shrink() { + size_t shrinked = 0; + decltype(store_) empty; + { + std::lock_guard lock(storeMutex_); + store_.swap(empty); + } + + // To avoid holding the mutex for an excessive amount of time, we first swap + // the content of the memory pool with some local container; this means that + // any operation on the previous memory pool will be on the local object that + // is not subject to thread-safety considerations. Also, a list of memory areas + // to be deallocated is maintained for deferred maintenance of the size table. + + std::vector to_deallocate; + for (auto& pair : empty) { + for (auto& ptr : pair.second) { + to_deallocate.push_back(reinterpret_cast(ptr)); + delete[] static_cast(ptr); + + allocated_ -= pair.first; + shrinked += pair.first; + } + } + + { + std::lock_guard lock(sizesMutex_); + for (const auto& address : to_deallocate) + sizes_.erase(address); + } + + return shrinked; +} + +size_t MemoryPool::bytesAllocated() const { + return allocated_; +} + +MemoryPool::~MemoryPool() { + shrink(); +} + +MemoryPool::MemoryPool(size_t allocatedMax) + : allocated_(0), allocatedMax_(allocatedMax), sentinel_(new size_t) {} + +} // namespace cthulhu diff --git a/Cthulhu/src/MemoryPoolLocalImpl.h b/Cthulhu/src/MemoryPoolLocalImpl.h new file mode 100644 index 000000000..e2a53f3d1 --- /dev/null +++ b/Cthulhu/src/MemoryPoolLocalImpl.h @@ -0,0 +1,58 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include + +namespace cthulhu { + +class MemoryPool { + using ByteType = uint8_t; + + struct Reclaimer { + //! Construct a buffer reclaimer for the specified buffer pool host. + Reclaimer(MemoryPool* _host, const std::shared_ptr& _sentinel); + //! The method to be invoked to reclaim the buffer. + void operator()(void* ptr) const; + + protected: + MemoryPool* host; //!< A pointer to the host that this reclaimer is servicing. + std::weak_ptr + sentinel; //!< The expiration of this sentinel indicates the deconstruction of the host. + }; + + public: + static constexpr size_t ALLOCATED_MAX_BYTES = 1 << 30; + MemoryPool(size_t allocatedMax = ALLOCATED_MAX_BYTES); + virtual ~MemoryPool(); + + //! Request a memory area of the specified size from the memory pool. + std::shared_ptr request(size_t nrBytes); + + //! Release all the memory areas that are allocated but not currently used. + size_t shrink(); + + //! Retrieve the number of bytes that the current memory pool occupies. + size_t bytesAllocated() const; + + private: + friend struct Reclaimer; + //! Reclaim a memory area back to the memory pool. + void reclaim(void* ptr); + + std::atomic allocated_; + std::atomic allocatedMax_; + std::mutex storeMutex_, sizesMutex_; + std::unordered_map sizes_; + std::unordered_map> store_; + std::shared_ptr sentinel_; + // The reclaimer maintains a weak reference to this sentinel. The deletion + // of this sentinel will result in the reclaimer to be alerted, and not + // invoke the reclaim method in this instance anymore. +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/PerformanceMonitor.cpp b/Cthulhu/src/PerformanceMonitor.cpp new file mode 100644 index 000000000..3f3493860 --- /dev/null +++ b/Cthulhu/src/PerformanceMonitor.cpp @@ -0,0 +1,46 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +void PerformanceMonitor::startMeasurement() { + XR_DEV_CHECK(!startTime_, "Cannot start two performance measurements"); + startTime_ = ClockType::now(); +} + +void PerformanceMonitor::endMeasurement() { + XR_DEV_CHECK(startTime_, "Tried to end performance measurement when none was in progress"); + std::chrono::duration runtime = ClockType::now() - startTime_.value(); + startTime_.reset(); + + std::scoped_lock summaryLock(summaryMutex_); + + summary_.numCalls++; + + if (summary_.numCalls == 1) { + // First measurement + summary_.minRuntime = summary_.meanRuntime = summary_.maxRuntime = summary_.totalRuntime; + } else { + summary_.minRuntime = runtime < summary_.minRuntime ? runtime : summary_.minRuntime; + summary_.maxRuntime = runtime > summary_.maxRuntime ? runtime : summary_.maxRuntime; + summary_.totalRuntime += runtime; + summary_.meanRuntime = summary_.totalRuntime / (double)summary_.numCalls; + } +} + +void PerformanceMonitor::sampleDropped() { + std::scoped_lock summaryLock(summaryMutex_); + summary_.numSamplesDropped++; +} + +PerformanceSummary PerformanceMonitor::getSummary() { + std::scoped_lock summaryLock(summaryMutex_); + // Copy summary_ so that continued writes to it will not affect the returned summary + return PerformanceSummary(summary_); +} + +}; // namespace cthulhu diff --git a/Cthulhu/src/QueueingAligner.cpp b/Cthulhu/src/QueueingAligner.cpp new file mode 100644 index 000000000..cab21fdce --- /dev/null +++ b/Cthulhu/src/QueueingAligner.cpp @@ -0,0 +1,160 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +namespace cthulhu { + +QueueingAligner::QueueingAligner(const float& outputRate) + : AlignerBase(ThreadPolicy::SINGLE_THREADED), outputRate_(outputRate) { + initThread(); +} + +QueueingAligner::~QueueingAligner() {} + +// Note: This is copy-paste from the standard Aligner +void QueueingAligner::registerConsumer(StreamInterface* si, int index) { + if (finalized_) { + XR_LOGE("Attempted to register a consumer after being finalized."); + return; + } + { + std::lock_guard lock(queueMutex_); + if (queues_.size() <= index) { + queues_.resize(index + 1); + } + } + SampleCallback callback = [this, index](const StreamSample& sample) -> void { + sampleCallback(index, sample); + }; + ConfigCallback ccallback = [this, index](const StreamConfig& config) -> bool { + return configCallback(index, config); + }; + queues_[index].id = si->description().id(); + queues_[index].consumer = std::make_unique(si, callback, ccallback); +} + +void QueueingAligner::align() { + if (!finalized_) { + return; + } + + std::chrono::time_point start = std::chrono::steady_clock::now(); + + std::vector samples; + samples.reserve(queues_.size()); + AlignerSamplesMeta samplesMeta; + samplesMeta.reserve(queues_.size()); + { + // We're safe to access queues_.size() outside of the lock, + // since we guarantee that the size will not change after + // finalization. + std::lock_guard lock(queueMutex_); + + if (!configured_) { + // Try to configure + bool updateConfig = true; + for (auto& queue : queues_) { + updateConfig = updateConfig && queue.hasConfig; + } + if (updateConfig) { + std::vector configs; + configs.reserve(queues_.size()); + AlignerConfigsMeta meta; + meta.reserve(queues_.size()); + for (const auto& queue : queues_) { + configs.push_back(queue.config); + meta.push_back(AlignerStreamMeta{queue.id, queue.config.sampleSizeInBytes}); + } + inhibitSampleCallback_ = !alignedConfigCallback(configs); + configured_ = true; + alignedConfigsMetaCallback(meta); + } + } + + if (configured_) { + // Aggregate samples and meta + for (auto& queue : queues_) { + StreamSample sample; + AlignerSampleMeta meta; + if (!queue.samples.empty()) { + sample.parameters = queue.samples.front().parameters; + sample.metadata = queue.samples.front().metadata; + meta.timestamp = queue.samples.front().metadata->header.timestamp; + // TBD: Should we propagate the history timestamps all of inputs? + } + // Note: we still propagate empty samples + int payloadSize = std::accumulate( + queue.samples.begin(), + queue.samples.end(), + 0, + [](int val, const StreamSample& next) -> int { return val + next.numberOfSubSamples; }); + sample.payload = Framework::instance().memoryPool()->getBufferFromPool( + queue.id, payloadSize * queue.config.sampleSizeInBytes); + meta.references.reserve(queue.samples.size()); + int index = 0; + for (const auto& inputSample : queue.samples) { + AlignerReferenceMeta reference; + std::memcpy( + ((CpuBuffer)sample.payload).get() + index * queue.config.sampleSizeInBytes, + ((CpuBuffer)inputSample.payload).get(), + inputSample.numberOfSubSamples * queue.config.sampleSizeInBytes); + index += inputSample.numberOfSubSamples; + reference.sequenceNumber = inputSample.metadata->header.sequenceNumber; + reference.subSampleOffset = 0; + reference.numSubSamples = inputSample.numberOfSubSamples; + meta.references.push_back(reference); + } + sample.numberOfSubSamples = payloadSize; + samples.push_back(sample); + samplesMeta.push_back(meta); + queue.samples.clear(); + } + } + } + + if (samples.size() == queues_.size()) { + if (!inhibitSampleCallback_) { + alignedSamplesMetaCallback(samplesMeta); + alignedCallback(samples); + } + } + + std::chrono::time_point end = std::chrono::steady_clock::now(); + auto ms = std::chrono::duration_cast(end - start).count(); + // The AlignerBase will sleep for 1ms, so offset this in our calculation + int delayInMs = (1000.0 / outputRate_) - ms - 1.0; + if (delayInMs > 0.0) { + std::this_thread::sleep_for(std::chrono::milliseconds(delayInMs)); + } +} + +void QueueingAligner::sampleCallback(size_t idx, const StreamSample& sample) { + { + std::lock_guard lock(queueMutex_); + queues_[idx].latestSequence = sample.metadata->header.sequenceNumber; + queues_[idx].samples.push_back(sample); + } +} + +bool QueueingAligner::configCallback(size_t idx, const StreamConfig& config) { + std::unique_lock lock(queueMutex_); + if (queues_[idx].hasConfig) { + lock.unlock(); + XR_LOGE( + "QueueingAligner received reconfiguration on a stream, which it does not support. " + "Turning off..."); + return false; + } + queues_[idx].config = config; + queues_[idx].hasConfig = true; + return true; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/RawDynamic.cpp b/Cthulhu/src/RawDynamic.cpp new file mode 100644 index 000000000..d30dafd61 --- /dev/null +++ b/Cthulhu/src/RawDynamic.cpp @@ -0,0 +1,27 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +#include + +namespace cthulhu { + +template <> +CpuBuffer RawDynamic<>::getBuffer() const { + return Framework::instance().memoryPool()->getBufferFromPool("", size()); +} + +template <> +RawDynamic<>::RawDynamic(CpuBuffer& buf, size_t count) + : elementCount(count), elementSize(sizeof(uint8_t)) { + if (Framework::instance().memoryPool()->isBufferFromPool(buf)) { + raw = buf; + } else { + raw = getBuffer(); + std::memcpy(raw.get(), buf.get(), size()); + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/Serialization.cpp b/Cthulhu/src/Serialization.cpp new file mode 100644 index 000000000..29f0918de --- /dev/null +++ b/Cthulhu/src/Serialization.cpp @@ -0,0 +1,205 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +namespace cthulhu { + +namespace details { +void serializeDynamicFields( + const SharedRawDynamicArray& dynamicParameters, + int numDynFields, + int& offset, + uint8_t* result) { + for (int fieldIdx = 0; fieldIdx < numDynFields; ++fieldIdx) { + // If fieldSize is empty, serialize it anyway. We'll look for the zero when we + // deserialize to understand if we're supposed to skip a field. + uint32_t fieldSize = dynamicParameters.get()[fieldIdx].size(); + std::memcpy(result + offset, &fieldSize, sizeof(uint32_t)); + offset += sizeof(uint32_t); + if (0 != fieldSize) { + std::memcpy(result + offset, dynamicParameters.get()[fieldIdx].raw.get(), fieldSize); + } + offset += fieldSize; + } +} + +void deserializeDynamicFields( + SharedRawDynamicArray& dynamicParameters, + int numDynFields, + int& offset, + const uint8_t* source) { + for (int fieldIdx = 0; fieldIdx < numDynFields; ++fieldIdx) { + uint32_t fieldSize; + std::memcpy(&fieldSize, &source[0] + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + if (0 != fieldSize) { + auto& rawDynamic = dynamicParameters.get()[fieldIdx]; + rawDynamic.raw = + std::shared_ptr(new uint8_t[fieldSize], [](uint8_t* p) -> void { delete[] p; }); + rawDynamic.elementCount = fieldSize; + rawDynamic.elementSize = sizeof(uint8_t); + std::memcpy(rawDynamic.raw.get(), &source[0] + offset, fieldSize); + } + offset += fieldSize; + } +} +} // namespace details + +std::vector serializeConfig(const std::string& typeName, const StreamConfig& config) { + std::vector result; + auto typeInfo = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!typeInfo) { + XR_LOGCE("Cthulhu", "Couldn't serialize config, failed to find type in registry: ", typeName); + return result; + } + const auto& paramSize = typeInfo->configParameterSize(); + const auto& numDynFields = typeInfo->configNumberDynamicFields(); + int totalDynSize = 0; + for (int fieldIdx = 0; fieldIdx < numDynFields; ++fieldIdx) { + totalDynSize += config.dynamicParameters.get()[fieldIdx].size(); + } + result.resize( + paramSize + totalDynSize + sizeof(int) * numDynFields + sizeof(double) + sizeof(uint32_t)); + int offset = 0; + std::memcpy(&result[0] + offset, config.parameters.get(), paramSize); + offset += paramSize; + + details::serializeDynamicFields(config.dynamicParameters, numDynFields, offset, result.data()); + + std::memcpy(&result[0] + offset, &config.nominalSampleRate, sizeof(double)); + offset += sizeof(double); + std::memcpy(&result[0] + offset, &config.sampleSizeInBytes, sizeof(uint32_t)); + return result; +} + +std::vector serializeSample( + const std::string& typeName, + const StreamSample& sample, + const StreamConfig* const config) { + std::vector result; + auto typeInfo = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!typeInfo) { + XR_LOGCE("Cthulhu", "Couldn't serialize sample, failed to find type in registry: ", typeName); + return result; + } + if (!typeInfo->isBasic()) { + if (!config) { + XR_LOGCE( + "Cthulhu", + "Couldn't serialize sample for non-basic type without a corresponding config: ", + typeName); + return result; + } + } + const auto& paramSize = typeInfo->sampleParameterSize(); + const auto& numDynFields = typeInfo->sampleNumberDynamicFields(); + int totalDynSize = 0; + for (int fieldIdx = 0; fieldIdx < numDynFields; ++fieldIdx) { + totalDynSize += sample.dynamicParameters.get()[fieldIdx].size(); + } + uint32_t payloadSize = + !typeInfo->isBasic() ? config->sampleSizeInBytes * sample.numberOfSubSamples : 0; + result.resize( + paramSize + totalDynSize + sizeof(int) * numDynFields + // numberOfSubSamples per DynField + payloadSize + sizeof(double) + // timestamp + 2 * sizeof(uint32_t)); + + int offset = 0; + + if (sample.parameters) { + std::memcpy(&result[0] + offset, sample.parameters.get(), paramSize); + offset += paramSize; + } + + details::serializeDynamicFields(sample.dynamicParameters, numDynFields, offset, &result[0]); + + std::memcpy(&result[0] + offset, &sample.numberOfSubSamples, sizeof(uint32_t)); + offset += sizeof(uint32_t); + if (sample.payload) { + std::memcpy(&result[0] + offset, ((CpuBuffer)sample.payload).get(), payloadSize); + offset += payloadSize; + } + + std::memcpy(&result[0] + offset, &sample.metadata->header.timestamp, sizeof(double)); + offset += sizeof(double); + std::memcpy(&result[0] + offset, &sample.metadata->header.sequenceNumber, sizeof(uint32_t)); + offset += sizeof(uint32_t); + return result; +} + +StreamConfig deserializeConfig(const std::string& typeName, const uint8_t* config) { + auto typeInfo = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!typeInfo) { + XR_LOGCE("Cthulhu", "Couldn't deserialize config, failed to find type in registry: ", typeName); + return StreamConfig(); + } + const auto& paramSize = typeInfo->configParameterSize(); + const auto& numDynFields = typeInfo->configNumberDynamicFields(); + + StreamConfig result(paramSize, numDynFields); + int offset = 0; + std::memcpy(result.parameters.get(), config + offset, paramSize); + offset += paramSize; + details::deserializeDynamicFields(result.dynamicParameters, numDynFields, offset, config); + std::memcpy((void*)&result.nominalSampleRate, config + offset, sizeof(double)); + offset += sizeof(double); + std::memcpy((void*)&result.sampleSizeInBytes, config + offset, sizeof(uint32_t)); + return result; +} + +StreamSample deserializeSample( + const std::string& typeName, + const uint8_t* sample, + const StreamConfig* const config) { + StreamSample result; + auto typeInfo = Framework::instance().typeRegistry()->findTypeName(typeName); + if (!typeInfo) { + XR_LOGCE("Cthulhu", "Couldn't deserialize sample, failed to find type in registry: ", typeName); + return result; + } + + if (!typeInfo->isBasic()) { + if (!config) { + XR_LOGCE( + "Cthulhu", + "Couldn't deserialize sample for non-basic type without a corresponding config: ", + typeName); + return result; + } + } + + int offset = 0; + + const auto& paramSize = typeInfo->sampleParameterSize(); + const auto& numDynFields = typeInfo->sampleNumberDynamicFields(); + if (paramSize > 0) { + result.parameters = + Framework::instance().memoryPool()->getBufferFromPool(StreamID{""}, paramSize); + std::memcpy(result.parameters.get(), sample + offset, paramSize); + offset += paramSize; + } + if (numDynFields > 0) { + result.dynamicParameters = cthulhu::makeSharedRawDynamicArray(numDynFields); + } + + details::deserializeDynamicFields(result.dynamicParameters, numDynFields, offset, sample); + std::memcpy((void*)&result.numberOfSubSamples, sample + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + uint32_t payloadSize = + !typeInfo->isBasic() ? config->sampleSizeInBytes * result.numberOfSubSamples : 0; + if (payloadSize > 0) { + result.payload = + Framework::instance().memoryPool()->getBufferFromPool(StreamID{""}, payloadSize); + std::memcpy(((CpuBuffer)result.payload).get(), sample + offset, payloadSize); + offset += payloadSize; + } + + std::memcpy(&result.metadata->header.timestamp, sample + offset, sizeof(double)); + offset += sizeof(double); + std::memcpy(&result.metadata->header.sequenceNumber, sample + offset, sizeof(uint32_t)); + offset += sizeof(uint32_t); + + return result; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamConfigEquality.cpp b/Cthulhu/src/StreamConfigEquality.cpp new file mode 100644 index 000000000..92265c0bd --- /dev/null +++ b/Cthulhu/src/StreamConfigEquality.cpp @@ -0,0 +1,38 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +namespace cthulhu { + +bool streamConfigsEqual( + const StreamConfig& lhs, + const StreamConfig& rhs, + const TypeInfoInterface& stream_type_info) { + if (lhs.nominalSampleRate != rhs.nominalSampleRate) { + return false; + } + if (lhs.sampleSizeInBytes != rhs.sampleSizeInBytes) { + return false; + } + if (stream_type_info.configParameterSize() > 0) { + if (std::memcmp( + lhs.parameters.get(), rhs.parameters.get(), stream_type_info.configParameterSize()) != + 0) { + return false; + } + } + if (stream_type_info.configNumberDynamicFields() > 0) { + for (int i = 0; i < stream_type_info.configNumberDynamicFields(); ++i) { + const auto& lhs_raw_dynamic = *(lhs.dynamicParameters.get() + i); + const auto& rhs_raw_dynamic = *(rhs.dynamicParameters.get() + i); + if (lhs_raw_dynamic != rhs_raw_dynamic) { + return false; + } + } + } + return true; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamInterface.cpp b/Cthulhu/src/StreamInterface.cpp new file mode 100644 index 000000000..ac51966e8 --- /dev/null +++ b/Cthulhu/src/StreamInterface.cpp @@ -0,0 +1,207 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +namespace cthulhu { + +StreamSample::StreamSample() : metadata(std::make_shared()) {} + +StreamProducer::StreamProducer(StreamInterface* si, bool async) : async_(async) { + if (si->hookProducer(this)) { + producedStream_ = si; + } + if (async) { + thread_ = std::thread( + [this](std::future signal) -> void { + while (signal.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout) { + std::queue tempQueue; + { + std::lock_guard lock(queueMutex_); + std::swap(tempQueue, queue_); + } + while (!tempQueue.empty()) { + DataVariant& item = tempQueue.front(); + if (item.type == DataVariant::Type::CONFIG) { + producedStream_->configure(item.config); + } else if (item.type == DataVariant::Type::SAMPLE) { + producedStream_->sendSample(item.sample); + } + tempQueue.pop(); + } + } + }, + stopSignal_.get_future()); + } +} + +StreamProducer::~StreamProducer() { + if (producedStream_ != nullptr) { + producedStream_->removeProducer(this); + } + if (async_) { + stopSignal_.set_value(); + while (!thread_.joinable()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + thread_.join(); + } +}; + +// This should be called before producing any samples +void StreamProducer::configureStream(const StreamConfig& config) const { + if (!async_) { + producedStream_->configure(config); + } else { + DataVariant item; + item.type = DataVariant::Type::CONFIG; + item.config = std::move(config); + std::lock_guard lock(queueMutex_); + queue_.push(std::move(item)); + if (queue_.size() > MAX_QUEUE_SIZE) { + XR_LOGW_ONCE("sample dropped at configureStream, consider increasing MAX_QUEUE_SIZE"); + queue_.pop(); + } + } +}; + +void StreamProducer::produceSample(const StreamSample& sample) const { + if (!async_) { + producedStream_->sendSample(sample); + } else { + DataVariant item; + item.type = DataVariant::Type::SAMPLE; + item.sample = std::move(sample); + std::lock_guard lock(queueMutex_); + queue_.push(std::move(item)); + if (queue_.size() > MAX_QUEUE_SIZE) { + XR_LOGW_ONCE("sample dropped at produceSample, consider increasing MAX_QUEUE_SIZE"); + queue_.pop(); + } + } +}; + +const StreamConfig* StreamProducer::config() const { + if (isActive() && producedStream_->isConfigured()) { + return &producedStream_->config(); + } + return nullptr; +}; + +StreamConsumer::StreamConsumer( + StreamInterface* si, + SampleCallback callback, + ConfigCallback configCallback, + bool async) + : callback_(callback), + configCallback_(configCallback), + async_(async), + performanceMonitor_{}, + queueCapacity_(DEFAULT_QUEUE_CAPACITY) { + si->hookConsumer(this); + consumedStream_ = si; + + if (async) { + thread_ = std::thread( + [this](std::future signal) -> void { + while (signal.wait_for(std::chrono::milliseconds(1)) == std::future_status::timeout) { + try { + Framework::validate(); + } catch (FrameworkCleanedUpException& e) { + break; + } + + std::queue tempQueue; + { + std::lock_guard lock(queueMutex_); + std::swap(tempQueue, queue_); + } + while (!tempQueue.empty()) { + DataVariant& item = tempQueue.front(); + if (item.type == DataVariant::Type::CONFIG) { + inhibitSampleCallback_ = !configCallback_(item.config); + } else if (item.type == DataVariant::Type::SAMPLE) { + if (!inhibitSampleCallback_) { + performanceMonitor_.startMeasurement(); + callback_(item.sample); + performanceMonitor_.endMeasurement(); + } + } + tempQueue.pop(); + } + } + }, + stopSignal_.get_future()); + } +}; + +StreamConsumer::~StreamConsumer() { + if (consumedStream_ != nullptr) { + consumedStream_->removeConsumer(this); + } + + if (async_) { + stopSignal_.set_value(); + while (!thread_.joinable()) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + thread_.join(); + } +}; + +void StreamConsumer::receiveConfig(const StreamConfig& config) const { + if (configCallback_ != nullptr) { + if (!async_) { + inhibitSampleCallback_ = !configCallback_(config); + } else { + DataVariant item; + item.type = DataVariant::Type::CONFIG; + item.config = std::move(config); + std::lock_guard lock(queueMutex_); + queue_.push(std::move(item)); + if (queue_.size() > queueCapacity_) { + queue_.pop(); + } + } + } +}; + +void StreamConsumer::consumeSample(const StreamSample& sample) const { + if (!async_) { + if (!inhibitSampleCallback_) { + performanceMonitor_.startMeasurement(); + callback_(sample); + performanceMonitor_.endMeasurement(); + } + } else { + DataVariant item; + item.type = DataVariant::Type::SAMPLE; + item.sample = std::move(sample); + std::lock_guard lock(queueMutex_); + queue_.push(std::move(item)); + if (queue_.size() > queueCapacity_) { + queue_.pop(); + performanceMonitor_.sampleDropped(); + } + } +} + +PerformanceSummary StreamConsumer::getPerformanceSummary() const { + return performanceMonitor_.getSummary(); +} + +uint64_t StreamConsumer::getQueueCapacity() const { + std::lock_guard lock(queueMutex_); + return queueCapacity_; +} + +void StreamConsumer::setQueueCapacity(uint64_t capacity) { + std::lock_guard lock(queueMutex_); + queueCapacity_ = capacity; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamInterfaceIPC.cpp b/Cthulhu/src/StreamInterfaceIPC.cpp new file mode 100644 index 000000000..9e2dcd870 --- /dev/null +++ b/Cthulhu/src/StreamInterfaceIPC.cpp @@ -0,0 +1,194 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "StreamInterfaceIPC.h" + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +#include +#include +namespace cthulhu { + +double getCurrentTimeSec() { + auto now = std::chrono::high_resolution_clock::now(); + auto timeSinceEpoch = + std::chrono::duration(now.time_since_epoch()); + return timeSinceEpoch.count(); +} + +StreamConsumerIPC::StreamConsumerIPC( + StreamInterfaceIPC* si, + const std::function& configCallback, + const std::function& sampleCallback, + bool updateConfig) + : streamInterface_(si), + configCallback_(configCallback), + sampleCallback_(sampleCallback), + stopSignal_{false} { + if (!streamInterface_) { + auto str = "Received invalid stream interface in IPC listener"; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + { + ScopedLockIPC streamLock(streamInterface_->streamLock); + streamInterface_->numSubscribers_++; + } + // If updateConfig is false, grab any existing config timestamp + // so the config doesn't get sent out. + if (!updateConfig) { + ScopedLockIPC dataLock(streamInterface_->dataLock); + if (streamInterface_->config.has_value()) { + latestConfigTime_ = streamInterface_->config->timestamp; + } + } + + thread_ = std::thread([this] { + while (!stopSignal_.load()) { + update(); + + // Wait for signal + ScopedLockIPC lock(streamInterface_->dataLock); + streamInterface_->dataUpdate.timed_wait( + lock, boost::get_system_time() + boost::posix_time::milliseconds(1)); + } + }); +} + +StreamConsumerIPC::~StreamConsumerIPC() { + // Grab the stream lock before we try to shut down our thread. This guarantees + // that we won't try to shut it down while an IPC producer is pushing data out + ScopedLockIPC lock(streamInterface_->streamLock); + + stopSignal_.store(true); + if (thread_.joinable()) { + thread_.join(); + } + + streamInterface_->numSubscribers_--; +} + +void StreamConsumerIPC::update() { + Framework::validate(); + + ScopedLockIPC lock(streamInterface_->dataLock); + const auto& config = streamInterface_->config; + const auto& sample = streamInterface_->sample; + if (config.has_value() && config->timestamp > latestConfigTime_) { + latestConfigTime_ = config->timestamp; + streamInterface_->configConsumedCount++; + if (configCallback_ && !configCallback_(config->data)) { + return; + } + } + if (sample.has_value() && sample->timestamp > latestSampleTime_) { + streamInterface_->sampleConsumedCount++; + if (sampleCallback_) { + if (sampleCallback_(sample->data)) { + latestSampleTime_ = sample->timestamp; + } + } + } +} + +StreamProducerIPC::StreamProducerIPC(StreamInterfaceIPC* si) : streamInterface_(si) { + ScopedLockIPC lock(streamInterface_->streamLock); + if (streamInterface_->advertised_) { + return; + } + streamInterface_->advertised_ = true; + valid_ = true; +} + +StreamProducerIPC::~StreamProducerIPC() { + if (valid_) { + ScopedLockIPC lock(streamInterface_->streamLock); + streamInterface_->advertised_ = false; + } +} + +void StreamProducerIPC::configure(const StreamConfigIPC& configIn) { + if (valid_) { + configureValid(configIn); + } +} + +void StreamProducerIPC::configureValid(const StreamConfigIPC& configIn) { + // Grab the stream lock so no one can join-in on the stream mid-call + // We want to have a fixed number of consumers that we're distributing to + ScopedLockIPC streamLock(streamInterface_->streamLock); + + { + ScopedLockIPC dataLock(streamInterface_->dataLock); + StreamConfigStampedIPC data(configIn); + data.timestamp = getCurrentTimeSec(); + + streamInterface_->configConsumedCount = 0; + streamInterface_->config = data; + streamInterface_->dataUpdate.notify_all(); + } + + // Wait until we hear that all of our consumers have finished + checkWaitForData([this]() { + return streamInterface_->configConsumedCount >= streamInterface_->numSubscribers(); + }); +} + +void StreamProducerIPC::publish(const StreamSampleIPC& sampleIn) { + if (valid_) { + publishValid(sampleIn); + } +} + +void StreamProducerIPC::publishValid(const StreamSampleIPC& sampleIn) { + // Grab the stream lock so no one can join-in on the stream mid-call + // We want to have a fixed number of consumers that we're distributing to + + ScopedLockIPC lock(streamInterface_->streamLock); + if (streamInterface_->numSubscribers() > 0) { + { + ScopedLockIPC dataLock(streamInterface_->dataLock); + StreamSampleStampedIPC data(sampleIn); + data.timestamp = getCurrentTimeSec(); + + streamInterface_->sampleConsumedCount = 0; + streamInterface_->sample = data; + streamInterface_->dataUpdate.notify_all(); + } + + // Wait until we hear that all of our consumers have finished + checkWaitForData([this]() { + return streamInterface_->sampleConsumedCount >= streamInterface_->numSubscribers(); + }); + } +} + +void StreamProducerIPC::checkWaitForData(std::function test) { + bool done = false; + boost::system_time checkDelay = + boost::get_system_time() + boost::posix_time::milliseconds(TIMEOUT_MILLISECONDS); + while (!done) { + std::this_thread::yield(); + + { + ScopedLockIPC dataLock(streamInterface_->dataLock, boost::interprocess::defer_lock); + if (dataLock.timed_lock(checkDelay)) { + done = test(); + } + } + Framework::validate(); + checkDelay = boost::get_system_time() + boost::posix_time::milliseconds(TIMEOUT_MILLISECONDS); + } + + // Clear our sample, since we don't want it to latch. + { + ScopedLockIPC dataLock(streamInterface_->dataLock); + streamInterface_->sample = {}; + } +} + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamInterfaceIPC.h b/Cthulhu/src/StreamInterfaceIPC.h new file mode 100644 index 000000000..9374655f6 --- /dev/null +++ b/Cthulhu/src/StreamInterfaceIPC.h @@ -0,0 +1,178 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include "IPCEssentials.h" + +#include +#include +#include +#include +#include + +#include +#include + +namespace cthulhu { + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + StreamTypeIPC; + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + ProcessingStampKey; + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + DynamicFieldName; + +typedef boost::interprocess:: + allocator, ManagedSHM::segment_manager> + ProcessingStampsAllocType; + +typedef boost::interprocess:: + map, ProcessingStampsAllocType> + ProcessingStampsIPC; + +class StreamDescriptionIPC { + public: + StreamDescriptionIPC() = delete; + StreamDescriptionIPC(const CharAllocatorIPC& alloc) : id(alloc), type(alloc) {} + StreamIDIPC id; + StreamTypeIPC type; +}; + +using RawDynamicIPC = RawDynamic; + +typedef boost::interprocess::allocator + RawDynamicIPCAllocType; + +typedef boost::interprocess::vector DynamicFields; + +struct StreamSampleIPC { + double timestamp; + uint32_t sequenceNumber; + std::variant payload; + BufferType payloadType; + uint32_t numberOfSubSamples; + SharedPtrIPC parameters; + ProcessingStampsIPC processingStamps; + DynamicFields dynamicSampleParameters; + + StreamSampleIPC(ManagedSHM::segment_manager* mgr) + : processingStamps(mgr), dynamicSampleParameters(mgr) {} +}; + +struct StreamConfigIPC { + double nominalSampleRate; + uint32_t sampleSizeInBytes; + SharedPtrIPC parameters; + DynamicFields dynamicConfigParameters; + + StreamConfigIPC(ManagedSHM::segment_manager* mgr) : dynamicConfigParameters(mgr) {} +}; + +class StreamConsumerIPC; +class StreamProducerIPC; + +struct StreamConfigStampedIPC { + explicit StreamConfigStampedIPC(const StreamConfigIPC& config) : data(config) {} + StreamConfigIPC data; + double timestamp = 0.0; +}; + +struct StreamSampleStampedIPC { + explicit StreamSampleStampedIPC(const StreamSampleIPC& sample) : data(sample) {} + StreamSampleIPC data; + double timestamp = 0.0; +}; + +// This is the definiiton of a StreamInterface, for use in the IPC registry +class StreamInterfaceIPC { + friend class StreamConsumerIPC; + friend class StreamProducerIPC; + + public: + // Non-copyable. Only one should exist, sitting in the Registry + StreamInterfaceIPC(const StreamInterfaceIPC& other) = delete; + StreamInterfaceIPC& operator=(const StreamInterfaceIPC& other) = delete; + StreamInterfaceIPC(StreamInterfaceIPC&& other) = delete; + StreamInterfaceIPC& operator=(StreamInterfaceIPC&& other) = delete; + + StreamInterfaceIPC() = delete; + + explicit StreamInterfaceIPC(const StreamDescriptionIPC& desc) : description_(desc){}; + + const StreamDescriptionIPC& description() const { + return description_; + } + + bool advertised() const { + return advertised_; + } + + uint8_t numSubscribers() const { + return numSubscribers_; + } + + private: + // Managed by the data lock + std::optional config; + uint8_t configConsumedCount = 0; + std::optional sample; + uint8_t sampleConsumedCount = 0; + ConditionIPC dataUpdate; + mutable MutexIPC dataLock; + + // These are to be controlled by the stream lock + bool advertised_ = false; + uint8_t numSubscribers_ = 0; + mutable MutexIPC streamLock; + + const StreamDescriptionIPC description_; +}; + +class StreamConsumerIPC { + public: + explicit StreamConsumerIPC( + StreamInterfaceIPC* si, + const std::function& configCallback, + const std::function& sampleCallback, + bool updateConfig = true); + ~StreamConsumerIPC(); + + private: + void update(); + + StreamInterfaceIPC* streamInterface_ = nullptr; + std::thread thread_; + std::function configCallback_; + std::function sampleCallback_; + double latestSampleTime_ = 0.0; + double latestConfigTime_ = 0.0; + std::atomic stopSignal_; +}; + +class StreamProducerIPC { + public: + explicit StreamProducerIPC(StreamInterfaceIPC* si); + + ~StreamProducerIPC(); + + void configure(const StreamConfigIPC& configIn); + + void publish(const StreamSampleIPC& sampleIn); + + private: + void configureValid(const StreamConfigIPC& configIn); + + void publishValid(const StreamSampleIPC& sampleIn); + + void checkWaitForData(std::function test); + + static constexpr unsigned int TIMEOUT_MILLISECONDS = 5; + + StreamInterfaceIPC* streamInterface_ = nullptr; + bool valid_ = false; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamRegistryIPC.h b/Cthulhu/src/StreamRegistryIPC.h new file mode 100644 index 000000000..e699189f2 --- /dev/null +++ b/Cthulhu/src/StreamRegistryIPC.h @@ -0,0 +1,36 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include "StreamInterfaceIPC.h" + +#include +#include + +#include + +namespace cthulhu { + +struct StreamRegistryIPC { + typedef boost::interprocess:: + allocator, ManagedSHM::segment_manager> + MapAllocType; + typedef boost::interprocess:: + map, MapAllocType> + MapType; + + StreamRegistryIPC() = delete; + StreamRegistryIPC(const StreamRegistryIPC&) = delete; + StreamRegistryIPC(StreamRegistryIPC&&) = delete; + + StreamRegistryIPC(const MapAllocType& alloc) : streams(std::less(), alloc) {} + + MapType streams; + MutexIPC registry_lock; + + // Maintain a count of processes using the registry. + // When this reaches 0, the process should cleanup the map + uint32_t reference_count = 0; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamRegistryIPCHybrid.cpp b/Cthulhu/src/StreamRegistryIPCHybrid.cpp new file mode 100644 index 000000000..6a8d69c78 --- /dev/null +++ b/Cthulhu/src/StreamRegistryIPCHybrid.cpp @@ -0,0 +1,563 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "StreamRegistryIPCHybrid.h" + +#include + +#include +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#include + +namespace cthulhu { + +StreamIPCHybrid::StreamIPCHybrid( + const StreamDescription& desc, + StreamInterfaceIPC* ipcStream, + MemoryPoolIPCHybrid* memoryPool, + size_t sampleParameterSize, + size_t configParameterSize, + size_t sampleDynamicFieldCount, + size_t configDynamicFieldCount, + ManagedSHM* shm) + : StreamInterface(desc), + ipcStream_(ipcStream), + memoryPool_(memoryPool), + ipcActive_(false), + ipcProducer_(nullptr), + ipcConsumer_(nullptr), + sampleParameterSize_(sampleParameterSize), + configParameterSize_(configParameterSize), + sampleDynamicFieldCount_(sampleDynamicFieldCount), + configDynamicFieldCount_(configDynamicFieldCount), + shm_(shm) {} + +StreamIPCHybrid::~StreamIPCHybrid() = default; + +void StreamIPCHybrid::notifyMemoryPool() { + if (!ipcStream_) { + return; + } + if (ipcStream_->numSubscribers() > 0 && !ipcActive_) { + // Notify the memory pool that it should be allocating this on + // shared memory + memoryPool_->activateStream(description_.id(), true); + ipcActive_ = true; + } else if (ipcStream_->numSubscribers() == 0 && ipcActive_) { + memoryPool_->activateStream(description_.id(), false); + ipcActive_ = false; + } +} + +bool StreamIPCHybrid::sendSample(const StreamSample& sample) { + if (paused_) { + return true; + } + + std::unique_lock lock(timed_mutex_, std::defer_lock); + if (!lock.try_lock_for(std::chrono::milliseconds(1))) { + XR_LOGW("Failed to send sample--timed out."); + return false; + } + + for (const auto& consumer : consumers_) { + consumer->consumeSample(sample); + } + sendSampleIPC(sample); + + return true; +} + +void StreamIPCHybrid::sendSampleIPC(const StreamSample& sample) { + if (!ipcProducer_) { + return; + } + notifyMemoryPool(); + + StreamSampleIPC ipcSample(shm_->get_segment_manager()); + + bool lookupSuccess = false; + + switch (sample.payload.type) { + case (BufferType::CPU): { + auto result = memoryPool_->convert(std::get(sample.payload.data)); + ipcSample.payload = result; + ipcSample.payloadType = BufferType::CPU; + lookupSuccess = result; + break; + } + case (BufferType::GPU): { + auto result = memoryPool_->convert(std::get(sample.payload.data)); + ipcSample.payload = result; + ipcSample.payloadType = BufferType::GPU; + lookupSuccess = result; + break; + } + default: { + ipcSample.payloadType = BufferType::NULL_BUFFER; + break; + } + } + + if (sample.payload && !lookupSuccess && + !Framework::instance().typeRegistry()->findTypeID(description_.type())->isBasic()) { + if (ipcActive_) { + XR_LOGW( + "StreamIPCHybrid - Failed to lookup shared memory pointer for payload of stream '{}'", + description_.id()); + } + return; + } + ipcSample.timestamp = sample.metadata->header.timestamp; + ipcSample.sequenceNumber = sample.metadata->header.sequenceNumber; + ipcSample.numberOfSubSamples = sample.numberOfSubSamples; + for (const auto& processingStamp : sample.metadata->processingStamps) { + ProcessingStampKey key(shm_->get_segment_manager()); + key = processingStamp.first.c_str(); + ipcSample.processingStamps[key] = processingStamp.second; + } + if (sample.parameters) { + auto sharedParametersPtr = memoryPool_->convert(sample.parameters); + if (sharedParametersPtr) { + ipcSample.parameters = sharedParametersPtr; + } else { + XR_LOGW_ONCE( + "StreamIPCHybrid - Failed to lookup shared memory pointer when sending parameters of stream '{}'", + description_.id()); + ipcSample.parameters = memoryPool_->getBufferFromSharedPoolDirect(sampleParameterSize_); + memcpy(ipcSample.parameters.get().get(), sample.parameters.get(), sampleParameterSize_); + } + } + + if (sample.dynamicParameters) { + ipcSample.dynamicSampleParameters = + DynamicFields(sampleDynamicFieldCount_, shm_->get_segment_manager()); + for (size_t idx = 0; idx < ipcSample.dynamicSampleParameters.size(); ++idx) { + auto& rawDynamicIPC = ipcSample.dynamicSampleParameters[idx]; + const auto& rawDynamic = *(sample.dynamicParameters.get() + idx); + rawDynamicIPC.elementCount = rawDynamic.elementCount; + rawDynamicIPC.elementSize = rawDynamic.elementSize; + + auto sharedDynamicParameterPtr = memoryPool_->convert(rawDynamic.raw); + if (sharedDynamicParameterPtr) { + rawDynamicIPC.raw = sharedDynamicParameterPtr; + } else { + XR_LOGW_ONCE( + "StreamIPCHybrid - Failed to lookup shared memory pointer when sending dynamic parameter {} of stream '{}'", + idx, + description_.id()); + rawDynamicIPC.raw = memoryPool_->getBufferFromSharedPoolDirect( + rawDynamicIPC.elementCount * rawDynamicIPC.elementSize); + std::memcpy( + rawDynamicIPC.raw.get().get(), + rawDynamic.raw.get(), + rawDynamicIPC.elementCount * rawDynamicIPC.elementSize); + } + } + } + ipcProducer_->publish(ipcSample); +} + +bool StreamIPCHybrid::configure(const StreamConfig& config) { + std::unique_lock lock(timed_mutex_, std::defer_lock); + if (!lock.try_lock_for(std::chrono::milliseconds(1))) { + XR_LOGW("Failed to configure stream--timed out."); + return false; + } + + configured_ = true; + config_ = config; + + for (const auto& consumer : consumers_) { + consumer->receiveConfig(config_); + } + configureIPC(config); + return true; +} + +void StreamIPCHybrid::configureIPC(const StreamConfig& config) { + if (!ipcProducer_) { + return; + } + notifyMemoryPool(); + StreamConfigIPC ipcConfig(shm_->get_segment_manager()); + ipcConfig.nominalSampleRate = config.nominalSampleRate; + ipcConfig.sampleSizeInBytes = config.sampleSizeInBytes; + ipcConfig.parameters = memoryPool_->getBufferFromSharedPoolDirect(configParameterSize_); + memcpy(ipcConfig.parameters.get().get(), config.parameters.get(), configParameterSize_); + + if (config.dynamicParameters) { + ipcConfig.dynamicConfigParameters = + DynamicFields(configDynamicFieldCount_, shm_->get_segment_manager()); + for (size_t idx = 0; idx < ipcConfig.dynamicConfigParameters.size(); ++idx) { + auto& rawDynamicIPC = ipcConfig.dynamicConfigParameters[idx]; + const auto& rawDynamic = *(config.dynamicParameters.get() + idx); + rawDynamicIPC.elementCount = rawDynamic.elementCount; + rawDynamicIPC.elementSize = rawDynamic.elementSize; + rawDynamicIPC.raw = memoryPool_->getBufferFromSharedPoolDirect( + rawDynamicIPC.elementCount * rawDynamicIPC.elementSize); + std::memcpy( + rawDynamicIPC.raw.get().get(), + rawDynamic.raw.get(), + rawDynamicIPC.elementCount * rawDynamicIPC.elementSize); + } + } + + ipcProducer_->configure(ipcConfig); +} + +bool StreamIPCHybrid::receiveConfigIPC(const StreamConfigIPC& config) { + StreamConfig local; + local.nominalSampleRate = config.nominalSampleRate; + local.sampleSizeInBytes = config.sampleSizeInBytes; + local.parameters.reset(new uint8_t[configParameterSize_], [](uint8_t* p) -> void { delete[] p; }); + memcpy(local.parameters.get(), config.parameters.get().get(), configParameterSize_); + + if (!config.dynamicConfigParameters.empty()) { + local.dynamicParameters = makeSharedRawDynamicArray(config.dynamicConfigParameters.size()); + for (size_t idx = 0; idx < config.dynamicConfigParameters.size(); ++idx) { + auto& localRawDynamic = *(local.dynamicParameters.get() + idx); + const auto& rawDynamicIPC = config.dynamicConfigParameters[idx]; + localRawDynamic.elementCount = rawDynamicIPC.elementCount; + localRawDynamic.elementSize = rawDynamicIPC.elementSize; + localRawDynamic.raw = std::shared_ptr( + new uint8_t[localRawDynamic.elementSize * localRawDynamic.elementCount](), + std::default_delete()); + std::memcpy( + localRawDynamic.raw.get(), + rawDynamicIPC.raw.get().get(), + localRawDynamic.elementSize * localRawDynamic.elementCount); + } + } + + return configure(local); +} + +bool StreamIPCHybrid::receiveSampleIPC(const StreamSampleIPC& sample) { + StreamSample local; + local.metadata.reset(new SampleMetadata()); + local.metadata->header.timestamp = sample.timestamp; + local.metadata->header.sequenceNumber = sample.sequenceNumber; + switch (sample.payloadType) { + case (BufferType::CPU): { + local.payload = memoryPool_->createLocal(std::get(sample.payload)); + break; + } + case (BufferType::GPU): { + local.payload = memoryPool_->createLocal(std::get(sample.payload)); + break; + } + default: { + break; + } + } + local.numberOfSubSamples = sample.numberOfSubSamples; + for (const auto& processingStamp : sample.processingStamps) { + std::string step(processingStamp.first.cbegin(), processingStamp.first.cend()); + local.metadata->processingStamps[step] = processingStamp.second; + } + if (sample.parameters) { + auto sharedParametersPtr = memoryPool_->createLocal(sample.parameters); + if (!sharedParametersPtr) { + XR_LOGW( + "StreamIPCHybrid - Failed to lookup shared memory pointer when receiving parameters of stream '{}'", + description_.id()); + return false; + } + local.parameters = sharedParametersPtr; + } + + if (!sample.dynamicSampleParameters.empty()) { + local.dynamicParameters = makeSharedRawDynamicArray(sample.dynamicSampleParameters.size()); + for (size_t idx = 0; idx < sample.dynamicSampleParameters.size(); ++idx) { + auto& localRawDynamic = *(local.dynamicParameters.get() + idx); + const auto& rawDynamicIPC = sample.dynamicSampleParameters[idx]; + localRawDynamic.elementCount = rawDynamicIPC.elementCount; + localRawDynamic.elementSize = rawDynamicIPC.elementSize; + + auto sharedDynamicParameterPtr = memoryPool_->createLocal(rawDynamicIPC.raw); + if (sharedDynamicParameterPtr) { + localRawDynamic.raw = sharedDynamicParameterPtr; + } else { + XR_LOGW( + "StreamIPCHybrid - Failed to lookup shared memory pointer when receiving dynamic parameter {} of stream '{}'", + idx, + description_.id()); + return false; + } + } + } + return sendSample(local); +} + +bool StreamIPCHybrid::hookProducer(const StreamProducer* const producer) { + std::lock_guard lock(timed_mutex_); + if (producer_ != nullptr) { + XR_LOGW("Not hooking producer on stream: {}", description_.id()); + return false; + } + XR_LOGD("Hooking producer on stream: {}", description_.id()); + producer_ = producer; + if (ipcStream_) { + ipcConsumer_.reset(); + ipcProducer_.reset(new StreamProducerIPC(ipcStream_)); + } + + return true; +} + +void StreamIPCHybrid::hookConsumer(const StreamConsumer* const consumer) { + XR_LOGD("Hooking consumer on stream: {}", description_.id()); + std::lock_guard lock(timed_mutex_); + consumers_.push_back(consumer); + // If this is a basic stream, none of the downstream consumers are expecting to use + // the config, but we still need to produce the signal + bool isBasic = Framework::instance().typeRegistry()->findTypeID(description_.type())->isBasic(); + if (isConfigured() || isBasic) { + consumer->receiveConfig(config_); + } + std::function configCb = nullptr; + if (ipcStream_) { + if (!isBasic) { + configCb = [this](const StreamConfigIPC& config) -> bool { + return this->receiveConfigIPC(config); + }; + } + if (!producer_ && !ipcConsumer_) { + ipcConsumer_.reset(new StreamConsumerIPC( + ipcStream_, configCb, [this](const StreamSampleIPC& sample) -> bool { + return this->receiveSampleIPC(sample); + })); + } + } +} + +void StreamIPCHybrid::removeProducer(const StreamProducer* const producer) { + std::lock_guard lock(timed_mutex_); + if (producer_ == producer) { + XR_LOGD("Removing producer on stream: {}", description_.id()); + producer_ = nullptr; + } else { + XR_LOGD("Not removing producer on stream: {}", description_.id()); + return; + } + ipcActive_ = false; + + if (ipcStream_) { + ipcProducer_.reset(); + if (consumers_.size() > 0) { + std::function configCb = nullptr; + if (!Framework::instance().typeRegistry()->findTypeID(description_.type())->isBasic()) { + configCb = [this](const StreamConfigIPC& config) -> bool { + return this->receiveConfigIPC(config); + }; + } + + ipcConsumer_.reset(new StreamConsumerIPC( + ipcStream_, + configCb, + [this](const StreamSampleIPC& sample) -> bool { return this->receiveSampleIPC(sample); }, + false)); + } + } +} + +void StreamIPCHybrid::removeConsumer(const StreamConsumer* const consumer) { + std::lock_guard lock(timed_mutex_); + + auto it = std::find(consumers_.begin(), consumers_.end(), consumer); + if (it != consumers_.end()) { + XR_LOGD("Removing consumer on stream: {}", description_.id()); + consumers_.erase(it); + } + if (ipcStream_) { + if (ipcConsumer_ && consumers_.empty()) { + ipcConsumer_.reset(); + } + } +} + +StreamRegistryIPCHybrid::StreamRegistryIPCHybrid( + MemoryPoolIPCHybrid* memoryPool, + const TypeRegistryInterface* typeRegistry, + ManagedSHM* shm) + : shm_(shm), memoryPool_(memoryPool), typeRegistry_(typeRegistry) { + registryData_ = + shm_->find_or_construct("StreamRegistry")(shm_->get_segment_manager()); + + if (registryData_ == nullptr) { + auto str = "Failed to open stream registry in shared memory."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + // This poses a risk to nuke. If it is locked by a dead process, we will hang + ScopedLockIPC lock(registryData_->registry_lock); + // even after ignoring this lock, we can still hang, presumably due to another lock + registryData_->reference_count++; +} + +bool StreamRegistryIPCHybrid::nuke(ManagedSHM* shm) { + shm->destroy("StreamRegistry"); + return true; +} + +StreamRegistryIPCHybrid::~StreamRegistryIPCHybrid() { + { + const auto lock = std::lock_guard(streamMutex_); + streams_.clear(); + } + + if (registryData_) { + ScopedLockIPC lock(registryData_->registry_lock); + registryData_->reference_count--; + if (registryData_->reference_count == 0 || force_clean_) { + registryData_->streams.clear(); + registryData_->reference_count = 0; + if (log_enabled_) { + XR_LOGD("Cleaning up ipc stream registry."); + } + } else if (log_enabled_) { + XR_LOGD( + "Not cleaning ipc stream registry, still references: {}", registryData_->reference_count); + } + } +} + +StreamInterface* StreamRegistryIPCHybrid::registerStream(const StreamDescription& desc) { + std::lock_guard lock(streamMutex_); + + auto type = typeRegistry_->findTypeID(desc.type()); + + // Lookup type name in registry + StreamDescriptionIPC descIPC(shm_->get_segment_manager()); + descIPC.id = desc.id().c_str(); + descIPC.type = type->typeName().c_str(); + + // Go to the shared memory first + StreamInterfaceIPC* ipcStream = nullptr; + { + StreamIDIPC idIPC(shm_->get_segment_manager()); + idIPC = desc.id().c_str(); + ScopedLockIPC ipcLock(registryData_->registry_lock); + if (registryData_->streams.find(idIPC) == registryData_->streams.end()) { + registryData_->streams.try_emplace(idIPC, descIPC); + } + ipcStream = &(registryData_->streams.at(idIPC)); + } + + // Then go to local + auto s = streams_.find(desc.id()); + if (s != streams_.end()) { + return static_cast(&(s->second)); + } + + size_t sampleSize = type->sampleParameterSize(); + size_t configSize = type->configParameterSize(); + size_t sampleDynamicFieldCount = type->sampleNumberDynamicFields(); + size_t configDynamicFieldCount = type->configNumberDynamicFields(); + + // Create hybrid in local if it doesn't exist + XR_LOGD("Inserting stream: {} into local registry.", desc.id()); + streams_.insert(std::make_pair( + desc.id(), + StreamIPCHybrid( + desc, + ipcStream, + memoryPool_, + sampleSize, + configSize, + sampleDynamicFieldCount, + configDynamicFieldCount, + shm_))); + return static_cast(&(streams_.find(desc.id())->second)); +} + +StreamInterface* StreamRegistryIPCHybrid::getStream(const StreamID& id) { + std::lock_guard lock(streamMutex_); + + // Go to the shared memory first + StreamInterfaceIPC* ipcStream = nullptr; + { + StreamIDIPC idIPC(shm_->get_segment_manager()); + idIPC = id.c_str(); + ScopedLockIPC ipcLock(registryData_->registry_lock); + if (registryData_->streams.find(idIPC) == registryData_->streams.end()) { + XR_LOGD( + "Requested a stream '{}' from the registry that does not exist, " + "and insertion is not allowed.", + id); + return nullptr; + } + ipcStream = &(registryData_->streams.at(idIPC)); + } + + // Then go to local + auto s = streams_.find(id); + if (s != streams_.end()) { + return static_cast(&(s->second)); + } + + if (!ipcStream) { + return nullptr; + } + + // If its in IPC, we're allowed to bring it to local. Just need to lookup the type + auto type = typeRegistry_->findTypeName(ipcStream->description().type.c_str()); + StreamDescription desc{id, type->typeID()}; + + size_t sampleSize = type->sampleParameterSize(); + size_t configSize = type->configParameterSize(); + size_t sampleDynamicFieldCount = type->sampleNumberDynamicFields(); + size_t configDynamicFieldCount = type->configNumberDynamicFields(); + + // Create hybrid in local if it doesn't exist + XR_LOGD("Inserting stream: {} into local registry.", desc.id()); + streams_.insert(std::make_pair( + desc.id(), + StreamIPCHybrid( + desc, + ipcStream, + memoryPool_, + sampleSize, + configSize, + sampleDynamicFieldCount, + configDynamicFieldCount, + shm_))); + return static_cast(&(streams_.find(desc.id())->second)); +} + +void StreamRegistryIPCHybrid::printStreamInfo() const { + std::lock_guard lock(streamMutex_); + std::cout << "There are " << streams_.size() << " streams in the registry.\n"; + for (const auto& stream : streams_) { + std::cout << stream.first << ":" + << "\n"; + std::cout << "\tProducer: " << (stream.second.producer() == nullptr ? "OFF" : "ON") << "\n"; + std::cout << "\tConsumers: " << stream.second.consumers().size() << "\n"; + } + std::cout << std::flush; +}; + +std::vector StreamRegistryIPCHybrid::streamsOfTypeID(uint32_t typeID) const { + std::vector ids; + + if (typeID == 0) { + return ids; + } + + // Lookup type name in registry + std::string type = typeRegistry_->findTypeID(typeID)->typeName(); + + // No point in checking local, the set of all streams are in ipc + ScopedLockIPC lock2(registryData_->registry_lock); + for (auto& stream : registryData_->streams) { + if (stream.second.description().type.c_str() == type) { + ids.push_back(stream.first.c_str()); + } + } + + return ids; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamRegistryIPCHybrid.h b/Cthulhu/src/StreamRegistryIPCHybrid.h new file mode 100644 index 000000000..29c5a5ad6 --- /dev/null +++ b/Cthulhu/src/StreamRegistryIPCHybrid.h @@ -0,0 +1,116 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#include "MemoryPoolIPCHybrid.h" +#include "StreamRegistryIPC.h" + +#include +#include + +namespace cthulhu { + +class StreamIPCHybrid : public StreamInterface { + public: + StreamIPCHybrid( + const StreamDescription& desc, + StreamInterfaceIPC* ipcStream, + MemoryPoolIPCHybrid* memoryPool, + size_t sampleParameterSize, + size_t configParameterSize, + size_t sampleDynamicFieldCount, + size_t configDynamicFieldCount, + ManagedSHM*); + virtual ~StreamIPCHybrid(); + + // Non-copyable. Only one should exist, sitting in the Registry + StreamIPCHybrid(const StreamIPCHybrid& other) = delete; + StreamIPCHybrid& operator=(const StreamIPCHybrid& other) = delete; + + // Move-constructable, only for insertion into the Registry + StreamIPCHybrid(StreamIPCHybrid&& other) + : StreamInterface(std::move(other)), + ipcStream_(other.ipcStream_), + memoryPool_(other.memoryPool_), + ipcActive_(other.ipcActive_), + ipcProducer_(std::move(other.ipcProducer_)), + ipcConsumer_(std::move(other.ipcConsumer_)), + sampleParameterSize_(other.sampleParameterSize_), + configParameterSize_(other.configParameterSize_), + sampleDynamicFieldCount_(other.sampleDynamicFieldCount_), + configDynamicFieldCount_(other.configDynamicFieldCount_), + shm_(other.shm_) {} + // Non move assignable, shouldn't be needed + StreamIPCHybrid& operator=(StreamIPCHybrid&& other) = delete; + + protected: + virtual bool sendSample(const StreamSample& sample) override; + + virtual bool configure(const StreamConfig& config) override; + + virtual bool hookProducer(const StreamProducer* const producer) override; + + virtual void hookConsumer(const StreamConsumer* const consumer) override; + + virtual void removeProducer(const StreamProducer* const producer) override; + + virtual void removeConsumer(const StreamConsumer* const consumer) override; + + private: + void notifyMemoryPool(); + void sendSampleIPC(const StreamSample& sample); + void configureIPC(const StreamConfig& config); + bool receiveConfigIPC(const StreamConfigIPC& config); + bool receiveSampleIPC(const StreamSampleIPC& sampleData); + + StreamInterfaceIPC* ipcStream_; + MemoryPoolIPCHybrid* memoryPool_; + + bool ipcActive_; + + std::unique_ptr ipcProducer_; + std::unique_ptr ipcConsumer_; + + size_t sampleParameterSize_; + size_t configParameterSize_; + size_t sampleDynamicFieldCount_; + size_t configDynamicFieldCount_; + ManagedSHM* shm_; +}; + +class StreamRegistryIPCHybrid : public StreamRegistryInterface { + public: + StreamRegistryIPCHybrid( + MemoryPoolIPCHybrid* memoryPool, + const TypeRegistryInterface* typeRegistry, + ManagedSHM* shm); + virtual ~StreamRegistryIPCHybrid(); + + virtual StreamInterface* registerStream(const StreamDescription& desc) override; + + virtual StreamInterface* getStream(const StreamID& id) override; + + virtual void printStreamInfo() const override; + + virtual std::vector streamsOfTypeID(uint32_t typeID) const override; + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(ManagedSHM* shm); + + private: + std::map streams_; + mutable std::mutex streamMutex_; + StreamRegistryIPC* registryData_ = nullptr; + + ManagedSHM* shm_; + MemoryPoolIPCHybrid* memoryPool_; + const TypeRegistryInterface* typeRegistry_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamRegistryLocal.cpp b/Cthulhu/src/StreamRegistryLocal.cpp new file mode 100644 index 000000000..805494dda --- /dev/null +++ b/Cthulhu/src/StreamRegistryLocal.cpp @@ -0,0 +1,132 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "StreamRegistryLocal.h" + +#include + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +StreamLocal::StreamLocal(const StreamDescription& desc) : StreamInterface(desc) {} + +StreamLocal::~StreamLocal() = default; + +bool StreamLocal::sendSample(const StreamSample& sample) { + if (paused_) { + return true; + } + + std::lock_guard lock(timed_mutex_); + for (const auto& consumer : consumers_) { + consumer->consumeSample(sample); + } + + return true; +}; + +bool StreamLocal::configure(const StreamConfig& config) { + configured_ = true; + // TBD: compare the configs to see if this is an update + config_ = config; + std::lock_guard lock(timed_mutex_); + for (const auto& consumer : consumers_) { + consumer->receiveConfig(config_); + } + + return true; +}; + +bool StreamLocal::hookProducer(const StreamProducer* const producer) { + std::lock_guard lock(timed_mutex_); + if (producer_ != nullptr) { + XR_LOGD("Not hooking producer on stream: {}", description_.id()); + return false; + } + XR_LOGD("Hooking producer on stream: {}", description_.id()); + producer_ = producer; + return true; +}; + +void StreamLocal::hookConsumer(const StreamConsumer* const consumer) { + XR_LOGD("Hooking consumer on stream: {}", description_.id()); + std::lock_guard lock(timed_mutex_); + consumers_.push_back(consumer); + // If this is a basic stream, none of the downstream consumers are expecting to use + // the config, but we still need to produce the signal + if (isConfigured() || + Framework::instance().typeRegistry()->findTypeID(description_.type())->isBasic()) { + consumer->receiveConfig(config_); + } +}; + +void StreamLocal::removeProducer(const StreamProducer* const producer) { + std::lock_guard lock(timed_mutex_); + if (producer_ == producer) { + XR_LOGD("Removing producer on stream: {}", description_.id()); + producer_ = nullptr; + } else { + XR_LOGD("Not removing producer on stream: {}", description_.id()); + } +}; + +void StreamLocal::removeConsumer(const StreamConsumer* const consumer) { + std::lock_guard lock(timed_mutex_); + auto it = std::find(consumers_.begin(), consumers_.end(), consumer); + if (it != consumers_.end()) { + XR_LOGD("Removing consumer on stream: {}", description_.id()); + consumers_.erase(it); + } +}; + +StreamInterface* StreamRegistryLocal::registerStream(const StreamDescription& desc) { + std::lock_guard lock(streamMutex_); + auto s = streams_.find(desc.id()); + if (s != streams_.end()) { + return static_cast(&(s->second)); + } + XR_LOGD("Inserting stream: {} into registry.", desc.id()); + streams_.insert(std::make_pair(desc.id(), StreamLocal(desc))); + return static_cast(&(streams_.find(desc.id())->second)); +} + +StreamInterface* StreamRegistryLocal::getStream(const StreamID& id) { + std::lock_guard lock(streamMutex_); + auto s = streams_.find(id); + if (s != streams_.end()) { + return static_cast(&(s->second)); + } + XR_LOGW( + "Requested a stream from the registry that does not exist, and insertion is not allowed."); + return nullptr; +} + +void StreamRegistryLocal::printStreamInfo() const { + std::lock_guard lock(streamMutex_); + for (const auto& stream : streams_) { + XR_LOGD("{}: ", stream.first); + XR_LOGD(" - Producer: {}", (stream.second.producer() != nullptr ? "ON" : "OFF")); + XR_LOGD(" - Consumers: {}", stream.second.consumers().size()); + } +}; + +std::vector StreamRegistryLocal::streamsOfTypeID(uint32_t typeID) const { + std::vector ids; + + if (typeID == 0) { + return ids; + } + + std::lock_guard lock(streamMutex_); + for (const auto& stream : streams_) { + if (stream.second.description().type() == typeID) { + ids.push_back(stream.second.description().id()); + } + } + return ids; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamRegistryLocal.h b/Cthulhu/src/StreamRegistryLocal.h new file mode 100644 index 000000000..6a56636aa --- /dev/null +++ b/Cthulhu/src/StreamRegistryLocal.h @@ -0,0 +1,57 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#include + +namespace cthulhu { + +class StreamLocal : public StreamInterface { + public: + StreamLocal(const StreamDescription& desc); + virtual ~StreamLocal(); + + // Non-copyable. Only one should exist, sitting in the Registry + StreamLocal(const StreamLocal& other) = delete; + StreamLocal& operator=(const StreamLocal& other) = delete; + + // Move-constructable, only for insertion into the Registry + StreamLocal(StreamLocal&& other) : StreamInterface(std::move(other)) {} + // Non move assignable, shouldn't be needed + StreamLocal& operator=(StreamLocal&& other) = delete; + + protected: + virtual bool sendSample(const StreamSample& sample) override; + + virtual bool configure(const StreamConfig& config) override; + + virtual bool hookProducer(const StreamProducer* const producer) override; + + virtual void hookConsumer(const StreamConsumer* const consumer) override; + + virtual void removeProducer(const StreamProducer* const producer) override; + + virtual void removeConsumer(const StreamConsumer* const consumer) override; +}; + +class StreamRegistryLocal : public StreamRegistryInterface { + public: + virtual ~StreamRegistryLocal() = default; + + virtual StreamInterface* registerStream(const StreamDescription& desc) override; + + virtual StreamInterface* getStream(const StreamID& id) override; + + virtual void printStreamInfo() const override; + + virtual std::vector streamsOfTypeID(uint32_t typeID) const override; + + private: + std::map streams_; + mutable std::mutex streamMutex_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/StreamType.cpp b/Cthulhu/src/StreamType.cpp new file mode 100644 index 000000000..b4ae6880d --- /dev/null +++ b/Cthulhu/src/StreamType.cpp @@ -0,0 +1,173 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +namespace cthulhu { + +StreamConfig& ConfigAccessor::config(AutoStreamConfig* wrapper) { + return wrapper->config_; +} + +StreamSample& SampleAccessor::sample(AutoStreamSample* wrapper) { + return wrapper->sample_; +} + +AutoStreamConfig::AutoStreamConfig(size_t staticFieldSize, size_t dynamicFieldSize) + : config_(staticFieldSize, dynamicFieldSize) {} + +AutoStreamConfig::AutoStreamConfig(const StreamConfig& config) : config_(config) {} + +AutoStreamConfig::~AutoStreamConfig() {} + +const StreamConfig& AutoStreamConfig::getConfig() const { + return config_; +} + +void AutoStreamConfig::setConfig(const StreamConfig& config) { + config_ = config; +} + +SampleRate::SampleRate(AutoStreamConfig* wrapper) { + wrapper_ = wrapper; +} + +const double& SampleRate::get() const { + return wrapper_->getConfig().nominalSampleRate; +} + +SampleRate::operator const double&() const { + return wrapper_->getConfig().nominalSampleRate; +} + +void SampleRate::set(const double& value) { + config(wrapper_).nominalSampleRate = value; +} + +SampleRate& SampleRate::operator=(const double& value) { + config(wrapper_).nominalSampleRate = value; + return *this; +} + +SampleSize::SampleSize(AutoStreamConfig* wrapper) { + wrapper_ = wrapper; +} + +uint32_t SampleSize::get() const { + return wrapper_->getConfig().sampleSizeInBytes; +} + +SampleSize::operator const uint32_t&() const { + return wrapper_->getConfig().sampleSizeInBytes; +} + +void SampleSize::set(const uint32_t& value) { + config(wrapper_).sampleSizeInBytes = value; +} + +SampleSize& SampleSize::operator=(const uint32_t& value) { + config(wrapper_).sampleSizeInBytes = value; + return *this; +} + +AutoStreamSample::AutoStreamSample(size_t size, size_t numberDynamicFields) { + if (size > 0) { + sample_.parameters = Framework::instance().memoryPool()->getBufferFromPool("", size); + memset(sample_.parameters.get(), 0, size); + } + if (numberDynamicFields > 0) { + sample_.dynamicParameters = makeSharedRawDynamicArray(numberDynamicFields); + } +} + +AutoStreamSample::AutoStreamSample( + const StreamSample& sample, + size_t size, + size_t numberDynamicFields) + : sample_(sample) { + if (!sample_.parameters && size > 0) { + sample_.parameters = Framework::instance().memoryPool()->getBufferFromPool("", size); + memset(sample_.parameters.get(), 0, size); + } + if (!sample_.dynamicParameters && numberDynamicFields > 0) { + sample_.dynamicParameters = makeSharedRawDynamicArray(numberDynamicFields); + } +} + +AutoStreamSample ::~AutoStreamSample() {} + +const StreamSample& AutoStreamSample::getSample() const { + return sample_; +} + +void AutoStreamSample::setSample(const StreamSample& sample) { + sample_ = sample; +} + +HeaderTimestamp::HeaderTimestamp(AutoStreamSample* wrapper) { + wrapper_ = wrapper; +} + +const double& HeaderTimestamp::get() const { + return wrapper_->getSample().metadata->header.timestamp; +} + +HeaderTimestamp::operator const double&() const { + return wrapper_->getSample().metadata->header.timestamp; +} + +void HeaderTimestamp::set(const double& value) { + sample(wrapper_).metadata->header.timestamp = value; +} + +HeaderTimestamp& HeaderTimestamp::operator=(const double& value) { + sample(wrapper_).metadata->header.timestamp = value; + return *this; +} + +HeaderSequence::HeaderSequence(AutoStreamSample* wrapper) { + wrapper_ = wrapper; +} + +uint32_t HeaderSequence::get() const { + return wrapper_->getSample().metadata->header.sequenceNumber; +} + +HeaderSequence::operator const uint32_t&() const { + return wrapper_->getSample().metadata->header.sequenceNumber; +} + +void HeaderSequence::set(const uint32_t& value) { + sample(wrapper_).metadata->header.sequenceNumber = value; +} + +HeaderSequence& HeaderSequence::operator=(const uint32_t& value) { + sample(wrapper_).metadata->header.sequenceNumber = value; + return *this; +} + +ProcessingTimestamp::ProcessingTimestamp(const std::string& stampName, AutoStreamSample* wrapper) + : stampName_(stampName), wrapper_(wrapper) { + // Add the named stamp to the sample if it doesn't exist + wrapper_->getSample().metadata->processingStamps[stampName_]; +} + +const double& ProcessingTimestamp::get() const { + return wrapper_->getSample().metadata->processingStamps.at(stampName_); +} + +ProcessingTimestamp::operator const double&() const { + return wrapper_->getSample().metadata->processingStamps.at(stampName_); +} + +void ProcessingTimestamp::set(const double& value) { + sample(wrapper_).metadata->processingStamps[stampName_] = value; +} + +ProcessingTimestamp& ProcessingTimestamp::operator=(const double& value) { + sample(wrapper_).metadata->processingStamps[stampName_] = value; + return *this; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/SubAligner.cpp b/Cthulhu/src/SubAligner.cpp new file mode 100644 index 000000000..290cf19ca --- /dev/null +++ b/Cthulhu/src/SubAligner.cpp @@ -0,0 +1,513 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include + +#include "SubAlignerImpl.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include +#include + +#include + +namespace { +template +inline double NOW() noexcept { + return std::chrono::duration(clock::now().time_since_epoch()).count(); +} +} // namespace + +namespace cthulhu { + +SubAligner::SubAligner( + const std::vector& settings, + const ThreadPolicy& threadPolicy) + : AlignerBase(threadPolicy), settings_(settings) { + contexts_[0].impl = std::make_unique(); + latestContext_ = 0; + initThread(); +} + +SubAligner::~SubAligner() { + killThread(); + streams_.clear(); +} + +void SubAligner::setPrimaryAlignmentStream(const StreamID& id, double maxLatencySeconds) { + // Required to be called after stream registration. So, we don't need + // to hold the lock when evaluating streams_, since it's not going to + // change size. + for (size_t idx = 0; idx < streams_.size(); ++idx) { + if (streams_[idx].streamID == id) { + const auto globalLock = std::lock_guard(globalMutex_); + finalizeStrategy_ = PrimarySelection(id, idx, maxLatencySeconds); + const auto activeContext = streams_[idx].activeContext; + auto& context = contexts_.at(activeContext); + const auto alignerLock = + std::scoped_lock(context.implMutex, context.streams[idx].streamMutex); + context.streams[idx].interface->primarize(); + return; + } + } + throw std::runtime_error("Desired primary stream '" + id + "' is not registered."); +} + +bool SubAligner::isRegistered(const StreamID& streamID) const { + const auto found = + std::find_if(streams_.cbegin(), streams_.cend(), [&streamID](const auto& alignedStream) { + return alignedStream.streamID == streamID; + }); + + return streams_.cend() != found; +} + +double SubAligner::getMaxLatencyOffset() const { + const auto max = std::max_element( + settings_.cbegin(), settings_.cend(), [](const auto& left, const auto& right) { + return left.timeOffset < right.timeOffset; + }); + const auto maxHint = std::max_element( + settingHints_.cbegin(), settingHints_.cend(), [](const auto& left, const auto& right) { + return left.second.timeOffset < right.second.timeOffset; + }); + const double maxOffset = max != settings_.cend() ? max->timeOffset : 0.0; + const double maxHintOffset = maxHint != settingHints_.cend() ? maxHint->second.timeOffset : 0.0; + return std::max(maxOffset, maxHintOffset); +} + +void SubAligner::registerConsumer(StreamInterface* si, int index) { + { + std::lock_guard lock(globalMutex_); + if (streams_.size() <= index) { + streams_.resize(index + 1); + } + } + SampleCallback callback = [this, index](const StreamSample& sample) -> void { + sampleCallback(index, sample); + }; + ConfigCallback ccallback = [this, index](const StreamConfig& config) -> bool { + return configCallback(index, config); + }; + streams_[index].streamID = si->description().id(); + streams_[index].consumer = std::make_unique(si, callback, ccallback); +} + +void SubAligner::setStreamSettingHint(const StreamID& id, const StreamSettings& settings) { + settingHints_[id] = settings; +} + +void SubAligner::setDefaultMetronome(bool value) { + defaultUseMetronome_ = value; +} + +void SubAligner::align() { + if (!finalized_) { + return; + } + + std::lock_guard lock(globalMutex_); + + std::set activeContexts; + { + for (const auto& stream : streams_) { + activeContexts.insert(stream.activeContext); + } + } + + auto context_itr = contexts_.begin(); + while (context_itr != contexts_.end()) { + // Clear out old contexts + if (contexts_.size() > 1 && activeContexts.find(context_itr->first) == activeContexts.end()) { + context_itr->second.impl->flush(); + context_itr = contexts_.erase(context_itr); + continue; + } + + // Run alignment + std::vector manifests; + { + std::lock_guard lock2(context_itr->second.implMutex); + auto res = context_itr->second.impl->align(-1); + manifests = context_itr->second.impl->retrieve(); + if (res <= 0 && manifests.empty()) { + ++context_itr; + continue; + } + } + processManifests(manifests, lock, context_itr->second); + ++context_itr; + } +} + +void SubAligner::processManifests( + const std::vector& manifests, + const std::lock_guard& globalMutexLock, + AlignerContext& context) { + // Flatten data and execute callbacks + for (auto& manifest : manifests) { + if (manifest.completed_streams.size() != streams_.size()) { + for (auto& stream : manifest.references) { + auto sindex = context.lookupIndex.at(stream.first); + auto sampleSize = + std::max(context.streams.at(sindex).config.sampleSizeInBytes, uint32_t(1)); + auto& sampleMap = context.streams.at(sindex).sampleMap; + for (auto& r : stream.second) { + if (r.nrbytes_offset + r.nrbytes_length == + (r.buffer_tagged.nrsamples_total * sampleSize)) { + sampleMap.erase(r.buffer_tagged.sequence_number); + } + } + } + + // Log which stream(s) was (were) missing, as it helps with troublshooting + fmt::memory_buffer buffer; + bool comma = false; + for (int stream_idx = 0; stream_idx < streams_.size(); ++stream_idx) { + if (0 == manifest.completed_streams.count(stream_idx)) { + fmt::format_to(buffer, "{}{}", comma ? "," : "", streams_[stream_idx].streamID); + comma = true; + } + } + + XR_LOGW( + "Subaligner::processManifests - Finalized an incomplete manifest, missing: {}", + buffer.data()); + continue; + } + // check if we need to bother with creating output samples when nobody consumes them (e.g. only + // records alignment metadata) + const bool samplesNeeded = hasSampleCallback() && !inhibitSampleCallback_; + + std::vector samples(streams_.size()); + AlignerSamplesMeta samplesMeta(streams_.size()); + for (auto& stream : manifest.references) { + auto sindex = context.lookupIndex.at(stream.first); + std::lock_guard lock(context.streams.at(sindex).streamMutex); + auto* const sample = samplesNeeded ? &samples[sindex] : nullptr; + auto& sampleMeta = samplesMeta[sindex]; + if (stream.second.size() > 0) { + size_t length = 0; + auto& sampleMap = context.streams.at(sindex).sampleMap; + const uint32_t sampleSize = context.streams.at(sindex).config.sampleSizeInBytes; + sampleMeta.references.resize(stream.second.size()); + size_t ridx = 0; + for (auto& r : stream.second) { + if (sampleMap.find(r.buffer_tagged.sequence_number) == sampleMap.end()) { + XR_LOGD( + "Subaligner::processManifests - Attempted to close a reference for which we've " + "don't have a sample."); + return; + } + sampleMeta.references[ridx].timestamp = + sampleMap[r.buffer_tagged.sequence_number].metadata->header.timestamp; + sampleMeta.references[ridx].sequenceNumber = + sampleMap[r.buffer_tagged.sequence_number].metadata->header.sequenceNumber; + sampleMeta.references[ridx].subSampleOffset = r.nrbytes_offset / sampleSize; + sampleMeta.references[ridx].numSubSamples = r.nrbytes_length / sampleSize; + length += r.nrbytes_length; + std::string sequenceString = std::to_string(r.buffer_tagged.sequence_number); + // Copy full history + if (sample) { + sample->metadata->history["subaligner_" + sequenceString] = + sampleMap[r.buffer_tagged.sequence_number].metadata; + sample->metadata->processingStamps["subaligner_" + sequenceString + "_start"] = + sampleMap[r.buffer_tagged.sequence_number] + .metadata->processingStamps["subaligner_start"]; + } + ++ridx; + } + uint8_t* ptr = nullptr; + if (sample) { + // allocate buffer for the output "flattened" sample + sample->parameters = sampleMap[stream.second[0].buffer_tagged.sequence_number].parameters; + sample->numberOfSubSamples = length / sampleSize; + sample->payload = Framework::instance().memoryPool()->getBufferFromPool( + streams_.at(sindex).streamID, length); + ptr = ((CpuBuffer)sample->payload).get(); + } + for (auto& r : stream.second) { + if (ptr) { + std::copy( + r.buffer_tagged.buffer_durational.buffer.get() + r.nrbytes_offset, + r.buffer_tagged.buffer_durational.buffer.get() + r.nrbytes_offset + + r.nrbytes_length, + ptr); + ptr += r.nrbytes_length; + } + + if (r.nrbytes_offset + r.nrbytes_length == + (r.buffer_tagged.nrsamples_total * sampleSize) && + sampleMap.find(r.buffer_tagged.sequence_number) != sampleMap.end()) { + sampleMap.erase(r.buffer_tagged.sequence_number); + } + } + // finalize sample header, first sample might be partial, compensate for the potential + // offset + const double samplePeriod = 1.0 / stream.second[0].buffer_tagged.sample_rate; + const double sample_timestamp = + stream.second[0].buffer_tagged.buffer_durational.duration.start_time + + double(stream.second[0].nrbytes_offset / sampleSize) * samplePeriod; + double sample_duration = double(length) / sampleSize * samplePeriod; + if (sample) { + sample->metadata->header.sequenceNumber = streams_.at(sindex).sequenceOut++; + sample->metadata->header.timestamp = sample_timestamp; + } + // effective computed duration of the manifest for this sample + sampleMeta.timestamp = sample_timestamp; + sampleMeta.duration = sample_duration; + } + } + // Check configs and execute + if (!context.configured) { + std::vector configs; + configs.reserve(context.streams.size()); + AlignerConfigsMeta configsMeta; + configsMeta.reserve(context.streams.size()); + size_t idx = 0; + for (const auto& stream : context.streams) { + configs.push_back(stream.second.config); + configsMeta.push_back( + AlignerStreamMeta{streams_[idx].streamID, stream.second.config.sampleSizeInBytes}); + idx++; + } + if (configs.size() == streams_.size()) { + inhibitSampleCallback_ = !alignedConfigCallback(configs); + context.configured = true; + alignedConfigsMetaCallback(configsMeta); + } + } + + if (!inhibitSampleCallback_) { + alignedSamplesMetaCallback(samplesMeta); + if (samplesNeeded) { + const auto seconds = NOW(); + for (const auto& sample : samples) { + sample.metadata->processingStamps["subaligner_end"] = seconds; + } + alignedCallback(samples); + } + } + } +} + +void SubAligner::enroll( + size_t idx, + const StreamConfig& config, + AlignerContext& context, + const std::lock_guard&) { + std::lock_guard lock(context.implMutex); + + // Get time offset and metronome + double offset = 0.0; + bool metronome = defaultUseMetronome_; + if (settings_.size() > idx) { + offset = settings_[idx].timeOffset; + metronome = settings_[idx].useMetronome; + } + + // Override with any hints + if (settingHints_.find(streams_[idx].streamID) != settingHints_.end()) { + const auto& sid = streams_[idx].streamID; + offset = settingHints_[sid].timeOffset; + metronome = settingHints_[sid].useMetronome; + } + + auto& streamData = context.streams[idx]; + // Enroll in aligner and store interface + streamData.interface = context.impl->enroll( + (config.sampleSizeInBytes != 0 ? config.sampleSizeInBytes : 1), + metronome ? config.nominalSampleRate : 0.0, + -offset); + XR_LOGT( + "Enrolling {} @ {:.3f} fps, {}using metronome.", + streams_[idx].streamID, + config.nominalSampleRate, + metronome ? "" : "NOT "); + + context.lookupIndex[context.streams[idx].interface->index()] = idx; + // Store config + streamData.config = config; + + if (0 == idx) { + context.streams[idx].interface->primarize(); + if (config.nominalSampleRate > 0.0) { + finalizeStrategy_ = 0.5 * config.nominalSampleRate + getMaxLatencyOffset(); + } + } +} + +void SubAligner::sampleCallback(size_t idx, const StreamSample& sample) { + int activeContext; + { + std::lock_guard lock(globalMutex_); + + activeContext = streams_[idx].activeContext; + + // Force everything onto the latest context, for the case where not all streams are + // reconfigured simultaneously + // Note: It may be better to estimate start/end-times for the contexts to determine + if (activeContext < latestContext_) { + auto& config = contexts_[activeContext].streams[idx].config; + streams_[idx].activeContext = latestContext_; + activeContext = latestContext_; + auto& context = contexts_.at(activeContext); + enroll(idx, config, context, lock); + } + } + + auto& context = contexts_.at(activeContext); + + if (std::holds_alternative(finalizeStrategy_) && + !std::get(finalizeStrategy_) + .isWithinTolerance(sample.metadata->header.timestamp)) { + XR_LOGW_EVERY_N_SEC( + 5, + "Too old sample arrived on stream: #{}, '{}', stamp: {}, tolerance: {}", + idx, + streams_[idx].streamID.c_str(), + sample.metadata->header.timestamp, + std::get(finalizeStrategy_).maxLatencySeconds); + // dump sample + return; + } + + // feed underlying aligner + { + sample.metadata->processingStamps["subaligner_start"] = NOW(); + const auto alignerLock = std::scoped_lock(context.implMutex, context.streams[idx].streamMutex); + // Store the sample data + const uint32_t seq = context.streams[idx].sequenceIn++; + context.streams[idx].sampleMap[seq] = sample; + if (!hasSampleCallback()) { + // Drop payload: we don't need to carry this buffer around for alignment, since + // we won't look at it later. + context.streams[idx].sampleMap[seq].payload = nullptr; + } + + // Feed data in aligner, but act only on the "metadata" as the references are already held by + // sampleMap + const size_t buffer_size = + sample.numberOfSubSamples * context.streams[idx].config.sampleSizeInBytes; + + // If the sampling rate for a stream is unknown, propose an end time that's 1ms + // in the future. I'm not sure why this is necessary, since it seems this should + // be something handled by the aligner itself. But, it's a carry over from the + // ArgentCapture library, where this exact computation was done for data without + // a sampling rate (vision pose, rendered pose, IMU, etc.) + // + // Without this end time computation, we cannot align streams that don't have a + // known sampling rate. This does nothing when the sample rate for a stream is + // known, since the default behavior of feed() is to inline -1.0 for the end time. + const double endTime = (0.0 == context.streams[idx].config.nominalSampleRate) + ? (sample.metadata->header.timestamp + 0.001) + : -1.0; + + context.streams[idx].interface->feed( + hasSampleCallback() ? (CpuBuffer)sample.payload : nullptr, + buffer_size, + sample.metadata->header.timestamp, + endTime); + } + + { + std::lock_guard lock(context.implMutex); + + // If there's no primary stream, finalize all streams that are determined to be + // lagging given the current sample timestamp. If there IS a primary stream, + // finalize all streams that are determined to be lagging given the primary stream's + // latest sample. + if (std::holds_alternative(finalizeStrategy_)) { + const double maxLatency = std::get(finalizeStrategy_); + context.impl->finalizeBefore(sample.metadata->header.timestamp - maxLatency); + } else { + auto& primarySelection = std::get(finalizeStrategy_); + context.impl->finalizeBefore( + sample.metadata->header.timestamp - primarySelection.maxLatencySeconds); + primarySelection.setReference(sample.metadata->header.timestamp); + } + } + if (policy_ == ThreadPolicy::THREAD_NEUTRAL) { + align(); + } +} + +bool SubAligner::configCallback(size_t idx, const StreamConfig& config) { + std::lock_guard lock(globalMutex_); + int activeContext = streams_[idx].activeContext + 1; + streams_[idx].activeContext = activeContext; + + // If an aligner doesn't exist for the new context, make it + if (contexts_.find(activeContext) == contexts_.end()) { + contexts_[activeContext].impl = std::make_unique(); + latestContext_ = std::max(activeContext, latestContext_); + } + auto& context = contexts_.at(activeContext); + + enroll(idx, config, context, lock); + + return true; +} + +void SubAligner::clear() { + const std::lock_guard globalLock(globalMutex_); + for (auto& [_, context] : contexts_) { + const std::lock_guard implLock(context.implMutex); + context.impl->finalize(); + context.impl->align(); + context.impl->retrieve(); + for (auto& [_, streamContext] : context.streams) { + const std::lock_guard streamLock(streamContext.streamMutex); + streamContext.sampleMap.clear(); + } + } +} + +std::optional PrimaryAlignmentStream::bestImageStream( + const SubAligner& aligner, + const std::vector& streamIDs, + double maxLatencyFraction) { + std::unordered_map imageStreamConfigs; + const auto imageType = cthulhu::Framework::instance().typeRegistry()->findTypeName("Image"); + for (const auto& streamID : streamIDs) { + if (const auto stream = cthulhu::Framework::instance().streamRegistry()->getStream(streamID); + stream && stream->description().type() == imageType->typeID()) { + if (!aligner.isRegistered(streamID)) { + const auto msg = fmt::format( + "Stream ID '{}' is up for primary image stream election, but it's unknown to the aligner. " + "Ensure that the stream is registered with the aligner", + streamID); + XR_LOGE("{}", msg); + throw std::runtime_error(msg); + } else { + imageStreamConfigs[streamID] = stream->config(); + } + } + } + + if (imageStreamConfigs.empty()) { + return std::nullopt; + } + + // Dereference OK; guaranteed to have at least one element + const auto& [streamID, config] = *std::min_element( + imageStreamConfigs.cbegin(), + imageStreamConfigs.cend(), + [](const auto& left, const auto& right) { + return left.second.nominalSampleRate < right.second.nominalSampleRate; + }); + + if (0.0 == config.nominalSampleRate) { + const auto msg = fmt::format( + "Stream ID '{}' has a sample rate of zero! We can't compute the allowable offset from that."); + XR_LOGE("{}", msg); + throw std::runtime_error(msg); + } + const double maxLatencyOffset = + maxLatencyFraction * (1.0 / config.nominalSampleRate) + aligner.getMaxLatencyOffset(); + + return PrimaryAlignmentStream::Election{streamID, maxLatencyOffset}; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/SubAlignerImpl.cpp b/Cthulhu/src/SubAlignerImpl.cpp new file mode 100644 index 000000000..e4f73c299 --- /dev/null +++ b/Cthulhu/src/SubAlignerImpl.cpp @@ -0,0 +1,440 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "SubAlignerImpl.h" + +#include + +namespace cthulhu { + +namespace subaligner { + +StreamInterface::StreamInterface(Aligner* aligner, int identifier) + : aligner_(aligner), identifier_(identifier) { + assert(aligner_ != nullptr); +} + +int StreamInterface::index() const { + return identifier_; +} + +void StreamInterface::release() { + aligner_->release(identifier_); +} + +void StreamInterface::primarize() { + aligner_->primarize(identifier_); +} + +bool StreamInterface::isPrimary() { + return aligner_->isPrimary(identifier_); +} + +double StreamInterface::obtainSamplePeriod(int multiplier) const { + return aligner_->obtainSamplePeriod(identifier_, multiplier); +} + +void StreamInterface::feed( + const Buffer& buf, + size_t buf_size, + double start_time, + double end_time, + double surrogate_timestamp) { + aligner_->enqueue(identifier_, buf, buf_size, start_time, end_time, surrogate_timestamp); +} + +Statistics StreamInterface::getStats() const { + return aligner_->getStats(identifier_); +} + +// struct Aligner::Metronome +// ========================= +// Public Methods + +void Aligner::Metronome::propagate(BufferDurationalTagged& batch) { + if (previous_batch.buffer_durational.duration.end_time < + previous_batch.buffer_durational.duration.start_time) { + previous_batch.buffer_durational.duration.end_time = + batch.buffer_durational.duration.start_time; + previous_batch.sample_rate = static_cast(previous_batch.nrsamples_total) / + (previous_batch.buffer_durational.duration.end_time - + previous_batch.buffer_durational.duration.start_time); + } + + if (previous_batch.sample_rate > 0) + update(previous_batch); + else + reference_time_estimate.decimal = batch.buffer_durational.duration.start_time; + + previous_batch.buffer_durational.duration = batch.buffer_durational.duration; + previous_batch.nrsamples_total = batch.nrsamples_total; + previous_batch.sample_rate = batch.sample_rate; + + batch.sample_rate = sample_rate_estimate.decimal; + batch.buffer_durational.duration.start_time = + nrsamples_cumulative / sample_rate_estimate.decimal + reference_time_estimate.decimal; + batch.buffer_durational.duration.end_time = batch.buffer_durational.duration.start_time + + batch.nrsamples_total / sample_rate_estimate.decimal; +} + +double Aligner::Metronome::obtainSampleRateEstimate() const { + return sample_rate_estimate.decimal; +} + +void Aligner::Metronome::reset() { + // The sample rate estimate is slightly regulated to be closer to the nominal rate. + sample_rate_estimate.numerator = 1; + sample_rate_estimate.denominator = nominal_rate; + sample_rate_estimate.decimal = nominal_rate; + + // Some of the fields that will be used for updates need to be initialized. + previous_batch.buffer_durational.duration.start_time = 0; + previous_batch.buffer_durational.duration.end_time = 1; + previous_batch.sample_rate = -1; + + reference_time_estimate = Fraction(); + nrsamples_cumulative = 0; +} + +Aligner::Metronome::Metronome(size_t _sample_bytewidth, double _nominal_rate) + : sample_bytewidth(_sample_bytewidth), nominal_rate(_nominal_rate) { + reset(); +} + +// struct Aligner::Metronome +// ========================= +// Protected Methods + +void Aligner::Metronome::update(const BufferDurationalTagged& batch) { + // Update the estimation of the reference time. This time is what all refined timestamps + // would be referencing to - whereas using the timestamp of the first batch would lead to + // systematic bias if the first timestamp is biased. + + reference_time_estimate.denominator += 1; + reference_time_estimate.numerator += + (batch.buffer_durational.duration.start_time + batch.buffer_durational.duration.end_time - + batch.nrsamples_total / sample_rate_estimate.decimal) / + 2.0 - + nrsamples_cumulative / sample_rate_estimate.decimal; + reference_time_estimate.decimal = + reference_time_estimate.numerator / reference_time_estimate.denominator; + + // Update the estimateion for the sample rate. The sample rate and time reference are solutions + // to a least-squares optimization problem based on the history of start times and number of + // samples, by essentially fitting them onto a line. Those two variables in question are the + // slope and intercept respectively. + + sample_rate_estimate.denominator += + 2.0 * nrsamples_cumulative * (nrsamples_cumulative + batch.nrsamples_total) + + batch.nrsamples_total * batch.nrsamples_total; + sample_rate_estimate.numerator += nrsamples_cumulative * + (batch.buffer_durational.duration.start_time + batch.buffer_durational.duration.end_time - + 2.0 * reference_time_estimate.decimal) + + batch.nrsamples_total * + (batch.buffer_durational.duration.end_time - reference_time_estimate.decimal); + sample_rate_estimate.decimal = sample_rate_estimate.denominator / sample_rate_estimate.numerator; + + nrsamples_cumulative += batch.nrsamples_total; +} + +StreamInterface* Aligner::enroll(size_t sample_bytewidth, double timestamp_offset) { + Stream stream; + stream.nrbytes_pending = 0; + stream.nrsamples_processed = 0; + stream.manifest_upstream_index = 0; + stream.deficit = 0.0; + stream.identifier = static_cast(registry_.size()); + stream.sample_bytewidth = sample_bytewidth; + stream.timestamp_offset = timestamp_offset; + + auto identifier = stream.identifier; + registry_[identifier] = new Stream(stream); + stream_interfaces_.emplace(identifier, new StreamInterface(this, identifier)); + return stream_interfaces_[identifier]; +} + +StreamInterface* +Aligner::enroll(size_t sample_bytewidth, double nominal_rate, double timestamp_offset) { + auto feeder = enroll(sample_bytewidth, timestamp_offset); + if (nominal_rate > 0.0) { + registry_[feeder->identifier_]->metronome = // install a metronome for fixed-rate data stream. + std::make_shared(sample_bytewidth, nominal_rate); + } + + return feeder; +} + +void Aligner::primarize(int identifier) { + primary_stream_id = identifier; +} + +bool Aligner::isPrimary(int identifier) const { + return (primary_stream_id == identifier); +} + +void Aligner::release(int identifier) { + registry_.erase(identifier); + stream_interfaces_.erase(identifier); +} + +double Aligner::obtainSamplePeriod(int identifier, int multiplier) const { + double sample_rate = -1.0; + + auto it = registry_.find(identifier); + if (it != registry_.cend()) { + auto& stream = it->second; + if (stream->metronome) + sample_rate = stream->metronome->obtainSampleRateEstimate(); + else if (!stream->batches.empty()) + sample_rate = stream->batches.front().sample_rate; + } + + // Implicit upcast to double. + return multiplier / sample_rate; +} + +Statistics Aligner::getStats(int identifier) const { + auto it = registry_.find(identifier); + if (it != registry_.cend()) + return it->second->stats; + else + return Statistics(); +} + +void Aligner::enqueue( + int identifier, + const Buffer& buf, + size_t buf_size, + double start_time, + double end_time, + double surrogate_timestamp) { + auto& stream = *registry_[identifier]; // This cannot possibly fail. + + BufferDurationalTagged batch; + batch.sequence_number = stream.stats.batches_received; + batch.nrsamples_total = buf_size / stream.sample_bytewidth; + batch.nrsamples_current = 0; + batch.sample_rate = 1.0; + batch.duration_unadjusted.start_time = start_time + stream.timestamp_offset; + batch.duration_unadjusted.end_time = end_time + stream.timestamp_offset; + batch.buffer_durational.buffer = buf; + batch.buffer_durational.duration = batch.duration_unadjusted; + assert(batch.nrsamples_total * stream.sample_bytewidth == buf_size); + + stream.stats.batches_received += 1; + stream.stats.samples_received += batch.nrsamples_total; + + // There are two possibilities on the end_time: if it is less than the start time, + // the invoker chooses not to provide a valid lifespan for this batch, in which case + // the determintion of the end time is deferred until the receipt of the next batch, + // the start time of which will be used as the end time here; or, if it is equal to or + // greater than the start time, the lifespan is valid and should be used immediately. + // The metronome regulates the start and end times in either cases. + + std::vector duration_requests; + auto finalizeBatch = [&](BufferDurationalTagged& batch) { + duration_requests.push_back(&batch.buffer_durational.duration); + batch.sample_rate = static_cast(batch.nrsamples_total) / + (batch.buffer_durational.duration.end_time - batch.buffer_durational.duration.start_time); + }; + + if (stream.metronome) + stream.metronome->propagate(batch); // This potentially ratifies the batch's linespan. + if (batch.buffer_durational.duration.end_time > batch.buffer_durational.duration.start_time) + finalizeBatch(batch); + if (!stream.batches.empty()) { + auto& previous_batch = stream.batches.back(); + if (previous_batch.buffer_durational.duration.end_time < + previous_batch.buffer_durational.duration.start_time) { + previous_batch.buffer_durational.duration.end_time = + batch.buffer_durational.duration.start_time; + finalizeBatch( + previous_batch); // Populate the duration requests and calculate the sample rate. + } + } + + // If the identifier is not equal to the primary stream identifier, we would not + // need to put into the requests for manifests. In that case, the list of potential + // duration requests are cleared. + + if (identifier != primary_stream_id) { + duration_requests.clear(); + } + + std::for_each(duration_requests.begin(), duration_requests.end(), [&](Duration* duration) { + request(duration->start_time, duration->end_time); + }); + + stream.batches.push_back(std::move(batch)); + return; +} + +void Aligner::request(double start_time, double end_time) { + Manifest manifest; + manifest.duration.start_time = start_time; + manifest.duration.end_time = end_time; + for (auto& stream : registry_) + stream.second->deficit += start_time - end_time; + + active_manifests_.push_back(std::move(manifest)); + return; +} + +int Aligner::finalizeOne() { + if (!active_manifests_.empty()) { + auto& manifest = active_manifests_.front(); + + // This statement implements the following semantics: if the user decides to forcefully + // finalize one manifest, samples that arrive after that point will not be retrospectively + // considered for alignment in that finalized manifest anymore; instead, they will be + // only considered for the subsequent manifest requests. + + for (auto& stream : registry_) + stream.second->manifest_upstream_index = + std::max(stream.second->manifest_upstream_index - 1, 0); + + // If there is an active manifest, we finalize it by passing it to the completed + // manifest queue for shipment, regardless of its completion status. Stats are also updated. + + for (const auto& pair : manifest.references) { + auto& stream = *registry_[pair.first]; + stream.stats.batches_emitted++; + stream.stats.samples_emitted += stream.nrsamples_processed; + stream.nrbytes_pending -= stream.nrsamples_processed * stream.sample_bytewidth; + stream.nrsamples_processed = 0; + } + + completed_manifests_.push_back(std::move(manifest)); + active_manifests_.pop_front(); + return 1; + } + + return 0; +} + +int Aligner::finalize(int nr_manifests) { + int nr_finalized = 0; + while (nr_finalized < nr_manifests && finalizeOne() > 0) + nr_finalized++; + + return nr_finalized; +} + +int Aligner::finalizeBefore(double time_point) { + int nr_finalized = 0; + while (!active_manifests_.empty()) { + auto& manifest = active_manifests_.front(); + if (manifest.duration.end_time < time_point) + nr_finalized += finalizeOne(); + else + break; + } + + return nr_finalized; +} + +void Aligner::flush() { + nr_manifests_emitted = 0; + nr_manifests_completed = 0; + active_manifests_.clear(); + completed_manifests_.clear(); + for (auto& item : registry_) { + auto& stream = item.second; + if (stream->metronome) + stream->metronome->reset(); + + stream->stats = {}; + stream->nrbytes_pending = 0; + stream->nrsamples_processed = 0; + stream->manifest_upstream_index = 0; + stream->deficit = 0; + stream->batches.clear(); + } +} + +int Aligner::align(int identifier_hint) { + bool should_switch = false; // Should switch to another stream? + + // A non-negative identifier hint means that a batch of samples from the corresponding stream + // has been received, and we should examine the possiblity for alignment of all manifests for + // that stream. + std::vector relevant_streams; + if (identifier_hint >= 0) + relevant_streams.push_back(identifier_hint); + else { + // If the hint is negative, examine all the streams. + relevant_streams.resize(registry_.size()); + std::iota(relevant_streams.begin(), relevant_streams.end(), 0); + } + + for (const auto& identifier : relevant_streams) { + should_switch = false; + auto& stream = *registry_[identifier]; + + // Attempt for alignment if there are active manifests and batches. Continue until + // either all manifests are complete of this stream or there are no batches anymore. + + while (!should_switch && stream.manifest_upstream_index < active_manifests_.size()) { + auto& manifest = active_manifests_[stream.manifest_upstream_index]; + should_switch = stream.batches.empty(); + // Cannot proceed if we don't have batches for alignment business. + + while (!should_switch && !stream.batches.empty()) { + auto& batch = stream.batches.front(); + if (batch.buffer_durational.duration.end_time < + batch.buffer_durational.duration.start_time) { + should_switch = true; + break; // Cannot proceed if the batch doesn't have an end time. + } + + // The manifest proposes the new offset in units of samples within the active batch to be + // this much... 0.5 is added to enforce the fifth assumption - see above and consider that + // double -> size_t is truncation. + auto proposed_sampleoffset = static_cast( + batch.sample_rate * + (manifest.duration.end_time - batch.buffer_durational.duration.start_time) + + 0.5); + if (proposed_sampleoffset <= static_cast(batch.nrsamples_current)) { + // This means that the request does not require samples beyond the current pointer + // within the batch. Consider the manifest to be complete of this stream in this case. + + manifest.completed_streams.insert(identifier); + stream.manifest_upstream_index++; // Proceed to the next manifest. + if (manifest.completed_streams.size() == registry_.size()) + nr_manifests_completed += finalizeOne(); + + // Break to obtain reference to the new manifest. + break; + } else { + // nr_samples can only be zero if and and only if batch.nrsamples_total = + // batch.nrsamples_current, in which case this batch should be dropped. If it is + // non-zero, insert a reference to the container. + size_t nr_samples = + std::min(static_cast(proposed_sampleoffset), batch.nrsamples_total) - + batch.nrsamples_current; + + if (!nr_samples) + stream.batches.pop_front(); + else { + Reference ref; + ref.nrbytes_offset = batch.nrsamples_current * stream.sample_bytewidth; + ref.nrbytes_length = nr_samples * stream.sample_bytewidth; + batch.nrsamples_current += nr_samples; + ref.buffer_tagged = batch; + + stream.nrsamples_processed += nr_samples; + stream.nrbytes_pending -= ref.nrbytes_length; + stream.deficit -= nr_samples / batch.sample_rate; + manifest.references[identifier].push_back(std::move(ref)); + + } // if (nr_samples) + } // if (proposed > current) + } // stream.batches.empty + } // head < size. + } // identifiers. + + return static_cast(nr_manifests_completed); +} + +} // namespace subaligner + +} // namespace cthulhu diff --git a/Cthulhu/src/SubAlignerImpl.h b/Cthulhu/src/SubAlignerImpl.h new file mode 100644 index 000000000..5d7f1ebcf --- /dev/null +++ b/Cthulhu/src/SubAlignerImpl.h @@ -0,0 +1,293 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Thread-Safety Consideration +// =========================== +// +// 1. The method enroll is not thread-safe and must be called sequentially. +// 2. The method enqueue can be called on different streams concurrently. +// 3. The method request must be called sequentially. +// 4. The method finalizeOne is not thread-safe. +// 5. The method finalize is not thread-safe. +// 6. The method align is definitely not thread-safe. + +namespace cthulhu { + +namespace subaligner { + +using Buffer = std::shared_ptr; + +struct Duration { + double start_time; + double end_time; +}; + +struct BufferDurational { + Buffer buffer; + Duration duration; +}; + +struct Statistics { + size_t samples_emitted = 0; + size_t samples_received = 0; + size_t batches_emitted = 0; + size_t batches_received = 0; +}; + +class Aligner; + +struct StreamInterface { + // Allow for mutual access of protected internal methods. + friend class Aligner; + explicit StreamInterface(Aligner* aligner, int identifier); + + //! Retrieve the index of this data stream. + int index() const; + //! Release this control interface and its associated stream. + void release(); + //! Designate this stream as the primary stream for automatic duration request. + void primarize(); + //! Check if this is the primary stream + bool isPrimary(); + // Retrieve an estimation of the sample period. + double obtainSamplePeriod(int multiplier = 1) const; + //! Feed a stamped batch of samples to the aligner for alignment. + void feed( + const Buffer& buf, + size_t buf_size, + double start_time, + double end_time = -1.0, + double surrogate_timestamp = -1.0); + //! Returns stream statistics. + Statistics getStats() const; + + protected: + Aligner* aligner_; + //!< A pointer to the aligner that's processing all the alignment stuff + int identifier_; //!< The identifier of the stream whose access is exposed via this interface. +}; + +struct BufferDurationalTagged { + double sample_rate; //!< The number of samples per unit time (second). + size_t sequence_number; //!< A sequence number for this buffer within some stream. + size_t nrsamples_total; //!< The total number of samples represented by this buffer. + size_t nrsamples_current; //!< The number of samples that are considered to have been used. + Duration duration_unadjusted; //!< The raw duration provided by the invoker, without adjustment. + BufferDurational + buffer_durational; //!< The managed buffer stamped with a duration, possibly adjusted. +}; + +struct Reference { + size_t nrbytes_offset; + size_t nrbytes_length; + BufferDurationalTagged buffer_tagged; +}; + +struct Manifest { + Duration duration; + std::set completed_streams; + std::unordered_map> references; +}; + +/* Aligner: Requirements and Assumptions + * ===================================== + * + * + * 1. The requested durations should not overlap and their start times should be + * monotonically increasing. Otherwise, the behavior is still well defined, but + * may not reflect the intended alignment policy: since each sample for each + * stream is used exactly once, durations that have overlap with previously + * requested ones will not reuse the samples that fall into the overlap region; + * also references to used samples are effectively dropped, such that durations + * that are old may have nothing aligned to it at all. Note that sometimes the + * presence of noice on the timestamps will slightly violate this assumption, but + * typically only a small number of samples are affected on the noisy band. + * + * 2. The linespans for sample batches for each stream should not overlap and their + * start times should be monotonically increasing. This ensures that each manifest, + * in service of the requested durations mentioned in 1. have samples whose time-stamps + * are also monotonically increasing. In service of a requested duration, references + * to praticular segments into the batches that are considered inclusive (see 5.) + * are added to the manifest based on the order of receipt of the batches, not + * necessarily their actual start times. This means that, if the assumption is violated, + * certain samples that are temporally after some other samples, although received earlier + * will appear earlier in the list of references in the manifest; the samples in the manifest + * for that particular stream no longer have monotonically increasing timestamps. Note that + * sometimes the presence of noise on the timestamps will slightly make the linespans + * overlap, but since each sample is used exactly once, this should have little impact. + * + * 3. The sizes for all the samples delivered on a particular stream must be + * identical. Otherwise, since the aligned batches are emitted asychronously + * with the incoming batches, some mechanism must be in place to track these + * sizes and possibly their semantics. This increases the complexity of the + * class (albeit making perfect sense in terms of the alignment operation), + * yet does not have a good use case for it to be justified. This is forcefully + * restricted, as the user cannot specify the number of samples for each batch; + * the number of bytes, combined with the sample byte width specified on instantiation, + * uniquely dictates the number of samples. If the number of bytes is not a + * multiple of the byte width, assertion may be raised. + * + * 4. Samples in each individual batch have identical lifespans (i.e., end time + * minus start time) and are temporally contiguous. This means that the duration + * of the batch is evenly distributed over all the samples. To specify different + * lifespans for individual samaples, use multiple batches instead. + * + * 5. A sample is considered to be inclusive of a duration if the middle point of + * its lifespan is. Specifying another point would destory the symmetry semantics; + * specifying two symmetric points with respect to the middle point, will either + * lead to one sample being automatically aligned with two successive requested + * durations, or one part of the duration not having well-defined semantics. + * + */ + +class Aligner { + /* Metronome: Additional Assumption + * ================================ + * + * 6. The rate, defined as the number of samples (fractional) within an arbitrarily small + * duration, divided by that duration, is fixed for all the samples from a particular + * stream. This means that: a) there should be no gap in the stream, b) the lifespan ( + * end time - start time) is identical for all samples, c) no two samples can have + * overlapping lifespans. This should be the predominant situation for most streams. + * + * This class essentially assumes a fixed rate and estimates an end time for each batch, + * given its start time and a history of start times and batch sizes, thus eliminating + * the need for the user to perform this calculation. + * + */ + + struct Metronome { + //! Construct a metronome of a particular byte width and nominal rate. + explicit Metronome(size_t _sample_bytewidth, double _nominal_rate); + //! Estimate the end time of this batch and update the corresponding field. + void propagate(BufferDurationalTagged& batch); + //! Obtain the current estimation of the sample rate. + double obtainSampleRateEstimate() const; + //! Resets frame rate estimation + void reset(); + + protected: + //! Update the estimation of the initial time reference and the sample rate. + void update(const BufferDurationalTagged& batch); + + struct Fraction { + double numerator = 0; + double denominator = 0; + double decimal = 0; + }; + + size_t sample_bytewidth; //!< The width of each individual sample in bytes. + double nrsamples_cumulative = + 0; //!< The cumulative number of samples this metronome has ever received. + double nominal_rate = 0; + Fraction + reference_time_estimate; //!< An estimation of the reference time (time base) of the stream. + Fraction sample_rate_estimate; //!< An estimation of the sample rate of the stream. + BufferDurationalTagged + previous_batch; //!< A container for some information in the previous batch. No buffer. + }; + + public: + struct Stream { + Statistics stats; //!< A suite of statistics on the samples received and emitted. + size_t nrbytes_pending; //!< The total number of bytes that have been received but not yet + //!< aligned to anything. + size_t nrsamples_processed; //!< The number of samples in the currently active batch that have + //!< been aligned to something. + int manifest_upstream_index; //!< The index of the manifest in the active manifest queue that + //!< this stream is working on. + double deficit; //!< The sum of requested durations that cannot be serviced due to lack of data + //!< on this stream. + + int identifier; //!< An unique identifier to this stream. + size_t sample_bytewidth; //!< The size of one sample in bytes (that shall remain unchanged over + //!< the entire session). + double timestamp_offset; //!< An offset that should be applied to all start and end times for + //!< incoming batches of samples. + std::shared_ptr + metronome; //!< An Discretional metronome that produces an estimation of the global sample + //!< rate and regulates the timestamps. + std::deque batches; //!< A queue of batches to be aligned. + }; + + // This grants access to the enqueue internal method. + friend struct StreamInterface; + + //! Enroll a stream into the aligner. + StreamInterface* enroll(size_t sample_bytewidth, double timestamp_offset); + //! Enroll a stream that has a fixed nominal rate into the aligner. + StreamInterface* enroll(size_t sample_bytewidth, double nominal_rate, double timestamp_offset); + //! Request references to samples within a particular duration, should be followed by a call to + //! align + void request(double start_time, double end_time); + //! Forcifully finalize currently active manifests despite their completion status. + int finalize(int nr_manifests = 1); + //! Finalize all the manifests before the specified time-point regardless of their completion + //! status. + int finalizeBefore(double time_point); + //! Attempt alignment on the stream corresponding to the identifier hint. + int align(int identifier_hint = -1); + + //! Retrieve a list of manifests that are currently available. + std::vector retrieve() { + decltype(completed_manifests_) other; + other.swap(completed_manifests_); + nr_manifests_completed = 0; + return other; + } + + //! Flushes content of all streams + void flush(); + + protected: + //! Forcifully finalize the currently active manifest if exists regardless of its completion + //! status. + int finalizeOne(); + //! Enqueue a stamped batch of samples for some stream + void enqueue( + int identifier, + const Buffer& buf, + size_t buf_size, + double start_time, + double end_time = -1.0, + double surrogate_timestamp = -1.0); + //! Designate the stream with the specified identifier as the primary stream. + void primarize(int identifier); + //! Check if the sstream with specified identifier is the primary stream + bool isPrimary(int identifier) const; + //! Release the control interface and its associated stream. + void release(int identifier); + //! Obtain the sample period estimated to the best knowledge. + double obtainSamplePeriod(int identifier, int multiplier = 1) const; + //! Returns stream statistics. + Statistics getStats(int identifier) const; + + int primary_stream_id; + size_t nr_manifests_emitted = + 0; //!< The number of manifests that have been emitted by this aligner. + size_t nr_manifests_completed = 0; //!< The number of manifests that have been completed. + + std::deque + active_manifests_; //!< A queue of manifests that are currently open for fulfillment. + std::vector + completed_manifests_; //!< A list of manifests that are fully serviced and ready for shipment. + std::unordered_map + registry_; //!< A table of streams that have been enrolled with this aligner. + std::unordered_map + stream_interfaces_; //!< A storage for all the stream interfaces. +}; + +} // namespace subaligner + +} // namespace cthulhu diff --git a/Cthulhu/src/TypeHelpers.cpp b/Cthulhu/src/TypeHelpers.cpp new file mode 100644 index 000000000..62065e17b --- /dev/null +++ b/Cthulhu/src/TypeHelpers.cpp @@ -0,0 +1,26 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +namespace cthulhu { + +#define TYPE_STRING_DEFINE(x) \ + template <> \ + std::string typeString() { \ + return #x; \ + } + +TYPE_STRING_DEFINE(bool) +TYPE_STRING_DEFINE(char) +TYPE_STRING_DEFINE(double) +TYPE_STRING_DEFINE(float) +TYPE_STRING_DEFINE(int64_t) +TYPE_STRING_DEFINE(uint64_t) +TYPE_STRING_DEFINE(int32_t) +TYPE_STRING_DEFINE(uint32_t) +TYPE_STRING_DEFINE(int16_t) +TYPE_STRING_DEFINE(uint16_t) +TYPE_STRING_DEFINE(int8_t) +TYPE_STRING_DEFINE(uint8_t) + +} // namespace cthulhu diff --git a/Cthulhu/src/TypeRegistryIPC.cpp b/Cthulhu/src/TypeRegistryIPC.cpp new file mode 100644 index 000000000..dbc6fed88 --- /dev/null +++ b/Cthulhu/src/TypeRegistryIPC.cpp @@ -0,0 +1,168 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "TypeRegistryIPC.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +TypeRegistryIPC::TypeRegistryIPC(ManagedSHM* shm) : shm_(shm) { + registryData_ = + shm_->find_or_construct("TypeRegistry")(shm_->get_segment_manager()); + + if (registryData_ == nullptr) { + auto str = "Failed to open type registry in shared memory."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + ScopedLockIPC lock(registryData_->registry_lock); + registryData_->reference_count++; +} + +bool TypeRegistryIPC::nuke(ManagedSHM* shm) { + shm->destroy("TypeRegistry"); + return true; +} + +TypeRegistryIPC::~TypeRegistryIPC() { + if (registryData_) { + ScopedLockIPC lock(registryData_->registry_lock); + registryData_->reference_count--; + if (registryData_->reference_count == 0 || force_clean_) { + registryData_->types.clear(); + registryData_->reference_count = 0; + if (log_enabled_) { + XR_LOGD("Cleaning up ipc type registry."); + } + } else if (log_enabled_) { + XR_LOGD( + "Not cleaning ipc type registry, still references: {}", registryData_->reference_count); + } + } +} + +TypeInfoInterfacePtr TypeRegistryIPC::findSampleType(const std::type_index& sampleType) const { + auto it = sampleTypeMap_.find(sampleType); + if (it != sampleTypeMap_.end()) { + return findTypeName(it->second); + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryIPC::findConfigType(const std::type_index& configType) const { + auto it = configTypeMap_.find(configType); + if (it != configTypeMap_.end()) { + return findTypeName(it->second); + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryIPC::findTypeName( + const std::string& streamName, + const std::lock_guard& cacheLock) const { + // Look in the cache + auto it = cache_.find(streamName); + if (it != cache_.end()) { + return it->second; + } + // Check IPC + TypeNameIPC typeNameIPC(shm_->get_segment_manager()); + typeNameIPC = streamName.c_str(); + ScopedLockIPC lockIPC(registryData_->registry_lock); + auto ipcData = registryData_->types.find(typeNameIPC); + if (ipcData != registryData_->types.end()) { + // Update the local cache + TypeInfoInterfacePtr result(new TypeInfoIPC(streamName, &ipcData->second)); + cache_[streamName] = result; + return result; + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryIPC::findTypeName(const std::string& typeName) const { + std::lock_guard lock(cacheMutex_); + return findTypeName(typeName, lock); +} + +TypeInfoInterfacePtr TypeRegistryIPC::findTypeID(uint32_t typeID) const { + std::lock_guard lock(cacheMutex_); + auto it = typeIDMap_.find(typeID); + if (it != typeIDMap_.end()) { + return findTypeName(it->second, lock); + } + + // Check IPC + TypeNameIPC typeNameIPC(shm_->get_segment_manager()); + ScopedLockIPC lockIPC(registryData_->registry_lock); + for (auto iter = registryData_->types.cbegin(); iter != registryData_->types.cend(); ++iter) { + if (typeID == iter->second.typeID) { + std::string typeName(iter->first.c_str()); + typeIDMap_[typeID] = typeName; + return findTypeName(typeName, lock); + } + } + + return TypeInfoInterfacePtr(); +} + +std::vector TypeRegistryIPC::typeNames() const { + std::vector typeNames; + ScopedLockIPC lock(registryData_->registry_lock); + for (auto it = registryData_->types.begin(); it != registryData_->types.end(); ++it) { + typeNames.push_back(it->first.c_str()); + } + return typeNames; +} + +TypeDefinitionIPC::TypeDefinitionIPC(const TypeDefinition& def, const CharAllocatorIPC& alloc) + : sampleParameterSize(def.sampleParameterSize), + configParameterSize(def.configParameterSize), + sampleNumberDynamicFields(def.sampleNumberDynamicFields), + configNumberDynamicFields(def.configNumberDynamicFields), + sampleFields(alloc), + configFields(alloc), + hasContentBlock(def.hasContentBlock), + hasSampleFieldsInContentBlock(def.hasSamplesInContentBlock), + isBasic(!def.configType) { + // Caller responsible for supplying sample and config fields separately +} + +void TypeRegistryIPC::registerType(TypeDefinition def) { + uint32_t typeID = 0; + { + ScopedLockIPC lock(registryData_->registry_lock); + TypeNameIPC typeNameIPC(shm_->get_segment_manager()); + typeNameIPC = def.typeName.c_str(); + TypeDefinitionIPC definition(def, shm_->get_segment_manager()); + fieldDataToIPC(shm_->get_segment_manager(), def.sampleFields, definition.sampleFields); + fieldDataToIPC(shm_->get_segment_manager(), def.configFields, definition.configFields); + + auto it = registryData_->types.find(typeNameIPC); + if (it != registryData_->types.end()) { + // Type in shared registry + definition.typeID = it->second.typeID; + if (it->second != definition) { + auto str = "Attempted to register type: [" + def.typeName + + "] which did not match the existing IPC definition."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + } else { + // Type is unknown to the shared registry + definition.typeID = registryData_->types.size() + 1; + registryData_->types.emplace(typeNameIPC, std::move(definition)); + } + typeID = definition.typeID; + } + + if (def.sampleType != typeid(nullptr)) { + sampleTypeMap_[def.sampleType] = def.typeName; + } + if (def.configType && *def.configType != typeid(nullptr)) { + configTypeMap_[*def.configType] = def.typeName; + } + typeIDMap_[typeID] = def.typeName; +} + +} // namespace cthulhu diff --git a/Cthulhu/src/TypeRegistryIPC.h b/Cthulhu/src/TypeRegistryIPC.h new file mode 100644 index 000000000..59282b33b --- /dev/null +++ b/Cthulhu/src/TypeRegistryIPC.h @@ -0,0 +1,237 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include "IPCEssentials.h" + +#include +#include +#include + +namespace cthulhu { + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + TypeStringIPC; + +struct FieldIPC { + FieldIPC() = delete; + FieldIPC(const CharAllocatorIPC& alloc) : typeName(alloc), fieldName(alloc) {} + uint32_t offset; + uint32_t size; + TypeStringIPC typeName; + TypeStringIPC fieldName; + uint32_t numElements; + bool isDynamic; + inline bool operator==(const FieldIPC& other) const { + return offset == other.offset && size == other.size && typeName == other.typeName && + fieldName == other.fieldName && numElements == other.numElements && + isDynamic == other.isDynamic; + } + + inline bool operator!=(const FieldIPC& other) const { + return !(this->operator==(other)); + } +}; + +typedef boost::interprocess::allocator + FieldIPCVectorAllocType; +typedef boost::interprocess::vector FieldDataIPC; + +inline void fieldDataToIPC(const CharAllocatorIPC& alloc, const FieldData& in, FieldDataIPC& out) { + for (const auto& field : in) { + FieldIPC fieldIPC(alloc); + fieldIPC.offset = field.second.offset; + fieldIPC.size = field.second.size; + fieldIPC.typeName = field.second.typeName.c_str(); + fieldIPC.fieldName = field.first.c_str(); + fieldIPC.numElements = field.second.numElements; + fieldIPC.isDynamic = field.second.isDynamic; + out.push_back(std::move(fieldIPC)); + } +}; + +inline void fieldDataFromIPC(const FieldDataIPC& in, FieldData& out) { + for (const auto& fieldIPC : in) { + Field field; + field.offset = fieldIPC.offset; + field.size = fieldIPC.size; + field.typeName = fieldIPC.typeName.c_str(); + field.numElements = fieldIPC.numElements; + field.isDynamic = fieldIPC.isDynamic; + out[fieldIPC.fieldName.c_str()] = std::move(field); + } +}; + +struct TypeDefinitionIPC { + TypeDefinitionIPC() = delete; + TypeDefinitionIPC(const TypeDefinition&, const CharAllocatorIPC& alloc); + uint32_t typeID; + uint32_t sampleParameterSize; + uint32_t configParameterSize; + uint32_t sampleNumberDynamicFields; + uint32_t configNumberDynamicFields; + FieldDataIPC sampleFields; + FieldDataIPC configFields; + bool hasContentBlock; + bool hasSampleFieldsInContentBlock; + bool isBasic; + + inline bool operator==(const TypeDefinitionIPC& other) const { + bool match = (sampleParameterSize == other.sampleParameterSize) && + (configParameterSize == other.configParameterSize) && + (sampleNumberDynamicFields == other.sampleNumberDynamicFields) && + (configNumberDynamicFields == other.configNumberDynamicFields) && + (sampleFields.size() == other.sampleFields.size()) && + (configFields.size() == other.configFields.size()) && + (hasContentBlock == other.hasContentBlock) && (isBasic == other.isBasic) && + (hasSampleFieldsInContentBlock == other.hasSampleFieldsInContentBlock) && + (typeID == other.typeID); + if (!match) { + return false; + } + for (size_t i = 0; i < sampleFields.size() && match; i++) { + match &= sampleFields[i] == other.sampleFields[i]; + } + for (size_t i = 0; i < configFields.size() && match; i++) { + match &= configFields[i] == other.configFields[i]; + } + return match; + } + + inline bool operator!=(const TypeDefinitionIPC& other) const { + return !(this->operator==(other)); + } +}; + +class TypeRegistryIPC; + +class TypeInfoIPC : public TypeInfoInterface { + public: + virtual ~TypeInfoIPC() = default; + + virtual inline std::string typeName() const override { + return name_; + } + + virtual inline uint32_t typeID() const override { + return definition_->typeID; + } + + virtual inline bool isBasic() const override { + return definition_->isBasic; + } + + virtual inline size_t sampleParameterSize() const override { + return definition_->sampleParameterSize; + } + + virtual inline size_t configParameterSize() const override { + return definition_->configParameterSize; + } + + virtual inline size_t sampleNumberDynamicFields() const override { + return definition_->sampleNumberDynamicFields; + } + + virtual inline size_t configNumberDynamicFields() const override { + return definition_->configNumberDynamicFields; + } + + virtual inline const FieldData& sampleFields() const override { + return sampleFields_; + } + + virtual inline const FieldData& configFields() const override { + return configFields_; + } + + virtual inline bool hasContentBlock() const override { + return definition_->hasContentBlock; + } + + virtual inline bool hasSamplesInContentBlock() const override { + return definition_->hasSampleFieldsInContentBlock; + } + + private: + TypeInfoIPC(std::string name, TypeDefinitionIPC* definition) + : name_(name), definition_(definition) { + fieldDataFromIPC(definition_->configFields, configFields_); + fieldDataFromIPC(definition_->sampleFields, sampleFields_); + } + + std::string name_; + TypeDefinitionIPC* definition_; + FieldData configFields_; + FieldData sampleFields_; + + friend class TypeRegistryIPC; +}; +using TypeInfoIPCPtr = std::shared_ptr; + +typedef boost::interprocess::basic_string, CharAllocatorIPC> + TypeNameIPC; + +struct TypeRegistryIPCData { + typedef boost::interprocess:: + allocator, ManagedSHM::segment_manager> + MapAllocType; + typedef boost::interprocess:: + map, MapAllocType> + MapType; + + TypeRegistryIPCData() = delete; + TypeRegistryIPCData(const TypeRegistryIPCData&) = delete; + TypeRegistryIPCData(TypeRegistryIPCData&&) = delete; + + TypeRegistryIPCData(const MapAllocType& alloc) : types(std::less(), alloc) {} + + MapType types; + MutexIPC registry_lock; + + // Maintain a count of processes using the registry. + // When this reaches 0, the process should cleanup the map + uint32_t reference_count = 0; +}; + +class TypeRegistryIPC : public TypeRegistryInterface { + public: + TypeRegistryIPC(ManagedSHM* shm); + virtual ~TypeRegistryIPC(); + + virtual TypeInfoInterfacePtr findSampleType(const std::type_index& sampleType) const override; + virtual TypeInfoInterfacePtr findConfigType(const std::type_index& configType) const override; + virtual TypeInfoInterfacePtr findTypeName(const std::string& typeName) const override; + virtual TypeInfoInterfacePtr findTypeID(uint32_t typeID) const override; + + virtual std::vector typeNames() const override; + + virtual void registerType(TypeDefinition) override; + + // Destroy the framework without any concern for other Cthulhu users + // + // Intended to be used as last-resort cleanup of a misbehaving Cthulhu framework. + // Users should typically favor cleanup(). + static bool nuke(ManagedSHM* shm); + + private: + TypeRegistryIPCData* registryData_ = nullptr; + ManagedSHM* shm_; + + // Cache the results in local memory so we don't have to go back to shared every time + // and the underlying types don't change (new types can be added, but never modified) + mutable std::unordered_map cache_; + mutable std::map typeIDMap_; + mutable std::mutex cacheMutex_; + + // These maps will no be modified after type initialization. + std::map sampleTypeMap_; + std::map configTypeMap_; + + TypeInfoInterfacePtr findTypeName(const std::string& typeName, const std::lock_guard&) + const; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/TypeRegistryLocal.cpp b/Cthulhu/src/TypeRegistryLocal.cpp new file mode 100644 index 000000000..7b3a62e14 --- /dev/null +++ b/Cthulhu/src/TypeRegistryLocal.cpp @@ -0,0 +1,70 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include "TypeRegistryLocal.h" + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +namespace cthulhu { + +TypeInfoInterfacePtr TypeRegistryLocal::findSampleType(const std::type_index& sampleType) const { + auto it = sampleTypeMap_.find(sampleType); + if (it != sampleTypeMap_.end()) { + return types_.at(it->second); + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryLocal::findConfigType(const std::type_index& configType) const { + auto it = configTypeMap_.find(configType); + if (it != configTypeMap_.end()) { + return types_.at(it->second); + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryLocal::findTypeName(const std::string& typeName) const { + auto it = streamNameMap_.find(typeName); + if (it != streamNameMap_.end()) { + return types_.at(it->second); + } + return TypeInfoInterfacePtr(); +} + +TypeInfoInterfacePtr TypeRegistryLocal::findTypeID(uint32_t typeID) const { + if (typeID > 0 && typeID <= types_.size()) { + return types_.at(typeID - 1); + } + return TypeInfoInterfacePtr(); +} + +std::vector TypeRegistryLocal::typeNames() const { + std::vector typeNames; + for (const auto& type : streamNameMap_) { + typeNames.push_back(type.first); + } + return typeNames; +} + +void TypeRegistryLocal::registerType(TypeDefinition definition) { + for (const auto& type : types_) { + if (type->typeName().compare(definition.typeName) == 0) { + auto str = + "Attempted to register type: [" + type->typeName() + "] which was detected as duplicate."; + XR_LOGE("{}", str); + throw std::runtime_error(str); + } + } + + if (definition.sampleType != typeid(nullptr)) { + sampleTypeMap_[definition.sampleType] = types_.size(); + } + if (definition.configType && *definition.configType != typeid(nullptr)) { + configTypeMap_[*definition.configType] = types_.size(); + } + streamNameMap_[definition.typeName] = types_.size(); + types_.push_back(std::shared_ptr( + new TypeInfoLocal{std::move(definition), static_cast(types_.size())})); +} + +} // namespace cthulhu diff --git a/Cthulhu/src/TypeRegistryLocal.h b/Cthulhu/src/TypeRegistryLocal.h new file mode 100644 index 000000000..0ce1d6b6c --- /dev/null +++ b/Cthulhu/src/TypeRegistryLocal.h @@ -0,0 +1,90 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace cthulhu { + +class TypeRegistryLocal; + +class TypeInfoLocal : public TypeInfoInterface { + public: + virtual ~TypeInfoLocal() = default; + + virtual inline std::string typeName() const override { + return definition_.typeName; + } + + virtual inline uint32_t typeID() const override { + return typeID_ + 1; + } + + virtual inline bool isBasic() const override { + return !(definition_.configType); + } + + virtual inline size_t sampleParameterSize() const override { + return definition_.sampleParameterSize; + } + + virtual inline size_t configParameterSize() const override { + return definition_.configParameterSize; + } + + virtual inline size_t sampleNumberDynamicFields() const override { + return definition_.sampleNumberDynamicFields; + } + + virtual inline size_t configNumberDynamicFields() const override { + return definition_.configNumberDynamicFields; + } + + virtual inline const FieldData& sampleFields() const override { + return definition_.sampleFields; + } + + virtual inline const FieldData& configFields() const override { + return definition_.configFields; + } + + virtual inline bool hasContentBlock() const override { + return definition_.hasContentBlock; + } + + virtual inline bool hasSamplesInContentBlock() const override { + return definition_.hasSamplesInContentBlock; + } + + private: + TypeDefinition definition_; + uint32_t typeID_ = 0; + + TypeInfoLocal(TypeDefinition definition, uint32_t typeID) + : definition_(std::move(definition)), typeID_(typeID) {} + + friend class TypeRegistryLocal; +}; +using TypeInfoLocalPtr = std::shared_ptr; + +class TypeRegistryLocal : public TypeRegistryInterface { + public: + virtual ~TypeRegistryLocal() = default; + + virtual TypeInfoInterfacePtr findSampleType(const std::type_index& sampleType) const override; + virtual TypeInfoInterfacePtr findConfigType(const std::type_index& configType) const override; + virtual TypeInfoInterfacePtr findTypeName(const std::string& streamName) const override; + virtual TypeInfoInterfacePtr findTypeID(uint32_t typeID) const override; + + virtual std::vector typeNames() const override; + + virtual void registerType(TypeDefinition) override; + + private: + std::vector types_; + std::map sampleTypeMap_; + std::map configTypeMap_; + std::map streamNameMap_; +}; + +} // namespace cthulhu diff --git a/Cthulhu/src/VulkanUtil.cpp b/Cthulhu/src/VulkanUtil.cpp new file mode 100644 index 000000000..8aa3aa2a7 --- /dev/null +++ b/Cthulhu/src/VulkanUtil.cpp @@ -0,0 +1,407 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#ifdef CTHULHU_HAS_VULKAN +#include +#endif + +#include + +#define DEFAULT_LOG_CHANNEL "Cthulhu" +#include + +#ifdef CTHULHU_HAS_VULKAN +// Load the functions from the external memory extensions +#ifdef _WIN32 +VkResult vkGetMemoryWin32HandleKHR( + VkDevice device, + const VkMemoryGetWin32HandleInfoKHR* pInfo, + HANDLE* pHandle) { + auto vkGetMemoryWin32HandleKHR2 = + PFN_vkGetMemoryWin32HandleKHR(vkGetDeviceProcAddr(device, "vkGetMemoryWin32HandleKHR")); + return vkGetMemoryWin32HandleKHR2(device, pInfo, pHandle); +} +#else +VkResult vkGetMemoryFdKHR(VkDevice device, const VkMemoryGetFdInfoKHR* pInfo, int* pFd) { + auto vkGetMemoryFdKHR2 = PFN_vkGetMemoryFdKHR(vkGetDeviceProcAddr(device, "vkGetMemoryFdKHR")); + return vkGetMemoryFdKHR2(device, pInfo, pFd); +} +#endif // _WIN32 +#endif // CTHULHU_HAS_VULKAN + +namespace cthulhu { + +#ifdef CTHULHU_HAS_VULKAN +struct VulkanUtilState { + VkInstance instance = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device = VK_NULL_HANDLE; + VkPhysicalDeviceMemoryProperties memoryProperties; +}; + +uint32_t findMemoryTypeIndex( + const VkPhysicalDeviceMemoryProperties& memoryProperties, + uint32_t memoryTypeBits, + VkFlags required, + VkFlags preferred, + VkFlags preferredNot) { + // first try, find required and with preferred and without preferred_not + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + bool isSupported = (1 << i) & memoryTypeBits; + if (isSupported) { + const VkMemoryType& memoryType = memoryProperties.memoryTypes[i]; + if ((memoryType.propertyFlags & required) == required && + (preferred && (memoryType.propertyFlags & preferred)) && + (preferredNot && !(memoryType.propertyFlags & preferredNot))) { + return i; + } + } + } + + // second try, find required and with preferred + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + bool isSupported = (1 << i) & memoryTypeBits; + if (isSupported) { + const VkMemoryType& memoryType = memoryProperties.memoryTypes[i]; + if ((memoryType.propertyFlags & required) == required && + (preferred && (memoryType.propertyFlags & preferred))) { + return i; + } + } + } + + // third try, find required and without preferred_not + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + bool isSupported = (1 << i) & memoryTypeBits; + if (isSupported) { + const VkMemoryType& memoryType = memoryProperties.memoryTypes[i]; + if ((memoryType.propertyFlags & required) == required && + (preferredNot && !(memoryType.propertyFlags & preferredNot))) { + return i; + } + } + } + + // fourth try, find any required + for (uint32_t i = 0; i < memoryProperties.memoryTypeCount; i++) { + bool isSupported = (1 << i) & memoryTypeBits; + if (isSupported) { + const VkMemoryType& memoryType = memoryProperties.memoryTypes[i]; + if ((memoryType.propertyFlags & required) == required) { + return i; + } + } + } + + XR_LOGE("No such memory type {} {} {} {}", memoryTypeBits, required, preferred, preferredNot); + return -1; +} +#else +// We forward declared this, so it needs to be provided to make clang happy +struct VulkanUtilState { + bool dummy; +}; +#endif // CTHULHU_HAS_VULKAN + +VulkanUtil::VulkanUtil() { +#ifdef CTHULHU_HAS_VULKAN + if (std::getenv("CTHULHU_DISABLE_VULKAN")) { + return; + } + + state_ = new VulkanUtilState(); + + // dummy app info + VkApplicationInfo applicationInfo = {}; + applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + applicationInfo.pApplicationName = "Cthulhu"; + applicationInfo.applicationVersion = 0; + applicationInfo.pEngineName = "Cthulhu"; + applicationInfo.engineVersion = 0; + applicationInfo.apiVersion = VK_API_VERSION_1_0; + VkInstanceCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.flags = 0; + createInfo.pApplicationInfo = &applicationInfo; + + // enable debug info + std::vector enabledExtensions{ + VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME}; + createInfo.enabledExtensionCount = enabledExtensions.size(); + createInfo.ppEnabledExtensionNames = enabledExtensions.data(); + std::vector layers = { +#ifdef _DEBUG + "VK_LAYER_LUNARG_standard_validation" +#endif + }; + createInfo.enabledLayerCount = layers.size(); + createInfo.ppEnabledLayerNames = layers.data(); + createInfo.pNext = nullptr; + + if (vkCreateInstance(&createInfo, nullptr, &state_->instance) != VK_SUCCESS) { + XR_LOGW("Failed to create Vulkan instance!"); + return; + } + + uint32_t numDevices; + vkEnumeratePhysicalDevices(state_->instance, &numDevices, nullptr); + if (!numDevices) { + XR_LOGW("No Vulkan devices found!"); + return; + } + std::vector devices(numDevices); + vkEnumeratePhysicalDevices(state_->instance, &numDevices, devices.data()); + + // Select the requested device + long int deviceIdx = 0; + auto deviceIdxStr = std::getenv("CTHULHU_GPU_DEVICE_IDX"); + if (deviceIdxStr) { + char* pEnd; + deviceIdx = std::strtol(deviceIdxStr, &pEnd, 10); + if (pEnd == deviceIdxStr) { + XR_LOGW( + "Detected malformed CTHULHU_GPU_DEVICE_IDX: [{}]. Defaulting to device 0.", deviceIdxStr); + } + if (deviceIdx >= devices.size()) { + XR_LOGW( + "Requested invalid CTHULHU_GPU_DEVICE_IDX: [{}]. [{}] devices are available. Defaulting to device 0.", + deviceIdx, + devices.size()); + deviceIdx = 0; + } + } + state_->physicalDevice = devices[deviceIdx]; + + // Retain the physical device's memory properties for use + vkGetPhysicalDeviceMemoryProperties(state_->physicalDevice, &state_->memoryProperties); + + // Request a queue, just because Vulkan requires it. + VkDeviceQueueCreateInfo deviceQueueCreateInfo; + deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + deviceQueueCreateInfo.pNext = 0; + deviceQueueCreateInfo.flags = 0; + deviceQueueCreateInfo.queueFamilyIndex = 0; + deviceQueueCreateInfo.queueCount = 1; + deviceQueueCreateInfo.pQueuePriorities = nullptr; + + VkDeviceCreateInfo deviceCreateInfo = {}; + + std::vector enabledExtensions2 = { + VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME, +#ifdef _WIN32 + VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, +#else + VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, + VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, +#endif + }; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.enabledExtensionCount = enabledExtensions2.size(); + deviceCreateInfo.ppEnabledExtensionNames = enabledExtensions2.data(); + deviceCreateInfo.queueCreateInfoCount = 1; + deviceCreateInfo.pQueueCreateInfos = &deviceQueueCreateInfo; + + if (vkCreateDevice(state_->physicalDevice, &deviceCreateInfo, nullptr, &state_->device) != + VK_SUCCESS) { + XR_LOGW("Failed to create Vulkan logical device!"); + return; + } + + isActive_ = true; +#else + (void)state_; +#endif // CTHULHU_HAS_VULKAN +} + +VulkanUtil::~VulkanUtil() { +#ifdef CTHULHU_HAS_VULKAN + if (state_ && state_->device != VK_NULL_HANDLE) { + vkDestroyDevice(state_->device, nullptr); + } + + if (state_ && state_->instance != VK_NULL_HANDLE) { + vkDestroyInstance(state_->instance, nullptr); + } + + if (state_) { + delete state_; + } +#endif +} + +std::pair VulkanUtil::allocate(uint32_t nrBytes, bool deviceLocal) { +#ifdef CTHULHU_HAS_VULKAN + if (!isActive_) { + return {0, 0}; + } + + // Create a buffer, just to get memory requirements + VkBufferCreateInfo bufferCreateInfo = {VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO}; + bufferCreateInfo.size = nrBytes; + bufferCreateInfo.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; + + // Enable export + VkExternalMemoryBufferCreateInfo infoEx{VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO}; +#ifdef _WIN32 + infoEx.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; +#else + infoEx.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; +#endif + bufferCreateInfo.pNext = &infoEx; + + VkBuffer buffer; + if (vkCreateBuffer(state_->device, &bufferCreateInfo, nullptr, &buffer) != VK_SUCCESS) { + XR_LOGW("Failed to allocate Vulkan buffer"); + return {0, 0}; + } + + // Require host visible, coherent memory + VkMemoryRequirements memReqs; + vkGetBufferMemoryRequirements(state_->device, buffer, &memReqs); + VkExportMemoryAllocateInfoKHR vulkanExportMemoryAllocateInfoKHR = {}; + vulkanExportMemoryAllocateInfoKHR.sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR; + vulkanExportMemoryAllocateInfoKHR.pNext = nullptr; +#ifdef _WIN32 + vulkanExportMemoryAllocateInfoKHR.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; +#else + vulkanExportMemoryAllocateInfoKHR.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; +#endif + + VkMemoryAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.pNext = &vulkanExportMemoryAllocateInfoKHR; + allocateInfo.allocationSize = memReqs.size; + VkFlags required, preferred, preferredNot; + if (deviceLocal) { + required = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + preferred = 0; + preferredNot = 0; + } else { + required = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + preferred = VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + preferredNot = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + } + allocateInfo.memoryTypeIndex = findMemoryTypeIndex( + state_->memoryProperties, memReqs.memoryTypeBits, required, preferred, preferredNot); + + // Allocate the memory + VkDeviceMemory bufferMemory; + if (vkAllocateMemory(state_->device, &allocateInfo, nullptr, &bufferMemory) != VK_SUCCESS) { + XR_LOGW("Failed to allocate Vulkan buffer memory!"); + return {0, 0}; + } + + // We no longer need the buffer + vkDestroyBuffer(state_->device, buffer, nullptr); + +#ifdef _WIN32 + VkMemoryGetWin32HandleInfoKHR info = {VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR}; + HANDLE handle{}; + info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + info.memory = bufferMemory; + vkGetMemoryWin32HandleKHR(state_->device, &info, &handle); +#else + VkMemoryGetFdInfoKHR info = {VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR}; + int handle{}; + info.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + info.memory = bufferMemory; + vkGetMemoryFdKHR(state_->device, &info, &handle); +#endif + + return {(uint64_t)handle, allocateInfo.memoryTypeIndex}; +#endif // CTHULHU_HAS_VULKAN + XR_LOGW("Failed to allocate GPU buffer. Vulkan support was not included in build."); + return {0, 0}; +} + +void VulkanUtil::free(uint64_t handle) { +#ifdef CTHULHU_HAS_VULKAN +#ifdef _WIN32 + CloseHandle((HANDLE)handle); +#else + close((int)handle); +#endif // _WIN32 +#endif // CTHULHU_HAS_VULKAN +} + +std::shared_ptr +VulkanUtil::map(uint64_t handle, uint32_t nrBytes, uint32_t memoryTypeIndex) { +#ifdef CTHULHU_HAS_VULKAN + if (!isActive_) { + return nullptr; + } + + // Re-import the handle into memory +#ifdef _WIN32 + VkImportMemoryWin32HandleInfoKHR vulkanImportMemoryHandleInfo = {}; + vulkanImportMemoryHandleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR; + vulkanImportMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT; + vulkanImportMemoryHandleInfo.handle = (HANDLE)handle; +#else + VkImportMemoryFdInfoKHR vulkanImportMemoryHandleInfo = {}; + vulkanImportMemoryHandleInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR; + vulkanImportMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT; + vulkanImportMemoryHandleInfo.fd = dup((int)handle); +#endif + + VkMemoryAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.pNext = &vulkanImportMemoryHandleInfo; + allocateInfo.allocationSize = nrBytes; + allocateInfo.memoryTypeIndex = memoryTypeIndex; + + // "Allocate" the memory, but really just import it + VkDeviceMemory bufferMemory; + auto ret = vkAllocateMemory(state_->device, &allocateInfo, nullptr, &bufferMemory); + if (ret != VK_SUCCESS) { + XR_LOGW( + "Failed to import Vulkan buffer memory at handle {}! Size {}, memory type {}. Error code was {}.", + handle, + nrBytes, + memoryTypeIndex, + ret); + return nullptr; + } + + // Map it to the host + void* result = nullptr; + if (vkMapMemory(state_->device, bufferMemory, 0, nrBytes, 0, &result) != VK_SUCCESS) { + XR_LOGW("Failed to map Vulkan buffer to host memory."); + return nullptr; + } + + return std::shared_ptr((uint8_t*)result, [this, bufferMemory](uint8_t* ptr) -> void { + vkFreeMemory(state_->device, bufferMemory, nullptr); + }); +#endif // CTHULHU_HAS_VULKAN + XR_LOGW("Failed to map GPU buffer. Vulkan support was not included in build."); + return nullptr; +} + +bool VulkanUtil::isActive() const { + return isActive_; +} + +bool VulkanUtil::isDeviceLocal(uint32_t memoryTypeIndex) const { +#ifdef CTHULHU_HAS_VULKAN + if (memoryTypeIndex > state_->memoryProperties.memoryTypeCount) { + throw std::runtime_error("memoryTypeIndex out of range"); + } + return state_->memoryProperties.memoryTypes[memoryTypeIndex].propertyFlags & + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; +#else + return false; +#endif +} + +} // namespace cthulhu diff --git a/Cthulhu/src/boost/interprocess/android_shared_memory.hpp b/Cthulhu/src/boost/interprocess/android_shared_memory.hpp new file mode 100644 index 000000000..d31e28d3b --- /dev/null +++ b/Cthulhu/src/boost/interprocess/android_shared_memory.hpp @@ -0,0 +1,276 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#ifndef BOOST_INTERPROCESS_ANDROID_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_ANDROID_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include //O_CREAT, O_*... +#include +#include //shm_xxx +#include //mode_t, S_IRWXG, S_IRWXO, S_IRWXU, +#include //ftruncate, close + +//!\file +//! Describes a shared memory object management class. + +namespace boost { +namespace interprocess { + +//! A class that wraps a shared memory mapping that can be used to +//! create mapped regions from the mapped files +class android_shared_memory { +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + // Non-copyable and non-assignable + BOOST_MOVABLE_BUT_NOT_COPYABLE(android_shared_memory) +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: + //! Default constructor. Represents an empty android_shared_memory. + android_shared_memory(); + + //! Creates a shared memory object with name "name" and mode "mode", with the access mode "mode" + //! If the file previously exists, throws an error.*/ + android_shared_memory(create_only_t, const char* name, mode_t mode) { + this->priv_open_or_create(ipcdetail::DoCreate, name, mode); + } + + //! Tries to create a shared memory object with name "name" and mode "mode", with the + //! access mode "mode". If the file previously exists, it tries to open it with mode "mode". + //! Otherwise throws an error. + android_shared_memory(open_or_create_t, const char* name, mode_t mode) { + this->priv_open_or_create(ipcdetail::DoOpenOrCreate, name, mode); + } + + //! Tries to open a shared memory object with name "name", with the access mode "mode". + //! If the file does not previously exist, it throws an error. + android_shared_memory(open_only_t, const char* name, mode_t mode) { + this->priv_open_or_create(ipcdetail::DoOpen, name, mode); + } + + //! Moves the ownership of "moved"'s shared memory object to *this. + //! After the call, "moved" does not represent any shared memory object. + //! Does not throw + android_shared_memory(BOOST_RV_REF(android_shared_memory) moved) + : m_handle(file_handle_t(ipcdetail::invalid_file())), m_mode(read_only) { + this->swap(moved); + } + + //! Moves the ownership of "moved"'s shared memory to *this. + //! After the call, "moved" does not represent any shared memory. + //! Does not throw + android_shared_memory& operator=(BOOST_RV_REF(android_shared_memory) moved) { + android_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //! Swaps the android_shared_memorys. Does not throw + void swap(android_shared_memory& moved); + + //! Erases a shared memory object from the system. + //! Returns false on error. Never throws + static bool remove(const char* name); + + //! Sets the size of the shared memory mapping + void truncate(offset_t length); + + //! Destroys *this and indicates that the calling process is finished using + //! the resource. All mapped regions are still + //! valid after destruction. The destructor function will deallocate + //! any system resources allocated by the system for use by this process for + //! this resource. The resource can still be opened again calling + //! the open constructor overload. To erase the resource from the system + //! use remove(). + ~android_shared_memory(); + + //! Returns the name of the shared memory object. + const char* get_name() const; + + //! Returns true if the size of the shared memory object + //! can be obtained and writes the size in the passed reference + bool get_size(offset_t& size) const; + + //! Returns access mode + mode_t get_mode() const; + + //! Returns mapping handle. Never throws. + mapping_handle_t get_mapping_handle() const; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + private: + //! Closes a previously opened file mapping. Never throws. + void priv_close(); + + //! Opens or creates a shared memory object. + bool priv_open_or_create(ipcdetail::create_enum_t type, const char* filename, mode_t mode); + + file_handle_t m_handle; + mode_t m_mode; + std::string m_filename; +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + +inline android_shared_memory::android_shared_memory() + : m_handle(file_handle_t(ipcdetail::invalid_file())), m_mode(read_only) {} + +inline android_shared_memory::~android_shared_memory() { + this->priv_close(); +} + +inline const char* android_shared_memory::get_name() const { + return m_filename.c_str(); +} + +inline bool android_shared_memory::get_size(offset_t& size) const { + return ipcdetail::get_file_size((file_handle_t)m_handle, size); +} + +inline void android_shared_memory::swap(android_shared_memory& other) { + boost::adl_move_swap(m_handle, other.m_handle); + boost::adl_move_swap(m_mode, other.m_mode); + m_filename.swap(other.m_filename); +} + +inline mapping_handle_t android_shared_memory::get_mapping_handle() const { + return ipcdetail::mapping_handle_from_file_handle(m_handle); +} + +inline mode_t android_shared_memory::get_mode() const { + return m_mode; +} + +namespace android_shared_memory_detail {} // namespace android_shared_memory_detail + +inline int ashmem_open(const char* name, int oflag) { + const int fd = open("/dev/ashmem", oflag); + + if (fd < 0) { + return fd; + } + + if (name != nullptr) { + char buf[ASHMEM_NAME_LEN]; + + strlcpy(buf, name, sizeof(buf)); + + const int ret = ioctl(fd, ASHMEM_SET_NAME, buf); + + if (ret < 0) { + close(fd); + return ret; + } + } + + return fd; +} + +inline bool android_shared_memory::priv_open_or_create( + ipcdetail::create_enum_t type, + const char* filename, + mode_t mode) { + m_filename = filename; + + // Create new mapping + int oflag = 0; + if (mode == read_only) { + oflag |= O_RDONLY; + } else if (mode == read_write) { + oflag |= O_RDWR; + } else { + error_info err(mode_error); + throw interprocess_exception(err); + } + + switch (type) { + case ipcdetail::DoOpen: { + // No oflag addition + m_handle = ashmem_open(m_filename.c_str(), oflag); + } break; + case ipcdetail::DoCreate: { + // oflag |= (O_CREAT | O_EXCL); + m_handle = ashmem_open(m_filename.c_str(), oflag); + } break; + case ipcdetail::DoOpenOrCreate: { + // Try to create shared memory + m_handle = ashmem_open(m_filename.c_str(), oflag); + } break; + default: { + error_info err = other_error; + throw interprocess_exception(err); + } + } + + // Check for error + if (m_handle < 0) { + error_info err = errno; + this->priv_close(); + throw interprocess_exception(err); + } + + m_mode = mode; + return true; +} + +inline bool android_shared_memory::remove(const char* filename) { + return true; +} + +inline void android_shared_memory::truncate(offset_t length) { + const int ret = ioctl(m_handle, ASHMEM_SET_SIZE, length); + if (ret < 0) { + error_info err(system_error_code()); + throw interprocess_exception(err); + } +} + +inline void android_shared_memory::priv_close() { + if (m_handle != -1) { + ::close(m_handle); + m_handle = -1; + } +} + +//! A class that stores the name of a shared memory +//! and calls android_shared_memory::remove(name) in its destructor +//! Useful to remove temporary shared memory objects in the presence +//! of exceptions +class remove_shared_memory_on_destroy { + const char* m_name; + + public: + remove_shared_memory_on_destroy(const char* name) : m_name(name) {} + + ~remove_shared_memory_on_destroy() { + android_shared_memory::remove(m_name); + } +}; + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_ANDROID_SHARED_MEMORY_HPP diff --git a/Cthulhu/src/boost/interprocess/detail/managed_open_or_create_impl_ashmem.hpp b/Cthulhu/src/boost/interprocess/detail/managed_open_or_create_impl_ashmem.hpp new file mode 100644 index 000000000..76f26be97 --- /dev/null +++ b/Cthulhu/src/boost/interprocess/detail/managed_open_or_create_impl_ashmem.hpp @@ -0,0 +1,383 @@ +/** + * Note: This file is forked from boost/interprocess/detail/managed_open_or_create_impl.hpp + * It provides a version of the templates that are usable by our android implementation of + * managed shared memory, by modifying the 3rd argument of the MappedRegion c'tor in line 291 and + * 338. + */ + +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/interprocess for documentation. +// +// Copyright 2004-present Facebook. All Rights Reserved. +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL_ASHMEM +#define BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL_ASHMEM + +#ifndef BOOST_CONFIG_HPP +#include +#endif +# +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include + +namespace boost { +namespace interprocess { + +namespace ipcdetail { + +template +class managed_open_or_create_impl_ashmem + : public managed_open_or_create_impl_device_holder { + // Non-copyable + BOOST_MOVABLE_BUT_NOT_COPYABLE(managed_open_or_create_impl_ashmem) + + typedef typename managed_open_or_create_impl_device_id_t::type device_id_t; + typedef managed_open_or_create_impl_device_holder DevHolder; + enum { UninitializedSegment, InitializingSegment, InitializedSegment, CorruptedSegment }; + + public: + static const std::size_t ManagedOpenOrCreateUserOffset = ct_rounded_size < + sizeof(boost::uint32_t), + MemAlignment + ? (MemAlignment) + : (::boost::container::dtl::alignment_of<::boost::container::dtl::max_align_t>::value) > + ::value; + + managed_open_or_create_impl_ashmem() {} + + managed_open_or_create_impl_ashmem( + create_only_t, + const device_id_t& id, + std::size_t size, + mode_t mode, + const void* addr) { + priv_open_or_create(DoCreate, id, size, mode, addr, null_mapped_region_function()); + } + + managed_open_or_create_impl_ashmem( + open_only_t, + const device_id_t& id, + mode_t mode, + const void* addr) { + priv_open_or_create(DoOpen, id, 0, mode, addr, null_mapped_region_function()); + } + + managed_open_or_create_impl_ashmem( + open_or_create_t, + const device_id_t& id, + std::size_t size, + mode_t mode, + const void* addr) { + priv_open_or_create(DoOpenOrCreate, id, size, mode, addr, null_mapped_region_function()); + } + + template + managed_open_or_create_impl_ashmem( + create_only_t, + const device_id_t& id, + std::size_t size, + mode_t mode, + const void* addr, + const ConstructFunc& construct_func) { + priv_open_or_create(DoCreate, id, size, mode, addr, construct_func); + } + + template + managed_open_or_create_impl_ashmem( + open_only_t, + const device_id_t& id, + mode_t mode, + const void* addr, + const ConstructFunc& construct_func) { + priv_open_or_create(DoOpen, id, 0, mode, addr, construct_func); + } + + template + managed_open_or_create_impl_ashmem( + open_or_create_t, + const device_id_t& id, + std::size_t size, + mode_t mode, + const void* addr, + const ConstructFunc& construct_func) { + priv_open_or_create(DoOpenOrCreate, id, size, mode, addr, construct_func); + } + + managed_open_or_create_impl_ashmem(BOOST_RV_REF(managed_open_or_create_impl_ashmem) moved) { + this->swap(moved); + } + + managed_open_or_create_impl_ashmem& operator=(BOOST_RV_REF(managed_open_or_create_impl_ashmem) + moved) { + managed_open_or_create_impl_ashmem tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + ~managed_open_or_create_impl_ashmem() {} + + std::size_t get_user_size() const { + return m_mapped_region.get_size() - ManagedOpenOrCreateUserOffset; + } + + void* get_user_address() const { + return static_cast(m_mapped_region.get_address()) + ManagedOpenOrCreateUserOffset; + } + + std::size_t get_real_size() const { + return m_mapped_region.get_size(); + } + + void* get_real_address() const { + return m_mapped_region.get_address(); + } + + void swap(managed_open_or_create_impl_ashmem& other) { + this->m_mapped_region.swap(other.m_mapped_region); + } + + bool flush() { + return m_mapped_region.flush(); + } + + const mapped_region& get_mapped_region() const { + return m_mapped_region; + } + + DeviceAbstraction& get_device() { + return this->DevHolder::get_device(); + } + + const DeviceAbstraction& get_device() const { + return this->DevHolder::get_device(); + } + + private: + // These are templatized to allow explicit instantiations + template + static void truncate_device(DeviceAbstraction&, offset_t, false_) {} // Empty + + template + static void truncate_device(DeviceAbstraction& dev, offset_t size, true_) { + dev.truncate(size); + } + + template + static bool check_offset_t_size(std::size_t, false_) { + return true; + } // Empty + + template + static bool check_offset_t_size(std::size_t size, true_) { + return size == std::size_t(offset_t(size)); + } + + // These are templatized to allow explicit instantiations + template + static void + create_device(DeviceAbstraction& dev, const device_id_t& id, std::size_t size, false_ file_like) { + (void)file_like; + DeviceAbstraction tmp(create_only, id, read_write, size); + tmp.swap(dev); + } + + template + static void + create_device(DeviceAbstraction& dev, const device_id_t& id, std::size_t, true_ file_like) { + (void)file_like; + DeviceAbstraction tmp(create_only, id, read_write); + tmp.swap(dev); + } + + template + inline void priv_open_or_create( + create_enum_t type, + const device_id_t& id, + std::size_t size, + mode_t mode, + const void* addr, + ConstructFunc construct_func) { + typedef bool_ file_like_t; + (void)mode; + bool created = false; + bool ronly = false; + bool cow = false; + DeviceAbstraction dev; + + if (type != DoOpen) { + // Check if the requested size is enough to build the managed metadata + const std::size_t func_min_size = construct_func.get_min_size(); + if ((std::size_t(-1) - ManagedOpenOrCreateUserOffset) < func_min_size || + size < (func_min_size + ManagedOpenOrCreateUserOffset)) { + throw interprocess_exception(error_info(size_error)); + } + } + // Check size can be represented by offset_t (used by truncate) + if (type != DoOpen && !check_offset_t_size(size, file_like_t())) { + throw interprocess_exception(error_info(size_error)); + } + if (type == DoOpen && mode == read_write) { + DeviceAbstraction tmp(open_only, id, read_write); + tmp.swap(dev); + created = false; + } else if (type == DoOpen && mode == read_only) { + DeviceAbstraction tmp(open_only, id, read_only); + tmp.swap(dev); + created = false; + ronly = true; + } else if (type == DoOpen && mode == copy_on_write) { + DeviceAbstraction tmp(open_only, id, read_only); + tmp.swap(dev); + created = false; + cow = true; + } else if (type == DoCreate) { + create_device(dev, id, size, file_like_t()); + created = true; + } else if (type == DoOpenOrCreate) { + // This loop is very ugly, but brute force is sometimes better + // than diplomacy. If someone knows how to open or create a + // file and know if we have really created it or just open it + // drop me a e-mail! + bool completed = false; + spin_wait swait; + while (!completed) { + try { + create_device(dev, id, size, file_like_t()); + created = true; + completed = true; + } catch (interprocess_exception& ex) { + if (ex.get_error_code() != already_exists_error) { + throw; + } else { + try { + DeviceAbstraction tmp(open_only, id, read_write); + dev.swap(tmp); + created = false; + completed = true; + } catch (interprocess_exception& e) { + if (e.get_error_code() != not_found_error) { + throw; + } + } catch (...) { + throw; + } + } + } catch (...) { + throw; + } + swait.yield(); + } + } + + if (created) { + try { + // If this throws, we are lost + truncate_device(dev, size, file_like_t()); + + // If the following throws, we will truncate the file to 1 + mapped_region region(dev, read_write, 0, size, addr); + boost::uint32_t* patomic_word = 0; // avoid gcc warning + patomic_word = static_cast(region.get_address()); + boost::uint32_t previous = + atomic_cas32(patomic_word, InitializingSegment, UninitializedSegment); + + if (previous == UninitializedSegment) { + try { + construct_func( + static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset, + size - ManagedOpenOrCreateUserOffset, + true); + // All ok, just move resources to the external mapped region + m_mapped_region.swap(region); + } catch (...) { + atomic_write32(patomic_word, CorruptedSegment); + throw; + } + atomic_write32(patomic_word, InitializedSegment); + } else if (previous == InitializingSegment || previous == InitializedSegment) { + throw interprocess_exception(error_info(already_exists_error)); + } else { + throw interprocess_exception(error_info(corrupted_error)); + } + } catch (...) { + try { + truncate_device(dev, 1u, file_like_t()); + } catch (...) { + } + throw; + } + } else { + if (FileBased) { + offset_t filesize = 0; + spin_wait swait; + while (filesize == 0) { + if (!get_file_size(file_handle_from_mapping_handle(dev.get_mapping_handle()), filesize)) { + error_info err = system_error_code(); + throw interprocess_exception(err); + } + swait.yield(); + } + if (filesize == 1) { + throw interprocess_exception(error_info(corrupted_error)); + } + } + + mapped_region region( + dev, ronly ? read_only : (cow ? copy_on_write : read_write), 0, size, addr); + + boost::uint32_t* patomic_word = static_cast(region.get_address()); + boost::uint32_t value = atomic_read32(patomic_word); + + spin_wait swait; + while (value == InitializingSegment || value == UninitializedSegment) { + swait.yield(); + value = atomic_read32(patomic_word); + } + + if (value != InitializedSegment) + throw interprocess_exception(error_info(corrupted_error)); + + construct_func( + static_cast(region.get_address()) + ManagedOpenOrCreateUserOffset, + region.get_size() - ManagedOpenOrCreateUserOffset, + false); + // All ok, just move resources to the external mapped region + m_mapped_region.swap(region); + } + if (StoreDevice) { + this->DevHolder::get_device() = boost::move(dev); + } + } + + friend void swap( + managed_open_or_create_impl_ashmem& left, + managed_open_or_create_impl_ashmem& right) { + left.swap(right); + } + + private: + friend class interprocess_tester; + void dont_close_on_destruction() { + interprocess_tester::dont_close_on_destruction(m_mapped_region); + } + + mapped_region m_mapped_region; +}; + +} // namespace ipcdetail + +} // namespace interprocess +} // namespace boost + +#include + +#endif //#ifndef BOOST_INTERPROCESS_MANAGED_OPEN_OR_CREATE_IMPL_ASHMEM diff --git a/Cthulhu/src/boost/interprocess/managed_android_shared_memory.hpp b/Cthulhu/src/boost/interprocess/managed_android_shared_memory.hpp new file mode 100644 index 000000000..21efd8c4f --- /dev/null +++ b/Cthulhu/src/boost/interprocess/managed_android_shared_memory.hpp @@ -0,0 +1,247 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#ifndef BOOST_INTERPROCESS_MANAGED_ANDROID_SHARED_MEMORY_HPP +#define BOOST_INTERPROCESS_MANAGED_ANDROID_SHARED_MEMORY_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +#pragma once +#endif + +#include +#include + +#include +#include +#include "android_shared_memory.hpp" +#include "detail/managed_open_or_create_impl_ashmem.hpp" +// These includes needed to fulfill default template parameters of +// predeclarations in interprocess_fwd.hpp +#include +#include + +namespace boost { +namespace interprocess { + +namespace ipcdetail { + +template +struct android_shmem_open_or_create { + typedef ipcdetail::managed_open_or_create_impl_ashmem< + android_shared_memory, + AllocationAlgorithm::Alignment, + true, + false> + type; +}; + +} // namespace ipcdetail + +//! A basic shared memory named object creation class. Initializes the +//! shared memory segment. Inherits all basic functionality from +//! basic_managed_memory_impl*/ +template class IndexType> +class basic_android_managed_shared_memory + : public ipcdetail::basic_managed_memory_impl< + CharType, + AllocationAlgorithm, + IndexType, + ipcdetail::android_shmem_open_or_create< + AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset>, + private ipcdetail::android_shmem_open_or_create::type { +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + typedef ipcdetail::basic_managed_memory_impl< + CharType, + AllocationAlgorithm, + IndexType, + ipcdetail::android_shmem_open_or_create< + AllocationAlgorithm>::type::ManagedOpenOrCreateUserOffset> + base_t; + typedef typename ipcdetail::android_shmem_open_or_create::type base2_t; + + typedef ipcdetail::create_open_func create_open_func_t; + + basic_android_managed_shared_memory* get_this_pointer() { + return this; + } + + public: + typedef android_shared_memory device_type; + typedef typename base_t::size_type size_type; + + private: + typedef typename base_t::char_ptr_holder_t char_ptr_holder_t; + BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_android_managed_shared_memory) +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED + + public: // functions + //! Destroys *this and indicates that the calling process is finished using + //! the resource. The destructor function will deallocate + //! any system resources allocated by the system for use by this process for + //! this resource. The resource can still be opened again calling + //! the open constructor overload. To erase the resource from the system + //! use remove(). + ~basic_android_managed_shared_memory() {} + + //! Default constructor. Does nothing. + //! Useful in combination with move semantics + basic_android_managed_shared_memory() {} + + //! Creates shared memory and creates and places the segment manager. + //! This can throw. + basic_android_managed_shared_memory( + create_only_t, + const char* name, + size_type size, + const void* addr = 0) + : base_t(), + base2_t( + create_only, + name, + size, + read_write, + addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoCreate)) {} + + //! Creates shared memory and creates and places the segment manager if + //! segment was not created. If segment was created it connects to the + //! segment. + //! This can throw. + basic_android_managed_shared_memory( + open_or_create_t, + const char* name, + size_type size, + const void* addr = 0) + : base_t(), + base2_t( + open_or_create, + name, + size, + read_write, + addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpenOrCreate)) {} + + //! Connects to a created shared memory and its segment manager. + //! in copy_on_write mode. + //! This can throw. + basic_android_managed_shared_memory(open_copy_on_write_t, const char* name, const void* addr = 0) + : base_t(), + base2_t( + open_only, + name, + copy_on_write, + addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpen)) {} + + //! Connects to a created shared memory and its segment manager. + //! in read-only mode. + //! This can throw. + basic_android_managed_shared_memory(open_read_only_t, const char* name, const void* addr = 0) + : base_t(), + base2_t( + open_only, + name, + read_only, + addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpen)) {} + + //! Connects to a created shared memory and its segment manager. + //! This can throw. + basic_android_managed_shared_memory(open_only_t, const char* name, const void* addr = 0) + : base_t(), + base2_t( + open_only, + name, + read_write, + addr, + create_open_func_t(get_this_pointer(), ipcdetail::DoOpen)) {} + + //! Moves the ownership of "moved"'s managed memory to *this. + //! Does not throw + basic_android_managed_shared_memory(BOOST_RV_REF(basic_android_managed_shared_memory) moved) { + basic_android_managed_shared_memory tmp; + this->swap(moved); + tmp.swap(moved); + } + + //! Moves the ownership of "moved"'s managed memory to *this. + //! Does not throw + basic_android_managed_shared_memory& operator=(BOOST_RV_REF(basic_android_managed_shared_memory) + moved) { + basic_android_managed_shared_memory tmp(boost::move(moved)); + this->swap(tmp); + return *this; + } + + //! Swaps the ownership of the managed shared memories managed by *this and other. + //! Never throws. + void swap(basic_android_managed_shared_memory& other) { + base_t::swap(other); + base2_t::swap(other); + } + + //! Tries to resize the managed shared memory object so that we have + //! room for more objects. + //! + //! This function is not synchronized so no other thread or process should + //! be reading or writing the file + static bool grow(const char* shmname, size_type extra_bytes) { + return base_t::template grow(shmname, extra_bytes); + } + + //! Tries to resize the managed shared memory to minimized the size of the file. + //! + //! This function is not synchronized so no other thread or process should + //! be reading or writing the file + static bool shrink_to_fit(const char* shmname) { + return base_t::template shrink_to_fit(shmname); + } +#if !defined(BOOST_INTERPROCESS_DOXYGEN_INVOKED) + + //! Tries to find a previous named allocation address. Returns a memory + //! buffer and the object count. If not found returned pointer is 0. + //! Never throws. + template + std::pair find(char_ptr_holder_t name) { + if (base2_t::get_mapped_region().get_mode() == read_only) { + return base_t::template find_no_lock(name); + } else { + return base_t::template find(name); + } + } + +#endif //#ifndef BOOST_INTERPROCESS_DOXYGEN_INVOKED +}; + +//! Typedef for a default basic_android_managed_shared_memory +//! of narrow characters +typedef basic_android_managed_shared_memory, iset_index> + managed_android_shared_memory; + +//! Typedef for a default basic_android_managed_shared_memory +//! of wide characters +typedef basic_android_managed_shared_memory, iset_index> + wmanaged_android_shared_memory; + +//! Typedef for a default basic_android_managed_shared_memory +//! of narrow characters to be placed in a fixed address +typedef basic_android_managed_shared_memory, iset_index> + fixed_managed_android_shared_memory; + +//! Typedef for a default basic_android_managed_shared_memory +//! of narrow characters to be placed in a fixed address +typedef basic_android_managed_shared_memory< + wchar_t, + rbtree_best_fit, + iset_index> + wfixed_managed_android_shared_memory; + +} // namespace interprocess +} // namespace boost + +#include + +#endif // BOOST_INTERPROCESS_MANAGED_ANDROID_SHARED_MEMORY_HPP diff --git a/DEFS b/DEFS new file mode 100644 index 000000000..0ebcf7e46 --- /dev/null +++ b/DEFS @@ -0,0 +1,10 @@ +HOST_INFO = host_info() + +if HOST_INFO.os.is_macos: + PLATFORM = "mac" +elif HOST_INFO.os.is_windows: + PLATFORM = "win" +elif HOST_INFO.os.is_linux: + PLATFORM = "linux" +else: + raise Exception("Unsupported platform") diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..b2c52f15a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +FROM centos:8 + +# Install Python, Java, wget, vim +RUN yum group install -y "Development Tools" +RUN yum install -y python2 python36 python36-devel wget java-1.8.0-openjdk \ + java-1.8.0-openjdk-devel vim + +# Install Ant +WORKDIR "/tmp" +RUN wget https://downloads.apache.org/ant/binaries/apache-ant-1.10.9-bin.zip +RUN unzip apache-ant-1.10.9-bin.zip \ + && mv apache-ant-1.10.9/ /opt/ant \ + && ln -s /opt/ant/bin/ant /usr/bin/ant + +# Download Buck +WORKDIR "/opt" +RUN git clone https://github.com/facebook/buck.git + +# Set JAVA_HOME +ENV JAVA_HOME="/usr/lib/jvm/java-1.8.0-openjdk" + +# Build Buck +WORKDIR "/opt/buck" +RUN ant +Run ln -s /opt/buck/bin/buck /usr/bin/buck + +# Install Watchman +WORKDIR "/opt/watchman" +RUN wget https://github.com/facebook/watchman/releases/download/v2020.09.21.00/watchman-v2020.09.21.00-linux.zip +RUN unzip watchman-v2020.09.21.00-linux.zip +WORKDIR "/opt/watchman/watchman-v2020.09.21.00-linux" +RUN mkdir -p /usr/local/{bin,lib} /usr/local/var/run/watchman +RUN cp bin/* /usr/local/bin +RUN cp lib/* /usr/local/lib +RUN chmod 755 /usr/local/bin/watchman +RUN chmod 2777 /usr/local/var/run/watchman + +# Copy LabGraph files +WORKDIR "/opt/labgraph" +COPY . . +RUN python3.6 setup.py install --user diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..b96dcb048 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) Facebook, Inc. and its affiliates. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 000000000..cc751207a --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# LabGraph + +LabGraph is a streaming framework built by the Facebook Reality Labs Research team at Facebook. + +## Quick Start + +**Prerequisites**: + +- [Buck](https://buck.build/setup/getting_started.html) ([Watchman](https://facebook.github.io/watchman/docs/install) also recommended) +- [Python 3.6](https://www.python.org/downloads/release/python-368/) (note: currently incompatible with Anaconda) +- **Windows only:** [Build Tools for Visual Studio 2019](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2019) + +**Setup**: + +*On Windows, this setup step must be run in "x64 Native Tools Command Prompt for VS 2019" so that we can access the Visual Studio compiler toolchain.* + +``` +cd labgraph +python setup.py install +``` + +To make sure things are working you can run the example: + +``` +python -m labgraph.examples.simple_viz +``` + +You can also run the test suite as follows: + +``` +python -m pytest --pyargs labgraph +``` + +Now go to the [documentation](docs/) to learn more! + + +**License**: +LabGraph is MIT licensed, as found in the LICENSE file. diff --git a/buck_ext.py b/buck_ext.py new file mode 100644 index 000000000..b88a02b46 --- /dev/null +++ b/buck_ext.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import os +import platform +import shutil +import subprocess + +from setuptools import Extension +from setuptools.command.build_ext import build_ext + + +CONFIG_FILE = { + "Windows": "win.buckconfig", +}.get(platform.system(), "unix.buckconfig") + + +class BuckExtension(Extension): + def __init__(self, name: str, target: str) -> None: + # don't invoke the original build_ext + super().__init__(name, sources=[]) + self.target = target + + +class buck_build_ext(build_ext): + def build_extensions(self) -> None: + if "DF_SKIP_BUCK_BUILD" in os.environ: + return + assert shutil.which("buck") is not None, ( + "Could not find buck on the PATH\n" + "To install Buck please see https://buck.build/setup/getting_started.html" + ) + exts_by_target = { + ext.target: ext for ext in self.extensions if isinstance(ext, BuckExtension) + } + result = ( + subprocess.check_output( + ["buck", "build", "--show-output", "--config-file", CONFIG_FILE] + + list(exts_by_target.keys()) + ) + .decode("utf-8") + .strip() + ) + for line in result.split("\n"): + target, output_path = line.split(" ") + shutil.copy(output_path, self.get_ext_fullpath(exts_by_target[target].name)) diff --git a/docs/concepts.md b/docs/concepts.md new file mode 100644 index 000000000..eab993cd7 --- /dev/null +++ b/docs/concepts.md @@ -0,0 +1,211 @@ +# LabGraph Concepts + +The fundamental units of systems built with LabGraph are: + +* [**Messages**](#messages) +* [**Streams**](#streams-and-topics) +* [**Topics**](#streams-and-topics) +* [**Nodes**](#nodes) +* [**Groups**](#groups) +* [**Graphs**](#graphs) + +Together, these concepts allow us to construct [real-time](https://en.wikipedia.org/wiki/Real-time_computing) computational [graphs](https://en.wikipedia.org/wiki/Graph_(discrete_mathematics). These are "networks" of algorithms working together to produce some result within a time constraint. We want to be able to iterate on systems we build this way as efficiently as possible, which is what LabGraph is designed to enable. By enabling the fast plug-and-play of different nodes in such a graph, we can rapidly try out different hardware sensors, preprocessing pipelines, machine learning models, and user interfaces. + +In this overview we will use a toy example of a simple visualization. The example is intended to illustrate the end-to-end combination of a data source, processing step, and user interface. While this may not seem like a useful piece of software to build, this example is a jumping-off point that is extensible to any combination of hardware, processing, and UI. + +## Messages + +A **message** is a piece of data with a consistent structure. For example: + +``` +import numpy as np +import labgraph.v1 as lg + +class RandomMessage(lg.Message): + timestamp: float + data: np.ndarray +``` +Here, we define two fields: + +* `timestamp`, a float which associates a timestamp with the data. +* `data`, a numpy array that stores some data (which we will generate randomly in this example) + +This should look familiar if you are familiar with [dataclasses](https://docs.python.org/3/library/dataclasses.html) or [named tuples](https://docs.python.org/3/library/collections.html#collections.namedtuple) in Python โ€“ these are libraries that allow the concise construction of simple data-wrapping classes using Python typehints. Like these builtin libraries, LabGraph relies on Python type hints to allow users to specify how data is composed. As you'll see when we look at groups, LabGraph relies heavily on type hints in general for composition. + +To create a message, we simply create an instance of the `RandomMessage` class: + +``` +import time +random_message = RandomMessage( + timestamp=time.time(), data=np.random.rand(100) +) +# Now LabGraph can use random_message +``` +Suppose we were running an experiment where someone presses a button, and we wanted to include the state of the button with every frame. We could just add a `button_pressed` field to `RandomMessage`, but this would couple `RandomMessage` with that experiment and make reusing it with other experiments harder. Instead, we can **compose message types** via class inheritance (in the same way that the `dataclasses` module allows): + +``` +class CustomMessage(RandomMessage): + button_pressed: bool +``` +Then `CustomMessage` retains all the fields of `RandomMessage`, and we can instantiate it like so: + +``` +custom_message = CustomMessage( + timestamp=time.time(), + data=np.random.rand(100), + button_pressed=True, +) +``` +## Streams and Topics + +A **stream** is a sequence of messages that is accessible in real-time. Streams are a useful construct when we want to build systems that respond in real-time to input from a hardware device. In this example we will stream `RandomMessage` which is not particularly useful, but you could imagine a sensor stream instead in an experimental setting. + +A **topic** is a named reference to a stream. This is useful because we usually want to refer to a stream by different names in different contexts. + +We'll see how to create topics when we discuss nodes below, and we'll see how to create streams when we discuss groups. + +## Nodes + +A **node** is a class that describes a self-contained algorithm that operates on topics. Nodes have the following properties: + +* They define topics which act as inputs and outputs for streams +* They describe their algorithms using methods that are marked with special LabGraph "decorators" +* They are guaranteed to always be running in the same Python process throughout the life of a graph, with access to the same memory. This means a node can store state that is unique to the algorithm it implements. + +Nodes describe their algorithms using methods that are marked with special LabGraph decorators. Here is an example of a node that takes a rolling average of some data: + +``` +class RollingState(lg.State): + messages: List[RandomMessage] = field(default_factory=list) + +class RollingConfig(lg.Config): + window: float + +class RollingAverager(lg.Node): + INPUT = lg.Topic(RandomMessage) + OUTPUT = lg.Topic(RandomMessage) + + state: RollingState + config: RollingConfig + + @lg.subscriber(INPUT) + @lg.publisher(OUTPUT) + async def average(self, message: RandomMessage) -> lg.AsyncPublisher: + current_time = time.time() + self.state.messages.append(message) + self.state.messages = [ + message + for message in self.state.messages + if message.timestamp >= current_time - self.config.window + ] + if len(self.state.messages) == 0: + return + all_data = np.stack([message.data for message in self.state.messages]) + mean_data = np.mean(all_data, axis=0) + yield self.OUTPUT, RandomMessage(timestamp=current_time, data=mean_data) +``` +First, we define some state & configuration - see [Lifecycles and Configuration](lifecycles-and-configuration) for details. Then we define the `RollingAverager` node: + +* We define two topics, `INPUT` and `OUTPUT` which are references to streams of type `RandomMessage`. These topics are local to the `RolingAverager` node; it is the only node that can interact with them. When we construct a graph, we can point these topics at whatever streams we want. +* We define a method `average` to describe the averaging algorithm. + * The **subscriber** decorator indicates that this method subscribes to the `INPUT` topic. Whenever a message is sent into the stream that the `INPUT` topic points to, the `average` method will be called with that message. + * The **publisher** decorator indicates that this method publishes to the `OUTPUT` topic. + * The `async` keyword indicates that this is a asyncio-enabled method. [asyncio](https://docs.python.org/3/library/asyncio.html) is a builtin Python library for writing concurrent code. + * `AsyncPublisher` is a typehint provided by LabGraph to help type publisher functions.. + * The averaging algorithm produces an average sample by looking at all previous samples over the window. + * The `yield` keyword is used to publish messages using asyncio. We yield a tuple containing the topic and the message to be published. + +## Groups + +A **group** is a container that includes some functionality that can be reused much like a node can be. A group can contain nodes, as well as other groups. As a result, groups enable composition and swappability of subgraphs. + +Suppose we wanted a way to quickly package together a data source and a transformation of that data. Here is a `Generator` node, as well as a group that packages it with `RollingAverager` above: + +``` +class GeneratorConfig(lg.Config): + sample_rate: float + num_features: int + +class Generator(lg.Node): + OUTPUT = lg.Topic(RandomMessage) + config: GeneratorConfig + + @lg.publisher(OUTPUT) + async def generate_noise(self) -> lg.AsyncPublisher: + while True: + yield self.OUTPUT, RandomMessage( + timestamp=time.time(), data=np.random.rand(self.config.num_features) + ) + await asyncio.sleep(1 / self.config.sample_rate) + +class AveragedNoiseConfig(lg.Config): + sample_rate: float + num_features: int + window: float + +class AveragedNoise(lg.Group): + OUTPUT = lg.Topic(RandomMessage) + + config: AveragedNoiseConfig + GENERATOR: Generator + ROLLING_AVERAGER: RollingAverager + + def connections(self) -> lg.Connections: + return ( + (self.GENERATOR.OUTPUT, self.ROLLING_AVERAGER.INPUT), + (self.ROLLING_AVERAGER.OUTPUT, self.OUTPUT), + ) + + def setup(self) -> None: + # Cascade configuration to contained nodes + self.GENERATOR.configure( + GeneratorConfig( + sample_rate=self.config.sample_rate, + num_features=self.config.num_features, + ) + ) + self.ROLLING_AVERAGER.configure(RollingConfig(window=self.config.window)) +``` +* We create an output topic for the group - other groups that contain this group can connect to this topic +* We assign a configuration to this group that contains all the information both nodes require +* We add the type annotations `GENERATOR` and `ROLLING_AVERAGER` to indicate that each `AveragedNoise` group contains these nodes. +* The `connections` method lets us specify how topics will be connected. When two topics are connected, it means they will point to the same stream at runtime. In this case we specify that the `OUTPUT` topic of the `Generator` will be connected to the `INPUT` topic of the `RollingAverager`. We also create the `OUTPUT` topic in `AveragedNoise` that basically exposes the output stream from `RollingAverager`. + +Now we can use `AveragedNoise` as if it were a node โ€“ it is a self-contained module that we can reuse anywhere we want. + +## Graphs + +A **graph** is a complete set of topics and nodes that describes a functioning system. It is actually a group, but it is assumed to be the outermost container for the description of a system. Suppose we want to display a live visualization using our group from earlier. We can define a graph as follows: + +``` +class Demo(lg.Graph): + AVERAGED_NOISE: AveragedNoise + PLOT: Plot + + def setup(self) -> None: + self.AVERAGED_NOISE.configure( + AveragedNoiseConfig( + sample_rate=SAMPLE_RATE, num_features=NUM_FEATURES, window=WINDOW + ) + ) + self.PLOT.configure( + PlotConfig(refresh_rate=REFRESH_RATE, num_bars=NUM_FEATURES) + ) + + def connections(self) -> lg.Connections: + return ((self.AVERAGED_NOISE.OUTPUT, self.PLOT.INPUT),) + + def process_modules(self) -> Tuple[lg.Module, ...]: + return (self.AVERAGED_NOISE, self.PLOT) +``` +* We add the `AVERAGED_NOISE` group from before, as well as a `Plot` node (implementation left out) that displays a live bar graph in a UI. +* Since graphs are groups, we can use `connections()` to connect `AveragedNoise` to `Plot`. +* Graphs have the additional functionality of being able to define `process_modules()` which lets us specify the process architecture of the groups and nodes the graph contains. In this case, by returning `(self.AVERAGED_NOISE, self.PLOT)` from this method, we cause the `AveragedNoise` group and the `Plot` node to run in separate processes. If we excluded this method, everything would run in a single process. In this way, `process_modules()` lets us concisely specify how a graph should be parallelized. + +Then we can run the graph using the `lg.run()` tool: + +``` +if __name__ == "__main__": + lg.run(Demo) +``` +That's it! This will run the graph, which will generate noise and display it in real-time. diff --git a/docs/cpp-interop.md b/docs/cpp-interop.md new file mode 100644 index 000000000..cc9689035 --- /dev/null +++ b/docs/cpp-interop.md @@ -0,0 +1,78 @@ +# C++ Interoperability + +Sometimes, Python just isn't fast enough to be able to process real-time signals within an acceptable latency bound. (Or, it's too much effort to tune Python to do so.) In these cases, we may want to drop down to C++ to implement some real-time processing in a more performant manner. + + + +LabGraph comes with a `labgraph_cpp` library which allows us to define nodes directly in C++. Then, with the help of [pybind11](https://github.com/pybind/pybind11), we can embed that node in a LabGraph graph just as we would a Python node. + +``` +// MyCPPSource.h +#pragma once +#include +class MyCPPSource : public labgraph::Node { + public: + std::vector getTopics() const; + std::vector getPublishers(); + void mainPublisher(); + static constexpr int const& kNumSamples = 10; + static constexpr double const& kPublishRate = 5.0; +}; +``` + + +``` +// MyCPPSource.cpp +#include "MyCPPSource.h" +#include "TestSample.h" +std::vector MyCPPSource::getTopics() const { + return {"A"}; +} +std::vector MyCPPSource::getPublishers() { + return {{{"A"}, [this]() { mainPublisher(); }}}; +} +void MyCPPSource::mainPublisher() { + // Publisher that sends 10 messages with a single int in each one + const double publish_sleep = 1.0 / kPublishRate; + for (uint32_t i = 0; i < kNumSamples; i++) { + TestSample sample; + sample.value = i; + publish("A", sample); + std::this_thread::sleep_for(std::chrono::duration(publish_sleep)); + } +} +``` +In the header and implementation above, we are defining `MyCPPSource`, which is a LabGraph C++ node that publishes to a single topic, A. Its number of samples and publish rate is fixed in this example, but these could be made configurable with a configuration object. `TestSample` as defined in TestSample.h is a Cthulhu sample type; see the [Cthulhu documentation](cthulhu) for more details on this. + + + +``` +#include +#include +#include "MyCPPSource.h" + +namespace py = pybind11; + +PYBIND11_MODULE(MyCPPNodes, m) { + std::vector sourceTopics = {"A"}; + labgraph::bindNode(m, "MyCPPSource", sourceTopics) + .def(py::init()) + .def_readonly_static("NUM_SAMPLES", &MyCPPSource::kNumSamples); +} +``` + + +Here we use pybind11 to create Python bindings for the node. Note the use of the `labgraph::bindNode` function; this creates a class binding with methods that LabGraph uses to identify information about the node, and then it returns the class binding for you to use like any other pybind11 binding. + + + +Finally, we can use `MyCPPSource` in a LabGraph graph: + + + +``` +from MyCPPNodes import MyCPPSource +class MyGraph(df.Graph): + CPP_SOURCE: MyCPPSource + ... +``` diff --git a/docs/cthulhu.md b/docs/cthulhu.md new file mode 100644 index 000000000..03270d598 --- /dev/null +++ b/docs/cthulhu.md @@ -0,0 +1,254 @@ +# Cthulhu + +Cthulhu is a flexible real-time streaming and synchronization framework. + +## What is Cthulhu? + +Cthulhu is a C++ library with minimal software dependencies. It provides an API for building low-latency processing graphs using standardized and customizable stream types. + +So, it's a pub/sub framework, why not just use ? + 1. Cthulhu's API enables explicit construction of a graphical flow of data. Think of pub/sub as the single-input or single-output cases, whereas Cthulhu enables multi-input-multi-output (MIMO) compute tasks. This enables the framework to automatically track the flow of individual samples through the pipeline, and produce end-to-end historical latency tracking of any sample. In the future, it may also provide a convenient API for dynamic flow control within the graph. + 2. Typical pub/sub frameworks focus on distributed socket-based communication. For systems with light-weight metadata streams, this works just fine. But with perception systems, we often use high-bandwidth data on our stream interfaces. Cthulhu allocates and recycles data buffers from shared memory, and exposes them to the user as ordinary shared pointer to enable transparent low-latency IPC to consumers that live in other processes on the same machine. + +Cthulhu is currently supported on Windows, Mac, Linux, and Android. + +## Why should I care? + +Cthulhu enables tooling and infrastructure reuse across real-time pipelines, and modularity for reuse of subcomponents. For a user that builds a new pipeline using entirely existing stream types and compute functions, all tooling comes for free. + +## Streams + +To use Cthulhu, first you must define the layout of your streaming data. Cthulhu comes packaged with a few fundamental types such as image and audio streams, but provides an API for users to register their own types without modification to the Cthulhu library. + +A sample of a stream has 4 components: + - Header - Unique identifying information. + - Timestamp + - Sequence + - ProcessingTimestamp(s) [Optional] - It is possible to tag a sample with timestamps that are associated with stages in the processing chain at which it was developed. An example would be the time at which an image was received in user-space software from a camera device. + - Content Block [Optional] - This is variable size bulk data. Think of it as the pixel data in an image. The size of the block must be derivable from the Config Fields (more on that later). This block can also be broken out into a set of sub-samples that is specified by an additional field. By default, the block is composed of a single sub-sample. + - Sample Field(s) [Optional] - These are light-weight fixed-size fields. Each field is named, and must be POD. + +A user can define a sample format by inheriting from cthulhu::AutoStreamSample: + +``` +class ImageData : public AutoStreamSample { + using T = ImageData; + + public: + // We are free to name each parameter as desired + HeaderTimestamp captureTimestamp{this}; + HeaderSequence frameNumber{this}; + + // Define the name which the processing stamp will be given + ProcessingTimestamp arrivalTimestamp{"arrival", this}; + + // If we want a Content Block, just add one with any parameter name. + ContentBlock data{this}; + + // All fields must be sandwiched between a FieldsBegin and FieldsEnd + FieldsBegin begin; + // Define the type (here uint32_t), + SampleField strideInBytes{"image_stride", this}; + SampleField offsetInBytes{"offset", this}; + FieldsEnd end; + + // This must be called as public, and takes the class name as argument + CTHULHU_AUTOSTREAM_SAMPLE(ImageData); +}; +``` + +If a stream has no Content Block, it is called a "Basic Stream." And your journey ends here. Put this in a header, and call the basic registration function from the corresponding cpp source file: + +``` +CTHULHU_REGISTER_BASIC_STREAM_TYPE(Image, cthulhu::ImageData); +``` + +This registers the type to the identified "Image", which must be unique across all actively communicating Cthulhu runtimes. + +If your stream includes a Content Block, it must also provide a Configuration which can be used to configure the Stream's Content Block format. This is similar to the Sample definition, but has the following components: + + - Compute Sample Size Function - This function must return the size of the Content Block being actively streamed. If the block is broken into sub-samples, it is the size of a single sub-sample. + - Sample Rate [Optional] - This is the nominal rate of samples being streamed. + - Config Field(s) - Similar to Sample Fields, but at least one field is required for use in the Compute Sample Size Function. + +Here is an example: + +``` +enum class PixelFormat : uint32_t { INVALID = 0, MONO_8 = 1, MONO_10 = 2, YUY2 = 3, COUNT }; + +class ImageFormat : public AutoStreamConfig { + using T = ImageFormat; + + public: + SampleRate nominalSampleRate{this}; + + FieldsBegin begin; + ConfigField width{"image_width", this}; + ConfigField height{"image_height", this}; + ConfigField pixelFormat{"pixel_format", this}; + FieldsEnd end; + + // This is the pure-virtual function that must be overridden + inline virtual uint32_t computeSampleSize() const override { + switch (pixelFormat) { + case PixelFormat::MONO_8: + return width * height; + case PixelFormat::MONO_10: + return (width * height * 10) / 8; + case PixelFormat::YUY2: + return 2U * width * height; + default: + return 0; + }; + }; + + CTHULHU_AUTOSTREAM_CONFIG(ImageFormat); +}; +``` + +This stream can then be registered as an ordinary stream type: +``` +CTHULHU_REGISTER_STREAM_TYPE(Image, cthulhu::ImageData, cthulhu::ImageFormat); +``` + +If a stream type is registered in a static library, it is important to ensure that symbols required for type registration get linked into the final executable. Using BUCK, these libraries should set `link_whole = True`. + +To work with the components of the streams, such as ConfigFields, they come with set()/get() functions, and also overload operator=() for convenience. So you can access them just like you would an ordinary data field. Underneath the hood, these types are just thin wrappers over a single generic StreamSample data structure object. This enables the framework to cast between typed and untyped data with minimal overhead, while providing regularized structure to the untyped data that allows it to work its magic without embedding the data in an additional container. + +You may ask: but what if I need multiple content blocks in my stream? The answer is, you don't. If you need an additional content block, then you need an additional stream. Cthulhu's APIs make it just as easy and performant to work with multiple streams instead of just one, so your system will thank you for the modularity of splitting out the data. + +## Nodes + +Nodes are a logical unit of compute within the pipeline which receives N data streams in to produce M data streams out. Cthulhu provides an API for convenient construction of Nodes. + +Here's an example of the most basic pub/sub behavior using a "Basic" stream type with sample type BasicSample: + +``` +cthulhu::Context myContext("my_context"); + +std::function cb = + [](const BasicSample& sample) -> void {}; +auto subscriber = myContext.subscribe("stream_name", cb); + +auto publisher = myContext.advertise("stream_name"); +BasicSampleType mySample; +publish.publish(mySample); +``` + +Since both the producer and the consumer in this example are in the same process, underneath the hood the call to publish() is directly calling the callback "cb" without any queueing or additional threads. This is great for cases where consumers are super-light-weight processing that have minimal penalty in injecting their function directly in the producer's thread since the data will reach the consumer with the least latency. + +But what if we had a heavy consuming function that needed its own thread or would otherwise slow down the consumer? That's what SubscriberOptions are for. We can call subscribe() with an additional options parameter which sets the ConsumerType to ASYNC. This will cause the subscriber to dedicate its own thread for processing its callback function. In this case, the publish() call will now push mySample to an async queue and notify the subscriber's thread. + +For usage of only single input or single output Nodes and basic stream types, this API looks a lot like basic pub/sub. Next, let's explore how we use an ordinary stream that uses both Config and Samples: + +``` +// Subscribers must now specify two callbacks, one for sample and one for config +// The config callback returns bool. With +std::function cb = + [](const cthulhu::ImageData& image) -> void { callback_executed = true; }; +std::function configCb = + [](const cthulhu::ImageFormat& format) -> bool { + return true; +}; + +auto sub = context.subscribe("image", cb, configCb); + +auto pub = context.advertise("image"); + +// We must configure our stream before we publish any samples on it! +// The config must produce a valid return value of computeSampleSize(), so here we set +// the height and width of the image to something valid +cthulhu::ImageFormat format; +format.width = 640; +format.height = 480; +format.pixelFormat = cthulhu::PixelFormat::MONO_8; +pub->configure(format); + +// We must use our publisher to allocate our sample data! +// This will leverage the current config of the stream, which is a 640 x 480 image +cthulhu::ImageData image = pub->allocateSample(); +pub->publish(image); +``` + +The difference here is that we now have 2 callbacks, and must call configure() before any calls to publish() on the stream. The Sample must also be allocated using the publisher since it has a Content Block. + +Calls to publish() and configure() are not thread safe. Thus, you should only push data to a producing Node on a single thread. Conversely, the config and sample callbacks do not need to handle thread safety. The user can assume that the two types of callbacks will only come from a single thread. + +So far, we've only explored single input and single output Nodes. Next, let's look at a Transformer with both an input and an output: + +``` +std::function cb = + [](const cthulhu::ImageData& image, cthulhu::ImageData& imageOut) -> void {}; +std::function configCb = + [](const cthulhu::ImageFormat& format, cthulhu::ImageFormat& formatOut) -> bool { + formatOut.width = 640; + formatOut.height = 480; + formatOut.pixelFormat = cthulhu::PixelFormat::MONO_8; + return true; +}; + +auto trans = + context.transform("image1", "image2", cb, config_cb); +``` + +This should look like a mix between the Publisher and Subscriber, because it is. The main difference is that the user is not responsible for allocating its output samples, as the framework will provide it to the callback pre-allocated. Configuring the output stream also happens within the callback to the configuration of the input stream. In many cases, the two configurations may be un-related, but this gives the flexibility in allowing the user to tie the two together. For example, an RGB to Grayscale transformer would maintain the height/width of the original image and expect the input pixel format to be RGB. + +Similar to Subscriber, this can be given TransformerOptions optionally to specify ASYNC mode. + +Finally, the most complex case of multi-input, multi-output, here is an example: + +``` +std::function&, std::vector&)> cb = + []( + const std::vector& imagesIn, + std::vector& imagesOut) -> void {}; +std::function&, std::vector&)> + configCb = [](const std::vector& imagesIn, + std::vector& imagesOut) -> bool { return true; }; +cthulhu::MultiTransformer trans = context.transform( + {std::vector{"image1", "image2"}}, + {std::vector{"image3"}}, + cb, + configCb); +``` + +This should look just like the regular transformer, but now the input stream and output streams are lists of stream ID's rather than single values. The callback arguments can also be grouped together with std::vector or std::array, which can be handy for cases where you have a large number of input or output streams of the same type. + +Underneath the hood, Cthulhu is creating Producers and Consumers for each of these streams, and joining them together in an Aligner and a Dispatcher. The default Alignment behavior is based on timestamp matching with a max latency and tolerance threshold. The user can create their own variants of Aligner and pass them via MultiTransformerOptions (or MultiSubscriberOptions). This allows for customizable alignment behavior. Cthulhu comes packaged with an additional SubAligner implementation that can align the sub-samples of streams within a Content Block. This requires any stream using sub-samples to include a Sample Rate within its Config. + +## Clock + +Cthulhu also provides a clock interface, useful for system simulation. A user should query time through cthulhu: +``` +auto time = cthulhu::clock()->getTime(); +``` +By default, this will just return wall time. However, a single context name can be given clock authority to control time. This should be whichever context is being used to control the flow of data via Publishers. +``` +int main() { + // Declare use of simulated time, with clock_owner as the context + cthulhu::ClockAuthority fac(true, "clock_owner"); + + ... + + // This context can now control time + cthulhu::Context owningContext("clock_owner"); + owningContext.getClockControl()->setTime(500.0); + owningContext.getClockControl()->start(); + + // And this one cannot + cthulhu::Context otherContext("some_context"); + otherContext.getClockControl(); // Returns nullptr +} +``` + +Listeners of the clock can subscribe to events, such as start, pause, etc. + +## Framework + +All of the above is sufficient for most users of Cthulhu to accomplish their goal. However, these functionalities under the hood are using the Cthulhu Framework Singleton to achieve their goals. The Framework has 4 components: + - TypeRegistry - Provides access to information about stream types that have been registered. E.g. names of fields, basic flag, sizes, etc. + - StreamRegistry - Provides access to stream interfaces on which data can be propagated (using raw StreamConfig and StreamSample's) + - MemoryPool - Allocates recyclable data buffers (from local memory, shared memory, etc) + - ClockManager - Manages the state of the clock, and access to its controls + +Currently, the default implementation of Framework is called "IPCHybrid." This implementation uses a mix of managed shared memory and local memory to achieve its goals with minimal latency. Thus, interactions between nodes in the same process don't have to go through shared memory and callbacks are executed directly. The CTHULHU_IPC compiler flag will set this, and removal of the flag will compile against a "Local" implementation of Framework that is restricted to a single process. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..7a3f163a0 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,30 @@ +# Introduction + +LabGraph is a Python framework for building real-time research systems. The Facebook Reality Lab Research (FRLR) team at Facebook uses it to rapidly prototype and test new wearable hardware systems, experimental stimulus protocols, digital signal processing steps, and live visualizations. LabGraph has allowed FRLR to greatly accelerate its pace of experimentation. We hope for other groups to benefit from this tooling as well. + +More specifically, LabGraph provides a way to define a computational graph in a standardized way. This results in a less tedious development process for real-time algorithms and systems. In other words, the framework decides how data types, computations, and connections between the inputs and outputs of related computations should be stated, and then it sets up the boilerplate needed to run these streaming computations efficiently in parallel. In turn, the researcher is able to focus on developing individual real-time algorithms while assuming the rest of the system runs correctly. + +We built LabGraph because there was no existing solution that we felt was sufficiently user-friendly, performant, and flexible. Our primary goal was to minimize the time it takes for a scientist to get from an idea to an experiment. In addition, we wanted to support the high data rates (several MHz) that might come from certain sensors. Also, we wanted to make it easy to extract algorithms from existing projects for reuse in new ones. + +## Features + +LabGraph comes with built-in support for the following: + +* **Performant real-time streaming:** LabGraph depends on Cthulhu (a C++ framework for real-time streaming. The Facebook Reality Lab in Pittsburgh has used this framework to stream high data rates (on the order of MHz), and with LabGraph we are adapting it to work with hardware. In particular Cthulhu uses shared memory to minimize copies and buffer recycling to minimize allocations. +* **Graph API:** LabGraph allows us to define computational graphs as Python classes. Each LabGraph graph describes a real-time system that includes "nodes" for hardware streaming, signal processing, machine learning, and/or user interfaces. We can also define reusable groups of nodes - each group describes a subsystem that we can reuse in different graphs. +* **Data logging:** A logger for the HDF5 disk format comes built-in, and additional formats can be implemented using a Logger abstraction. The data types used in streams and on disk are derived from Messages, which are an extension of dataclasses; creating and updating these types is as easy as working with dataclasses. +* **Python-C++ interoperability:** LabGraph allows nodes to be written in C++, which can be useful in situations where tuning the performance of an algorithm in Python would be too difficult. Using pybind11, C++ nodes can be dropped into LabGraph graphs as if they were Python nodes. For more flexibility (but at the cost of access to LabGraph features), it is also possible to write C++ that interacts directly with the Cthulhu transport framework. +* **Stimulus events:** We can write "event generators" to define the stimulus events that will occur in an experiment. This serves as a useful abstraction for the current state of the experiment. +* **Parallelism in Python:** Writing parallel Python code is notoriously difficult. LabGraph helps ease some of this difficulty with a) a process manager that takes care of spawning and monitoring parallel processes, and b) asyncio support for concurrency within each process. + +## Opinions + +The development of LabGraph has been motivated by the following beliefs: + +1. **Modularization is critical to building many reliable experimental systems.** Modularization is not the fastest way to build a single system, but it is essential when building many. By doing so, we build a library of well-tested components with behavior that can be isolated from any other part of the system. This keeps the debugging of complex systems tractable and also allows us to write good unit tests. +2. **Python is the language of choice for closed-loop research.** The Python ecosystem is uniquely well-positioned to support decoding efforts: we have access to sophisticated tools for numerical computation and machine learning, as well as a plethora of other well-tested software for working with hardware and UIs. As a result, LabGraph is a Python-first framework. +3. **We need a better way to transition between real-time and analysis work.** The search for the answer to this question has motivated many of our design decisions in LabGraph to date, although so far LabGraph has remained a real-time-only framework. We are just now starting to propose and implement the first designs for using LabGraph graphs & data in an "offline" analysis context. When we are done with this effort we expect to greatly accelerate our cycles of analysis, development, and experimentation. + +## Team + +LabGraph is currently maintained by Jimmy Feng (primary), Pradeep Damodara, Ryan Catoen and Allen Yin. A non-exhaustive but growing list needs to mention: Dev Chakraborty (primary), Pradeep Damodara, Ryan Catoen, Ruben Sethi, Allen Yin, Rudy Sevile, Sho Nakagome, Ryan Orendorff, Anton Vorontsov, Rosemary Le, Ying Yang, Emily Mugler and Steph Naufel. diff --git a/docs/lifecycles-and-configuration.md b/docs/lifecycles-and-configuration.md new file mode 100644 index 000000000..3f6f73ae2 --- /dev/null +++ b/docs/lifecycles-and-configuration.md @@ -0,0 +1,63 @@ +# Module Lifecycle + +A node, group, or graph (a module) goes through the following steps in its lifetime: + +1. **Definition**: The module type is defined in Python code which the Python interpreter reads into memory. +2. **Construction**: We construct an instance of the module. If the module is a graph, then the user explicitly constructs a graph like `graph = MyGraph()`. Otherwise, a module is implicitly constructed by its containing graph when that graph is constructed. +3. **Setup**: As a LabGraph graph is starting up, `setup()` is called on every module. If a group contains some other modules, the group's `setup()` will always be called before those modules' `setup()`s are called. During the `setup()` call, the module can prepare itself for execution. If the module is a group, then it can also configure the modules it contains - see [Configuration](#configuration). +4. **Execution**: When the graph is ready, LabGraph will begin execution of all modules simultaneously. +5. **Cleanup**: When all modules have terminated, LabGraph will run `cleanup()` on every module. `cleanup()` will be called in the same order that `setup()` was called. + +# Configuration + +LabGraph provides a way to concisely specify configuration that is given to a graph and forwarded to its descendant nodes. We start by defining a configuration type: + +``` +class MyNodeConfig(df.Config): + num_trials: int + participant_name: str +``` +`Config` classes actually just `Message` classes, except that they also provide special utilities for configuring graphs, as you'll see. + + + +We specify the configuration for a `Node`, `Group`, or `Graph` by giving it a `config` type annotation: + +``` +class MyNode(df.Node): + config: MyNodeConfig + + ... +``` +Then we can configure it by calling `configure()` on it. We configure a node or group in the `setup()` method of its containing group: + +``` +class MyGroupConfig(df.Config): + ... + +class MyGroup(df.Config): + config: MyGroupConfig + MY_NODE: MyNode + + def setup(self) -> None: + # Cascade config to MY_NODE based on the + # group's config + my_node_config = MyNodeConfig(...) + self.MY_NODE.configure(my_node_config) +``` +The exception to this is graphs, which we can construct and configure directly: + +``` +my_graph = MyGraph() +my_graph.configure(MyGraphConfig(...)) +``` +Rather than hard-coding the top-level configuration like this, though, we can automatically build the configuration from from command-line arguments like so: + +``` +my_config = MyGraphConfig.fromargs() +``` +The `df.run` function actually gets configuration using `fromargs()`, so we can also just run a graph using command-line arguments like so: + +``` +df.run(MyGraph) +``` diff --git a/docs/messages.md b/docs/messages.md new file mode 100644 index 000000000..253297b85 --- /dev/null +++ b/docs/messages.md @@ -0,0 +1,35 @@ +# Messages + +LabGraph Messages are how we define data types for use in our computational graphs. They work like [dataclasses](https://docs.python.org/3/library/dataclasses.html) in Python (and in fact use dataclasses under the hood), but they have some additional features: + +* **Shared memory:** Every message is allocated in shared memory (via Cthulhu, the underlying transport framework for LabGraph). So, we can put large amounts of data into a message and expect that data not to be copied between when we publish it from a node and when we receive it in another node. +* **Fixed vs. dynamic fields:** Some field types, like `int` and `float`, have fixed length, meaning they always take up a fixed amount of space in memory. Others, like `str` and `bytes`, have dynamic length, meaning we don't know how much space they'll take in memory until we create the message. In general, fixed-length field types will be more performant than dynamic-length field types because Cthulhu is able to recycle buffers of the same length more efficiently. However, dynamic-length fields can add useful flexibility when we simply don't know the length of our fields until runtime. We have a default mapping from common types to fixed and dynamic field types, but it is also possible to explicitly create fixed-length fields for `str`, `bytes`, and `numpy.ndarray`. +* **Message type connectability:** Sometimes we want to use different message types for different topics, but still be able to connect them. For example, we may want a field type to be dynamic in general, but fixed when dealing with a particular hardware system. As a result, we allow connecting topics with different message types so long as those types are *connectable*. Two message types are connectable if: + 1. They have the same number of fields, and + 2. For every *i*, the *i*th field in each message type is connectable, where two fields are connectable if: + 1. They are both fixed-length fields with the same length, or + 2. They are both dynamic-length fields, or + 3. They are a fixed-length field and a dynamic-length field with the same underlying Python type + +Here is a simple example of connectability: + +``` +class MyMessage1(df.Message): + field1: int + field2: df.NumpyType(shape=(100, 100)) + +class MyMessage2(df.Message): + field1: df.BytesType(length=8) + field2: np.ndarray + +class MyMessage3(df.Message): + field1: int + field2: df.NumpyType(shape=(100, 200)) +``` +Here are the connectability statements we can make: + +* **MyMessage1 and MyMessage2 are connectable.** The field1 fields are fixed-length fields of the same length (8 bytes), and the field2 fields are a fixed and dynamic field with the same underlying Python type (`np.ndarray`). +* **MyMessage2 and MyMessage3 are connectable.** This is very similar to the previous statement. The field1 fields are fixed with the same length, and the field2 fields are fixed and dynamic, but both `np.ndarray`. +* **MyMessage1 and MyMessage3 are not connectable.** This is because while their field1 fields are connectable, their field2 fields are fixed-length fields with different lengths, so they are not connectable. + +The implication of this is that a stream cannot have two topics with types `MyMessage1` and `MyMessage3`. The other pairings would be fine, though. diff --git a/docs/zmq-support.md b/docs/zmq-support.md new file mode 100644 index 000000000..f986c6fc0 --- /dev/null +++ b/docs/zmq-support.md @@ -0,0 +1,22 @@ +# ZMQ Support + +LabGraph has two types of nodes which allow us to use the [ZeroMQ (ZMQ) library](https://zeromq.org/languages/python/): `ZMQPollerNode` and `ZMQSenderNode`. They work with ZMQ sockets that use the PUB and SUB modes; other modes like REQ/REP and PAIR are currently unsupported. + +## ZMQMessage + +The basic message type that is used by both the `ZMQPollerNode` and `ZMQSenderNode` to communicate ZMQ data to the graph. It has just one field, `data`, which contains the raw bytes sent over the ZMQ socket. + +## ZMQPollerNode + +This node polls ZMQ data of a particular ZMQ topic at a particular read address (both configurable). Any data polled by the node is published as a `ZMQMessage` back to the rest of the graph. This node has the following configuration parameters via `ZMQPollerConfig`: + +* `read_addr`: The address through which ZMQ data should be polled. +* `zmq_topic`: The ZMQ topic being polled. +* `poll_time`: How long each iteration of the polling loop should take (in seconds) + +## ZMQSenderNode + +This node subscribes to a stream of `ZMQMessage`s, and publishes its contents over ZMQ at a configured address/topic. This node has the following configuration parameters via `ZMQSenderConfig`: + +* `write_addr`: The address to which ZMQ data should be written. +* `zmq_topic`: The ZMQ topic being written to. diff --git a/labgraph/__init__.py b/labgraph/__init__.py new file mode 100644 index 000000000..cc41712e2 --- /dev/null +++ b/labgraph/__init__.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "Aligner", + "AsyncPublisher", + "background", + "BaseEventGenerator", + "BaseEventGeneratorNode", + "BytesType", + "CFloatType", + "CIntType", + "Config", + "Connections", + "CPPNodeConfig", + "DeferredMessage", + "LabGraphError", + "Event", + "EventGraph", + "EventPublishingHeap", + "EventPublishingHeapEntry", + "FieldType", + "FloatType", + "Graph", + "ParallelRunner", + "Group", + "IntType", + "HDF5Logger", + "Logger", + "LoggerConfig", + "main", + "Message", + "Module", + "LocalRunner", + "Node", + "NodeTestHarness", + "NormalTermination", + "NumpyType", + "publisher", + "run", + "RunnerOptions", + "run_async", + "run_with_harness", + "State", + "StrType", + "subscriber", + "TerminationMessage", + "TimestampAligner", + "TimestampedMessage", + "Topic", + "WaitBeginMessage", + "WaitEndMessage", +] + + +from .events import ( + BaseEventGenerator, + BaseEventGeneratorNode, + DeferredMessage, + Event, + EventGraph, + EventPublishingHeap, + EventPublishingHeapEntry, + TerminationMessage, + WaitBeginMessage, + WaitEndMessage, +) +from .graphs import ( + AsyncPublisher, + Config, + Connections, + CPPNodeConfig, + Graph, + Group, + Module, + Node, + NodeTestHarness, + State, + Topic, + background, + main, + publisher, + run_async, + run_with_harness, + subscriber, +) +from .loggers import Logger, LoggerConfig +from .loggers.hdf5.logger import HDF5Logger +from .messages import ( + BytesType, + CFloatType, + CIntType, + FieldType, + FloatType, + IntType, + Message, + NumpyDynamicType, + NumpyType, + StrType, + TimestampedMessage, +) +from .runners import ( + Aligner, + LocalRunner, + NormalTermination, + ParallelRunner, + RunnerOptions, + TimestampAligner, + run, +) +from .util import LabGraphError diff --git a/labgraph/_cthulhu/__init__.py b/labgraph/_cthulhu/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/labgraph/_cthulhu/bindings.py b/labgraph/_cthulhu/bindings.py new file mode 100644 index 000000000..6c65d2dce --- /dev/null +++ b/labgraph/_cthulhu/bindings.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# This is a wrapper around cthulhubindings to randomize the name of the shared memory it +# uses. This allows us to keep shared memory for different LabGraph graphs separate +# when they are running simultaneously. + +import os + +from ..util.random import random_string + +SHM_NAME_ENV_VAR = "CTHULHU_SHM_NAME" +DEFAULT_SHM_NAME = "CthulhuSHM" + +# Update the shared memory name to a randomized one if it is the default one or unset +if ( + SHM_NAME_ENV_VAR not in os.environ + or os.environ[SHM_NAME_ENV_VAR] == DEFAULT_SHM_NAME +): + SHM_PREFIX = "LABGRAPH_SHMEM_" + SHM_SUFFIX = random_string(16) + os.environ[SHM_NAME_ENV_VAR] = f"{SHM_PREFIX}{SHM_SUFFIX}" + +import cthulhubindings # noqa: E402 + +# TODO (T88919098): For now we manually export items from the bindings to pass +# typechecking (avoiding import *). An improvement would be to generate mypy stubs from +# C++ extensions. +Aligner = cthulhubindings.Aligner +AlignerMode = cthulhubindings.AlignerMode +AnyBuffer = cthulhubindings.AnyBuffer +BufferType = cthulhubindings.BufferType +Clock = cthulhubindings.Clock +ClockAuthority = cthulhubindings.ClockAuthority +ClockEvent = cthulhubindings.ClockEvent +clockManager = cthulhubindings.clockManager +ClockManager = cthulhubindings.ClockManager +ContextInfo = cthulhubindings.ContextInfo +ControllableClock = cthulhubindings.ControllableClock +CpuBuffer = cthulhubindings.CpuBuffer +DynamicParameters = cthulhubindings.DynamicParameters +Field = cthulhubindings.Field +GpuBuffer = cthulhubindings.GpuBuffer +ImageBuffer = cthulhubindings.ImageBuffer +memoryPool = cthulhubindings.memoryPool +MemoryPool = cthulhubindings.MemoryPool +PerformanceSummary = cthulhubindings.PerformanceSummary +SampleHeader = cthulhubindings.SampleHeader +SampleMetadata = cthulhubindings.SampleMetadata +StreamConfig = cthulhubindings.StreamConfig +StreamConsumer = cthulhubindings.StreamConsumer +StreamDescription = cthulhubindings.StreamDescription +StreamInterface = cthulhubindings.StreamInterface +StreamProducer = cthulhubindings.StreamProducer +streamRegistry = cthulhubindings.streamRegistry +StreamRegistry = cthulhubindings.StreamRegistry +StreamSample = cthulhubindings.StreamSample +ThreadPolicy = cthulhubindings.ThreadPolicy +TypeDefinition = cthulhubindings.TypeDefinition +TypeInfo = cthulhubindings.TypeInfo +typeRegistry = cthulhubindings.typeRegistry +TypeRegistry = cthulhubindings.TypeRegistry diff --git a/labgraph/_cthulhu/clock.py b/labgraph/_cthulhu/clock.py new file mode 100644 index 000000000..10aeb0735 --- /dev/null +++ b/labgraph/_cthulhu/clock.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from .bindings import ( # type: ignore + Clock, + ClockAuthority, + clockManager, + ControllableClock, +) + + +class ExperimentClock: + """ + Wrapper for a Cthulhu Clock. All nodes which need to keep + track of time should create its own instance of this clock. + """ + + def __init__(self) -> None: + self.clock: Clock = clockManager().clock() + + def get_time(self) -> float: + return self.clock.getTime() # type: ignore + + +class ClockController: + """ + Wrapper for Cthulhu's ControllableClock. The state node responsible + for 'ticking' forward the clock in a simulation should be its + sole owner. + + Must either call start() or tick forward the clock manually. + """ + + CONTEXT_NAME = "clock_owner" + + def __init__(self) -> None: + ClockAuthority(True, self.CONTEXT_NAME) + self.controllable_clock: ControllableClock = clockManager().controlClock( + self.CONTEXT_NAME + ) + self.clock: ExperimentClock = ExperimentClock() + self.controllable_clock.pause() + self._is_paused: bool = True + + def _pause(self) -> None: + if not self._is_paused: + self.controllable_clock.pause() + self._is_paused = True + + def is_paused(self) -> bool: + return self._is_paused + + def start(self, start_time: float) -> None: + """ + Starts running the clock at the specified start_time. + """ + + self.controllable_clock.start(start_time) + self._is_paused = False + + def set_time(self, time: float, start_running: bool = False) -> None: + """ + Sets the current time on the clock. The optional + start_running parameters specifies if the clock should + run after this function call. + """ + + self._pause() + + if start_running: + self.start(time) + else: + self.controllable_clock.setTime(time) + + def set_realtime_factor(self, factor: float) -> None: + """ + Sets the realtime factor for the clock. The clock will + maintain whichever state it was in (running/paused) prior + to this function being called. + """ + + should_restart: bool = not self._is_paused + self._pause() + + self.controllable_clock.setRealtimeFactor(factor) + if should_restart: + curr_time: float = self.clock.get_time() + self.controllable_clock.start(curr_time) + + def tick(self, increment_by: float = 1) -> None: + """ + Ticks forward the current time on the clock, pausing the + clock if it is not paused already. + """ + + self._pause() + curr_time: float = self.clock.get_time() + self.controllable_clock.setTime(curr_time + increment_by) diff --git a/labgraph/_cthulhu/cthulhu.py b/labgraph/_cthulhu/cthulhu.py new file mode 100644 index 000000000..e2557adbd --- /dev/null +++ b/labgraph/_cthulhu/cthulhu.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from enum import Enum, auto +from types import TracebackType +from typing import Callable, Generic, Optional, Type, TypeVar + +from ..messages.message import Message +from ..util.error import LabGraphError +from .bindings import ( # type: ignore + PerformanceSummary, + StreamConsumer, + StreamDescription, + StreamInterface, + StreamProducer, + StreamSample, + streamRegistry, + typeRegistry, +) + + +T = TypeVar("T") + + +class LabGraphCallbackParams(Generic[T]): + def __init__(self, message: T, stream_id: Optional[str]) -> None: + self.message = message + self.stream_id = stream_id + + message: T + stream_id: Optional[str] + + +LabGraphCallback = Callable[..., None] +CthulhuCallback = Callable[[StreamSample], None] + + +class Mode(Enum): + SYNC = auto() + ASYNC = auto() + + +class Consumer(StreamConsumer): # type: ignore + """ + Convenience wrapper of Cthulhu's `StreamConsumer` that allows us to specify a + callback accepting LabGraph `Message`s. + + Args: + stream_interface: The stream interface to use. + sample_callback: The callback to use (uses LabGraph messages). + """ + + def __init__( + self, + stream_interface: StreamInterface, + sample_callback: LabGraphCallback, + mode: Mode = Mode.SYNC, + stream_id: Optional[str] = None, + ) -> None: + super(Consumer, self).__init__( + **{ + "si": stream_interface, + "sampleCb": self._to_cthulhu_callback(sample_callback), + "async": mode == Mode.ASYNC, + } + ) + self.stream_id = stream_id + + def _to_cthulhu_callback(self, callback: LabGraphCallback) -> CthulhuCallback: + """ + Given a LabGraph callback, creates a Cthulhu callback (accepting + `StreamSample`s). + """ + + def wrapped_callback(sample: StreamSample) -> None: + assert hasattr(callback, "__annotations__") + annotated_types = { + arg: arg_type + for arg, arg_type in callback.__annotations__.items() + if not arg == "return" + } + + message_types = [ + arg_type + for arg_type in annotated_types.values() + if issubclass(arg_type, Message) + or issubclass(arg_type, LabGraphCallbackParams) + ] + assert len(message_types) == 1 + + message_type = message_types[0] + if issubclass(message_type, Message): + message = message_type(__sample__=sample) + callback(message) + elif issubclass(message_type, LabGraphCallbackParams): + (arg_type,) = message_type.__args__ + message = arg_type(__sample__=sample) + params = LabGraphCallbackParams(message, self.stream_id) + callback(params) + else: + raise TypeError( + f"Expected callback taking type '{Message.__name__}' or '{LabGraphCallbackParams.__name__}', got '{message_type.__name__}'" + ) + + return wrapped_callback + + def __enter__(self) -> "Consumer": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + self.close() + + +class Producer(StreamProducer): # type: ignore + """ + Convenience wrapper of Cthulhu's `StreamProducer` that accepts a LabGraph message. + + Args: + stream_interface: The stream interface to use. + """ + + def __init__( + self, stream_interface: StreamInterface, mode: Mode = Mode.SYNC + ) -> None: + super(Producer, self).__init__( + **{"si": stream_interface, "async": mode == Mode.ASYNC} + ) + self.stream_interface = stream_interface + + def produce_message(self, message: Message) -> None: + """ + Produces a LabGraph message to the Cthulhu stream. + + Args: + message: The message to produce. + """ + self.produceSample(message.__sample__) + + def __enter__(self) -> "Producer": + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + self.close() + + +def register_stream(name: str, message_type: Type[Message]) -> StreamInterface: + """ + Registers a stream with a LabGraph message type to the Cthulhu stream registry. + + Args: + name: The name of the stream. + message_type: The type of the stream. + """ + cthulhu_type = typeRegistry().findTypeName(message_type.versioned_name) + assert cthulhu_type is not None + existing_stream = streamRegistry().getStream(name) + if existing_stream is not None: + type_id = existing_stream.description.type + existing_type = typeRegistry().findTypeID(type_id) + if existing_type.typeName != message_type.versioned_name: + raise LabGraphError( + f"Tried to register stream '{name}' with type " + f"'{message_type.versioned_name}', but it already exists with type " + f"'{existing_type.typeName}'" + ) + return existing_stream + return streamRegistry().registerStream(StreamDescription(name, cthulhu_type.typeID)) + + +def get_stream(name: str) -> Optional[StreamInterface]: + """ + Returns the stream with the given name. + + Args: + name: The name of the stream. + """ + return streamRegistry().getStream(name) + + +def format_performance_summary(summary: PerformanceSummary) -> str: + return ( + f"Callback runtime: {summary.min_runtime} min {summary.max_runtime} max " + f"{summary.mean_runtime} mean\n" + f"Total runtime: {summary.total_runtime}\n" + f"{summary.num_calls} calls\n" + f"{summary.num_samples_dropped} samples dropped" + ) diff --git a/labgraph/_cthulhu/tests/__init__.py b/labgraph/_cthulhu/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/_cthulhu/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/_cthulhu/tests/test_clock.py b/labgraph/_cthulhu/tests/test_clock.py new file mode 100644 index 000000000..c0acbe72a --- /dev/null +++ b/labgraph/_cthulhu/tests/test_clock.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import time + +import pytest + +from ...util.testing import local_test +from ..clock import ClockController, ExperimentClock + + +NUM_BUSY_TICKS = 100 +NUM_TICKS = 10 +CLOCK_READ_DELAY = 0.1 +ACCEPTABLE_DELTA = 0.02 +CLOCK_WAIT = 1 + + +@local_test +def test_manual_busy_tick() -> None: + """ + Tests that we can continuously tick forward the clock + without delay using the controller and have the correct time + read back by a regular experiment clock. + """ + + controllable_clock: ClockController = ClockController() + local_clock: ExperimentClock = ExperimentClock() + + controllable_clock.set_time(0.0) + for i in range(1, NUM_BUSY_TICKS + 1): + controllable_clock.tick(1) + read_time = local_clock.get_time() + assert read_time == i + + +@local_test +def test_regular_clock_time() -> None: + """ + Tests that we can query back regular system time through + the clock as default behaviour. + """ + + controllable_clock: ClockController = ClockController() + system_time = time.time() + local_clock: ExperimentClock = ExperimentClock() + + controllable_clock.start(system_time) + for _ in range(NUM_TICKS): + read_time = local_clock.get_time() + system_time = time.time() + assert system_time - read_time < ACCEPTABLE_DELTA + time.sleep(CLOCK_READ_DELAY) + + +@local_test +def test_clock_with_realtime_factor() -> None: + """ + Tests that we can successfully set and use a realtime + factor on the clock. + """ + + controllable_clock: ClockController = ClockController() + local_clock: ExperimentClock = ExperimentClock() + test_factor: float = 5.0 + + assert controllable_clock.is_paused() + controllable_clock.set_realtime_factor(test_factor) + assert controllable_clock.is_paused() # Should still be paused + + start_time = time.time() + controllable_clock.start(start_time) + + time.sleep(CLOCK_WAIT) # Wait for some time to elapse + system_time = time.time() + experiment_time = local_clock.get_time() + + system_time_diff = system_time - start_time + experiment_time_diff = experiment_time - start_time + + assert experiment_time_diff >= (system_time_diff * test_factor - ACCEPTABLE_DELTA) + assert experiment_time_diff <= (system_time_diff * test_factor + ACCEPTABLE_DELTA) diff --git a/labgraph/_cthulhu/tests/test_cthulhu.py b/labgraph/_cthulhu/tests/test_cthulhu.py new file mode 100644 index 000000000..5f8cb30d3 --- /dev/null +++ b/labgraph/_cthulhu/tests/test_cthulhu.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import time + +import pytest + +from ...messages.message import Message +from ...util.random import random_string +from ...util.testing import local_test +from ..cthulhu import Consumer, LabGraphCallbackParams, Producer, register_stream + + +RANDOM_ID_LENGTH = 128 +NUM_MESSAGES = 100 +SAMPLE_RATE = 100 + + +class MyMessage(Message): + int_field: int + + +@local_test +def test_producer_and_consumer() -> None: + """ + Tests that we can use the LabGraph wrappers around the Cthulhu APIs to publish + and subscribe to messages. + """ + stream_name = random_string(length=RANDOM_ID_LENGTH) + stream_interface = register_stream(name=stream_name, message_type=MyMessage) + + received_messages = [] + + with Producer(stream_interface=stream_interface) as producer: + + def callback(params: LabGraphCallbackParams[MyMessage]) -> None: + received_messages.append(params.message) + + with Consumer(stream_interface=stream_interface, sample_callback=callback): + + for i in range(NUM_MESSAGES): + producer.produce_message(MyMessage(int_field=i)) + time.sleep(1 / SAMPLE_RATE) + + assert len(received_messages) == NUM_MESSAGES + + for i in range(NUM_MESSAGES): + assert received_messages[i].int_field == i + + +@local_test +def test_complex_graph() -> None: + """ + Tests that we can use the LabGraph wrappers around the Cthulhu APIs to stream + messages in a more complex graph. + """ + stream_name1 = random_string(length=RANDOM_ID_LENGTH) + stream_name2 = random_string(length=RANDOM_ID_LENGTH) + stream1 = register_stream(name=stream_name1, message_type=MyMessage) + stream2 = register_stream(name=stream_name2, message_type=MyMessage) + + received_messages = [] + + with Producer(stream_interface=stream1) as producer1: + + with Producer(stream_interface=stream2) as producer2: + + def transform_callback(params: LabGraphCallbackParams[MyMessage]) -> None: + producer2.produce_message( + MyMessage(int_field=params.message.int_field * 2) + ) + + with Consumer(stream_interface=stream1, sample_callback=transform_callback): + + def sink_callback(params: LabGraphCallbackParams[MyMessage]) -> None: + received_messages.append(params.message) + + with Consumer(stream_interface=stream2, sample_callback=sink_callback): + for i in range(NUM_MESSAGES): + producer1.produce_message(MyMessage(int_field=i)) + time.sleep(1 / SAMPLE_RATE) + + assert len(received_messages) == NUM_MESSAGES + + for i in range(NUM_MESSAGES): + assert received_messages[i].int_field == i * 2 diff --git a/labgraph/cpp/Node.cpp b/labgraph/cpp/Node.cpp new file mode 100644 index 000000000..119ffcb08 --- /dev/null +++ b/labgraph/cpp/Node.cpp @@ -0,0 +1,113 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace labgraph { + +Node::Node() : context_("") {} + +void Node::run() { + pybind11::gil_scoped_release release; + std::vector threads; + auto publishers = getPublishers(); + for (const auto& publisherInfo : publishers) { + threads.push_back(std::thread(publisherInfo.publisher)); + } + for (auto& thread : threads) { + thread.join(); + } +} + +void Node::bootstrap(NodeBootstrapInfo& bootstrapInfo) { + for (const auto& topic : bootstrapInfo.topics) { + bootstrapStream(topic.topicName, topic.streamID); + } +} + +void Node::bootstrapStream(const std::string& topic, const cthulhu::StreamID& streamID) { + auto topics = getTopics(); + if (std::find(topics.begin(), topics.end(), topic) == topics.end()) { + throw std::runtime_error("C++ node bootstrapped with invalid topic '" + topic + "'"); + } + if (streamIDsByTopic_.count(topic) != 0) { + throw std::runtime_error("C++ node bootstrapped topic '" + topic + "' multiple times"); + } + streamIDsByTopic_[topic] = streamID; + + auto labgraphPublishers = getPublishers(); + auto labgraphSubscribers = getSubscribers(); + auto labgraphTransformers = getTransformers(); + + cthulhu::StreamInterface* si = + cthulhu::Framework::instance().streamRegistry()->getStream(streamID); + if (!si) { + throw std::runtime_error( + "C++ node bootstrapped topic '" + topic + "' with invalid stream ID '" + streamID + "'"); + } + cthulhu::StreamDescription desc = si->description(); + + for (const auto& publisher : labgraphPublishers) { + auto topicsBegin = publisher.publishedTopics.begin(); + auto topicsEnd = publisher.publishedTopics.end(); + if (std::find(topicsBegin, topicsEnd, topic) != topicsEnd) { + auto cthulhuType = cthulhu::Framework::instance().typeRegistry()->findTypeID(desc.type()); + cthulhuPublishersByTopic_[topic] = + cthulhu::ptrWrap(context_.advertise(desc.id(), desc.type())); + break; + } + } + + for (const auto& subscriber : labgraphSubscribers) { + if (subscriber.subscribedTopic == topic) { + cthulhuSubscribersByTopic_.insert( + {topic, + cthulhu::ptrWrap(context_.subscribeGeneric( + desc.id(), subscriber.subscriber, nullptr, {cthulhu::ConsumerType::ASYNC}))}); + break; + } + } + + for (const auto& transformer : labgraphTransformers) { + auto topicsBegin = transformer.publishedTopics.begin(); + auto topicsEnd = transformer.publishedTopics.end(); + if (std::find(topicsBegin, topicsEnd, topic) != topicsEnd && + cthulhuPublishersByTopic_.count(topic) == 0) { + cthulhuPublishersByTopic_[topic] = + cthulhu::ptrWrap(context_.advertise(desc.id(), desc.type())); + } + if (transformer.subscribedTopic == topic && cthulhuSubscribersByTopic_.count(topic) == 0) { + cthulhuSubscribersByTopic_.insert( + {topic, + cthulhu::ptrWrap(context_.subscribeGeneric( + desc.id(), transformer.transformer, nullptr, {cthulhu::ConsumerType::ASYNC}))}); + } + } +} + +std::vector Node::getPublishers() { + return {}; +} + +std::vector Node::getSubscribers() { + return {}; +} + +std::vector Node::getTransformers() { + return {}; +} + +void Node::setup() {} +void Node::cleanup() {} + +Node::~Node() {} + +} // namespace labgraph diff --git a/labgraph/cpp/__init__.py b/labgraph/cpp/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/cpp/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/cpp/bindings.cpp b/labgraph/cpp/bindings.cpp new file mode 100644 index 000000000..a7294df31 --- /dev/null +++ b/labgraph/cpp/bindings.cpp @@ -0,0 +1,48 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include +#include + +#include + +namespace py = pybind11; + +namespace labgraph { + +void bindings(py::module_& m) { + m.doc() = "LabGraph C++: C++ nodes for LabGraph"; + + py::class_(m, "Node") + .def("setup", &Node::setup) + .def("cleanup", &Node::cleanup) + .def("run", &Node::run) + .def("_bootstrap", &Node::bootstrap) + .def_property_readonly("topics", &Node::getTopics); + + py::class_(m, "NodeTopic") + .def(py::init(), py::arg("topic_name"), py::arg("stream_id")) + .def_readonly("topic_name", &NodeTopic::topicName) + .def_readonly("stream_id", &NodeTopic::streamID); + + py::class_(m, "NodeBootstrapInfo") + .def(py::init>(), py::arg("topics")) + .def_readonly("topics", &NodeBootstrapInfo::topics); +} + +} // namespace labgraph + +PYBIND11_MODULE(labgraph_cpp, m) { + labgraph::bindings(m); + + py::cpp_function cleanup_callback([](py::handle weakref) { + cthulhu::Framework::instance().cleanup(); + weakref.dec_ref(); + }); + + // Call cleanup with a weakref to a sentinel object on the bindings via a callback. + // This ensures cleanup happens early enough for the Vulkan API to still be loaded. + m.def("_sentinel", []() -> void {}); + (void)py::weakref(m.attr("_sentinel"), cleanup_callback).release(); +} diff --git a/labgraph/cpp/include/labgraph/Node.h b/labgraph/cpp/include/labgraph/Node.h new file mode 100644 index 000000000..3bec829df --- /dev/null +++ b/labgraph/cpp/include/labgraph/Node.h @@ -0,0 +1,123 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +namespace labgraph { + +/** + * struct NodeTopic + * + * Describes a mapping between a LabGraph topic and a Cthulhu stream. + */ +struct NodeTopic { + std::string topicName; + cthulhu::StreamID streamID; +}; + +/** + * struct NodeBootstrapInfo + * + * Contains all information needed to bootstrap a LabGraph C++ node into a state ready + * for execution in an existing LabGraph graph. + */ +struct NodeBootstrapInfo { + std::vector topics; // Mapping of LabGraph topics to Cthulhu streams +}; + +typedef std::function Publisher; +typedef std::function Subscriber; + +/** + * struct PublisherInfo + * + * Describes a publisher (its published topics and its main function). + */ +struct PublisherInfo { + std::vector publishedTopics; + Publisher publisher; +}; + +/** + * struct SubscriberInfo + * + * Describes a subscriber (its subscribed topic and its callback function). + */ +struct SubscriberInfo { + SubscriberInfo(const std::string topic, Subscriber sub) + : subscribedTopic(topic), subscriber(sub) {} + std::string subscribedTopic; + Subscriber subscriber; +}; + +/** + * struct TransformerInfo + * + * Describes a transformer (its published topics, subscribed topic and its callback + * function). + */ +struct TransformerInfo { + std::vector publishedTopics; + std::string subscribedTopic; + Subscriber transformer; +}; + +/** + * class Node + * + * Describes a C++ node in a LabGraph graph. + */ +class Node { + public: + Node(); + virtual ~Node(); + + /*** Setup function that is run when the LabGraph graph is starting up. */ + virtual void setup(); + + /** + * Entry point that is run in the LabGraph graph to start all the node's publishers. + */ + void run(); + + /*** Cleanup function that is run when the LabGraph graph is shutting down. */ + virtual void cleanup(); + + /** + * Bootstrapping function that is run by the LabGraph graph to connect this node's + * topics with their corresponding Cthulhu streams. + */ + void bootstrap(NodeBootstrapInfo& bootstrapInfo); + + virtual std::vector getTopics() const = 0; + virtual std::vector getPublishers(); + virtual std::vector getSubscribers(); + virtual std::vector getTransformers(); + + protected: + /** + * Publishes a Cthulhu sample to a topic. + * + * @param topic The labgraph topic to publish to + * @param sample The Cthulhu sample to publish + */ + template + void publish(const std::string& topic, const T& sample); + + protected: + cthulhu::Context context_; + + std::map cthulhuPublishersByTopic_; + std::multimap cthulhuSubscribersByTopic_; + + std::map streamIDsByTopic_; + + private: + void bootstrapStream(const std::string& topic, const std::string& streamID); +}; + +}; // namespace labgraph + +#include diff --git a/labgraph/cpp/include/labgraph/NodeImpl.h b/labgraph/cpp/include/labgraph/NodeImpl.h new file mode 100644 index 000000000..2795f077e --- /dev/null +++ b/labgraph/cpp/include/labgraph/NodeImpl.h @@ -0,0 +1,23 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace labgraph { + +template +void Node::publish(const std::string& topic, const T& sample) { + auto topics = getTopics(); + if (std::find(topics.begin(), topics.end(), topic) == topics.end()) { + throw std::runtime_error("C++ node published to invalid topic '" + topic + "'"); + } + if (cthulhuPublishersByTopic_.count(topic) == 0) { + throw std::runtime_error( + "C++ node tried to publish to topic '" + topic + "' with no bootstrapped Cthulhu stream"); + } + + cthulhuPublishersByTopic_[topic]->publish(sample); +} + +} // namespace labgraph diff --git a/labgraph/cpp/include/labgraph/bindings.h b/labgraph/cpp/include/labgraph/bindings.h new file mode 100644 index 000000000..5b9ab1332 --- /dev/null +++ b/labgraph/cpp/include/labgraph/bindings.h @@ -0,0 +1,23 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include +#include + +namespace labgraph { +void bindings(pybind11::module&); + +template +pybind11::class_ bindNode( + pybind11::module& m, + const std::string& pythonName, + const std::vector& topicNames) { + auto result = pybind11::class_(m, pythonName.c_str()); + result = result.def_property_readonly_static( + "topic_names", [topicNames](pybind11::object /* self */) { return topicNames; }); + return result; +} + +} // namespace labgraph diff --git a/labgraph/cpp/tests/MyCPPSink.cpp b/labgraph/cpp/tests/MyCPPSink.cpp new file mode 100644 index 000000000..11042143f --- /dev/null +++ b/labgraph/cpp/tests/MyCPPSink.cpp @@ -0,0 +1,29 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include + +#include "MyCPPSink.h" +#include "TestSample.h" + +MyCPPSink::MyCPPSink(const std::string& filename) { + outputFile_.open(filename); +} + +std::vector MyCPPSink::getTopics() const { + return {"B"}; +} + +std::vector MyCPPSink::getSubscribers() { + return {{"B", [this](const cthulhu::StreamSample& sample) { mainSubscriber(sample); }}}; +} + +void MyCPPSink::mainSubscriber(const cthulhu::StreamSample& sample) { + // Subscriber that writes messages to disk + TestSample testSample; + testSample.setSample(sample); + outputFile_ << testSample.value << std::endl; +} + +MyCPPSink::~MyCPPSink() { + outputFile_.close(); +} diff --git a/labgraph/cpp/tests/MyCPPSink.h b/labgraph/cpp/tests/MyCPPSink.h new file mode 100644 index 000000000..78a5760a7 --- /dev/null +++ b/labgraph/cpp/tests/MyCPPSink.h @@ -0,0 +1,21 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include +#include + +class MyCPPSink : public labgraph::Node { + public: + MyCPPSink(const std::string& filename); + ~MyCPPSink(); + std::vector getTopics() const; + std::vector getSubscribers(); + void mainSubscriber(const cthulhu::StreamSample& sample); + + private: + std::ofstream outputFile_; +}; diff --git a/labgraph/cpp/tests/MyCPPSource.cpp b/labgraph/cpp/tests/MyCPPSource.cpp new file mode 100644 index 000000000..de5ed27f7 --- /dev/null +++ b/labgraph/cpp/tests/MyCPPSource.cpp @@ -0,0 +1,29 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +#include "MyCPPSource.h" +#include "TestSample.h" + +CTHULHU_REGISTER_BASIC_STREAM_TYPE(Test, TestSample); + +std::vector MyCPPSource::getTopics() const { + return {"A"}; +} + +std::vector MyCPPSource::getPublishers() { + return {{{"A"}, [this]() { mainPublisher(); }}}; +} + +void MyCPPSource::mainPublisher() { + // Publisher that sends 10 messages with a single int in each one + std::this_thread::sleep_for(std::chrono::seconds(1)); + const double publish_sleep = 1.0 / kPublishRate; + for (uint32_t i = 0; i < kNumSamples; i++) { + TestSample sample; + sample.value = i; + publish("A", sample); + std::this_thread::sleep_for(std::chrono::duration(publish_sleep)); + } +} diff --git a/labgraph/cpp/tests/MyCPPSource.h b/labgraph/cpp/tests/MyCPPSource.h new file mode 100644 index 000000000..eacb3da17 --- /dev/null +++ b/labgraph/cpp/tests/MyCPPSource.h @@ -0,0 +1,15 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +class MyCPPSource : public labgraph::Node { + public: + std::vector getTopics() const; + std::vector getPublishers(); + void mainPublisher(); + + static constexpr int const& kNumSamples = 10; + static constexpr double const& kPublishRate = 5.0; +}; diff --git a/labgraph/cpp/tests/TestSample.h b/labgraph/cpp/tests/TestSample.h new file mode 100644 index 000000000..7d3f69e03 --- /dev/null +++ b/labgraph/cpp/tests/TestSample.h @@ -0,0 +1,16 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +struct TestSample : public cthulhu::AutoStreamSample { + using T = TestSample; + + cthulhu::FieldsBegin begin; + cthulhu::SampleField value{"value", this}; + cthulhu::FieldsEnd end; + + CTHULHU_AUTOSTREAM_SAMPLE(TestSample); +}; diff --git a/labgraph/cpp/tests/bindings.cpp b/labgraph/cpp/tests/bindings.cpp new file mode 100644 index 000000000..662260338 --- /dev/null +++ b/labgraph/cpp/tests/bindings.cpp @@ -0,0 +1,21 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include +#include "MyCPPSink.h" +#include "MyCPPSource.h" + +namespace py = pybind11; + +PYBIND11_MODULE(MyCPPNodes, m) { + m.doc() = "LabGraph C++: MyCPPNodes unit test"; + + std::vector sourceTopics = {"A"}; + labgraph::bindNode(m, "MyCPPSource", sourceTopics) + .def(py::init()) + .def_readonly_static("NUM_SAMPLES", &MyCPPSource::kNumSamples); + + std::vector sinkTopics = {"B"}; + labgraph::bindNode(m, "MyCPPSink", sinkTopics) + .def(py::init(), py::arg("filename")); +} diff --git a/labgraph/events/__init__.py b/labgraph/events/__init__.py new file mode 100644 index 000000000..b1a9fc221 --- /dev/null +++ b/labgraph/events/__init__.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "BaseEventGenerator", + "DeferredMessage", + "Event", + "EventGraph", + "BaseEventGeneratorNode", + "EventPublishingHeap", + "EventPublishingHeapEntry", + "WaitBeginMessage", + "WaitEndMessage", + "TerminationMessage", +] + +from .event_generator import ( + BaseEventGenerator, + DeferredMessage, + Event, + EventGraph, + EventPublishingHeap, + EventPublishingHeapEntry, +) +from .event_generator_node import BaseEventGeneratorNode +from .event_messages import WaitBeginMessage, WaitEndMessage, TerminationMessage diff --git a/labgraph/events/event_generator.py b/labgraph/events/event_generator.py new file mode 100644 index 000000000..9cd5ba7a1 --- /dev/null +++ b/labgraph/events/event_generator.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import time +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Any, Dict, Optional, Tuple, Type + +from ..graphs.topic import Topic +from ..messages.message import Message, TimestampedMessage +from ..util.error import LabGraphError +from ..util.min_heap import MinHeap + + +class DeferredMessage: + """ + Certain members of a Message might be dependent on when the message + is generated - Example: `timestamp`. + Since `Message` is immutable, we pass `DeferredMessage` to an event, + and the actual message is constructed on access. + """ + + def __init__(self, message_type: Type[Message], *args: Any, **kwargs: Any) -> None: + self._message_type = message_type + self._args = args + self._kwargs = kwargs + self._message: Optional[Message] = None + + def build_message(self) -> Message: + if not self._message: + if issubclass(self._message_type, TimestampedMessage): + # TimestampedMessage has timestamp as the first field/argument + # - Add timestamp at the front of args to satisfy this + self._args = (time.time(),) + self._args + self._message = self._message_type(*self._args, **self._kwargs) + del self._args + del self._kwargs + return self._message + + +@dataclass +class Event: + """ + Dataclass representing an event generated by an event generator, + where `message` should be published to `topic` at `delay` seconds + after its predecessor. + + Args: + _message: The DeferredMessage which should be published for this event. + The underlying message is built when the property is accessed. + topic: The topic this event's message should be published on. + delay: The delay between the start of this event and the end of + the previous event. + duration: The amount of time this event will last for. + """ + + _message: DeferredMessage + topic: Topic + delay: float + duration: float = 0.0 + + def __post_init__(self) -> None: + if self.duration < 0.0: + raise LabGraphError("event cannot have a negative duration.") + + def __hash__(self) -> int: # Needed for usage as dictionary key + return hash(id(self)) + + @property + def message(self) -> Message: + return self._message.build_message() + + +EventPublishingHeapEntry = Tuple[float, int, Event] +""" +An entry of an EventGeneratorNode's publishing heap. Each entry is composed +as (timestamp, id, event). +""" + +EventPublishingHeap = MinHeap[EventPublishingHeapEntry] +""" +The heap used by an EventGeneratorNode to determine the order that its events +should be published in. +""" + + +class EventGraph: + """ + Helper class wrapping functionality for joining events. + + Args: + last_event_added: The most recently added event to the event heap. + heap: The underlying MinHeap used to store events. + _accumulated_times: Accumulated times for events inserted so far. + """ + + last_event_added: Event + heap: EventPublishingHeap + _accumulated_times: Dict[Event, float] + + def __init__(self, start_event: Event) -> None: + self.heap = EventPublishingHeap() + self._accumulated_times = {} + self._add_start_event(start_event) + + def add_event_at_start(self, event: Event, previous_event: Event) -> None: + """ + Adds `event` to the heap based on accumulated time of `previous_event`, where + `event` occurs at the beginning of the latter event. + """ + + accumulated_time = self._get_accumulated_time(event, previous_event, False) + self._push_heap_entry(event, accumulated_time) + + def add_event_at_end(self, event: Event, previous_event: Event) -> None: + """ + Adds `event` to the heap based on accumulated time of `previous_event`, where + `event` occurs after the duration specified for the latter. + """ + + accumulated_time = self._get_accumulated_time(event, previous_event, True) + self._push_heap_entry(event, accumulated_time) + + def _add_start_event(self, event: Event) -> None: + """ + Adds `event` to the heap as the first event of the graph. + """ + if event.delay != 0.0: + raise LabGraphError("start_event cannot have a non-zero delay.") + self._push_heap_entry(event, 0.0) + + def _get_accumulated_time( + self, event: Event, previous_event: Event, add_duration: bool + ) -> float: + accumulated_time = self._accumulated_times.get(previous_event) + if accumulated_time is None: + raise LabGraphError("previous_event has not been inserted yet.") + if add_duration: + accumulated_time += previous_event.duration + accumulated_time += event.delay + if accumulated_time < 0.0: + raise LabGraphError("event occurs before start time.") + return accumulated_time + + def _push_heap_entry(self, event: Event, accumulated_time: float) -> None: + self._accumulated_times[event] = accumulated_time + heap_entry: EventPublishingHeapEntry = ( + accumulated_time, + # Use insert order for selection when same delay + self.heap.count, + event, + ) + self.heap.push(heap_entry) + self.last_event_added = event + + +class BaseEventGenerator(ABC): + """ + The base event generator which should act as a parent class for future + generators. The generate_events function should be overwritten to create + and return the event heap. + """ + + def __init__(self) -> None: + self._next_publish_time: float = 0.0 + + @abstractmethod + def generate_events(self) -> EventPublishingHeap: + """ + Generates a graph of events and returns the first event in the graph. + """ + + raise NotImplementedError() + + @abstractmethod + def set_topics(self) -> None: + """ + Derived classes should set its topics as instance + attributes for access in this method. + """ + + raise NotImplementedError() diff --git a/labgraph/events/event_generator_node.py b/labgraph/events/event_generator_node.py new file mode 100644 index 000000000..fb7ea75d4 --- /dev/null +++ b/labgraph/events/event_generator_node.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import abstractmethod +from time import time # TODO: Replace with LabGraph clock +from typing import Any, Dict, List, Tuple + +from ..graphs.method import AsyncPublisher, get_method_metadata +from ..graphs.node import Node, NodeMeta +from ..graphs.topic import Topic +from .event_generator import BaseEventGenerator, EventPublishingHeap +from .event_messages import WaitEndMessage + + +CHECK_FOR_WAIT_COMPLETION_DELAY = 0.1 +ACCEPTABLE_PUBLISH_TIME_DIFF = 0.01 + + +class BaseEventGeneratorNodeMeta(NodeMeta): + """ + Metaclass for EventGeneratorNodes. This metaclass is responsible + for dynamically populating the `publish_events` function on the + derived event generator with @publisher decorators for all topics + defined on the class. + """ + + _PUBLISH_FUNCTION_KEY = "publish_events" + + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any] + ) -> None: + # Pre-process topics before NodeMeta + topics: List[Topic] = [] + for field_value in fields.values(): + if isinstance(field_value, Topic): + # Only subscribe to wait end topic + if field_value.message_type is not WaitEndMessage: + topics.append(field_value) + + publishing_func = fields[cls._PUBLISH_FUNCTION_KEY] + if len(topics) > 0: + metadata = get_method_metadata(publishing_func) + metadata.published_topics = topics + + super(BaseEventGeneratorNodeMeta, cls).__init__(name, bases, fields) + + +class BaseEventGeneratorNode(Node, metaclass=BaseEventGeneratorNodeMeta): + """ + An abstract base class for an EventGeneratorNode, which publishes + messages from its event generator based on times specified for + each message. + """ + + def __init__(self) -> None: + super(BaseEventGeneratorNode, self).__init__() + self._start_time: float = time() + + def _time_elapsed_since_start(self) -> float: + return time() - self._start_time + + def setup_generator(self, generator: BaseEventGenerator) -> None: + """ + Saves a generator to the node. Should be overridden to + perform any necessary setup for the generator. + """ + + self._generator = generator + + def generate_events(self) -> EventPublishingHeap: + """ + Returns the heap of events generated by the generator associated + with this node. + """ + + return self._generator.generate_events() + + @abstractmethod + async def publish_events(self) -> AsyncPublisher: + """ + Publishes the events returned from `generate_events` based on the time + specified for each event in the graph. + """ + + raise NotImplementedError() diff --git a/labgraph/events/event_messages.py b/labgraph/events/event_messages.py new file mode 100644 index 000000000..8cd0f5d70 --- /dev/null +++ b/labgraph/events/event_messages.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from ..messages import TimestampedMessage + + +class WaitBeginMessage(TimestampedMessage): + """ + Message sent by an EventGeneratorNode to signal the start of + an expected wait on its recipient. + + Args: + timeout: The maximum amount of time the wait may last. + """ + + timeout: float + + +class WaitEndMessage(TimestampedMessage): + """ + Message sent back to an EventGeneratorNode to indicate that + the sender has finished waiting. + + Args: + wait_length: The actual length of the wait, in seconds. + """ + + wait_length: float + + +class TerminationMessage(TimestampedMessage): + """ + Message sent by an EventGeneratorNode to signal the end of the + experiment. Publisher nodes waiting indefinitely to send out + wait-end messages should stop publishing once received. + """ + + pass diff --git a/labgraph/events/tests/__init__.py b/labgraph/events/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/events/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/events/tests/test_event_generator.py b/labgraph/events/tests/test_event_generator.py new file mode 100644 index 000000000..4a4bfa3d9 --- /dev/null +++ b/labgraph/events/tests/test_event_generator.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Any + +import pytest + +from ...graphs import Topic +from ...messages import Message, TimestampedMessage +from ...util.error import LabGraphError +from .. import ( + BaseEventGenerator, + DeferredMessage, + Event, + EventGraph, + EventPublishingHeap, +) + + +pytest_plugins = ["pytest_mock"] + + +class MyMessage(Message): + args_field: str + kwargs_field: str + + +class MyTimestampedMessage(TimestampedMessage): + args_field: str + kwargs_field: str + + +class MyBaseEventGenerator(BaseEventGenerator): + def generate_events(self) -> EventPublishingHeap: + return super().generate_events() + + def set_topics(self) -> None: + super().set_topics() + + +def test_deferred_message_init(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + assert message._message_type == MyMessage + assert message._args == ("unittest_args",) + assert message._kwargs == {"kwargs_field": "unittest_kwargs"} + assert message._message is None + + +def test_deferred_message_build_regular(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + built = message.build_message() + assert not hasattr(message, "_args") + assert not hasattr(message, "_kwargs") + assert isinstance(built, MyMessage) + expected = MyMessage("unittest_args", kwargs_field="unittest_kwargs") + assert built == expected + + +def test_deferred_message_build_timestamped(mocker: Any) -> None: + mock_time = mocker.patch("labgraph.events.event_generator.time") + mock_time.time.return_value = 0.0 + message = DeferredMessage( + MyTimestampedMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + built = message.build_message() + assert not hasattr(message, "_args") + assert not hasattr(message, "_kwargs") + assert isinstance(built, MyTimestampedMessage) + expected = MyTimestampedMessage( + 0.0, "unittest_args", kwargs_field="unittest_kwargs" + ) + assert built == expected + + +def test_event_init(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + event = Event(message, topic, 0.0) + assert event._message == message + assert event.topic == topic + assert event.delay == 0.0 + assert event.duration == 0.0 + + +def test_event_init_negative_duration(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + with pytest.raises(LabGraphError): + _ = Event(message, topic, 0.0, -1.0) + + +def test_event_build_message(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + event = Event(message, topic, 0.0) + expected = MyMessage("unittest_args", kwargs_field="unittest_kwargs") + assert event.message == expected + + +def test_event_graph_init(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + event = Event(message, topic, 0.0) + graph = EventGraph(event) + assert len(graph.heap) == 1 + assert graph.last_event_added == event + + +def test_event_graph_init_bad_start_event(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + event = Event(message, topic, -1.0) + with pytest.raises(LabGraphError): + _ = EventGraph(event) + + +def test_event_graph_accumulated_time(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + start = Event(message, topic, 0.0, 1.0) + graph = EventGraph(start) + parent = Event(message, topic, 0.0, 1.0) + child_1 = Event(message, topic, -0.5, 1.0) + child_2 = Event(message, topic, -0.5, 1.0) + graph.add_event_at_end(parent, start) + graph.add_event_at_start(child_1, parent) + graph.add_event_at_start(child_2, parent) + entries = [] + while graph.heap: + entries.append(graph.heap.pop()) + expected = [(0.0, 0, start), (0.5, 2, child_1), (0.5, 3, child_2), (1.0, 1, parent)] + assert entries == expected + + +def test_event_graph_accumulated_time_no_previous(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + start = Event(message, topic, 0.0, 1.0) + graph = EventGraph(start) + parent = Event(message, topic, 0.0, 1.0) + child = Event(message, topic, 0.0, 1.0) + with pytest.raises(LabGraphError): + graph.add_event_at_end(child, parent) + + +def test_event_graph_accumulated_time_before_start(mocker: Any) -> None: + message = DeferredMessage( + MyMessage, "unittest_args", kwargs_field="unittest_kwargs" + ) + topic = Topic(MyMessage) + start = Event(message, topic, 0.0, 1.0) + graph = EventGraph(start) + parent = Event(message, topic, 0.0, 1.0) + child = Event(message, topic, -3.0, 1.0) + graph.add_event_at_end(parent, start) + with pytest.raises(LabGraphError): + graph.add_event_at_end(child, parent) + + +def test_base_event_generator_abc(mocker: Any) -> None: + generator = MyBaseEventGenerator() + with pytest.raises(NotImplementedError): + _ = generator.generate_events() + with pytest.raises(NotImplementedError): + generator.set_topics() diff --git a/labgraph/events/tests/test_event_generator_node.py b/labgraph/events/tests/test_event_generator_node.py new file mode 100644 index 000000000..5b4488738 --- /dev/null +++ b/labgraph/events/tests/test_event_generator_node.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +from typing import Any + +import pytest + +from ...graphs import AsyncPublisher, Topic +from ...graphs.method import get_method_metadata +from ...messages import Message +from .. import BaseEventGenerator, BaseEventGeneratorNode, EventPublishingHeap + + +pytest_plugins = ["pytest_mock"] + + +class MyMessage(Message): + my_field: str + + +class MyBaseEventGenerator(BaseEventGenerator): + def __init__(self) -> None: + self.heap = EventPublishingHeap() + + def generate_events(self) -> EventPublishingHeap: + return self.heap + + def set_topics(self) -> None: + pass + + +class MyBaseEventGeneratorNode(BaseEventGeneratorNode): + + MY_TOPIC = Topic(MyMessage) + + async def publish_events(self) -> AsyncPublisher: + return await super().publish_events() + + +@pytest.fixture +def event_loop(): # type: ignore + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + yield loop + loop.close() + + +def test_base_event_generator_node_meta(mocker: Any) -> None: + node = MyBaseEventGeneratorNode() + publisher_metadata = get_method_metadata(node.publish_events) + topic = publisher_metadata.published_topics[0] + assert topic.name == node.MY_TOPIC.name + assert topic.message_type == node.MY_TOPIC.message_type + + +def test_base_event_generator_node_init(mocker: Any) -> None: + mock_time = mocker.patch( + "labgraph.events.event_generator_node.time" + ) + mock_time.return_value = 0.0 + node = MyBaseEventGeneratorNode() + assert node._start_time == 0.0 + + +def test_base_event_generator_node_elapsed(mocker: Any) -> None: + mock_time = mocker.patch( + "labgraph.events.event_generator_node.time" + ) + mock_time.side_effect = [0.0, 1.0] + node = MyBaseEventGeneratorNode() + assert node._time_elapsed_since_start() == 1.0 + + +def test_base_event_generator_node_generator(mocker: Any) -> None: + generator = MyBaseEventGenerator() + node = MyBaseEventGeneratorNode() + node.setup_generator(generator) + assert node._generator == generator + assert node.generate_events() == generator.heap + + +def test_base_event_generator_node_publish(event_loop: Any, mocker: Any) -> None: + node = MyBaseEventGeneratorNode() + with pytest.raises(NotImplementedError): + _ = event_loop.run_until_complete(node.publish_events()) diff --git a/labgraph/examples/__init__.py b/labgraph/examples/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/examples/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/examples/simple_viz.py b/labgraph/examples/simple_viz.py new file mode 100644 index 000000000..231fb8962 --- /dev/null +++ b/labgraph/examples/simple_viz.py @@ -0,0 +1,218 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# Built-in imports +import asyncio +import time +from dataclasses import field +from typing import Any, List, Optional, Tuple + +# Import labgraph +import labgraph as lg + +# Imports required for this example +import matplotlib.animation as animation +import matplotlib.axes +import matplotlib.pyplot as plt +import numpy as np + + +# Constants used by nodes +SAMPLE_RATE = 10.0 +NUM_FEATURES = 100 +WINDOW = 2.0 +REFRESH_RATE = 2.0 + + +# A data type used in streaming, see docs: Messages +class RandomMessage(lg.Message): + timestamp: float + data: np.ndarray + + +# ================================= NOISE GENERATOR ==================================== + + +# Configuration for NoiseGenerator, see docs: Lifecycles and Configuration +class NoiseGeneratorConfig(lg.Config): + sample_rate: float # Rate at which to generate noise + num_features: int # Number of features to generate + + +# A data source node that generates random noise to a single output topic +class NoiseGenerator(lg.Node): + OUTPUT = lg.Topic(RandomMessage) + config: NoiseGeneratorConfig + + # A publisher method that produces data on a single topic + @lg.publisher(OUTPUT) + async def generate_noise(self) -> lg.AsyncPublisher: + while True: + yield self.OUTPUT, RandomMessage( + timestamp=time.time(), data=np.random.rand(self.config.num_features) + ) + await asyncio.sleep(1 / self.config.sample_rate) + + +# ================================= ROLLING AVERAGER =================================== + +# The state of the RollingAverager node: holds windowed messages +class RollingState(lg.State): + messages: List[RandomMessage] = field(default_factory=list) + + +# Configuration for RollingAverager +class RollingConfig(lg.Config): + window: float # Window, in seconds, to average over + + +# A transformer node that accepts some data on an input topic and averages that data +# over the configured window to its output topic +class RollingAverager(lg.Node): + INPUT = lg.Topic(RandomMessage) + OUTPUT = lg.Topic(RandomMessage) + + state: RollingState + config: RollingConfig + + # A transformer method that transforms data from one topic into another + @lg.subscriber(INPUT) + @lg.publisher(OUTPUT) + async def average(self, message: RandomMessage) -> lg.AsyncPublisher: + current_time = time.time() + self.state.messages.append(message) + self.state.messages = [ + message + for message in self.state.messages + if message.timestamp >= current_time - self.config.window + ] + if len(self.state.messages) == 0: + return + all_data = np.stack([message.data for message in self.state.messages]) + mean_data = np.mean(all_data, axis=0) + yield self.OUTPUT, RandomMessage(timestamp=current_time, data=mean_data) + + +# ================================== AVERAGED NOISE ==================================== + + +# Configuration for AveragedNoise +class AveragedNoiseConfig(lg.Config): + sample_rate: float # Rate at which to generate noise + num_features: int # Number of features to generate + window: float # Window, in seconds, to average over + + +# A group that combines noise generation and rolling averaging. The output topic +# contains averaged noise. We could just put all three nodes in a graph below, but we +# add this group to demonstrate the grouping functionality. +class AveragedNoise(lg.Group): + OUTPUT = lg.Topic(RandomMessage) + + config: AveragedNoiseConfig + GENERATOR: NoiseGenerator + ROLLING_AVERAGER: RollingAverager + + def connections(self) -> lg.Connections: + # To produce averaged noise, we connect the noise generator to the averager + # Then we "expose" the averager's output as an output of this group + return ( + (self.GENERATOR.OUTPUT, self.ROLLING_AVERAGER.INPUT), + (self.ROLLING_AVERAGER.OUTPUT, self.OUTPUT), + ) + + def setup(self) -> None: + # Cascade this group's configuration to its contained nodes + self.GENERATOR.configure( + NoiseGeneratorConfig( + sample_rate=self.config.sample_rate, + num_features=self.config.num_features, + ) + ) + self.ROLLING_AVERAGER.configure(RollingConfig(window=self.config.window)) + + +# ======================================= PLOT ========================================= + + +# The state of the Plot: holds the most recent data received, which should be displayed +class PlotState(lg.State): + data: Optional[np.ndarray] = None + + +# The configuration for the Plot +class PlotConfig(lg.Config): + refresh_rate: float # How frequently to refresh the bar graph + num_bars: int # The number of bars to display (note this should be == num_features) + + +# A node that creates a matplotlib bar graph that displays the produced data in +# real-time +class Plot(lg.Node): + INPUT = lg.Topic(RandomMessage) + state: PlotState + config: PlotConfig + + def setup(self) -> None: + self.ax: Optional[matplotlib.axes.Axes] = None + + # A subscriber method that simply receives data and updates the node's state + @lg.subscriber(INPUT) + def got_message(self, message: RandomMessage) -> None: + self.state.data = message.data + + # A main method does not interact with topics, but has its own line of execution - + # this can be useful for Python libraries that must be run in the main thread. For + # example, scikit-learn and pyqtgraph are libraries that need the main thread. + @lg.main + def run_plot(self) -> None: + fig = plt.figure() + self.ax = fig.add_subplot(1, 1, 1) + self.ax.set_ylim((0, 1)) + anim = animation.FuncAnimation( # noqa: F841 + fig, self._animate, interval=1 / self.config.refresh_rate * 1000 + ) + plt.show() + raise lg.NormalTermination() + + def _animate(self, i: int) -> None: + if self.ax is None: + return + self.ax.clear() + self.ax.set_ylim([0, 1]) + self.ax.bar(range(self.config.num_bars), self.state.data) + + +# ======================================= DEMO ========================================= + + +# A graph for the demo in this example. Hooks together the AveragedNoise group +# (containing NoiseGenerator and RollingAverager) and the Plot node. +class Demo(lg.Graph): + AVERAGED_NOISE: AveragedNoise + PLOT: Plot + + def setup(self) -> None: + # Provide configuration using global constants (but if we wanted to, we could + # have a configuration object provided to this graph as well). + self.AVERAGED_NOISE.configure( + AveragedNoiseConfig( + sample_rate=SAMPLE_RATE, num_features=NUM_FEATURES, window=WINDOW + ) + ) + self.PLOT.configure( + PlotConfig(refresh_rate=REFRESH_RATE, num_bars=NUM_FEATURES) + ) + + # Connect the AveragedNoise output to the Plot input + def connections(self) -> lg.Connections: + return ((self.AVERAGED_NOISE.OUTPUT, self.PLOT.INPUT),) + + # Parallelization: Run AveragedNoise and Plot in separate processes + def process_modules(self) -> Tuple[lg.Module, ...]: + return (self.AVERAGED_NOISE, self.PLOT) + + +# Entry point: run the Demo graph +if __name__ == "__main__": + lg.run(Demo) diff --git a/labgraph/examples/simulation.py b/labgraph/examples/simulation.py new file mode 100644 index 000000000..8e7cbe178 --- /dev/null +++ b/labgraph/examples/simulation.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import time +from typing import Tuple, Optional + +import labgraph as lg +import numpy as np +from scipy import signal +from scipy.stats import gamma +import matplotlib.animation as animation +import matplotlib.axes +import matplotlib.pyplot as plt + +# Constants used by nodes +SAMPLE_RATE = 10.0 +NUM_FEATURES = 220 +WINDOW = 2.0 +REFRESH_RATE = 2.0 + + +# Simulation configurations +SAMPLE_SIZE_CYCLE = 30 +SAMPLES_REST = 9 +ORDER_OF_ZERO_DAUB = 10 +PEAK_GAMMA_SHAPE = 6 +UNDERSHOOT_GAMMA_SHAPE = 12 +TIME_TO_ZERO_HFR = 0.35 + + +class SimulationFunction: + """ + Simulation functions to generate a cycle (one cycle of the function). + """ + + # Last element is removed to ensure no overlaps between cycles. + phase_data = np.linspace(-np.pi, np.pi, SAMPLE_SIZE_CYCLE)[:-1] + + # Generate a sine cycle + def sin_cycle(self): + return np.sin(self.phase_data) + + # Generate a square cycle + def square_cycle(self): + return np.sign(np.sin(self.phase_data)) + + # Generate a heartbeat-like cycle using daubechies cycle + def daub_cycle(self): + hb = signal.wavelets.daub(ORDER_OF_ZERO_DAUB) + zero_array = np.zeros(SAMPLES_REST, dtype=float) + hb_full = np.concatenate([hb, zero_array]) + return hb_full + + # Generate a hemodynamic responses (HRFs) cycle + def hrf_cycle(self): + times = np.arange(1, SAMPLE_SIZE_CYCLE) + peak_values = gamma.pdf(times, PEAK_GAMMA_SHAPE) + undershoot_values = gamma.pdf(times, UNDERSHOOT_GAMMA_SHAPE) + values = peak_values - TIME_TO_ZERO_HFR * undershoot_values + return values / np.max(values) + + +class SimulationMessage(lg.Message): + timestamp: np.ndarray + daub_data: np.ndarray + + +class GeneratorConfig(lg.Config): + sample_rate: float # Rate at which to generate noise + num_features: int # Number of features to generate + window: float # Window, in seconds, to average over + + +class SimulationGenerator(lg.Node): + """ + Generate messages to visualize + Repeatedly generate cycles using simulation functions. + + Note: Cycle periods of different functions are chosen + the same in this example. + """ + + OUTPUT = lg.Topic(SimulationMessage) + config: GeneratorConfig + + @lg.publisher(OUTPUT) + async def generate_simulation(self) -> lg.AsyncPublisher: + SF = SimulationFunction() + daub_base_data = SF.daub_cycle() + counter = 0 + data_length = len(daub_base_data) + + while True: + for i in range(data_length): + daub_base_data_itr = np.concatenate([daub_base_data[i:], daub_base_data[:i]]) + yield self.OUTPUT, SimulationMessage( + timestamp=np.array(np.arange(counter*data_length, (counter+1)*data_length), dtype=np.float), + daub_data=daub_base_data_itr, + ) + await asyncio.sleep(1 / self.config.sample_rate) + counter += 1 + + +# ======================================= PLOT ========================================= + + +# The state of the Plot: holds the most recent data received, which should be displayed +class PlotState(lg.State): + data: Optional[np.ndarray] = None + timestamp: Optional[np.ndarray] = None + + +# The configuration for the Plot +class PlotConfig(lg.Config): + refresh_rate: float # How frequently to refresh the bar graph + num_bars: int # The number of bars to display (note this should be == num_features) + + +# A node that creates a matplotlib bar graph that displays the produced data in +# real-time +class Plot(lg.Node): + INPUT = lg.Topic(SimulationMessage) + state: PlotState + config: PlotConfig + + def setup(self) -> None: + self.ax: Optional[matplotlib.axes.Axes] = None + + # A subscriber method that simply receives data and updates the node's state + @lg.subscriber(INPUT) + def got_message(self, message: SimulationMessage) -> None: + # This demo wil use heart-beat like signal as an example + # Other data examples are also available by changing message.daub_data + self.state.data = message.daub_data + self.state.timestamp = message.timestamp + + # A main method does not interact with topics, but has its own line of execution - + # this can be useful for Python libraries that must be run in the main thread. For + # example, scikit-learn and pyqtgraph are libraries that need the main thread. + @lg.main + def run_plot(self) -> None: + fig = plt.figure() + self.ax = fig.add_subplot(1, 1, 1) + #self.ax.set_ylim((0, 1)) + anim = animation.FuncAnimation( # noqa: F841 + fig, self._animate, interval=1 / self.config.refresh_rate * 1000 + ) + plt.show() + raise lg.NormalTermination() + + def _animate(self, i: int) -> None: + if self.ax is None: + return + self.ax.clear() + #self.ax.set_ylim([0, 1]) + #self.ax.bar(range(self.config.num_bars), self.state.data) + self.ax.plot(self.state.timestamp, self.state.data) + + +# ======================================= DEMO ========================================= + + +# A graph for the demo in this example. Hooks together the AveragedNoise group +# (containing NoiseGenerator and RollingAverager) and the Plot node. +class Demo(lg.Graph): + SIMULATIONGENERATOR: SimulationGenerator + PLOT: Plot + + def setup(self) -> None: + # Provide configuration using global constants (but if we wanted to, we could + # have a configuration object provided to this graph as well). + self.SIMULATIONGENERATOR.configure( + GeneratorConfig( + sample_rate=SAMPLE_RATE, num_features=NUM_FEATURES, window=WINDOW + ) + ) + self.PLOT.configure( + PlotConfig(refresh_rate=REFRESH_RATE, num_bars=NUM_FEATURES) + ) + + # Connect the AveragedNoise output to the Plot input + def connections(self) -> lg.Connections: + return ((self.SIMULATIONGENERATOR.OUTPUT, self.PLOT.INPUT),) + + # Parallelization: Run AveragedNoise and Plot in separate processes + def process_modules(self) -> Tuple[lg.Module, ...]: + return (self.SIMULATIONGENERATOR, self.PLOT) + + +# Entry point: run the Demo graph +if __name__ == "__main__": + lg.run(Demo) diff --git a/labgraph/graphs/__init__.py b/labgraph/graphs/__init__.py new file mode 100644 index 000000000..bdc5354d0 --- /dev/null +++ b/labgraph/graphs/__init__.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "AsyncPublisher", + "background", + "Config", + "CPPNodeConfig", + "Graph", + "Group", + "Connections", + "main", + "Module", + "Node", + "NodeTestHarness", + "publisher", + "run_async", + "run_with_harness", + "State", + "subscriber", + "Topic", +] + +from .config import Config +from .cpp_node import CPPNodeConfig +from .graph import Graph +from .group import Connections, Group +from .method import AsyncPublisher, background, main, publisher, subscriber +from .module import Module +from .node import Node +from .node_test_harness import NodeTestHarness, run_async, run_with_harness +from .state import State +from .topic import Topic diff --git a/labgraph/graphs/config.py b/labgraph/graphs/config.py new file mode 100644 index 000000000..c37068ba1 --- /dev/null +++ b/labgraph/graphs/config.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import argparse +from enum import Enum +from typing import Any, List, Optional + +from ..messages.message import Field, Message +from ..util.error import LabGraphError + + +class Config(Message): + """ + Represents a configuration for a module. A configuration defines how a module will + behave. + """ + + @classmethod + def fromargs(cls, args: Optional[List[str]] = None) -> "Config": + """ + Builds a Config object based on command-line arguments. + + Args: + args: Command-line arguments to parse. If not provided, looks at `sys.argv`. + """ + parser = argparse.ArgumentParser() + for field_name, field in cls.__message_fields__.items(): + _add_field_to_argument_parser(parser, field_name, field) + if args is not None: + parse_result = parser.parse_args(args) + else: + parse_result = parser.parse_args() + return cls(**{k: v for k, v in vars(parse_result).items() if v is not None}) + + +def _add_field_to_argument_parser( + parser: argparse.ArgumentParser, field_name: str, field: Field[Any] +) -> None: + """ + Adds an argument to the parser corresponding to the provided field. + + Args: + parser: The argument parser + field_name: The name of the field + field: The field + """ + field_name_dashes = field_name.replace("_", "-") + field_option = f"--{field_name_dashes}" + python_type = field.data_type.python_type + if python_type in (int, str, float): + parser.add_argument(field_option, type=python_type, required=field.required) + elif python_type is bool: + parser.add_argument(field_option, action="store_true") + elif issubclass(python_type, Enum): + parser.add_argument( + field_option, + type=lambda item: python_type[item], # type: ignore + choices=list(python_type), + required=field.required, + ) + else: + raise LabGraphError( + "Invalid type for argument parsing for config field. " + f"'{field_name}' has type '{python_type.__name__}'" + ) diff --git a/labgraph/graphs/cpp_node.py b/labgraph/graphs/cpp_node.py new file mode 100644 index 000000000..3f8b7410a --- /dev/null +++ b/labgraph/graphs/cpp_node.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from dataclasses import field +from typing import Any, List, Optional, Type + +from labgraph_cpp import Node as _Node, NodeBootstrapInfo # type: ignore + +# HACK: Import from LabGraph's wrapper of Cthulhu before importing dynamic libs to set +# the shared memory name +from .._cthulhu import bindings # noqa: F401 +from ..messages.message import Message +from ..util.error import LabGraphError +from .config import Config +from .method import Subscriber, background +from .node import Node +from .state import State +from .stream import Stream +from .topic import Topic + + +class CPPNodeConfig(Config): + args: List[Any] = field(default_factory=list) + cpp_class: Optional[Type[_Node]] = None + + +class CPPNode(Node): + config: CPPNodeConfig + + __cpp_node: Optional[_Node] + + def __init__( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> None: + super().__init__(config=config, state=state) + # We want to guarantee cpp_class is set on creation so that we can get topic + # information from the C++ code + assert config is not None + assert config.cpp_class is not None + self.__cpp_node = None + + topic_names = config.cpp_class.topic_names + for topic_name in topic_names: + assert topic_name not in self.__topics__.keys() + topic = Topic(Message) + setattr(self, topic_name, topic) + self.__topics__[topic_name] = topic + self.__streams__[topic_name] = Stream( + id=topic_name, topic_paths=(topic_name,), message_type=Message + ) + + def _bootstrap(self, bootstrap_info: NodeBootstrapInfo) -> None: + self._cpp_node._bootstrap(bootstrap_info) + + def configure(self, config: Config) -> None: + # Because cpp_class is set on creation and we use it to get topic information + # for this node, we don't want to overwrite it during configure(). We keep the + # cpp_class fixed and just pass args through. + assert isinstance(config, CPPNodeConfig) + config = CPPNodeConfig(cpp_class=self.config.cpp_class, args=config.args) + super().configure(config) + + @background + async def run(self) -> None: + import asyncio + + await asyncio.get_event_loop().run_in_executor(None, self._cpp_node.run) + + @property + def _cpp_node(self) -> _Node: + assert self.__cpp_node is not None + return self.__cpp_node + + def setup(self) -> None: + assert self.config.cpp_class is not None + self.__cpp_node = self.config.cpp_class(*self.config.args) + self._cpp_node.setup() + + def cleanup(self) -> None: + try: + self._cpp_node.cleanup() + except AssertionError: + # No CPP node (didn't bootstrap yet); this is fine + pass + + @staticmethod + def dummy_subscriber_method(message: Message) -> None: + pass diff --git a/labgraph/graphs/graph.py b/labgraph/graphs/graph.py new file mode 100644 index 000000000..9bca19e35 --- /dev/null +++ b/labgraph/graphs/graph.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Any, Dict, Optional, Sequence, Tuple + +from ..util.error import LabGraphError +from ..util.logger import get_logger +from .config import Config +from .group import Group, GroupMeta +from .module import Module +from .node import Node +from .state import State +from .stream import Stream +from .topic import Topic + + +logger = get_logger(__name__) + + +class GraphMeta(GroupMeta): + # HACK: We take kwargs here because Python 3.6 passes an extra tvars + # argument to the metaclass of a Generic. We can get rid of the kwargs + # argument here in Python 3.7 which no longer passes this. + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any], **kwargs: Any + ) -> None: + super(GraphMeta, cls).__init__(name, bases, fields) + + if hasattr(cls, "__annotations__"): + if "config" in cls.__annotations__: + if not issubclass(cls.__annotations__["config"], Config): + raise LabGraphError( + "The config for a Graph must be a subclass of Config, got " + f"{cls.__annotations__['config']}" + ) + + +class Graph(Group, metaclass=GraphMeta): + """ + Represents a computational graph. A graph is simply a group that validates that + all of its topics have publishers and subscribers. + """ + + config: Config + + def __init__( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> None: + super(Graph, self).__init__(config=config, state=state) + + self._validate_topics() + + def _validate_topics(self) -> None: + """ + Validates all the graph's topics have publishers and subscribers. Raises an + error if any topic lacks a publisher or subscriber. + """ + stream_is_published = { + stream_id: False for stream_id in self.__streams__.keys() + } + stream_is_subscribed = { + stream_id: False for stream_id in self.__streams__.keys() + } + + for publisher in self.publishers.values(): + for stream_id in stream_is_published.keys(): + stream_set = set(self.__streams__[stream_id].topic_paths) + if len(stream_set.intersection(publisher.published_topic_paths)) > 0: + stream_is_published[stream_id] = True + + for subscriber in self.subscribers.values(): + for stream_id in stream_is_subscribed.keys(): + if ( + subscriber.subscribed_topic_path + in self.__streams__[stream_id].topic_paths + ): + stream_is_subscribed[stream_id] = True + + unpublished_streams = { + stream_id + for stream_id, published in stream_is_published.items() + if not published + } + unsubscribed_streams = { + stream_id + for stream_id, subscribed in stream_is_subscribed.items() + if not subscribed + } + + if len(unpublished_streams) > 0 or len(unsubscribed_streams) > 0: + message = f"{self.__class__.__name__} has unused topics:\n" + submessages = [] + if len(unpublished_streams) > 0: + for stream_id in unpublished_streams: + for topic_path in self.__streams__[stream_id].topic_paths: + submessages.append(f"\t- {topic_path} has no publishers\n") + if len(unsubscribed_streams) > 0: + for stream_id in unsubscribed_streams: + for topic_path in self.__streams__[stream_id].topic_paths: + submessages.append(f"\t- {topic_path} has no subscribers\n") + message += "".join(sorted(submessages)) + message += ( + "This could mean that there are publishers and/or subscribers of " + "Cthulhu streams that LabGraph doesn't know about, and/or that data " + "in some topics is being discarded.\n" + ) + + # TODO: We warn instead of raising an error because LabGraph currently + # tries to run any publishers/subscribers it knows about as async functions, + # so for now we keep it ignorant of C++ publisher/subcriber methods. + logger.warning(message.strip()) + + def _get_streams_by_logging_id(self) -> Dict[str, Stream]: + logging_spec: Dict[str, Topic] = self.logging() + return { + logging_id: self._stream_for_topic_path(self._get_topic_path(topic)) + for logging_id, topic in logging_spec.items() + } + + def process_modules(self) -> Sequence[Module]: + """ + Returns a set of modules that will be the root of each process in this + graph when it is executed in a distributed way. By default, this graph + is the only process module, meaning the entire graph is run in a single + process. Override this method in a graph to specify a different + distribution of modules over processes. + """ + return (self,) + + def logging(self) -> Dict[str, Topic]: + """ + Returns a dictionary, where each key value pair represents a + `Topic` to be logged. The logger will be provided the string key as + the identifier for the logged topic. `HDF5Logger` (the default logger) uses + this string identifier as the HDF5 dataset name. + """ + return {} diff --git a/labgraph/graphs/group.py b/labgraph/graphs/group.py new file mode 100644 index 000000000..5f659a370 --- /dev/null +++ b/labgraph/graphs/group.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import logging +from collections.abc import Iterable +from copy import deepcopy +from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Type, Union + +import typeguard +from labgraph_cpp import Node as _Node # type: ignore +from typing_extensions import Protocol, runtime_checkable + +# HACK: Import from LabGraph's wrapper of Cthulhu before importing dynamic libs to set +# the shared memory name +from .._cthulhu import bindings as cthulhu # noqa: F401 +from ..messages.message import Message +from ..util.error import LabGraphError +from .config import Config +from .cpp_node import CPPNode, CPPNodeConfig +from .method import Main, Publisher, Subscriber +from .module import Module, ModuleMeta +from .node import Node +from .state import State +from .stream import Stream +from .topic import PATH_DELIMITER, Topic + + +Connections = Sequence[Tuple[Topic, Topic]] +logger = logging.getLogger(__name__) + + +class GroupMeta(ModuleMeta): + """ + Metaclass for `Group` classes. This metaclass is responsible for reading the + children of the group (`Node`s and other `Group`s) from the class variables + and storing them. + """ + + __children_types__: Dict[str, Union[Type[Module], Type[_Node]]] + + # HACK: We take kwargs here because Python 3.6 passes an extra tvars + # argument to the metaclass of a Generic. We can get rid of the kwargs + # argument here in Python 3.7 which no longer passes this. + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any], **kwargs: Any + ) -> None: + super(GroupMeta, cls).__init__(name, bases, fields) + + # Collect the group's children types + cls.__children_types__ = {} + if hasattr(cls, "__annotations__"): + for field_name, field_type in cls.__annotations__.items(): + if isinstance(field_type, type) and ( + issubclass(field_type, Module) or issubclass(field_type, _Node) + ): + cls.__children_types__[field_name] = field_type + + +class Group(Module, metaclass=GroupMeta): + """ + Represents a group in a graph. A group defines a collection of nodes and + other groups. By overriding `connections()` a group can link the topics of + its children in order to set up communications. + """ + + def __init__( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> None: + super(Group, self).__init__(config=config, state=state) + + # Collect the group's children (as instances) + for child_name, child_type in self.__class__.__children_types__.items(): + if not self._is_valid_child_name(child_name): + continue + if issubclass(child_type, _Node): + cpp_node = CPPNode(config=CPPNodeConfig(cpp_class=child_type)) + self.__children__[child_name] = cpp_node + else: + self.__children__[child_name] = child_type() + + for child_name, child in self.__children__.items(): + setattr(self, child_name, child) + + # Collect the group's descendants (children + recursive children of + # child groups) + for child_name, child in self.__children__.items(): + self.__descendants__[child_name] = child + for child_name, child in self.__children__.items(): + if isinstance(child, Group): + for descendant_path, descendant in child.__descendants__.items(): + self.__descendants__[ + PATH_DELIMITER.join((child_name, descendant_path)) + ] = descendant + + # Collect the group's descendants' topics + if isinstance(child, Group) or isinstance(child, Node): + for topic_path, topic in child.__topics__.items(): + self.__topics__[ + PATH_DELIMITER.join((child_name, topic_path)) + ] = topic + + # Collect the group's node methods + for descendant_path, descendant in self.__descendants__.items(): + if isinstance(descendant, Node): + for method_name, method in descendant.__methods__.items(): + new_method = deepcopy(method) + if isinstance(new_method, Publisher): + new_method.published_topic_paths = tuple( + PATH_DELIMITER.join((descendant_path, topic_path)) + for topic_path in new_method.published_topic_paths + ) + if isinstance(new_method, Subscriber): + new_method.subscribed_topic_path = PATH_DELIMITER.join( + (descendant_path, new_method.subscribed_topic_path) + ) + self.__methods__[ + PATH_DELIMITER.join((descendant_path, method_name)) + ] = new_method + + # Collect the group's stream information + self.__streams__ = self._get_streams() + + # Update the descendants' stream information so that connected topics have the + # same backing stream + self._update_descendant_streams() + + # Ensure the connections of this group didn't create any streams with multiple + # publishers + self._validate_streams() + + def _get_streams(self) -> Dict[str, Stream]: + """ + Returns a dictionary containing a stream for each group of topics that are + joined to each other. Topic joins are transitive, i.e., if A is joined to B, and + B is joined to C, then A is joined to C. + """ + + # This is basically a version of the union-find algorithm. We start by putting + # each topic in its own stream, then for each topic pair that is joined, we merge + # each topics' stream. + + stream_nums: Dict[str, int] = {} + + for topic_name in self.__topics__.keys(): + if PATH_DELIMITER not in topic_name: + # Put each topic in this group in its own stream + stream_nums[topic_name] = len(stream_nums) + + for child_name, child in self.__children__.items(): + # Preserve the streams that child modules have already computed + for stream in child.__streams__.values(): + new_stream_num = len(stream_nums) + for topic_path in stream.topic_paths: + stream_nums[ + PATH_DELIMITER.join((child_name, topic_path)) + ] = new_stream_num + + # Use `connections()` to merge streams + connections = list(self.connections()) + typeguard.check_type( + f"{self.__class__.__name__}.{self.connections.__name__}()", + connections, + Connections, + ) + for topic1, topic2 in connections: + # Find the topic paths for these `Topic` objects + topic_paths: List[str] = [] + for topic in (topic1, topic2): + for topic_path, descendant_topic in self.__topics__.items(): + if topic is descendant_topic: + topic_paths.append(topic_path) + break + + assert len(topic_paths) == 2 + + # Set the stream numbers of all topics in the two old streams to be + # the same + old_stream_nums = (stream_nums[topic_paths[0]], stream_nums[topic_paths[1]]) + new_stream_num = min(old_stream_nums) + for topic_path, stream_num in list(stream_nums.items()): + if stream_num in old_stream_nums: + stream_nums[topic_path] = new_stream_num + + # Group the topics by stream number, validate their message types, and sort the + # topic names in each stream + result = [] + for stream_num in set(stream_nums.values()): + topic_paths = sorted(p for p, n in stream_nums.items() if n == stream_num) + + message_types_by_topic: Dict[str, Type[Message]] = {} + for topic_path in topic_paths: + message_types_by_topic[topic_path] = self.__topics__[ + topic_path + ].message_type + + message_types = list(message_types_by_topic.values()) + # Use == to unique instead of creating a set() which compares via `is` + message_types = [ + m for i, m in enumerate(message_types) if message_types.index(m) == i + ] + + # HACK: Since we don't currently use Cthulhu dynamic types, we don't know + # what types a CPPNode's topics use. We type them as Message for now, and + # exclude them from the topics-have-same-type check below. + for message_type in list(message_types): + if message_type is Message: + message_types.remove(message_type) + + if len(message_types) > 1: + error_message = ( + "Topics in stream must have matching message types, found the " + "following types for the same stream:\n" + ) + for topic_path in topic_paths: + error_message += ( + f"- {topic_path}: {message_types_by_topic[topic_path]}\n" + ) + raise LabGraphError(error_message) + + if len(message_types) == 0: + warning_message = ( + "Found no message types for a stream. This could be because the " + "topic is never used in Python. Consume a topic with a message " + "type in Python to make this stream work. This stream contains the " + "following topics:\n" + ) + for topic_path in topic_paths: + warning_message += f"- {topic_path}\n" + + logger.warning(warning_message) + + result.append(Stream(topic_paths=tuple(topic_paths))) + else: + # The stream is valid, so create the stream object + result.append( + Stream( + topic_paths=tuple(topic_paths), + message_type=list(message_types)[0], + ) + ) + + # Index the streams by id + return {stream.id: stream for stream in result} + + def _update_descendant_streams(self) -> None: + """ + Updates the descendants' streams so that connected topics have the same + underlying streams. + """ + for module_path, module in self.__descendants__.items(): + streams = { + stream.id: stream + for stream in self.__streams__.values() + if any( + topic_path.startswith(module_path) + for topic_path in stream.topic_paths + ) + } + module_streams = { + stream.id: Stream( + id=stream.id, + message_type=stream.message_type, + topic_paths=tuple( + topic_path[len(module_path) + len(PATH_DELIMITER) :] + for topic_path in stream.topic_paths + if topic_path.startswith(module_path) + ), + ) + for stream in streams.values() + } + module.__streams__ = module_streams + + def connections(self) -> "Connections": + """ + Override `connections` in order to specify which topics in this group should + be joined to each other. Topics that are joined together will be backed by the + same stream. This is intended to be used to connect different children of this + group together. For example, if node `N` publishes to topic `A` and + group `C` subscribes to topic `B`, we can return `((self.N.A, self.C.B),)` + here to connect `N`'s output to `C`'s input. + """ + return () # Return no connections by default + + def _is_valid_child_name(self, name: str) -> bool: + """ + Returns true if the given name is valid for a child of this group. Notably, + returns false for LabGraph-internal fields starting with "__" as well as + special fields like `config`. + """ + if name.startswith("__"): + return False + SPECIAL_NAMES = ("config", "state") + if name in SPECIAL_NAMES: + return False + return True diff --git a/labgraph/graphs/method.py b/labgraph/graphs/method.py new file mode 100644 index 000000000..b1bbdc153 --- /dev/null +++ b/labgraph/graphs/method.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from typing import ( + Any, + AsyncIterator, + Awaitable, + Callable, + Coroutine, + List, + Optional, + Sequence, + Tuple, +) + +from typing_extensions import Protocol + +from ..util.error import LabGraphError +from .topic import Topic + + +_METADATA_LABEL = "_METADATA" + + +class AsyncPublisher(Protocol): + """ + Convenience return type for async publisher methods. An async method that yields + tuples of LabGraph topics and messages can be typed as returning this. + For example: + + ``` + import labgraph as lg + ... + class MyNode(Node): + A = Topic(MyMessage) + + @publisher(A) + def publisher_method(self) -> lg.AsyncPublisher: + ... + yield self.A, message + ... + ``` + """ + + def __aiter__(self) -> AsyncIterator[Tuple[Topic, Any]]: + ... + + +PublisherType = Callable[..., AsyncPublisher] +SubscriberType = Callable[..., Any] +TransformerType = Callable[..., AsyncPublisher] +BackgroundType = Callable[..., Awaitable[None]] +MainType = Callable[..., None] + + +class NodeMethod(ABC): + """ + Represents a method on a Node that has been decorated by LabGraph. Subclasses + include topic paths, if applicable. + """ + + name: str + + @abstractmethod + def __init__(self, name: str) -> None: + self.name = name + + +@dataclass +class MethodMetadata: + """ + Represents metadata on a method that is created by a LabGraph decorator. The + `MethodMetadata` is used to validate the decorator usage and then construct a + `NodeMethod`. + """ + + name: str + published_topics: List[Topic] = field(default_factory=list) + subscribed_topic: Optional[Topic] = None + is_background: bool = False + is_main: bool = False + + @property + def node_method(self) -> NodeMethod: + """ + Constructs a `NodeMethod` using this metadata. The `NodeMethod` uses topic paths + instead of `Topic` objects. + """ + self.validate() + + if len(self.published_topics) > 0 and self.subscribed_topic is not None: + return Transformer( + name=self.name, + published_topic_paths=tuple( + topic.name for topic in self.published_topics + ), + subscribed_topic_path=self.subscribed_topic.name + if self.subscribed_topic is not None + else None, + ) + elif len(self.published_topics) > 0: + return Publisher( + name=self.name, + published_topic_paths=tuple( + topic.name for topic in self.published_topics + ), + ) + elif self.subscribed_topic is not None: + return Subscriber( + name=self.name, + subscribed_topic_path=self.subscribed_topic.name + if self.subscribed_topic is not None + else None, + ) + elif self.is_background: + return Background(name=self.name) + elif self.is_main: + return Main(name=self.name) + else: + raise LabGraphError("Unexpected NodeMethod type") + + def validate(self) -> None: + for i, topic1 in enumerate(self.published_topics): + for j, topic2 in enumerate(self.published_topics): + if i != j and topic1 is topic2: + raise LabGraphError( + f"Method '{self.name}' got two @publisher decorators for the " + "same topic" + ) + + if len(self.published_topics) > 0: + if self.is_background: + raise LabGraphError( + f"Method '{self.name}' cannot have both a @{publisher.__name__} " + f"decorator and a @{background.__name__} decorator" + ) + if self.is_main: + raise LabGraphError( + f"Method '{self.name}' cannot have both a @{publisher.__name__} " + f"decorator and a @{main.__name__} decorator" + ) + + if self.subscribed_topic is not None: + if self.is_background: + raise LabGraphError( + f"Method '{self.name}' cannot have both a @{subscriber.__name__} " + f"decorator and a @{background.__name__} decorator" + ) + if self.is_main: + raise LabGraphError( + f"Method '{self.name}' cannot have both a @{subscriber.__name__} " + f"decorator and a @{main.__name__} decorator" + ) + + if self.is_background and self.is_main: + raise LabGraphError( + f"Method '{self.name}' cannot have both a @{background.__name__} " + f"decorator and a @{main.__name__} decorator" + ) + + +def get_method_metadata(method: Callable[..., Any]) -> MethodMetadata: + """ + Returns the `MethodMetadata` associated with a method, creating one if it doesn't + already exist. + """ + metadata: MethodMetadata + if hasattr(method, _METADATA_LABEL): + metadata = getattr(method, _METADATA_LABEL) + assert isinstance(metadata, MethodMetadata) + else: + metadata = MethodMetadata(name=method.__name__) + setattr(method, _METADATA_LABEL, metadata) + return metadata + + +class Publisher(NodeMethod): + """ + Represents a LabGraph method decorated by `@publisher`. + """ + + published_topic_paths: Tuple[str, ...] + + def __init__(self, name: str, published_topic_paths: Sequence[str]) -> None: + NodeMethod.__init__(self, name) + self.published_topic_paths = tuple(published_topic_paths) + + +def publisher(topic: Topic) -> Callable[[PublisherType], PublisherType]: + """ + Decorator for methods on a `Node` subclass. `@publisher(T)` causes the method to be + able to publish to the topic `T`. + """ + + def publisher_wrapper(method: PublisherType) -> PublisherType: + metadata = get_method_metadata(method) + metadata.published_topics.append(topic) + metadata.validate() + return method + + return publisher_wrapper + + +class Subscriber(NodeMethod): + """ + Represents a LabGraph method decorated by `@subscriber`. + """ + + subscribed_topic_path: str + + def __init__(self, name: str, subscribed_topic_path: str) -> None: + NodeMethod.__init__(self, name) + self.subscribed_topic_path = subscribed_topic_path + + +def subscriber(topic: Topic) -> Callable[[SubscriberType], SubscriberType]: + """ + Decorator for methods on a `Node` subclass. `@subscriber(T)` causes the method to be + subscribed to the topic `T`. + """ + + def subscriber_wrapper(method: SubscriberType) -> SubscriberType: + annotations = { + arg: arg_type + for arg, arg_type in method.__annotations__.items() + if arg not in ("self", "return") + } + if ( + not len(annotations) == 1 + or list(annotations.values())[0] != topic.message_type + or method.__code__.co_argcount != 2 + or method.__code__.co_varnames[0] != "self" + or method.__code__.co_varnames[1] != list(annotations.keys())[0] + # TODO: We could also check the return type here + ): + raise LabGraphError( + f"Expected subscriber '{method.__name__}' to have signature def " + f"{method.__name__}(self, message: {topic.message_type.__name__}) -> " + "None" + ) + + metadata = get_method_metadata(method) + if metadata.subscribed_topic is not None: + raise LabGraphError( + f"Method '{metadata.name}' already has a @{subscriber.__name__} " + "decorator" + ) + + metadata.subscribed_topic = topic + metadata.validate() + return method + + return subscriber_wrapper + + +class Transformer(Publisher, Subscriber): + """ + Represents a LabGraph method decorated by both `@publisher` and `@subscriber`. + """ + + def __init__( + self, + name: str, + published_topic_paths: Sequence[str], + subscribed_topic_path: str, + ) -> None: + Publisher.__init__(self, name, published_topic_paths) + Subscriber.__init__(self, name, subscribed_topic_path) + + +class Background(NodeMethod): + """ + Represents a LabGraph method decorated by `@background`. + """ + + def __init__(self, name: str) -> None: + super(Background, self).__init__(name) + + +def background(method: BackgroundType) -> BackgroundType: + """ + Decorator for methods on a `Node` subclass. Adding `@background` causes the + method to be run in a background event loop when the node starts up. The method + cannot also be a subscriber or publisher. This is useful for methods that don't + interact with topics - for example, UI-related methods. + """ + metadata = get_method_metadata(method) + if metadata.is_background: + raise LabGraphError( + f"Method '{metadata.name}' already has a @{background.__name__} decorator" + ) + metadata.is_background = True + metadata.validate() + return method + + +class Main(NodeMethod): + """ + Represents a LabGraph method decorated by `@main`. + """ + + def __init__(self, name: str) -> None: + super(Main, self).__init__(name) + + +def main(method: MainType) -> MainType: + """ + Decorator for methods on a `Node` subclass. Adding `@main` causes the + method to be run in the main thread when the graph starts up. The method cannot also + be a subscriber or publisher. This is useful for methods that don't interact with + topics - for example, UI-related methods. Each node can only have one method + decorated by `@main`. + """ + metadata = get_method_metadata(method) + if metadata.is_main: + raise LabGraphError( + f"Method '{metadata.name}' already has a @{main.__name__} decorator" + ) + metadata.is_main = True + metadata.validate() + return method diff --git a/labgraph/graphs/module.py b/labgraph/graphs/module.py new file mode 100644 index 000000000..d70c1cf65 --- /dev/null +++ b/labgraph/graphs/module.py @@ -0,0 +1,384 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import ABC, ABCMeta +from copy import deepcopy +from typing import Any, Callable, Dict, Optional, Set, Tuple, Type, TypeVar + +import typeguard + +from ..messages.message import Message +from ..util.error import LabGraphError +from ..util.random import random_string +from .config import Config +from .method import ( + Background, + BackgroundType, + Main, + MainType, + NodeMethod, + Publisher, + PublisherType, + Subscriber, + SubscriberType, + Transformer, + TransformerType, +) +from .state import State +from .stream import Stream +from .topic import PATH_DELIMITER, Topic + + +MODULE_ID_LENGTH = 16 + +T = TypeVar("T", bound=NodeMethod) # TypeVar for NodeMethod return types + + +class ModuleMeta(ABCMeta): + """ + Metaclass for module classes. See `Module` for what a module is. This + metaclass is responsible for collecting the topic information from the class + variables defined on the class. + """ + + __topics__: Dict[str, Topic] + __state_type__: Type[State] + __config_type__: Type[Config] + + # HACK: We take kwargs here because Python 3.6 passes an extra tvars + # argument to the metaclass of a Generic. We can get rid of the kwargs + # argument here in Python 3.7 which no longer passes this. + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any], **kwargs: Any + ) -> None: + super(ModuleMeta, cls).__init__(name, bases, fields) + + cls.__topics__ = {} + + # Collect existing topics from base classes + for base_cls in bases: + for topic_name, topic in vars(base_cls).items(): + if not isinstance(topic, Topic): + continue + + # Raise if names of topics in multiple base classes collide + if topic_name in cls.__topics__: + raise LabGraphError( + f"Base classes of {cls.__name__} have conflicting topics named " + f"{topic_name}" + ) + + cls.__topics__[topic_name] = topic + + # Add the current class's topics + for field_name, field_value in fields.items(): + if not isinstance(field_value, Topic): + continue + + # Raise if a topic object was already used by a module (i.e., its _name) was + # set + if field_value._name is not None: + raise LabGraphError( + "Duplicate topic object found: please assign different Topic " + f"objects to values {field_value.name} and {cls.__name__}." + f"{field_name}" + ) + + field_value._assign_name(field_name) + + # Raise if a topic name collides with a superclass's topic name + if field_name in cls.__topics__: + raise LabGraphError( + f"Topic {cls.__name__}/{field_name} hides superclass's topic" + ) + + cls.__topics__[field_name] = field_value + + cls.__state_type__: Type[State] = State + cls.__config_type__: Type[Config] = Config + if hasattr(cls, "__annotations__"): + if "state" in cls.__annotations__: + cls.__state_type__ = cls.__annotations__["state"] + if "config" in cls.__annotations__: + cls.__config_type__ = cls.__annotations__["config"] + + +class Module(ABC, metaclass=ModuleMeta): + """ + An abstraction for a LabGraph component that can be run within a single process. + """ + + state: State + _config: Optional[Config] + __topics__: Dict[str, Topic] + _id: str + __children__: Dict[str, "Module"] + __descendants__: Dict[str, "Module"] + __streams__: Dict[str, Stream] + __methods__: Dict[str, NodeMethod] + + def __init__( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> None: + self.state = state or self.__class__.__state_type__() + self._config = config + self.__topics__ = deepcopy(self.__class__.__topics__) + for topic_name, topic in self.__topics__.items(): + setattr(self, topic_name, topic) + self._id = random_string(MODULE_ID_LENGTH) + self.__children__ = {} + self.__descendants__ = {} + self.__streams__ = {} + self.__methods__ = {} + + def setup(self) -> None: + """ + Sets up the module. Subclasses can override to specify setup behavior that runs on + graph startup. + """ + pass + + def cleanup(self) -> None: + """ + Cleans up the module. Subclasses can override to specify cleanup behavior that + runs on graph termination. + """ + pass + + def configure(self, config: Config) -> None: + """ + Sets the configuration for this module. + """ + self._config = config + + @property + def is_configured(self) -> bool: + return self._config is not None + + @property + def config(self) -> Config: + if self._config is None: + try: + # Try to create a default config with no arguments (would work with a + # message type with fields that all have default values) + self._config = self.__class__.__config_type__() + except TypeError: + raise LabGraphError( + f"Configuration not set. Call {self.__class__.__name__}.configure() to set the " + "configuration." + ) + return self._config + + @property + def id(self) -> str: + """ + Returns a runtime identifier for the module. + """ + return self._id + + def _get_method(self, method_path: str) -> Callable[..., Any]: + """ + Returns the callable method in a node given a method path. + + Args: + method_path: The path of the method to return. + """ + assert method_path in self.__methods__.keys() + node_path = PATH_DELIMITER.join(method_path.split(PATH_DELIMITER)[:-1]) + method_name = method_path.split(PATH_DELIMITER)[-1] + if node_path == "": + node = self + else: + node = self.__descendants__[node_path] + return getattr(node, method_name) # type: ignore + + def _get_subscriber_method(self, subscriber_path: str) -> SubscriberType: + """ + Returns a callable subscriber method in a node given a subscriber path. + + Args: + subscriber_path: The path of the subscriber method to return. + """ + method = self._get_method(subscriber_path) + typeguard.check_type(subscriber_path, method, SubscriberType) + return method + + def _get_publisher_method(self, publisher_path: str) -> PublisherType: + """ + Returns a callable publisher method in a node given a publisher path. + + Args: + publisher_path: The path of the publisher method to return. + """ + method = self._get_method(publisher_path) + typeguard.check_type(publisher_path, method, PublisherType) + return method + + def _get_background_method(self, background_path: str) -> BackgroundType: + """ + Returns a callable background method in a node given a background path. + + Args: + background_path: The path of the background method to return. + """ + method = self._get_method(background_path) + typeguard.check_type(background_path, method, BackgroundType) + return method + + def _get_main_method(self, main_path: str) -> MainType: + """ + Returns a callable main method in a node given a main path. + + Args: + main_path: The path of the main method to return. + """ + method = self._get_method(main_path) + typeguard.check_type(main_path, method, MainType) + return method + + def _get_transformer_method(self, transformer_path: str) -> TransformerType: + """ + Returns a callable transformer method in a node given a transformer path. + + Args: + transformer_path: The path of the transformer method to return. + """ + method = self._get_method(transformer_path) + typeguard.check_type(transformer_path, method, TransformerType) + return method + + def _get_streams_by_logging_id(self) -> Dict[str, Stream]: + """ + Returns a dictionary where each entry is a global logging identifier + for its associated `Stream`. + + Since logging identifiers are meant to be global, they are only + valid to define on a `Graph` and not a `Module` or `Group`. + """ + return {} + + def _get_methods_of_type(self, method_type: Type[T]) -> Dict[str, T]: + return { + method_path: method + for method_path, method in self.__methods__.items() + if isinstance(method, method_type) + } + + @property + def publishers(self) -> Dict[str, Publisher]: + """ + Returns the publishers of this group's nodes. + """ + return self._get_methods_of_type(Publisher) + + @property + def subscribers(self) -> Dict[str, Subscriber]: + """ + Returns the subscribers of this group's nodes. + """ + return self._get_methods_of_type(Subscriber) + + @property + def transformers(self) -> Dict[str, Transformer]: + """ + Returns the transformers of this group's nodes. + """ + return self._get_methods_of_type(Transformer) + + @property + def backgrounds(self) -> Dict[str, Background]: + """ + Returns the background methods of this group's nodes. + """ + return self._get_methods_of_type(Background) + + @property + def main(self) -> Tuple[Optional[str], Optional[Main]]: + """ + Returns the main method of this module, if any. The return value is a tuple of + the method path and the method. If there is no main method, this returns + `(None, None)`. + """ + main_methods = self._get_methods_of_type(Main) + if len(main_methods) > 1: + method_names = ", ".join(main_methods.keys()) + raise LabGraphError( + "Cannot have multiple methods decorated with @main in nodes in the " + f"same process: found methods {method_names}" + ) + if len(main_methods) == 0: + return (None, None) + + return next(iter(main_methods.items())) + + def _stream_for_topic_path(self, topic_path: str) -> Stream: + """ + Returns the stream the topic at `topic_path` is in. + """ + for stream in self.__streams__.values(): + if topic_path in stream.topic_paths: + return stream + raise LabGraphError(f"Topic '{topic_path}' is not in a stream") + + def _get_topic_path(self, topic: Topic) -> str: + """ + Given a `Topic` object, returns the path to the topic in this module. + """ + for topic_path, candidate_topic in self.__topics__.items(): + if topic is candidate_topic: + return topic_path + + raise LabGraphError( + f"Could not find topic '{topic.name}' in module {self.__class__.__name__}" + ) + + def _get_module_path(self, module: "Module") -> str: + """ + Given a `Module` object, returns the path to the descendant module of this + module. + """ + for module_path, candidate_module in self.__descendants__.items(): + if not isinstance(candidate_module, Module): + continue + if candidate_module is module: + return module_path + + raise LabGraphError( + f"Could not find module '{module.__class__.__name__}' ({module.id}) in " + f"module {self.__class__.__name__}" + ) + + @property + def message_types(self) -> Set[Type[Message]]: + """ + Returns the message types used by this module's topics. + """ + return {topic.message_type for topic in self.__topics__.values()} + + def __str__(self) -> str: + return f"{self.__class__.__name__} ({self.id})" + + def _validate_streams(self) -> None: + """ + Performs validation of the streams in this group: + - guarantees that each stream has only one publisher + """ + for stream in self.__streams__.values(): + publisher_paths = set() + for topic_path in stream.topic_paths: + for method_path, method in self.__methods__.items(): + if ( + isinstance(method, Publisher) + and topic_path in method.published_topic_paths + ): + publisher_paths.add(method_path) + if len(publisher_paths) > 1: + error_message = ( + f"The stream for topics ({', '.join(sorted(stream.topic_paths))}) " + "has multiple publishers, but only one publisher is allowed. The " + "following publishers were found:\n" + ) + error_message += "\n".join( + sorted(f"- {path}" for path in publisher_paths) + ) + raise LabGraphError(error_message) diff --git a/labgraph/graphs/node.py b/labgraph/graphs/node.py new file mode 100644 index 000000000..cc7d2413f --- /dev/null +++ b/labgraph/graphs/node.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from copy import deepcopy +from typing import Any, Dict, Optional, Tuple + +from ..util.error import LabGraphError +from .config import Config +from .method import _METADATA_LABEL, NodeMethod, get_method_metadata +from .module import Module, ModuleMeta +from .state import State +from .stream import Stream + + +class NodeMeta(ModuleMeta): + """ + Metaclass for Node classes. This metaclass is responsible for reading the decorators + on a Node subclass and producing `NodeMethod` objects which are descriptions of the + decorated methods that type of node has. These objects are propagated to the node's + ancestors when an instance is added to a graph. + """ + + __methods__: Dict[str, NodeMethod] + + # HACK: We take kwargs here because Python 3.6 passes an extra tvars + # argument to the metaclass of a Generic. We can get rid of the kwargs + # argument here in Python 3.7 which no longer passes this. + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any], **kwargs: Any + ) -> None: + super(NodeMeta, cls).__init__(name, bases, fields) + + if hasattr(cls, "__methods__"): + # Copy methods from superclass + cls.__methods__ = {**cls.__methods__} + else: + cls.__methods__ = {} + + # Collect metadata created by decorators on the node's methods + for field_name, field_value in fields.items(): + if callable(field_value) and hasattr(field_value, _METADATA_LABEL): + metadata = get_method_metadata(field_value) + + published_topics = metadata.published_topics + subscribed_topic = metadata.subscribed_topic + + # Validate the topic objects provided to @publisher and @subscriber + # decorators + for topic in published_topics + ( + [subscribed_topic] if subscribed_topic is not None else [] + ): + if topic._name is None or topic.name not in cls.__topics__.keys(): + topic_verb = ( + "subscribed to" + if topic is subscribed_topic + else "published" + ) + raise LabGraphError( + f"Invalid topic {topic_verb} by {cls.__name__}." + f"{field_name} - set the topic as a class variable " + f"in {cls.__name__}" + ) + + # Validate that there are not multiple @main decorators + if metadata.is_main: + other_methods = { + n: v + for n, v in fields.items() + if callable(v) + and hasattr(v, _METADATA_LABEL) + and n != field_name + } + + for other_method_name, other_method in other_methods.items(): + if get_method_metadata(other_method).is_main: + raise LabGraphError( + f"Cannot have multiple methods decorated with @main in " + f"{name}: found methods '{field_name}' and " + f"'{other_method_name}'" + ) + + # Validation complete: add the method to the node class + cls.__methods__[field_name] = metadata.node_method + + +class Node(Module, metaclass=NodeMeta): + """ + Represents a node in a graph. A user can instantiate this to define computation that + always occurs within the same process in a graph. Since nodes are modules, + topics can be added to nodes as class variables. Nodes can then use the @publisher + and @subscriber decorators to describe how the node's methods interact with those + topics. + + A method with a @subscriber(T) decorator is called with a message whenever + the topic T receives that message. A method with a @publisher(T) decorator must be + defined as async and can yield T, M to publish message M to topic T. A method can + subscribe to at most one topic but can publish to any number of topics via multiple + decorators. + + A method with one or more @publisher decorators but no @subscriber decorator is + considered an entry point of the graph and will be called at graph startup. + """ + + def __init__( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> None: + super(Node, self).__init__(config=config, state=state) + + self.__methods__ = deepcopy(self.__class__.__methods__) + + for topic_name, topic in self.__topics__.items(): + setattr(self, topic_name, topic) + + stream = Stream(topic_paths=(topic_name,), message_type=topic.message_type) + self.__streams__[stream.id] = stream + + self._validate_streams() diff --git a/labgraph/graphs/node_test_harness.py b/labgraph/graphs/node_test_harness.py new file mode 100644 index 000000000..a7c69c67a --- /dev/null +++ b/labgraph/graphs/node_test_harness.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import functools +import inspect +from contextlib import contextmanager +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Generic, + Iterator, + List, + Mapping, + Optional, + Sequence, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +from ..messages.message import Message +from ..util.testing import get_event_loop +from .config import Config +from .method import AsyncPublisher +from .node import Node +from .state import State +from .topic import Topic + + +N = TypeVar("N", bound=Node) # Node type +T = TypeVar("T", bound=Tuple[Topic, Message]) # Type yielded by async functions + + +class NodeTestHarness(Generic[N]): + """ + Utility class for testing LabGraph nodes. This allows a user to test some behavior + of a node in an asyncio event loop, with the harness taking care of setting up and + cleaning up the node. + + Args: + node_type: The type of node this harness will test. + """ + + def __init__(self, node_type: Type[N]) -> None: + self.node_type: Type[N] = node_type + + @contextmanager + def get_node( + self, config: Optional[Config] = None, state: Optional[State] = None + ) -> Iterator[N]: + """ + Context manager to create, configure and yield a node of specified type. + Node is cleaned up when the context manager exits. + + Args: + config: The configuration to set on the node, if provided. + state: The state to set on the Node, if provided. + """ + node = None + try: + node = self.node_type(config=config, state=state) + node.setup() + yield node + finally: + if node is not None: + node.cleanup() + + +@overload +def run_with_harness( + node_type: Type[N], + fn: Callable[[N], AsyncIterable[T]], + config: Optional[Config], + state: Optional[State], + max_num_results: Optional[int] = None, +) -> List[T]: + ... + + +@overload +def run_with_harness( + node_type: Type[N], + fn: Callable[[N], Awaitable[T]], + config: Optional[Config], + state: Optional[State], +) -> T: + ... + + +def run_with_harness(node_type, fn, config=None, state=None, max_num_results=None): + """ + Runs an async function on a new node of the provided type using `NodeTestHarness`. + + Args: + node_type: The type of node to create. + fn: + The async function to run. An instance of a node typed `node_type` will be + provided to the function as an argument. + config: The configuration to set on the node, if provided. + state: The state to set on the node, if provided. + max_num_results: + If `fn` is an async generator, the maximum number of results it will generate. + If this is `None`, then the generator can produce an unbounded number of + results. + """ + # Check whether the max_num_results argument was improperly provided + _check_max_num_results_arg(run_with_harness.__name__, fn, max_num_results) + + test_harness = NodeTestHarness(node_type=node_type) + with test_harness.get_node(config=config, state=state) as node: + return run_async(fn, args=[node], max_num_results=max_num_results) + + +@overload +def run_async( + fn: Callable[..., Awaitable[T]], + args: Optional[Sequence[Any]] = None, + kwargs: Optional[Mapping[str, Any]] = None, +) -> T: + ... + + +@overload +def run_async( + fn: Callable[..., AsyncIterable[T]], + args: Optional[Sequence[Any]] = None, + kwargs: Optional[Mapping[str, Any]] = None, + max_num_results: Optional[int] = None, +) -> List[T]: + ... + + +def run_async(fn, args=None, kwargs=None, max_num_results=None): + """ + Runs an async function to completion. Uses the current thread's event loop. Blocks + until the async function has finished executing. Forwards all arguments after `fn` + to the async function. + + Args: + fn: The async function to run. + args: Positional arguments to forward to the function. + kwargs: Keyword arguments to forward to the function. + max_num_results: + If `fn` is an async generator, the maximum number of results it will generate. + If this is `None`, then the generator can produce an unbounded number of + results. + """ + # Check whether the max_num_results argument was improperly provided + _check_max_num_results_arg(run_async.__name__, fn, max_num_results) + + # Unwrap functools.partial so we can check whether it is async + if isinstance(fn, functools.partial): + test_fn = fn.func + else: + test_fn = fn + if inspect.isasyncgenfunction(test_fn): + return get_event_loop().run_until_complete( + _async_generator_to_list( + fn=fn, + args=args or [], + kwargs=kwargs or {}, + max_num_results=max_num_results, + ) + ) + elif asyncio.iscoroutinefunction(test_fn): + return get_event_loop().run_until_complete(fn(*(args or []), **(kwargs or {}))) + else: + raise TypeError(f"{run_async.__name__}: function '{fn}' is not async") + + +def _check_max_num_results_arg( + called_fn_name: str, + fn: Union[Callable[..., Awaitable[Any]], Callable[..., AsyncIterable[Any]]], + max_num_results: Optional[int] = None, +) -> None: + if not inspect.isasyncgenfunction(fn) and max_num_results is not None: + raise TypeError( + f"{called_fn_name}: function '{fn}' is not an async generator but " + "max_num_results was provided" + ) + + +async def _async_generator_to_list( + fn: Callable[..., AsyncIterable[T]], + args: Sequence[Any], + kwargs: Mapping[str, Any], + max_num_results: Optional[int] = None, +) -> List[T]: + if max_num_results is not None and max_num_results < 0: + raise ValueError("max_num_results must be non-negative") + result = [] + async for retval in fn(*args, **kwargs): + result.append(retval) + if max_num_results is not None and len(result) >= max_num_results: + return result + return result diff --git a/labgraph/graphs/parent_graph_info.py b/labgraph/graphs/parent_graph_info.py new file mode 100644 index 000000000..0aaab988b --- /dev/null +++ b/labgraph/graphs/parent_graph_info.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import multiprocessing as mp +from dataclasses import dataclass + + +@dataclass +class ParentGraphInfo: + """ + Contains information about a module or logger's parent graph. + + Args: + graph_id: The id of the parent graph, determined at runtime. + barrier: The barrier to use to coordinate startup with other modules. + """ + + graph_id: str + startup_barrier: mp.Barrier # type: ignore diff --git a/labgraph/graphs/state.py b/labgraph/graphs/state.py new file mode 100644 index 000000000..ac9c736b6 --- /dev/null +++ b/labgraph/graphs/state.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from contextlib import ContextDecorator +from dataclasses import dataclass +from types import TracebackType +from typing import Any, Callable, Dict, List, Optional, Tuple, Type, TypeVar + + +class StateMeta(type): + def __init__( + cls, name: str, bases: Tuple[type, ...], fields: Dict[str, Any] + ) -> None: + super(StateMeta, cls).__init__(name, bases, fields) + + dataclass(cls) # type: ignore + + +class State(metaclass=StateMeta): + """ + Represents the state of a LabGraph module. State objects are useful when we would + like the module to use some memory to run its algorithm while also being able to: + + - bootstrap that module into some state in the "middle" of its algorithm + - record all internal events of that module for the purpose of replay + """ + + pass diff --git a/labgraph/graphs/stream.py b/labgraph/graphs/stream.py new file mode 100644 index 000000000..df1209ea6 --- /dev/null +++ b/labgraph/graphs/stream.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Optional, Tuple, Type + +from ..messages.message import Message +from ..util.random import random_string + + +STREAM_ID_LENGTH = 16 + + +class Stream: + """ + Represents a stream, which is a sequence of messages that is accessible in + real-time. A stream may be accessed via one or more topics. + """ + + id: str + topic_paths: Tuple[str, ...] + message_type: Optional[Type[Message]] + + def __init__( + self, + topic_paths: Tuple[str, ...], + message_type: Optional[Type[Message]] = None, + id: Optional[str] = None, + ) -> None: + self.topic_paths = topic_paths + self.message_type = message_type + self.id = id or random_string(STREAM_ID_LENGTH) diff --git a/labgraph/graphs/tests/__init__.py b/labgraph/graphs/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/graphs/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/graphs/tests/test_config.py b/labgraph/graphs/tests/test_config.py new file mode 100644 index 000000000..3f454a892 --- /dev/null +++ b/labgraph/graphs/tests/test_config.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from enum import Enum, IntEnum + +import pytest + +from ...util import LabGraphError +from ..config import Config +from ..node import Node + + +class MyIntEnum(IntEnum): + A = 0 + B = 1 + + +class MyStrEnum(str, Enum): + A = "0" + B = "1" + + +class MyConfig(Config): + int_field: int + str_field: str + bool_field: bool + float_field: float + int_enum_field: MyIntEnum + str_enum_field: MyStrEnum + + +class MyNode(Node): + config: MyConfig + + def setup(self) -> None: + self.config + + +def test_config_from_args() -> None: + """ + Test that we can build a config from command-line arguments. + """ + test_args = [ + "--int-field", + "5", + "--str-field", + "hello", + "--float-field", + "0.5", + "--int-enum-field", + "B", + "--str-enum-field", + "A", + "--bool-field", + ] + expected_config = { + "int_field": 5, + "str_field": "hello", + "float_field": 0.5, + "int_enum_field": MyIntEnum.B, + "str_enum_field": MyStrEnum.A, + "bool_field": True, + } + config = MyConfig.fromargs(args=test_args) + assert config.asdict() == expected_config + + +def test_node_config() -> None: + """ + Test that we can provide config to a node. + """ + node = MyNode() + node.configure( + MyConfig( + int_field=5, + str_field="hello", + float_field=0.5, + int_enum_field=MyIntEnum.B, + str_enum_field=MyStrEnum.A, + bool_field=True, + ) + ) + node.setup() + + +def test_node_no_config() -> None: + """ + Test that accessing config on an unconfigured node throws a descriptive exception. + """ + node = MyNode() + + with pytest.raises(LabGraphError) as err: + node.setup() + + assert ( + "Configuration not set. Call MyNode.configure() to set the configuration." + in str(err.value) + ) diff --git a/labgraph/graphs/tests/test_graph.py b/labgraph/graphs/tests/test_graph.py new file mode 100644 index 000000000..acadcae8a --- /dev/null +++ b/labgraph/graphs/tests/test_graph.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Any, Dict + +from ...messages.message import Message +from ..graph import Graph +from ..group import Connections, Group +from ..method import AsyncPublisher, publisher, subscriber +from ..node import Node +from ..topic import Topic + + +pytest_plugins = ["pytest_mock"] + + +def test_incomplete_graph(mocker: Any) -> None: + """ + Tests that an attempted graph with topics that lack publishers and/or subcribers + logs a warning. + """ + logger_module = __name__.rsplit(".", 2)[0] + ".graph.logger" + mock_logger = mocker.patch(logger_module) + + class MyMessage(Message): + int_field: int + + class MyNode(Node): + A = Topic(MyMessage) + B = Topic(MyMessage) + + @subscriber(A) + @publisher(B) + def my_transformer(self, message: MyMessage) -> AsyncPublisher: + pass + + class MyChildGroup(Group): + C = Topic(MyMessage) + MY_NODE1: MyNode + MY_NODE2: MyNode + + def connections(self) -> Connections: + return ((self.C, self.MY_NODE1.A), (self.MY_NODE1.B, self.MY_NODE2.A)) + + class MyParentGroup(Group): + D = Topic(MyMessage) + E = Topic(MyMessage) + MY_CHILD1: MyChildGroup + MY_CHILD2: MyChildGroup + + def connections(self) -> Connections: + return ((self.D, self.MY_CHILD1.C), (self.E, self.MY_CHILD2.MY_NODE1.A)) + + class MyGraph(Graph): + MY_COMPONENT: MyParentGroup + + def logging(self) -> Dict[str, Topic]: + return {"D": self.MY_COMPONENT.D} + + MyGraph() + + expected_message = ( + "MyGraph has unused topics:\n" + "\t- MY_COMPONENT/D has no publishers\n" + "\t- MY_COMPONENT/E has no publishers\n" + "\t- MY_COMPONENT/MY_CHILD1/C has no publishers\n" + "\t- MY_COMPONENT/MY_CHILD1/MY_NODE1/A has no publishers\n" + "\t- MY_COMPONENT/MY_CHILD1/MY_NODE2/B has no subscribers\n" + "\t- MY_COMPONENT/MY_CHILD2/C has no publishers\n" + "\t- MY_COMPONENT/MY_CHILD2/MY_NODE1/A has no publishers\n" + "\t- MY_COMPONENT/MY_CHILD2/MY_NODE2/B has no subscribers\n" + "This could mean that there are publishers and/or subscribers of Cthulhu " + "streams that LabGraph doesn't know about, and/or that data in some topics is " + "being discarded." + ) + + mock_logger.warning.assert_called_with(expected_message) + + +def test_complete_graph() -> None: + """ + Tests that we are able to construct a valid graph where all the topics have + publishers and subscribers. + """ + + class MyMessage(Message): + int_field: int + str_field: str + + class MySource(Node): + A = Topic(MyMessage) + + @publisher(A) + def my_publisher(self) -> AsyncPublisher: + pass + + class MyTransformer(Node): + B = Topic(MyMessage) + C = Topic(MyMessage) + + @subscriber(B) + @publisher(C) + def my_transformer(self, message: MyMessage) -> AsyncPublisher: + pass + + class MySink(Node): + D = Topic(MyMessage) + + @subscriber(D) + def my_subscriber(self, message: MyMessage) -> None: + pass + + class MyGraph(Graph): + MY_SOURCE: MySource + MY_TRANSFORMER: MyTransformer + MY_SINK: MySink + + def connections(self) -> Connections: + return ( + (self.MY_SOURCE.A, self.MY_TRANSFORMER.B), + (self.MY_TRANSFORMER.C, self.MY_SINK.D), + ) + + MyGraph() diff --git a/labgraph/graphs/tests/test_group.py b/labgraph/graphs/tests/test_group.py new file mode 100644 index 000000000..ebfd53210 --- /dev/null +++ b/labgraph/graphs/tests/test_group.py @@ -0,0 +1,290 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Any, Dict, Set, Tuple, Type + +import pytest + +from ...messages.message import Message +from ...util.error import LabGraphError +from ..group import Connections, Group +from ..method import AsyncPublisher, NodeMethod, Transformer, publisher, subscriber +from ..module import Module +from ..node import Node +from ..topic import PATH_DELIMITER, Topic + + +class MyMessage(Message): + int_field: int + + +class MyMessage2(Message): + int_field: int + + +class MyNode(Node): + A = Topic(MyMessage) + B = Topic(MyMessage) + + @subscriber(A) + @publisher(B) + def my_transformer(self, message: MyMessage) -> AsyncPublisher: + pass + + +class MyChildGroup(Group): + C = Topic(MyMessage) + MY_NODE1: MyNode + MY_NODE2: MyNode + + def connections(self) -> Connections: + return ((self.C, self.MY_NODE1.A), (self.MY_NODE1.B, self.MY_NODE2.A)) + + +class MyParentGroup(Group): + D = Topic(MyMessage) + E = Topic(MyMessage2) + MY_CHILD1: MyChildGroup + MY_CHILD2: MyChildGroup + + def connections(self) -> Connections: + return ((self.D, self.MY_CHILD1.C), (self.E, self.MY_CHILD2.MY_NODE1.A)) + + +class MySubclassGroup(MyParentGroup): + F = Topic(MyMessage2) + + def connections(self) -> Connections: + return ( + (self.D, self.MY_CHILD1.C), + (self.E, self.MY_CHILD2.MY_NODE1.A), + (self.E, self.F), + ) + + +parent_group = MyParentGroup() + +expected_streams = ( + ( + parent_group, + ( + ("D", "MY_CHILD1/C", "MY_CHILD1/MY_NODE1/A"), + ("E", "MY_CHILD2/C", "MY_CHILD2/MY_NODE1/A"), + ("MY_CHILD1/MY_NODE1/B", "MY_CHILD1/MY_NODE2/A"), + ("MY_CHILD1/MY_NODE2/B",), + ("MY_CHILD2/MY_NODE1/B", "MY_CHILD2/MY_NODE2/A"), + ("MY_CHILD2/MY_NODE2/B",), + ), + ), + ( + parent_group.MY_CHILD1, + (("C", "MY_NODE1/A"), ("MY_NODE1/B", "MY_NODE2/A"), ("MY_NODE2/B",)), + ), + ( + parent_group.MY_CHILD2, + (("C", "MY_NODE1/A"), ("MY_NODE1/B", "MY_NODE2/A"), ("MY_NODE2/B",)), + ), +) + + +@pytest.mark.parametrize("group,streams", expected_streams) # type: ignore +def test_group_streams(group: Group, streams: Tuple[Tuple[str, ...], ...]) -> None: + stream_paths = tuple( + sorted(stream.topic_paths for stream in group.__streams__.values()) + ) + assert stream_paths == streams + + +expected_descendants = ( + ( + parent_group.MY_CHILD1, + { + "MY_NODE1": parent_group.MY_CHILD1.MY_NODE1, + "MY_NODE2": parent_group.MY_CHILD1.MY_NODE2, + }, + ), + ( + parent_group, + { + "MY_CHILD1": parent_group.MY_CHILD1, + "MY_CHILD2": parent_group.MY_CHILD2, + "MY_CHILD1/MY_NODE1": parent_group.MY_CHILD1.MY_NODE1, + "MY_CHILD1/MY_NODE2": parent_group.MY_CHILD1.MY_NODE2, + "MY_CHILD2/MY_NODE1": parent_group.MY_CHILD2.MY_NODE1, + "MY_CHILD2/MY_NODE2": parent_group.MY_CHILD2.MY_NODE2, + }, + ), +) + + +@pytest.mark.parametrize("group,descendants", expected_descendants) # type: ignore +def test_group_descendants(group: Group, descendants: Dict[str, Any]) -> None: + assert group.__descendants__ == descendants + + +expected_children = ( + ( + parent_group.MY_CHILD1, + { + "MY_NODE1": parent_group.MY_CHILD1.MY_NODE1, + "MY_NODE2": parent_group.MY_CHILD1.MY_NODE2, + }, + ), + ( + parent_group, + {"MY_CHILD1": parent_group.MY_CHILD1, "MY_CHILD2": parent_group.MY_CHILD2}, + ), +) + + +@pytest.mark.parametrize("group,children", expected_children) # type: ignore +def test_group_children(group: Group, children: Dict[str, Module]) -> None: + assert group.__children__ == children + + +expected_methods = ( + ( + parent_group.MY_CHILD1, + { + "MY_NODE1/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_NODE1/B",), + subscribed_topic_path="MY_NODE1/A", + ), + "MY_NODE2/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_NODE2/B",), + subscribed_topic_path="MY_NODE2/A", + ), + }, + ), + ( + parent_group, + { + "MY_CHILD1/MY_NODE1/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_CHILD1/MY_NODE1/B",), + subscribed_topic_path="MY_CHILD1/MY_NODE1/A", + ), + "MY_CHILD1/MY_NODE2/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_CHILD1/MY_NODE2/B",), + subscribed_topic_path="MY_CHILD1/MY_NODE2/A", + ), + "MY_CHILD2/MY_NODE1/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_CHILD2/MY_NODE1/B",), + subscribed_topic_path="MY_CHILD2/MY_NODE1/A", + ), + "MY_CHILD2/MY_NODE2/my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("MY_CHILD2/MY_NODE2/B",), + subscribed_topic_path="MY_CHILD2/MY_NODE2/A", + ), + }, + ), +) + + +@pytest.mark.parametrize("group,methods", expected_methods) # type: ignore +def test_group_methods(group: Group, methods: Dict[str, NodeMethod]) -> None: + for method_path, method in methods.items(): + assert isinstance(group.__methods__[method_path], type(method)) + assert vars(group.__methods__[method_path]) == vars(method) + + +expected_topics = ( + ( + parent_group.MY_CHILD1, + {"C", "MY_NODE1/A", "MY_NODE1/B", "MY_NODE2/A", "MY_NODE2/B"}, + ), + ( + parent_group, + { + "D", + "E", + "MY_CHILD1/C", + "MY_CHILD1/MY_NODE1/A", + "MY_CHILD1/MY_NODE1/B", + "MY_CHILD1/MY_NODE2/A", + "MY_CHILD1/MY_NODE2/B", + "MY_CHILD2/C", + "MY_CHILD2/MY_NODE1/A", + "MY_CHILD2/MY_NODE1/B", + "MY_CHILD2/MY_NODE2/A", + "MY_CHILD2/MY_NODE2/B", + }, + ), +) + + +@pytest.mark.parametrize("group,topics", expected_topics) # type: ignore +def test_group_topics(group: Group, topics: Set[str]) -> None: + for topic_name in topics: + topic = group.__topics__[topic_name] + if PATH_DELIMITER not in topic_name: + assert getattr(group, topic_name) is topic + assert topic.name == topic_name.split(PATH_DELIMITER)[-1] + assert topic.message_type == MyMessage + + +class BadPublishersNode(Node): + A = Topic(MyMessage) + + @publisher(A) + async def pub(self) -> AsyncPublisher: + yield self.A, MyMessage(int_field=1) + + +class BadPublishersGroup(Group): + NODE1: BadPublishersNode + NODE2: BadPublishersNode + + def connections(self) -> Connections: + return ((self.NODE1.A, self.NODE2.A),) + + +def test_bad_publishers_group() -> None: + with pytest.raises(LabGraphError) as err: + _ = BadPublishersGroup() + + assert ( + "The stream for topics (NODE1/A, NODE2/A) has multiple publishers, but only " + "one publisher is allowed. The following publishers were found:\n" + "- NODE1/pub\n" + "- NODE2/pub" in str(err.value) + ) + + +class BadConnectionsGroup1(Group): + def connections(self) -> Connections: + return 5 # type: ignore + + +class BadConnectionsGroup2(Group): + A = Topic(MyMessage) + B = Topic(MyMessage) + + def connections(self) -> Connections: + return (self.A, self.B) # type: ignore + + +class BadConnectionsGroup3(Group): + A = Topic(MyMessage) + B = Topic(MyMessage) + C = Topic(MyMessage) + + def connections(self) -> Connections: + return ((self.A, self.B, self.C),) # type: ignore + + +@pytest.mark.parametrize( + "group_type", (BadConnectionsGroup1, BadConnectionsGroup2, BadConnectionsGroup3) +) +def test_bad_connections_group(group_type: Type[Group]) -> None: + with pytest.raises(TypeError) as err: + group = group_type() + + +def test_subclass_group() -> None: + subclass_group = MySubclassGroup() diff --git a/labgraph/graphs/tests/test_harness.py b/labgraph/graphs/tests/test_harness.py new file mode 100644 index 000000000..da6c6cdcd --- /dev/null +++ b/labgraph/graphs/tests/test_harness.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import dataclasses + +import pytest + +from ...messages.message import Message +from ..config import Config +from ..method import AsyncPublisher, publisher, subscriber +from ..node import Node +from ..node_test_harness import NodeTestHarness, run_async, run_with_harness +from ..state import State +from ..topic import Topic + + +NUM_MESSAGES = 10 + + +class MyMessage(Message): + my_field: int + + +class MyConfig(Config): + my_field: int + + +class MyState(State): + counter: int + + +class MyNode(Node): + config: MyConfig + state: MyState + + A = Topic(MyMessage) + B = Topic(MyMessage) + + def setup(self) -> None: + # Some simple state we can set to check that setup() executed + self.other_state: int = 5 + + # A simple publisher + @publisher(A) + async def my_publisher(self) -> AsyncPublisher: + for i in range(NUM_MESSAGES): + yield self.A, MyMessage(my_field=i) + + # A simple subscriber that updates state (used by the test to check it ran) + @subscriber(B) + async def my_subscriber(self, message: MyMessage) -> None: + self.state.counter = message.my_field + + def cleanup(self) -> None: + # Update the state so we can check cleanup() ran + self.other_state = 6 + + +def test_get_node() -> None: + """ + Test NodeTestHarness.get_node() + """ + harness = NodeTestHarness(MyNode) + with harness.get_node( + config=MyConfig(1), state=MyState(counter=-1) # type: ignore + ) as node: # type: ignore + # Ensure node is of correct type + assert isinstance(node, MyNode) + # Check the node has its config set + assert node.config.asdict() == {"my_field": 1} + # Check the node has its state set + assert dataclasses.asdict(node.state) == {"counter": -1} + # Check the node ran setup() + assert node.other_state == 5 + + # Check the node ran cleanup() after leaving the with block + assert node.other_state == 6 + + +def test_run_async() -> None: + """ + Test run_async() + """ + harness = NodeTestHarness(MyNode) + with harness.get_node( + config=MyConfig(1), state=MyState(counter=-1) # type: ignore + ) as node: # type: ignore + # Run the async publisher function and assert its yielded messages + publish_result = run_async(node.my_publisher) + assert len(publish_result) == NUM_MESSAGES + assert [message.asdict() for _, message in publish_result] == [ + {"my_field": i} for i in range(NUM_MESSAGES) + ] + + # Run the async subscriber function + run_async(node.my_subscriber, args=[MyMessage(my_field=20)]) # type: ignore + # Assert that the subscriber function ran + assert node.state.counter == 20 + + +def test_run_with_harness() -> None: + """ + Test run_with_harness() + """ + publish_result = run_with_harness( + MyNode, + MyNode.my_publisher, + config=MyConfig(1), + state=MyState(counter=1), # type: ignore + ) + assert len(publish_result) == NUM_MESSAGES + assert [message.asdict() for _, message in publish_result] == [ + {"my_field": i} for i in range(NUM_MESSAGES) + ] + + +def test_run_with_harness_max_num_results() -> None: + """ + Test passing max_num_results to run_with_harness + """ + publish_result = run_with_harness( + MyNode, + MyNode.my_publisher, + config=MyConfig(1), + state=MyState(counter=1), # type: ignore + max_num_results=1, + ) + assert len(publish_result) == 1 + + # Check that using max_num_results with a non-generator raises + with pytest.raises(TypeError): + run_with_harness(MyNode, _not_a_generator, max_num_results=1) # type: ignore + + +def test_run_async_max_num_results() -> None: + """ + Test passing max_num_results to run_async + """ + harness = NodeTestHarness(MyNode) + with harness.get_node( + config=MyConfig(1), state=MyState(counter=-1) # type: ignore + ) as node: # type: ignore + publish_result = run_async(node.my_publisher, max_num_results=1) + assert len(publish_result) == 1 + + # Check that using max_num_results with a non-generator raises + with pytest.raises(TypeError): + run_async(_not_a_generator, max_num_results=1) # type: ignore + + +async def _not_a_generator() -> None: + pass diff --git a/labgraph/graphs/tests/test_module.py b/labgraph/graphs/tests/test_module.py new file mode 100644 index 000000000..fc6c0694d --- /dev/null +++ b/labgraph/graphs/tests/test_module.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Type + +import pytest + +from ...messages.message import Message +from ..module import Module +from ..topic import PATH_DELIMITER, Topic + + +class MyMessageA(Message): + """ + Simple message type for testing topics. + """ + + a: int + + +class MyMessageB(Message): + """ + Simple message type for testing topics. + """ + + b: float + + +class MyModule(Module): + """ + Simple child module class for testing. + """ + + A = Topic(message_type=MyMessageA) + B = Topic(message_type=MyMessageB) + + def __init__(self) -> None: + super(MyModule, self).__init__() + + +module = MyModule() + +expected_topics = (("A", MyMessageA), ("B", MyMessageB)) + + +@pytest.mark.parametrize("topic_name,message_type", expected_topics) # type: ignore +def test_topics(topic_name: str, message_type: Type[Message]) -> None: + """ + Tests that MyModule has the correct topics. + """ + topic = module.__topics__[topic_name] + assert getattr(module, topic_name) is topic + assert isinstance(topic, Topic) + assert topic.message_type == message_type + assert topic.name == topic_name diff --git a/labgraph/graphs/tests/test_node.py b/labgraph/graphs/tests/test_node.py new file mode 100644 index 000000000..8aa2f4fbe --- /dev/null +++ b/labgraph/graphs/tests/test_node.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Dict, Type + +import pytest + +from ...messages.message import Message +from ...util.error import LabGraphError +from ..method import ( + AsyncPublisher, + NodeMethod, + Publisher, + Subscriber, + Transformer, + publisher, + subscriber, +) +from ..node import Node +from ..topic import Topic + + +class MyMessage(Message): + int_field: int + + +class MyNode(Node): + A = Topic(MyMessage) + B = Topic(MyMessage) + + @subscriber(A) + def my_subscriber(self, message: MyMessage) -> None: + pass + + @publisher(A) + def my_publisher(self, message: MyMessage) -> AsyncPublisher: + pass + + @subscriber(A) + @publisher(B) + def my_transformer(self, message: MyMessage) -> AsyncPublisher: + pass + + +node = MyNode() + +expected_node_methods = ( + ( + MyNode, + { + "my_publisher": Publisher( + name="my_publisher", published_topic_paths=("A",) + ), + "my_subscriber": Subscriber( + name="my_subscriber", subscribed_topic_path="A" + ), + "my_transformer": Transformer( + name="my_transformer", + published_topic_paths=("B",), + subscribed_topic_path="A", + ), + }, + ), +) + + +@pytest.mark.parametrize("node_type,methods", expected_node_methods) # type: ignore +def test_node_methods(node_type: Type[Node], methods: Dict[str, NodeMethod]) -> None: + """ + Tests that MyNode has the expected NodeMethod objects. + """ + node = node_type() + for method_name, method in methods.items(): + assert isinstance(node.__methods__[method_name], type(method)) + assert vars(node.__methods__[method_name]) == vars(method) + + +def test_node_invalid_published_topic() -> None: + bad_topic = Topic(MyMessage) + with pytest.raises(LabGraphError) as err: + + class BadTopicNode(Node): + @publisher(bad_topic) + def my_publisher(self) -> AsyncPublisher: + pass + + assert ( + "Invalid topic published by BadTopicNode.my_publisher - set the topic as a " + "class variable in BadTopicNode" in str(err.value) + ) + + +def test_node_invalid_subscribed_topic() -> None: + bad_topic = Topic(MyMessage) + with pytest.raises(LabGraphError) as err: + + class BadTopicNode(Node): + @subscriber(bad_topic) + def my_subscriber(self, message: MyMessage) -> None: + pass + + assert ( + "Invalid topic subscribed to by BadTopicNode.my_subscriber - set the topic as " + "a class variable in BadTopicNode" in str(err.value) + ) + + +class BadPublishersNode(Node): + OUTPUT = Topic(MyMessage) + + @publisher(OUTPUT) + async def bad_publisher1(self) -> AsyncPublisher: + yield self.OUTPUT, MyMessage(int_field=1) + + @publisher(OUTPUT) + async def bad_publisher2(self) -> AsyncPublisher: + yield self.OUTPUT, MyMessage(int_field=1) + + +def test_bad_publishers_node() -> None: + with pytest.raises(LabGraphError) as err: + _ = BadPublishersNode() + + assert ( + "The stream for topics (OUTPUT) has multiple publishers, but only one " + "publisher is allowed. The following publishers were found:\n" + "- bad_publisher1\n" + "- bad_publisher2" in str(err.value) + ) diff --git a/labgraph/graphs/tests/test_publisher.py b/labgraph/graphs/tests/test_publisher.py new file mode 100644 index 000000000..ebdb0db75 --- /dev/null +++ b/labgraph/graphs/tests/test_publisher.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import pytest + +from ...messages.message import Message +from ...util.error import LabGraphError +from ..method import AsyncPublisher, publisher +from ..topic import Topic + + +class MyMessage(Message): + int_field: int + + +def test_duplicate_publisher() -> None: + with pytest.raises(LabGraphError) as err: + A = Topic(MyMessage) + + @publisher(A) + @publisher(A) + def my_publisher() -> AsyncPublisher: + pass + + assert ( + "Method 'my_publisher' got two @publisher decorators for the same topic" + in str(err.value) + ) + + +def test_multiple_publisher() -> None: + A = Topic(MyMessage) + B = Topic(MyMessage) + + @publisher(A) + @publisher(B) + def my_publisher() -> AsyncPublisher: + pass diff --git a/labgraph/graphs/tests/test_subscriber.py b/labgraph/graphs/tests/test_subscriber.py new file mode 100644 index 000000000..cb4cde766 --- /dev/null +++ b/labgraph/graphs/tests/test_subscriber.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import pytest + +from ...messages.message import Message +from ...util.error import LabGraphError +from ..method import subscriber +from ..node import Node +from ..topic import Topic + + +class MyMessage(Message): + int_field: int + + +def test_duplicate_subscriber() -> None: + """ + Tests that an error is thrown when multiple subscriber decorators are applied to a + method. + """ + with pytest.raises(LabGraphError) as err: + + class MyNode(Node): + A = Topic(MyMessage) + + @subscriber(A) + @subscriber(A) + def my_subscriber(self, message: MyMessage) -> None: + pass + + assert "Method 'my_subscriber' already has a @subscriber decorator" in str( + err.value + ) + + +def test_subscriber_signature() -> None: + """ + Tests that an error is thrown when a subscriber has an invalid signature for message + callbacks. + """ + with pytest.raises(LabGraphError) as err: + + class MyNode(Node): + A = Topic(MyMessage) + + @subscriber(A) + def my_subscriber(self) -> None: + pass + + assert ( + "Expected subscriber 'my_subscriber' to have signature def my_subscriber(self, " + "message: MyMessage) -> None" + ) in str(err.value) diff --git a/labgraph/graphs/topic.py b/labgraph/graphs/topic.py new file mode 100644 index 000000000..073d83be0 --- /dev/null +++ b/labgraph/graphs/topic.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import ABC, ABCMeta, abstractmethod +from collections import namedtuple +from copy import deepcopy +from typing import Any, Dict, NamedTuple, Optional, Tuple, Type, Union, cast + +from ..messages.message import Message +from ..util.error import LabGraphError + + +PATH_DELIMITER = "/" + + +class Topic: + """ + Represents a topic in a graph. A user can instantiate this in a `Module` in + order to add the topic to their graph. The name of the topic is inferred + from the class variable to which it is assigned - it remains `None` until + then. It is referred to via its class variable, which has the added benefit + of being possible to check for correctness statically. Note that topics are + basically references to streams, and multiple topics can reference the same + stream by connecting them via `Group.connections`. + + Args: + message_type: The message type for messages that are in this topic. + """ + + message_type: Type[Message] + + def __init__(self, message_type: Type[Message]) -> None: + self.message_type = message_type + self._name: Optional[str] = None + + def _assign_name(self, name: str) -> None: + assert self._name is None + self._name = name + + @property + def name(self) -> str: + assert self._name is not None + return self._name diff --git a/labgraph/loggers/__init__.py b/labgraph/loggers/__init__.py new file mode 100644 index 000000000..da9ed86ad --- /dev/null +++ b/labgraph/loggers/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = ["Logger", "LoggerConfig"] + +from .logger import Logger, LoggerConfig diff --git a/labgraph/loggers/hdf5/__init__.py b/labgraph/loggers/hdf5/__init__.py new file mode 100644 index 000000000..c0c12473b --- /dev/null +++ b/labgraph/loggers/hdf5/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = ["HDF5Logger"] + +from .logger import HDF5Logger diff --git a/labgraph/loggers/hdf5/logger.py b/labgraph/loggers/hdf5/logger.py new file mode 100644 index 000000000..d5504e904 --- /dev/null +++ b/labgraph/loggers/hdf5/logger.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import logging +import threading +from pathlib import Path +from typing import Any, Callable, Mapping, Optional, Sequence, Tuple, Union + +import h5py +import numpy as np + +from ...graphs.parent_graph_info import ParentGraphInfo +from ...graphs.stream import Stream +from ...graphs.topic import PATH_DELIMITER +from ...messages.message import Message +from ...messages.types import ( + T_I, + BoolType, + BytesType, + CFloatType, + CIntType, + DynamicType, + FieldType, + FloatType, + IntEnumType, + IntType, + NumpyDynamicType, + NumpyType, + StrDynamicType, + StrEnumType, + StrType, + T, +) +from ...util.error import LabGraphError +from ..logger import Logger + + +HDF5_PATH_DELIMITER = "/" + +logger = logging.getLogger(__name__) + + +class HDF5Logger(Logger): + """ + Represents a logger that writes messages to an HDF5 file. + """ + + def setup(self) -> None: + super().setup() + output_path = Path(self.config.output_directory) / Path( + f"{self.config.recording_name}.h5" + ) + logger.info(f"logging to {output_path}") + self.file = h5py.File(str(output_path), "w") + self.file_lock = threading.Lock() # Prevents file close while writing + + def write(self, messages_by_logging_id: Mapping[str, Sequence[Message]]) -> None: + with self.file_lock: + if self.file is None: + num_messages = sum( + len(messages) for messages in messages_by_logging_id.values() + ) + logger.warn(f"dropping {num_messages} messages while stopping") + return + for logging_id, messages in messages_by_logging_id.items(): + hdf5_path = logging_id + group_path = "/" + HDF5_PATH_DELIMITER.join( + hdf5_path.split(PATH_DELIMITER)[:-1] + ) + group = self.file.require_group(group_path) + + dataset_dtype = np.dtype( + [ + (field.name, *get_numpy_type_for_field_type(field.data_type)) + for field in messages[0].__class__.__message_fields__.values() + ] + ) + + dataset_name = hdf5_path.split(PATH_DELIMITER)[-1] + if dataset_name not in group: + dataset = group.create_dataset( + dataset_name, + shape=(len(messages),), + maxshape=(None,), + dtype=dataset_dtype, + ) + else: + dataset = group[dataset_name] + dataset.resize(len(dataset) + len(messages), 0) + + for i, message in enumerate(messages): + # Convert dynamic-length bytes fields into numpy arrays so h5py can + # read/write them + message_fields = list(message.astuple()) + for j, value in enumerate(message_fields): + if not isinstance( + list(message.__class__.__message_fields__.values())[ + j + ].data_type, + DynamicType, + ): + continue + if isinstance(value, bytes): + message_fields[j] = np.array(bytearray(value)) + elif isinstance(value, bytearray): + message_fields[j] = np.array(value) + + dataset[-len(messages) + i] = tuple(message_fields) + + self.file.flush() + + def cleanup(self) -> None: + super().cleanup() + if self.file is not None: + with self.file_lock: + output_path = Path(self.config.output_directory) / Path( + f"{self.config.recording_name}.h5" + ) + logger.info(f"closing hdf5 file ({output_path})") + self.file.close() + self.file = None + + +def get_numpy_type_for_field_type( + field_type: FieldType[T], +) -> Union[Tuple[np.dtype], Tuple[np.dtype, Tuple[int, ...]]]: + if ( + isinstance(field_type, StrType) + or isinstance(field_type, BytesType) + or isinstance(field_type, StrEnumType) + ): + encoding = ( + field_type.encoding if field_type in (StrType, StrEnumType) else "ascii" + ) + return (h5py.string_dtype(encoding=encoding, length=field_type.length),) + elif isinstance(field_type, IntType) or isinstance(field_type, IntEnumType): + return (get_numpy_type_for_int_type(field_type),) + elif isinstance(field_type, FloatType): + return (get_numpy_type_for_float_type(field_type),) + elif isinstance(field_type, BoolType): + return (np.bool,) + elif isinstance(field_type, NumpyType): + return (field_type.dtype, field_type.shape) + elif isinstance(field_type, DynamicType): + return (get_dynamic_type(field_type),) + + raise LabGraphError(f"No equivalent numpy type for field type: {field_type}") + + +def get_numpy_type_for_int_type(int_type: Union[IntType, IntEnumType[T_I]]) -> np.dtype: + return { + CIntType.CHAR: np.int8, + CIntType.UNSIGNED_CHAR: np.uint8, + CIntType.SHORT: np.int16, + CIntType.UNSIGNED_SHORT: np.uint16, + CIntType.INT: np.int32, + CIntType.UNSIGNED_INT: np.uint32, + CIntType.LONG: np.int64, + CIntType.UNSIGNED_LONG: np.uint64, + CIntType.UNSIGNED_LONG_LONG: np.uint64, + CIntType.LONG_LONG: np.int64, + }[int_type.c_type] + + +def get_numpy_type_for_float_type(float_type: FloatType) -> np.dtype: + return {CFloatType.FLOAT: np.float32, CFloatType.DOUBLE: np.float64}[ + float_type.c_type + ] + + +def get_dynamic_type(field_type: FieldType[Any]) -> np.dtype: + if isinstance(field_type, StrDynamicType): + return h5py.string_dtype(encoding=field_type.encoding) + elif isinstance(field_type, NumpyDynamicType): + return h5py.vlen_dtype(field_type.dtype) + else: + return h5py.vlen_dtype(np.uint8) diff --git a/labgraph/loggers/logger.py b/labgraph/loggers/logger.py new file mode 100644 index 000000000..c2ba3e78b --- /dev/null +++ b/labgraph/loggers/logger.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import ctypes +import functools +import multiprocessing as mp +import tempfile +import threading +import time +import traceback +from abc import ABC, abstractmethod +from dataclasses import field +from typing import Callable, Dict, List, Mapping, Optional, Sequence, Tuple, Type + +from .._cthulhu.cthulhu import Consumer, Mode, get_stream +from ..graphs.config import Config +from ..graphs.method import background +from ..graphs.node import Node +from ..graphs.stream import Stream +from ..messages.message import Message +from ..util.logger import get_logger +from ..util.random import random_string + + +logger = get_logger(__name__) + + +class LoggerConfig(Config): + """ + Describes configuration for a logger. + + Args: + output_directory: The directory in which to log streams to disk. + recording_name: + The name of the recording. Logger implementations will use this argument to + build the filename(s) for the logs. + buffer_size: + The size of the buffer the logger will keep in memory before flushing to + disk. + flush_period: + The time (in seconds) after which the logger will periodically flush to + disk. Defaults to 1 second. If `None`, the logger will only flush when the + buffer is full. + streams_by_logging_id: + A dictionary of the LabGraph stream objects by logging id. When specified, + the logger will subscribe to the Cthulhu streams itself. This should always + be provided unless the logger is being unit tested. + """ + + output_directory: str = field(default_factory=tempfile.gettempdir) + recording_name: str = field(default_factory=functools.partial(random_string, 16)) + buffer_size: int = 100 + flush_period: Optional[float] = 1 + streams_by_logging_id: Dict[str, Stream] = field(default_factory=dict) + + +class Logger(Node): + config: LoggerConfig + + def setup(self) -> None: + self.buffer: List[Tuple[str, Message]] = [] + self.running: bool = False + + self.consumers: Dict[str, Consumer] = {} + for logging_id, stream in self.config.streams_by_logging_id.items(): + callback = self._get_logger_callback(logging_id, stream) + + stream_interface = get_stream(stream.id) + assert ( + stream_interface is not None + ), f"Expected stream '{stream.id}' to be created" + self.consumers[stream.id] = Consumer( + stream_interface=stream_interface, + sample_callback=callback, + mode=Mode.SYNC, + stream_id=stream.id, + ) + + @abstractmethod + def write(self, messages_by_logging_id: Mapping[str, Sequence[Message]]) -> None: + """ + Writes messages to disk. + + Args: + messages_by_logging_id: + The messages to write to disk, keyed by the logging id to write to. + """ + raise NotImplementedError() + + @background + async def run_logger(self) -> None: + import asyncio + + loop = asyncio.get_event_loop() + + self.running = True + buffer_size = self.config.buffer_size + flush_period = self.config.flush_period + last_flushed_at = time.perf_counter() + while self.running: + current_time = time.perf_counter() + if len(self.buffer) >= buffer_size or ( + flush_period is not None + and current_time - last_flushed_at >= flush_period + ): + last_flushed_at = current_time + flushed_buffer = self.flush_buffer() + if sum(len(messages) for messages in flushed_buffer.values()) > 0: + await loop.run_in_executor(None, self.write, flushed_buffer) + await asyncio.sleep(0.01) + + def buffer_message(self, logging_id: str, message: Message) -> None: + self.buffer.append((logging_id, message)) + + def flush_buffer(self) -> Dict[str, List[Message]]: + self.buffer, flushed_buffer = [], self.buffer + result: Dict[str, List[Message]] = {} + for logging_id, message in flushed_buffer: + if logging_id not in result: + result[logging_id] = [message] + else: + result[logging_id].append(message) + return result + + def _get_logger_callback( + self, logging_id: str, stream: Stream + ) -> Callable[[Message], None]: + # We add the correct type annotation so LabGraph knows what message type to + # deserialize to + assert stream.message_type is not None + MessageType: Type[Message] = stream.message_type + + def callback(message: MessageType) -> None: # type: ignore + self.buffer_message(logging_id, message) + + return callback + + def cleanup(self) -> None: + self.running = False + if len(self.buffer) > 0: + self.write(self.flush_buffer()) diff --git a/labgraph/loggers/tests/__init__.py b/labgraph/loggers/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/loggers/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/loggers/tests/test_loggers.py b/labgraph/loggers/tests/test_loggers.py new file mode 100644 index 000000000..0d73465c2 --- /dev/null +++ b/labgraph/loggers/tests/test_loggers.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import random +import time +from typing import Callable, Dict, List, Mapping, Optional, Sequence, Tuple + +import numpy as np + +from ..._cthulhu.cthulhu import Mode, Producer, register_stream +from ...graphs.parent_graph_info import ParentGraphInfo +from ...graphs.stream import Stream +from ...messages.message import Message +from ...util.random import random_string +from ...util.testing import get_event_loop, local_test +from ..logger import Logger, LoggerConfig + + +NUM_MESSAGES_PER_STREAM = 100 +MESSAGE_RATE = 100 + + +class MyMessage1(Message): + int_field: int + + +class MyMessage2(Message): + str_field: str + + +class MyMessage3(Message): + bool_field: bool + + +class NaiveLogger(Logger): + """ + Naive logger for testing that simply appends messages to a buffer. Also adds a @main + method that kills the + """ + + def setup(self) -> None: + super().setup() + self.output: Dict[str, List[Message]] = {} + + def write(self, messages_by_logging_id: Mapping[str, Sequence[Message]]) -> None: + for logging_id, messages in messages_by_logging_id.items(): + if logging_id not in self.output: + self.output[logging_id] = list(messages) + else: + self.output[logging_id] += list(messages) + + +@local_test +def test_logger() -> None: + """ + Test that the naive logger receives all messages sent via Cthulhu. + """ + logging_ids = (random_string(16), random_string(16), random_string(16)) + stream_ids = (random_string(16), random_string(16), random_string(16)) + message_types = (MyMessage1, MyMessage2, MyMessage3) + streams_by_logging_id = { + logging_ids[i]: Stream( + id=stream_ids[i], + topic_paths=(f"MY_NODE/{'ABC'[i]}",), + message_type=message_types[i], + ) + for i in range(3) + } + + cthulhu_streams_by_id = { + stream_ids[i]: register_stream( + name=stream_ids[i], message_type=message_types[i] + ) + for i in range(3) + } + + producers = { + stream_id: Producer(stream_interface=stream_interface, mode=Mode.SYNC) + for stream_id, stream_interface in cthulhu_streams_by_id.items() + } + + producers_and_messages: List[Tuple[Producer, Message]] = [] + for i in range(NUM_MESSAGES_PER_STREAM): + producers_and_messages.append( + (producers[stream_ids[0]], MyMessage1(int_field=i)) + ) + producers_and_messages.append( + (producers[stream_ids[1]], MyMessage2(str_field=str(i))) + ) + producers_and_messages.append( + (producers[stream_ids[2]], MyMessage3(bool_field=i % 2 == 0)) + ) + random.shuffle(producers_and_messages) + messages = [p[1] for p in producers_and_messages] + + config = LoggerConfig(streams_by_logging_id=streams_by_logging_id) + logger = NaiveLogger() + logger.configure(config) + logger.setup() + + import asyncio + + loop = get_event_loop() + loop.run_until_complete( + asyncio.gather( + logger.run_logger(), _write_messages(logger, producers_and_messages) + ) + ) + + logger.cleanup() + + for producer in producers.values(): + producer.close() + + expected_int_values = [ + message.int_field for message in messages if isinstance(message, MyMessage1) + ] + actual_int_values = [message.int_field for message in logger.output[logging_ids[0]]] + assert sorted(expected_int_values) == sorted(actual_int_values) + + expected_str_values = [ + message.str_field for message in messages if isinstance(message, MyMessage2) + ] + actual_str_values = [message.str_field for message in logger.output[logging_ids[1]]] + assert sorted(expected_str_values) == sorted(actual_str_values) + + expected_bool_values = [ + message.bool_field for message in messages if isinstance(message, MyMessage3) + ] + actual_bool_values = [ + message.bool_field for message in logger.output[logging_ids[2]] + ] + assert sorted(expected_bool_values) == sorted(actual_bool_values) + + +async def _write_messages( + logger: Logger, producers_and_messages: List[Tuple[Producer, Message]] +) -> None: + import asyncio + + for producer, message in producers_and_messages: + producer.produce_message(message) + await asyncio.sleep(1.0 / MESSAGE_RATE) + + logger.running = False diff --git a/labgraph/messages/__init__.py b/labgraph/messages/__init__.py new file mode 100644 index 000000000..5986aec83 --- /dev/null +++ b/labgraph/messages/__init__.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "BytesType", + "CFloatType", + "CIntType", + "FieldType", + "FloatType", + "IntType", + "Message", + "NumpyDynamicType", + "NumpyType", + "StrType", + "TimestampedMessage", +] + +from .message import Message, TimestampedMessage +from .types import ( + BytesType, + CFloatType, + CIntType, + FieldType, + FloatType, + IntType, + NumpyDynamicType, + NumpyType, + StrType, +) diff --git a/labgraph/messages/message.py b/labgraph/messages/message.py new file mode 100644 index 000000000..93adb0872 --- /dev/null +++ b/labgraph/messages/message.py @@ -0,0 +1,501 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# Defines simple messaging constructs for LabGraph + +import dataclasses +import hashlib +import logging +import struct +from collections import OrderedDict +from typing import Any, Dict, Generic, Optional, Tuple, Type, TypeVar, Union + +from .._cthulhu.bindings import ( + Field as CthulhuField, + memoryPool, + StreamSample, + TypeDefinition, + typeRegistry, +) +from ..util.error import LabGraphError +from .types import DEFAULT_BYTE_ORDER, FieldType, StructType, get_field_type + + +logger = logging.getLogger(__name__) + +T = TypeVar("T") + +# Internal fields that are present on Message instances but are not included when +# serializing the message for streaming +LOCAL_INTERNAL_FIELDS = ( + "__sample__", + "__original_message__", + "__original_message_type__", +) + + +class Field(Generic[T]): + """ + Represents a field in a LabGraph message. + + Args: + name: The name of the field. + data_type: The data type of the field. + offset: The offset of the field's data within a message in memory. + """ + + name: str + data_type: FieldType[T] + offset: int + dataclasses_field: dataclasses.Field # type: ignore + + def __init__( + self, + name: str, + data_type: FieldType[T], + offset: int, + dataclasses_field: dataclasses.Field, # type: ignore + ) -> None: + self.name = name + self.data_type = data_type + self.offset = offset + self.dataclasses_field = dataclasses_field + + @property + def required(self) -> bool: + return ( + self.dataclasses_field.default == dataclasses.MISSING + and self.dataclasses_field.default_factory # type: ignore + == dataclasses.MISSING + ) + + def get_default_value(self) -> T: + assert not self.required + if self.dataclasses_field.default != dataclasses.MISSING: + value = self.dataclasses_field.default + else: + value = self.dataclasses_field.default_factory() # type: ignore + + assert self.data_type.isinstance(value), ( + f"Expected default value for field '{self.name}' to match type " + f"'{self.data_type.description}', got value {value}" + ) + return value # type: ignore + + +class MessageMeta(type): + """ + Metaclass for messages. Responsible for collecting field information from the + class's type annotations. Works similarly to the builtin `dataclasses` module but is + not compatible with it. When any class is defined using this metaclass, we also + register a corresponding Cthulhu type. + """ + + __message_size__: int + __message_fields__: "OrderedDict[str, Field[Any]]" + __format_string__: str + __num_dynamic_fields__: int + + def __init__( + cls, name: str, bases: Tuple[type, ...], members: Dict[str, Any] + ) -> None: + super(MessageMeta, cls).__init__(name, bases, members) + + # Make the class a dataclass + dataclasses.dataclass(frozen=True, init=False, eq=False)(cls) # type: ignore + assert dataclasses.is_dataclass(cls) + + # Emulate the __post_init__ method from a normal dataclasses + if not hasattr(cls, "__post_init__"): + cls.__post_init__ = lambda self: None + + # Use big endian by default for all IPC communications + cls.__format_string__ = DEFAULT_BYTE_ORDER.value + cls.__message_fields__ = OrderedDict([]) + cls.__num_dynamic_fields__ = 0 + + # Collect field information using the dataclass's fields + if hasattr(cls, "__annotations__"): + for field in dataclasses.fields(cls): + if field.name in LOCAL_INTERNAL_FIELDS: + # Skip local internal fields (not serialized) + continue + + # Add a field, substituting a primitive Python type for a `FieldType` + # when possible + + data_type = ( + field.type + if isinstance(field.type, FieldType) + else get_field_type(field.type) + ) + + if data_type.size is None: + my_field = Field( + name=field.name, + data_type=data_type, + offset=cls.__num_dynamic_fields__, + dataclasses_field=field, + ) + cls.__num_dynamic_fields__ += 1 + elif isinstance(data_type, StructType): + my_field = Field( + name=field.name, + data_type=data_type, + offset=struct.calcsize(cls.__format_string__), + dataclasses_field=field, + ) + cls.__format_string__ += data_type.format_string + else: + raise NotImplementedError( + f"Unexpected field type {data_type.__class__}" + ) + + cls.__message_fields__[my_field.name] = my_field + + cls.__message_size__ = struct.calcsize(cls.__format_string__) + + logger.debug( + f"{cls.__name__}:registering cthulhu type with length " + f"{cls.__message_size__}" + ) + + # Register this message type with Cthulhu + type_definition = TypeDefinition() + type_definition.typeName = cls.versioned_name + type_definition.sampleParameterSize = cls.__message_size__ + type_definition.sampleNumberDynamicFields = cls.__num_dynamic_fields__ + type_definition.hasContentBlock = True + type_definition.sampleFields = { + field.name: CthulhuField( + field.offset, + field.data_type.size or 1, # 1 if pointer to dynamic field + "uint8_t", + field.data_type.size or 1, # 1 if pointer to dynamic field + field.data_type.size is None, + ) + for field in cls.__message_fields__.values() + } + typeRegistry().registerType(type_definition) + + type_id = typeRegistry().findTypeName(cls.versioned_name).typeID + logger.debug(f"{cls.__name__}:registered cthulhu type with ID {type_id}") + + def __call__(cls, *args: Any, **kwds: Any) -> Any: + instance = type.__call__(cls, *args, **kwds) + instance.__post_init__() + return instance + + @property + def full_name(cls) -> str: + """ + Returns the fully qualified name of the message type (i.e., including + its module name). + """ + return f"{cls.__module__}.{cls.__name__}" + + def __eq__(cls, other: Any) -> bool: + """ + Returns true if this message type is equivalent to the other message type. + Message types are equivalent if they have the same number of fields, and the + length of each field is the same. + """ + if not isinstance(other, MessageMeta): + return False + if len(cls.__message_fields__) != len(other.__message_fields__): + return False + for arg1, arg2 in zip( + cls.__message_fields__.values(), other.__message_fields__.values() + ): + if arg1.data_type.python_type != arg2.data_type.python_type: + return False + if ( + arg1.data_type.size is not None + and arg2.data_type.size is not None + and arg1.data_type.size != arg2.data_type.size + ): + return False + return True + + def __hash__(cls) -> int: + """ + Returns the hash of the message type. + """ + return hash(tuple(cls.__message_fields__.values())) + + @property + def versioned_name(cls) -> str: + """ + Returns a name for the message type that is versioned. When the memory layout + of the message type (i.e., its format string) changes, the versioned name + changes as well. + """ + # TODO: Remove dependency on `versioned_name` for message equivalency (see + # T64643702, https://fb.quip.com/1dcNAmzas8No) + hash_input = f"{cls.__format_string__},{cls.__num_dynamic_fields__}" + fields_hash = hashlib.sha256(hash_input.encode("ascii")).hexdigest() + return f"{cls.full_name}:{fields_hash}" + + def _index_of_field(cls, field_name: str) -> int: + """ + Returns the index of the field named `field_name`. + + Args: + field_name: The name of the field. + """ + for i, (_, field) in enumerate(cls.__message_fields__.items()): + if field.name == field_name: + return i + raise LabGraphError(f"{cls.__name__} has no field '{field_name}'") + + +class IsOriginalMessage: + pass + + +M = TypeVar("M", bound="Message", covariant=True) + + +class Message(metaclass=MessageMeta): + """ + Represents a LabGraph message. A message is a collection of data that can be sent + between nodes via topics. The fields available to every message of a certain type + are defined via type annotations on the corresponding subclass of `Message`. + Subclasses recursively include their superclasses' fields. + + Messages can be thought of as similar to (but not compatible with) instances of + dataclasses in the builtin `dataclasses` module. + + Messages' data are stored in shared memory via Cthulhu, meaning the transmission of + messages between nodes requires no copying of data. + """ + + # If __original_message_type__ is set, then we cache an instance of that class for + # faster message reading + __original_message__: Optional[Union["Message", IsOriginalMessage]] + + # Cthulhu sample that backs this message - the Cthulhu sample manages this message's + # shared memory + __sample__: StreamSample + + __original_message_type__: Optional[Type["Message"]] + + def __init__(self, *args: Any, **kwargs: Any) -> None: + super().__setattr__("__original_message__", None) + super().__setattr__("__original_message_type__", None) + if 1 <= len(kwargs) <= 2 and "__sample__" in kwargs.keys(): + # Option to create a message directly from Cthulhu sample + # Bypasses frozen check due to `frozen=True` by calling `__setattr__` on + # `object` + if "__original_message_type__" in kwargs.keys(): + super().__setattr__( + "__original_message_type__", kwargs["__original_message_type__"] + ) + super().__setattr__("__sample__", kwargs["__sample__"]) + return + + # Otherwise, build up a Cthulhu sample using the provided arguments + + cls = type(self) + + # Build a dictionary of values + values: Dict[str, Any] = {} + + # Add to the dictionary from the positional arguments + for i, arg in enumerate(args): + # Check that there are as many kwargs as non-internal fields on this message + # type + if len(values) == len(cls.__message_fields__): + raise TypeError( + f"__init__() takes {len(cls.__message_fields__)} positional " + f"arguments but {len(args)} were given" + ) + values[list(cls.__message_fields__.keys())[i]] = arg + + # Add to the dictionary from the keyword arguments + for key, value in kwargs.items(): + if key in values: + raise TypeError( + f"__init__() for {cls.__name__} got multiple values for argument " + f"'{key}'" + ) + elif key not in cls.__message_fields__: + raise TypeError( + f"__init__() for {cls.__name__} got an unexpected keyword argument " + f"'{key}'" + ) + + values[key] = value + + # Ensure we have all required values, and fill in default values + for field in cls.__message_fields__.values(): + if field.name not in values.keys(): + if field.required: + raise TypeError(f"__init__() missing argument: '{field.name}'") + else: + values[field.name] = field.get_default_value() + + # Validate all the values + for field in cls.__message_fields__.values(): + value = values[field.name] + if not field.data_type.isinstance(value): + raise TypeError( + f"__init__() for {cls.__name__} got invalid value for argument " + f"'{field.name}': {value} (expected a " + f"{field.data_type.description})" + ) + + # Allocate shared memory for a Cthulhu sample + sample = StreamSample() + + if cls.__message_size__ > 0: + sample.parameters = memoryPool().getBufferFromPool("", cls.__message_size__) + + # Preprocess the fixed-length field values and put them in the correct sequence + # for serialization + fixed_values = [ + field.data_type.preprocess(values[field.name]) + for field in cls.__message_fields__.values() + if field.data_type.size is not None + ] + + # Serialize the fixed-length field values + fixed_bytes = struct.pack(cls.__format_string__, *fixed_values) + + # Write the serialized fixed-length field values to shared memory + memoryview(sample.parameters)[ + : cls.__message_size__ + ] = fixed_bytes # type: ignore + + if cls.__num_dynamic_fields__ > 0: + # Preprocess the dynamic-length field values + dynamic_values = [ + field.data_type.preprocess(values[field.name]) + for field in cls.__message_fields__.values() + if field.data_type.size is None + ] + + # Allocate shared memory for the dynamic-length field values + dynamic_buffers = [ + memoryPool().getBufferFromPool("", len(value)) + for value in dynamic_values + ] + + # Write the serialized dynamic-length field values to shared memory + for value, buffer in zip(dynamic_values, dynamic_buffers): + memoryview(buffer)[: len(value)] = value + + # Set the sample's dynamic parameters + if len(dynamic_buffers) > 0: + sample.dynamicParameters = dynamic_buffers + + # Bypasses frozen check due to `frozen=True` by calling `__setattr__` on + # `object` + super().__setattr__("__sample__", sample) + + def asdict(self) -> "OrderedDict[str, Any]": + """ + Serialize the message as a dictionary. + """ + return OrderedDict( + (field.name, getattr(self, field.name)) + for field in self.__message_fields__.values() + ) + + def astuple(self) -> Tuple[Any, ...]: + """ + Serialize the message as a tuple. + """ + return tuple( + getattr(self, field.name) for field in self.__message_fields__.values() + ) + + @classmethod + def fromdict(cls: Type[M], data: Dict[str, Any]) -> M: + """ + Deserialize a message from a dictionary. + + Args: + data: The dictionary to deserialize. + """ + return cls(**data) + + def replace(self: M, **kwargs: Dict[str, Any]) -> M: + """ + Returns a new message with the fields replaced by the provided keyword + arguments. + """ + values = self.asdict() + values.update(kwargs) + return self.__class__(**values) + + def __getstate__(self) -> Dict[str, Any]: + return self.asdict() + + def __setstate__(self, state: Dict[str, Any]) -> None: + self.__class__.__init__(self, **state) + + def __getattribute__(self, name: str) -> Any: + all_fields = super().__getattribute__("__class__").__message_fields__ + if name not in all_fields: + return super().__getattribute__(name) + cls = type(self) + field = all_fields[name] + + # Use __original_message__ if necessary + if not isinstance(self.__original_message__, IsOriginalMessage): + message_cls = self.__original_message_type__ + if message_cls is None or message_cls is cls: + super().__setattr__("__original_message__", IsOriginalMessage()) + else: + if self.__original_message__ is None: + super().__setattr__( + "__original_message__", message_cls(__sample__=self.__sample__) + ) + original_field_name = list(message_cls.__message_fields__.items())[ + cls._index_of_field(name) + ][0] + result = getattr(self.__original_message__, original_field_name) + if not field.data_type.isinstance(result): + raise LabGraphError( + f"Could not convert from {message_cls.__name__}." + f"{original_field_name} to {cls.__name__}.{name}: invalid " + f"value {result}" + ) + return result + + if field.data_type.size is None: + # Dynamic field + field_buffer = bytearray(self.__sample__.dynamicParameters[field.offset]) + return field.data_type.postprocess(field_buffer) + elif isinstance(field.data_type, StructType): + field_memoryview = memoryview(self.__sample__.parameters)[ + field.offset : field.offset + field.data_type.size + ] + return field.data_type.postprocess( + struct.unpack( + DEFAULT_BYTE_ORDER.value + field.data_type.format_string, + field_memoryview, + )[0] + ) + else: + raise NotImplementedError( + f"Unexpected field type {field.data_type.__class__}" + ) + + def __eq__(self, other: Any) -> bool: + if not isinstance(other, Message): + raise NotImplementedError() + if type(self) != type(other): + return False + return self.asdict() == other.asdict() + + +class TimestampedMessage(Message): + """ + Represents a simple timestamped LabGraph message. All messages which + may be aligned using a timestamp should inherit from this class. + """ + + # Convention: units of seconds. + timestamp: float diff --git a/labgraph/messages/tests/__init__.py b/labgraph/messages/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/messages/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/messages/tests/test_message.py b/labgraph/messages/tests/test_message.py new file mode 100644 index 000000000..05e855fd9 --- /dev/null +++ b/labgraph/messages/tests/test_message.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# Unit tests for the Message class. + +from enum import Enum +from typing import Any, Dict, List + +import numpy as np +import pytest + +from ..message import Message +from ..types import NumpyDynamicType, NumpyType + + +NUMPY_SHAPE = (10, 10) + + +class MyStrEnum(str, Enum): + A = "A" + B = "B" + + +class MyIntEnum(int, Enum): + A = 1 + B = 2 + + +class MyMessage(Message): + """ + Simple message type with primitive fields for testing. + """ + + int_field: int + str_field: str + float_field: float + bool_field: bool + bytes_field: bytes + + +class MyDefaultMessage(Message): + """ + Simple message type with some default fields. + """ + + field1: int + field2: str + field3: bool = True + field4: bool = False + field5: int = 10 + + +class MyEnumMessage(Message): + """ + Simple message type with different enumerated fields for testing. + """ + + str_enum_field: MyStrEnum + int_enum_field: MyIntEnum + + +class MyNestedMessage(MyMessage): + """ + Simple nested message type with primitive fields for testing. + """ + + b_extra_field: str + a_extra_field: int + + +class MyNumpyMessage(Message): + """ + Simple message type with a numpy field for testing numpy serialization. + """ + + field1: str + field2: NumpyType(shape=NUMPY_SHAPE, dtype=np.float64) # type: ignore + field3: int + + +class MyNumpyMessage2(Message): + """ + Simple message type with some fields for testing message type equality to + `MyNumpyMessage`. + """ + + field1: str + field2: NumpyType(shape=NUMPY_SHAPE, dtype=np.float64) # type: ignore + field3: int + + +class MyNumpyMessage3(Message): + """ + Simple message type with some fields for testing message type equality to + `MyNumpyMessage`. + """ + + field1: int + field2: NumpyType(shape=NUMPY_SHAPE, dtype=np.float64) # type: ignore + field3: str + + +class MyNumpyMessage4(Message): + """ + Simple message type with some fields for testing message type equality to + `MyNumpyMessage`. + """ + + field1: str + field2: NumpyType(shape=(5,), dtype=np.float64) # type: ignore + field3: int + + +class MyDynamicNumpyMessage(Message): + """ + Simple message type with a dynamic numpy field for testing serialization and type + comparisons. + """ + + field1: str + field2: np.ndarray + field3: int + + +class MyDynamicNumpyIntMessage(Message): + """ + Simple message type with a dynamic numpy field for testing serialization and type + comparisons. + """ + + field1: str + field2: NumpyDynamicType(dtype=np.int64) # type: ignore + field3: int + + +class MyDynamicMessage(Message): + """ + Simple message type with some arbitrary dynamic fields. + """ + + field1: Dict[str, Any] + field2: int + field3: List[Any] + + +class MyInvalidDefaultMessage(Message): + """ + Message type with an invalid default value for testing this error case. + """ + + field1: str = 5 # type: ignore + + +def test_enum_message_creation() -> None: + """ + Tests that we can create instances of MyEnumMessage. + """ + message = MyEnumMessage(str_enum_field=MyStrEnum.A, int_enum_field=MyIntEnum.B) + + assert message.str_enum_field == MyStrEnum.A + assert message.int_enum_field == MyIntEnum.B + + +def test_message_creation() -> None: + """ + Tests that we can create instances of MyMessage. + """ + message = MyMessage( + int_field=5, + str_field="hello", + float_field=5.0, + bool_field=True, + bytes_field=b"world", + ) + + assert message.int_field == 5 + assert message.str_field == "hello" + assert message.float_field == 5.0 + assert message.bool_field is True + assert message.bytes_field == b"world" + + +def test_default_message_creation() -> None: + """ + Tests that we can create instances of `MyDefaultMessage` which has default fields. + """ + message1 = MyDefaultMessage(field1=5, field2="hello") + message2 = MyDefaultMessage(field1=10, field2="world", field3=False, field5=40) + assert message1.asdict() == { + "field1": 5, + "field2": "hello", + "field3": True, + "field4": False, + "field5": 10, + } + assert message2.asdict() == { + "field1": 10, + "field2": "world", + "field3": False, + "field4": False, + "field5": 40, + } + + +def test_nested_message_creation() -> None: + """ + Tests that we can create instances of MyNestedMessage. + """ + message = MyNestedMessage( + int_field=6, + str_field="goodbye", + float_field=10.0, + bool_field=False, + bytes_field=b"world", + a_extra_field=5, + b_extra_field="test", + ) + + assert message.int_field == 6 + assert message.str_field == "goodbye" + assert message.float_field == 10.0 + assert message.bool_field is False + assert message.bytes_field == b"world" + assert message.a_extra_field == 5 + assert message.b_extra_field == "test" + + +def test_asdict() -> None: + """ + Tests that we can serialize a message as a dictionary. + """ + message = MyNestedMessage( + int_field=6, + str_field="goodbye", + float_field=10.0, + bool_field=False, + bytes_field=b"world", + a_extra_field=5, + b_extra_field="test", + ) + + assert message.asdict() == { + "int_field": 6, + "str_field": "goodbye", + "float_field": 10.0, + "bool_field": False, + "bytes_field": b"world", + "a_extra_field": 5, + "b_extra_field": "test", + } + + +def test_equality() -> None: + """ + Tests that we can check the equality of different message instances. + """ + message1 = MyMessage( + int_field=5, + str_field="hello", + float_field=5.0, + bool_field=True, + bytes_field=b"world", + ) + message2 = MyMessage( + int_field=5, + str_field="hello", + float_field=5.0, + bool_field=True, + bytes_field=b"world", + ) + message3 = MyMessage( + int_field=6, + str_field="hello", + float_field=5.0, + bool_field=True, + bytes_field=b"world", + ) + assert message1 == message2 + assert message1 != message3 + + +def test_fromdict() -> None: + """ + Tests that we can deserialize a message from a dictionary. + """ + message = MyNestedMessage.fromdict( + { + "int_field": 6, + "str_field": "goodbye", + "float_field": 10.0, + "bool_field": False, + "bytes_field": b"world", + "a_extra_field": 5, + "b_extra_field": "test", + } + ) + + assert message == MyNestedMessage( + int_field=6, + str_field="goodbye", + float_field=10.0, + bool_field=False, + bytes_field=b"world", + a_extra_field=5, + b_extra_field="test", + ) + + +def test_numpy() -> None: + """ + Tests that we can serialize and deserialize messages with numpy fields. + """ + + arr = np.random.rand(*NUMPY_SHAPE) + message = MyNumpyMessage(field1="hello", field2=arr, field3=3) + assert message.field1 == "hello" + assert (message.field2 == arr).all() + assert message.field3 == 3 + + +def test_invalid_field_error() -> None: + """ + Tests that setting an invalid field value on a message raises a `TypeError`. + """ + with pytest.raises(TypeError) as err: + MyMessage( + int_field="bad field", # bad field + str_field="hello", + float_field=5.0, + bool_field=True, + bytes_field=b"world", + ) + assert str(err.value) == ( + "__init__() for MyMessage got invalid value for argument 'int_field': bad " + "field (expected a int)" + ) + + +def test_invalid_field_error_positional() -> None: + """ + Tests that setting an invalid field value (as a positional argument) on a message + raises a `TypeError`. + """ + with pytest.raises(TypeError) as err: + MyMessage("bad field", "hello", 5.0, True, b"world") + assert str(err.value) == ( + "__init__() for MyMessage got invalid value for argument 'int_field': bad " + "field (expected a int)" + ) + + +def test_message_type_equality() -> None: + """ + Tests message type equality. Only `MyNumpyMessage` and `MyNumpyMessage2` are + equivalent; all other comparison should return false. + """ + assert MyNumpyMessage == MyNumpyMessage2 + assert MyNumpyMessage != MyNumpyMessage3 + assert MyNumpyMessage != MyNumpyMessage4 + assert MyNumpyMessage2 != MyNumpyMessage3 + assert MyNumpyMessage2 != MyNumpyMessage4 + assert MyNumpyMessage3 != MyNumpyMessage4 + + +def test_dynamic_numpy_field() -> None: + """ + Tests that we can define and construct a message type with a dynamic numpy field. + """ + + assert isinstance( + MyDynamicNumpyMessage.__message_fields__["field2"].data_type, NumpyDynamicType + ) + array = np.random.rand(3, 3) + message = MyDynamicNumpyMessage(field1="hello", field2=array, field3=5) + assert message.field1 == "hello" + assert (message.field2 == array).all() + assert message.field3 == 5 + + +def test_dynamic_numpy_field_with_type() -> None: + """ + Tests that we can define and construct a message type with a dynamic numpy field + with a dtype. + """ + + assert isinstance( + MyDynamicNumpyIntMessage.__message_fields__["field2"].data_type, + NumpyDynamicType, + ) + array = np.random.randint(5, size=(3, 3), dtype=np.int64) + message = MyDynamicNumpyIntMessage(field1="hello", field2=array, field3=5) + assert message.field1 == "hello" + assert (message.field2 == array).all() + assert message.field3 == 5 + + +def test_dynamic_numpy_field_with_invalid_type() -> None: + """ + Tests that we throw an error when we construct a message type with an incorrect + dtype for the dynamic numpy field. + """ + + with pytest.raises(TypeError): + MyDynamicNumpyIntMessage(field1="hello", field2=np.random.rand(3, 3), field3=5) + + +def test_static_to_dynamic_conversion() -> None: + """ + Tests that we can convert a static field to a dynamic field between equivalent + message types. + """ + array = np.random.rand(*NUMPY_SHAPE) + message1 = MyNumpyMessage(field1="hello", field2=array, field3=5) + message2 = MyDynamicNumpyMessage( + __sample__=message1.__sample__, __original_message_type__=MyNumpyMessage + ) + assert message2.field1 == "hello" + assert (message2.field2 == array).all() + assert message2.field3 == 5 + + +def test_dynamic_to_static_conversion() -> None: + """ + Tests that we can convert a dynamic field to a static field between equivalent + message types. + """ + array = np.random.rand(*NUMPY_SHAPE) + message1 = MyDynamicNumpyMessage(field1="hello", field2=array, field3=5) + message2 = MyNumpyMessage( + __sample__=message1.__sample__, __original_message_type__=MyDynamicNumpyMessage + ) + assert message2.field1 == "hello" + assert (message2.field2 == array).all() + assert message2.field3 == 5 + + +def test_dynamic_fields() -> None: + """ + Tests that we can serialize some more dynamic field types. + """ + field1 = {"key1": 5, "key2": "value2"} + field2 = 12 + field3 = [5, "hello", 6.2] + message = MyDynamicMessage(field1=field1, field2=field2, field3=field3) + assert message.field1 == field1 + assert message.field2 == field2 + assert message.field3 == field3 + + +def test_invalid_default_field() -> None: + """ + Tests that a badly-typed default field value raises an error. + """ + with pytest.raises(AssertionError) as err: + MyInvalidDefaultMessage() + assert ( + str(err.value) + == "Expected default value for field 'field1' to match type 'str', got value 5" + ) + + +class TestPostInit: + """ + Tests that + 1. a message that has a __post_init__ method is triggered upon message + object creation. + 2. `super().__post_init__()` works when the parent message class has not + defined the method (class Pos). + 3. the inherited stack of __post_init__ calls all fire. + """ + + positive_error_string = "Pos.positive_int must be positive" + negative_error_string = "PosNeg.negative_int must be negative" + + class Pos(Message): + positive_int: int + + def __post_init__(self) -> None: + super().__post_init__() # type: ignore + + if self.positive_int <= 0: + raise ValueError(TestPostInit.positive_error_string) + + class PosNeg(Pos): + negative_int: int + + def __post_init__(self) -> None: + super().__post_init__() + + if self.negative_int >= 0: + raise ValueError(TestPostInit.negative_error_string) + + def test_post_init_runs(self) -> None: + """Tests objectives 1 and 2 above.""" + + # We can make an object correctly. + self.Pos(1) + + # Pos's constraint violated + with pytest.raises(ValueError, match=TestPostInit.positive_error_string): + self.Pos(0) + + with pytest.raises(ValueError, match=TestPostInit.positive_error_string): + self.Pos(-1) + + def test_post_init_runs_all_inherited(self) -> None: + """Tests objective 3 above.""" + + # We can make a valid object. + self.PosNeg(1, -1) + + # Pos's constraint violated + with pytest.raises(ValueError, match=TestPostInit.positive_error_string): + self.PosNeg(0, -1) + + with pytest.raises(ValueError, match=TestPostInit.positive_error_string): + self.PosNeg(-1, -1) + + # PosNeg's constraint violated + with pytest.raises(ValueError, match=TestPostInit.negative_error_string): + self.PosNeg(1, 0) + + with pytest.raises(ValueError, match=TestPostInit.negative_error_string): + self.PosNeg(1, 1) + + # Pos's and PosNeg's constraint violated + with pytest.raises(ValueError, match=TestPostInit.positive_error_string): + self.PosNeg(-1, 1) diff --git a/labgraph/messages/types.py b/labgraph/messages/types.py new file mode 100644 index 000000000..474335809 --- /dev/null +++ b/labgraph/messages/types.py @@ -0,0 +1,597 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import pickle +import struct +from abc import ABC, abstractmethod, abstractproperty +from enum import Enum +from io import BytesIO +from typing import Any, Generic, Optional, Tuple, Type, TypeVar + +import numpy as np +import typeguard + + +DEFAULT_STR_LENGTH = 128 + + +class ByteOrder(str, Enum): + """ + Represents a byte order used by a message in memory. + """ + + BIG_ENDIAN = ">" + LITTLE_ENDIAN = "<" + + +DEFAULT_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN + + +class CIntType(str, Enum): + """ + Represents a C integer type. The string value of the C type in this enum is the + format string for that enum in the `struct` module. + """ + + CHAR = "b" + UNSIGNED_CHAR = "B" + SHORT = "h" + UNSIGNED_SHORT = "H" + INT = "i" + UNSIGNED_INT = "I" + LONG = "l" + UNSIGNED_LONG = "L" + LONG_LONG = "q" + UNSIGNED_LONG_LONG = "Q" + + +class CFloatType(Enum): + """ + Represents a C floating-precision type. The string value of the C type in this enum + is the format string for that enum in the `struct` module. + """ + + FLOAT = "f" + DOUBLE = "d" + + +T = TypeVar("T") + + +class FieldType(ABC, Generic[T]): + """ + Represents a LabGraph field type. Subclasses implement methods that describe how to + check for instances of the type and serialize the type. + """ + + @abstractmethod + def isinstance(self, obj: Any) -> bool: + """ + Returns true if `obj` conforms to this field type. + + Args: + obj: The object to check against this field type. + """ + raise NotImplementedError() + + @abstractproperty + def description(self) -> str: + """ + A string description of this field type. + """ + raise NotImplementedError() + + @abstractproperty + def python_type(self) -> type: + """ + The raw Python type that this field type corresponds to. + """ + raise NotImplementedError() + + @property + def size(self) -> Optional[int]: + """ + The size in memory that this field type takes. If None, then this field has a + dynamic length. + """ + raise NotImplementedError() + + def preprocess(self, value: T) -> Any: + """ + Preprocesses a value of this field type so it can be serialized. The default + implementation does nothing to the value; subclasses can override this to + provide preprocessing behavior. + + Args: + value: The value to preprocess. + """ + return value + + def postprocess(self, value: Any) -> T: + """ + Postprocesses a deserialized object to conform to this field type. The default + implementation does nothing to the value; subclasses can override this to + provide postprocessing behavior. + + Args: + value: The value to postprocess. + """ + assert self.isinstance(value) + return value # type: ignore + + +class StructType(FieldType[T]): + """ + Represents a type that has fixed length and can be serialized using the built-in + `struct` library. + """ + + @abstractproperty + def format_string(self) -> str: + """ + The format string of this field type, for the `struct` module. + """ + raise NotImplementedError() + + @property + def size(self) -> int: + return struct.calcsize(f"{DEFAULT_BYTE_ORDER.value}{self.format_string}") + + +class IntType(StructType[int]): + """ + Represents an integer type. + + Args: + c_type: + The corresponding C type to serialize this integer as. Defaults to + `long`. + """ + + c_type: CIntType + + def __init__(self, c_type: CIntType = CIntType.LONG) -> None: + self.c_type = c_type + + @property + def format_string(self) -> str: + return str(self.c_type.value) + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, int) + + @property + def description(self) -> str: + return "int" + + @property + def python_type(self) -> type: + return int + + +T_I = TypeVar("T_I", bound=Enum) # Enumerated integer type + + +class IntEnumType(StructType[T_I]): + """ + Represents an integer type. + + Args: + c_type: + The corresponding C type to serialize this integer as. Defaults to + `long`. + """ + + c_type: CIntType + + def __init__(self, enum_type: Type[T_I], c_type: CIntType = CIntType.LONG) -> None: + self.c_type = c_type + self.enum_type: Type[T_I] = enum_type + + @property + def format_string(self) -> str: + return str(self.c_type.value) + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, self.enum_type) + + @property + def description(self) -> str: + return self.enum_type.__name__ + + def postprocess(self, value: int) -> T_I: + return self.enum_type(value) + + @property + def python_type(self) -> type: + return self.enum_type + + +class BoolType(StructType[bool]): + """ + Represents a boolean type. + + Args: + c_type: + The corresponding C type to serialize this integer as. Defaults to + `long`. + """ + + @property + def format_string(self) -> str: + return "?" + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, bool) + + @property + def description(self) -> str: + return "bool" + + @property + def python_type(self) -> type: + return bool + + +class FloatType(StructType[float]): + """ + Represents a floating-precision type. + + Args: + c_type: + The corresponding C type to serialize this float as. Defaults to + `double`. + """ + + c_type: CFloatType + + def __init__(self, c_type: CFloatType = CFloatType.DOUBLE) -> None: + self.c_type = c_type + + @property + def format_string(self) -> str: + return str(self.c_type.value) + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, float) + + @property + def description(self) -> str: + return "float" + + @property + def python_type(self) -> type: + return float + + +class StrType(StructType[str]): + """ + Represents a string type. + + Args: + length: + The maximum length of a string that conforms to this type. Necessary to + allow this field to be serialized with fixed length. + encoding: The encoding to use to serialize strings for this field. + """ + + length: int + encoding: str + + def __init__( + self, length: int = DEFAULT_STR_LENGTH, encoding: str = "utf-8" + ) -> None: + self.length = length + self.encoding = encoding + + @property + def format_string(self) -> str: + return f"{self.length}s" + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, str) and len(obj) <= self.length + + @property + def description(self) -> str: + return f"str({self.length})" + + def preprocess(self, value: str) -> bytes: + return value.encode(self.encoding) + + def postprocess(self, value: bytes) -> str: + return value.decode(self.encoding).rstrip("\0") + + @property + def python_type(self) -> type: + return str + + +T_S = TypeVar("T_S", bound=Enum) # Enumerated string type + + +class StrEnumType(StructType[T_S]): + """ + Represents an enumerated string type. + + Args: + encoding: The encoding to use to serialize strings for this field. + """ + + length: int + encoding: str + + def __init__(self, enum_type: Type[T_S], encoding: str = "utf-8") -> None: + self.length = max(len(item.value) for item in enum_type) + self.encoding = encoding + self.enum_type = enum_type + + @property + def format_string(self) -> str: + return f"{self.length}s" + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, self.enum_type) + + @property + def description(self) -> str: + return self.enum_type.__name__ + + def preprocess(self, value: T_S) -> bytes: + str_value: str = value.value + return str_value.encode(self.encoding) + + def postprocess(self, value: bytes) -> T_S: + str_value = value.decode(self.encoding).rstrip("\0") + return self.enum_type(str_value) + + @property + def python_type(self) -> type: + return self.enum_type + + +class BytesType(StructType[bytes]): + """ + Represents a bytes type. + + Args: + length: + The maximum length of a byte string that conforms to this type. Necessary to + allow this field to be serialized with fixed length. + """ + + length: int + + def __init__(self, length: int = DEFAULT_STR_LENGTH) -> None: + self.length = length + + @property + def format_string(self) -> str: + return f"{self.length}s" + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, bytes) and len(obj) <= self.length + + @property + def description(self) -> str: + return f"bytes({self.length})" + + def postprocess(self, value: bytes) -> bytes: + return value.rstrip(b"\0") + + @property + def python_type(self) -> type: + return bytes + + +class NumpyOrder(str, Enum): + C = "C" + F = "F" + + +class NumpyType(StructType[np.ndarray]): + """ + Represents a numpy array type. + + Args: + shape: The shape of a numpy array of this type. + dtype: The dtype of a numpy array of this type. + order: The order of the numpy array's data for multidimensional arrays ("C" or "F") + """ + + shape: Tuple[int] + dtype: np.dtype + order: NumpyOrder + + def __init__( + self, + shape: Tuple[int], + dtype: np.dtype = np.float64, + order: NumpyOrder = NumpyOrder.C, + ) -> None: + self.shape = shape + self.dtype = dtype + self.order = order + + @property + def format_string(self) -> str: + arr = np.zeros(shape=self.shape, dtype=self.dtype) + bytes_length = arr.size * arr.itemsize + return f"{bytes_length}s" + + def isinstance(self, obj: Any) -> bool: + return ( + isinstance(obj, np.ndarray) + and obj.shape == self.shape + and obj.dtype == self.dtype + ) + + @property + def description(self) -> str: + return f"numpy.ndarray({self.shape}, {self.dtype})" + + def preprocess(self, arr: np.ndarray) -> bytes: + return arr.tobytes(order=self.order) # type: ignore + + def postprocess(self, arr_bytes: bytes) -> np.ndarray: + return np.frombuffer(buffer=arr_bytes, dtype=self.dtype).reshape(self.shape) + + @property + def python_type(self) -> type: + return np.ndarray # type: ignore + + +class DynamicType(FieldType[T]): + """ + Represents a dynamic field type. + """ + + def isinstance(self, obj: Any) -> bool: + try: + typeguard.check_type("", obj, self.python_type) + return True + except TypeError: + return False + + @abstractproperty + def python_type(self) -> Type[T]: + raise NotImplementedError() + + @property + def size(self) -> Optional[int]: + return None + + +class ObjectDynamicType(DynamicType[Any]): + """ + Represents a dynamic field type for any object. This is a fallback type for when we + don't know how else to serialize a field. This type simply uses pickling to + serialize objects. + """ + + @property + def python_type(self) -> Type[object]: + return object + + @property + def description(self) -> str: + return "object" + + def preprocess(self, obj: T) -> bytes: + return pickle.dumps(obj) + + def postprocess(self, obj_bytes: bytes) -> T: + return pickle.loads(obj_bytes) # type: ignore + + +class NumpyDynamicType(DynamicType[np.ndarray]): + """ + Represents a numpy dynamic field type. + + Args: + dtype: The dtype of a numpy array of this type. + """ + + dtype: np.dtype + + def __init__(self, dtype: np.dtype = np.float64) -> None: + self.dtype = dtype + + @property + def python_type(self) -> type: + return np.ndarray # type: ignore + + def isinstance(self, obj: Any) -> bool: + return isinstance(obj, np.ndarray) and obj.dtype == self.dtype + + def preprocess(self, obj: np.ndarray) -> bytes: + assert self.isinstance(obj) + buf = BytesIO() + np.save(buf, obj) + buf.seek(0) + return buf.read() + + def postprocess(self, obj_bytes: bytes) -> np.ndarray: + buf = BytesIO(obj_bytes) + arr = np.load(buf) + assert isinstance(arr, np.ndarray) + return arr.astype(self.dtype) + + @property + def description(self) -> str: + return f"numpy.ndarray({self.dtype})" + + +class StrDynamicType(DynamicType[str]): + """ + Represents a string dynamic field type. + """ + + encoding: str + + def __init__(self, encoding: str = "utf-8") -> None: + super().__init__() + self.encoding = encoding + + @property + def python_type(self) -> type: + return str + + def preprocess(self, obj: str) -> bytes: + return obj.encode(self.encoding) + + def postprocess(self, obj_bytes: bytes) -> str: + return obj_bytes.decode(self.encoding) + + @property + def description(self) -> str: + return "str" + + +class BytesDynamicType(DynamicType[bytes]): + """ + Represents a bytes dynamic field type. + """ + + @property + def python_type(self) -> type: + return bytes + + @property + def description(self) -> str: + return "bytes" + + +PRIMITIVE_TYPES = { + int: IntType, + float: FloatType, + str: StrDynamicType, + bool: BoolType, + bytes: BytesDynamicType, +} + + +def get_field_type(python_type: Type[T]) -> FieldType[T]: + """ + Returns a `FieldType` that contains all the information LabGraph needs for a field. + + Args: + `python_type`: A Python type to get a `FieldType` for. + """ + + if not isinstance(python_type, type): + return ObjectDynamicType() + if issubclass(python_type, Enum): + if issubclass(python_type, str): + return StrEnumType(python_type) # type: ignore + elif issubclass(python_type, int): + return IntEnumType(python_type) # type: ignore + else: + raise TypeError( + "Message field enums must be a subtype of either int or str." + ) + elif python_type in PRIMITIVE_TYPES: + return PRIMITIVE_TYPES[python_type]() # type: ignore + elif python_type == np.ndarray: + return NumpyDynamicType() + + return ObjectDynamicType() diff --git a/labgraph/runners/__init__.py b/labgraph/runners/__init__.py new file mode 100644 index 000000000..82b8c033b --- /dev/null +++ b/labgraph/runners/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "Aligner", + "BootstrapInfo", + "ParallelRunner", + "LocalRunner", + "run", + "RunnerOptions", + "TimestampAligner", + "NormalTermination", +] + +from .aligner import Aligner, TimestampAligner +from .exceptions import NormalTermination +from .local_runner import LocalRunner +from .parallel_runner import ParallelRunner, run +from .runner import BootstrapInfo, RunnerOptions diff --git a/labgraph/runners/aligner.py b/labgraph/runners/aligner.py new file mode 100644 index 000000000..ac1371050 --- /dev/null +++ b/labgraph/runners/aligner.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import collections +import time +from abc import ABC, abstractmethod +from typing import Any, Dict, List, Optional, Tuple + +from .._cthulhu.cthulhu import LabGraphCallback, LabGraphCallbackParams +from ..messages.message import TimestampedMessage +from ..util.error import LabGraphError +from ..util.min_heap import MinHeap + + +class Aligner(ABC): + """ + Base aligner class which all future aligners should inherit from. + All runners may optionally carry an aligner. + + Methods: + register(stream_id, callback): + Called to register a subscribing callback onto the stream + with the given id. + push(stream_id, message): + Called to add a message to the aligner's message buffer. + get_aligned(): + Periodically called in order to re-publish messages + to subscribing callbacks, if applicable. + wait_for_completion(): + Called at the end of the runner's lifecycle to terminate + the aligner, waiting first for remaining messages to be published. + """ + + @abstractmethod + def register(self, stream_id: str, callback: LabGraphCallback) -> None: + pass + + @abstractmethod + def push(self, params: LabGraphCallbackParams[Any]) -> None: + pass + + @abstractmethod + async def get_aligned(self) -> None: + pass + + @abstractmethod + def wait_for_completion(self) -> None: + pass + + @abstractmethod + async def run(self) -> None: + pass + + +TimestampedHeapEntry = Tuple[ + float, int, str, LabGraphCallbackParams[TimestampedMessage] +] + +TimestampedHeap = MinHeap[TimestampedHeapEntry] +""" +The heap used by a TimestampAligner to determine the order of aligned messages. +""" + + +class TimestampAligner(Aligner): + """ + Default aligner used to align messages from multiple incoming streams. + Subscribers which intend to receive messages from the aligner must + first register themselves to the aligner; after the provided lag period, + any messages in the buffer will be re-published in chronological order. + + Unless explicitly told to terminate, the aligner continues running until + either i) all messages in the buffer have been delivered, or if ii) the + runner associated with the aligner is still "active"--i.e. more messages + are likely to require processing by the aligner in the future. + + Args: + lag: The time lag during which incoming messages are buffered. + """ + + def __init__(self, lag: float) -> None: + # Min-heap containing all messages, sorted by timestamp + # HACK: Avoiding pickling issues by deferring construction of heap + self._pq: Optional[TimestampedHeap] = None + + # Lag (in seconds) during which incoming messages are buffered + self.lag: float = lag + # Callbacks keyed by the id of the stream they're subscribing to + self.callbacks: Dict[str, List[LabGraphCallback]] = collections.defaultdict( + list + ) + + self.active: bool = True # Current state of associated runner + self.terminate: bool = False # Flag to quit immediately + + def register(self, stream_id: str, callback: LabGraphCallback) -> None: + self.callbacks[stream_id].append(callback) + + def push(self, params: LabGraphCallbackParams[TimestampedMessage]) -> None: + message = params.message + if params.stream_id is None: + raise LabGraphError( + "TimestampAligner::push expected stream id, but got None." + ) + heap_entry: TimestampedHeapEntry = ( + message.timestamp, + self.pq.count, + params.stream_id, + params, + ) + self.pq.push(heap_entry) + + async def get_aligned(self) -> None: + now = time.time() + while self.pq and (self.pq[0][0] + self.lag < now): + _, _, stream_id, next_params = self.pq.pop() + for callback in self.callbacks[stream_id]: + callback(next_params.message) + + def wait_for_completion(self) -> None: + self.active = False + + def stop(self) -> None: + self.terminate = True + + async def run(self) -> None: + # Continue running as long as runner is active/buffer not empty + while not self.terminate and (self.active or self.pq): + await asyncio.sleep(0.001) + await self.get_aligned() + + @property + def pq(self) -> TimestampedHeap: + if self._pq is None: + self._pq = TimestampedHeap() + return self._pq diff --git a/labgraph/runners/cthulhu.py b/labgraph/runners/cthulhu.py new file mode 100644 index 000000000..70ff57e7c --- /dev/null +++ b/labgraph/runners/cthulhu.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from .._cthulhu.cthulhu import register_stream +from ..graphs.module import Module +from ..util.logger import get_logger + + +logger = get_logger(__name__) + + +def create_module_streams(module: Module) -> None: + """ + Creates the Cthulhu streams defined on the module. + + Args: + module: The module to create Cthulhu streams for. + """ + logger.debug(f"{module}:creating cthulhu streams") + + # Create the streams + for stream in module.__streams__.values(): + if stream.message_type is None: + warning_message = ( + "Found no message types for a stream. This could be because the " + "topic is never used in Python. Consume a topic with a message " + "type in Python to make this stream work. This stream contains the " + "following topics:\n" + ) + for topic_path in stream.topic_paths: + warning_message += f"- {topic_path}\n" + + logger.warning(warning_message) + + continue + + logger.debug( + f"{module}:{stream.id}:creating cthulhu stream for topics " + f"{', '.join(stream.topic_paths)}" + ) + register_stream(stream.id, stream.message_type) diff --git a/labgraph/runners/entry.py b/labgraph/runners/entry.py new file mode 100644 index 000000000..3ec5006ef --- /dev/null +++ b/labgraph/runners/entry.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import dataclasses +import importlib +import pickle +from typing import Dict, Optional + +import click + +from .local_runner import LocalRunner +from .process_manager import ProcessManagerState +from .runner import BootstrapInfo, RunnerOptions +from .util import get_module_class + + +@click.command() +@click.option( + "--module", + type=str, + help="The fully-qualified classname of the module to run", + required=True, +) +@click.option( + "--process-name", + type=str, + help="The name of the process in the ProcessManager state", + required=True, +) +@click.option( + "--stream-namespace", + type=str, + help="The namespace of the streams in the managed process", +) +@click.option( + f"--{ProcessManagerState.SUBPROCESS_ARG}", + type=str, + help="The path to the ProcessManager state file", +) +@click.option( + "--streams-file-path", type=str, help="The path to the stream file for the module" +) +@click.option( + "--options-file-path", type=str, help="The path to the options file for the module" +) +@click.option( + "--config-file-path", type=str, help="The path to the config file for the module" +) +@click.option( + "--state-file-path", type=str, help="The path to the state file for the module" +) +def main( + module: str, + process_name: str, + stream_namespace: Optional[str] = None, + process_manager_state_file: Optional[str] = None, + streams_file_path: Optional[str] = None, + options_file_path: Optional[str] = None, + config_file_path: Optional[str] = None, + state_file_path: Optional[str] = None, +) -> None: + assert (process_name is None) == (process_manager_state_file is None), ( + "Expected both or neither of --process-name and " + f"--{ProcessManagerState.SUBPROCESS_ARG}" + ) + + # Get the Python class for the LabGraph module + module_cls = get_module_class(*module.rsplit(".", 1)) + + # Restore the config and state for the module + config, state = None, None + if config_file_path is not None: + with open(config_file_path, "rb") as config_file: + cls_path, config_dict = pickle.load(config_file) + config = _load_cls(cls_path)(**config_dict) + assert isinstance(config, module_cls.__config_type__) + if state_file_path is not None: + with open(state_file_path, "rb") as state_file: + cls_path, state_dict = pickle.load(state_file) + state = _load_cls(cls_path)(**state_dict) + assert isinstance(state, module_cls.__state_type__) + + # Construct an instance of the module + module_instance = module_cls(config=config, state=state) + + # Restore or create runner options + if options_file_path is not None: + with open(options_file_path, "rb") as options_file: + options = pickle.load(options_file) + assert isinstance(options, RunnerOptions) + else: + options = RunnerOptions() + + # Add bootstrap info to runner options + if process_manager_state_file is not None: + stream_ids_by_topic_path: Dict[str, str] = {} + if streams_file_path is not None: + with open(streams_file_path, "rb") as streams_file: + stream_ids_by_topic_path = pickle.load(streams_file) + assert isinstance(stream_ids_by_topic_path, dict) + options = dataclasses.replace( + options, + bootstrap_info=BootstrapInfo( + process_name=process_name, + process_manager_state=ProcessManagerState.load( + process_manager_state_file + ), + stream_ids_by_topic_path=stream_ids_by_topic_path, + stream_namespace=stream_namespace, + ), + ) + runner = LocalRunner(module=module_instance, options=options) + runner.run() + + +def _load_cls(cls_path: str) -> type: + module_path, cls_name = cls_path.rsplit(".", 1) + cls = getattr(importlib.import_module(module_path), cls_name) + assert isinstance(cls, type) + return cls + + +if __name__ == "__main__": + main() diff --git a/labgraph/runners/exceptions.py b/labgraph/runners/exceptions.py new file mode 100644 index 000000000..da9683c95 --- /dev/null +++ b/labgraph/runners/exceptions.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from ..messages.message import Message + + +class NormalTermination(Exception): + """ + Raised to indicate normal graph termination. + """ + + pass + + +class ExceptionMessage(Message): + """ + Holds the bytes for a thrown exception in a LabGraph message. + Convenient for passing exceptions between processes. + """ + + exception: bytes diff --git a/labgraph/runners/launch.py b/labgraph/runners/launch.py new file mode 100644 index 000000000..45161af14 --- /dev/null +++ b/labgraph/runners/launch.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import os +import platform +import shlex +import subprocess +import sys +from typing import Optional, Sequence + +from ..util.logger import get_logger +from ..util.resource import get_resource_tempfile + + +logger = get_logger(__name__) + + +def launch( + module: str, args: Optional[Sequence[str]] = None, *posargs, **kwargs +) -> subprocess.Popen: # type: ignore + """ + Runs the given module with the given arguments in a subprocess. This method for + launching a subprocess works even when inside a PEX environment. + + Args: + module: The module to run as the entry point. + args: The arguments to pass to the child process. + *args: Positional arguments forwarded to subprocess.Popen. + **kwargs: Keyword arguments forwarded to subprocess.Popen. + """ + args = args or [] + python_path = sys.executable + if _in_pex(): + pex_env_path = _get_pex_path() + parent_module = __name__.rsplit(".", 1)[0] + pex_bin_path = get_resource_tempfile(parent_module, "pex") + command = ( + f"{python_path} {pex_bin_path} --pex-path {pex_env_path} -m {module} -- " + f"{_join_args(args)}" + ) + env = os.environ.copy() + else: + command = f"{python_path} -m {module} {_join_args(args)}" + env = {**os.environ, "PYTHONPATH": os.pathsep.join(sys.path)} + + logger.debug(f"Launching subprocess: {command}") + if platform.system() == "Windows": + return subprocess.Popen(command, env=env, *posargs, **kwargs) # type: ignore + else: + return subprocess.Popen( # type: ignore + shlex.split(command), env=env, *posargs, **kwargs + ) + + +def _join_args(args: Sequence[str]) -> str: + if platform.system() == "Windows": + return " ".join(args) + else: + return " ".join(shlex.quote(arg) for arg in args) + + +def _in_pex() -> bool: + # HACK: There is currently no canonical way to detect whether we are running from + # inside a PEX environment. This is a hack based on the fact that PEX adds a _pex + # module inside the environment. + # More information: https://github.com/pantsbuild/pex/issues/721 + try: + import _pex # type: ignore + + return True + except ModuleNotFoundError: + return False + + +def _get_pex_path() -> str: + pex_path = sys.argv[0] + if not pex_path.endswith(".pex"): + raise RuntimeError(f"Could not find PEX path, found argv[0] = {pex_path}") + return pex_path diff --git a/labgraph/runners/local_runner.py b/labgraph/runners/local_runner.py new file mode 100644 index 000000000..a31c6b603 --- /dev/null +++ b/labgraph/runners/local_runner.py @@ -0,0 +1,788 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import contextlib +import functools +import inspect +import os +import pickle +import sys +import threading +import time +import traceback +from dataclasses import dataclass, field +from typing import ( + Any, + AsyncIterable, + Awaitable, + Callable, + Coroutine, + Dict, + List, + Optional, + Tuple, + Type, +) + +import yappi +from labgraph_cpp import NodeBootstrapInfo, NodeTopic # type: ignore + +# HACK: Import from LabGraph's wrapper of Cthulhu before importing dynamic libs to set +# the shared memory name +from .._cthulhu.cthulhu import ( + Consumer, + LabGraphCallbackParams, + Mode, + Producer, + format_performance_summary, + get_stream, +) +from ..graphs.cpp_node import CPPNode +from ..graphs.method import SubscriberType, Transformer +from ..graphs.module import Module +from ..graphs.topic import PATH_DELIMITER, Topic +from ..messages.message import Message +from ..util.logger import get_logger +from .cthulhu import create_module_streams +from .exceptions import ExceptionMessage, NormalTermination +from .process_manager import ProcessPhase +from .profiling import should_profile, write_profiling_results +from .runner import Runner, RunnerOptions + + +logger = get_logger(__name__) + +BARRIER_TIMEOUT = 60 +ASYNCIO_SHUTDOWN_POLL_TIME = 1 +ASYNCIO_SHUTDOWN_TIME = 10 +DEFAULT_QUEUE_CAPACITY = 10000 + +EXCEPTION_STREAM_SUFFIX = "_EXCEPTION" + + +@dataclass +class LocalRunnerState: + """ + Describes the state of a `LocalRunner`. + + Args: + lock: + Lock that can be used for synchronizing access to state between the + `LocalRunner`'s threads. + producers: The Cthulhu producers used by the module. + consumers: The Cthulhu consumers used by the module. + callbacks: The callbacks registered by the module's asyncio thread. + setup_barrier: + Barrier for coordinating startup between the `LocalRunner`'s threads. + ready_event: + A signal that the background thread waits on to know that the main thread + has completed all its startup tasks. + setup_complete: A flag indicating whether setup is complete for this module. + cleanup_started: A flag indicating whether cleanup has started for this module. + """ + + lock: threading.Lock = field(default_factory=threading.Lock) + producers: Dict[str, Producer] = field(default_factory=dict) + consumers: Dict[str, Consumer] = field(default_factory=dict) + callbacks: Dict[str, SubscriberType] = field(default_factory=dict) + setup_barrier: threading.Barrier = field( + default_factory=functools.partial(threading.Barrier, 2, timeout=BARRIER_TIMEOUT) + ) + ready_event: threading.Event = field(default_factory=threading.Event) + setup_complete: bool = False + cleanup_started: bool = False + + +class LocalRunner(Runner): + """ + A utility for running LabGraph modules. Given a module, runs the computation it + describes by creating two threads, one for its foreground processing and one for + its event loop processing. + + Foreground processing consists of: + + - Cthulhu stream setup + - Graph setup and cleanup + - Methods on nodes decorated with @main + + Background processing consists of: + + - Methods on nodes decorated with @publisher and/or @subscriber + - Methods on nodes decorated with @background + + Args: + module: The module to run. + options: Options describing how the module will be run. + """ + + def __init__(self, module: Module, options: Optional[RunnerOptions] = None) -> None: + self._module = module + self._options = options or RunnerOptions() + + self._running = False + self._exception: Optional[BaseException] = None + self._handled_exception: bool = False + + def run(self) -> None: + """ + Starts the LabGraph module. Returns when the module has terminated. + """ + try: + if should_profile(): + yappi.set_clock_type("cpu") + yappi.start() + self._running = True + logger.debug(f"{self._module}:started") + self._state = LocalRunnerState() + + # Start the background thread (runs the event loop) + async_thread = _AsyncThread(runner=self) + async_thread.start() + logger.debug(f"{self._module}:asyncio thread starting") + + # Start the monitor thread (monitors the graph for termination) + monitor_thread = _MonitorThread(runner=self) + monitor_thread.start() + logger.debug(f"{self._module}:monitor thread started") + + # Run nodes' setup() functions + logger.debug(f"{self._module}:setup running") + self._run_setup() + self._state.setup_complete = True + logger.debug(f"{self._module}:setup done") + + # Thread barrier: signal nodes' setup is done + wait for background thread + # to set up callbacks + self._state.setup_barrier.wait() + logger.debug(f"{self._module}:asyncio thread ready") + + # Set up Cthulhu + logger.debug(f"{self._module}:cthulhu setting up") + self._setup_cthulhu() + logger.debug(f"{self._module}:cthulhu ready") + + # Coordinate process readiness with other processes, if present + if self._options.bootstrap_info is not None: + # Signal that this process is ready + self._options.bootstrap_info.process_manager_state.update( + self._options.bootstrap_info.process_name, ProcessPhase.READY + ) + logger.debug(f"{self._module}:waiting for other processes in graph") + self._wait_for_ready() + logger.debug(f"{self._module}:graph ready") + self._options.bootstrap_info.process_manager_state.update( + self._options.bootstrap_info.process_name, ProcessPhase.RUNNING + ) + + # Thread event: signal to background thread that Cthulhu and graph are + # set up + self._state.ready_event.set() + + # Run @main method, if any + logger.debug(f"{self._module}:@main running") + self._run_main() + logger.debug(f"{self._module}:@main complete") + + # Wait for the background thread to finish (this will happen shortly after + # producers stop producing, causing the task queue to clear up, or when an + # exception is raised) + logger.debug(f"{self._module}:waiting for async thread") + async_thread.join() + logger.debug(f"{self._module}:async thread complete") + + # If the background thread raised an exception, re-raise it on the main + # thread + if self._exception is not None: + raise self._exception + except BaseException: + self._handle_exception() + finally: + self._running = False + if self._options.bootstrap_info is not None: + # Signal that this process is ready + self._options.bootstrap_info.process_manager_state.update( + self._options.bootstrap_info.process_name, ProcessPhase.STOPPING + ) + if not self._state.cleanup_started and self._state.setup_complete: + # Run nodes' cleanup() functions + self._state.cleanup_started = True + logger.debug(f"{self._module}:running cleanup in main thread") + self._run_cleanup() + logger.debug(f"{self._module}:cleanup complete") + + logger.debug(f"{self._module}:waiting for monitor thread") + monitor_thread.join() + logger.debug(f"{self._module}:monitor thread complete") + + if should_profile(): + yappi.stop() + write_profiling_results(self._module) + + for stream_id, consumer in self._state.consumers.items(): + performance_summary = consumer.get_performance_summary() + if performance_summary.num_calls > 0: + logger.info( + f"PERFORMANCE SUMMARY FOR {stream_id}:\n" + f"{format_performance_summary(performance_summary)}" + ) + + logger.debug(f"{self._module}:terminating") + + if self._options.bootstrap_info is not None: + # Signal that this process is ready + self._options.bootstrap_info.process_manager_state.update( + self._options.bootstrap_info.process_name, ProcessPhase.TERMINATED + ) + else: + # If there is an exception, raise it to the caller + if self._exception is not None: + raise self._exception + + def _setup_cthulhu(self) -> None: + """ + Sets up Cthulhu as the transport for the LabGraph graph. Creates streams only + if the module has no parent graph. Then creates producers and consumers + according to the publishers and subscribers in the module. + """ + if self._options.bootstrap_info is None: + create_module_streams(self._module) + self._create_producers() + self._create_consumers() + self._bootstrap_cpp_nodes() + + def _bootstrap_cpp_nodes(self) -> None: + module_tuples = list(self._module.__descendants__.items()) + module_tuples.append(("", self._module)) + for node_path, node in module_tuples: + if not isinstance(node, CPPNode): + continue + node_topics: List[Tuple[str, str]] = [] + for topic_name in node.__topics__.keys(): + if node_path == "": + topic_path = topic_name + else: + topic_path = PATH_DELIMITER.join((node_path, topic_name)) + stream = self._module._stream_for_topic_path(topic_path) + if stream.message_type is None: + continue + root_stream_id = stream.id + if self._options.bootstrap_info is not None: + if self._options.bootstrap_info.stream_namespace is not None: + root_stream_id = ( + self._options.bootstrap_info.stream_ids_by_topic_path[ + f"{self._options.bootstrap_info.stream_namespace}" + f"{PATH_DELIMITER}{topic_path}" + ] + ) + else: + root_stream_id = ( + self._options.bootstrap_info.stream_ids_by_topic_path[ + topic_path + ] + ) + node_topics.append((topic_name, root_stream_id)) + bootstrap_info = NodeBootstrapInfo( + topics=[ + NodeTopic(topic_name, stream_id) + for topic_name, stream_id in node_topics + ] + ) + node._bootstrap(bootstrap_info) + + def _wait_for_ready(self) -> None: + if self._options.bootstrap_info is None: + return + while ( + self._options.bootstrap_info.process_manager_state.get_overall().value + < ProcessPhase.READY.value + ): + time.sleep(0.1) + + def _run_main(self) -> None: + """ + Runs the @main-decorated method in this module, if any. + """ + main_path, _ = self._module.main + if main_path is None: + return + main_method = self._module._get_main_method(main_path) + main_method() + + def _create_producers(self) -> None: + """ + Creates a Cthulhu `StreamProducer` for each stream published to in this module. + """ + logger.debug(f"{self._module}:creating cthulhu producers") + produced_topic_paths = set() + for publisher in self._module.publishers.values(): + for topic_path in publisher.published_topic_paths: + produced_topic_paths.add(topic_path) + + for topic_path in produced_topic_paths: + # If running as a subprocess, get the topic path relative to the graph root + root_topic_path = topic_path + local_stream_id = self._module._stream_for_topic_path(topic_path).id + root_stream_id = local_stream_id + if self._options.bootstrap_info is not None: + if self._options.bootstrap_info.stream_namespace is not None: + root_topic_path = ( + f"{self._options.bootstrap_info.stream_namespace}" + f"{PATH_DELIMITER}{root_topic_path}" + ) + root_stream_id = self._options.bootstrap_info.stream_ids_by_topic_path[ + root_topic_path + ] + + cthulhu_stream = get_stream(root_stream_id) + assert cthulhu_stream is not None, ( + f"Cthulhu stream for topic {root_topic_path} ({root_stream_id}) was " + "not created" + ) + producer = Producer(stream_interface=cthulhu_stream, mode=Mode.ASYNC) + with self._state.lock: + self._state.producers[local_stream_id] = producer + + def _callback_for_stream(self, stream_id: str) -> Callable[..., None]: + """ + Returns a callback for the given stream id. The actual callbacks are registered + in the `LocalRunner`'s state object by the asyncio thread. This returns a + callback that looks up the registered callback and then calls it. + """ + # Typing `callback` with `MessageType` allows us to know how to deserialize + # the incoming message in shared memory + + MessageType = self._module.__streams__[stream_id].message_type + assert MessageType is not None + if self._options.aligner is not None: + # Type with extra information for the aligner + MessageType = LabGraphCallbackParams[MessageType] # type: ignore + + def callback(message: MessageType) -> None: # type: ignore + with self._state.lock: + callback_fn = self._state.callbacks[stream_id] + callback_fn(message) + + return callback + + def _create_consumers(self) -> None: + """ + Creates a Cthulhu `StreamConsumer` for every stream subscribed to in this + module. + """ + logger.debug(f"{self._module}:creating cthulhu consumers") + + # Register a `StreamConsumer` for each stream + for subscriber in self._module.subscribers.values(): + # If running as a subprocess, get the topic path relative to the graph root + root_topic_path = subscriber.subscribed_topic_path + local_stream_id = self._module._stream_for_topic_path( + subscriber.subscribed_topic_path + ).id + root_stream_id = local_stream_id + if self._options.bootstrap_info is not None: + if self._options.bootstrap_info.stream_namespace is not None: + root_topic_path = ( + f"{self._options.bootstrap_info.stream_namespace}" + f"{PATH_DELIMITER}{root_topic_path}" + ) + root_stream_id = self._options.bootstrap_info.stream_ids_by_topic_path[ + root_topic_path + ] + cthulhu_stream = get_stream(root_stream_id) + assert cthulhu_stream is not None, ( + f"Cthulhu stream for topic {root_topic_path} ({root_stream_id}) was " + "not created" + ) + consumer = Consumer( + stream_interface=cthulhu_stream, + sample_callback=self._callback_for_stream(local_stream_id), + mode=Mode.ASYNC, + stream_id=local_stream_id, + ) + consumer.queue_capacity = DEFAULT_QUEUE_CAPACITY + with self._state.lock: + self._state.consumers[local_stream_id] = consumer + + def _run_setup(self) -> None: + """ + Runs the `setup()` function on each descendant module of this `LocalRunner`'s + module, ensuring that every parent has `setup()` called before any of its + descendants. + """ + setup_stack: List[Module] = [self._module] + while len(setup_stack) > 0: + module = setup_stack.pop() + module.setup() + for child_module in module.__children__.values(): + setup_stack.append(child_module) + + def _run_cleanup(self) -> None: + """ + Runs the `cleanup()` function on each descendant module of this `LocalRunner`'s + module, ensuring that every parent has `cleanup()` called before any of its + descendants. + """ + cleanup_stack: List[Module] = [self._module] + while len(cleanup_stack) > 0: + module = cleanup_stack.pop() + module.cleanup() + if isinstance(module, Module): + for child_module in module.__children__.values(): + cleanup_stack.append(child_module) + + def _handle_exception(self) -> None: + if self._handled_exception: + return + else: + self._handled_exception = True + + self._running = False + + _, exception, _ = sys.exc_info() + + if isinstance(exception, NormalTermination): + logger.info(f"{self._module}:shutting down normally") + else: + # Log exception info + logger.critical(f"{self._module}:UNCAUGHT EXCEPTION") + logger.critical(traceback.format_exc()) + self._exception = exception + + if self._options.bootstrap_info is not None: + if not isinstance(exception, NormalTermination): + self._options.bootstrap_info.process_manager_state.set_exception( + self._options.bootstrap_info.process_name, repr(exception) + ) + + +class _AsyncThread(threading.Thread): + """ + A thread for the asyncio event loop used by a `LocalRunner`. This frees the + `LocalRunner`'s main thread for code that needs the main thread, e.g., UI code. + + Args: + module: The module being run. + options: The options used to configure the `LocalRunner`. + state: The state shared with the `LocalRunner`. + """ + + def __init__(self, runner: LocalRunner) -> None: + super().__init__() + self.runner = runner + self.module = runner._module + self.options = runner._options or RunnerOptions() + self.state = runner._state + self.original_stream_types = self.get_original_stream_types() + + def run(self) -> None: + """ + Runs the `_AsyncThread`'s event loop. + """ + + logger.debug(f"{self.module}:started background thread") + + # We import asyncio here and keep asyncio object construction within this method + # in order to ensure that no asyncio state leaks into the global state, + # guaranteeing it will never be pickled. We want this because subtle bugs can + # arise when asyncio objects are transported across process boundaries. Many + # of the objects in this method are kept as locals rather than being set as + # properties in order to avoid accidentally accessing them from the main thread, + # e.g., in the `LocalRunner`. + + import asyncio + + # Create event loop + loop = asyncio.new_event_loop() + loop.set_exception_handler(self.handle_exception) + asyncio.set_event_loop(loop) + + try: + # Create callback methods that run in the event loop + with self.state.lock: + for stream in self.module.__streams__.values(): + callbacks = [] + for subscriber_path, subscriber in self.module.subscribers.items(): + if subscriber.subscribed_topic_path in stream.topic_paths: + if isinstance(subscriber, Transformer): + callbacks.append( + self.wrap_transformer_callback( + transformer_path=subscriber_path, loop=loop + ) + ) + else: + callbacks.append( + self.wrap_subscriber_callback( + subscriber_path=subscriber_path, loop=loop + ) + ) + + stream_callback = self.wrap_all_callbacks(callbacks, loop=loop) + + if self.options.aligner is not None: + # Inject aligner into callback if present + self.options.aligner.register(stream.id, stream_callback) + stream_callback = self.options.aligner.push + + self.state.callbacks[stream.id] = stream_callback + + # Thread barrier: wait for nodes' setup + signal to main thread that + # callbacks are ready + self.state.setup_barrier.wait() + + # Thread event: wait for main thread to set up Cthulhu + self.state.ready_event.wait() + + # Schedule startup coroutines in event loop + for awaitable in self.get_startup_methods(): + asyncio.ensure_future(awaitable, loop=loop) + + # Schedule aligner task + if self.options.aligner is not None: + logger.debug(f"{self.module}:background thread:run aligner") + loop.create_task(self.options.aligner.run()) + + logger.debug(f"{self.module}:background thread:run event loop") + + with contextlib.ExitStack() as run_stack: + if "PROFILE" in os.environ: + # Run yappi profiling + run_stack.enter_context(yappi.run()) + + # Run event loop + while self.runner._running: + loop.run_until_complete(asyncio.sleep(0.01)) + except BaseException: + logger.debug(f"{self.module}:handling exception in background thread") + self.runner._handle_exception() + + if not self.state.cleanup_started and self.state.setup_complete: + # The main thread may not be able to run cleanup if it is blocked by a + # @main function. So we try to run cleanup in the background thread + # first. + self.state.cleanup_started = True + logger.debug(f"{self.module}:running cleanup in background thread") + self.runner._run_cleanup() + logger.debug(f"{self.module}:cleanup complete") + + # Terminate the aligner + if self.options.aligner is not None: + logger.debug(f"{self.module}:background thread:terminate aligner") + self.options.aligner.wait_for_completion() + logger.debug(f"{self.module}:background thread:shutting down async gens") + loop.run_until_complete(loop.shutdown_asyncgens()) + + logger.debug(f"{self.module}:background thread:waiting for pending tasks") + pending_start_time = time.perf_counter() + while True: + time.sleep(ASYNCIO_SHUTDOWN_POLL_TIME) + pending = [ + task for task in asyncio.Task.all_tasks(loop=loop) if not task.done() + ] + if len(pending) == 0: + logger.debug(f"{self.module}:background thread:closing event loop") + loop.close() + return + elif time.perf_counter() - pending_start_time >= ASYNCIO_SHUTDOWN_TIME: + logger.warning( + f"{self.module}:background thread:closing event loop with " + f"{len(pending)} tasks left" + ) + # Suppress exception handling - otherwise the handler catches "Task + # was destroyed but it is pending!" + loop.set_exception_handler(lambda _l, _c: None) + try: + loop.close() + except Exception: + # Exception expected with pending tasks + pass + return + logger.debug(f"{self.module}:{len(pending)} tasks left") + loop.run_until_complete(asyncio.sleep(1)) + + def get_original_stream_types(self) -> Dict[str, Type[Message]]: + stream_types = {} + for stream in self.module.__streams__.values(): + publishers = [ + publisher + for publisher in self.module.publishers.values() + if len( + set(publisher.published_topic_paths).intersection( + stream.topic_paths + ) + ) + > 0 + ] + if len(publishers) != 1: + continue + publisher = publishers[0] + topic_path = list( + set(publisher.published_topic_paths).intersection(stream.topic_paths) + )[0] + topic = self.module.__topics__[topic_path] + + subscriber_paths = [ + subscriber_path + for subscriber_path, subscriber in self.module.subscribers.items() + if subscriber.subscribed_topic_path in stream.topic_paths + ] + for subscriber_path in subscriber_paths: + stream_types[subscriber_path] = topic.message_type + return stream_types + + def get_startup_methods(self) -> List[Coroutine[None, None, None]]: + return [ + self.run_publisher_method(publisher_method) + for publisher_method in self.get_publisher_methods() + ] + self.get_background_methods() # type: ignore + + async def run_publisher_method( + self, publisher_method: Callable[[], AsyncIterable[Tuple[Topic, Message]]] + ) -> None: + import asyncio + + async for topic, message in publisher_method(): + topic_path = self.module._get_topic_path(topic) + stream = self.module._stream_for_topic_path(topic_path) + producer = self.state.producers[stream.id] + producer.produce_message(message) + + def get_publisher_methods( + self, + ) -> List[Callable[[], AsyncIterable[Tuple[Topic, Message]]]]: + return [ + self.module._get_publisher_method(publisher_path) + for publisher_path, publisher in self.module.publishers.items() + # Transformers don't run on graph startup + if not isinstance(publisher, Transformer) + ] + + def get_background_methods(self) -> List[Awaitable[None]]: + return [ + self.module._get_background_method(background_path)() + for background_path in self.module.backgrounds.keys() + ] + + def wrap_subscriber_callback( + self, subscriber_path: str, loop: Any + ) -> Callable[[Message], Awaitable[None]]: + """ + Returns a subscriber callback as an async function. + + Args: + subscriber_path: The path to the @subscriber-decorated callback. + loop: The event loop to run the callback on. + """ + + subscriber_method = self.module._get_subscriber_method(subscriber_path) + + if inspect.iscoroutinefunction(subscriber_method): + return subscriber_method + + async def subscriber_callback(message: Message) -> None: + if subscriber_path in self.original_stream_types: + object.__setattr__( + message, + "__original_message_type__", + self.original_stream_types[subscriber_path], + ) + if loop.is_closed(): + logger.warn( + f"{message.__class__.__name__} dropped while graph shutting down" + ) + return + loop.call_soon(self.module._get_subscriber_method(subscriber_path), message) + return + + return subscriber_callback + + def wrap_transformer_callback( + self, transformer_path: str, loop: Any + ) -> Callable[[Message], Awaitable[None]]: + """ + Returns a transformer callback as an async function. + + Args: + transformer_path: + The path to the callback with both @subscriber and @publisher + decorators. + loop: The event loop to run the callback on. + """ + + async def transformer_callback(message: Message) -> None: + if transformer_path in self.original_stream_types: + object.__setattr__( + message, + "__original_message_type__", + self.original_stream_types[transformer_path], + ) + await self.run_publisher_method( + functools.partial( + self.module._get_transformer_method(transformer_path), message + ) + ) + + return transformer_callback + + def wrap_all_callbacks( + self, callbacks: List[Callable[[Message], Awaitable[None]]], loop: Any + ) -> SubscriberType: + """ + Given a list of callbacks, returns a callback that wraps all of them by + scheduling all of them on the event loop when a message is received. + + Args: + callbacks: The callbacks to wrap. + loop: The event loop to schedule the callbacks on. + """ + import asyncio + + def callback(message: Message) -> None: + if loop.is_closed(): + logger.warn( + f"{message.__class__.__name__} dropped while graph shutting down" + ) + return + for callback in callbacks: + asyncio.ensure_future(callback(message), loop=loop) + + return callback + + def handle_exception(self, loop: Any, context: Dict[str, Any]) -> None: + try: + if "exception" in context: + exception = context["exception"] + else: + exception = Exception(f"{context}") + raise exception # Re-raise the exception so the runner can see it + except Exception: + self.runner._handle_exception() + + +class _MonitorThread(threading.Thread): + def __init__(self, runner: LocalRunner) -> None: + super().__init__() + self.runner = runner + + def run(self) -> None: + if self.runner._options.bootstrap_info is None: + return + + while True: + if not self.runner._running: + logger.debug(f"{self.runner._module}:monitor thread stopping") + return + + try: + if ( + self.runner._options.bootstrap_info.process_manager_state.get_overall().value + >= ProcessPhase.STOPPING.value + ): + logger.debug( + f"{self.runner._module}:stopping due to graph shutdown" + ) + self.runner._running = False + return + except (EOFError, ConnectionError, OSError, BrokenPipeError): + logger.warning(f"{self.runner._module}:lost process manager, stopping") + self.runner._running = False + time.sleep(0.1) diff --git a/labgraph/runners/parallel_runner.py b/labgraph/runners/parallel_runner.py new file mode 100644 index 000000000..313160fe8 --- /dev/null +++ b/labgraph/runners/parallel_runner.py @@ -0,0 +1,211 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import dataclasses +import importlib +import inspect +import multiprocessing as mp +import pickle +import sys +import tempfile +import threading +import time +from pathlib import Path +from typing import List, Optional, Type + +import yappi + +from .._cthulhu.cthulhu import Consumer, Producer, register_stream +from ..graphs.graph import Graph +from ..graphs.module import Module +from ..graphs.parent_graph_info import ParentGraphInfo +from ..loggers.logger import Logger, LoggerConfig +from ..util.logger import get_logger +from .cthulhu import create_module_streams +from .exceptions import ExceptionMessage, NormalTermination +from .process_manager import ProcessInfo, ProcessManager +from .profiling import should_profile, write_profiling_results +from .runner import Runner, RunnerOptions +from .util import get_module_class + + +logger = get_logger(__name__) + +BARRIER_TIMEOUT = 60 +SHUTDOWN_PERIOD = 5 +EXCEPTION_POLL_TIME = 1 + +EXCEPTION_STREAM_SUFFIX = "_EXCEPTION" + +LOGGER_KEY = "__LOGGER__" + + +class ParallelRunner(Runner): + def __init__(self, graph: Graph, options: Optional[RunnerOptions] = None) -> None: + self._graph = graph + self._options = options or RunnerOptions() + + # TODO: Validate process groups + self._modules = tuple(self._graph.process_modules()) + self._logger: Optional[Logger] = None + self._exception: Optional[BaseException] = None + + self._temp_files: List[str] = [] + + def run(self) -> None: + """ + Starts the LabGraph graph. Returns when the graph has terminated. + """ + self._graph.setup() + self._create_logger() + create_module_streams(self._graph) + self._start_processes() + + def _create_logger(self) -> None: + streams_by_logging_id = self._graph._get_streams_by_logging_id() + if len(streams_by_logging_id) == 0: + return + logger = self._options.logger_type( + config=self._options.logger_config.replace( + streams_by_logging_id=streams_by_logging_id + ) + ) + self._modules = self._modules + (logger,) + + def _start_processes(self) -> None: + processes = [] + for module in self._modules: + assert isinstance(module, Module) + python_module = self._get_class_module(module.__class__) + module_class_name = module.__class__.__name__ + get_module_class(python_module, module_class_name) # Validate class + + process_args = ["--module", f"{python_module}.{module_class_name}"] + + # Write config and state to disk for subprocess to use + if module._config is not None: + with tempfile.NamedTemporaryFile("wb", delete=False) as config_file: + pickle.dump( + ( + self._get_class_qualname(module._config.__class__), + module._config.asdict(), + ), + config_file, + ) + self._temp_files.append(config_file.name) + process_args += ["--config-file-path", config_file.name] + + if module.state is not None: + with tempfile.NamedTemporaryFile("wb", delete=False) as state_file: + pickle.dump( + ( + self._get_class_qualname(module.state.__class__), + dataclasses.asdict(module.state), + ), + state_file, + ) + self._temp_files.append(state_file.name) + process_args += ["--state-file-path", state_file.name] + + # Write stream information to disk + streams_by_topic_path = {} + for stream in self._graph.__streams__.values(): + for topic_path in stream.topic_paths: + streams_by_topic_path[topic_path] = stream.id + with tempfile.NamedTemporaryFile("wb", delete=False) as streams_file: + pickle.dump(streams_by_topic_path, streams_file) + self._temp_files.append(streams_file.name) + process_args += ["--streams-file-path", streams_file.name] + + # Write runner options to disk + with tempfile.NamedTemporaryFile("wb", delete=False) as options_file: + pickle.dump(self._options, options_file) + self._temp_files.append(options_file.name) + process_args += ["--options-file-path", options_file.name] + + if module is self._graph: + module_path = "" + elif isinstance(module, Logger): + module_path = LOGGER_KEY + else: + module_path = self._graph._get_module_path(module) + process_args += ["--stream-namespace", module_path] + processes.append( + ProcessInfo( + name=module_path or module.__class__.__name__, + module=__name__.replace("parallel_runner", "entry"), + args=tuple(process_args), + ) + ) + + self._process_manager = ProcessManager(processes=processes) + self._process_manager.run() + + def _get_class_qualname(self, cls: type) -> str: + return f"{self._get_class_module(cls)}.{cls.__name__}" + + def _get_class_module(self, cls: type) -> str: + python_module = cls.__module__ + if python_module != "__main__": + return python_module + + # Getting the real module name for __main__ can be annoyingly complicated... + try: + entry_point: Optional[str] = None + + # Try to get the module name from the file path + cls_file = inspect.getfile(cls) + cls_path = Path(cls_file) + path_components = cls_path.with_name(cls_path.stem).parts + + if all(not component.endswith(".pex") for component in path_components): + while len(path_components) > 0: + try: + entry_point = ".".join(path_components) + importlib.import_module(entry_point) + break + except (ImportError, TypeError): + entry_point = None + finally: + path_components = path_components[1:] + + # Try to get the module name from the PEX + if entry_point is None: + + if not sys.argv[0].endswith(".pex"): + raise RuntimeError() + from _pex.pex_info import PexInfo # type: ignore + + pex_info = PexInfo.from_pex(sys.argv[0]) + entry_point = pex_info.entry_point + + # Fail if all methods failed to find an entry point + if entry_point is None: + raise RuntimeError() + + assert isinstance(entry_point, str) + entry_module = importlib.import_module(entry_point) + if hasattr(entry_module, cls.__name__): + return entry_point + else: + raise RuntimeError() + except (ImportError, RuntimeError): + raise RuntimeError( + f"Putting {cls.__name__} in the main scope is preventing its use with " + f"df.{self.__class__.__name__}. Please consider either a) creating " + "another module to use as the main module or b) using __main__.py " + "instead.\nhttps://docs.python.org/3.6/library/__main__.html" + ) + + +def run(graph_type: Type[Graph]) -> None: + """ + Entry point for running LabGraph graphs. Call `run` with a LabGraph graph type to + run a new graph of that type. + """ + config_type = graph_type.__config_type__ + config = config_type.fromargs() + graph = graph_type() + graph.configure(config) + runner = ParallelRunner(graph=graph) + runner.run() diff --git a/labgraph/runners/process_manager.py b/labgraph/runners/process_manager.py new file mode 100644 index 000000000..fc4adf670 --- /dev/null +++ b/labgraph/runners/process_manager.py @@ -0,0 +1,632 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import dataclasses +import enum +import multiprocessing as mp +import pickle +import socket +import subprocess +import tempfile +import time +from multiprocessing import managers +from typing import Callable, Dict, Optional, Sequence, Set, Tuple, Union + +import psutil + +from ..util.logger import get_logger +from ..util.random import random_string +from .launch import launch + + +logger = get_logger(__name__) + +MONITOR_SLEEP_TIME = 0.01 +DEFAULT_STARTUP_PERIOD = 60 +DEFAULT_SHUTDOWN_PERIOD = 30 +AUTH_KEY_LENGTH = 16 + + +class ProcessPhase(enum.Enum): + """ + Describes the current running state of a process managed by a `ProcessManager`. + """ + + STARTING = enum.auto() + READY = enum.auto() + RUNNING = enum.auto() + STOPPING = enum.auto() + TERMINATED = enum.auto() + + +class ProcessFailureType(enum.Enum): + CRASH = enum.auto() + EXCEPTION = enum.auto() + HANG = enum.auto() + + +class ProcessManagerException(RuntimeError): + """ + Raised when something goes wrong when running a `ProcessManager`. + """ + + def __init__( + self, + failures: Dict[str, Optional[ProcessFailureType]], + exceptions: Dict[str, Optional[str]], + phases: Dict[str, ProcessPhase], + ) -> None: + self._failures = failures + self._exceptions = exceptions + self._phases = phases + super().__init__(self.message) + + @property + def failures(self) -> Dict[str, Optional[ProcessFailureType]]: + return self._failures + + @property + def exceptions(self) -> Dict[str, Optional[str]]: + return self._exceptions + + @property + def message(self) -> str: + msg = "Some managed processes failed:\n" + for process_name in self._failures.keys(): + msg += self._message_for_failure(process_name) + "\n" + return msg + + def _message_for_failure(self, process_name: str) -> str: + return f"- {process_name}: " + { + None: "Terminated normally", + ProcessFailureType.CRASH: "Crashed (terminated unexpectedly)", + ProcessFailureType.EXCEPTION: ( + f"Raised an exception: {self._exceptions[process_name]}" + ), + ProcessFailureType.HANG: ( + "Hanged (stopped responding) while in phase " + f"{self._phases[process_name].name}" + ), + }[self._failures[process_name]] + + +@dataclasses.dataclass +class ProcessManagerServerInfo: + port: int + auth_key: bytes = dataclasses.field( + default_factory=lambda: random_string(AUTH_KEY_LENGTH).encode("ascii") + ) + host: str = "127.0.0.1" + + @property + def address(self) -> Tuple[str, int]: + return (self.host, self.port) + + +class ProcessManagerState: + """ + Holds state for all the processes managed by a `ProcessManager`. Thread-safe. + + Args: + process_names: The names of all the processes being managed. + """ + + # Argument passed to subprocesses so they can find the shared state + SUBPROCESS_ARG = "process-manager-state-file" + + _server_info: Optional[ProcessManagerServerInfo] = None + _manager: Optional[mp.managers.SyncManager] = None + _manager_started = False + + def __init__(self, process_names: Set[str], manager_name: str) -> None: + # Start the `mp.Manager` if it is not started + if not self.__class__._manager_started: + self.__class__._server_info = ProcessManagerServerInfo( + port=self.__class__._get_free_tcp_port() + ) + self.__class__._manager = mp.managers.SyncManager( + authkey=self.__class__._server_info.auth_key, + address=self.__class__._server_info.address, + ) + self.__class__._manager.start() + self.__class__._manager_started = True + + assert self._manager is not None + + self._manager_name = manager_name + process_names = set(process_names).union({manager_name}) + + # Basic state of all managed processes + self._phases = self._manager.dict( + {process_name: ProcessPhase.STARTING for process_name in process_names} + ) + self._exceptions: Dict[str, Optional[str]] = self._manager.dict( + {process_name: None for process_name in process_names} + ) + + # Synchronizes access to _phases and _exceptions + self.lock = self._manager.RLock() + + def get_all(self) -> Dict[str, ProcessPhase]: + """ + Returns the current running state for all managed processes. + """ + with self.lock: + return {**self._phases} + + def get(self, name: str) -> ProcessPhase: + """ + Returns the current running state for the managed process with the given name. + + Args: + name: The name of the managed process. + """ + return self._phases[name] + + def update(self, name: str, phase: ProcessPhase) -> None: + """ + Updates the current running state for the managed process with the given name. + + Args: + name: The name of the managed process. + phase: The new running state. + """ + with self.lock: + old_phase = self._phases[name] + logger.debug(f"{name}:updated state:{old_phase.name} -> {phase.name}") + assert phase.value > old_phase.value + self._phases[name] = phase + + def get_exception(self, name: str) -> Optional[str]: + """ + Gets the description of the exception that the managed process with the given + name raised, if any. + + Args: + name: The name of the managed process. + """ + return self._exceptions[name] + + def set_exception(self, name: str, exception_desc: str) -> None: + """ + Sets the current exception for the managed process with the given name. + + Args: + name: The name of the managed process. + exception_desc: + A string description of the exception that was thrown by the managed + process. + """ + with self.lock: + assert self.get_exception(name) is None + self._exceptions[name] = exception_desc + + @property + def has_exception(self) -> bool: + """ + Returns true if an exception was raised in any process. + """ + with self.lock: + return any(exception is not None for exception in self._exceptions.values()) + + @classmethod + def load(cls, filename: str) -> "ProcessManagerState": + """ + Loads a saved `ProcessManagerState` from a file. + + Args: + filename: The filename to read the state from. + """ + # See https://bugs.python.org/msg214582 for more information on why we use auth + # keys here. + with open(filename, "rb") as state_file: + # Unpickle the outer layer + result = pickle.load(state_file) + assert isinstance(result, tuple) + # The outer layer should contain an auth key as well as the "real" bytes + server_info, state_bytes = result + assert isinstance(server_info, ProcessManagerServerInfo) + assert isinstance(state_bytes, bytes) + # Unpickling `mp.Manager` proxy objects (`_phases` and `_exceptions`) + # requires us to set the correct auth key. We do so temporarily to avoid + # contaminating global state. + old_auth_key = mp.current_process().authkey + mp.current_process().authkey = server_info.auth_key + state = pickle.loads(state_bytes) + assert isinstance(state, ProcessManagerState) + mp.current_process().authkey = old_auth_key + return state + + def dump(self, filename: str) -> None: + """ + Dumps this `ProcessManagerState` to a file. + + Args: + filename: The filename to dump to. + """ + # See https://bugs.python.org/msg214582 for more information on why we use auth + # keys here. + with open(filename, "wb") as state_file: + # We pickle twice: first we pickle the state itself, and then we pickle the + # auth key with the pickled bytes. The reason is we will need this auth key + # in the child process in order to unpickle the state bytes. + state_bytes = pickle.dumps(self) + pickle.dump((self.__class__._server_info, state_bytes), state_file) + + def get_overall(self) -> ProcessPhase: + """ + Returns the overall phase of all managed processes. + """ + return self._phases[self._manager_name] + + @classmethod + def _get_free_tcp_port(cls) -> int: + tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + tcp.bind(("", 0)) + addr, port = tcp.getsockname() + tcp.close() + return int(port) + + +@dataclasses.dataclass(frozen=True) +class ProcessInfo: + """ + Describes a process to be run by a `ProcessManager`. + + Args: + module: The Python module to run in the child process. + args: Any arguments to pass to the child process. Empty by default. + name: + The name of the child process. If not provided, an integer counter will be + used. + """ + + module: str + args: Tuple[str, ...] = dataclasses.field(default_factory=tuple) + name: Optional[str] = None + + +class ProcessManager: + """ + Class for managing several process. The `ProcessManager` handles starting all the + processes, sharing state between them, and terminating the processes if anything + goes wrong (i.e., if a crash, an exception, or a hang occurs). + + Args: + processes: + A list of `ProcessInfo` objects describing processes to run. Each process + will receive a --process-manager-state-file option with a filename that + it should load a `ProcessManagerState` from. Then it is expected to keep + that state object up-to-date on its status. + name: + The name of this process manager. This will be used to track the state of + the overall graph in `ProcessManagerState`. + startup_period: + The time, in seconds, that each process has to start running. If a process + exceeds this time, the `ProcessManager` will consider this an erroneous + state and stop all the processes. + shutdown_period: + The time, in seconds, that each process has to shut down. If a process + exceeds this time, the `ProcessManager` will consider this a hang and stop + all the processes. + """ + + def __init__( + self, + processes: Sequence[ProcessInfo], + name: Optional[str] = None, + startup_period: float = DEFAULT_STARTUP_PERIOD, + shutdown_period: float = DEFAULT_SHUTDOWN_PERIOD, + ) -> None: + self._name = name or self.__class__.__name__ + self._startup_period = startup_period + self._shutdown_period = shutdown_period + + # Index the `ProcessInfo` objects by name, and fill in the names for any without + # names using an integer counter + self._process_info: Dict[str, ProcessInfo] = {} + process_counter = 0 + for process_info in processes: + if process_info.name is None: + while str(process_counter) in self._process_info.keys(): + process_counter += 1 + process_info = dataclasses.replace( + process_info, name=str(process_counter) + ) + if process_info.name in self._process_info.keys(): + raise ValueError( + f"{self.__class__.__name__} got multiple processes named " + f"{process_info.name}" + ) + assert process_info.name is not None + assert process_info.name != self._name + self._process_info[process_info.name] = process_info + + # Initiatialize state (this will be shared between processes via `mp.Manager`) + self._state = ProcessManagerState(set(self._process_info.keys()), self._name) + + # Write the state information to disk so that other processes can access it + self._state_file = tempfile.NamedTemporaryFile(delete=False) + self._state_file.close() + self._state.dump(self._state_file.name) + + # Runtime state for the manager + self._processes: Dict[str, subprocess.Popen] = {} # type: ignore + self._start_time: Optional[float] = None + + self._manager_exception: Optional[BaseException] = None + self._hanged_processes: Set[str] = set() + self._crashed_processes: Set[str] = set() + + def run(self) -> None: + """ + Runs the `ProcessManager`. This starts all the processes and blocks until they + all terminate. This may raise an exception if a crash, an exception, or a hang + occurred in the processes that were started. + """ + try: + self._start_processes() + # Because process startup time can be variable, start the timer for process + # startup after all processes are staretd + self._start_time = time.perf_counter() + self._wait_for_startup_phase(ProcessPhase.READY) + self._wait_for_startup_phase(ProcessPhase.RUNNING) + self._monitor() + except BaseException as e: + self._manager_exception = e + self._terminate_gracefully() + finally: + self._raise_exception() + + def _start_processes(self) -> None: + """ + Starts all the processes. + """ + for process_info in self._process_info.values(): + # `launch` launches a child process, resilient to PEX environments + assert process_info.name is not None + self._processes[process_info.name] = launch( + process_info.module, + process_info.args + + ( + f"--{ProcessManagerState.SUBPROCESS_ARG}", + self._state_file.name, + "--process-name", + process_info.name, + ), + ) + + def _wait_for_startup_phase(self, target_phase: ProcessPhase) -> None: + """ + Waits for all processes to enter the same phase during startup. Kills all + processes if they crash, raise, or hang. + """ + if self._state.get(self._name).value >= target_phase.value: + self._terminate_gracefully() + return + should_terminate = False # Flag that can be set to kill the manager + logger.debug( + f"{self._name}:waiting for all processes to be {target_phase.name}" + ) + while True: + with self._state.lock: + # Check if any process has crashed + self._check_crashed_processes() + if len(self._crashed_processes) > 0: + should_terminate = True + + # Check if any process raised an exception + if self._state.has_exception: + should_terminate = True + + phases = self._state.get_all() + + # Stop waiting if all the processes have entered the right state + if all( + phase.value >= target_phase.value + for name, phase in phases.items() + if name != self._name + ): + overall_phase = ProcessPhase( + min( + phase.value + for name, phase in phases.items() + if name != self._name + ) + ) + if self._state.get_overall() != overall_phase: + self._state.update(self._name, overall_phase) + break + + # Check if any processes took too long to enter the state + slow_processes = { + process_name: phase + for process_name, phase in phases.items() + if phase.value < target_phase.value and process_name != self._name + } + current_time = time.perf_counter() + assert self._start_time is not None + if ( + current_time - self._start_time >= self._startup_period + and len(slow_processes) > 0 + ): + error = ( + f"{self._name}:modules took too long to be {target_phase.name}:\n" + ) + for name, phase in slow_processes.items(): + error += f"- {name}: {phase.name}\n" + self._hanged_processes.add(name) + logger.error(error) + + should_terminate = True + + if should_terminate: + break + + time.sleep(MONITOR_SLEEP_TIME) + + # Terminate if the termination flag was set + if should_terminate: + self._terminate_gracefully() + return + + logger.debug(f"{self._name}:processes are all {target_phase.name}") + + def _monitor(self) -> None: + """ + Monitors the running processes for any change in their state. + """ + if self._state.get_overall().value >= ProcessPhase.STOPPING.value: + return + logger.debug(f"{self._name}:monitoring running processes") + should_terminate = False + while True: + with self._state.lock: + # If any process is stopping, stop all managed processes + for process_name, phase in self._state._phases.items(): + if phase.value >= ProcessPhase.STOPPING.value: + logger.debug(f"{self._name}:{process_name} stopping") + should_terminate = True + + # Check if any process has crashed + self._check_crashed_processes() + if len(self._crashed_processes) > 0: + should_terminate = True + + # Check if any process has raised an exception + if self._state.has_exception: + should_terminate = True + break + + if should_terminate: + break + + time.sleep(MONITOR_SLEEP_TIME) + logger.debug(f"{self._name}:monitoring complete") + if should_terminate: + self._terminate_gracefully() + + def _raise_exception(self) -> None: + """ + Raises an exception based on the information collected while the managed + processes were running. + """ + if self._manager_exception is not None: + raise self._manager_exception + with self._state.lock: + if ( + all(exception is None for exception in self._state._exceptions.values()) + and len(self._hanged_processes) == 0 + and len(self._crashed_processes) == 0 + ): + return + raise ProcessManagerException( + failures={ + process_name: ProcessFailureType.EXCEPTION + if self._state._exceptions[process_name] is not None + else ProcessFailureType.HANG + if process_name in self._hanged_processes + else ProcessFailureType.CRASH + if process_name in self._crashed_processes + else None + for process_name in self._process_info.keys() + }, + exceptions={**self._state._exceptions}, + phases=self._state.get_all(), + ) + + def _terminate_gracefully(self) -> None: + """ + Terminates the managed processes gratefully. + """ + # Short circuit if already terminated + if self._state.get(self._name) == ProcessPhase.TERMINATED: + return + + logger.debug(f"{self._name}:terminating gracefully") + + with self._state.lock: + # Set the manager's state to STOPPING. This is the signal that managed + # processes must use - they are expected to then stop and terminate + # themselves. This makes for a graceful termination. + if self._state.get(self._name) != ProcessPhase.STOPPING: + self._state.update(self._name, ProcessPhase.STOPPING) + + terminate_start = time.perf_counter() + # Wait for all processes to terminate + while True: + if len(self._get_dead_processes()) == len(self._processes): + with self._state.lock: + self._state.update(self._name, ProcessPhase.TERMINATED) + + # Check if any processes crashed while stopping + if self._state.get_exception(self._name) is None: + self._check_crashed_processes() + + logger.debug(f"{self._name}:terminated gracefully") + return + + # Check if the termination has exceeded the shutdown period + current_time = time.perf_counter() + if current_time - terminate_start >= self._shutdown_period: + break + time.sleep(MONITOR_SLEEP_TIME) + + for process_name in set(self._processes.keys()).difference( + self._get_dead_processes() + ): + self._hanged_processes.add(process_name) + logger.warning(f"{self._name}:graceful termination timed out") + # No more Mr. Nice Guy; terminate the processes forcibly + self._terminate_forcibly() + + def _terminate_forcibly(self) -> None: + # Short circuit if already terminated + if self._state.get(self._name) == ProcessPhase.TERMINATED: + return + + logger.warning(f"{self._name}:terminating forcibly") + with self._state.lock: + if self._state.get(self._name) != ProcessPhase.STOPPING: + self._state.update(self._name, ProcessPhase.STOPPING) + + # Murder all the processes + for name, process in self._processes.items(): + if process.poll() is None: + proc = psutil.Process(process.pid) + for child in proc.children(recursive=True): + child.kill() + proc.kill() + logger.warning(f"{name}: terminated forcibly") + + with self._state.lock: + self._state.update(self._name, ProcessPhase.TERMINATED) + + def _get_dead_processes(self) -> Set[str]: + """ + Returns all processes that are no longer alive. + """ + return { + process_name + for process_name, process in self._processes.items() + if process.poll() is not None + } + + def _check_crashed_processes(self) -> None: + """ + Checks for crashed processes. Crashed processes are dead processes whose final + phase was not TERMINATED. + """ + with self._state.lock: + dead_processes = self._get_dead_processes() + crashed_processes = { + name + for name in dead_processes + if self._state.get(name) != ProcessPhase.TERMINATED + } + if len(crashed_processes) > 0: + error = f"{self._name}:modules crashed:\n" + for process_name in crashed_processes: + self._crashed_processes.add(process_name) + error += f"- {process_name}\n" + logger.error(error) diff --git a/labgraph/runners/profiling.py b/labgraph/runners/profiling.py new file mode 100644 index 000000000..20728beab --- /dev/null +++ b/labgraph/runners/profiling.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import os +from pathlib import Path + +import appdirs +import yappi + +from ..graphs.module import Module +from ..util.logger import get_logger + + +logger = get_logger(__name__) + + +def should_profile() -> bool: + return "PROFILE" in os.environ + + +def write_profiling_results(module: Module) -> None: + """ + Writes profiling results for the `LocalRunner` session to disk. The .pstat file + can be read with the Python pstat module. + """ + results_dir = appdirs.user_log_dir("labgraph", "labgraph") + results_path = Path(results_dir) / Path( + f"profile_{module.__class__.__name__}_{module.id}.pstat" + ) + results_path.parent.mkdir(parents=True, exist_ok=True) + yappi.get_func_stats().save(str(results_path), type="pstat") + logger.info(f"{module}:saved profiling results to {results_path}") diff --git a/labgraph/runners/runner.py b/labgraph/runners/runner.py new file mode 100644 index 000000000..c7cb72066 --- /dev/null +++ b/labgraph/runners/runner.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from typing import Dict, Optional, Type + +from ..graphs.module import Module +from ..graphs.parent_graph_info import ParentGraphInfo +from ..graphs.stream import Stream +from ..graphs.topic import PATH_DELIMITER, Topic +from ..loggers.hdf5.logger import HDF5Logger +from ..loggers.logger import Logger, LoggerConfig +from ..messages.message import Message +from ..messages.types import BytesType +from ..util.error import LabGraphError +from ..util.logger import get_logger +from .aligner import Aligner +from .process_manager import ProcessManagerState + + +@dataclass +class BootstrapInfo: + process_name: str + process_manager_state: ProcessManagerState + stream_ids_by_topic_path: Dict[str, str] + stream_namespace: Optional[str] = None + + +@dataclass +class RunnerOptions: + """ + Options that can be provided to a `Runner`. + + Args: + aligner: + An `Aligner` object that describes an alignment algorithm to use on all + streams. + logger_type: The Python class for the logger type to use. + logger_config: Configuration to provide the logger. + """ + + aligner: Optional[Aligner] = None + bootstrap_info: Optional[BootstrapInfo] = None + logger_type: Type[Logger] = HDF5Logger + logger_config: LoggerConfig = field(default_factory=LoggerConfig) + + +class Runner(ABC): + @abstractmethod + def __init__(self, module: Module, options: Optional[RunnerOptions] = None) -> None: + raise NotImplementedError() + + @abstractmethod + def run(self) -> None: + raise NotImplementedError() diff --git a/labgraph/runners/tests/__init__.py b/labgraph/runners/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/runners/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/runners/tests/test_aligner.py b/labgraph/runners/tests/test_aligner.py new file mode 100644 index 000000000..a8ade34f2 --- /dev/null +++ b/labgraph/runners/tests/test_aligner.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import time +from typing import List + +import pytest + +from ...graphs.graph import Graph +from ...graphs.group import Connections +from ...graphs.method import AsyncPublisher, publisher, subscriber +from ...graphs.node import Node +from ...graphs.topic import Topic +from ...messages.message import TimestampedMessage +from ...util.testing import local_test +from ..aligner import TimestampAligner +from ..exceptions import NormalTermination +from ..parallel_runner import ParallelRunner +from ..runner import RunnerOptions + + +NUM_MESSAGES = 5 +FAST_PUBLISH_RATE = 10 +SLOW_PUBLISH_RATE = 1 + +SMALL_ALIGN_LAG = 0.01 +LARGE_ALIGN_LAG = 5 + + +class MyMessage1(TimestampedMessage): + int_field: int + + +class MyMessage2(TimestampedMessage): + int_field: int + + +class MySource1(Node): + A = Topic(MyMessage1) + + @publisher(A) + async def source(self) -> AsyncPublisher: + latest = time.time() + for i in reversed(range(NUM_MESSAGES)): + yield self.A, MyMessage1(timestamp=latest - i, int_field=i) + await asyncio.sleep(1 / SLOW_PUBLISH_RATE) + + +class MySource2(Node): + A = Topic(MyMessage2) + + @publisher(A) + async def source(self) -> AsyncPublisher: + latest = time.time() + for i in reversed(range(NUM_MESSAGES)): + yield self.A, MyMessage2(timestamp=latest - i, int_field=i) + await asyncio.sleep(1 / FAST_PUBLISH_RATE) + + +class MySink(Node): + D = Topic(MyMessage1) + E = Topic(MyMessage2) + + def setup(self) -> None: + self.results: List[float] = [] + + @subscriber(D) + def sink1(self, message: MyMessage1) -> None: + self.results.append(message.timestamp) + if len(self.results) == 2 * NUM_MESSAGES: + raise NormalTermination() + + @subscriber(E) + def sink2(self, message: MyMessage2) -> None: + self.results.append(message.timestamp) + if len(self.results) == 2 * NUM_MESSAGES: + raise NormalTermination() + + +class MyGraph(Graph): + SOURCE1: MySource1 + SOURCE2: MySource2 + SINK: MySink + + def connections(self) -> Connections: + return ((self.SOURCE1.A, self.SINK.D), (self.SOURCE2.A, self.SINK.E)) + + +@local_test +@pytest.mark.skip("T70572430: Fix aligner tests") +def test_slow_align_interval() -> None: + """ + Tests that when the default timestamp aligner is specified for a runner + with insufficient time lag, the results from its streams should arrive in + expected (not chronological) order. + """ + + graph = MyGraph() + aligner = TimestampAligner(SMALL_ALIGN_LAG) + runner = ParallelRunner(graph=graph, options=RunnerOptions(aligner=aligner)) + runner.run() + + assert len(graph.SINK.results) == NUM_MESSAGES * 2 + assert graph.SINK.results != sorted(graph.SINK.results) + + +@local_test +@pytest.mark.skip("T70572430: Fix aligner tests") +def test_align_two_streams() -> None: + """ + Tests that when the default timestamp aligner is specified for a runner + with sufficient time lag, the results from all its streams should arrive + in chronological order. + """ + + graph = MyGraph() + aligner = TimestampAligner(LARGE_ALIGN_LAG) + runner = ParallelRunner(graph=graph, options=RunnerOptions(aligner=aligner)) + runner.run() + + assert len(graph.SINK.results) == NUM_MESSAGES * 2 + assert graph.SINK.results == sorted(graph.SINK.results) diff --git a/labgraph/runners/tests/test_cpp.py b/labgraph/runners/tests/test_cpp.py new file mode 100644 index 000000000..194fd2a87 --- /dev/null +++ b/labgraph/runners/tests/test_cpp.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import time +from pathlib import Path +from typing import Dict, Sequence + +import h5py +from MyCPPNodes import MyCPPSink, MyCPPSource # type: ignore + +from ...graphs.config import Config +from ...graphs.cpp_node import CPPNodeConfig +from ...graphs.graph import Graph +from ...graphs.group import Connections +from ...graphs.method import subscriber +from ...graphs.module import Module +from ...graphs.node import Node +from ...graphs.topic import Topic +from ...messages.message import Message +from ...runners.exceptions import NormalTermination +from ...runners.parallel_runner import ParallelRunner +from ...util.testing import get_test_filename, local_test + + +class MyMessage(Message): + value: int + + +class MySinkConfig(Config): + filename: str + + +class MyPythonSink(Node): + C = Topic(MyMessage) + + config: MySinkConfig + + def setup(self) -> None: + self.messages_seen: int = 0 + + @subscriber(C) + def sink(self, message: MyMessage) -> None: + with open(self.config.filename, "a") as f: + f.write(str(message.value) + "\n") + self.messages_seen += 1 + if self.messages_seen == MyCPPSource.NUM_SAMPLES: + time.sleep(2) + raise NormalTermination() + + +class MyGraphConfig(Config): + python_filename: str + cpp_filename: str + + +class MyMixedGraph(Graph): + CPP_SOURCE: MyCPPSource + CPP_SINK: MyCPPSink + PYTHON_SINK: MyPythonSink + + config: MyGraphConfig + + def setup(self) -> None: + self.CPP_SINK.configure(CPPNodeConfig(args=[self.config.cpp_filename])) + self.PYTHON_SINK.configure(MySinkConfig(filename=self.config.python_filename)) + + def connections(self) -> Connections: + return ( + (self.CPP_SOURCE.A, self.CPP_SINK.B), + (self.CPP_SOURCE.A, self.PYTHON_SINK.C), + ) + + def process_modules(self) -> Sequence[Module]: + return [self.CPP_SOURCE, self.CPP_SINK, self.PYTHON_SINK] + + def logging(self) -> Dict[str, Topic]: + return { + "cpp_source": self.CPP_SOURCE.A, + "cpp_sink": self.CPP_SINK.B, + "python_sink": self.PYTHON_SINK.C, + } + + +@local_test +def test_cpp_graph() -> None: + """ + Tests that we can run a graph with both C++ and Python nodes, and read the results + on disk. + """ + # Run the graph + graph = MyMixedGraph() + python_filename = get_test_filename() + cpp_filename = get_test_filename() + graph.configure( + MyGraphConfig(python_filename=python_filename, cpp_filename=cpp_filename) + ) + runner = ParallelRunner(graph=graph) + # Get the HDF5 log path to verify the logs later + output_path = str( # noqa: F841 + Path(runner._options.logger_config.output_directory) + / Path(f"{runner._options.logger_config.recording_name}.h5") + ) + runner.run() + + # Check C++ sink output + cpp_nums = set(range(MyCPPSource.NUM_SAMPLES)) + with open(cpp_filename, "r") as f: + for line in f: + num = int(line.strip()) + cpp_nums.remove(num) + + assert len(cpp_nums) == 0, f"Missing numbers in C++ sink output: {cpp_nums}" + + # Check Python sink output + python_nums = set(range(MyCPPSource.NUM_SAMPLES)) + with open(python_filename, "r") as f: + for line in f: + num = int(line.strip()) + if num in python_nums: + python_nums.remove(num) + + assert ( + len(python_nums) == 0 + ), f"Missing numbers in Python sink output: {python_nums}" + + # Check HDF5 logger output + with h5py.File(output_path, "r") as h5py_file: + for hdf5_path in ("cpp_source", "cpp_sink", "python_sink"): + dataset = h5py_file[hdf5_path] + assert dataset.shape == (MyCPPSource.NUM_SAMPLES,) + dataset_nums = {int(num[0]) for num in dataset} + assert dataset_nums == set(range(MyCPPSource.NUM_SAMPLES)) diff --git a/labgraph/runners/tests/test_exception.py b/labgraph/runners/tests/test_exception.py new file mode 100644 index 000000000..eb06bf9d2 --- /dev/null +++ b/labgraph/runners/tests/test_exception.py @@ -0,0 +1,204 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from typing import Awaitable, Dict, Mapping, Sequence, Type + +import pytest + +from ...graphs.graph import Graph +from ...graphs.group import Connections +from ...graphs.method import AsyncPublisher, background, main, publisher, subscriber +from ...graphs.module import Module +from ...graphs.node import Node +from ...graphs.topic import Topic +from ...loggers.logger import Logger +from ...messages.message import Message +from ...runners.local_runner import LocalRunner +from ...runners.parallel_runner import LOGGER_KEY, ParallelRunner +from ...runners.runner import RunnerOptions +from ...util.testing import local_test +from ..process_manager import ProcessFailureType, ProcessManagerException + + +class MyTestException(Exception): + pass + + +class MyTestMessage(Message): + int_field: int + + +class MainThrowerNode(Node): + @main + def entry(self) -> None: + raise MyTestException() + + +class BackgroundThrowerNode(Node): + @background + async def background(self) -> None: + raise MyTestException() + + +class PublisherThrowerNode(Node): + TOPIC = Topic(MyTestMessage) + + @publisher(TOPIC) + async def publisher(self) -> AsyncPublisher: + raise MyTestException() + yield self.TOPIC, MyTestMessage(1) + + +class PublisherSubscriberThrowerNode(Node): + TOPIC = Topic(MyTestMessage) + + @subscriber(TOPIC) + async def subscriber(self, message: MyTestMessage) -> None: + raise MyTestException() + + @publisher(TOPIC) + async def publisher(self) -> AsyncPublisher: + yield self.TOPIC, MyTestMessage(1) + + +MODULE_TYPES = ( + MainThrowerNode, + BackgroundThrowerNode, + PublisherThrowerNode, + PublisherSubscriberThrowerNode, +) + + +@local_test +@pytest.mark.parametrize("module_type", MODULE_TYPES) # type: ignore +def test_local_throw(module_type: Type[Node]) -> None: + node = module_type() + runner = LocalRunner(module=node) + with pytest.raises(MyTestException): + runner.run() + + +class SubscriberNode(Node): + TOPIC = Topic(MyTestMessage) + + @subscriber(TOPIC) + async def subscriber(self, message: MyTestMessage) -> None: + pass + + +class PublisherThrowerGraph(Graph): + PUBLISHER: PublisherThrowerNode + SUBSCRIBER: SubscriberNode + + def connections(self) -> Connections: + return ((self.PUBLISHER.TOPIC, self.SUBSCRIBER.TOPIC),) + + def process_modules(self) -> Sequence[Module]: + return (self.PUBLISHER, self.SUBSCRIBER) + + +class SubscriberThrowerNode(Node): + TOPIC = Topic(MyTestMessage) + + @subscriber(TOPIC) + async def subscriber(self, message: MyTestMessage) -> None: + raise MyTestException() + + +class PublisherNode(Node): + TOPIC = Topic(MyTestMessage) + + @publisher(TOPIC) + async def publisher(self) -> AsyncPublisher: + yield self.TOPIC, MyTestMessage(1) + + +class SubscriberThrowerGraph(Graph): + PUBLISHER: PublisherNode + SUBSCRIBER: SubscriberThrowerNode + + def connections(self) -> Connections: + return ((self.PUBLISHER.TOPIC, self.SUBSCRIBER.TOPIC),) + + def process_modules(self) -> Sequence[Module]: + return (self.PUBLISHER, self.SUBSCRIBER) + + +class MainThrowerGraph(Graph): + PUBLISHER: PublisherNode + SUBSCRIBER: SubscriberNode + MAIN: MainThrowerNode + + def connections(self) -> Connections: + return ((self.PUBLISHER.TOPIC, self.SUBSCRIBER.TOPIC),) + + def process_modules(self) -> Sequence[Module]: + return (self.PUBLISHER, self.SUBSCRIBER, self.MAIN) + + +class BackgroundThrowerGraph(Graph): + PUBLISHER: PublisherNode + SUBSCRIBER: SubscriberNode + BACKGROUND: BackgroundThrowerNode + + def connections(self) -> Connections: + return ((self.PUBLISHER.TOPIC, self.SUBSCRIBER.TOPIC),) + + def process_modules(self) -> Sequence[Module]: + return (self.PUBLISHER, self.SUBSCRIBER, self.BACKGROUND) + + +GRAPH_TYPES = ( + PublisherThrowerGraph, + SubscriberThrowerGraph, + MainThrowerGraph, + BackgroundThrowerGraph, +) + + +@local_test +@pytest.mark.parametrize("graph_type", GRAPH_TYPES) # type: ignore +def test_parallel_throw(graph_type: Type[Graph]) -> None: + graph = graph_type() + runner = ParallelRunner(graph=graph) + with pytest.raises(ProcessManagerException) as ex: + runner.run() + assert [f for f in ex.value.failures.values() if f is not None] == [ + ProcessFailureType.EXCEPTION + ] + + +class PublisherSubscriberGraph(Graph): + PUBLISHER: PublisherNode + SUBSCRIBER: SubscriberNode + + def connections(self) -> Connections: + return ((self.PUBLISHER.TOPIC, self.SUBSCRIBER.TOPIC),) + + def logging(self) -> Dict[str, Topic]: + return {"topic": self.PUBLISHER.TOPIC} + + def process_modules(self) -> Sequence[Module]: + return (self.PUBLISHER, self.SUBSCRIBER) + + +class ThrowerLogger(Logger): + def write(self, messages_by_logging_id: Mapping[str, Sequence[Message]]) -> None: + raise MyTestException() + + +@local_test +def test_logger_throw() -> None: + graph = PublisherSubscriberGraph() + runner = ParallelRunner( + graph=graph, options=RunnerOptions(logger_type=ThrowerLogger) + ) + with pytest.raises(ProcessManagerException) as ex: + runner.run() + + assert ex.value.failures == { + LOGGER_KEY: ProcessFailureType.EXCEPTION, + "PUBLISHER": None, + "SUBSCRIBER": None, + } + assert ex.value.exceptions[LOGGER_KEY] == "MyTestException()" diff --git a/labgraph/runners/tests/test_launch.py b/labgraph/runners/tests/test_launch.py new file mode 100644 index 000000000..179e3c802 --- /dev/null +++ b/labgraph/runners/tests/test_launch.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import sys +import tempfile + +from ...util.random import random_string +from ..launch import launch + + +def test_launch() -> None: + temp_file = tempfile.NamedTemporaryFile(delete=False) + temp_file.close() + string = random_string(10) + + launch(__name__, [temp_file.name, string]).wait() + with open(temp_file.name, "r") as output_file: + result = output_file.read() + assert result == string + + +if __name__ == "__main__": + filename = sys.argv[1] + string = sys.argv[2] + with open(filename, "w") as output_file: + output_file.write(string) diff --git a/labgraph/runners/tests/test_process_manager.py b/labgraph/runners/tests/test_process_manager.py new file mode 100644 index 000000000..1b8a41a41 --- /dev/null +++ b/labgraph/runners/tests/test_process_manager.py @@ -0,0 +1,314 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import enum +import functools +import sys +import time +from typing import Optional + +import click +import pytest + +from ...util.testing import local_test +from ..process_manager import ( + ProcessFailureType, + ProcessInfo, + ProcessManager, + ProcessManagerException, + ProcessManagerState, + ProcessPhase, +) + + +TEST_STARTUP_PERIOD = 5 +TEST_SHUTDOWN_PERIOD = 3 +PROCESS_WAIT_TIME = 0.1 +PROCESS_SLEEP_TIME = 0.01 + + +class DummyException(Exception): + """ + Dummy exception for tests to raise. + """ + + pass + + +class ShutdownBehavior(enum.Enum): + """ + A shutdown behavior that `proc` can observe. + """ + + NORMAL = enum.auto() + CRASH = enum.auto() + EXCEPTION = enum.auto() + HANG = enum.auto() + + +def proc( + state: ProcessManagerState, + name: str, + manager_name: str, + shutdown: ShutdownBehavior, + last_phase: ProcessPhase = ProcessPhase.TERMINATED, +) -> None: + """ + A minimal version of a process managed by a `ProcessManager`. Used for testing the + `ProcessManager`. The process simply updates its phase and sleeps. + + Args: + state: The `ProcessManager`'s state. + name: The name of the process. + manager_name: The name of the `ProcessManager`. + shutdown: + The shutdown behavior that this process will observe: + - `ShutdownBehavior.NORMAL`: go through all phases and terminate normally. + - `ShutdownBehavior.CRASH`: exit the entire process suddenly at a certain + phase. + - `ShutdownBehavior.EXCEPTION`: raise an exception at a certain phase. + - `ShutdownBehavior.HANG: hang at a certain phase. + last_phase: + The last phase that `proc` will enter. This must be + `ProcessPhase.TERMINATED` if the shutdown behavior is normal. + """ + assert shutdown != ShutdownBehavior.NORMAL or last_phase == ProcessPhase.TERMINATED + last_phase_changed_at = time.perf_counter() + + while True: + time.sleep(PROCESS_SLEEP_TIME) + + # If the manager is stopping, set this process to be stopping + with state.lock: + if ( + state.get(manager_name) == ProcessPhase.STOPPING + and state.get(name) != ProcessPhase.STOPPING + ): + state.update(name, ProcessPhase.STOPPING) + last_phase_changed_at = time.perf_counter() + + # Leave the sleep loop if we are now in the last phase + if ProcessPhase.STOPPING.value >= last_phase.value: + break + + # Transition to the next phase if we have slept for long enough + current_time = time.perf_counter() + if current_time - last_phase_changed_at > PROCESS_WAIT_TIME: + current_phases = state.get_all() + current_phase = current_phases[name] + if ( + current_phase == ProcessPhase.READY + and current_phases[manager_name].value < ProcessPhase.READY.value + ): + continue + new_phase = { + ProcessPhase.STARTING: ProcessPhase.READY, + ProcessPhase.READY: ProcessPhase.RUNNING, + ProcessPhase.RUNNING: ProcessPhase.STOPPING, + ProcessPhase.STOPPING: ProcessPhase.TERMINATED, + }[current_phase] + state.update(name, new_phase) + last_phase_changed_at = time.perf_counter() + + # Leave the sleep loop if we are now in the last phase + if new_phase.value >= last_phase.value: + break + + if shutdown == ShutdownBehavior.EXCEPTION: + # Update the state with a dummy exception, then stop + state.set_exception(name, repr(DummyException())) + with state.lock: + if state.get(name) != ProcessPhase.STOPPING: + state.update(name, ProcessPhase.STOPPING) + time.sleep(PROCESS_WAIT_TIME) + state.update(name, ProcessPhase.TERMINATED) + return + elif shutdown == ShutdownBehavior.HANG: + # Hang forever; the `ProcessManager` should then kill this process + while True: + time.sleep(PROCESS_SLEEP_TIME) + + +@local_test +def test_normal() -> None: + """ + Tests that we can run multiple processes that terminate normally. + """ + manager = ProcessManager( + processes=( + ProcessInfo( + module=__name__, + name="proc1", + args=("--manager-name", "test_manager", "--shutdown", "NORMAL"), + ), + ProcessInfo( + module=__name__, + name="proc2", + args=("--manager-name", "test_manager", "--shutdown", "NORMAL"), + ), + ), + name="test_manager", + startup_period=TEST_STARTUP_PERIOD, + shutdown_period=TEST_SHUTDOWN_PERIOD, + ) + + manager.run() + + +@pytest.mark.parametrize( + "crash_phase", + ( + ProcessPhase.STARTING, + ProcessPhase.READY, + ProcessPhase.RUNNING, + ProcessPhase.STOPPING, + ), +) +@local_test +def test_crash(crash_phase: ProcessPhase) -> None: + """ + Tests that we can run multiple processes where one of them crashes. + """ + manager = ProcessManager( + processes=( + ProcessInfo( + module=__name__, + name="proc1", + args=( + "--manager-name", + "test_manager", + "--shutdown", + "CRASH", + "--last-phase", + crash_phase.name, + ), + ), + ProcessInfo( + module=__name__, + name="proc2", + args=("--manager-name", "test_manager", "--shutdown", "NORMAL"), + ), + ), + name="test_manager", + startup_period=TEST_STARTUP_PERIOD, + shutdown_period=TEST_SHUTDOWN_PERIOD, + ) + + with pytest.raises(ProcessManagerException) as ex: + manager.run() + assert ex.value.failures == {"proc1": ProcessFailureType.CRASH, "proc2": None} + + +@pytest.mark.parametrize( + "exception_phase", + ( + ProcessPhase.STARTING, + ProcessPhase.READY, + ProcessPhase.RUNNING, + ProcessPhase.STOPPING, + ), +) +@local_test +def test_exception(exception_phase: ProcessPhase) -> None: + """ + Tests that we can run multiple processes where one of them raises an exception. + """ + manager = ProcessManager( + processes=( + ProcessInfo( + module=__name__, + name="proc1", + args=( + "--manager-name", + "test_manager", + "--shutdown", + "EXCEPTION", + "--last-phase", + exception_phase.name, + ), + ), + ProcessInfo( + module=__name__, + name="proc2", + args=("--manager-name", "test_manager", "--shutdown", "NORMAL"), + ), + ), + name="test_manager", + startup_period=TEST_STARTUP_PERIOD, + shutdown_period=TEST_SHUTDOWN_PERIOD, + ) + + with pytest.raises(ProcessManagerException) as ex: + manager.run() + assert ex.value.failures == {"proc1": ProcessFailureType.EXCEPTION, "proc2": None} + + +@pytest.mark.parametrize( + "hang_phase", + ( + ProcessPhase.STARTING, + ProcessPhase.READY, + ProcessPhase.RUNNING, + ProcessPhase.STOPPING, + ), +) +@local_test +def test_hang(hang_phase: ProcessPhase) -> None: + """ + Tests that we can run multiple processes where one of them hangs. + """ + manager = ProcessManager( + processes=( + ProcessInfo( + module=__name__, + name="proc1", + args=( + "--manager-name", + "test_manager", + "--shutdown", + "HANG", + "--last-phase", + hang_phase.name, + ), + ), + ProcessInfo( + module=__name__, + name="proc2", + args=("--manager-name", "test_manager", "--shutdown", "NORMAL"), + ), + ), + name="test_manager", + startup_period=TEST_STARTUP_PERIOD, + shutdown_period=TEST_SHUTDOWN_PERIOD, + ) + + with pytest.raises(ProcessManagerException) as ex: + manager.run() + assert ex.value.failures == {"proc1": ProcessFailureType.HANG, "proc2": None} + + +@click.command() +@click.option(f"--{ProcessManagerState.SUBPROCESS_ARG}", required=True) +@click.option("--process-name", required=True) +@click.option("--manager-name", required=True) +@click.option("--shutdown", required=True) +@click.option("--last-phase") +def child_main( + process_manager_state_file: str, + process_name: str, + manager_name: str, + shutdown: str, + last_phase: Optional[str] = None, +) -> None: + proc( + ProcessManagerState.load(process_manager_state_file), + process_name, + manager_name, + ShutdownBehavior[shutdown], + ProcessPhase[last_phase] if last_phase is not None else ProcessPhase.TERMINATED, + ) + + +if __name__ == "__main__": + if f"--{ProcessManagerState.SUBPROCESS_ARG}" in sys.argv: + child_main() diff --git a/labgraph/runners/tests/test_runner.py b/labgraph/runners/tests/test_runner.py new file mode 100644 index 000000000..2b7df2c5d --- /dev/null +++ b/labgraph/runners/tests/test_runner.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import json +import os +import threading +from pathlib import Path +from typing import Dict, Sequence, Union + +import h5py +import pytest + +from ...graphs.config import Config +from ...graphs.graph import Graph +from ...graphs.group import Connections, Group +from ...graphs.method import AsyncPublisher, background, main, publisher, subscriber +from ...graphs.module import Module +from ...graphs.node import Node +from ...graphs.topic import Topic +from ...messages.message import Message +from ...util.random import random_string +from ...util.testing import get_test_filename, local_test +from ..exceptions import NormalTermination +from ..local_runner import LocalRunner +from ..parallel_runner import ParallelRunner + + +NUM_MESSAGES = 30 +SAMPLE_RATE = 10 + +LOCAL_OUTPUT_FILENAME = get_test_filename("json") +DISTRIBUTED_OUTPUT_FILENAME = get_test_filename("json") +PARALLEL_ONE_PROCESS_FILENAME = get_test_filename("json") + + +class MyMessage1(Message): + int_field: int + + +class MyMessage2(Message): + str_field: str + + +class MySource(Node): + A = Topic(MyMessage1) + + def __init__(self) -> None: + super(MySource, self).__init__() + + @publisher(A) + async def source(self) -> AsyncPublisher: + for i in range(NUM_MESSAGES): + yield self.A, MyMessage1(int_field=i) + await asyncio.sleep(1 / SAMPLE_RATE) + + +class MyTransform(Node): + B = Topic(MyMessage1) + C = Topic(MyMessage2) + + @subscriber(B) + @publisher(C) + async def transform(self, message: MyMessage1) -> AsyncPublisher: + yield self.C, MyMessage2(str_field=str(message.int_field)) + + +class MySinkConfig(Config): + output_filename: str + + +class MySink(Node): + D = Topic(MyMessage2) + config: MySinkConfig + + def setup(self) -> None: + self.messages_seen: int = 0 + + @subscriber(D) + def sink(self, message: MyMessage2) -> None: + with open(self.config.output_filename, "a") as output_file: + output_file.write(json.dumps(message.asdict()) + "\n") + self.messages_seen += 1 + if self.messages_seen == NUM_MESSAGES: + raise NormalTermination() + + +class MyLocalGraph(Graph): + config: MySinkConfig + + SOURCE: MySource + TRANSFORM: MyTransform + SINK: MySink + + def setup(self) -> None: + self.SINK.configure(self.config) + + def connections(self) -> Connections: + return ((self.SOURCE.A, self.TRANSFORM.B), (self.TRANSFORM.C, self.SINK.D)) + + def logging(self) -> Dict[str, Topic]: + return {"source_a": self.SOURCE.A, "transform_c": self.TRANSFORM.C} + + +@local_test +def test_local_run() -> None: + runner = LocalRunner( + module=MyLocalGraph(config=MySinkConfig(output_filename=LOCAL_OUTPUT_FILENAME)) + ) + runner.run() + remaining_numbers = {str(i) for i in range(NUM_MESSAGES)} + with open(LOCAL_OUTPUT_FILENAME, "r") as output_file: + lines = output_file.readlines() + assert len(lines) == NUM_MESSAGES + for line in lines: + message = MyMessage2.fromdict(json.loads(line)) + assert message.str_field in remaining_numbers + remaining_numbers.remove(message.str_field) + + assert len(remaining_numbers) == 0 + os.remove(LOCAL_OUTPUT_FILENAME) + + +class PubGroup(Group): + SOURCE: MySource + TRANSFORM: MyTransform + + def connections(self) -> Connections: + return ((self.SOURCE.A, self.TRANSFORM.B),) + + +class SubGroup(Group): + SINK: MySink + config: MySinkConfig + + def setup(self) -> None: + self.SINK.configure(self.config) + + +class MyDistributedConfig(Config): + output_filename: str + + +class MyDistributedGraph(Graph): + PUB: PubGroup + SUB: SubGroup + + config: MyDistributedConfig + + def setup(self) -> None: + self.SUB.configure(MySinkConfig(output_filename=self.config.output_filename)) + + def connections(self) -> Connections: + return ((self.PUB.TRANSFORM.C, self.SUB.SINK.D),) + + def process_modules(self) -> Sequence[Module]: + return (self.PUB, self.SUB) + + def logging(self) -> Dict[str, Topic]: + return {"source_a": self.PUB.SOURCE.A, "transform_c": self.PUB.TRANSFORM.C} + + +@local_test +def test_parallel_run() -> None: + graph = MyDistributedGraph() + graph.configure(MyDistributedConfig(output_filename=DISTRIBUTED_OUTPUT_FILENAME)) + runner = ParallelRunner(graph=graph) + runner.run() + + remaining_numbers = {str(i) for i in range(NUM_MESSAGES)} + with open(DISTRIBUTED_OUTPUT_FILENAME, "r") as output_file: + lines = output_file.readlines() + assert len(lines) == NUM_MESSAGES + for line in lines: + message = MyMessage2.fromdict(json.loads(line)) + assert message.str_field in remaining_numbers + remaining_numbers.remove(message.str_field) + + assert len(remaining_numbers) == 0 + os.remove(DISTRIBUTED_OUTPUT_FILENAME) + + +class MyBackgroundMainConfig(Config): + background_filename: str + main_filename: str + string: str + + +class MyBackgroundMainNode(Node): + config: MyBackgroundMainConfig + + def setup(self) -> None: + self.barrier = threading.Barrier(2) + + @background + async def my_background(self) -> None: + with open(self.config.background_filename, "w") as f: + f.write(self.config.string) + self.barrier.wait() + + @main + def my_main(self) -> None: + with open(self.config.main_filename, "w") as f: + f.write(self.config.string) + self.barrier.wait() + raise NormalTermination() + + +@local_test +def test_background_method() -> None: + """ + Tests that methods decorated with `@background` and `@main` are executed correctly. + """ + test_background_filename = get_test_filename() + test_main_filename = get_test_filename() + test_string = random_string(100) + + node = MyBackgroundMainNode() + node.configure( + MyBackgroundMainConfig( + background_filename=test_background_filename, + main_filename=test_main_filename, + string=test_string, + ) + ) + runner = LocalRunner(module=node) + runner.run() + with open(test_background_filename, "r") as f: + background_written_string = f.read() + assert test_string == background_written_string + with open(test_main_filename, "r") as f: + main_written_string = f.read() + assert test_string == main_written_string + + +@local_test +def test_parallel_logging() -> None: + """ + Tests that a `ParallelRunner` can log to disk. + """ + graph = MyDistributedGraph() + graph.configure(MyDistributedConfig(output_filename=DISTRIBUTED_OUTPUT_FILENAME)) + runner = ParallelRunner(graph=graph) + runner.run() + + output_path = str( + Path(runner._options.logger_config.output_directory) + / Path(f"{runner._options.logger_config.recording_name}.h5") + ) + + with h5py.File(output_path, "r") as h5py_file: + for hdf5_path in ("source_a", "transform_c"): + dataset = h5py_file[hdf5_path] + assert dataset.shape == (NUM_MESSAGES,) + dataset_nums = {int(num[0]) for num in dataset} + assert dataset_nums == set(range(NUM_MESSAGES)) + + +@local_test +def test_parallel_one_process() -> None: + """ + Tests that a `ParallelRunner` runs on a graph with only one process. + """ + runner = ParallelRunner( + graph=MyLocalGraph( + config=MySinkConfig(output_filename=PARALLEL_ONE_PROCESS_FILENAME) + ) + ) + runner.run() + remaining_numbers = {str(i) for i in range(NUM_MESSAGES)} + with open(PARALLEL_ONE_PROCESS_FILENAME, "r") as output_file: + lines = output_file.readlines() + assert len(lines) == NUM_MESSAGES + for line in lines: + message = MyMessage2.fromdict(json.loads(line)) + assert message.str_field in remaining_numbers + remaining_numbers.remove(message.str_field) + + assert len(remaining_numbers) == 0 + os.remove(PARALLEL_ONE_PROCESS_FILENAME) diff --git a/labgraph/runners/util.py b/labgraph/runners/util.py new file mode 100644 index 000000000..13228ef5b --- /dev/null +++ b/labgraph/runners/util.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import importlib +import inspect +from typing import Type + +from ..graphs.module import Module + + +def get_module_class(python_module: str, python_class: str) -> Type[Module]: + mod = importlib.import_module(python_module) + + if hasattr(mod, python_class): + cls = getattr(mod, python_class) + else: + # We are going to check if the module was merely renamed by checking + # the `__name__` attribute of every class in the module. + real_class_name = python_class + + for attr_name in dir(mod): + attr = getattr(mod, attr_name) + if inspect.isclass(attr): + if attr.__name__ == real_class_name: + # We found the rename + python_class = attr_name + break + else: + raise NameError( + f"Could not find LabGraph a class in module `{python_module}`` with " + f"the following class.__name__: `{real_class_name}`. " + f"If it refers to an anonymous class, consider moving it " + f"to the module scope of {python_module}." + ) + cls = getattr(mod, python_class) + assert issubclass( + cls, Module + ), f"Expected a subclass of {Module.__name__}, got {cls.__name__}" + if not issubclass(cls, Module): + raise TypeError(f"Expected a subclass of {Module.__name__}, got {cls.__name__}") + return cls # type: ignore diff --git a/labgraph/simulations/__init__.py b/labgraph/simulations/__init__.py new file mode 100644 index 000000000..f6770fe4d --- /dev/null +++ b/labgraph/simulations/__init__.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "FunctionGenerator", + "FunctionChannelConfig", + "FunctionGeneratorMessage", + "FunctionGeneratorNode", +] + +from .function_generator import ( + FunctionChannelConfig, + FunctionGenerator, + FunctionGeneratorMessage, +) +from .function_generator_node import FunctionGeneratorNode diff --git a/labgraph/simulations/function_generator.py b/labgraph/simulations/function_generator.py new file mode 100644 index 000000000..eb592ca98 --- /dev/null +++ b/labgraph/simulations/function_generator.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import List, Tuple + +from numpy import ndarray + +from ..messages.message import TimestampedMessage + + +@dataclass +class FunctionChannelConfig: + shape: Tuple[int] + + +class FunctionGeneratorMessage(TimestampedMessage): + data: ndarray + + +class FunctionGenerator(ABC): + """ + Abstract base class for a function generator. Derived generators + should implement logic for generating some function. + """ + + def set_channel_config(self, channel_config: FunctionChannelConfig) -> None: + """ + Sets the configuration object specifying how data should be generated + across channels for this generator. + + Args: + channel_config: The channel configuration object. + """ + + self.channel_config = channel_config + + @abstractmethod + def next_sample(self) -> FunctionGeneratorMessage: + """ + Returns the next sample that should be produced in the + experiment based on the current state information. + """ + + raise NotImplementedError() + + def next_n_samples(self, n: int = 1) -> List[ndarray]: + """ + Returns the next n samples that should be produced in the + experiment based on the current state information. + + Args: + n: The number of samples that should be produced. 1 by default. + """ + + samples = [self.next_sample() for _ in range(n)] + + return samples diff --git a/labgraph/simulations/function_generator_node.py b/labgraph/simulations/function_generator_node.py new file mode 100644 index 000000000..9f1e2dc83 --- /dev/null +++ b/labgraph/simulations/function_generator_node.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from .._cthulhu.clock import ExperimentClock +from ..graphs.node import Node +from .function_generator import FunctionGenerator + + +class FunctionGeneratorNode(Node): + """ + A node which generates samples to the graph based on + user-specified functions. + """ + + def __init__(self) -> None: + super().__init__() + self._clock = ExperimentClock() + + def set_generator(self, generator: FunctionGenerator) -> None: + self._generator = generator diff --git a/labgraph/tests/__init__.py b/labgraph/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/labgraph/tests/mypy.ini b/labgraph/tests/mypy.ini new file mode 100644 index 000000000..d5c7dda1a --- /dev/null +++ b/labgraph/tests/mypy.ini @@ -0,0 +1,43 @@ +[mypy] +python_version = 3.6 +namespace_packages = true +show_error_context = true +show_column_numbers = true +pretty = true +no_site_packages = true + +# Add libraries below that don't have mypy stubs +[mypy-appdirs.*] +ignore_missing_imports = true +[mypy-cthulhubindings.*] +ignore_missing_imports = true +[mypy-labgraph_cpp.*] +ignore_missing_imports = true +[mypy-h5py.*] +ignore_missing_imports = true +[mypy-*.labgraph_viz.*] +ignore_missing_imports = true +[mypy-matplotlib.*] +ignore_missing_imports = true +[mypy-MyCPPNodes.*] +ignore_missing_imports = true +[mypy-numpy.*] +ignore_missing_imports = true +[mypy-pip.*] +ignore_missing_imports = true +[mypy-psutil.*] +ignore_missing_imports = true +[mypy-pytest.*] +ignore_missing_imports = true +[mypy-setuptools.*] +ignore_missing_imports = true +[mypy-scipy.*] +ignore_missing_imports = true +[mypy-typeguard.*] +ignore_missing_imports = true +[mypy-wheel.*] +ignore_missing_imports = true +[mypy-yappi.*] +ignore_missing_imports = true +[mypy-zmq.*] +ignore_missing_imports = true diff --git a/labgraph/tests/test_imports.py b/labgraph/tests/test_imports.py new file mode 100644 index 000000000..70ea32084 --- /dev/null +++ b/labgraph/tests/test_imports.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + + +def test_imports() -> None: + """ + Tests that we can import top-level LabGraph objects correctly. + """ + + from .. import ( # noqa: F401 + Aligner, + AsyncPublisher, + background, + BaseEventGenerator, + BaseEventGeneratorNode, + CFloatType, + CIntType, + Config, + Connections, + CPPNodeConfig, + DeferredMessage, + LabGraphError, + Event, + EventGraph, + EventPublishingHeap, + EventPublishingHeapEntry, + FieldType, + FloatType, + Graph, + Group, + HDF5Logger, + IntType, + LocalRunner, + Logger, + LoggerConfig, + main, + Message, + Module, + Node, + NodeTestHarness, + NormalTermination, + NumpyType, + ParallelRunner, + publisher, + run_with_harness, + run, + RunnerOptions, + State, + StrType, + subscriber, + TerminationMessage, + TimestampAligner, + TimestampedMessage, + Topic, + WaitBeginMessage, + WaitEndMessage, + ) diff --git a/labgraph/tests/test_typecheck.py b/labgraph/tests/test_typecheck.py new file mode 100644 index 000000000..2ba075e86 --- /dev/null +++ b/labgraph/tests/test_typecheck.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import os +import runpy +import shutil +import subprocess +import tempfile +from glob import glob +from pathlib import Path +from typing import Optional +from zipfile import ZipFile + +import labgraph as lg + +from ..runners.launch import _get_pex_path, _in_pex, launch +from ..util.logger import get_logger +from ..util.resource import get_resource_tempfile + + +SOURCE_PATH = "labgraph" + +logger = get_logger(__name__) + + +def test_typecheck() -> None: + """ + Typechecks LabGraph using mypy. Assumes that the test is running from a PEX (if + not, the test skips). + """ + mypy_ini_path = get_resource_tempfile(__name__, "mypy.ini") + mypy_args = ["--config-file", mypy_ini_path] + + zip_path: Optional[str] = None + try: + # If available, get the path to the typecheck_src.zip source archive + zip_path = get_resource_tempfile(__name__, "typecheck_src.zip") + except FileNotFoundError: + pass # Just let zip_path be None and handle this case below + + temp_dir: Optional[tempfile.TemporaryDirectory] = None + if zip_path is None: + # If the source archive is not available, typecheck the installed location + # for LabGraph + src_path = str(Path(lg.__file__).parent) + mypy_args += glob(f"{src_path}/**/*.py", recursive=True) + else: + # If available, typecheck the typecheck_src.zip source archive + temp_dir = tempfile.TemporaryDirectory() # noqa: P201 + src_path = temp_dir.name + # Extract the source files from the zip file + src_file = ZipFile(zip_path) + for file_path in src_file.namelist(): + if file_path.startswith(SOURCE_PATH) and file_path.endswith(".py"): + src_file.extract(file_path, src_path) + mypy_args.append(file_path) + + # Typecheck in a subprocess + mypy_proc = launch("mypy", mypy_args, cwd=src_path, stdout=subprocess.PIPE) + mypy_output: Optional[str] = None + if mypy_proc.stdout is not None: + mypy_output = mypy_proc.stdout.read().decode("utf-8") + mypy_proc.wait() + + if temp_dir is not None: + temp_dir.cleanup() + + if mypy_proc.returncode != 0: + error_message = f"Typechecking failed (exit code {mypy_proc.returncode})" + if mypy_output is not None: + logger.error(mypy_output) + error_message += f":\n\n{mypy_output}" + raise RuntimeError(error_message) diff --git a/labgraph/util/__init__.py b/labgraph/util/__init__.py new file mode 100644 index 000000000..28c03ef4a --- /dev/null +++ b/labgraph/util/__init__.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +__all__ = [ + "LabGraphError", + "get_resource_tempfile", + "get_test_filename", + "async_test", + "local_test", + "get_free_port", +] + +from .error import LabGraphError +from .resource import get_resource_tempfile +from .testing import async_test, get_free_port, get_test_filename, local_test diff --git a/labgraph/util/error.py b/labgraph/util/error.py new file mode 100644 index 000000000..e62f9d85f --- /dev/null +++ b/labgraph/util/error.py @@ -0,0 +1,11 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + + +class LabGraphError(Exception): + """ + Represents a LabGraph error. `LabGraphError` Will be raised when an error is tied + to particular LabGraph concepts such as graph construction. + """ + + pass diff --git a/labgraph/util/logger.py b/labgraph/util/logger.py new file mode 100644 index 000000000..09bf13f3a --- /dev/null +++ b/labgraph/util/logger.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import logging +import os + + +def get_log_level() -> str: + return os.environ.get("LOGLEVEL", "INFO").upper() + + +logging.basicConfig(level=getattr(logging, get_log_level())) + + +def get_logger(module_name: str) -> logging.Logger: + logger = logging.getLogger(module_name) + logger.setLevel(get_log_level()) + return logger diff --git a/labgraph/util/min_heap.py b/labgraph/util/min_heap.py new file mode 100644 index 000000000..b91a0e852 --- /dev/null +++ b/labgraph/util/min_heap.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from dataclasses import dataclass, field +from heapq import heappop, heappush +from typing import TypeVar, Generic, List, Optional + +HeapEntry = TypeVar("HeapEntry") + + +@dataclass +class MinHeap(Generic[HeapEntry]): + count = 0 + heap: List[HeapEntry] = field(default_factory=list) + + def push(self, entry: HeapEntry) -> None: + heappush(self.heap, entry) + self.count += 1 + + def pop(self) -> HeapEntry: + return heappop(self.heap) + + def __getitem__(self, index: int) -> HeapEntry: + return self.heap[index] + + def __len__(self) -> int: + return len(self.heap) diff --git a/labgraph/util/random.py b/labgraph/util/random.py new file mode 100644 index 000000000..0d2e12758 --- /dev/null +++ b/labgraph/util/random.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import random +import string + + +def random_string( + length: int, characters: str = string.ascii_letters + string.digits +) -> str: + """ + Generates a random string of a given length from a given character set. + + Args: + length: The length of the string to generate. + characters: A string containing characters to choose from. + """ + return "".join(random.choice(characters) for _ in range(length)) diff --git a/labgraph/util/resource.py b/labgraph/util/resource.py new file mode 100644 index 000000000..f1ea38a2e --- /dev/null +++ b/labgraph/util/resource.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import pkgutil +import sys +import tempfile +import zipimport + + +def get_resource_tempfile(package: str, resource: str) -> str: + """ + Returns a filename for a resource. Works even in zipped packages. + + Args: + package: The package the resource is contained in. + resource: The name of the resource. + """ + with tempfile.NamedTemporaryFile(mode="wb", delete=False) as temp_file: + try: + data = pkgutil.get_data(package, resource) + assert data is not None + temp_file.write(data) + except (NotADirectoryError, FileNotFoundError): + if sys.argv[0].endswith(".pex"): + pex_path = sys.argv[0] + elif sys.argv[1].endswith(".pex"): + pex_path = sys.argv[1] + else: + raise + zip_importer = zipimport.zipimporter(pex_path) + temp_file.write( + zip_importer.get_data( # type: ignore + package.replace(".", "/") + "/" + resource + ) + ) + return temp_file.name diff --git a/labgraph/util/testing.py b/labgraph/util/testing.py new file mode 100644 index 000000000..c1233d343 --- /dev/null +++ b/labgraph/util/testing.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import os +import socket +import tempfile +from contextlib import closing +from pathlib import Path +from typing import Any, Callable + +import pytest + +from .random import random_string + + +FILENAME_LENGTH = 16 + +# Flag used to indicate that we are running in Sandcastle, and therefore should skip +# local tests. +# +# Some documentation of this env var here: https://fburl.com/wiki/9is1b6ks +SANDCASTLE_TEST_FLAG = "SANDCASTLE_NEXUS" + + +def get_test_filename(extension: str = "txt") -> str: + """ + Returns a filename for testing purposes in the system temporary directory. + + Args: + extension: The extension for the file. + """ + + file_path = str( + Path(tempfile.gettempdir()) + / Path(f"{random_string(FILENAME_LENGTH)}.{extension}") + ) + + # Create the file + with open(file_path, "w"): + pass + + return file_path + + +def async_test(test: Callable[..., Any]) -> Callable[..., Any]: + """ + Decorator for running an async test in an asyncio event loop. + + Args: + test: The test function to decorate. + """ + + def test_wrapped(*args: Any, **kwargs: Any) -> None: + get_event_loop().run_until_complete(test(*args, **kwargs)) + + return test_wrapped + + +def local_test(test: Callable[..., Any]) -> Callable[..., Any]: + return pytest.mark.skipif( # type: ignore + SANDCASTLE_TEST_FLAG in os.environ, reason="local test, skipping in Sandcastle" + )(test) + + +def get_free_port() -> int: + with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s: + s.bind(("", 0)) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + return s.getsockname()[1] # type: ignore + + +def get_event_loop() -> asyncio.AbstractEventLoop: + loop = asyncio.get_event_loop() + if loop.is_closed(): + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop diff --git a/labgraph/util/version.py b/labgraph/util/version.py new file mode 100644 index 000000000..dfb4605f4 --- /dev/null +++ b/labgraph/util/version.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# Constant representing the version of LabGraph. +VERSION = "1.0.0" diff --git a/labgraph/zmq_node/__init__.py b/labgraph/zmq_node/__init__.py new file mode 100644 index 000000000..af3d62ad5 --- /dev/null +++ b/labgraph/zmq_node/__init__.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +# flake8: noqa + +__all__ = [ + "ZMQMessage", + "ZMQPollerNode", + "ZMQSenderNode", + "ZMQPollerConfig", + "ZMQSenderConfig", +] + +from .zmq_message import ZMQMessage +from .zmq_poller_node import ZMQPollerConfig, ZMQPollerNode +from .zmq_sender_node import ZMQSenderConfig, ZMQSenderNode diff --git a/labgraph/zmq_node/constants.py b/labgraph/zmq_node/constants.py new file mode 100644 index 000000000..f3f8d4912 --- /dev/null +++ b/labgraph/zmq_node/constants.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from enum import IntEnum + +import zmq + + +class ZMQEvent(IntEnum): + """ + Convenience enum that allows us to map zmq events (which are just ints) to their + human-readable labels. + """ + + EVENT_CONNECTED = zmq.EVENT_CONNECTED + EVENT_CONNECT_DELAYED = zmq.EVENT_CONNECT_DELAYED + EVENT_CONNECT_RETRIED = zmq.EVENT_CONNECT_RETRIED + EVENT_LISTENING = zmq.EVENT_LISTENING + EVENT_BIND_FAILED = zmq.EVENT_BIND_FAILED + EVENT_ACCEPTED = zmq.EVENT_ACCEPTED + EVENT_ACCEPT_FAILED = zmq.EVENT_ACCEPT_FAILED + EVENT_CLOSED = zmq.EVENT_CLOSED + EVENT_CLOSE_FAILED = zmq.EVENT_CLOSE_FAILED + EVENT_DISCONNECTED = zmq.EVENT_DISCONNECTED + EVENT_MONITOR_STOPPED = zmq.EVENT_MONITOR_STOPPED + EVENT_ALL = zmq.EVENT_ALL + EVENT_HANDSHAKE_FAILED_NO_DETAIL = zmq.EVENT_HANDSHAKE_FAILED_NO_DETAIL + EVENT_HANDSHAKE_SUCCEEDED = zmq.EVENT_HANDSHAKE_SUCCEEDED + EVENT_HANDSHAKE_FAILED_PROTOCOL = zmq.EVENT_HANDSHAKE_FAILED_PROTOCOL + EVENT_HANDSHAKE_FAILED_AUTH = zmq.EVENT_HANDSHAKE_FAILED_AUTH diff --git a/labgraph/zmq_node/tests/__init__.py b/labgraph/zmq_node/tests/__init__.py new file mode 100644 index 000000000..860ac27c6 --- /dev/null +++ b/labgraph/zmq_node/tests/__init__.py @@ -0,0 +1,2 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. diff --git a/labgraph/zmq_node/tests/test_zmq_node.py b/labgraph/zmq_node/tests/test_zmq_node.py new file mode 100644 index 000000000..fd6cd57d6 --- /dev/null +++ b/labgraph/zmq_node/tests/test_zmq_node.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio +import os +import time +from multiprocessing import Process +from typing import List, Sequence + +import pytest +import zmq + +from ...graphs import ( + AsyncPublisher, + Config, + Connections, + Graph, + Module, + Node, + Topic, + publisher, + subscriber, +) +from ...runners import LocalRunner, NormalTermination, ParallelRunner +from ...util.testing import get_free_port, get_test_filename, local_test +from ..zmq_message import ZMQMessage +from ..zmq_poller_node import ZMQPollerConfig, ZMQPollerNode +from ..zmq_sender_node import ZMQSenderConfig, ZMQSenderNode + + +NUM_MESSAGES = 5 +SAMPLE_RATE = 10 +STARTUP_TIME = 1 + +ZMQ_ADDR = "tcp://127.0.0.1" +ZMQ_TOPIC = "zmq_topic" + +DATA_DELIMITER = b"\0" + + +class MySinkConfig(Config): + output_filename: str + + +class MySink(Node): + """ + Convenience node for receiving messages from a `ZMQPollerNode`. + """ + + TOPIC = Topic(ZMQMessage) + config: MySinkConfig + + def setup(self) -> None: + self.output_file = open(self.config.output_filename, "wb") + self.num_received = 0 + + @subscriber(TOPIC) + async def sink(self, message: ZMQMessage) -> None: + self.output_file.write(message.data) + self.output_file.write(DATA_DELIMITER) + + self.num_received += 1 + if self.num_received == NUM_MESSAGES: + raise NormalTermination() + + def cleanup(self) -> None: + self.output_file.close() + + +class MySourceConfig(Config): + should_terminate: bool = True + + +class MySource(Node): + """ + Convenience node for sending messages to a `ZMQSenderNode`. + """ + + TOPIC = Topic(ZMQMessage) + config: MySourceConfig + samples = [bytes([i]) for i in range(1, NUM_MESSAGES + 1)] + + @publisher(TOPIC) + async def source(self) -> AsyncPublisher: + for sample_bytes in self.samples: + yield self.TOPIC, ZMQMessage(sample_bytes) + await asyncio.sleep(1 / SAMPLE_RATE) + + if self.config.should_terminate: + raise NormalTermination() + + +def write_samples_to_zmq(address: str, samples: Sequence[bytes], topic: str) -> None: + context = zmq.Context() + socket = context.socket(zmq.PUB) + socket.bind(address) + + # NOTE: In place of waiting on a monitor socket, we wait for a startup time + # here. Otherwise we would need to listen on an extra socket in this function, + # increasing the complexity of this test. If this startup wait becomes flaky, we may + # want to consider adding the monitor socket here. + time.sleep(STARTUP_TIME) + for sample_bytes in samples: + socket.send_multipart((bytes(topic, "UTF-8"), sample_bytes)) + time.sleep(1 / SAMPLE_RATE) + socket.close() + + +def recv_samples_from_zmq(address: str, topic: str, output_fname: str) -> None: + context = zmq.Context() + socket = context.socket(zmq.SUB) + socket.setsockopt(zmq.SUBSCRIBE, bytes(topic, "UTF-8")) + socket.connect(address) + + with open(output_fname, "bw") as output_file: + for _ in range(NUM_MESSAGES): + received = socket.recv_multipart() + topic, data = received + output_file.write(data) + output_file.write(DATA_DELIMITER) + socket.close() + + +@local_test +def test_zmq_poller_node() -> None: + """ + Tests that a `ZMQPollerNode` is able to read samples from a ZMQ socket and echo + the samples back out of the graph. + """ + + class MyZMQPollerGraphConfig(Config): + read_addr: str + zmq_topic: str + output_filename: str + + class MyZMQPollerGraph(Graph): + MY_SOURCE: ZMQPollerNode + MY_SINK: MySink + config: MyZMQPollerGraphConfig + + def setup(self) -> None: + self.MY_SOURCE.configure( + ZMQPollerConfig( + read_addr=self.config.read_addr, zmq_topic=self.config.zmq_topic + ) + ) + self.MY_SINK.configure( + MySinkConfig(output_filename=self.config.output_filename) + ) + + def connections(self) -> Connections: + return ((self.MY_SOURCE.topic, self.MY_SINK.TOPIC),) + + graph = MyZMQPollerGraph() + output_filename = get_test_filename() + address = f"{ZMQ_ADDR}:{get_free_port()}" + graph.configure( + MyZMQPollerGraphConfig( + read_addr=address, zmq_topic=ZMQ_TOPIC, output_filename=output_filename + ) + ) + runner = LocalRunner(module=graph) + + samples = [bytes([i]) for i in range(1, NUM_MESSAGES + 1)] + p = Process(target=write_samples_to_zmq, args=(address, samples, ZMQ_TOPIC)) + p.start() + runner.run() + p.join() + + with open(output_filename, "br") as f: + data = f.read() + assert set(samples) == set(data.strip(DATA_DELIMITER).split(DATA_DELIMITER)) + + +@local_test +def test_zmq_sender_node() -> None: + """ + Tests that a `ZMQSenderNode` is able to read samples from the graph and write the + samples back out to a ZMQ socket. + """ + + class MyZMQSenderGraph(Graph): + MY_SOURCE: MySource + MY_SINK: ZMQSenderNode + + config: ZMQSenderConfig + + def setup(self) -> None: + self.MY_SOURCE.configure(MySourceConfig()) + self.MY_SINK.configure(self.config) + + def connections(self) -> Connections: + return ((self.MY_SOURCE.TOPIC, self.MY_SINK.topic),) + + output_filename = get_test_filename() + graph = MyZMQSenderGraph() + address = f"{ZMQ_ADDR}:{get_free_port()}" + graph.configure(ZMQSenderConfig(write_addr=address, zmq_topic=ZMQ_TOPIC)) + runner = LocalRunner(module=graph) + + p = Process( + target=recv_samples_from_zmq, args=(address, ZMQ_TOPIC, output_filename) + ) + p.start() + runner.run() + p.join() + + with open(output_filename, "br") as f: + data = f.read() + assert set(graph.MY_SOURCE.samples) == set( + data.strip(DATA_DELIMITER).split(DATA_DELIMITER) + ) + + +@local_test +def test_zmq_send_and_poll() -> None: + """ + Tests that a `ZMQSenderNode` and a `ZMQPollerNode` can work together. + """ + + class MyZMQGraphConfig(Config): + addr: str + zmq_topic: str + output_filename: str + + class MyZMQGraph(Graph): + DF_SOURCE: MySource + ZMQ_SENDER: ZMQSenderNode + ZMQ_POLLER: ZMQPollerNode + DF_SINK: MySink + + def setup(self) -> None: + self.DF_SOURCE.configure(MySourceConfig(should_terminate=False)) + self.ZMQ_SENDER.configure( + ZMQSenderConfig( + write_addr=self.config.addr, zmq_topic=self.config.zmq_topic + ) + ) + self.ZMQ_POLLER.configure( + ZMQPollerConfig( + read_addr=self.config.addr, zmq_topic=self.config.zmq_topic + ) + ) + self.DF_SINK.configure( + MySinkConfig(output_filename=self.config.output_filename) + ) + + def connections(self) -> Connections: + return ( + (self.DF_SOURCE.TOPIC, self.ZMQ_SENDER.topic), + (self.ZMQ_POLLER.topic, self.DF_SINK.TOPIC), + ) + + def process_modules(self) -> Sequence[Module]: + return (self.DF_SOURCE, self.ZMQ_SENDER, self.ZMQ_POLLER, self.DF_SINK) + + output_filename = get_test_filename() + graph = MyZMQGraph() + address = f"{ZMQ_ADDR}:{get_free_port()}" + graph.configure( + MyZMQGraphConfig( + addr=address, zmq_topic=ZMQ_TOPIC, output_filename=output_filename + ) + ) + runner = ParallelRunner(graph=graph) + runner.run() + + with open(output_filename, "br") as f: + data = f.read() + assert set(graph.DF_SOURCE.samples) == set( + data.strip(DATA_DELIMITER).split(DATA_DELIMITER) + ) diff --git a/labgraph/zmq_node/zmq_message.py b/labgraph/zmq_node/zmq_message.py new file mode 100644 index 000000000..f7fe4058e --- /dev/null +++ b/labgraph/zmq_node/zmq_message.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from ..messages import Message +from ..messages.types import BytesType + + +class ZMQMessage(Message): + """ + A message representing data that was/will be communicated + to ZMQ. + """ + + data: bytes diff --git a/labgraph/zmq_node/zmq_poller_node.py b/labgraph/zmq_node/zmq_poller_node.py new file mode 100644 index 000000000..5c7b7a359 --- /dev/null +++ b/labgraph/zmq_node/zmq_poller_node.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio + +import zmq +import zmq.asyncio +from zmq.utils.monitor import parse_monitor_message + +from ..graphs import AsyncPublisher, Config, Node, Topic, background, publisher +from ..util.logger import get_logger +from ..zmq_node import ZMQMessage +from .constants import ZMQEvent + + +POLL_TIME = 0.1 + +logger = get_logger(__name__) + + +class ZMQPollerConfig(Config): + read_addr: str + zmq_topic: str + poll_time: float = POLL_TIME + + +class ZMQPollerNode(Node): + """ + Represents a node in the graph which polls data from ZMQ. + Data polled from ZMQ are subsequently pushed to the rest of the + graph as a ZMQMessage. + + Args: + read_addr: The address from which ZMQ data should be polled. + zmq_topic: The ZMQ topic being polled. + timeout: + The maximum amount of time (in seconds) that should be + spent polling a ZMQ socket each time. Defaults to + FOREVER_POLL_TIME if not specified. + exit_condition: + An optional ZMQ event code specifying the event which, + if encountered by the monitor, should signal the termination + of this particular node's activity. + """ + + topic = Topic(ZMQMessage) + config: ZMQPollerConfig + + def setup(self) -> None: + self.context = zmq.asyncio.Context() + self.socket = self.context.socket(zmq.SUB) + self.monitor = self.socket.get_monitor_socket() + self.socket.connect(self.config.read_addr) + self.socket.subscribe(self.config.zmq_topic) + + self.poller = zmq.Poller() + self.poller.register(self.socket, zmq.POLLIN) + + self.socket_open = False + + def cleanup(self) -> None: + self.socket.close() + + @background + async def socket_monitor(self) -> None: + while True: + monitor_result = await self.monitor.poll(100, zmq.POLLIN) + if monitor_result: + data = await self.monitor.recv_multipart() + evt = parse_monitor_message(data) + + event = ZMQEvent(evt["event"]) + logger.debug(f"{self}:{event.name}") + + if event == ZMQEvent.EVENT_CONNECTED: + self.socket_open = True + elif event == ZMQEvent.EVENT_CLOSED: + was_open = self.socket_open + self.socket_open = False + # ZMQ seems to be sending spurious CLOSED event when we + # try to connect before the source is running. Only give up + # if we were previously connected. If we give up now, we + # will never unblock zmq_publisher. + if was_open: + break + elif event in ( + ZMQEvent.EVENT_DISCONNECTED, + ZMQEvent.EVENT_MONITOR_STOPPED, + ): + self.socket_open = False + break + + @publisher(topic) + async def zmq_publisher(self) -> AsyncPublisher: + # Wait for socket connection + while not self.socket_open: + await asyncio.sleep(POLL_TIME) + + while self.socket_open: + poll_result = await self.socket.poll( + self.config.poll_time * 1000, zmq.POLLIN + ) + if poll_result: + _, data = await self.socket.recv_multipart() + yield self.topic, ZMQMessage(data) diff --git a/labgraph/zmq_node/zmq_sender_node.py b/labgraph/zmq_node/zmq_sender_node.py new file mode 100644 index 000000000..38fbf65ba --- /dev/null +++ b/labgraph/zmq_node/zmq_sender_node.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +import asyncio + +import zmq +import zmq.asyncio +from zmq.utils.monitor import parse_monitor_message + +from ..graphs import Config, Node, Topic, background, subscriber +from ..util.logger import get_logger +from ..zmq_node import ZMQMessage +from .constants import ZMQEvent + + +STARTUP_WAIT_TIME = 0.1 + +logger = get_logger(__name__) + + +class ZMQSenderConfig(Config): + write_addr: str + zmq_topic: str + + +class ZMQSenderNode(Node): + """ + Represents a node in a LabGraph graph that subscribes to messages in a + LabGraph topic and forwards them by writing to a ZMQ socket. + + Args: + write_addr: The address to which ZMQ data should be written. + zmq_topic: The ZMQ topic being sent. + """ + + topic = Topic(ZMQMessage) + config: ZMQSenderConfig + + def setup(self) -> None: + self.context = zmq.asyncio.Context() + self.socket = self.context.socket(zmq.PUB) + self.monitor = self.socket.get_monitor_socket() + logger.debug(f"{self}:binding to {self.config.write_addr}") + self.socket.bind(self.config.write_addr) + self.has_subscribers = False + + def cleanup(self) -> None: + self.socket.close() + + @background + async def _socket_monitor(self) -> None: + while True: + monitor_result = await self.monitor.poll(100, zmq.POLLIN) + if monitor_result: + data = await self.monitor.recv_multipart() + evt = parse_monitor_message(data) + + event = ZMQEvent(evt["event"]) + logger.debug(f"{self}:{event.name}") + + if event == ZMQEvent.EVENT_ACCEPTED: + logger.debug(f"{self}:subscriber joined") + self.has_subscribers = True + elif event in ( + ZMQEvent.EVENT_DISCONNECTED, + ZMQEvent.EVENT_MONITOR_STOPPED, + ZMQEvent.EVENT_CLOSED, + ): + break + + @subscriber(topic) + async def zmq_subscriber(self, message: ZMQMessage) -> None: + while not self.has_subscribers: + await asyncio.sleep(STARTUP_WAIT_TIME) + await self.socket.send_multipart( + (bytes(self.config.zmq_topic, "UTF-8"), message.data), flags=zmq.NOBLOCK + ) diff --git a/logging/BUCK b/logging/BUCK new file mode 100644 index 000000000..fb01931cc --- /dev/null +++ b/logging/BUCK @@ -0,0 +1,9 @@ +cxx_library( + name="logging", + preferred_linkage="static", + raw_headers=glob(["include/logging/*.h"]), + header_namespace="logging", + public_include_directories=["include"], + deps=["//third-party/fmt:fmt"], + visibility=["PUBLIC"], +) diff --git a/logging/include/logging/Checks.h b/logging/include/logging/Checks.h new file mode 100644 index 000000000..85c68037b --- /dev/null +++ b/logging/include/logging/Checks.h @@ -0,0 +1,23 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +namespace arvr { +namespace logging { + +template +void check(Condition condition, Args&&... args) { + if (condition) { + return; + } + stubLog(std::forward(args)...); + std::abort(); +} + +} // namespace logging +} // namespace arvr + +#define XR_CHECK(condition, ...) ::arvr::logging::check(condition, __VA_ARGS__) +#define XR_DEV_CHECK(condition, ...) XR_CHECK(condition, __VA_ARGS__) diff --git a/logging/include/logging/Log.h b/logging/include/logging/Log.h new file mode 100644 index 000000000..8e6dcd300 --- /dev/null +++ b/logging/include/logging/Log.h @@ -0,0 +1,37 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +#include + +#ifndef DEFAULT_LOG_CHANNEL +#error "DEFAULT_LOG_CHANNEL must be defined before including " +#endif // DEFAULT_LOG_CHANNEL + +#define XR_LOG_DEFAULT(levelName, level, ...) \ + XR_LOG_CHANNELNAME(DEFAULT_LOG_CHANNEL, levelName, level, __VA_ARGS__) + +#define XR_LOGT(...) XR_LOG_DEFAULT("TRACE", ::arvr::logging::Level::Trace, __VA_ARGS__) +#define XR_LOGD(...) XR_LOG_DEFAULT("DEBUG", ::arvr::logging::Level::Debug, __VA_ARGS__) +#define XR_LOGI(...) XR_LOG_DEFAULT("INFO", ::arvr::logging::Level::Info, __VA_ARGS__) +#define XR_LOGW(...) XR_LOG_DEFAULT("WARNING", ::arvr::logging::Level::Warning, __VA_ARGS__) +#define XR_LOGE(...) XR_LOG_DEFAULT("ERROR", ::arvr::logging::Level::Error, __VA_ARGS__) + +#define XR_LOGT_EVERY_N_SEC(n, ...) XR_LOGT(__VA_ARGS__) +#define XR_LOGD_EVERY_N_SEC(n, ...) XR_LOGD(__VA_ARGS__) +#define XR_LOGI_EVERY_N_SEC(n, ...) XR_LOGI(__VA_ARGS__) +#define XR_LOGW_EVERY_N_SEC(n, ...) XR_LOGW(__VA_ARGS__) +#define XR_LOGE_EVERY_N_SEC(n, ...) XR_LOGE(__VA_ARGS__) + +#define XR_LOGT_EVERY_N(n, ...) XR_LOGT(__VA_ARGS__) +#define XR_LOGD_EVERY_N(n, ...) XR_LOGD(__VA_ARGS__) +#define XR_LOGI_EVERY_N(n, ...) XR_LOGI(__VA_ARGS__) +#define XR_LOGW_EVERY_N(n, ...) XR_LOGW(__VA_ARGS__) +#define XR_LOGE_EVERY_N(n, ...) XR_LOGE(__VA_ARGS__) + +#define XR_LOGT_ONCE(...) XR_LOGT(__VA_ARGS__) +#define XR_LOGD_ONCE(...) XR_LOGD(__VA_ARGS__) +#define XR_LOGI_ONCE(...) XR_LOGI(__VA_ARGS__) +#define XR_LOGW_ONCE(...) XR_LOGW(__VA_ARGS__) +#define XR_LOGE_ONCE(...) XR_LOGE(__VA_ARGS__) diff --git a/logging/include/logging/LogChannel.h b/logging/include/logging/LogChannel.h new file mode 100644 index 000000000..a720b5dd9 --- /dev/null +++ b/logging/include/logging/LogChannel.h @@ -0,0 +1,72 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include +#include + +namespace arvr { +namespace logging { +static constexpr const size_t kLogCapacity = 500; + +template +void log(const char* channel, const char* levelName, ::arvr::logging::Level level, Args&&... args) { + static char buffer[kLogCapacity]; + + if (level > static_cast<::arvr::logging::Level>(::arvr::logging::sGlobalLogLevel)) { + return; + } + + char* const out = ::fmt::format_to_n(buffer, kLogCapacity, std::forward(args)...).out; + int lineLength = out - buffer; + std::string line(out, out + lineLength); + + stubLog("[{}][{}] {}", channel, levelName, line); +} + +template +void logIf( + bool condition, + const char* channel, + const char* levelName, + ::arvr::logging::Level level, + Args&&... args) { + if (!condition) { + return; + } + log(channel, levelName, level, std::forward(args)...); +} + +} // namespace logging +} // namespace arvr + +#define XR_LOG_CHANNELNAME(channelName, levelName, level, ...) \ + ::arvr::logging::log(channelName, levelName, level, __VA_ARGS__) + +#define XR_LOGCT(channelName, ...) \ + XR_LOG_CHANNELNAME(channelName, "TRACE", ::arvr::logging::Level::Trace, __VA_ARGS__) +#define XR_LOGCD(channelName, ...) \ + XR_LOG_CHANNELNAME(channelName, "DEBUG", ::arvr::logging::Level::Debug, __VA_ARGS__) +#define XR_LOGCI(channelName, ...) \ + XR_LOG_CHANNELNAME(channelName, "INFO", ::arvr::logging::Level::Info, __VA_ARGS__) +#define XR_LOGCW(channelName, ...) \ + XR_LOG_CHANNELNAME(channelName, "WARNING", ::arvr::logging::Level::Warning, __VA_ARGS__) +#define XR_LOGCE(channelName, ...) \ + XR_LOG_CHANNELNAME(channelName, "ERROR", ::arvr::logging::Level::Error, __VA_ARGS__) + +#define XR_LOGIF_CHANNELNAME(condition, channelName, levelName, level, ...) \ + ::arvr::logging::logIf(condition, channelName, levelName, level, __VA_ARGS__) + +#define XR_LOGCT_IF(condition, channelName, ...) \ + XR_LOGIF_CHANNELNAME(condition, channelName, "TRACE", ::arvr::logging::Level::Trace, __VA_ARGS__) +#define XR_LOGCD_IF(condition, channelName, ...) \ + XR_LOGIF_CHANNELNAME(condition, channelName, "DEBUG", ::arvr::logging::Level::Debug, __VA_ARGS__) +#define XR_LOGCI_IF(condition, channelName, ...) \ + XR_LOGIF_CHANNELNAME(condition, channelName, "INFO", ::arvr::logging::Level::Info, __VA_ARGS__) +#define XR_LOGCW_IF(condition, channelName, ...) \ + XR_LOGIF_CHANNELNAME( \ + condition, channelName, "WARNING", ::arvr::logging::Level::Warning, __VA_ARGS__) +#define XR_LOGCE_IF(condition, channelName, ...) \ + XR_LOGIF_CHANNELNAME(condition, channelName, "ERROR", ::arvr::logging::Level::Error, __VA_ARGS__) diff --git a/logging/include/logging/LogLevel.h b/logging/include/logging/LogLevel.h new file mode 100644 index 000000000..87a928a0b --- /dev/null +++ b/logging/include/logging/LogLevel.h @@ -0,0 +1,44 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +namespace arvr { +namespace logging { + +/** + * Predefined log levels which can be extended if needed. + **/ +enum class Level { + Disabled = 0, ///< Completely suppresses log output. Not available in the logging macros. + Error = 1, ///< + Warning = 2, + Info = 3, + Debug = 4, + Trace = 5, + UseGlobalSettings = 100, ///< Use the global log level instead of a channel override. Not + ///< available in the logging macros. +}; // enum class Level + +/// The global level is a global variable and thus needs to be defined by the backend +static int sGlobalLogLevel = static_cast(Level::Info); + +/** + * Set the global log level that applies for all channels, unless the channel has separate settings. + */ +inline void setGlobalLogLevel(int level) { + sGlobalLogLevel = level; +} + +inline void setGlobalLogLevel(Level level) { + setGlobalLogLevel(static_cast(level)); +} + +/** + * Returns the current global log level. + */ +inline int globalLogLevel() { + return sGlobalLogLevel; +} + +} // namespace logging +} // namespace arvr diff --git a/logging/include/logging/Stub.h b/logging/include/logging/Stub.h new file mode 100644 index 000000000..bfd6c0de6 --- /dev/null +++ b/logging/include/logging/Stub.h @@ -0,0 +1,21 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include + +#include + +namespace arvr { +namespace logging { + +template +void stubLog(Args&&... args) { + static std::mutex logMutex; + std::scoped_lock logLock(logMutex); + + ::fmt::print(std::forward(args)...); +} + +} // namespace logging +} // namespace arvr diff --git a/setup.py b/setup.py new file mode 100644 index 000000000..9ad37e9dc --- /dev/null +++ b/setup.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# Copyright 2004-present Facebook. All Rights Reserved. + +from buck_ext import BuckExtension, buck_build_ext +from setuptools import find_packages, setup + +LIBRARY_EXTENSIONS = [ + BuckExtension( + name="cthulhubindings", + target="//:cthulhubindings#default,shared", + ), + BuckExtension( + name="labgraph_cpp", + target="//:labgraph_cpp_bindings#default,shared", + ), + BuckExtension( + name="MyCPPNodes", + target="//:MyCPPNodes#default,shared", + ), +] + + +setup( + name="labgraph", + version="1.0.0", + description="Python streaming framework", + packages=find_packages(), + package_data={"labgraph": ["tests/mypy.ini"]}, + python_requires=">=3.6, <3.7", + ext_modules=LIBRARY_EXTENSIONS, + cmdclass={"build_ext": buck_build_ext}, + install_requires=[ + "appdirs==1.4.3", + "click==7.0", + "dataclasses==0.6", + "h5py==2.10.0", + "matplotlib==3.1.1", + "mypy==0.782", + "numpy==1.16.4", + "psutil==5.6.7", + "pytest==3.10.1", + "pytest_mock==2.0.0", + "pyzmq==18.1.0", + "typeguard==2.5.1", + "typing_extensions==3.7.4", + "yappi==1.2.5", + ], +) diff --git a/third-party/boost/BUCK b/third-party/boost/BUCK new file mode 100644 index 000000000..2e96b837e --- /dev/null +++ b/third-party/boost/BUCK @@ -0,0 +1,173 @@ +load("//:DEFS", "PLATFORM") + +BOOST_DATE_TIME_RAW_HEADERS = ["boost/date_time.h*", "boost/date_time/**/*.h*", "boost/date_time/**/*.ipp"] +BOOST_THREAD_RAW_HEADERS = [ + "boost/thread.h*", + "boost/thread/**/*.h*", + "libs/thread/**/*.h*", + "libs/thread/src/pthread/once_atomic.cpp", +] +BOOST_CHRONO_RAW_HEADERS = [ + "boost/chrono.h*", + "boost/chrono/**/*.h*", + "libs/chrono/**/*.h*", +] +BOOST_SYSTEM_RAW_HEADERS = [ + "boost/system/**/*.h*", + "libs/system/**/*.h*", +] + +CXXFLAGS = [ + "-fexceptions", + "-Wall", + "-Wno-narrowing", + "-Wno-overloaded-virtual", + "-Wno-shadow", + "-Wno-unused-function", + "-Wno-unused-variable", + "-Wno-unused-parameter", + "-Wno-unused-local-typedefs", + "-frtti", +] + +WINCXXFLAGS = [ + "-DBOOST_THREAD_BUILD_LIB", +] + +PUBLIC_PREPROCESSOR_FLAGS = [ + "-DBOOST_ALL_NO_LIB", + "-DBOOST_PP_VARIADICS=1", +] + +PREPROCESSOR_WINDOWS_FLAGS = [ + "-DWIN32_LEAN_AND_MEAN", +] + +cxx_library( + name = "boost", + header_namespace = "third-party/boost", + preferred_linkage = "static", + public_include_directories = ["."], + preprocessor_flags = PUBLIC_PREPROCESSOR_FLAGS, + raw_headers = glob( + ["boost/*.h*", "boost/**/*.h*", "boost/**/*.ipp", "libs/**/*.h*"], + exclude = glob(BOOST_DATE_TIME_RAW_HEADERS) + glob(BOOST_THREAD_RAW_HEADERS) + glob(BOOST_CHRONO_RAW_HEADERS) + glob(BOOST_SYSTEM_RAW_HEADERS) + [ + "boost/asio.h*", + "boost/asio/**/*.h*", + "boost/asio/**/*.ipp", + "boost/context/**/*.h*", + "libs/context/**/*.h*", + "boost/coroutine/**/*.h*", + "libs/coroutine/**/*.h*", + "boost/dll.h*", + "boost/dll/**/*.h*", + "boost/filesystem.h*", + "boost/filesystem/**/*.h*", + "libs/filesystem/**/*.h*", + "boost/interprocess/**/*.hpp", + "boost/iostreams/**/*.h*", + "libs/iostreams/**.h*", + "boost/log/**/*.h*", + "libs/log/**/*.h*", + "boost/program_options.h*", + "boost/program_options/**/*.h*", + "libs/program_options/**/*.h*", + "boost/python.h*", + "boost/python/**/*.h*", + "libs/python/**/*.h*", + "boost/*regex*.h*", + "boost/regex/**/*.h*", + "boost/algorithm/**/*regex*.h*", + "libs/regex/**/*.h*", + "libs/serialization/**/*.h*", + "libs/serialization/**/*.ipp", + "boost/timer.h*", + "boost/timer/**/*.h*", + "libs/timer/**/*.h*", + ], + ), + visibility = ["PUBLIC"], +) + +cxx_library( + name = "boost_date_time", + header_namespace = "third-party/boost", + preferred_linkage = "static", + include_directories = ["."], + compiler_flags = { + "win": WINCXXFLAGS, + }.get(PLATFORM, CXXFLAGS), + preprocessor_flags = { + "win": PREPROCESSOR_WINDOWS_FLAGS, + }.get(PLATFORM, []) + PUBLIC_PREPROCESSOR_FLAGS, + srcs = glob(["libs/date_time/src/gregorian/*.cpp"]), + raw_headers = glob(BOOST_DATE_TIME_RAW_HEADERS), + exported_deps = [":boost"], + visibility = ["PUBLIC"], +) + +cxx_library( + name = "boost_thread", + header_namespace = "third-party/boost", + preferred_linkage = "static", + srcs = { + "win": [ + "libs/thread/src/future.cpp", + "libs/thread/src/tss_null.cpp", + "libs/thread/src/win32/thread.cpp", + "libs/thread/src/win32/tss_dll.cpp", + "libs/thread/src/win32/tss_pe.cpp", + ], + }.get(PLATFORM, [ + "libs/thread/src/future.cpp", + "libs/thread/src/pthread/once.cpp", + "libs/thread/src/pthread/thread.cpp", + "libs/thread/src/pthread/once_atomic.cpp", + ]), + compiler_flags = { + "win": WINCXXFLAGS, + }.get(PLATFORM, CXXFLAGS + ["-Wno-non-virtual-dtor"]), + include_directories = ["."], + preprocessor_flags = { + "win": PREPROCESSOR_WINDOWS_FLAGS, + }.get(PLATFORM, []) + PUBLIC_PREPROCESSOR_FLAGS, + exported_deps = [":boost", ":boost_chrono", ":boost_date_time", ":boost_system"], + raw_headers = glob(BOOST_THREAD_RAW_HEADERS), + visibility = ["PUBLIC"], +) + +cxx_library( + name = "boost_chrono", + preferred_linkage = "static", + srcs = [ + "libs/chrono/src/chrono.cpp", + "libs/chrono/src/process_cpu_clocks.cpp", + "libs/chrono/src/thread_clock.cpp", + ], + compiler_flags = { + "win": WINCXXFLAGS, + }.get(PLATFORM, CXXFLAGS), + include_directories = ["."], + preprocessor_flags = { + "win": PREPROCESSOR_WINDOWS_FLAGS, + }.get(PLATFORM, []) + PUBLIC_PREPROCESSOR_FLAGS, + exported_deps = [":boost", ":boost_system"], + raw_headers = glob(BOOST_CHRONO_RAW_HEADERS), + visibility = ["PUBLIC"], +) + +cxx_library( + name = "boost_system", + preferred_linkage = "static", + srcs = glob(["libs/system/src/**/*.cpp"]), + compiler_flags = { + "win": WINCXXFLAGS, + }.get(PLATFORM, CXXFLAGS), + include_directories = ["."], + preprocessor_flags = { + "win": PREPROCESSOR_WINDOWS_FLAGS, + }.get(PLATFORM, []) + PUBLIC_PREPROCESSOR_FLAGS, + exported_deps = [":boost"], + raw_headers = glob(BOOST_SYSTEM_RAW_HEADERS), + visibility = ["PUBLIC"], +) diff --git a/third-party/boost/LICENSE_1_0.txt b/third-party/boost/LICENSE_1_0.txt new file mode 100644 index 000000000..36b7cd93c --- /dev/null +++ b/third-party/boost/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third-party/boost/README.md b/third-party/boost/README.md new file mode 100644 index 000000000..d4678952b --- /dev/null +++ b/third-party/boost/README.md @@ -0,0 +1,11 @@ +# Boost C++ Libraries + +The Boost project provides free peer-reviewed portable C++ source libraries. + +We emphasize libraries that work well with the C++ Standard Library. Boost +libraries are intended to be widely useful, and usable across a broad spectrum +of applications. The Boost license encourages both commercial and non-commercial use +and does not require attribution for binary use. + +The project website is www.boost.org, where you can obtain more information and +[download](https://www.boost.org/users/download/) the current release. diff --git a/third-party/boost/boost/algorithm/algorithm.hpp b/third-party/boost/boost/algorithm/algorithm.hpp new file mode 100644 index 000000000..2bbee1d2d --- /dev/null +++ b/third-party/boost/boost/algorithm/algorithm.hpp @@ -0,0 +1,88 @@ +/* + Copyright (c) Marshall Clow 2014. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Revision history: + 2 Dec 2014 mtc First version; power + +*/ + +/// \file algorithm.hpp +/// \brief Misc Algorithms +/// \author Marshall Clow +/// + +#ifndef BOOST_ALGORITHM_HPP +#define BOOST_ALGORITHM_HPP + +#include // for plus and multiplies + +#include // for boost::disable_if +#include + +namespace boost { namespace algorithm { + +template +BOOST_CXX14_CONSTEXPR T identity_operation ( std::multiplies ) { return T(1); } + +template +BOOST_CXX14_CONSTEXPR T identity_operation ( std::plus ) { return T(0); } + + +/// \fn power ( T x, Integer n ) +/// \return the value "x" raised to the power "n" +/// +/// \param x The value to be exponentiated +/// \param n The exponent (must be >= 0) +/// +// \remark Taken from Knuth, The Art of Computer Programming, Volume 2: +// Seminumerical Algorithms, Section 4.6.3 +template +BOOST_CXX14_CONSTEXPR typename boost::enable_if, T>::type +power (T x, Integer n) { + T y = 1; // Should be "T y{1};" + if (n == 0) return y; + while (true) { + if (n % 2 == 1) { + y = x * y; + if (n == 1) + return y; + } + n = n / 2; + x = x * x; + } + return y; + } + +/// \fn power ( T x, Integer n, Operation op ) +/// \return the value "x" raised to the power "n" +/// using the operation "op". +/// +/// \param x The value to be exponentiated +/// \param n The exponent (must be >= 0) +/// \param op The operation used +/// +// \remark Taken from Knuth, The Art of Computer Programming, Volume 2: +// Seminumerical Algorithms, Section 4.6.3 +template +BOOST_CXX14_CONSTEXPR typename boost::enable_if, T>::type +power (T x, Integer n, Operation op) { + T y = identity_operation(op); + if (n == 0) return y; + while (true) { + if (n % 2 == 1) { + y = op(x, y); + if (n == 1) + return y; + } + n = n / 2; + x = op(x, x); + } + return y; + } + +}} + +#endif // BOOST_ALGORITHM_HPP diff --git a/third-party/boost/boost/algorithm/apply_permutation.hpp b/third-party/boost/boost/algorithm/apply_permutation.hpp new file mode 100644 index 000000000..b9de0ded7 --- /dev/null +++ b/third-party/boost/boost/algorithm/apply_permutation.hpp @@ -0,0 +1,126 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. + + + Based on https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115 +*/ + +/// \file apply_permutation.hpp +/// \brief Apply permutation to a sequence. +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_APPLY_PERMUTATION_HPP +#define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP + +#include +#include + +#include +#include + +namespace boost { namespace algorithm +{ + +/// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_begin The start of the item sequence +/// \param item_end One past the end of the item sequence +/// \param ind_begin The start of the index sequence. +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end) +{ + typedef typename std::iterator_traits::difference_type Diff; + typedef typename std::iterator_traits::difference_type Index; + using std::swap; + Diff size = std::distance(item_begin, item_end); + for (Diff i = 0; i < size; i++) + { + Diff current = i; + while (i != ind_begin[current]) + { + Index next = ind_begin[current]; + swap(item_begin[current], item_begin[next]); + ind_begin[current] = current; + current = next; + } + ind_begin[current] = current; + } +} + +/// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_begin The start of the item sequence +/// \param item_end One past the end of the item sequence +/// \param ind_begin The start of the index sequence. +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_reverse_permutation( + RandomAccessIterator1 item_begin, + RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin, + RandomAccessIterator2 ind_end) +{ + typedef typename std::iterator_traits::difference_type Diff; + using std::swap; + Diff length = std::distance(item_begin, item_end); + for (Diff i = 0; i < length; i++) + { + while (i != ind_begin[i]) + { + Diff next = ind_begin[i]; + swap(item_begin[i], item_begin[next]); + swap(ind_begin[i], ind_begin[next]); + } + } +} + +/// \fn apply_permutation ( Range1 item_range, Range2 ind_range ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_range The item sequence +/// \param ind_range The index sequence +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_permutation(Range1& item_range, Range2& ind_range) +{ + apply_permutation(boost::begin(item_range), boost::end(item_range), + boost::begin(ind_range), boost::end(ind_range)); +} + +/// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_range The item sequence +/// \param ind_range The index sequence +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_reverse_permutation(Range1& item_range, Range2& ind_range) +{ + apply_reverse_permutation(boost::begin(item_range), boost::end(item_range), + boost::begin(ind_range), boost::end(ind_range)); +} + +}} +#endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP diff --git a/third-party/boost/boost/algorithm/clamp.hpp b/third-party/boost/boost/algorithm/clamp.hpp new file mode 100644 index 000000000..d027acdf2 --- /dev/null +++ b/third-party/boost/boost/algorithm/clamp.hpp @@ -0,0 +1,175 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Revision history: + 27 June 2009 mtc First version + 23 Oct 2010 mtc Added predicate version + +*/ + +/// \file clamp.hpp +/// \brief Clamp algorithm +/// \author Marshall Clow +/// +/// Suggested by olafvdspek in https://svn.boost.org/trac/boost/ticket/3215 + +#ifndef BOOST_ALGORITHM_CLAMP_HPP +#define BOOST_ALGORITHM_CLAMP_HPP + +#include // For std::less +#include // For std::iterator_traits +#include + +#include +#include +#include // for identity +#include // for boost::disable_if + +namespace boost { namespace algorithm { + +/// \fn clamp ( T const& val, +/// typename boost::mpl::identity::type const & lo, +/// typename boost::mpl::identity::type const & hi, Pred p ) +/// \return the value "val" brought into the range [ lo, hi ] +/// using the comparison predicate p. +/// If p ( val, lo ) return lo. +/// If p ( hi, val ) return hi. +/// Otherwise, return the original value. +/// +/// \param val The value to be clamped +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + BOOST_CXX14_CONSTEXPR T const & clamp ( T const& val, + typename boost::mpl::identity::type const & lo, + typename boost::mpl::identity::type const & hi, Pred p ) + { +// assert ( !p ( hi, lo )); // Can't assert p ( lo, hi ) b/c they might be equal + return p ( val, lo ) ? lo : p ( hi, val ) ? hi : val; + } + + +/// \fn clamp ( T const& val, +/// typename boost::mpl::identity::type const & lo, +/// typename boost::mpl::identity::type const & hi ) +/// \return the value "val" brought into the range [ lo, hi ]. +/// If the value is less than lo, return lo. +/// If the value is greater than "hi", return hi. +/// Otherwise, return the original value. +/// +/// \param val The value to be clamped +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// + template + BOOST_CXX14_CONSTEXPR T const& clamp ( const T& val, + typename boost::mpl::identity::type const & lo, + typename boost::mpl::identity::type const & hi ) + { + return boost::algorithm::clamp ( val, lo, hi, std::less()); + } + +/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out, +/// std::iterator_traits::value_type const & lo, +/// std::iterator_traits::value_type const & hi ) +/// \return clamp the sequence of values [first, last) into [ lo, hi ] +/// +/// \param first The start of the range of values +/// \param last One past the end of the range of input values +/// \param out An output iterator to write the clamped values into +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// + template + BOOST_CXX14_CONSTEXPR OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out, + typename std::iterator_traits::value_type const & lo, + typename std::iterator_traits::value_type const & hi ) + { + // this could also be written with bind and std::transform + while ( first != last ) + *out++ = boost::algorithm::clamp ( *first++, lo, hi ); + return out; + } + +/// \fn clamp_range ( const Range &r, OutputIterator out, +/// typename std::iterator_traits::type>::value_type const & lo, +/// typename std::iterator_traits::type>::value_type const & hi ) +/// \return clamp the sequence of values [first, last) into [ lo, hi ] +/// +/// \param r The range of values to be clamped +/// \param out An output iterator to write the clamped values into +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// + template + BOOST_CXX14_CONSTEXPR typename boost::disable_if_c::value, OutputIterator>::type + clamp_range ( const Range &r, OutputIterator out, + typename std::iterator_traits::type>::value_type const & lo, + typename std::iterator_traits::type>::value_type const & hi ) + { + return boost::algorithm::clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi ); + } + + +/// \fn clamp_range ( InputIterator first, InputIterator last, OutputIterator out, +/// std::iterator_traits::value_type const & lo, +/// std::iterator_traits::value_type const & hi, Pred p ) +/// \return clamp the sequence of values [first, last) into [ lo, hi ] +/// using the comparison predicate p. +/// +/// \param first The start of the range of values +/// \param last One past the end of the range of input values +/// \param out An output iterator to write the clamped values into +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. + +/// + template + BOOST_CXX14_CONSTEXPR OutputIterator clamp_range ( InputIterator first, InputIterator last, OutputIterator out, + typename std::iterator_traits::value_type const & lo, + typename std::iterator_traits::value_type const & hi, Pred p ) + { + // this could also be written with bind and std::transform + while ( first != last ) + *out++ = boost::algorithm::clamp ( *first++, lo, hi, p ); + return out; + } + +/// \fn clamp_range ( const Range &r, OutputIterator out, +/// typename std::iterator_traits::type>::value_type const & lo, +/// typename std::iterator_traits::type>::value_type const & hi, +/// Pred p ) +/// \return clamp the sequence of values [first, last) into [ lo, hi ] +/// using the comparison predicate p. +/// +/// \param r The range of values to be clamped +/// \param out An output iterator to write the clamped values into +/// \param lo The lower bound of the range to be clamped to +/// \param hi The upper bound of the range to be clamped to +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +// +// Disable this template if the first two parameters are the same type; +// In that case, the user will get the two iterator version. + template + BOOST_CXX14_CONSTEXPR typename boost::disable_if_c::value, OutputIterator>::type + clamp_range ( const Range &r, OutputIterator out, + typename std::iterator_traits::type>::value_type const & lo, + typename std::iterator_traits::type>::value_type const & hi, + Pred p ) + { + return boost::algorithm::clamp_range ( boost::begin ( r ), boost::end ( r ), out, lo, hi, p ); + } + + +}} + +#endif // BOOST_ALGORITHM_CLAMP_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/all_of.hpp b/third-party/boost/boost/algorithm/cxx11/all_of.hpp new file mode 100644 index 000000000..527bbd50f --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/all_of.hpp @@ -0,0 +1,83 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file all_of.hpp +/// \brief Test ranges to see if all elements match a value or predicate. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_ALL_OF_HPP +#define BOOST_ALGORITHM_ALL_OF_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn all_of ( InputIterator first, InputIterator last, Predicate p ) +/// \return true if all elements in [first, last) satisfy the predicate 'p' +/// \note returns true on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p A predicate for testing the elements of the sequence +/// +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR bool all_of ( InputIterator first, InputIterator last, Predicate p ) +{ + for ( ; first != last; ++first ) + if ( !p(*first)) + return false; + return true; +} + +/// \fn all_of ( const Range &r, Predicate p ) +/// \return true if all elements in the range satisfy the predicate 'p' +/// \note returns true on an empty range +/// +/// \param r The input range +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR bool all_of ( const Range &r, Predicate p ) +{ + return boost::algorithm::all_of ( boost::begin (r), boost::end (r), p ); +} + +/// \fn all_of_equal ( InputIterator first, InputIterator last, const T &val ) +/// \return true if all elements in [first, last) are equal to 'val' +/// \note returns true on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool all_of_equal ( InputIterator first, InputIterator last, const T &val ) +{ + for ( ; first != last; ++first ) + if ( val != *first ) + return false; + return true; +} + +/// \fn all_of_equal ( const Range &r, const T &val ) +/// \return true if all elements in the range are equal to 'val' +/// \note returns true on an empty range +/// +/// \param r The input range +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool all_of_equal ( const Range &r, const T &val ) +{ + return boost::algorithm::all_of_equal ( boost::begin (r), boost::end (r), val ); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_ALL_OF_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/any_of.hpp b/third-party/boost/boost/algorithm/cxx11/any_of.hpp new file mode 100644 index 000000000..d9e241413 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/any_of.hpp @@ -0,0 +1,84 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +/// \file +/// \brief Test ranges to see if any elements match a value or predicate. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_ANY_OF_HPP +#define BOOST_ALGORITHM_ANY_OF_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn any_of ( InputIterator first, InputIterator last, Predicate p ) +/// \return true if any of the elements in [first, last) satisfy the predicate +/// \note returns false on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p A predicate for testing the elements of the sequence +/// +template +BOOST_CXX14_CONSTEXPR bool any_of ( InputIterator first, InputIterator last, Predicate p ) +{ + for ( ; first != last; ++first ) + if ( p(*first)) + return true; + return false; +} + +/// \fn any_of ( const Range &r, Predicate p ) +/// \return true if any elements in the range satisfy the predicate 'p' +/// \note returns false on an empty range +/// +/// \param r The input range +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR bool any_of ( const Range &r, Predicate p ) +{ + return boost::algorithm::any_of (boost::begin (r), boost::end (r), p); +} + +/// \fn any_of_equal ( InputIterator first, InputIterator last, const V &val ) +/// \return true if any of the elements in [first, last) are equal to 'val' +/// \note returns false on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool any_of_equal ( InputIterator first, InputIterator last, const V &val ) +{ + for ( ; first != last; ++first ) + if ( val == *first ) + return true; + return false; +} + +/// \fn any_of_equal ( const Range &r, const V &val ) +/// \return true if any of the elements in the range are equal to 'val' +/// \note returns false on an empty range +/// +/// \param r The input range +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool any_of_equal ( const Range &r, const V &val ) +{ + return boost::algorithm::any_of_equal (boost::begin (r), boost::end (r), val); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_ANY_OF_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/copy_if.hpp b/third-party/boost/boost/algorithm/cxx11/copy_if.hpp new file mode 100644 index 000000000..dc1fdeff3 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/copy_if.hpp @@ -0,0 +1,129 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file copy_if.hpp +/// \brief Copy a subset of a sequence to a new sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_COPY_IF_HPP +#define BOOST_ALGORITHM_COPY_IF_HPP + +#include // for std::pair, std::make_pair +#include +#include + +namespace boost { namespace algorithm { + +/// \fn copy_if ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +/// \brief Copies all the elements from the input range that satisfy the +/// predicate to the output range. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR OutputIterator copy_if ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +{ + for ( ; first != last; ++first ) + if (p(*first)) + *result++ = *first; + return result; +} + +/// \fn copy_if ( const Range &r, OutputIterator result, Predicate p ) +/// \brief Copies all the elements from the input range that satisfy the +/// predicate to the output range. +/// \return The updated output iterator +/// +/// \param r The input range +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR OutputIterator copy_if ( const Range &r, OutputIterator result, Predicate p ) +{ + return boost::algorithm::copy_if (boost::begin (r), boost::end(r), result, p); +} + + +/// \fn copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +/// \brief Copies all the elements at the start of the input range that +/// satisfy the predicate to the output range. +/// \return The updated input and output iterators +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR std::pair +copy_while ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +{ + for ( ; first != last && p(*first); ++first ) + *result++ = *first; + return std::make_pair(first, result); +} + +/// \fn copy_while ( const Range &r, OutputIterator result, Predicate p ) +/// \brief Copies all the elements at the start of the input range that +/// satisfy the predicate to the output range. +/// \return The updated input and output iterators +/// +/// \param r The input range +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +copy_while ( const Range &r, OutputIterator result, Predicate p ) +{ + return boost::algorithm::copy_while (boost::begin (r), boost::end(r), result, p); +} + + +/// \fn copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +/// \brief Copies all the elements at the start of the input range that do not +/// satisfy the predicate to the output range. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR std::pair +copy_until ( InputIterator first, InputIterator last, OutputIterator result, Predicate p ) +{ + for ( ; first != last && !p(*first); ++first ) + *result++ = *first; + return std::make_pair(first, result); +} + +/// \fn copy_until ( const Range &r, OutputIterator result, Predicate p ) +/// \brief Copies all the elements at the start of the input range that do not +/// satisfy the predicate to the output range. +/// \return The updated output iterator +/// +/// \param r The input range +/// \param result An output iterator to write the results into +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR std::pair::type, OutputIterator> +copy_until ( const Range &r, OutputIterator result, Predicate p ) +{ + return boost::algorithm::copy_until (boost::begin (r), boost::end(r), result, p); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_COPY_IF_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/copy_n.hpp b/third-party/boost/boost/algorithm/cxx11/copy_n.hpp new file mode 100644 index 000000000..e4bebd076 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/copy_n.hpp @@ -0,0 +1,35 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file copy_n.hpp +/// \brief Copy n items from one sequence to another +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_COPY_N_HPP +#define BOOST_ALGORITHM_COPY_N_HPP + +namespace boost { namespace algorithm { + +/// \fn copy_n ( InputIterator first, Size n, OutputIterator result ) +/// \brief Copies exactly n (n > 0) elements from the range starting at first to +/// the range starting at result. +/// \return The updated output iterator +/// +/// \param first The start of the input sequence +/// \param n The number of elements to copy +/// \param result An output iterator to write the results into +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR OutputIterator copy_n ( InputIterator first, Size n, OutputIterator result ) +{ + for ( ; n > 0; --n, ++first, ++result ) + *result = *first; + return result; +} +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_COPY_IF_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/find_if_not.hpp b/third-party/boost/boost/algorithm/cxx11/find_if_not.hpp new file mode 100644 index 000000000..6f5799a33 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/find_if_not.hpp @@ -0,0 +1,51 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file find_if_not.hpp +/// \brief Find the first element in a sequence that does not satisfy a predicate. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_FIND_IF_NOT_HPP +#define BOOST_ALGORITHM_FIND_IF_NOT_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn find_if_not(InputIterator first, InputIterator last, Predicate p) +/// \brief Finds the first element in the sequence that does not satisfy the predicate. +/// \return The iterator pointing to the desired element. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p A predicate for testing the elements of the range +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR InputIterator find_if_not ( InputIterator first, InputIterator last, Predicate p ) +{ + for ( ; first != last; ++first ) + if ( !p(*first)) + break; + return first; +} + +/// \fn find_if_not ( const Range &r, Predicate p ) +/// \brief Finds the first element in the sequence that does not satisfy the predicate. +/// \return The iterator pointing to the desired element. +/// +/// \param r The input range +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR typename boost::range_iterator::type find_if_not ( const Range &r, Predicate p ) +{ + return boost::algorithm::find_if_not (boost::begin (r), boost::end(r), p); +} + +}} +#endif // BOOST_ALGORITHM_FIND_IF_NOT_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/iota.hpp b/third-party/boost/boost/algorithm/cxx11/iota.hpp new file mode 100644 index 000000000..6efc4d8dc --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/iota.hpp @@ -0,0 +1,65 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file iota.hpp +/// \brief Generate an increasing series +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_IOTA_HPP +#define BOOST_ALGORITHM_IOTA_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn iota ( ForwardIterator first, ForwardIterator last, T value ) +/// \brief Generates an increasing sequence of values, and stores them in [first, last) +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param value The initial value of the sequence to be generated +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR void iota ( ForwardIterator first, ForwardIterator last, T value ) +{ + for ( ; first != last; ++first, ++value ) + *first = value; +} + +/// \fn iota ( Range &r, T value ) +/// \brief Generates an increasing sequence of values, and stores them in the input Range. +/// +/// \param r The input range +/// \param value The initial value of the sequence to be generated +/// +template +BOOST_CXX14_CONSTEXPR void iota ( Range &r, T value ) +{ + boost::algorithm::iota (boost::begin(r), boost::end(r), value); +} + + +/// \fn iota_n ( OutputIterator out, T value, std::size_t n ) +/// \brief Generates an increasing sequence of values, and stores them in the input Range. +/// +/// \param out An output iterator to write the results into +/// \param value The initial value of the sequence to be generated +/// \param n The number of items to write +/// +template +BOOST_CXX14_CONSTEXPR OutputIterator iota_n ( OutputIterator out, T value, std::size_t n ) +{ + for ( ; n > 0; --n, ++value ) + *out++ = value; + + return out; +} + +}} + +#endif // BOOST_ALGORITHM_IOTA_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/is_partitioned.hpp b/third-party/boost/boost/algorithm/cxx11/is_partitioned.hpp new file mode 100644 index 000000000..fb2c5a17a --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/is_partitioned.hpp @@ -0,0 +1,58 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file is_partitioned.hpp +/// \brief Tell if a sequence is partitioned +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_IS_PARTITIONED_HPP +#define BOOST_ALGORITHM_IS_PARTITIONED_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_partitioned ( InputIterator first, InputIterator last, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p The predicate to test the values with +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR bool is_partitioned ( InputIterator first, InputIterator last, UnaryPredicate p ) +{ +// Run through the part that satisfy the predicate + for ( ; first != last; ++first ) + if ( !p (*first)) + break; +// Now the part that does not satisfy the predicate + for ( ; first != last; ++first ) + if ( p (*first)) + return false; + return true; +} + +/// \fn is_partitioned ( const Range &r, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param r The input range +/// \param p The predicate to test the values with +/// +template +BOOST_CXX14_CONSTEXPR bool is_partitioned ( const Range &r, UnaryPredicate p ) +{ + return boost::algorithm::is_partitioned (boost::begin(r), boost::end(r), p); +} + + +}} + +#endif // BOOST_ALGORITHM_IS_PARTITIONED_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/is_permutation.hpp b/third-party/boost/boost/algorithm/cxx11/is_permutation.hpp new file mode 100644 index 000000000..0098cd53f --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/is_permutation.hpp @@ -0,0 +1,185 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file is_permutation.hpp +/// \brief Is a sequence a permutation of another sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_IS_PERMUTATION11_HPP +#define BOOST_ALGORITHM_IS_PERMUTATION11_HPP + +#include // for std::find_if, count_if, mismatch +#include // for std::pair +#include // for std::equal_to +#include + +#include +#include +#include +#include + +namespace boost { namespace algorithm { + +/// \cond DOXYGEN_HIDE +namespace detail { + template + struct value_predicate { + value_predicate ( Predicate p, Iterator it ) : p_ ( p ), it_ ( it ) {} + + template + bool operator () ( const T1 &t1 ) const { return p_ ( *it_, t1 ); } + private: + Predicate p_; + Iterator it_; + }; + +// Preconditions: +// 1. The sequences are the same length +// 2. Any common elements on the front have been removed (not necessary for correctness, just for performance) + template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > + bool is_permutation_inner ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate p ) { + // for each unique value in the sequence [first1,last1), count how many times + // it occurs, and make sure it occurs the same number of times in [first2, last2) + for ( ForwardIterator1 iter = first1; iter != last1; ++iter ) { + value_predicate pred ( p, iter ); + + /* For each value we haven't seen yet... */ + if ( std::find_if ( first1, iter, pred ) == iter ) { + std::size_t dest_count = std::count_if ( first2, last2, pred ); + if ( dest_count == 0 || dest_count != (std::size_t) std::count_if ( iter, last1, pred )) + return false; + } + } + + return true; + } + + template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate> + bool is_permutation_tag ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate p, + std::forward_iterator_tag, std::forward_iterator_tag ) { + + // Skip the common prefix (if any) + while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) { + ++first1; + ++first2; + } + if ( first1 != last1 && first2 != last2 ) + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, + std::equal_to::value_type> ()); + return first1 == last1 && first2 == last2; + } + + template + bool is_permutation_tag ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, + BinaryPredicate p, + std::random_access_iterator_tag, std::random_access_iterator_tag ) { + // Cheap check + if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 )) + return false; + // Skip the common prefix (if any) + while ( first1 != last1 && first2 != last2 && p ( *first1, *first2 )) { + ++first1; + ++first2; + } + + if ( first1 != last1 && first2 != last2 ) + return is_permutation_inner (first1, last1, first2, last2, p); + return first1 == last1 && first2 == last2; + } + +} +/// \endcond + +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2, BinaryPredicate p ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last1 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \param p The predicate to compare elements with +/// +/// \note This function is part of the C++2011 standard library. +template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, BinaryPredicate p ) +{ +// Skip the common prefix (if any) + std::pair eq = std::mismatch (first1, last1, first2, p); + first1 = eq.first; + first2 = eq.second; + if ( first1 != last1 ) { + // Create last2 + ForwardIterator2 last2 = first2; + std::advance ( last2, std::distance (first1, last1)); + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, p ); + } + + return true; +} + +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, ForwardIterator2 first2 ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last2 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \note This function is part of the C++2011 standard library. +template< class ForwardIterator1, class ForwardIterator2 > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2 ) +{ +// How should I deal with the idea that ForwardIterator1::value_type +// and ForwardIterator2::value_type could be different? Define my own comparison predicate? +// Skip the common prefix (if any) + std::pair eq = std::mismatch (first1, last1, first2 ); + first1 = eq.first; + first2 = eq.second; + if ( first1 != last1 ) { + // Create last2 + ForwardIterator2 last2 = first2; + std::advance ( last2, std::distance (first1, last1)); + return boost::algorithm::detail::is_permutation_inner ( first1, last1, first2, last2, + std::equal_to::value_type> ()); + } + return true; +} + + +/// \fn is_permutation ( const Range &r, ForwardIterator first2 ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param r The input range +/// \param first2 The start of the second sequence +template +bool is_permutation ( const Range &r, ForwardIterator first2 ) +{ + return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2 ); +} + +/// \fn is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param r The input range +/// \param first2 The start of the second sequence +/// \param pred The predicate to compare elements with +/// +// Disable this template when the first two parameters are the same type +// That way the non-range version will be chosen. +template +typename boost::disable_if_c::value, bool>::type +is_permutation ( const Range &r, ForwardIterator first2, BinaryPredicate pred ) +{ + return boost::algorithm::is_permutation (boost::begin (r), boost::end (r), first2, pred ); +} + +}} + +#endif // BOOST_ALGORITHM_IS_PERMUTATION11_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/is_sorted.hpp b/third-party/boost/boost/algorithm/cxx11/is_sorted.hpp new file mode 100644 index 000000000..276621161 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/is_sorted.hpp @@ -0,0 +1,280 @@ +// Copyright (c) 2010 Nuovation System Designs, LLC +// Grant Erickson +// +// Reworked somewhat by Marshall Clow; August 2010 +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/ for latest version. +// + +#ifndef BOOST_ALGORITHM_ORDERED_HPP +#define BOOST_ALGORITHM_ORDERED_HPP + +#include +#include + +#include +#include + +#include +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_sorted_until ( ForwardIterator first, ForwardIterator last, Pred p ) +/// \return the point in the sequence [first, last) where the elements are unordered +/// (according to the comparison predicate 'p'). +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// \param p A binary predicate that returns true if two elements are ordered. +/// + template + BOOST_CXX14_CONSTEXPR ForwardIterator is_sorted_until ( ForwardIterator first, ForwardIterator last, Pred p ) + { + if ( first == last ) return last; // the empty sequence is ordered + ForwardIterator next = first; + while ( ++next != last ) + { + if ( p ( *next, *first )) + return next; + first = next; + } + return last; + } + +/// \fn is_sorted_until ( ForwardIterator first, ForwardIterator last ) +/// \return the point in the sequence [first, last) where the elements are unordered +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// + template + BOOST_CXX14_CONSTEXPR ForwardIterator is_sorted_until ( ForwardIterator first, ForwardIterator last ) + { + typedef typename std::iterator_traits::value_type value_type; + return boost::algorithm::is_sorted_until ( first, last, std::less()); + } + + +/// \fn is_sorted ( ForwardIterator first, ForwardIterator last, Pred p ) +/// \return whether or not the entire sequence is sorted +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// \param p A binary predicate that returns true if two elements are ordered. +/// + template + BOOST_CXX14_CONSTEXPR bool is_sorted ( ForwardIterator first, ForwardIterator last, Pred p ) + { + return boost::algorithm::is_sorted_until (first, last, p) == last; + } + +/// \fn is_sorted ( ForwardIterator first, ForwardIterator last ) +/// \return whether or not the entire sequence is sorted +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// + template + BOOST_CXX14_CONSTEXPR bool is_sorted ( ForwardIterator first, ForwardIterator last ) + { + return boost::algorithm::is_sorted_until (first, last) == last; + } + +/// +/// -- Range based versions of the C++11 functions +/// + +/// \fn is_sorted_until ( const R &range, Pred p ) +/// \return the point in the range R where the elements are unordered +/// (according to the comparison predicate 'p'). +/// +/// \param range The range to be tested. +/// \param p A binary predicate that returns true if two elements are ordered. +/// + template + BOOST_CXX14_CONSTEXPR typename boost::lazy_disable_if_c< + boost::is_same::value, + typename boost::range_iterator + >::type is_sorted_until ( const R &range, Pred p ) + { + return boost::algorithm::is_sorted_until ( boost::begin ( range ), boost::end ( range ), p ); + } + + +/// \fn is_sorted_until ( const R &range ) +/// \return the point in the range R where the elements are unordered +/// +/// \param range The range to be tested. +/// + template + BOOST_CXX14_CONSTEXPR typename boost::range_iterator::type is_sorted_until ( const R &range ) + { + return boost::algorithm::is_sorted_until ( boost::begin ( range ), boost::end ( range )); + } + +/// \fn is_sorted ( const R &range, Pred p ) +/// \return whether or not the entire range R is sorted +/// (according to the comparison predicate 'p'). +/// +/// \param range The range to be tested. +/// \param p A binary predicate that returns true if two elements are ordered. +/// + template + BOOST_CXX14_CONSTEXPR typename boost::lazy_disable_if_c< boost::is_same::value, boost::mpl::identity >::type + is_sorted ( const R &range, Pred p ) + { + return boost::algorithm::is_sorted ( boost::begin ( range ), boost::end ( range ), p ); + } + + +/// \fn is_sorted ( const R &range ) +/// \return whether or not the entire range R is sorted +/// +/// \param range The range to be tested. +/// + template + BOOST_CXX14_CONSTEXPR bool is_sorted ( const R &range ) + { + return boost::algorithm::is_sorted ( boost::begin ( range ), boost::end ( range )); + } + + +/// +/// -- Range based versions of the C++11 functions +/// + +/// \fn is_increasing ( ForwardIterator first, ForwardIterator last ) +/// \return true if the entire sequence is increasing; i.e, each item is greater than or +/// equal to the previous one. +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// +/// \note This function will return true for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_strictly_increasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_increasing ( ForwardIterator first, ForwardIterator last ) + { + typedef typename std::iterator_traits::value_type value_type; + return boost::algorithm::is_sorted (first, last, std::less()); + } + + +/// \fn is_increasing ( const R &range ) +/// \return true if the entire sequence is increasing; i.e, each item is greater than or +/// equal to the previous one. +/// +/// \param range The range to be tested. +/// +/// \note This function will return true for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_strictly_increasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_increasing ( const R &range ) + { + return is_increasing ( boost::begin ( range ), boost::end ( range )); + } + + + +/// \fn is_decreasing ( ForwardIterator first, ForwardIterator last ) +/// \return true if the entire sequence is decreasing; i.e, each item is less than +/// or equal to the previous one. +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// +/// \note This function will return true for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_strictly_decreasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_decreasing ( ForwardIterator first, ForwardIterator last ) + { + typedef typename std::iterator_traits::value_type value_type; + return boost::algorithm::is_sorted (first, last, std::greater()); + } + +/// \fn is_decreasing ( const R &range ) +/// \return true if the entire sequence is decreasing; i.e, each item is less than +/// or equal to the previous one. +/// +/// \param range The range to be tested. +/// +/// \note This function will return true for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_strictly_decreasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_decreasing ( const R &range ) + { + return is_decreasing ( boost::begin ( range ), boost::end ( range )); + } + + + +/// \fn is_strictly_increasing ( ForwardIterator first, ForwardIterator last ) +/// \return true if the entire sequence is strictly increasing; i.e, each item is greater +/// than the previous one +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// +/// \note This function will return false for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_increasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_strictly_increasing ( ForwardIterator first, ForwardIterator last ) + { + typedef typename std::iterator_traits::value_type value_type; + return boost::algorithm::is_sorted (first, last, std::less_equal()); + } + +/// \fn is_strictly_increasing ( const R &range ) +/// \return true if the entire sequence is strictly increasing; i.e, each item is greater +/// than the previous one +/// +/// \param range The range to be tested. +/// +/// \note This function will return false for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_increasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_strictly_increasing ( const R &range ) + { + return is_strictly_increasing ( boost::begin ( range ), boost::end ( range )); + } + + +/// \fn is_strictly_decreasing ( ForwardIterator first, ForwardIterator last ) +/// \return true if the entire sequence is strictly decreasing; i.e, each item is less than +/// the previous one +/// +/// \param first The start of the sequence to be tested. +/// \param last One past the end of the sequence +/// +/// \note This function will return false for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_decreasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_strictly_decreasing ( ForwardIterator first, ForwardIterator last ) + { + typedef typename std::iterator_traits::value_type value_type; + return boost::algorithm::is_sorted (first, last, std::greater_equal()); + } + +/// \fn is_strictly_decreasing ( const R &range ) +/// \return true if the entire sequence is strictly decreasing; i.e, each item is less than +/// the previous one +/// +/// \param range The range to be tested. +/// +/// \note This function will return false for sequences that contain items that compare +/// equal. If that is not what you intended, you should use is_decreasing instead. + template + BOOST_CXX14_CONSTEXPR bool is_strictly_decreasing ( const R &range ) + { + return is_strictly_decreasing ( boost::begin ( range ), boost::end ( range )); + } + +}} // namespace boost + +#endif // BOOST_ALGORITHM_ORDERED_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/none_of.hpp b/third-party/boost/boost/algorithm/cxx11/none_of.hpp new file mode 100644 index 000000000..e537c2673 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/none_of.hpp @@ -0,0 +1,82 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file none_of.hpp +/// \brief Test ranges to see if no elements match a value or predicate. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_NONE_OF_HPP +#define BOOST_ALGORITHM_NONE_OF_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn none_of ( InputIterator first, InputIterator last, Predicate p ) +/// \return true if none of the elements in [first, last) satisfy the predicate 'p' +/// \note returns true on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p A predicate for testing the elements of the sequence +/// +template +BOOST_CXX14_CONSTEXPR bool none_of ( InputIterator first, InputIterator last, Predicate p ) +{ + for ( ; first != last; ++first ) + if ( p(*first)) + return false; + return true; +} + +/// \fn none_of ( const Range &r, Predicate p ) +/// \return true if none of the elements in the range satisfy the predicate 'p' +/// \note returns true on an empty range +/// +/// \param r The input range +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR bool none_of ( const Range &r, Predicate p ) +{ + return boost::algorithm::none_of (boost::begin (r), boost::end (r), p ); +} + +/// \fn none_of_equal ( InputIterator first, InputIterator last, const V &val ) +/// \return true if none of the elements in [first, last) are equal to 'val' +/// \note returns true on an empty range +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool none_of_equal ( InputIterator first, InputIterator last, const V &val ) +{ + for ( ; first != last; ++first ) + if ( val == *first ) + return false; + return true; +} + +/// \fn none_of_equal ( const Range &r, const V &val ) +/// \return true if none of the elements in the range are equal to 'val' +/// \note returns true on an empty range +/// +/// \param r The input range +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool none_of_equal ( const Range &r, const V & val ) +{ + return boost::algorithm::none_of_equal (boost::begin (r), boost::end (r), val); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_NONE_OF_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/one_of.hpp b/third-party/boost/boost/algorithm/cxx11/one_of.hpp new file mode 100644 index 000000000..3b95180dc --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/one_of.hpp @@ -0,0 +1,89 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file one_of.hpp +/// \brief Test ranges to see if only one element matches a value or predicate. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_ONE_OF_HPP +#define BOOST_ALGORITHM_ONE_OF_HPP + +#include + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn one_of ( InputIterator first, InputIterator last, Predicate p ) +/// \return true if the predicate 'p' is true for exactly one item in [first, last). +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p A predicate for testing the elements of the sequence +/// +template +BOOST_CXX14_CONSTEXPR bool one_of ( InputIterator first, InputIterator last, Predicate p ) +{ +// find_if + for (; first != last; ++first) + if (p(*first)) + break; + + if (first == last) + return false; // Didn't occur at all + return boost::algorithm::none_of (++first, last, p); +} + +/// \fn one_of ( const Range &r, Predicate p ) +/// \return true if the predicate 'p' is true for exactly one item in the range. +/// +/// \param r The input range +/// \param p A predicate for testing the elements of the range +/// +template +BOOST_CXX14_CONSTEXPR bool one_of ( const Range &r, Predicate p ) +{ + return boost::algorithm::one_of ( boost::begin (r), boost::end (r), p ); +} + + +/// \fn one_of_equal ( InputIterator first, InputIterator last, const V &val ) +/// \return true if the value 'val' exists only once in [first, last). +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool one_of_equal ( InputIterator first, InputIterator last, const V &val ) +{ +// find + for (; first != last; ++first) + if (*first == val) + break; + + if (first == last) + return false; // Didn't occur at all + return boost::algorithm::none_of_equal (++first, last, val); +} + +/// \fn one_of_equal ( const Range &r, const V &val ) +/// \return true if the value 'val' exists only once in the range. +/// +/// \param r The input range +/// \param val A value to compare against +/// +template +BOOST_CXX14_CONSTEXPR bool one_of_equal ( const Range &r, const V &val ) +{ + return boost::algorithm::one_of_equal ( boost::begin (r), boost::end (r), val ); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_ALL_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/partition_copy.hpp b/third-party/boost/boost/algorithm/cxx11/partition_copy.hpp new file mode 100644 index 000000000..635b1e739 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/partition_copy.hpp @@ -0,0 +1,71 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file partition_copy.hpp +/// \brief Copy a subset of a sequence to a new sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_PARTITION_COPY_HPP +#define BOOST_ALGORITHM_PARTITION_COPY_HPP + +#include // for std::pair + +#include +#include +#include + +namespace boost { namespace algorithm { + +/// \fn partition_copy ( InputIterator first, InputIterator last, +/// OutputIterator1 out_true, OutputIterator2 out_false, UnaryPredicate p ) +/// \brief Copies the elements that satisfy the predicate p from the range [first, last) +/// to the range beginning at d_first_true, and +/// copies the elements that do not satisfy p to the range beginning at d_first_false. +/// +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param out_true An output iterator to write the elements that satisfy the predicate into +/// \param out_false An output iterator to write the elements that do not satisfy the predicate into +/// \param p A predicate for dividing the elements of the input sequence. +/// +/// \note This function is part of the C++2011 standard library. +template +BOOST_CXX14_CONSTEXPR std::pair +partition_copy ( InputIterator first, InputIterator last, + OutputIterator1 out_true, OutputIterator2 out_false, UnaryPredicate p ) +{ + for ( ; first != last; ++first ) + if ( p (*first)) + *out_true++ = *first; + else + *out_false++ = *first; + return std::pair ( out_true, out_false ); +} + +/// \fn partition_copy ( const Range &r, +/// OutputIterator1 out_true, OutputIterator2 out_false, UnaryPredicate p ) +/// +/// \param r The input range +/// \param out_true An output iterator to write the elements that satisfy the predicate into +/// \param out_false An output iterator to write the elements that do not satisfy the predicate into +/// \param p A predicate for dividing the elements of the input sequence. +/// +template +BOOST_CXX14_CONSTEXPR std::pair +partition_copy ( const Range &r, OutputIterator1 out_true, OutputIterator2 out_false, + UnaryPredicate p ) +{ + return boost::algorithm::partition_copy + (boost::begin(r), boost::end(r), out_true, out_false, p ); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_PARTITION_COPY_HPP diff --git a/third-party/boost/boost/algorithm/cxx11/partition_point.hpp b/third-party/boost/boost/algorithm/cxx11/partition_point.hpp new file mode 100644 index 000000000..2c2767ae5 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx11/partition_point.hpp @@ -0,0 +1,65 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file partition_point.hpp +/// \brief Find the partition point in a sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_PARTITION_POINT_HPP +#define BOOST_ALGORITHM_PARTITION_POINT_HPP + +#include // for std::distance, advance + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn partition_point ( ForwardIterator first, ForwardIterator last, Predicate p ) +/// \brief Given a partitioned range, returns the partition point, i.e, the first element +/// that does not satisfy p +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p The predicate to test the values with +/// \note This function is part of the C++2011 standard library. +template +ForwardIterator partition_point ( ForwardIterator first, ForwardIterator last, Predicate p ) +{ + std::size_t dist = std::distance ( first, last ); + while ( first != last ) { + std::size_t d2 = dist / 2; + ForwardIterator ret_val = first; + std::advance (ret_val, d2); + if (p (*ret_val)) { + first = ++ret_val; + dist -= d2 + 1; + } + else { + last = ret_val; + dist = d2; + } + } + return first; +} + +/// \fn partition_point ( Range &r, Predicate p ) +/// \brief Given a partitioned range, returns the partition point +/// +/// \param r The input range +/// \param p The predicate to test the values with +/// +template +typename boost::range_iterator::type partition_point ( Range &r, Predicate p ) +{ + return boost::algorithm::partition_point (boost::begin(r), boost::end(r), p); +} + + +}} + +#endif // BOOST_ALGORITHM_PARTITION_POINT_HPP diff --git a/third-party/boost/boost/algorithm/cxx14/equal.hpp b/third-party/boost/boost/algorithm/cxx14/equal.hpp new file mode 100644 index 000000000..526aae996 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx14/equal.hpp @@ -0,0 +1,104 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file equal.hpp +/// \brief Test ranges to if they are equal +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_EQUAL_HPP +#define BOOST_ALGORITHM_EQUAL_HPP + +#include + +namespace boost { namespace algorithm { + +namespace detail { + + template + struct eq { + BOOST_CONSTEXPR bool operator () ( const T1& v1, const T2& v2 ) const { return v1 == v2 ;} + }; + + template + BOOST_CXX14_CONSTEXPR + bool equal ( RandomAccessIterator1 first1, RandomAccessIterator1 last1, + RandomAccessIterator2 first2, RandomAccessIterator2 last2, BinaryPredicate pred, + std::random_access_iterator_tag, std::random_access_iterator_tag ) + { + // Random-access iterators let is check the sizes in constant time + if ( std::distance ( first1, last1 ) != std::distance ( first2, last2 )) + return false; + + // std::equal + for (; first1 != last1; ++first1, ++first2) + if (!pred(*first1, *first2)) + return false; + return true; + } + + template + BOOST_CXX14_CONSTEXPR + bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred, + std::input_iterator_tag, std::input_iterator_tag ) + { + for (; first1 != last1 && first2 != last2; ++first1, ++first2 ) + if ( !pred(*first1, *first2 )) + return false; + + return first1 == last1 && first2 == last2; + } +} + +/// \fn equal ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2, +/// BinaryPredicate pred ) +/// \return true if all elements in the two ranges are equal +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +/// \param pred A predicate for comparing the elements of the ranges +template +BOOST_CXX14_CONSTEXPR +bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, BinaryPredicate pred ) +{ + return boost::algorithm::detail::equal ( + first1, last1, first2, last2, pred, + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +/// \fn equal ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2 ) +/// \return true if all elements in the two ranges are equal +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +template +BOOST_CXX14_CONSTEXPR +bool equal ( InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2 ) +{ + return boost::algorithm::detail::equal ( + first1, last1, first2, last2, + boost::algorithm::detail::eq< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type> (), + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +// There are already range-based versions of these. + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_EQUAL_HPP diff --git a/third-party/boost/boost/algorithm/cxx14/is_permutation.hpp b/third-party/boost/boost/algorithm/cxx14/is_permutation.hpp new file mode 100644 index 000000000..639446bf3 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx14/is_permutation.hpp @@ -0,0 +1,79 @@ +/* + Copyright (c) Marshall Clow 2014. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file is_permutation.hpp +/// \brief Is a sequence a permutation of another sequence (four iterator versions) +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_IS_PERMUTATION14_HPP +#define BOOST_ALGORITHM_IS_PERMUTATION14_HPP + +#include // for std::pair +#include // for std::equal_to +#include + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, +/// ForwardIterator2 first2, ForwardIterator2 last2 ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last2 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \param last1 One past the end of the second sequence +/// \note This function is part of the C++2014 standard library. +template< class ForwardIterator1, class ForwardIterator2 > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2 ) +{ +// How should I deal with the idea that ForwardIterator1::value_type +// and ForwardIterator2::value_type could be different? Define my own comparison predicate? + std::pair eq = boost::algorithm::mismatch + ( first1, last1, first2, last2 ); + if ( eq.first == last1 && eq.second == last2) + return true; + return boost::algorithm::detail::is_permutation_tag ( + eq.first, last1, eq.second, last2, + std::equal_to::value_type> (), + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +/// \fn is_permutation ( ForwardIterator1 first, ForwardIterator1 last, +/// ForwardIterator2 first2, ForwardIterator2 last2, +/// BinaryPredicate p ) +/// \brief Tests to see if the sequence [first,last) is a permutation of the sequence starting at first2 +/// +/// \param first1 The start of the input sequence +/// \param last1 One past the end of the input sequence +/// \param first2 The start of the second sequence +/// \param last2 One past the end of the second sequence +/// \param pred The predicate to compare elements with +/// +/// \note This function is part of the C++2014 standard library. +template< class ForwardIterator1, class ForwardIterator2, class BinaryPredicate > +bool is_permutation ( ForwardIterator1 first1, ForwardIterator1 last1, + ForwardIterator2 first2, ForwardIterator2 last2, + BinaryPredicate pred ) +{ + std::pair eq = boost::algorithm::mismatch + ( first1, last1, first2, last2, pred ); + if ( eq.first == last1 && eq.second == last2) + return true; + return boost::algorithm::detail::is_permutation_tag ( + first1, last1, first2, last2, pred, + typename std::iterator_traits::iterator_category (), + typename std::iterator_traits::iterator_category ()); +} + +}} + +#endif // BOOST_ALGORITHM_IS_PERMUTATION14_HPP diff --git a/third-party/boost/boost/algorithm/cxx14/mismatch.hpp b/third-party/boost/boost/algorithm/cxx14/mismatch.hpp new file mode 100644 index 000000000..46017190d --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx14/mismatch.hpp @@ -0,0 +1,65 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file mismatch.hpp +/// \brief Find the first mismatched element in a sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_MISMATCH_HPP +#define BOOST_ALGORITHM_MISMATCH_HPP + +#include // for std::pair +#include + +namespace boost { namespace algorithm { + +/// \fn mismatch ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2, +/// BinaryPredicate pred ) +/// \return a pair of iterators pointing to the first elements in the sequence that do not match +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +/// \param pred A predicate for comparing the elements of the ranges +template +BOOST_CXX14_CONSTEXPR std::pair mismatch ( + InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2, + BinaryPredicate pred ) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if ( !pred ( *first1, *first2 )) + break; + return std::pair(first1, first2); +} + +/// \fn mismatch ( InputIterator1 first1, InputIterator1 last1, +/// InputIterator2 first2, InputIterator2 last2 ) +/// \return a pair of iterators pointing to the first elements in the sequence that do not match +/// +/// \param first1 The start of the first range. +/// \param last1 One past the end of the first range. +/// \param first2 The start of the second range. +/// \param last2 One past the end of the second range. +template +BOOST_CXX14_CONSTEXPR std::pair mismatch ( + InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, InputIterator2 last2 ) +{ + for (; first1 != last1 && first2 != last2; ++first1, ++first2) + if ( *first1 != *first2 ) + break; + return std::pair(first1, first2); +} + +// There are already range-based versions of these. + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_MISMATCH_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/exclusive_scan.hpp b/third-party/boost/boost/algorithm/cxx17/exclusive_scan.hpp new file mode 100644 index 000000000..e4ec112d2 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/exclusive_scan.hpp @@ -0,0 +1,52 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file exclusive_scan.hpp +/// \brief ??? +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP +#define BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +OutputIterator exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init, BinaryOperation bOp) +{ + if (first != last) + { + T saved = init; + do + { + init = bOp(init, *first); + *result = saved; + saved = init; + ++result; + } while (++first != last); + } + return result; +} + +template +OutputIterator exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init) +{ + typedef typename std::iterator_traits::value_type VT; + return boost::algorithm::exclusive_scan(first, last, result, init, std::plus()); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_EXCLUSIVE_SCAN_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/for_each_n.hpp b/third-party/boost/boost/algorithm/cxx17/for_each_n.hpp new file mode 100644 index 000000000..71f6cde3c --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/for_each_n.hpp @@ -0,0 +1,37 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file for_each_n.hpp +/// \brief Apply a functor to the elements of a sequence +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_FOR_EACH_N_HPP +#define BOOST_ALGORITHM_FOR_EACH_N_HPP + +#include // for std::pair + +namespace boost { namespace algorithm { + +/// \fn for_each_n(InputIterator first, Size n, Function f); +/// \return first + n +/// +/// \param first The start of the first range. +/// \param n One past the end of the first range. +/// \param f A functor to apply to the elements of the sequence +/// \note If f returns a result, the result is ignored. +template +InputIterator for_each_n(InputIterator first, Size n, Function f) +{ + for ( ; n > 0; --n, ++first ) + f(*first); + + return first; +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_FOR_EACH_N_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/inclusive_scan.hpp b/third-party/boost/boost/algorithm/cxx17/inclusive_scan.hpp new file mode 100644 index 000000000..5c60c39d2 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/inclusive_scan.hpp @@ -0,0 +1,60 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file transform_reduce.hpp +/// \brief Combine the (transformed) elements of a sequence (or two) into a single value. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP +#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +OutputIterator inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, BinaryOperation bOp, T init) +{ + for (; first != last; ++first, (void) ++result) { + init = bOp(init, *first); + *result = init; + } + return result; +} + + +template +OutputIterator inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, BinaryOperation bOp) +{ + if (first != last) { + typename std::iterator_traits::value_type init = *first; + *result++ = init; + if (++first != last) + return boost::algorithm::inclusive_scan(first, last, result, bOp, init); + } + + return result; +} + +template +OutputIterator inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result) +{ + typedef typename std::iterator_traits::value_type VT; + return boost::algorithm::inclusive_scan(first, last, result, std::plus()); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/reduce.hpp b/third-party/boost/boost/algorithm/cxx17/reduce.hpp new file mode 100644 index 000000000..55424b6e5 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/reduce.hpp @@ -0,0 +1,72 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file reduce.hpp +/// \brief Combine the elements of a sequence into a single value +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_REDUCE_HPP +#define BOOST_ALGORITHM_REDUCE_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +T reduce(InputIterator first, InputIterator last, T init, BinaryOperation bOp) +{ + ; + for (; first != last; ++first) + init = bOp(init, *first); + return init; +} + +template +T reduce(InputIterator first, InputIterator last, T init) +{ + typedef typename std::iterator_traits::value_type VT; + return boost::algorithm::reduce(first, last, init, std::plus()); +} + +template +typename std::iterator_traits::value_type +reduce(InputIterator first, InputIterator last) +{ + return boost::algorithm::reduce(first, last, + typename std::iterator_traits::value_type()); +} + +template +typename boost::range_value::type +reduce(const Range &r) +{ + return boost::algorithm::reduce(boost::begin(r), boost::end(r)); +} + +// Not sure that this won't be ambiguous (1) +template +T reduce(const Range &r, T init) +{ + return boost::algorithm::reduce(boost::begin (r), boost::end (r), init); +} + + +// Not sure that this won't be ambiguous (2) +template +T reduce(const Range &r, T init, BinaryOperation bOp) +{ + return boost::algorithm::reduce(boost::begin(r), boost::end(r), init, bOp); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_REDUCE_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/transform_exclusive_scan.hpp b/third-party/boost/boost/algorithm/cxx17/transform_exclusive_scan.hpp new file mode 100644 index 000000000..dd3c9c834 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/transform_exclusive_scan.hpp @@ -0,0 +1,46 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file transform_exclusive_scan.hpp +/// \brief ???? +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP +#define BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +OutputIterator transform_exclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, T init, + BinaryOperation bOp, UnaryOperation uOp) +{ + if (first != last) + { + T saved = init; + do + { + init = bOp(init, uOp(*first)); + *result = saved; + saved = init; + ++result; + } while (++first != last); + } + return result; +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_TRANSFORM_EXCLUSIVE_SCAN_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/transform_inclusive_scan.hpp b/third-party/boost/boost/algorithm/cxx17/transform_inclusive_scan.hpp new file mode 100644 index 000000000..1d1197656 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/transform_inclusive_scan.hpp @@ -0,0 +1,59 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file transform_reduce.hpp +/// \brief Combine the (transformed) elements of a sequence (or two) into a single value. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP +#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, + BinaryOperation bOp, UnaryOperation uOp, + T init) +{ + for (; first != last; ++first, (void) ++result) { + init = bOp(init, uOp(*first)); + *result = init; + } + + return result; +} + +template +OutputIterator transform_inclusive_scan(InputIterator first, InputIterator last, + OutputIterator result, + BinaryOperation bOp, UnaryOperation uOp) +{ + if (first != last) { + typename std::iterator_traits::value_type init = uOp(*first); + *result++ = init; + if (++first != last) + return boost::algorithm::transform_inclusive_scan + (first, last, result, bOp, uOp, init); + } + + return result; +} + + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP diff --git a/third-party/boost/boost/algorithm/cxx17/transform_reduce.hpp b/third-party/boost/boost/algorithm/cxx17/transform_reduce.hpp new file mode 100644 index 000000000..869638476 --- /dev/null +++ b/third-party/boost/boost/algorithm/cxx17/transform_reduce.hpp @@ -0,0 +1,55 @@ +/* + Copyright (c) Marshall Clow 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file transform_reduce.hpp +/// \brief Combine the (transformed) elements of a sequence (or two) into a single value. +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP +#define BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP + +#include // for std::plus +#include // for std::iterator_traits + +#include +#include +#include + +namespace boost { namespace algorithm { + +template +T transform_reduce(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, T init, + BinaryOperation1 bOp1, BinaryOperation2 bOp2) +{ + for (; first1 != last1; ++first1, (void) ++first2) + init = bOp1(init, bOp2(*first1, *first2)); + return init; +} + +template +T transform_reduce(InputIterator first, InputIterator last, + T init, BinaryOperation bOp, UnaryOperation uOp) +{ + for (; first != last; ++first) + init = bOp(init, uOp(*first)); + return init; +} + +template +T transform_reduce(InputIterator1 first1, InputIterator1 last1, + InputIterator2 first2, T init) +{ + return boost::algorithm::transform_reduce(first1, last1, first2, init, + std::plus(), std::multiplies()); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_TRANSFORM_REDUCE_HPP diff --git a/third-party/boost/boost/algorithm/find_backward.hpp b/third-party/boost/boost/algorithm/find_backward.hpp new file mode 100644 index 000000000..66901a147 --- /dev/null +++ b/third-party/boost/boost/algorithm/find_backward.hpp @@ -0,0 +1,97 @@ +/* + Copyright (c) T. Zachary Laine 2018. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt) +*/ +#ifndef BOOST_ALGORITHM_FIND_BACKWARD_HPP +#define BOOST_ALGORITHM_FIND_BACKWARD_HPP + +#include +#include +#include + +#include + + +namespace boost { namespace algorithm { + +template +BOOST_CXX14_CONSTEXPR +BidiIter find_backward(BidiIter first, BidiIter last, const T & x) +{ + BidiIter it = last; + while (it != first) { + if (*--it == x) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_backward(Range & range, const T & x) +{ + return ::boost::algorithm::find_backward(boost::begin(range), boost::end(range), x); +} + +template +BOOST_CXX14_CONSTEXPR +BidiIter find_not_backward(BidiIter first, BidiIter last, const T & x) +{ + BidiIter it = last; + while (it != first) { + if (*--it != x) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_not_backward(Range & range, const T & x) +{ + return ::boost::algorithm::find_not_backward(boost::begin(range), boost::end(range), x); +} + +template +BOOST_CXX14_CONSTEXPR +BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p) +{ + BidiIter it = last; + while (it != first) { + if (p(*--it)) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_if_backward(Range & range, Pred p) +{ + return ::boost::algorithm::find_if_backward(boost::begin(range), boost::end(range), p); +} + +template +BOOST_CXX14_CONSTEXPR +BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p) +{ + BidiIter it = last; + while (it != first) { + if (!p(*--it)) + return it; + } + return last; +} + +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_if_not_backward(Range & range, Pred p) +{ + return ::boost::algorithm::find_if_not_backward(boost::begin(range), boost::end(range), p); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_FIND_BACKWARD_HPP diff --git a/third-party/boost/boost/algorithm/find_not.hpp b/third-party/boost/boost/algorithm/find_not.hpp new file mode 100644 index 000000000..ef4df00b8 --- /dev/null +++ b/third-party/boost/boost/algorithm/find_not.hpp @@ -0,0 +1,39 @@ +/* + Copyright (c) T. Zachary Laine 2018. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE10.txt or copy at http://www.boost.org/LICENSE10.txt) +*/ +#ifndef BOOST_ALGORITHM_FIND_NOT_HPP +#define BOOST_ALGORITHM_FIND_NOT_HPP + +#include +#include +#include + +#include + + +namespace boost { namespace algorithm { + +template +BOOST_CXX14_CONSTEXPR +InputIter find_not(InputIter first, Sentinel last, const T & x) +{ + for (; first != last; ++first) { + if (*first != x) + break; + } + return first; +} + +template +BOOST_CXX14_CONSTEXPR +typename boost::range_iterator::type find_not(Range & r, const T & x) +{ + return ::boost::algorithm::find_not(boost::begin(r), boost::end(r), x); +} + +}} // namespace boost and algorithm + +#endif // BOOST_ALGORITHM_FIND_NOT_HPP diff --git a/third-party/boost/boost/algorithm/gather.hpp b/third-party/boost/boost/algorithm/gather.hpp new file mode 100644 index 000000000..944bc9434 --- /dev/null +++ b/third-party/boost/boost/algorithm/gather.hpp @@ -0,0 +1,123 @@ +/* + Copyright 2008 Adobe Systems Incorporated + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Revision history: + January 2008 mtc Version for Adobe Source Library + January 2013 mtc Version for Boost.Algorithm + +*/ + +/**************************************************************************************************/ + +/*! +\author Marshall Clow +\date January 2008 +*/ + +#ifndef BOOST_ALGORITHM_GATHER_HPP +#define BOOST_ALGORITHM_GATHER_HPP + +#include // for std::stable_partition +#include + +#include // for boost::bind +#include // for boost::begin(range) +#include // for boost::end(range) + + +/**************************************************************************************************/ +/*! + \defgroup gather gather + \ingroup mutating_algorithm + + \c gather() takes a collection of elements defined by a pair of iterators and moves + the ones satisfying a predicate to them to a position (called the pivot) within + the sequence. The algorithm is stable. The result is a pair of iterators that + contains the items that satisfy the predicate. + + Given an sequence containing: +
+    0 1 2 3 4 5 6 7 8 9
+    
+ + a call to gather ( arr, arr + 10, arr + 4, IsEven ()) will result in: + +
+    1 3 0 2 4 6 8 5 7 9
+        |---|-----|
+      first |  second
+          pivot
+    
+ + + The problem is broken down into two basic steps, namely, moving the items before the pivot + and then moving the items from the pivot to the end. These "moves" are done with calls to + stable_partition. + + \par Storage Requirements: + + The algorithm uses stable_partition, which will attempt to allocate temporary memory, + but will work in-situ if there is none available. + + \par Time Complexity: + + If there is sufficient memory available, the run time is linear in N. + If there is not any memory available, then the run time is O(N log N). +*/ + +/**************************************************************************************************/ + +namespace boost { namespace algorithm { + +/**************************************************************************************************/ + +/*! + \ingroup gather + \brief iterator-based gather implementation +*/ + +template < + typename BidirectionalIterator, // Iter models BidirectionalIterator + typename Pred> // Pred models UnaryPredicate +std::pair gather + ( BidirectionalIterator first, BidirectionalIterator last, BidirectionalIterator pivot, Pred pred ) +{ +// The first call partitions everything up to (but not including) the pivot element, +// while the second call partitions the rest of the sequence. + return std::make_pair ( + std::stable_partition ( first, pivot, !boost::bind ( pred, _1 )), + std::stable_partition ( pivot, last, boost::bind ( pred, _1 ))); +} + +/**************************************************************************************************/ + +/*! + \ingroup gather + \brief range-based gather implementation +*/ + +template < + typename BidirectionalRange, // + typename Pred> // Pred models UnaryPredicate +std::pair< + typename boost::range_iterator::type, + typename boost::range_iterator::type> +gather ( + const BidirectionalRange &range, + typename boost::range_iterator::type pivot, + Pred pred ) +{ + return boost::algorithm::gather ( boost::begin ( range ), boost::end ( range ), pivot, pred ); +} + +/**************************************************************************************************/ + +}} // namespace + +/**************************************************************************************************/ + +#endif + diff --git a/third-party/boost/boost/algorithm/hex.hpp b/third-party/boost/boost/algorithm/hex.hpp new file mode 100644 index 000000000..b8335843a --- /dev/null +++ b/third-party/boost/boost/algorithm/hex.hpp @@ -0,0 +1,325 @@ +/* + Copyright (c) Marshall Clow 2011-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Thanks to Nevin for his comments/help. +*/ + +/* + General problem - turn a sequence of integral types into a sequence of hexadecimal characters. + - and back. +*/ + +/// \file hex.hpp +/// \brief Convert sequence of integral types into a sequence of hexadecimal +/// characters and back. Based on the MySQL functions HEX and UNHEX +/// \author Marshall Clow + +#ifndef BOOST_ALGORITHM_HEXHPP +#define BOOST_ALGORITHM_HEXHPP + +#include // for std::iterator_traits +#include + +#include +#include +#include +#include +#include + +#include +#include + + +namespace boost { namespace algorithm { + +/*! + \struct hex_decode_error + \brief Base exception class for all hex decoding errors +*/ /*! + \struct non_hex_input + \brief Thrown when a non-hex value (0-9, A-F) encountered when decoding. + Contains the offending character +*/ /*! + \struct not_enough_input + \brief Thrown when the input sequence unexpectedly ends + +*/ +struct hex_decode_error : virtual boost::exception, virtual std::exception {}; +struct not_enough_input : virtual hex_decode_error {}; +struct non_hex_input : virtual hex_decode_error {}; +typedef boost::error_info bad_char; + +namespace detail { +/// \cond DOXYGEN_HIDE + + template + OutputIterator encode_one ( T val, OutputIterator out, const char * hexDigits ) { + const std::size_t num_hex_digits = 2 * sizeof ( T ); + char res [ num_hex_digits ]; + char *p = res + num_hex_digits; + for ( std::size_t i = 0; i < num_hex_digits; ++i, val >>= 4 ) + *--p = hexDigits [ val & 0x0F ]; + return std::copy ( res, res + num_hex_digits, out ); + } + + template + unsigned char hex_char_to_int ( T val ) { + char c = static_cast ( val ); + unsigned retval = 0; + if ( c >= '0' && c <= '9' ) retval = c - '0'; + else if ( c >= 'A' && c <= 'F' ) retval = c - 'A' + 10; + else if ( c >= 'a' && c <= 'f' ) retval = c - 'a' + 10; + else BOOST_THROW_EXCEPTION (non_hex_input() << bad_char (c)); + return static_cast(retval); + } + +// My own iterator_traits class. +// It is here so that I can "reach inside" some kinds of output iterators +// and get the type to write. + template + struct hex_iterator_traits { + typedef typename std::iterator_traits::value_type value_type; + }; + + template + struct hex_iterator_traits< std::back_insert_iterator > { + typedef typename Container::value_type value_type; + }; + + template + struct hex_iterator_traits< std::front_insert_iterator > { + typedef typename Container::value_type value_type; + }; + + template + struct hex_iterator_traits< std::insert_iterator > { + typedef typename Container::value_type value_type; + }; + +// ostream_iterators have three template parameters. +// The first one is the output type, the second one is the character type of +// the underlying stream, the third is the character traits. +// We only care about the first one. + template + struct hex_iterator_traits< std::ostream_iterator > { + typedef T value_type; + }; + + template + bool iter_end ( Iterator current, Iterator last ) { return current == last; } + + template + bool ptr_end ( const T* ptr, const T* /*end*/ ) { return *ptr == '\0'; } + +// What can we assume here about the inputs? +// is std::iterator_traits::value_type always 'char' ? +// Could it be wchar_t, say? Does it matter? +// We are assuming ASCII for the values - but what about the storage? + template + typename boost::enable_if::value_type>, OutputIterator>::type + decode_one ( InputIterator &first, InputIterator last, OutputIterator out, EndPred pred ) { + typedef typename hex_iterator_traits::value_type T; + T res (0); + + // Need to make sure that we get can read that many chars here. + for ( std::size_t i = 0; i < 2 * sizeof ( T ); ++i, ++first ) { + if ( pred ( first, last )) + BOOST_THROW_EXCEPTION (not_enough_input ()); + res = ( 16 * res ) + hex_char_to_int (*first); + } + + *out = res; + return ++out; + } +/// \endcond + } + + +/// \fn hex ( InputIterator first, InputIterator last, OutputIterator out ) +/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex ( InputIterator first, InputIterator last, OutputIterator out ) { + for ( ; first != last; ++first ) + out = detail::encode_one ( *first, out, "0123456789ABCDEF" ); + return out; + } + + +/// \fn hex_lower ( InputIterator first, InputIterator last, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex_lower ( InputIterator first, InputIterator last, OutputIterator out ) { + for ( ; first != last; ++first ) + out = detail::encode_one ( *first, out, "0123456789abcdef" ); + return out; + } + + +/// \fn hex ( const T *ptr, OutputIterator out ) +/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. +/// +/// \param ptr A pointer to a 0-terminated sequence of data. +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if, OutputIterator>::type +hex ( const T *ptr, OutputIterator out ) { + while ( *ptr ) + out = detail::encode_one ( *ptr++, out, "0123456789ABCDEF" ); + return out; + } + + +/// \fn hex_lower ( const T *ptr, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param ptr A pointer to a 0-terminated sequence of data. +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if, OutputIterator>::type +hex_lower ( const T *ptr, OutputIterator out ) { + while ( *ptr ) + out = detail::encode_one ( *ptr++, out, "0123456789abcdef" ); + return out; + } + + +/// \fn hex ( const Range &r, OutputIterator out ) +/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. +/// +/// \param r The input range +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex ( const Range &r, OutputIterator out ) { + return hex (boost::begin(r), boost::end(r), out); +} + + +/// \fn hex_lower ( const Range &r, OutputIterator out ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param r The input range +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +typename boost::enable_if::value_type>, OutputIterator>::type +hex_lower ( const Range &r, OutputIterator out ) { + return hex_lower (boost::begin(r), boost::end(r), out); +} + + +/// \fn unhex ( InputIterator first, InputIterator last, OutputIterator out ) +/// \brief Converts a sequence of hexadecimal characters into a sequence of integers. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +OutputIterator unhex ( InputIterator first, InputIterator last, OutputIterator out ) { + while ( first != last ) + out = detail::decode_one ( first, last, out, detail::iter_end ); + return out; + } + + +/// \fn unhex ( const T *ptr, OutputIterator out ) +/// \brief Converts a sequence of hexadecimal characters into a sequence of integers. +/// +/// \param ptr A pointer to a null-terminated input sequence. +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +OutputIterator unhex ( const T *ptr, OutputIterator out ) { +// If we run into the terminator while decoding, we will throw a +// malformed input exception. It would be nicer to throw a 'Not enough input' +// exception - but how much extra work would that require? + while ( *ptr ) + out = detail::decode_one ( ptr, (const T *) NULL, out, detail::ptr_end ); + return out; + } + + +/// \fn OutputIterator unhex ( const Range &r, OutputIterator out ) +/// \brief Converts a sequence of hexadecimal characters into a sequence of integers. +/// +/// \param r The input range +/// \param out An output iterator to the results into +/// \return The updated output iterator +/// \note Based on the MySQL function of the same name +template +OutputIterator unhex ( const Range &r, OutputIterator out ) { + return unhex (boost::begin(r), boost::end(r), out); + } + + +/// \fn String hex ( const String &input ) +/// \brief Converts a sequence of integral types into a hexadecimal sequence of characters. +/// +/// \param input A container to be converted +/// \return A container with the encoded text +template +String hex ( const String &input ) { + String output; + output.reserve (input.size () * (2 * sizeof (typename String::value_type))); + (void) hex (input, std::back_inserter (output)); + return output; + } + + +/// \fn String hex_lower ( const String &input ) +/// \brief Converts a sequence of integral types into a lower case hexadecimal sequence of characters. +/// +/// \param input A container to be converted +/// \return A container with the encoded text +template +String hex_lower ( const String &input ) { + String output; + output.reserve (input.size () * (2 * sizeof (typename String::value_type))); + (void) hex_lower (input, std::back_inserter (output)); + return output; + } + + +/// \fn String unhex ( const String &input ) +/// \brief Converts a sequence of hexadecimal characters into a sequence of characters. +/// +/// \param input A container to be converted +/// \return A container with the decoded text +template +String unhex ( const String &input ) { + String output; + output.reserve (input.size () / (2 * sizeof (typename String::value_type))); + (void) unhex (input, std::back_inserter (output)); + return output; + } + +}} + +#endif // BOOST_ALGORITHM_HEXHPP diff --git a/third-party/boost/boost/algorithm/is_palindrome.hpp b/third-party/boost/boost/algorithm/is_palindrome.hpp new file mode 100644 index 000000000..09881109a --- /dev/null +++ b/third-party/boost/boost/algorithm/is_palindrome.hpp @@ -0,0 +1,140 @@ +/* + Copyright (c) Alexander Zaitsev , 2016 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. +*/ + +/// \file is_palindrome.hpp +/// \brief Checks the input sequence on palindrome. +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_IS_PALINDROME_HPP +#define BOOST_ALGORITHM_IS_PALINDROME_HPP + +#include +#include +#include + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param begin The start of the input sequence +/// \param end One past the end of the input sequence +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end, Predicate p) +{ + if(begin == end) + { + return true; + } + + --end; + while(begin != end) + { + if(!p(*begin, *end)) + { + return false; + } + ++begin; + if(begin == end) + { + break; + } + --end; + } + return true; +} + +/// \fn is_palindrome ( BidirectionalIterator begin, BidirectionalIterator end ) +/// \return true if the entire sequence is palindrome +/// +/// \param begin The start of the input sequence +/// \param end One past the end of the input sequence +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(BidirectionalIterator begin, BidirectionalIterator end) +{ + return is_palindrome(begin, end, + std::equal_to::value_type> ()); +} + +/// \fn is_palindrome ( const R& range ) +/// \return true if the entire sequence is palindrome +/// +/// \param range The range to be tested. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const R& range) +{ + return is_palindrome(boost::begin(range), boost::end(range)); +} + +/// \fn is_palindrome ( const R& range, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param range The range to be tested. +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const R& range, Predicate p) +{ + return is_palindrome(boost::begin(range), boost::end(range), p); +} + +/// \fn is_palindrome ( const char* str ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +bool is_palindrome(const char* str) +{ + if(!str) + return true; + return is_palindrome(str, str + strlen(str)); +} + +/// \fn is_palindrome ( const char* str, Predicate p ) +/// \return true if the entire sequence is palindrome +/// +/// \param str C-string to be tested. +/// \param p A predicate used to compare the values. +/// +/// \note This function will return true for empty sequences and for palindromes. +/// For other sequences function will return false. +/// Complexity: O(N). +template +bool is_palindrome(const char* str, Predicate p) +{ + if(!str) + return true; + return is_palindrome(str, str + strlen(str), p); +} +}} + +#endif // BOOST_ALGORITHM_IS_PALINDROME_HPP diff --git a/third-party/boost/boost/algorithm/is_partitioned_until.hpp b/third-party/boost/boost/algorithm/is_partitioned_until.hpp new file mode 100644 index 000000000..42683e1d8 --- /dev/null +++ b/third-party/boost/boost/algorithm/is_partitioned_until.hpp @@ -0,0 +1,63 @@ +/* + Copyright (c) Alexander Zaitsev , 2017. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +*/ + +/// \file is_partitioned_until.hpp +/// \brief Tell if a sequence is partitioned +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP +#define BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn is_partitioned_until ( InputIterator first, InputIterator last, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param first The start of the input sequence +/// \param last One past the end of the input sequence +/// \param p The predicate to test the values with +/// +/// \note Returns the first iterator 'it' in the sequence [first, last) for which is_partitioned(first, it, p) is false. +/// Returns last if the entire sequence is partitioned. +/// Complexity: O(N). +template +InputIterator is_partitioned_until ( InputIterator first, InputIterator last, UnaryPredicate p ) +{ +// Run through the part that satisfy the predicate + for ( ; first != last; ++first ) + if ( !p (*first)) + break; +// Now the part that does not satisfy the predicate + for ( ; first != last; ++first ) + if ( p (*first)) + return first; + return last; +} + +/// \fn is_partitioned_until ( const Range &r, UnaryPredicate p ) +/// \brief Tests to see if a sequence is partitioned according to a predicate. +/// In other words, all the items in the sequence that satisfy the predicate are at the beginning of the sequence. +/// +/// \param r The input range +/// \param p The predicate to test the values with +/// +/// \note Returns the first iterator 'it' in the sequence [first, last) for which is_partitioned(first, it, p) is false. +/// Returns last if the entire sequence is partitioned. +/// Complexity: O(N). +template +typename boost::range_iterator::type is_partitioned_until ( const Range &r, UnaryPredicate p ) +{ + return boost::algorithm::is_partitioned_until (boost::begin(r), boost::end(r), p); +} + +}} + +#endif // BOOST_ALGORITHM_IS_PARTITIONED_UNTIL_HPP diff --git a/third-party/boost/boost/algorithm/minmax.hpp b/third-party/boost/boost/algorithm/minmax.hpp new file mode 100644 index 000000000..053a7d60a --- /dev/null +++ b/third-party/boost/boost/algorithm/minmax.hpp @@ -0,0 +1,47 @@ +// (C) Copyright Herve Bronnimann 2004. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 1 July 2004 + Split the code into two headers to lessen dependence on + Boost.tuple. (Herve) + 26 June 2004 + Added the code for the boost minmax library. (Herve) +*/ + +#ifndef BOOST_ALGORITHM_MINMAX_HPP +#define BOOST_ALGORITHM_MINMAX_HPP + +/* PROPOSED STANDARD EXTENSIONS: + * + * minmax(a, b) + * Effect: (b // for using pairs with boost::cref +#include + +namespace boost { + + template + tuple< T const&, T const& > + minmax(T const& a, T const& b) { + return (b + tuple< T const&, T const& > + minmax(T const& a, T const& b, BinaryPredicate comp) { + return comp(b,a) ? make_tuple(cref(b),cref(a)) : make_tuple(cref(a),cref(b)); + } + +} // namespace boost + +#endif // BOOST_ALGORITHM_MINMAX_HPP diff --git a/third-party/boost/boost/algorithm/minmax_element.hpp b/third-party/boost/boost/algorithm/minmax_element.hpp new file mode 100644 index 000000000..752f6cbdb --- /dev/null +++ b/third-party/boost/boost/algorithm/minmax_element.hpp @@ -0,0 +1,553 @@ +// (C) Copyright Herve Bronnimann 2004. +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 1 July 2004 + Split the code into two headers to lessen dependence on + Boost.tuple. (Herve) + 26 June 2004 + Added the code for the boost minmax library. (Herve) +*/ + +#ifndef BOOST_ALGORITHM_MINMAX_ELEMENT_HPP +#define BOOST_ALGORITHM_MINMAX_ELEMENT_HPP + +/* PROPOSED STANDARD EXTENSIONS: + * + * minmax_element(first, last) + * Effect: std::make_pair( std::min_element(first, last), + * std::max_element(first, last) ); + * + * minmax_element(first, last, comp) + * Effect: std::make_pair( std::min_element(first, last, comp), + * std::max_element(first, last, comp) ); + */ + +#include // for std::pair and std::make_pair + +namespace boost { + + namespace detail { // for obtaining a uniform version of minmax_element + // that compiles with VC++ 6.0 -- avoid the iterator_traits by + // having comparison object over iterator, not over dereferenced value + + template + struct less_over_iter { + bool operator()(Iterator const& it1, + Iterator const& it2) const { return *it1 < *it2; } + }; + + template + struct binary_pred_over_iter { + explicit binary_pred_over_iter(BinaryPredicate const& p ) : m_p( p ) {} + bool operator()(Iterator const& it1, + Iterator const& it2) const { return m_p(*it1, *it2); } + private: + BinaryPredicate m_p; + }; + + // common base for the two minmax_element overloads + + template + std::pair + basic_minmax_element(ForwardIter first, ForwardIter last, Compare comp) + { + if (first == last) + return std::make_pair(last,last); + + ForwardIter min_result = first; + ForwardIter max_result = first; + + // if only one element + ForwardIter second = first; ++second; + if (second == last) + return std::make_pair(min_result, max_result); + + // treat first pair separately (only one comparison for first two elements) + ForwardIter potential_min_result = last; + if (comp(first, second)) + max_result = second; + else { + min_result = second; + potential_min_result = first; + } + + // then each element by pairs, with at most 3 comparisons per pair + first = ++second; if (first != last) ++second; + while (second != last) { + if (comp(first, second)) { + if (comp(first, min_result)) { + min_result = first; + potential_min_result = last; + } + if (comp(max_result, second)) + max_result = second; + } else { + if (comp(second, min_result)) { + min_result = second; + potential_min_result = first; + } + if (comp(max_result, first)) + max_result = first; + } + first = ++second; + if (first != last) ++second; + } + + // if odd number of elements, treat last element + if (first != last) { // odd number of elements + if (comp(first, min_result)) { + min_result = first; + potential_min_result = last; + } + else if (comp(max_result, first)) + max_result = first; + } + + // resolve min_result being incorrect with one extra comparison + // (in which case potential_min_result is necessarily the correct result) + if (potential_min_result != last + && !comp(min_result, potential_min_result)) + min_result = potential_min_result; + + return std::make_pair(min_result,max_result); + } + + } // namespace detail + + template + std::pair + minmax_element(ForwardIter first, ForwardIter last) + { + return detail::basic_minmax_element(first, last, + detail::less_over_iter() ); + } + + template + std::pair + minmax_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) + { + return detail::basic_minmax_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + +} + +/* PROPOSED BOOST EXTENSIONS + * In the description below, [rfirst,rlast) denotes the reversed range + * of [first,last). Even though the iterator type of first and last may + * be only a Forward Iterator, it is possible to explain the semantics + * by assuming that it is a Bidirectional Iterator. In the sequel, + * reverse(ForwardIterator&) returns the reverse_iterator adaptor. + * This is not how the functions would be implemented! + * + * first_min_element(first, last) + * Effect: std::min_element(first, last); + * + * first_min_element(first, last, comp) + * Effect: std::min_element(first, last, comp); + * + * last_min_element(first, last) + * Effect: reverse( std::min_element(reverse(last), reverse(first)) ); + * + * last_min_element(first, last, comp) + * Effect: reverse( std::min_element(reverse(last), reverse(first), comp) ); + * + * first_max_element(first, last) + * Effect: std::max_element(first, last); + * + * first_max_element(first, last, comp) + * Effect: max_element(first, last); + * + * last_max_element(first, last) + * Effect: reverse( std::max_element(reverse(last), reverse(first)) ); + * + * last_max_element(first, last, comp) + * Effect: reverse( std::max_element(reverse(last), reverse(first), comp) ); + * + * first_min_first_max_element(first, last) + * Effect: std::make_pair( first_min_element(first, last), + * first_max_element(first, last) ); + * + * first_min_first_max_element(first, last, comp) + * Effect: std::make_pair( first_min_element(first, last, comp), + * first_max_element(first, last, comp) ); + * + * first_min_last_max_element(first, last) + * Effect: std::make_pair( first_min_element(first, last), + * last_max_element(first, last) ); + * + * first_min_last_max_element(first, last, comp) + * Effect: std::make_pair( first_min_element(first, last, comp), + * last_max_element(first, last, comp) ); + * + * last_min_first_max_element(first, last) + * Effect: std::make_pair( last_min_element(first, last), + * first_max_element(first, last) ); + * + * last_min_first_max_element(first, last, comp) + * Effect: std::make_pair( last_min_element(first, last, comp), + * first_max_element(first, last, comp) ); + * + * last_min_last_max_element(first, last) + * Effect: std::make_pair( last_min_element(first, last), + * last_max_element(first, last) ); + * + * last_min_last_max_element(first, last, comp) + * Effect: std::make_pair( last_min_element(first, last, comp), + * last_max_element(first, last, comp) ); + */ + +namespace boost { + + // Min_element and max_element variants + + namespace detail { // common base for the overloads + + template + ForwardIter + basic_first_min_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return last; + ForwardIter min_result = first; + while (++first != last) + if (comp(first, min_result)) + min_result = first; + return min_result; + } + + template + ForwardIter + basic_last_min_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return last; + ForwardIter min_result = first; + while (++first != last) + if (!comp(min_result, first)) + min_result = first; + return min_result; + } + + template + ForwardIter + basic_first_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return last; + ForwardIter max_result = first; + while (++first != last) + if (comp(max_result, first)) + max_result = first; + return max_result; + } + + template + ForwardIter + basic_last_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return last; + ForwardIter max_result = first; + while (++first != last) + if (!comp(first, max_result)) + max_result = first; + return max_result; + } + + } // namespace detail + + template + ForwardIter + first_min_element(ForwardIter first, ForwardIter last) + { + return detail::basic_first_min_element(first, last, + detail::less_over_iter() ); + } + + template + ForwardIter + first_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) + { + return detail::basic_first_min_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + template + ForwardIter + last_min_element(ForwardIter first, ForwardIter last) + { + return detail::basic_last_min_element(first, last, + detail::less_over_iter() ); + } + + template + ForwardIter + last_min_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) + { + return detail::basic_last_min_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + template + ForwardIter + first_max_element(ForwardIter first, ForwardIter last) + { + return detail::basic_first_max_element(first, last, + detail::less_over_iter() ); + } + + template + ForwardIter + first_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) + { + return detail::basic_first_max_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + template + ForwardIter + last_max_element(ForwardIter first, ForwardIter last) + { + return detail::basic_last_max_element(first, last, + detail::less_over_iter() ); + } + + template + ForwardIter + last_max_element(ForwardIter first, ForwardIter last, BinaryPredicate comp) + { + return detail::basic_last_max_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + + // Minmax_element variants -- comments removed + + namespace detail { + + template + std::pair + basic_first_min_last_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) + return std::make_pair(last,last); + + ForwardIter min_result = first; + ForwardIter max_result = first; + + ForwardIter second = ++first; + if (second == last) + return std::make_pair(min_result, max_result); + + if (comp(second, min_result)) + min_result = second; + else + max_result = second; + + first = ++second; if (first != last) ++second; + while (second != last) { + if (!comp(second, first)) { + if (comp(first, min_result)) + min_result = first; + if (!comp(second, max_result)) + max_result = second; + } else { + if (comp(second, min_result)) + min_result = second; + if (!comp(first, max_result)) + max_result = first; + } + first = ++second; if (first != last) ++second; + } + + if (first != last) { + if (comp(first, min_result)) + min_result = first; + else if (!comp(first, max_result)) + max_result = first; + } + + return std::make_pair(min_result, max_result); + } + + template + std::pair + basic_last_min_first_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return std::make_pair(last,last); + + ForwardIter min_result = first; + ForwardIter max_result = first; + + ForwardIter second = ++first; + if (second == last) + return std::make_pair(min_result, max_result); + + if (comp(max_result, second)) + max_result = second; + else + min_result = second; + + first = ++second; if (first != last) ++second; + while (second != last) { + if (comp(first, second)) { + if (!comp(min_result, first)) + min_result = first; + if (comp(max_result, second)) + max_result = second; + } else { + if (!comp(min_result, second)) + min_result = second; + if (comp(max_result, first)) + max_result = first; + } + first = ++second; if (first != last) ++second; + } + + if (first != last) { + if (!comp(min_result, first)) + min_result = first; + else if (comp(max_result, first)) + max_result = first; + } + + return std::make_pair(min_result, max_result); + } + + template + std::pair + basic_last_min_last_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + if (first == last) return std::make_pair(last,last); + + ForwardIter min_result = first; + ForwardIter max_result = first; + + ForwardIter second = first; ++second; + if (second == last) + return std::make_pair(min_result,max_result); + + ForwardIter potential_max_result = last; + if (comp(first, second)) + max_result = second; + else { + min_result = second; + potential_max_result = second; + } + + first = ++second; if (first != last) ++second; + while (second != last) { + if (comp(first, second)) { + if (!comp(min_result, first)) + min_result = first; + if (!comp(second, max_result)) { + max_result = second; + potential_max_result = last; + } + } else { + if (!comp(min_result, second)) + min_result = second; + if (!comp(first, max_result)) { + max_result = first; + potential_max_result = second; + } + } + first = ++second; + if (first != last) ++second; + } + + if (first != last) { + if (!comp(min_result, first)) + min_result = first; + if (!comp(first, max_result)) { + max_result = first; + potential_max_result = last; + } + } + + if (potential_max_result != last + && !comp(potential_max_result, max_result)) + max_result = potential_max_result; + + return std::make_pair(min_result,max_result); + } + + } // namespace detail + + template + inline std::pair + first_min_first_max_element(ForwardIter first, ForwardIter last) + { + return minmax_element(first, last); + } + + template + inline std::pair + first_min_first_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + return minmax_element(first, last, comp); + } + + template + std::pair + first_min_last_max_element(ForwardIter first, ForwardIter last) + { + return detail::basic_first_min_last_max_element(first, last, + detail::less_over_iter() ); + } + + template + inline std::pair + first_min_last_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + return detail::basic_first_min_last_max_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + template + std::pair + last_min_first_max_element(ForwardIter first, ForwardIter last) + { + return detail::basic_last_min_first_max_element(first, last, + detail::less_over_iter() ); + } + + template + inline std::pair + last_min_first_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + return detail::basic_last_min_first_max_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + + template + std::pair + last_min_last_max_element(ForwardIter first, ForwardIter last) + { + return detail::basic_last_min_last_max_element(first, last, + detail::less_over_iter() ); + } + + template + inline std::pair + last_min_last_max_element(ForwardIter first, ForwardIter last, + BinaryPredicate comp) + { + return detail::basic_last_min_last_max_element(first, last, + detail::binary_pred_over_iter(comp) ); + } + +} // namespace boost + +#endif // BOOST_ALGORITHM_MINMAX_ELEMENT_HPP diff --git a/third-party/boost/boost/algorithm/searching/boyer_moore.hpp b/third-party/boost/boost/algorithm/searching/boyer_moore.hpp new file mode 100644 index 000000000..192d4dec2 --- /dev/null +++ b/third-party/boost/boost/algorithm/searching/boyer_moore.hpp @@ -0,0 +1,272 @@ +/* + Copyright (c) Marshall Clow 2010-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP +#define BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP + +#include // for std::iterator_traits + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace boost { namespace algorithm { + +/* + A templated version of the boyer-moore searching algorithm. + +References: + http://www.cs.utexas.edu/users/moore/best-ideas/string-searching/ + http://www.cs.utexas.edu/~moore/publications/fstrpos.pdf + +Explanations: + http://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_string_search_algorithm + http://www.movsd.com/bm.htm + http://www.cs.ucdavis.edu/~gusfield/cs224f09/bnotes.pdf + +The Boyer-Moore search algorithm uses two tables, a "bad character" table +to tell how far to skip ahead when it hits a character that is not in the pattern, +and a "good character" table to tell how far to skip ahead when it hits a +mismatch on a character that _is_ in the pattern. + +Requirements: + * Random access iterators + * The two iterator types (patIter and corpusIter) must + "point to" the same underlying type and be comparable. + * Additional requirements may be imposed but the skip table, such as: + ** Numeric type (array-based skip table) + ** Hashable type (map-based skip table) +*/ + + template > + class boyer_moore { + typedef typename std::iterator_traits::difference_type difference_type; + public: + boyer_moore ( patIter first, patIter last ) + : pat_first ( first ), pat_last ( last ), + k_pattern_length ( std::distance ( pat_first, pat_last )), + skip_ ( k_pattern_length, -1 ), + suffix_ ( k_pattern_length + 1 ) + { + this->build_skip_table ( first, last ); + this->build_suffix_table ( first, last ); + } + + ~boyer_moore () {} + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// + template + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + BOOST_STATIC_ASSERT (( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); + + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start + + const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); + // If the pattern is larger than the corpus, we can't find it! + if ( k_corpus_length < k_pattern_length ) + return std::make_pair(corpus_last, corpus_last); + + // Do the search + return this->do_search ( corpus_first, corpus_last ); + } + + template + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { + return (*this) (boost::begin(r), boost::end(r)); + } + + private: +/// \cond DOXYGEN_HIDE + patIter pat_first, pat_last; + const difference_type k_pattern_length; + typename traits::skip_table_t skip_; + std::vector suffix_; + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// \param p A predicate used for the search comparisons. + /// + template + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { + /* ---- Do the matching ---- */ + corpusIter curPos = corpus_first; + const corpusIter lastPos = corpus_last - k_pattern_length; + difference_type j, k, m; + + while ( curPos <= lastPos ) { + /* while ( std::distance ( curPos, corpus_last ) >= k_pattern_length ) { */ + // Do we match right where we are? + j = k_pattern_length; + while ( pat_first [j-1] == curPos [j-1] ) { + j--; + // We matched - we're done! + if ( j == 0 ) + return std::make_pair(curPos, curPos + k_pattern_length); + } + + // Since we didn't match, figure out how far to skip forward + k = skip_ [ curPos [ j - 1 ]]; + m = j - k - 1; + if ( k < j && m > suffix_ [ j ] ) + curPos += m; + else + curPos += suffix_ [ j ]; + } + + return std::make_pair(corpus_last, corpus_last); // We didn't find anything + } + + + void build_skip_table ( patIter first, patIter last ) { + for ( std::size_t i = 0; first != last; ++first, ++i ) + skip_.insert ( *first, i ); + } + + + template + void compute_bm_prefix ( Iter first, Iter last, Container &prefix ) { + const std::size_t count = std::distance ( first, last ); + BOOST_ASSERT ( count > 0 ); + BOOST_ASSERT ( prefix.size () == count ); + + prefix[0] = 0; + std::size_t k = 0; + for ( std::size_t i = 1; i < count; ++i ) { + BOOST_ASSERT ( k < count ); + while ( k > 0 && ( first[k] != first[i] )) { + BOOST_ASSERT ( k < count ); + k = prefix [ k - 1 ]; + } + + if ( first[k] == first[i] ) + k++; + prefix [ i ] = k; + } + } + + void build_suffix_table ( patIter first, patIter last ) { + const std::size_t count = (std::size_t) std::distance ( first, last ); + + if ( count > 0 ) { // empty pattern + std::vector::value_type> reversed(count); + (void) std::reverse_copy ( first, last, reversed.begin ()); + + std::vector prefix (count); + compute_bm_prefix ( first, last, prefix ); + + std::vector prefix_reversed (count); + compute_bm_prefix ( reversed.begin (), reversed.end (), prefix_reversed ); + + for ( std::size_t i = 0; i <= count; i++ ) + suffix_[i] = count - prefix [count-1]; + + for ( std::size_t i = 0; i < count; i++ ) { + const std::size_t j = count - prefix_reversed[i]; + const difference_type k = i - prefix_reversed[i] + 1; + + if (suffix_[j] > k) + suffix_[j] = k; + } + } + } +/// \endcond + }; + + +/* Two ranges as inputs gives us four possibilities; with 2,3,3,4 parameters + Use a bit of TMP to disambiguate the 3-argument templates */ + +/// \fn boyer_moore_search ( corpusIter corpus_first, corpusIter corpus_last, +/// patIter pat_first, patIter pat_last ) +/// \brief Searches the corpus for the pattern. +/// +/// \param corpus_first The start of the data to search (Random Access Iterator) +/// \param corpus_last One past the end of the data to search +/// \param pat_first The start of the pattern to search for (Random Access Iterator) +/// \param pat_last One past the end of the data to search for +/// + template + std::pair boyer_moore_search ( + corpusIter corpus_first, corpusIter corpus_last, + patIter pat_first, patIter pat_last ) + { + boyer_moore bm ( pat_first, pat_last ); + return bm ( corpus_first, corpus_last ); + } + + template + std::pair boyer_moore_search ( + corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + boyer_moore bm ( boost::begin(pattern), boost::end (pattern)); + return bm ( corpus_first, corpus_last ); + } + + template + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > + ::type + boyer_moore_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) + { + boyer_moore bm ( pat_first, pat_last ); + return bm (boost::begin (corpus), boost::end (corpus)); + } + + template + std::pair::type, typename boost::range_iterator::type> + boyer_moore_search ( CorpusRange &corpus, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + boyer_moore bm ( boost::begin(pattern), boost::end (pattern)); + return bm (boost::begin (corpus), boost::end (corpus)); + } + + + // Creator functions -- take a pattern range, return an object + template + boost::algorithm::boyer_moore::type> + make_boyer_moore ( const Range &r ) { + return boost::algorithm::boyer_moore + ::type> (boost::begin(r), boost::end(r)); + } + + template + boost::algorithm::boyer_moore::type> + make_boyer_moore ( Range &r ) { + return boost::algorithm::boyer_moore + ::type> (boost::begin(r), boost::end(r)); + } + +}} + +#endif // BOOST_ALGORITHM_BOYER_MOORE_SEARCH_HPP diff --git a/third-party/boost/boost/algorithm/searching/boyer_moore_horspool.hpp b/third-party/boost/boost/algorithm/searching/boyer_moore_horspool.hpp new file mode 100644 index 000000000..aacb5cb83 --- /dev/null +++ b/third-party/boost/boost/algorithm/searching/boyer_moore_horspool.hpp @@ -0,0 +1,202 @@ +/* + Copyright (c) Marshall Clow 2010-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP +#define BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP + +#include // for std::iterator_traits + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +// #define BOOST_ALGORITHM_BOYER_MOORE_HORSPOOL_DEBUG_HPP + +namespace boost { namespace algorithm { + +/* + A templated version of the boyer-moore-horspool searching algorithm. + + Requirements: + * Random access iterators + * The two iterator types (patIter and corpusIter) must + "point to" the same underlying type. + * Additional requirements may be imposed buy the skip table, such as: + ** Numeric type (array-based skip table) + ** Hashable type (map-based skip table) + +http://www-igm.univ-mlv.fr/%7Elecroq/string/node18.html + +*/ + + template > + class boyer_moore_horspool { + typedef typename std::iterator_traits::difference_type difference_type; + public: + boyer_moore_horspool ( patIter first, patIter last ) + : pat_first ( first ), pat_last ( last ), + k_pattern_length ( std::distance ( pat_first, pat_last )), + skip_ ( k_pattern_length, k_pattern_length ) { + + // Build the skip table + std::size_t i = 0; + if ( first != last ) // empty pattern? + for ( patIter iter = first; iter != last-1; ++iter, ++i ) + skip_.insert ( *iter, k_pattern_length - 1 - i ); +#ifdef BOOST_ALGORITHM_BOYER_MOORE_HORSPOOL_DEBUG_HPP + skip_.PrintSkipTable (); +#endif + } + + ~boyer_moore_horspool () {} + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// + template + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + BOOST_STATIC_ASSERT (( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); + + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start + + const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); + // If the pattern is larger than the corpus, we can't find it! + if ( k_corpus_length < k_pattern_length ) + return std::make_pair(corpus_last, corpus_last); + + // Do the search + return this->do_search ( corpus_first, corpus_last ); + } + + template + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { + return (*this) (boost::begin(r), boost::end(r)); + } + + private: +/// \cond DOXYGEN_HIDE + patIter pat_first, pat_last; + const difference_type k_pattern_length; + typename traits::skip_table_t skip_; + + /// \fn do_search ( corpusIter corpus_first, corpusIter corpus_last ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// \param k_corpus_length The length of the corpus to search + /// + template + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last ) const { + corpusIter curPos = corpus_first; + const corpusIter lastPos = corpus_last - k_pattern_length; + while ( curPos <= lastPos ) { + // Do we match right where we are? + std::size_t j = k_pattern_length - 1; + while ( pat_first [j] == curPos [j] ) { + // We matched - we're done! + if ( j == 0 ) + return std::make_pair(curPos, curPos + k_pattern_length); + j--; + } + + curPos += skip_ [ curPos [ k_pattern_length - 1 ]]; + } + + return std::make_pair(corpus_last, corpus_last); + } +// \endcond + }; + +/* Two ranges as inputs gives us four possibilities; with 2,3,3,4 parameters + Use a bit of TMP to disambiguate the 3-argument templates */ + +/// \fn boyer_moore_horspool_search ( corpusIter corpus_first, corpusIter corpus_last, +/// patIter pat_first, patIter pat_last ) +/// \brief Searches the corpus for the pattern. +/// +/// \param corpus_first The start of the data to search (Random Access Iterator) +/// \param corpus_last One past the end of the data to search +/// \param pat_first The start of the pattern to search for (Random Access Iterator) +/// \param pat_last One past the end of the data to search for +/// + template + std::pair boyer_moore_horspool_search ( + corpusIter corpus_first, corpusIter corpus_last, + patIter pat_first, patIter pat_last ) + { + boyer_moore_horspool bmh ( pat_first, pat_last ); + return bmh ( corpus_first, corpus_last ); + } + + template + std::pair boyer_moore_horspool_search ( + corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + boyer_moore_horspool bmh ( boost::begin(pattern), boost::end (pattern)); + return bmh ( corpus_first, corpus_last ); + } + + template + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > + ::type + boyer_moore_horspool_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) + { + boyer_moore_horspool bmh ( pat_first, pat_last ); + return bm (boost::begin (corpus), boost::end (corpus)); + } + + template + std::pair::type, typename boost::range_iterator::type> + boyer_moore_horspool_search ( CorpusRange &corpus, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + boyer_moore_horspool bmh ( boost::begin(pattern), boost::end (pattern)); + return bmh (boost::begin (corpus), boost::end (corpus)); + } + + + // Creator functions -- take a pattern range, return an object + template + boost::algorithm::boyer_moore_horspool::type> + make_boyer_moore_horspool ( const Range &r ) { + return boost::algorithm::boyer_moore_horspool + ::type> (boost::begin(r), boost::end(r)); + } + + template + boost::algorithm::boyer_moore_horspool::type> + make_boyer_moore_horspool ( Range &r ) { + return boost::algorithm::boyer_moore_horspool + ::type> (boost::begin(r), boost::end(r)); + } + +}} + +#endif // BOOST_ALGORITHM_BOYER_MOORE_HORSPOOOL_SEARCH_HPP diff --git a/third-party/boost/boost/algorithm/searching/detail/bm_traits.hpp b/third-party/boost/boost/algorithm/searching/detail/bm_traits.hpp new file mode 100644 index 000000000..12143636b --- /dev/null +++ b/third-party/boost/boost/algorithm/searching/detail/bm_traits.hpp @@ -0,0 +1,113 @@ +/* + Copyright (c) Marshall Clow 2010-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP +#define BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP + +#include // for CHAR_BIT +#include +#include // for std::iterator_traits + +#include +#include +#include +#include + +#include +#ifdef BOOST_NO_CXX11_HDR_UNORDERED_MAP +#include +#else +#include +#endif + +#include + +namespace boost { namespace algorithm { namespace detail { + +// +// Default implementations of the skip tables for B-M and B-M-H +// + template class skip_table; + +// General case for data searching other than bytes; use a map + template + class skip_table { + private: +#ifdef BOOST_NO_CXX11_HDR_UNORDERED_MAP + typedef boost::unordered_map skip_map; +#else + typedef std::unordered_map skip_map; +#endif + const value_type k_default_value; + skip_map skip_; + + public: + skip_table ( std::size_t patSize, value_type default_value ) + : k_default_value ( default_value ), skip_ ( patSize ) {} + + void insert ( key_type key, value_type val ) { + skip_ [ key ] = val; // Would skip_.insert (val) be better here? + } + + value_type operator [] ( key_type key ) const { + typename skip_map::const_iterator it = skip_.find ( key ); + return it == skip_.end () ? k_default_value : it->second; + } + + void PrintSkipTable () const { + std::cout << "BM(H) Skip Table :" << std::endl; + for ( typename skip_map::const_iterator it = skip_.begin (); it != skip_.end (); ++it ) + if ( it->second != k_default_value ) + std::cout << " " << it->first << ": " << it->second << std::endl; + std::cout << std::endl; + } + }; + + +// Special case small numeric values; use an array + template + class skip_table { + private: + typedef typename boost::make_unsigned::type unsigned_key_type; + typedef boost::array skip_map; + skip_map skip_; + const value_type k_default_value; + public: + skip_table ( std::size_t /*patSize*/, value_type default_value ) : k_default_value ( default_value ) { + std::fill_n ( skip_.begin(), skip_.size(), default_value ); + } + + void insert ( key_type key, value_type val ) { + skip_ [ static_cast ( key ) ] = val; + } + + value_type operator [] ( key_type key ) const { + return skip_ [ static_cast ( key ) ]; + } + + void PrintSkipTable () const { + std::cout << "BM(H) Skip Table :" << std::endl; + for ( typename skip_map::const_iterator it = skip_.begin (); it != skip_.end (); ++it ) + if ( *it != k_default_value ) + std::cout << " " << std::distance (skip_.begin (), it) << ": " << *it << std::endl; + std::cout << std::endl; + } + }; + + template + struct BM_traits { + typedef typename std::iterator_traits::difference_type value_type; + typedef typename std::iterator_traits::value_type key_type; + typedef boost::algorithm::detail::skip_table::value && (sizeof(key_type)==1)> skip_table_t; + }; + +}}} // namespaces + +#endif // BOOST_ALGORITHM_SEARCH_DETAIL_BM_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/searching/detail/debugging.hpp b/third-party/boost/boost/algorithm/searching/detail/debugging.hpp new file mode 100644 index 000000000..3996e0f50 --- /dev/null +++ b/third-party/boost/boost/algorithm/searching/detail/debugging.hpp @@ -0,0 +1,30 @@ +/* + Copyright (c) Marshall Clow 2010-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP +#define BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP + +#include +/// \cond DOXYGEN_HIDE + +namespace boost { namespace algorithm { namespace detail { + +// Debugging support + template + void PrintTable ( Iter first, Iter last ) { + std::cout << std::distance ( first, last ) << ": { "; + for ( Iter iter = first; iter != last; ++iter ) + std::cout << *iter << " "; + std::cout << "}" << std::endl; + } + +}}} +/// \endcond + +#endif // BOOST_ALGORITHM_SEARCH_DETAIL_DEBUG_HPP diff --git a/third-party/boost/boost/algorithm/searching/knuth_morris_pratt.hpp b/third-party/boost/boost/algorithm/searching/knuth_morris_pratt.hpp new file mode 100644 index 000000000..5b5b64a72 --- /dev/null +++ b/third-party/boost/boost/algorithm/searching/knuth_morris_pratt.hpp @@ -0,0 +1,263 @@ +/* + Copyright (c) Marshall Clow 2010-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP +#define BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP + +#include +#include // for std::iterator_traits + +#include +#include + +#include +#include + +#include +#include + +#include + +// #define BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_DEBUG + +namespace boost { namespace algorithm { + +// #define NEW_KMP + +/* + A templated version of the Knuth-Morris-Pratt searching algorithm. + + Requirements: + * Random-access iterators + * The two iterator types (I1 and I2) must "point to" the same underlying type. + + http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm + http://www.inf.fh-flensburg.de/lang/algorithmen/pattern/kmpen.htm +*/ + + template + class knuth_morris_pratt { + typedef typename std::iterator_traits::difference_type difference_type; + public: + knuth_morris_pratt ( patIter first, patIter last ) + : pat_first ( first ), pat_last ( last ), + k_pattern_length ( std::distance ( pat_first, pat_last )), + skip_ ( k_pattern_length + 1 ) { +#ifdef NEW_KMP + preKmp ( pat_first, pat_last ); +#else + init_skip_table ( pat_first, pat_last ); +#endif +#ifdef BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_DEBUG + detail::PrintTable ( skip_.begin (), skip_.end ()); +#endif + } + + ~knuth_morris_pratt () {} + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// \param p A predicate used for the search comparisons. + /// + template + std::pair + operator () ( corpusIter corpus_first, corpusIter corpus_last ) const { + BOOST_STATIC_ASSERT (( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); + + if ( corpus_first == corpus_last ) return std::make_pair(corpus_last, corpus_last); // if nothing to search, we didn't find it! + if ( pat_first == pat_last ) return std::make_pair(corpus_first, corpus_first); // empty pattern matches at start + + const difference_type k_corpus_length = std::distance ( corpus_first, corpus_last ); + // If the pattern is larger than the corpus, we can't find it! + if ( k_corpus_length < k_pattern_length ) + return std::make_pair(corpus_last, corpus_last); + + return do_search ( corpus_first, corpus_last, k_corpus_length ); + } + + template + std::pair::type, typename boost::range_iterator::type> + operator () ( Range &r ) const { + return (*this) (boost::begin(r), boost::end(r)); + } + + private: +/// \cond DOXYGEN_HIDE + patIter pat_first, pat_last; + const difference_type k_pattern_length; + std::vector skip_; + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// \param p A predicate used for the search comparisons. + /// + template + std::pair + do_search ( corpusIter corpus_first, corpusIter corpus_last, + difference_type k_corpus_length ) const { + difference_type match_start = 0; // position in the corpus that we're matching + +#ifdef NEW_KMP + int patternIdx = 0; + while ( match_start < k_corpus_length ) { + while ( patternIdx > -1 && pat_first[patternIdx] != corpus_first [match_start] ) + patternIdx = skip_ [patternIdx]; //<--- Shifting the pattern on mismatch + + patternIdx++; + match_start++; //<--- corpus is always increased by 1 + + if ( patternIdx >= (int) k_pattern_length ) + return corpus_first + match_start - patternIdx; + } + +#else +// At this point, we know: +// k_pattern_length <= k_corpus_length +// for all elements of skip, it holds -1 .. k_pattern_length +// +// In the loop, we have the following invariants +// idx is in the range 0 .. k_pattern_length +// match_start is in the range 0 .. k_corpus_length - k_pattern_length + 1 + + const difference_type last_match = k_corpus_length - k_pattern_length; + difference_type idx = 0; // position in the pattern we're comparing + + while ( match_start <= last_match ) { + while ( pat_first [ idx ] == corpus_first [ match_start + idx ] ) { + if ( ++idx == k_pattern_length ) + return std::make_pair(corpus_first + match_start, corpus_first + match_start + k_pattern_length); + } + // Figure out where to start searching again + // assert ( idx - skip_ [ idx ] > 0 ); // we're always moving forward + match_start += idx - skip_ [ idx ]; + idx = skip_ [ idx ] >= 0 ? skip_ [ idx ] : 0; + // assert ( idx >= 0 && idx < k_pattern_length ); + } +#endif + + // We didn't find anything + return std::make_pair(corpus_last, corpus_last); + } + + + void preKmp ( patIter first, patIter last ) { + const difference_type count = std::distance ( first, last ); + + difference_type i, j; + + i = 0; + j = skip_[0] = -1; + while (i < count) { + while (j > -1 && first[i] != first[j]) + j = skip_[j]; + i++; + j++; + if (first[i] == first[j]) + skip_[i] = skip_[j]; + else + skip_[i] = j; + } + } + + + void init_skip_table ( patIter first, patIter last ) { + const difference_type count = std::distance ( first, last ); + + difference_type j; + skip_ [ 0 ] = -1; + for ( int i = 1; i <= count; ++i ) { + j = skip_ [ i - 1 ]; + while ( j >= 0 ) { + if ( first [ j ] == first [ i - 1 ] ) + break; + j = skip_ [ j ]; + } + skip_ [ i ] = j + 1; + } + } +// \endcond + }; + + +/* Two ranges as inputs gives us four possibilities; with 2,3,3,4 parameters + Use a bit of TMP to disambiguate the 3-argument templates */ + +/// \fn knuth_morris_pratt_search ( corpusIter corpus_first, corpusIter corpus_last, +/// patIter pat_first, patIter pat_last ) +/// \brief Searches the corpus for the pattern. +/// +/// \param corpus_first The start of the data to search (Random Access Iterator) +/// \param corpus_last One past the end of the data to search +/// \param pat_first The start of the pattern to search for (Random Access Iterator) +/// \param pat_last One past the end of the data to search for +/// + template + std::pair knuth_morris_pratt_search ( + corpusIter corpus_first, corpusIter corpus_last, + patIter pat_first, patIter pat_last ) + { + knuth_morris_pratt kmp ( pat_first, pat_last ); + return kmp ( corpus_first, corpus_last ); + } + + template + std::pair knuth_morris_pratt_search ( + corpusIter corpus_first, corpusIter corpus_last, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + knuth_morris_pratt kmp ( boost::begin(pattern), boost::end (pattern)); + return kmp ( corpus_first, corpus_last ); + } + + template + typename boost::disable_if_c< + boost::is_same::value, + std::pair::type, typename boost::range_iterator::type> > + ::type + knuth_morris_pratt_search ( CorpusRange &corpus, patIter pat_first, patIter pat_last ) + { + knuth_morris_pratt kmp ( pat_first, pat_last ); + return kmp (boost::begin (corpus), boost::end (corpus)); + } + + template + std::pair::type, typename boost::range_iterator::type> + knuth_morris_pratt_search ( CorpusRange &corpus, const PatternRange &pattern ) + { + typedef typename boost::range_iterator::type pattern_iterator; + knuth_morris_pratt kmp ( boost::begin(pattern), boost::end (pattern)); + return kmp (boost::begin (corpus), boost::end (corpus)); + } + + + // Creator functions -- take a pattern range, return an object + template + boost::algorithm::knuth_morris_pratt::type> + make_knuth_morris_pratt ( const Range &r ) { + return boost::algorithm::knuth_morris_pratt + ::type> (boost::begin(r), boost::end(r)); + } + + template + boost::algorithm::knuth_morris_pratt::type> + make_knuth_morris_pratt ( Range &r ) { + return boost::algorithm::knuth_morris_pratt + ::type> (boost::begin(r), boost::end(r)); + } +}} + +#endif // BOOST_ALGORITHM_KNUTH_MORRIS_PRATT_SEARCH_HPP diff --git a/third-party/boost/boost/algorithm/sort_subrange.hpp b/third-party/boost/boost/algorithm/sort_subrange.hpp new file mode 100644 index 000000000..7fb2cb55d --- /dev/null +++ b/third-party/boost/boost/algorithm/sort_subrange.hpp @@ -0,0 +1,109 @@ +/* + Copyright (c) Marshall Clow 2008-2012. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Revision history: + 28 Sep 2015 mtc First version + +*/ + +/// \file sort_subrange.hpp +/// \brief Sort a subrange +/// \author Marshall Clow +/// +/// Suggested by Sean Parent in his CppCon 2015 keynote + +#ifndef BOOST_ALGORITHM_SORT_SUBRANGE_HPP +#define BOOST_ALGORITHM_SORT_SUBRANGE_HPP + +#include // For std::less +#include // For std::iterator_traits +#include // For nth_element and partial_sort + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn sort_subrange ( T const& val, +/// Iterator first, Iterator last, +/// Iterator sub_first, Iterator sub_last, +/// Pred p ) +/// \brief Sort the subrange [sub_first, sub_last) that is inside +/// the range [first, last) as if you had sorted the entire range. +/// +/// \param first The start of the larger range +/// \param last The end of the larger range +/// \param sub_first The start of the sub range +/// \param sub_last The end of the sub range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + void sort_subrange ( + Iterator first, Iterator last, + Iterator sub_first, Iterator sub_last, + Pred p) + { + if (sub_first == sub_last) return; // the empty sub-range is already sorted. + + if (sub_first != first) { // sub-range is at the start, don't need to partition + (void) std::nth_element(first, sub_first, last, p); + ++sub_first; + } + std::partial_sort(sub_first, sub_last, last, p); + } + + + + template + void sort_subrange (Iterator first, Iterator last, Iterator sub_first, Iterator sub_last) + { + typedef typename std::iterator_traits::value_type value_type; + return sort_subrange(first, last, sub_first, sub_last, std::less()); + } + +/// range versions? + + +/// \fn partition_subrange ( T const& val, +/// Iterator first, Iterator last, +/// Iterator sub_first, Iterator sub_last, +/// Pred p ) +/// \brief Gather the elements of the subrange [sub_first, sub_last) that is +/// inside the range [first, last) as if you had sorted the entire range. +/// +/// \param first The start of the larger range +/// \param last The end of the larger range +/// \param sub_first The start of the sub range +/// \param sub_last The end of the sub range +/// \param p A predicate to use to compare the values. +/// p ( a, b ) returns a boolean. +/// + template + void partition_subrange ( + Iterator first, Iterator last, + Iterator sub_first, Iterator sub_last, + Pred p) + { + if (sub_first != first) { + (void) std::nth_element(first, sub_first, last, p); + ++sub_first; + } + + if (sub_last != last) + (void) std::nth_element(sub_first, sub_last, last, p); + } + + template + void partition_subrange (Iterator first, Iterator last, Iterator sub_first, Iterator sub_last) + { + typedef typename std::iterator_traits::value_type value_type; + return partition_subrange(first, last, sub_first, sub_last, std::less()); + } + +}} + +#endif // BOOST_ALGORITHM_SORT_SUBRANGE_HPP diff --git a/third-party/boost/boost/algorithm/string.hpp b/third-party/boost/boost/algorithm/string.hpp new file mode 100644 index 000000000..077151739 --- /dev/null +++ b/third-party/boost/boost/algorithm/string.hpp @@ -0,0 +1,31 @@ +// Boost string_algo library string_algo.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ALGO_HPP +#define BOOST_STRING_ALGO_HPP + +/*! \file + Cumulative include for string_algo library +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#endif // BOOST_STRING_ALGO_HPP diff --git a/third-party/boost/boost/algorithm/string/case_conv.hpp b/third-party/boost/boost/algorithm/string/case_conv.hpp new file mode 100644 index 000000000..683340b8e --- /dev/null +++ b/third-party/boost/boost/algorithm/string/case_conv.hpp @@ -0,0 +1,176 @@ +// Boost string_algo library case_conv.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CASE_CONV_HPP +#define BOOST_STRING_CASE_CONV_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/*! \file + Defines sequence case-conversion algorithms. + Algorithms convert each element in the input sequence to the + desired case using provided locales. +*/ + +namespace boost { + namespace algorithm { + +// to_lower -----------------------------------------------// + + //! Convert to lower case + /*! + Each element of the input sequence is converted to lower + case. The result is a copy of the input converted to lower case. + It is returned as a sequence or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param Loc A locale used for conversion + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + + */ + template + inline OutputIteratorT + to_lower_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + + //! Convert to lower case + /*! + \overload + */ + template + inline SequenceT to_lower_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + + //! Convert to lower case + /*! + Each element of the input sequence is converted to lower + case. The input sequence is modified in-place. + + \param Input A range + \param Loc a locale used for conversion + */ + template + inline void to_lower( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_lowerF< + typename range_value::type >(Loc)); + } + +// to_upper -----------------------------------------------// + + //! Convert to upper case + /*! + Each element of the input sequence is converted to upper + case. The result is a copy of the input converted to upper case. + It is returned as a sequence or copied to the output iterator + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param Loc A locale used for conversion + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT + to_upper_copy( + OutputIteratorT Output, + const RangeT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Output, + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + //! Convert to upper case + /*! + \overload + */ + template + inline SequenceT to_upper_copy( + const SequenceT& Input, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::detail::transform_range_copy( + Input, + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + //! Convert to upper case + /*! + Each element of the input sequence is converted to upper + case. The input sequence is modified in-place. + + \param Input An input range + \param Loc a locale used for conversion + */ + template + inline void to_upper( + WritableRangeT& Input, + const std::locale& Loc=std::locale()) + { + ::boost::algorithm::detail::transform_range( + ::boost::as_literal(Input), + ::boost::algorithm::detail::to_upperF< + typename range_value::type >(Loc)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::to_lower; + using algorithm::to_lower_copy; + using algorithm::to_upper; + using algorithm::to_upper_copy; + +} // namespace boost + +#endif // BOOST_STRING_CASE_CONV_HPP diff --git a/third-party/boost/boost/algorithm/string/classification.hpp b/third-party/boost/boost/algorithm/string/classification.hpp new file mode 100644 index 000000000..ca43602d4 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/classification.hpp @@ -0,0 +1,312 @@ +// Boost string_algo library classification.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CLASSIFICATION_HPP +#define BOOST_STRING_CLASSIFICATION_HPP + +#include +#include +#include +#include +#include +#include + + +/*! \file + Classification predicates are included in the library to give + some more convenience when using algorithms like \c trim() and \c all(). + They wrap functionality of STL classification functions ( e.g. \c std::isspace() ) + into generic functors. +*/ + +namespace boost { + namespace algorithm { + +// classification functor generator -------------------------------------// + + //! is_classified predicate + /*! + Construct the \c is_classified predicate. This predicate holds if the input is + of specified \c std::ctype category. + + \param Type A \c std::ctype category + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(Type, Loc); + } + + //! is_space predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::space category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_space(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::space, Loc); + } + + //! is_alnum predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::alnum category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_alnum(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::alnum, Loc); + } + + //! is_alpha predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::alpha category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_alpha(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::alpha, Loc); + } + + //! is_cntrl predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::cntrl category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_cntrl(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::cntrl, Loc); + } + + //! is_digit predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::digit category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_digit(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::digit, Loc); + } + + //! is_graph predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::graph category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_graph(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::graph, Loc); + } + + //! is_lower predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::lower category. + + \param Loc A locale used for classification + \return An instance of \c is_classified predicate + */ + inline detail::is_classifiedF + is_lower(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::lower, Loc); + } + + //! is_print predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::print category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_print(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::print, Loc); + } + + //! is_punct predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::punct category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_punct(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::punct, Loc); + } + + //! is_upper predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::upper category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_upper(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::upper, Loc); + } + + //! is_xdigit predicate + /*! + Construct the \c is_classified predicate for the \c ctype_base::xdigit category. + + \param Loc A locale used for classification + \return An instance of the \c is_classified predicate + */ + inline detail::is_classifiedF + is_xdigit(const std::locale& Loc=std::locale()) + { + return detail::is_classifiedF(std::ctype_base::xdigit, Loc); + } + + //! is_any_of predicate + /*! + Construct the \c is_any_of predicate. The predicate holds if the input + is included in the specified set of characters. + + \param Set A set of characters to be recognized + \return An instance of the \c is_any_of predicate + */ + template + inline detail::is_any_ofF< + BOOST_STRING_TYPENAME range_value::type> + is_any_of( const RangeT& Set ) + { + iterator_range::type> lit_set(boost::as_literal(Set)); + return detail::is_any_ofF::type>(lit_set); + } + + //! is_from_range predicate + /*! + Construct the \c is_from_range predicate. The predicate holds if the input + is included in the specified range. (i.e. From <= Ch <= To ) + + \param From The start of the range + \param To The end of the range + \return An instance of the \c is_from_range predicate + */ + template + inline detail::is_from_rangeF is_from_range(CharT From, CharT To) + { + return detail::is_from_rangeF(From,To); + } + + // predicate combinators ---------------------------------------------------// + + //! predicate 'and' composition predicate + /*! + Construct the \c class_and predicate. This predicate can be used + to logically combine two classification predicates. \c class_and holds, + if both predicates return true. + + \param Pred1 The first predicate + \param Pred2 The second predicate + \return An instance of the \c class_and predicate + */ + template + inline detail::pred_andF + operator&&( + const predicate_facade& Pred1, + const predicate_facade& Pred2 ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_andF( + *static_cast(&Pred1), + *static_cast(&Pred2) ); + } + + //! predicate 'or' composition predicate + /*! + Construct the \c class_or predicate. This predicate can be used + to logically combine two classification predicates. \c class_or holds, + if one of the predicates return true. + + \param Pred1 The first predicate + \param Pred2 The second predicate + \return An instance of the \c class_or predicate + */ + template + inline detail::pred_orF + operator||( + const predicate_facade& Pred1, + const predicate_facade& Pred2 ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_orF( + *static_cast(&Pred1), + *static_cast(&Pred2)); + } + + //! predicate negation operator + /*! + Construct the \c class_not predicate. This predicate represents a negation. + \c class_or holds if of the predicates return false. + + \param Pred The predicate to be negated + \return An instance of the \c class_not predicate + */ + template + inline detail::pred_notF + operator!( const predicate_facade& Pred ) + { + // Doing the static_cast with the pointer instead of the reference + // is a workaround for some compilers which have problems with + // static_cast's of template references, i.e. CW8. /grafik/ + return detail::pred_notF(*static_cast(&Pred)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::is_classified; + using algorithm::is_space; + using algorithm::is_alnum; + using algorithm::is_alpha; + using algorithm::is_cntrl; + using algorithm::is_digit; + using algorithm::is_graph; + using algorithm::is_lower; + using algorithm::is_upper; + using algorithm::is_print; + using algorithm::is_punct; + using algorithm::is_xdigit; + using algorithm::is_any_of; + using algorithm::is_from_range; + +} // namespace boost + +#endif // BOOST_STRING_PREDICATE_HPP diff --git a/third-party/boost/boost/algorithm/string/compare.hpp b/third-party/boost/boost/algorithm/string/compare.hpp new file mode 100644 index 000000000..734303a9a --- /dev/null +++ b/third-party/boost/boost/algorithm/string/compare.hpp @@ -0,0 +1,199 @@ +// Boost string_algo library compare.hpp header file -------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_COMPARE_HPP +#define BOOST_STRING_COMPARE_HPP + +#include +#include + +/*! \file + Defines element comparison predicates. Many algorithms in this library can + take an additional argument with a predicate used to compare elements. + This makes it possible, for instance, to have case insensitive versions + of the algorithms. +*/ + +namespace boost { + namespace algorithm { + + // is_equal functor -----------------------------------------------// + + //! is_equal functor + /*! + Standard STL equal_to only handle comparison between arguments + of the same type. This is a less restrictive version which wraps operator ==. + */ + struct is_equal + { + //! Function operator + /*! + Compare two operands for equality + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1==Arg2; + } + }; + + //! case insensitive version of is_equal + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_iequal + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_iequal( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)==std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)==std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_less functor -----------------------------------------------// + + //! is_less functor + /*! + Convenient version of standard std::less. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_less + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1 + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)(Arg1,m_Loc)(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + // is_not_greater functor -----------------------------------------------// + + //! is_not_greater functor + /*! + Convenient version of standard std::not_greater_to. Operation is templated, therefore it is + not required to specify the exact types upon the construction + */ + struct is_not_greater + { + //! Functor operation + /*! + Compare two operands using > operator + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + return Arg1<=Arg2; + } + }; + + + //! case insensitive version of is_not_greater + /*! + Case insensitive comparison predicate. Comparison is done using + specified locales. + */ + struct is_not_igreater + { + //! Constructor + /*! + \param Loc locales used for comparison + */ + is_not_igreater( const std::locale& Loc=std::locale() ) : + m_Loc( Loc ) {} + + //! Function operator + /*! + Compare two operands. Case is ignored. + */ + template< typename T1, typename T2 > + bool operator()( const T1& Arg1, const T2& Arg2 ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper(Arg1)<=std::toupper(Arg2); + #else + return std::toupper(Arg1,m_Loc)<=std::toupper(Arg2,m_Loc); + #endif + } + + private: + std::locale m_Loc; + }; + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::is_equal; + using algorithm::is_iequal; + using algorithm::is_less; + using algorithm::is_iless; + using algorithm::is_not_greater; + using algorithm::is_not_igreater; + +} // namespace boost + + +#endif // BOOST_STRING_COMPARE_HPP diff --git a/third-party/boost/boost/algorithm/string/concept.hpp b/third-party/boost/boost/algorithm/string/concept.hpp new file mode 100644 index 000000000..17e834959 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/concept.hpp @@ -0,0 +1,83 @@ +// Boost string_algo library concept.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONCEPT_HPP +#define BOOST_STRING_CONCEPT_HPP + +#include +#include +#include +#include + +/*! \file + Defines concepts used in string_algo library +*/ + +namespace boost { + namespace algorithm { + + //! Finder concept + /*! + Defines the Finder concept. Finder is a functor which selects + an arbitrary part of a string. Search is performed on + the range specified by starting and ending iterators. + + Result of the find operation must be convertible to iterator_range. + */ + template + struct FinderConcept + { + private: + typedef iterator_range range; + public: + void constraints() + { + // Operation + r=(*pF)(i,i); + } + private: + range r; + IteratorT i; + FinderT* pF; + }; // Finder_concept + + + //! Formatter concept + /*! + Defines the Formatter concept. Formatter is a functor, which + takes a result from a finder operation and transforms it + in a specific way. + + Result must be a container supported by container_traits, + or a reference to it. + */ + template + struct FormatterConcept + { + public: + void constraints() + { + // Operation + ::boost::begin((*pFo)( (*pF)(i,i) )); + ::boost::end((*pFo)( (*pF)(i,i) )); + } + private: + IteratorT i; + FinderT* pF; + FormatterT *pFo; + }; // FormatterConcept; + + } // namespace algorithm +} // namespace boost + + + + +#endif // BOOST_STRING_CONCEPT_HPP diff --git a/third-party/boost/boost/algorithm/string/config.hpp b/third-party/boost/boost/algorithm/string/config.hpp new file mode 100644 index 000000000..559750ac8 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/config.hpp @@ -0,0 +1,28 @@ +// Boost string_algo library config.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONFIG_HPP +#define BOOST_STRING_CONFIG_HPP + +#include +#include + +#ifdef BOOST_STRING_DEDUCED_TYPENAME +# error "macro already defined!" +#endif + +#define BOOST_STRING_TYPENAME BOOST_DEDUCED_TYPENAME + +// Metrowerks workaround +#if BOOST_WORKAROUND(__MWERKS__, <= 0x3003) // 8.x +#pragma parse_func_templ off +#endif + +#endif // BOOST_STRING_CONFIG_HPP diff --git a/third-party/boost/boost/algorithm/string/constants.hpp b/third-party/boost/boost/algorithm/string/constants.hpp new file mode 100644 index 000000000..6ed70effc --- /dev/null +++ b/third-party/boost/boost/algorithm/string/constants.hpp @@ -0,0 +1,36 @@ +// Boost string_algo library constants.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CONSTANTS_HPP +#define BOOST_STRING_CONSTANTS_HPP + +namespace boost { + namespace algorithm { + + //! Token compression mode + /*! + Specifies token compression mode for the token_finder. + */ + enum token_compress_mode_type + { + token_compress_on, //!< Compress adjacent tokens + token_compress_off //!< Do not compress adjacent tokens + }; + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::token_compress_on; + using algorithm::token_compress_off; + +} // namespace boost + +#endif // BOOST_STRING_CONSTANTS_HPP + diff --git a/third-party/boost/boost/algorithm/string/detail/case_conv.hpp b/third-party/boost/boost/algorithm/string/detail/case_conv.hpp new file mode 100644 index 000000000..233912ca0 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/case_conv.hpp @@ -0,0 +1,127 @@ +// Boost string_algo library string_funct.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CASE_CONV_DETAIL_HPP +#define BOOST_STRING_CASE_CONV_DETAIL_HPP + +#include +#include +#include + +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// case conversion functors -----------------------------------------------// + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#endif + + // a tolower functor + template + struct to_lowerF + { + typedef CharT argument_type; + typedef CharT result_type; + // Constructor + to_lowerF( const std::locale& Loc ) : m_Loc( &Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::tolower( static_cast::type> ( Ch )); + #else + return std::tolower( Ch, *m_Loc ); + #endif + } + private: + const std::locale* m_Loc; + }; + + // a toupper functor + template + struct to_upperF + { + typedef CharT argument_type; + typedef CharT result_type; + // Constructor + to_upperF( const std::locale& Loc ) : m_Loc( &Loc ) {} + + // Operation + CharT operator ()( CharT Ch ) const + { + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x564) && !defined(_USE_OLD_RW_STL) + return std::toupper( static_cast::type> ( Ch )); + #else + return std::toupper( Ch, *m_Loc ); + #endif + } + private: + const std::locale* m_Loc; + }; + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + +// algorithm implementation ------------------------------------------------------------------------- + + // Transform a range + template + OutputIteratorT transform_range_copy( + OutputIteratorT Output, + const RangeT& Input, + FunctorT Functor) + { + return std::transform( + ::boost::begin(Input), + ::boost::end(Input), + Output, + Functor); + } + + // Transform a range (in-place) + template + void transform_range( + const RangeT& Input, + FunctorT Functor) + { + std::transform( + ::boost::begin(Input), + ::boost::end(Input), + ::boost::begin(Input), + Functor); + } + + template + inline SequenceT transform_range_copy( + const RangeT& Input, + FunctorT Functor) + { + return SequenceT( + ::boost::make_transform_iterator( + ::boost::begin(Input), + Functor), + ::boost::make_transform_iterator( + ::boost::end(Input), + Functor)); + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CASE_CONV_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/classification.hpp b/third-party/boost/boost/algorithm/string/detail/classification.hpp new file mode 100644 index 000000000..704d9d20f --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/classification.hpp @@ -0,0 +1,353 @@ +// Boost string_algo library classification.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP +#define BOOST_STRING_CLASSIFICATION_DETAIL_HPP + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// classification functors -----------------------------------------------// + + // is_classified functor + struct is_classifiedF : + public predicate_facade + { + // Boost.ResultOf support + typedef bool result_type; + + // Constructor from a locale + is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) : + m_Type(Type), m_Locale(Loc) {} + // Operation + template + bool operator()( CharT Ch ) const + { + return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch ); + } + + #if defined(__BORLANDC__) && (__BORLANDC__ >= 0x560) && (__BORLANDC__ <= 0x582) && !defined(_USE_OLD_RW_STL) + template<> + bool operator()( char const Ch ) const + { + return std::use_facet< std::ctype >(m_Locale).is( m_Type, Ch ); + } + #endif + + private: + std::ctype_base::mask m_Type; + std::locale m_Locale; + }; + + + // is_any_of functor + /* + returns true if the value is from the specified set + */ + template + struct is_any_ofF : + public predicate_facade > + { + private: + // set cannot operate on const value-type + typedef typename ::boost::remove_const::type set_value_type; + + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + template + is_any_ofF( const RangeT& Range ) : m_Size(0) + { + // Prepare storage + m_Storage.m_dynSet=0; + + std::size_t Size=::boost::distance(Range); + m_Size=Size; + set_value_type* Storage=0; + + if(use_fixed_storage(m_Size)) + { + // Use fixed storage + Storage=&m_Storage.m_fixSet[0]; + } + else + { + // Use dynamic storage + m_Storage.m_dynSet=new set_value_type[m_Size]; + Storage=m_Storage.m_dynSet; + } + + // Use fixed storage + ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage); + ::std::sort(Storage, Storage+m_Size); + } + + // Copy constructor + is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size) + { + // Prepare storage + m_Storage.m_dynSet=0; + const set_value_type* SrcStorage=0; + set_value_type* DestStorage=0; + + if(use_fixed_storage(m_Size)) + { + // Use fixed storage + DestStorage=&m_Storage.m_fixSet[0]; + SrcStorage=&Other.m_Storage.m_fixSet[0]; + } + else + { + // Use dynamic storage + m_Storage.m_dynSet=new set_value_type[m_Size]; + DestStorage=m_Storage.m_dynSet; + SrcStorage=Other.m_Storage.m_dynSet; + } + + // Use fixed storage + ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size); + } + + // Destructor + ~is_any_ofF() + { + if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) + { + delete [] m_Storage.m_dynSet; + } + } + + // Assignment + is_any_ofF& operator=(const is_any_ofF& Other) + { + // Handle self assignment + if(this==&Other) return *this; + + // Prepare storage + const set_value_type* SrcStorage; + set_value_type* DestStorage; + + if(use_fixed_storage(Other.m_Size)) + { + // Use fixed storage + DestStorage=&m_Storage.m_fixSet[0]; + SrcStorage=&Other.m_Storage.m_fixSet[0]; + + // Delete old storage if was present + if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0) + { + delete [] m_Storage.m_dynSet; + } + + // Set new size + m_Size=Other.m_Size; + } + else + { + // Other uses dynamic storage + SrcStorage=Other.m_Storage.m_dynSet; + + // Check what kind of storage are we using right now + if(use_fixed_storage(m_Size)) + { + // Using fixed storage, allocate new + set_value_type* pTemp=new set_value_type[Other.m_Size]; + DestStorage=pTemp; + m_Storage.m_dynSet=pTemp; + m_Size=Other.m_Size; + } + else + { + // Using dynamic storage, check if can reuse + if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size + bool operator()( Char2T Ch ) const + { + const set_value_type* Storage= + (use_fixed_storage(m_Size)) + ? &m_Storage.m_fixSet[0] + : m_Storage.m_dynSet; + + return ::std::binary_search(Storage, Storage+m_Size, Ch); + } + private: + // check if the size is eligible for fixed storage + static bool use_fixed_storage(std::size_t size) + { + return size<=sizeof(set_value_type*)*2; + } + + + private: + // storage + // The actual used storage is selected on the type + union + { + set_value_type* m_dynSet; + set_value_type m_fixSet[sizeof(set_value_type*)*2]; + } + m_Storage; + + // storage size + ::std::size_t m_Size; + }; + + // is_from_range functor + /* + returns true if the value is from the specified range. + (i.e. x>=From && x>=To) + */ + template + struct is_from_rangeF : + public predicate_facade< is_from_rangeF > + { + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {} + + // Operation + template + bool operator()( Char2T Ch ) const + { + return ( m_From <= Ch ) && ( Ch <= m_To ); + } + + private: + CharT m_From; + CharT m_To; + }; + + // class_and composition predicate + template + struct pred_andF : + public predicate_facade< pred_andF > + { + public: + + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_andF( Pred1T Pred1, Pred2T Pred2 ) : + m_Pred1(Pred1), m_Pred2(Pred2) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return m_Pred1(Ch) && m_Pred2(Ch); + } + + private: + Pred1T m_Pred1; + Pred2T m_Pred2; + }; + + // class_or composition predicate + template + struct pred_orF : + public predicate_facade< pred_orF > + { + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_orF( Pred1T Pred1, Pred2T Pred2 ) : + m_Pred1(Pred1), m_Pred2(Pred2) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return m_Pred1(Ch) || m_Pred2(Ch); + } + + private: + Pred1T m_Pred1; + Pred2T m_Pred2; + }; + + // class_not composition predicate + template< typename PredT > + struct pred_notF : + public predicate_facade< pred_notF > + { + public: + // Boost.ResultOf support + typedef bool result_type; + + // Constructor + pred_notF( PredT Pred ) : m_Pred(Pred) {} + + // Operation + template + bool operator()( CharT Ch ) const + { + return !m_Pred(Ch); + } + + private: + PredT m_Pred; + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/find_format.hpp b/third-party/boost/boost/algorithm/string/detail/find_format.hpp new file mode 100644 index 000000000..b39875024 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/find_format.hpp @@ -0,0 +1,204 @@ +// Boost string_algo library find_format.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_DETAIL_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_copy (iterator variant) implementation -------------------------------// + + template< + typename OutputIteratorT, + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline OutputIteratorT find_format_copy_impl2( + OutputIteratorT Output, + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult ) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_const_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Match not found - return original sequence + Output = std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + return Output; + } + + // Copy the beginning of the sequence + Output = std::copy( ::boost::begin(Input), ::boost::begin(M), Output ); + // Format find result + // Copy formatted result + Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output ); + // Copy the rest of the sequence + Output = std::copy( M.end(), ::boost::end(Input), Output ); + + return Output; + } + + template< + typename OutputIteratorT, + typename InputT, + typename FormatterT, + typename FindResultT > + inline OutputIteratorT find_format_copy_impl( + OutputIteratorT Output, + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult ) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_copy_impl2( + Output, + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + } + } + + +// find_format_copy implementation --------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline InputT find_format_copy_impl2( + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_const_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Match not found - return original sequence + return InputT( Input ); + } + + InputT Output; + // Copy the beginning of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), ::boost::begin(Input), M.begin() ); + // Copy formatted result + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() ); + // Copy the rest of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.end(), ::boost::end(Input) ); + + return Output; + } + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline InputT find_format_copy_impl( + const InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_copy_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return Input; + } + } + + // replace implementation ----------------------------------------------------// + + template< + typename InputT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline void find_format_impl2( + InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef find_format_store< + BOOST_STRING_TYPENAME + range_iterator::type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + if ( !M ) + { + // Search not found - return original sequence + return; + } + + // Replace match + ::boost::algorithm::detail::replace( Input, M.begin(), M.end(), M.format_result() ); + } + + template< + typename InputT, + typename FormatterT, + typename FindResultT > + inline void find_format_impl( + InputT& Input, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + ::boost::algorithm::detail::find_format_impl2( + Input, + Formatter, + FindResult, + Formatter(FindResult) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/find_format_all.hpp b/third-party/boost/boost/algorithm/string/detail/find_format_all.hpp new file mode 100644 index 000000000..52930c83a --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/find_format_all.hpp @@ -0,0 +1,273 @@ +// Boost string_algo library find_format_all.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_format_all_copy (iterator variant) implementation ---------------------------// + + template< + typename OutputIteratorT, + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline OutputIteratorT find_format_all_copy_impl2( + OutputIteratorT Output, + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult ) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Initialize last match + input_iterator_type LastMatch=::boost::begin(Input); + + // Iterate through all matches + while( M ) + { + // Copy the beginning of the sequence + Output = std::copy( LastMatch, M.begin(), Output ); + // Copy formatted result + Output = std::copy( ::boost::begin(M.format_result()), ::boost::end(M.format_result()), Output ); + + // Proceed to the next match + LastMatch=M.end(); + M=Finder( LastMatch, ::boost::end(Input) ); + } + + // Copy the rest of the sequence + Output = std::copy( LastMatch, ::boost::end(Input), Output ); + + return Output; + } + + template< + typename OutputIteratorT, + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline OutputIteratorT find_format_all_copy_impl( + OutputIteratorT Output, + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult ) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_all_copy_impl2( + Output, + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return std::copy( ::boost::begin(Input), ::boost::end(Input), Output ); + } + } + + // find_format_all_copy implementation ----------------------------------------------// + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline InputT find_format_all_copy_impl2( + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult, + const FormatResultT& FormatResult) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Initialize last match + input_iterator_type LastMatch=::boost::begin(Input); + + // Output temporary + InputT Output; + + // Iterate through all matches + while( M ) + { + // Copy the beginning of the sequence + boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, M.begin() ); + // Copy formatted result + boost::algorithm::detail::insert( Output, ::boost::end(Output), M.format_result() ); + + // Proceed to the next match + LastMatch=M.end(); + M=Finder( LastMatch, ::boost::end(Input) ); + } + + // Copy the rest of the sequence + ::boost::algorithm::detail::insert( Output, ::boost::end(Output), LastMatch, ::boost::end(Input) ); + + return Output; + } + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline InputT find_format_all_copy_impl( + const InputT& Input, + FinderT Finder, + FormatterT Formatter, + const FindResultT& FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + return ::boost::algorithm::detail::find_format_all_copy_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } else { + return Input; + } + } + + // find_format_all implementation ------------------------------------------------// + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT, + typename FormatResultT > + inline void find_format_all_impl2( + InputT& Input, + FinderT Finder, + FormatterT Formatter, + FindResultT FindResult, + FormatResultT FormatResult) + { + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef find_format_store< + input_iterator_type, + FormatterT, + FormatResultT > store_type; + + // Create store for the find result + store_type M( FindResult, FormatResult, Formatter ); + + // Instantiate replacement storage + std::deque< + BOOST_STRING_TYPENAME range_value::type> Storage; + + // Initialize replacement iterators + input_iterator_type InsertIt=::boost::begin(Input); + input_iterator_type SearchIt=::boost::begin(Input); + + while( M ) + { + // process the segment + InsertIt=process_segment( + Storage, + Input, + InsertIt, + SearchIt, + M.begin() ); + + // Adjust search iterator + SearchIt=M.end(); + + // Copy formatted replace to the storage + ::boost::algorithm::detail::copy_to_storage( Storage, M.format_result() ); + + // Find range for a next match + M=Finder( SearchIt, ::boost::end(Input) ); + } + + // process the last segment + InsertIt=::boost::algorithm::detail::process_segment( + Storage, + Input, + InsertIt, + SearchIt, + ::boost::end(Input) ); + + if ( Storage.empty() ) + { + // Truncate input + ::boost::algorithm::detail::erase( Input, InsertIt, ::boost::end(Input) ); + } + else + { + // Copy remaining data to the end of input + ::boost::algorithm::detail::insert( Input, ::boost::end(Input), Storage.begin(), Storage.end() ); + } + } + + template< + typename InputT, + typename FinderT, + typename FormatterT, + typename FindResultT > + inline void find_format_all_impl( + InputT& Input, + FinderT Finder, + FormatterT Formatter, + FindResultT FindResult) + { + if( ::boost::algorithm::detail::check_find_result(Input, FindResult) ) { + ::boost::algorithm::detail::find_format_all_impl2( + Input, + Finder, + Formatter, + FindResult, + Formatter(FindResult) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_ALL_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/find_format_store.hpp b/third-party/boost/boost/algorithm/string/detail/find_format_store.hpp new file mode 100644 index 000000000..b9f4a88d9 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/find_format_store.hpp @@ -0,0 +1,89 @@ +// Boost string_algo library find_format_store.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP +#define BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// temporary format and find result storage --------------------------------// + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(push) +#pragma warning(disable:4512) //assignment operator could not be generated +#endif + template< + typename ForwardIteratorT, + typename FormatterT, + typename FormatResultT > + class find_format_store : + public iterator_range + { + public: + // typedefs + typedef iterator_range base_type; + typedef FormatterT formatter_type; + typedef FormatResultT format_result_type; + + public: + // Construction + find_format_store( + const base_type& FindResult, + const format_result_type& FormatResult, + const formatter_type& Formatter ) : + base_type(FindResult), + m_FormatResult(FormatResult), + m_Formatter(Formatter) {} + + // Assignment + template< typename FindResultT > + find_format_store& operator=( FindResultT FindResult ) + { + iterator_range::operator=(FindResult); + if( !this->empty() ) { + m_FormatResult=m_Formatter(FindResult); + } + + return *this; + } + + // Retrieve format result + const format_result_type& format_result() + { + return m_FormatResult; + } + + private: + format_result_type m_FormatResult; + const formatter_type& m_Formatter; + }; + + template + bool check_find_result(InputT&, FindResultT& FindResult) + { + typedef BOOST_STRING_TYPENAME + range_const_iterator::type input_iterator_type; + iterator_range ResultRange(FindResult); + return !ResultRange.empty(); + } + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +#pragma warning(pop) +#endif + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_FORMAT_STORE_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/find_iterator.hpp b/third-party/boost/boost/algorithm/string/detail/find_iterator.hpp new file mode 100644 index 000000000..4f90a98fc --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/find_iterator.hpp @@ -0,0 +1,87 @@ +// Boost string_algo library find_iterator.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_ITERATOR_DETAIL_HPP +#define BOOST_STRING_FIND_ITERATOR_DETAIL_HPP + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// find_iterator base -----------------------------------------------// + + // Find iterator base + template + class find_iterator_base + { + protected: + // typedefs + typedef IteratorT input_iterator_type; + typedef iterator_range match_type; + typedef function2< + match_type, + input_iterator_type, + input_iterator_type> finder_type; + + protected: + // Protected construction/destruction + + // Default constructor + find_iterator_base() {} + // Copy construction + find_iterator_base( const find_iterator_base& Other ) : + m_Finder(Other.m_Finder) {} + + // Constructor + template + find_iterator_base( FinderT Finder, int ) : + m_Finder(Finder) {} + + // Destructor + ~find_iterator_base() {} + + // Find operation + match_type do_find( + input_iterator_type Begin, + input_iterator_type End ) const + { + if (!m_Finder.empty()) + { + return m_Finder(Begin,End); + } + else + { + return match_type(End,End); + } + } + + // Check + bool is_null() const + { + return m_Finder.empty(); + } + + private: + // Finder + finder_type m_Finder; + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_FIND_ITERATOR_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/finder.hpp b/third-party/boost/boost/algorithm/string/detail/finder.hpp new file mode 100644 index 000000000..a2a958212 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/finder.hpp @@ -0,0 +1,639 @@ +// Boost string_algo library finder.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FINDER_DETAIL_HPP +#define BOOST_STRING_FINDER_DETAIL_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + + +// find first functor -----------------------------------------------// + + // find a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, functor returns + */ + template + struct first_finderF + { + typedef SearchIteratorT search_iterator_type; + + // Construction + template< typename SearchT > + first_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + first_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=Begin; + OuterIt!=End; + ++OuterIt) + { + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + input_iterator_type InnerIt=OuterIt; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if ( SubstrIt==m_Search.end() ) + return result_type( OuterIt, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find last functor -----------------------------------------------// + + // find the last match a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct last_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + + // Construction + template< typename SearchT > + last_finderF( const SearchT& Search, PredicateT Comp ) : + m_Search(::boost::begin(Search), ::boost::end(Search)), m_Comp(Comp) {} + last_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + PredicateT Comp ) : + m_Search(SearchBegin, SearchEnd), m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + if( boost::empty(m_Search) ) + return result_type( End, End ); + + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return findit( Begin, End, category() ); + } + + private: + // forward iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::forward_iterator_tag ) const + { + typedef iterator_range result_type; + + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M=first_finder( Begin, End ); + result_type Last=M; + + while( M ) + { + Last=M; + M=first_finder( ::boost::end(M), End ); + } + + return Last; + } + + // bidirectional iterator + template< typename ForwardIteratorT > + iterator_range + findit( + ForwardIteratorT Begin, + ForwardIteratorT End, + std::bidirectional_iterator_tag ) const + { + typedef iterator_range result_type; + typedef ForwardIteratorT input_iterator_type; + + // Outer loop + for(input_iterator_type OuterIt=End; + OuterIt!=Begin; ) + { + input_iterator_type OuterIt2=--OuterIt; + + input_iterator_type InnerIt=OuterIt2; + search_iterator_type SubstrIt=m_Search.begin(); + for(; + InnerIt!=End && SubstrIt!=m_Search.end(); + ++InnerIt,++SubstrIt) + { + if( !( m_Comp(*InnerIt,*SubstrIt) ) ) + break; + } + + // Substring matching succeeded + if( SubstrIt==m_Search.end() ) + return result_type( OuterIt2, InnerIt ); + } + + return result_type( End, End ); + } + + private: + iterator_range m_Search; + PredicateT m_Comp; + }; + +// find n-th functor -----------------------------------------------// + + // find the n-th match of a subsequence in the sequence ( functor ) + /* + Returns a pair marking the subsequence in the sequence. + If the find fails, returns + */ + template + struct nth_finderF + { + typedef SearchIteratorT search_iterator_type; + typedef first_finderF< + search_iterator_type, + PredicateT> first_finder_type; + typedef last_finderF< + search_iterator_type, + PredicateT> last_finder_type; + + // Construction + template< typename SearchT > + nth_finderF( + const SearchT& Search, + int Nth, + PredicateT Comp) : + m_Search(::boost::begin(Search), ::boost::end(Search)), + m_Nth(Nth), + m_Comp(Comp) {} + nth_finderF( + search_iterator_type SearchBegin, + search_iterator_type SearchEnd, + int Nth, + PredicateT Comp) : + m_Search(SearchBegin, SearchEnd), + m_Nth(Nth), + m_Comp(Comp) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_Nth>=0) + { + return find_forward(Begin, End, m_Nth); + } + else + { + return find_backward(Begin, End, -m_Nth); + } + + } + + private: + // Implementation helpers + template< typename ForwardIteratorT > + iterator_range + find_forward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + first_finder_type first_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( Begin, Begin ); + + for( unsigned int n=0; n<=N; ++n ) + { + // find next match + M=first_finder( ::boost::end(M), End ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + template< typename ForwardIteratorT > + iterator_range + find_backward( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N) const + { + typedef iterator_range result_type; + + // Sanity check + if( boost::empty(m_Search) ) + return result_type( End, End ); + + // Instantiate find functor + last_finder_type last_finder( + m_Search.begin(), m_Search.end(), m_Comp ); + + result_type M( End, End ); + + for( unsigned int n=1; n<=N; ++n ) + { + // find next match + M=last_finder( Begin, ::boost::begin(M) ); + + if ( !M ) + { + // Subsequence not found, return + return M; + } + } + + return M; + } + + + private: + iterator_range m_Search; + int m_Nth; + PredicateT m_Comp; + }; + +// find head/tail implementation helpers ---------------------------// + + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=Begin; + for( + unsigned int Index=0; + Index + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type(Begin,Begin+N); + } + + // Find head implementation + template + iterator_range + find_head_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::find_head_impl( Begin, End, N, category() ); + } + + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::forward_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + unsigned int Index=0; + input_iterator_type It=Begin; + input_iterator_type It2=Begin; + + // Advance It2 by N increments + for( Index=0; Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::bidirectional_iterator_tag ) + { + typedef ForwardIteratorT input_iterator_type; + typedef iterator_range result_type; + + input_iterator_type It=End; + for( + unsigned int Index=0; + Index + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N, + std::random_access_iterator_tag ) + { + typedef iterator_range result_type; + + if ( (End<=Begin) || ( static_cast(End-Begin) < N ) ) + return result_type( Begin, End ); + + return result_type( End-N, End ); + } + + // Operation + template< typename ForwardIteratorT > + iterator_range + find_tail_impl( + ForwardIteratorT Begin, + ForwardIteratorT End, + unsigned int N ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::find_tail_impl( Begin, End, N, category() ); + } + + + +// find head functor -----------------------------------------------// + + + // find a head in the sequence ( functor ) + /* + This functor find a head of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct head_finderF + { + // Construction + head_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return ::boost::algorithm::detail::find_head_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + ::boost::algorithm::detail::find_tail_impl( Begin, End, -m_N ); + + return ::boost::make_iterator_range(Begin, Res.begin()); + } + } + + private: + int m_N; + }; + +// find tail functor -----------------------------------------------// + + + // find a tail in the sequence ( functor ) + /* + This functor find a tail of the specified range. For + a specified N, the head is a subsequence of N starting + elements of the range. + */ + struct tail_finderF + { + // Construction + tail_finderF( int N ) : m_N(N) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + if(m_N>=0) + { + return ::boost::algorithm::detail::find_tail_impl( Begin, End, m_N ); + } + else + { + iterator_range Res= + ::boost::algorithm::detail::find_head_impl( Begin, End, -m_N ); + + return ::boost::make_iterator_range(Res.end(), End); + } + } + + private: + int m_N; + }; + +// find token functor -----------------------------------------------// + + // find a token in a sequence ( functor ) + /* + This find functor finds a token specified be a predicate + in a sequence. It is equivalent of std::find algorithm, + with an exception that it return range instead of a single + iterator. + + If bCompress is set to true, adjacent matching tokens are + concatenated into one match. + */ + template< typename PredicateT > + struct token_finderF + { + // Construction + token_finderF( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) : + m_Pred(Pred), m_eCompress(eCompress) {} + + // Operation + template< typename ForwardIteratorT > + iterator_range + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef iterator_range result_type; + + ForwardIteratorT It=std::find_if( Begin, End, m_Pred ); + + if( It==End ) + { + return result_type( End, End ); + } + else + { + ForwardIteratorT It2=It; + + if( m_eCompress==token_compress_on ) + { + // Find first non-matching character + while( It2!=End && m_Pred(*It2) ) ++It2; + } + else + { + // Advance by one position + ++It2; + } + + return result_type( It, It2 ); + } + } + + private: + PredicateT m_Pred; + token_compress_mode_type m_eCompress; + }; + +// find range functor -----------------------------------------------// + + // find a range in the sequence ( functor ) + /* + This functor actually does not perform any find operation. + It always returns given iterator range as a result. + */ + template + struct range_finderF + { + typedef ForwardIterator1T input_iterator_type; + typedef iterator_range result_type; + + // Construction + range_finderF( + input_iterator_type Begin, + input_iterator_type End ) : m_Range(Begin, End) {} + + range_finderF(const iterator_range& Range) : + m_Range(Range) {} + + // Operation + template< typename ForwardIterator2T > + iterator_range + operator()( + ForwardIterator2T, + ForwardIterator2T ) const + { +#if BOOST_WORKAROUND( __MWERKS__, <= 0x3003 ) + return iterator_range(this->m_Range); +#else + return m_Range; +#endif + } + + private: + iterator_range m_Range; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FINDER_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/finder_regex.hpp b/third-party/boost/boost/algorithm/string/detail/finder_regex.hpp new file mode 100644 index 000000000..9cb01cfaf --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/finder_regex.hpp @@ -0,0 +1,122 @@ +// Boost string_algo library find_regex.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FINDER_REGEX_DETAIL_HPP +#define BOOST_STRING_FINDER_REGEX_DETAIL_HPP + +#include +#include + +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// regex find functor -----------------------------------------------// + + // regex search result + template + struct regex_search_result : + public iterator_range + { + typedef regex_search_result type; + typedef iterator_range base_type; + typedef BOOST_STRING_TYPENAME base_type::value_type value_type; + typedef BOOST_STRING_TYPENAME base_type::difference_type difference_type; + typedef BOOST_STRING_TYPENAME base_type::const_iterator const_iterator; + typedef BOOST_STRING_TYPENAME base_type::iterator iterator; + typedef boost::match_results match_results_type; + + // Construction + + // Construction from the match result + regex_search_result( const match_results_type& MatchResults ) : + base_type( MatchResults[0].first, MatchResults[0].second ), + m_MatchResults( MatchResults ) {} + + // Construction of empty match. End iterator has to be specified + regex_search_result( IteratorT End ) : + base_type( End, End ) {} + + regex_search_result( const regex_search_result& Other ) : + base_type( Other.begin(), Other.end() ), + m_MatchResults( Other.m_MatchResults ) {} + + // Assignment + regex_search_result& operator=( const regex_search_result& Other ) + { + base_type::operator=( Other ); + m_MatchResults=Other.m_MatchResults; + return *this; + } + + // Match result retrieval + const match_results_type& match_results() const + { + return m_MatchResults; + } + + private: + // Saved match result + match_results_type m_MatchResults; + }; + + // find_regex + /* + Regex based search functor + */ + template + struct find_regexF + { + typedef RegExT regex_type; + typedef const RegExT& regex_reference_type; + + // Construction + find_regexF( regex_reference_type Rx, match_flag_type MatchFlags = match_default ) : + m_Rx(Rx), m_MatchFlags(MatchFlags) {} + + // Operation + template< typename ForwardIteratorT > + regex_search_result + operator()( + ForwardIteratorT Begin, + ForwardIteratorT End ) const + { + typedef ForwardIteratorT input_iterator_type; + typedef regex_search_result result_type; + + // instantiate match result + match_results result; + // search for a match + if ( ::boost::regex_search( Begin, End, result, m_Rx, m_MatchFlags ) ) + { + // construct a result + return result_type( result ); + } + else + { + // empty result + return result_type( End ); + } + } + + private: + regex_reference_type m_Rx; // Regexp + match_flag_type m_MatchFlags; // match flags + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FIND_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/formatter.hpp b/third-party/boost/boost/algorithm/string/detail/formatter.hpp new file mode 100644 index 000000000..c071822f2 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/formatter.hpp @@ -0,0 +1,119 @@ +// Boost string_algo library formatter.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FORMATTER_DETAIL_HPP +#define BOOST_STRING_FORMATTER_DETAIL_HPP + + +#include +#include +#include +#include + +#include + +// generic replace functors -----------------------------------------------// + +namespace boost { + namespace algorithm { + namespace detail { + +// const format functor ----------------------------------------------------// + + // constant format functor + template + struct const_formatF + { + private: + typedef BOOST_STRING_TYPENAME + range_const_iterator::type format_iterator; + typedef iterator_range result_type; + + public: + // Construction + const_formatF(const RangeT& Format) : + m_Format(::boost::begin(Format), ::boost::end(Format)) {} + + // Operation +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + template + result_type& operator()(const Range2T&) + { + return m_Format; + } +#endif + + template + const result_type& operator()(const Range2T&) const + { + return m_Format; + } + + private: + result_type m_Format; + }; + +// identity format functor ----------------------------------------------------// + + // identity format functor + template + struct identity_formatF + { + // Operation + template< typename Range2T > + const RangeT& operator()(const Range2T& Replace) const + { + return RangeT(::boost::begin(Replace), ::boost::end(Replace)); + } + }; + +// empty format functor ( used by erase ) ------------------------------------// + + // empty format functor + template< typename CharT > + struct empty_formatF + { + template< typename ReplaceT > + empty_container operator()(const ReplaceT&) const + { + return empty_container(); + } + }; + +// dissect format functor ----------------------------------------------------// + + // dissect format functor + template + struct dissect_formatF + { + public: + // Construction + dissect_formatF(FinderT Finder) : + m_Finder(Finder) {} + + // Operation + template + inline iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> + operator()(const RangeT& Replace) const + { + return m_Finder(::boost::begin(Replace), ::boost::end(Replace)); + } + + private: + FinderT m_Finder; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FORMATTER_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/formatter_regex.hpp b/third-party/boost/boost/algorithm/string/detail/formatter_regex.hpp new file mode 100644 index 000000000..5f26407be --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/formatter_regex.hpp @@ -0,0 +1,61 @@ +// Boost string_algo library formatter_regex.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FORMATTER_REGEX_DETAIL_HPP +#define BOOST_STRING_FORMATTER_REGEX_DETAIL_HPP + +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// regex format functor -----------------------------------------// + + // regex format functor + template + struct regex_formatF + { + private: + typedef StringT result_type; + typedef BOOST_STRING_TYPENAME StringT::value_type char_type; + + public: + // Construction + regex_formatF( const StringT& Fmt, match_flag_type Flags=format_default ) : + m_Fmt(Fmt), m_Flags( Flags ) {} + + template + result_type operator()( + const regex_search_result& Replace ) const + { + if ( Replace.empty() ) + { + return result_type(); + } + else + { + return Replace.match_results().format( m_Fmt, m_Flags ); + } + } + private: + const StringT& m_Fmt; + match_flag_type m_Flags; + }; + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_FORMATTER_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/predicate.hpp b/third-party/boost/boost/algorithm/string/detail/predicate.hpp new file mode 100644 index 000000000..5acf3cc66 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/predicate.hpp @@ -0,0 +1,77 @@ +// Boost string_algo library predicate.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_PREDICATE_DETAIL_HPP +#define BOOST_STRING_PREDICATE_DETAIL_HPP + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// ends_with predicate implementation ----------------------------------// + + template< + typename ForwardIterator1T, + typename ForwardIterator2T, + typename PredicateT> + inline bool ends_with_iter_select( + ForwardIterator1T Begin, + ForwardIterator1T End, + ForwardIterator2T SubBegin, + ForwardIterator2T SubEnd, + PredicateT Comp, + std::bidirectional_iterator_tag) + { + ForwardIterator1T it=End; + ForwardIterator2T pit=SubEnd; + for(;it!=Begin && pit!=SubBegin;) + { + if( !(Comp(*(--it),*(--pit))) ) + return false; + } + + return pit==SubBegin; + } + + template< + typename ForwardIterator1T, + typename ForwardIterator2T, + typename PredicateT> + inline bool ends_with_iter_select( + ForwardIterator1T Begin, + ForwardIterator1T End, + ForwardIterator2T SubBegin, + ForwardIterator2T SubEnd, + PredicateT Comp, + std::forward_iterator_tag) + { + if ( SubBegin==SubEnd ) + { + // empty subsequence check + return true; + } + + iterator_range Result + =last_finder( + ::boost::make_iterator_range(SubBegin, SubEnd), + Comp)(Begin, End); + + return !Result.empty() && Result.end()==End; + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_PREDICATE_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/replace_storage.hpp b/third-party/boost/boost/algorithm/string/detail/replace_storage.hpp new file mode 100644 index 000000000..db35e4c53 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/replace_storage.hpp @@ -0,0 +1,159 @@ +// Boost string_algo library replace_storage.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP +#define BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP + +#include +#include +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// storage handling routines -----------------------------------------------// + + template< typename StorageT, typename OutputIteratorT > + inline OutputIteratorT move_from_storage( + StorageT& Storage, + OutputIteratorT DestBegin, + OutputIteratorT DestEnd ) + { + OutputIteratorT OutputIt=DestBegin; + + while( !Storage.empty() && OutputIt!=DestEnd ) + { + *OutputIt=Storage.front(); + Storage.pop_front(); + ++OutputIt; + } + + return OutputIt; + } + + template< typename StorageT, typename WhatT > + inline void copy_to_storage( + StorageT& Storage, + const WhatT& What ) + { + Storage.insert( Storage.end(), ::boost::begin(What), ::boost::end(What) ); + } + + +// process segment routine -----------------------------------------------// + + template< bool HasStableIterators > + struct process_segment_helper + { + // Optimized version of process_segment for generic sequence + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + ForwardIteratorT operator()( + StorageT& Storage, + InputT& /*Input*/, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + { + // Copy data from the storage until the beginning of the segment + ForwardIteratorT It=::boost::algorithm::detail::move_from_storage( Storage, InsertIt, SegmentBegin ); + + // 3 cases are possible : + // a) Storage is empty, It==SegmentBegin + // b) Storage is empty, It!=SegmentBegin + // c) Storage is not empty + + if( Storage.empty() ) + { + if( It==SegmentBegin ) + { + // Case a) everything is grand, just return end of segment + return SegmentEnd; + } + else + { + // Case b) move the segment backwards + return std::copy( SegmentBegin, SegmentEnd, It ); + } + } + else + { + // Case c) -> shift the segment to the left and keep the overlap in the storage + while( It!=SegmentEnd ) + { + // Store value into storage + Storage.push_back( *It ); + // Get the top from the storage and put it here + *It=Storage.front(); + Storage.pop_front(); + + // Advance + ++It; + } + + return It; + } + } + }; + + template<> + struct process_segment_helper< true > + { + // Optimized version of process_segment for list-like sequence + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + ForwardIteratorT operator()( + StorageT& Storage, + InputT& Input, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + + { + // Call replace to do the job + ::boost::algorithm::detail::replace( Input, InsertIt, SegmentBegin, Storage ); + // Empty the storage + Storage.clear(); + // Iterators were not changed, simply return the end of segment + return SegmentEnd; + } + }; + + // Process one segment in the replace_all algorithm + template< + typename StorageT, + typename InputT, + typename ForwardIteratorT > + inline ForwardIteratorT process_segment( + StorageT& Storage, + InputT& Input, + ForwardIteratorT InsertIt, + ForwardIteratorT SegmentBegin, + ForwardIteratorT SegmentEnd ) + { + return + process_segment_helper< + has_stable_iterators::value>()( + Storage, Input, InsertIt, SegmentBegin, SegmentEnd ); + } + + + } // namespace detail + } // namespace algorithm +} // namespace boost + +#endif // BOOST_STRING_REPLACE_STORAGE_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/sequence.hpp b/third-party/boost/boost/algorithm/string/detail/sequence.hpp new file mode 100644 index 000000000..dc4740911 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/sequence.hpp @@ -0,0 +1,200 @@ +// Boost string_algo library sequence.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_DETAIL_SEQUENCE_HPP +#define BOOST_STRING_DETAIL_SEQUENCE_HPP + +#include +#include +#include +#include +#include + +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// insert helpers -------------------------------------------------// + + template< typename InputT, typename ForwardIteratorT > + inline void insert( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator At, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + Input.insert( At, Begin, End ); + } + + template< typename InputT, typename InsertT > + inline void insert( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator At, + const InsertT& Insert ) + { + ::boost::algorithm::detail::insert( Input, At, ::boost::begin(Insert), ::boost::end(Insert) ); + } + +// erase helper ---------------------------------------------------// + + // Erase a range in the sequence + /* + Returns the iterator pointing just after the erase subrange + */ + template< typename InputT > + inline typename InputT::iterator erase( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To ) + { + return Input.erase( From, To ); + } + +// replace helper implementation ----------------------------------// + + // Optimized version of replace for generic sequence containers + // Assumption: insert and erase are expensive + template< bool HasConstTimeOperations > + struct replace_const_time_helper + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + // Copy data to the container ( as much as possible ) + ForwardIteratorT InsertIt=Begin; + BOOST_STRING_TYPENAME InputT::iterator InputIt=From; + for(; InsertIt!=End && InputIt!=To; InsertIt++, InputIt++ ) + { + *InputIt=*InsertIt; + } + + if ( InsertIt!=End ) + { + // Replace sequence is longer, insert it + Input.insert( InputIt, InsertIt, End ); + } + else + { + if ( InputIt!=To ) + { + // Replace sequence is shorter, erase the rest + Input.erase( InputIt, To ); + } + } + } + }; + + template<> + struct replace_const_time_helper< true > + { + // Const-time erase and insert methods -> use them + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + BOOST_STRING_TYPENAME InputT::iterator At=Input.erase( From, To ); + if ( Begin!=End ) + { + if(!Input.empty()) + { + Input.insert( At, Begin, End ); + } + else + { + Input.insert( Input.begin(), Begin, End ); + } + } + } + }; + + // No native replace method + template< bool HasNative > + struct replace_native_helper + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + replace_const_time_helper< + boost::mpl::and_< + has_const_time_insert, + has_const_time_erase >::value >()( + Input, From, To, Begin, End ); + } + }; + + // Container has native replace method + template<> + struct replace_native_helper< true > + { + template< typename InputT, typename ForwardIteratorT > + void operator()( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + Input.replace( From, To, Begin, End ); + } + }; + +// replace helper -------------------------------------------------// + + template< typename InputT, typename ForwardIteratorT > + inline void replace( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + replace_native_helper< has_native_replace::value >()( + Input, From, To, Begin, End ); + } + + template< typename InputT, typename InsertT > + inline void replace( + InputT& Input, + BOOST_STRING_TYPENAME InputT::iterator From, + BOOST_STRING_TYPENAME InputT::iterator To, + const InsertT& Insert ) + { + if(From!=To) + { + ::boost::algorithm::detail::replace( Input, From, To, ::boost::begin(Insert), ::boost::end(Insert) ); + } + else + { + ::boost::algorithm::detail::insert( Input, From, ::boost::begin(Insert), ::boost::end(Insert) ); + } + } + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_DETAIL_SEQUENCE_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/trim.hpp b/third-party/boost/boost/algorithm/string/detail/trim.hpp new file mode 100644 index 000000000..1233e49d3 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/trim.hpp @@ -0,0 +1,95 @@ +// Boost string_algo library trim.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_TRIM_DETAIL_HPP +#define BOOST_STRING_TRIM_DETAIL_HPP + +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// trim iterator helper -----------------------------------------------// + + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end_iter_select( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace, + std::forward_iterator_tag ) + { + ForwardIteratorT TrimIt=InBegin; + + for( ForwardIteratorT It=InBegin; It!=InEnd; ++It ) + { + if ( !IsSpace(*It) ) + { + TrimIt=It; + ++TrimIt; + } + } + + return TrimIt; + } + + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end_iter_select( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace, + std::bidirectional_iterator_tag ) + { + for( ForwardIteratorT It=InEnd; It!=InBegin; ) + { + if ( !IsSpace(*(--It)) ) + return ++It; + } + + return InBegin; + } + // Search for first non matching character from the beginning of the sequence + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_begin( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace ) + { + ForwardIteratorT It=InBegin; + for(; It!=InEnd; ++It ) + { + if (!IsSpace(*It)) + return It; + } + + return It; + } + + // Search for first non matching character from the end of the sequence + template< typename ForwardIteratorT, typename PredicateT > + inline ForwardIteratorT trim_end( + ForwardIteratorT InBegin, + ForwardIteratorT InEnd, + PredicateT IsSpace ) + { + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return ::boost::algorithm::detail::trim_end_iter_select( InBegin, InEnd, IsSpace, category() ); + } + + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_TRIM_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/detail/util.hpp b/third-party/boost/boost/algorithm/string/detail/util.hpp new file mode 100644 index 000000000..7844b6723 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/detail/util.hpp @@ -0,0 +1,107 @@ +// Boost string_algo library util.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_UTIL_DETAIL_HPP +#define BOOST_STRING_UTIL_DETAIL_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + namespace detail { + +// empty container -----------------------------------------------// + + // empty_container + /* + This class represents always empty container, + containing elements of type CharT. + + It is supposed to be used in a const version only + */ + template< typename CharT > + struct empty_container + { + typedef empty_container type; + typedef CharT value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef const value_type& reference; + typedef const value_type& const_reference; + typedef const value_type* iterator; + typedef const value_type* const_iterator; + + + // Operations + const_iterator begin() const + { + return reinterpret_cast(0); + } + + const_iterator end() const + { + return reinterpret_cast(0); + } + + bool empty() const + { + return false; + } + + size_type size() const + { + return 0; + } + }; + +// bounded copy algorithm -----------------------------------------------// + + // Bounded version of the std::copy algorithm + template + inline OutputIteratorT bounded_copy( + InputIteratorT First, + InputIteratorT Last, + OutputIteratorT DestFirst, + OutputIteratorT DestLast ) + { + InputIteratorT InputIt=First; + OutputIteratorT OutputIt=DestFirst; + for(; InputIt!=Last && OutputIt!=DestLast; InputIt++, OutputIt++ ) + { + *OutputIt=*InputIt; + } + + return OutputIt; + } + +// iterator range utilities -----------------------------------------// + + // copy range functor + template< + typename SeqT, + typename IteratorT=BOOST_STRING_TYPENAME SeqT::const_iterator > + struct copy_iterator_rangeF + { + typedef iterator_range argument_type; + typedef SeqT result_type; + SeqT operator()( const iterator_range& Range ) const + { + return copy_range(Range); + } + }; + + } // namespace detail + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_UTIL_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/erase.hpp b/third-party/boost/boost/algorithm/string/erase.hpp new file mode 100644 index 000000000..688379097 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/erase.hpp @@ -0,0 +1,844 @@ +// Boost string_algo library erase.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ERASE_HPP +#define BOOST_STRING_ERASE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines various erase algorithms. Each algorithm removes + part(s) of the input according to a searching criteria. +*/ + +namespace boost { + namespace algorithm { + +// erase_range -------------------------------------------------------// + + //! Erase range algorithm + /*! + Remove the given range from the input. The result is a modified copy of + the input. It is returned as a sequence or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param SearchRange A range in the input to be removed + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT erase_range_copy( + OutputIteratorT Output, + const RangeT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase range algorithm + /*! + \overload + */ + template + inline SequenceT erase_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase range algorithm + /*! + Remove the given range from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param SearchRange A range in the input to be removed + */ + template + inline void erase_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_first --------------------------------------------------------// + + //! Erase first algorithm + /*! + Remove the first occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm + /*! + \overload + */ + template + inline SequenceT erase_first_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm + /*! + Remove the first occurrence of the substring from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + */ + template + inline void erase_first( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_first ( case insensitive ) ------------------------------------// + + //! Erase first algorithm ( case insensitive ) + /*! + Remove the first occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_first_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase first algorithm ( case insensitive ) + /*! + Remove the first occurrence of the substring from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_first( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_last --------------------------------------------------------// + + //! Erase last algorithm + /*! + Remove the last occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm + /*! + \overload + */ + template + inline SequenceT erase_last_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm + /*! + Remove the last occurrence of the substring from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + */ + template + inline void erase_last( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_last ( case insensitive ) ------------------------------------// + + //! Erase last algorithm ( case insensitive ) + /*! + Remove the last occurrence of the substring from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_last_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase last algorithm ( case insensitive ) + /*! + Remove the last occurrence of the substring from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_last( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_nth --------------------------------------------------------------------// + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT erase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + */ + template + inline void erase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_nth ( case insensitive ) ---------------------------------------------// + + //! Erase nth algorithm ( case insensitive ) + /*! + Remove the Nth occurrence of the substring in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + \overload + */ + template + inline SequenceT ierase_nth_copy( + const SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + empty_formatter(Input) ); + } + + //! Erase nth algorithm + /*! + Remove the Nth occurrence of the substring in the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for. + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_nth( + SequenceT& Input, + const RangeT& Search, + int Nth, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + +// erase_all --------------------------------------------------------// + + //! Erase all algorithm + /*! + Remove all the occurrences of the string from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Search A substring to be searched for. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT erase_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm + /*! + \overload + */ + template + inline SequenceT erase_all_copy( + const SequenceT& Input, + const RangeT& Search ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm + /*! + Remove all the occurrences of the string from the input. + The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for. + */ + template + inline void erase_all( + SequenceT& Input, + const RangeT& Search ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_all ( case insensitive ) ------------------------------------// + + //! Erase all algorithm ( case insensitive ) + /*! + Remove all the occurrences of the string from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT ierase_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ierase_all_copy( + const SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + + //! Erase all algorithm ( case insensitive ) + /*! + Remove all the occurrences of the string from the input. + The input sequence is modified in-place. Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + */ + template + inline void ierase_all( + SequenceT& Input, + const RangeT& Search, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::empty_formatter(Input) ); + } + +// erase_head --------------------------------------------------------------------// + + //! Erase head algorithm + /*! + Remove the head from the input. The head is a prefix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The result is a modified copy of the input. + It is returned as a sequence or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT> + inline OutputIteratorT erase_head_copy( + OutputIteratorT Output, + const RangeT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase head algorithm + /*! + \overload + */ + template + inline SequenceT erase_head_copy( + const SequenceT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase head algorithm + /*! + Remove the head from the input. The head is a prefix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the head + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + */ + template + inline void erase_head( + SequenceT& Input, + int N ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + +// erase_tail --------------------------------------------------------------------// + + //! Erase tail algorithm + /*! + Remove the tail from the input. The tail is a suffix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT> + inline OutputIteratorT erase_tail_copy( + OutputIteratorT Output, + const RangeT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase tail algorithm + /*! + \overload + */ + template + inline SequenceT erase_tail_copy( + const SequenceT& Input, + int N ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase tail algorithm + /*! + Remove the tail from the input. The tail is a suffix of a sequence of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the tail + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + */ + template + inline void erase_tail( + SequenceT& Input, + int N ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::empty_formatter( Input ) ); + } + + } // namespace algorithm + + // pull names into the boost namespace + using algorithm::erase_range_copy; + using algorithm::erase_range; + using algorithm::erase_first_copy; + using algorithm::erase_first; + using algorithm::ierase_first_copy; + using algorithm::ierase_first; + using algorithm::erase_last_copy; + using algorithm::erase_last; + using algorithm::ierase_last_copy; + using algorithm::ierase_last; + using algorithm::erase_nth_copy; + using algorithm::erase_nth; + using algorithm::ierase_nth_copy; + using algorithm::ierase_nth; + using algorithm::erase_all_copy; + using algorithm::erase_all; + using algorithm::ierase_all_copy; + using algorithm::ierase_all; + using algorithm::erase_head_copy; + using algorithm::erase_head; + using algorithm::erase_tail_copy; + using algorithm::erase_tail; + +} // namespace boost + + +#endif // BOOST_ERASE_HPP diff --git a/third-party/boost/boost/algorithm/string/find.hpp b/third-party/boost/boost/algorithm/string/find.hpp new file mode 100644 index 000000000..f2c2926b5 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/find.hpp @@ -0,0 +1,334 @@ +// Boost string_algo library find.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_HPP +#define BOOST_STRING_FIND_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines a set of find algorithms. The algorithms are searching + for a substring of the input. The result is given as an \c iterator_range + delimiting the substring. +*/ + +namespace boost { + namespace algorithm { + +// Generic find -----------------------------------------------// + + //! Generic find algorithm + /*! + Search the input using the given finder. + + \param Input A string which will be searched. + \param Finder Finder object used for searching. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c RangeT::iterator or + \c RangeT::const_iterator, depending on the constness of + the input parameter. + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find( + RangeT& Input, + const FinderT& Finder) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return Finder(::boost::begin(lit_input),::boost::end(lit_input)); + } + +// find_first -----------------------------------------------// + + //! Find first algorithm + /*! + Search for the first occurrence of the substring in the input. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c RangeT::iterator or + \c RangeT::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_first( + Range1T& Input, + const Range2T& Search) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search)); + } + + //! Find first algorithm ( case insensitive ) + /*! + Search for the first occurrence of the substring in the input. + Searching is case insensitive. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + ifind_first( + Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::first_finder(Search,is_iequal(Loc))); + } + +// find_last -----------------------------------------------// + + //! Find last algorithm + /*! + Search for the last occurrence of the substring in the input. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_last( + Range1T& Input, + const Range2T& Search) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search)); + } + + //! Find last algorithm ( case insensitive ) + /*! + Search for the last match a string in the input. + Searching is case insensitive. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + ifind_last( + Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::last_finder(Search, is_iequal(Loc))); + } + +// find_nth ----------------------------------------------------------------------// + + //! Find n-th algorithm + /*! + Search for the n-th (zero-indexed) occurrence of the substring in the + input. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \param Nth An index (zero-indexed) of the match to be found. + For negative N, the matches are counted from the end of string. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_nth( + Range1T& Input, + const Range2T& Search, + int Nth) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth)); + } + + //! Find n-th algorithm ( case insensitive ). + /*! + Search for the n-th (zero-indexed) occurrence of the substring in the + input. Searching is case insensitive. + + \param Input A string which will be searched. + \param Search A substring to be searched for. + \param Nth An index (zero-indexed) of the match to be found. + For negative N, the matches are counted from the end of string. + \param Loc A locale used for case insensitive comparison + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + ifind_nth( + Range1T& Input, + const Range2T& Search, + int Nth, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::nth_finder(Search,Nth,is_iequal(Loc))); + } + +// find_head ----------------------------------------------------------------------// + + //! Find head algorithm + /*! + Get the head of the input. Head is a prefix of the string of the + given size. If the input is shorter then required, whole input is considered + to be the head. + + \param Input An input string + \param N Length of the head + For N>=0, at most N characters are extracted. + For N<0, at most size(Input)-|N| characters are extracted. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c Range1T::iterator or + \c Range1T::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_head( + RangeT& Input, + int N) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::head_finder(N)); + } + +// find_tail ----------------------------------------------------------------------// + + //! Find tail algorithm + /*! + Get the tail of the input. Tail is a suffix of the string of the + given size. If the input is shorter then required, whole input is considered + to be the tail. + + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, at most size(Input)-|N| characters are extracted. + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c RangeT::iterator or + \c RangeT::const_iterator, depending on the constness of + the input parameter. + + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_tail( + RangeT& Input, + int N) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::tail_finder(N)); + } + +// find_token --------------------------------------------------------------------// + + //! Find token algorithm + /*! + Look for a given token in the string. Token is a character that matches the + given predicate. + If the "token compress mode" is enabled, adjacent tokens are considered to be one match. + + \param Input A input string. + \param Pred A unary predicate to identify a token + \param eCompress Enable/Disable compressing of adjacent tokens + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c RangeT::iterator or + \c RangeT::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type> + find_token( + RangeT& Input, + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off) + { + return ::boost::algorithm::find(Input, ::boost::algorithm::token_finder(Pred, eCompress)); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::find; + using algorithm::find_first; + using algorithm::ifind_first; + using algorithm::find_last; + using algorithm::ifind_last; + using algorithm::find_nth; + using algorithm::ifind_nth; + using algorithm::find_head; + using algorithm::find_tail; + using algorithm::find_token; + +} // namespace boost + + +#endif // BOOST_STRING_FIND_HPP diff --git a/third-party/boost/boost/algorithm/string/find_format.hpp b/third-party/boost/boost/algorithm/string/find_format.hpp new file mode 100644 index 000000000..0e84a4ee6 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/find_format.hpp @@ -0,0 +1,287 @@ +// Boost string_algo library find_format.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_FORMAT_HPP +#define BOOST_STRING_FIND_FORMAT_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines generic replace algorithms. Each algorithm replaces + part(s) of the input. The part to be replaced is looked up using a Finder object. + Result of finding is then used by a Formatter object to generate the replacement. +*/ + +namespace boost { + namespace algorithm { + +// generic replace -----------------------------------------------------------------// + + //! Generic replace algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename FinderT, + typename FormatterT> + inline OutputIteratorT find_format_copy( + OutputIteratorT Output, + const RangeT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return detail::find_format_copy_impl( + Output, + lit_input, + Formatter, + Finder( ::boost::begin(lit_input), ::boost::end(lit_input) ) ); + } + + //! Generic replace algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT> + inline SequenceT find_format_copy( + const SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + return detail::find_format_copy_impl( + Input, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + } + + //! Generic replace algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. The input is modified in-place. + + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT> + inline void find_format( + SequenceT& Input, + FinderT Finder, + FormatterT Formatter) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + detail::find_format_impl( + Input, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + } + + +// find_format_all generic ----------------------------------------------------------------// + + //! Generic replace all algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. Repeat this for all matching + substrings. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename FinderT, + typename FormatterT> + inline OutputIteratorT find_format_all_copy( + OutputIteratorT Output, + const RangeT& Input, + FinderT Finder, + FormatterT Formatter) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return detail::find_format_all_copy_impl( + Output, + lit_input, + Finder, + Formatter, + Finder(::boost::begin(lit_input), ::boost::end(lit_input))); + } + + //! Generic replace all algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT > + inline SequenceT find_format_all_copy( + const SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + return detail::find_format_all_copy_impl( + Input, + Finder, + Formatter, + Finder( ::boost::begin(Input), ::boost::end(Input) ) ); + } + + //! Generic replace all algorithm + /*! + Use the Finder to search for a substring. Use the Formatter to format + this substring and replace it in the input. Repeat this for all matching + substrings.The input is modified in-place. + + \param Input An input sequence + \param Finder A Finder object used to search for a match to be replaced + \param Formatter A Formatter object used to format a match + */ + template< + typename SequenceT, + typename FinderT, + typename FormatterT > + inline void find_format_all( + SequenceT& Input, + FinderT Finder, + FormatterT Formatter ) + { + // Concept check + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_const_iterator::type> + )); + BOOST_CONCEPT_ASSERT(( + FormatterConcept< + FormatterT, + FinderT,BOOST_STRING_TYPENAME range_const_iterator::type> + )); + + detail::find_format_all_impl( + Input, + Finder, + Formatter, + Finder(::boost::begin(Input), ::boost::end(Input))); + + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::find_format_copy; + using algorithm::find_format; + using algorithm::find_format_all_copy; + using algorithm::find_format_all; + +} // namespace boost + + +#endif // BOOST_STRING_FIND_FORMAT_HPP diff --git a/third-party/boost/boost/algorithm/string/find_iterator.hpp b/third-party/boost/boost/algorithm/string/find_iterator.hpp new file mode 100644 index 000000000..5a52d92e4 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/find_iterator.hpp @@ -0,0 +1,388 @@ +// Boost string_algo library find_iterator.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FIND_ITERATOR_HPP +#define BOOST_STRING_FIND_ITERATOR_HPP + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/*! \file + Defines find iterator classes. Find iterator repeatedly applies a Finder + to the specified input string to search for matches. Dereferencing + the iterator yields the current match or a range between the last and the current + match depending on the iterator used. +*/ + +namespace boost { + namespace algorithm { + +// find_iterator -----------------------------------------------// + + //! find_iterator + /*! + Find iterator encapsulates a Finder and allows + for incremental searching in a string. + Each increment moves the iterator to the next match. + + Find iterator is a readable forward traversal iterator. + + Dereferencing the iterator yields an iterator_range delimiting + the current match. + */ + template + class find_iterator : + public iterator_facade< + find_iterator, + const iterator_range, + forward_traversal_tag >, + private detail::find_iterator_base + { + private: + // facade support + friend class ::boost::iterator_core_access; + + private: + // typedefs + + typedef detail::find_iterator_base base_type; + typedef BOOST_STRING_TYPENAME + base_type::input_iterator_type input_iterator_type; + typedef BOOST_STRING_TYPENAME + base_type::match_type match_type; + + public: + //! Default constructor + /*! + Construct null iterator. All null iterators are equal. + + \post eof()==true + */ + find_iterator() {} + + //! Copy constructor + /*! + Construct a copy of the find_iterator + */ + find_iterator( const find_iterator& Other ) : + base_type(Other), + m_Match(Other.m_Match), + m_End(Other.m_End) {} + + //! Constructor + /*! + Construct new find_iterator for a given finder + and a range. + */ + template + find_iterator( + IteratorT Begin, + IteratorT End, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_Match(Begin,Begin), + m_End(End) + { + increment(); + } + + //! Constructor + /*! + Construct new find_iterator for a given finder + and a range. + */ + template + find_iterator( + RangeT& Col, + FinderT Finder ) : + detail::find_iterator_base(Finder,0) + { + iterator_range::type> lit_col(::boost::as_literal(Col)); + m_Match=::boost::make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col)); + m_End=::boost::end(lit_col); + + increment(); + } + + private: + // iterator operations + + // dereference + const match_type& dereference() const + { + return m_Match; + } + + // increment + void increment() + { + m_Match=this->do_find(m_Match.end(),m_End); + } + + // comparison + bool equal( const find_iterator& Other ) const + { + bool bEof=eof(); + bool bOtherEof=Other.eof(); + + return bEof || bOtherEof ? bEof==bOtherEof : + ( + m_Match==Other.m_Match && + m_End==Other.m_End + ); + } + + public: + // operations + + //! Eof check + /*! + Check the eof condition. Eof condition means that + there is nothing more to be searched i.e. find_iterator + is after the last match. + */ + bool eof() const + { + return + this->is_null() || + ( + m_Match.begin() == m_End && + m_Match.end() == m_End + ); + } + + private: + // Attributes + match_type m_Match; + input_iterator_type m_End; + }; + + //! find iterator construction helper + /*! + * Construct a find iterator to iterate through the specified string + */ + template + inline find_iterator< + BOOST_STRING_TYPENAME range_iterator::type> + make_find_iterator( + RangeT& Collection, + FinderT Finder) + { + return find_iterator::type>( + Collection, Finder); + } + +// split iterator -----------------------------------------------// + + //! split_iterator + /*! + Split iterator encapsulates a Finder and allows + for incremental searching in a string. + Unlike the find iterator, split iterator iterates + through gaps between matches. + + Find iterator is a readable forward traversal iterator. + + Dereferencing the iterator yields an iterator_range delimiting + the current match. + */ + template + class split_iterator : + public iterator_facade< + split_iterator, + const iterator_range, + forward_traversal_tag >, + private detail::find_iterator_base + { + private: + // facade support + friend class ::boost::iterator_core_access; + + private: + // typedefs + + typedef detail::find_iterator_base base_type; + typedef BOOST_STRING_TYPENAME + base_type::input_iterator_type input_iterator_type; + typedef BOOST_STRING_TYPENAME + base_type::match_type match_type; + + public: + //! Default constructor + /*! + Construct null iterator. All null iterators are equal. + + \post eof()==true + */ + split_iterator() : + m_Next(), + m_End(), + m_bEof(true) + {} + + //! Copy constructor + /*! + Construct a copy of the split_iterator + */ + split_iterator( const split_iterator& Other ) : + base_type(Other), + m_Match(Other.m_Match), + m_Next(Other.m_Next), + m_End(Other.m_End), + m_bEof(Other.m_bEof) + {} + + //! Constructor + /*! + Construct new split_iterator for a given finder + and a range. + */ + template + split_iterator( + IteratorT Begin, + IteratorT End, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_Match(Begin,Begin), + m_Next(Begin), + m_End(End), + m_bEof(false) + { + // force the correct behavior for empty sequences and yield at least one token + if(Begin!=End) + { + increment(); + } + } + //! Constructor + /*! + Construct new split_iterator for a given finder + and a collection. + */ + template + split_iterator( + RangeT& Col, + FinderT Finder ) : + detail::find_iterator_base(Finder,0), + m_bEof(false) + { + iterator_range::type> lit_col(::boost::as_literal(Col)); + m_Match=make_iterator_range(::boost::begin(lit_col), ::boost::begin(lit_col)); + m_Next=::boost::begin(lit_col); + m_End=::boost::end(lit_col); + + // force the correct behavior for empty sequences and yield at least one token + if(m_Next!=m_End) + { + increment(); + } + } + + + private: + // iterator operations + + // dereference + const match_type& dereference() const + { + return m_Match; + } + + // increment + void increment() + { + match_type FindMatch=this->do_find( m_Next, m_End ); + + if(FindMatch.begin()==m_End && FindMatch.end()==m_End) + { + if(m_Match.end()==m_End) + { + // Mark iterator as eof + m_bEof=true; + } + } + + m_Match=match_type( m_Next, FindMatch.begin() ); + m_Next=FindMatch.end(); + } + + // comparison + bool equal( const split_iterator& Other ) const + { + bool bEof=eof(); + bool bOtherEof=Other.eof(); + + return bEof || bOtherEof ? bEof==bOtherEof : + ( + m_Match==Other.m_Match && + m_Next==Other.m_Next && + m_End==Other.m_End + ); + } + + public: + // operations + + //! Eof check + /*! + Check the eof condition. Eof condition means that + there is nothing more to be searched i.e. find_iterator + is after the last match. + */ + bool eof() const + { + return this->is_null() || m_bEof; + } + + private: + // Attributes + match_type m_Match; + input_iterator_type m_Next; + input_iterator_type m_End; + bool m_bEof; + }; + + //! split iterator construction helper + /*! + * Construct a split iterator to iterate through the specified collection + */ + template + inline split_iterator< + BOOST_STRING_TYPENAME range_iterator::type> + make_split_iterator( + RangeT& Collection, + FinderT Finder) + { + return split_iterator::type>( + Collection, Finder); + } + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::find_iterator; + using algorithm::make_find_iterator; + using algorithm::split_iterator; + using algorithm::make_split_iterator; + +} // namespace boost + + +#endif // BOOST_STRING_FIND_ITERATOR_HPP diff --git a/third-party/boost/boost/algorithm/string/finder.hpp b/third-party/boost/boost/algorithm/string/finder.hpp new file mode 100644 index 000000000..61f6e4155 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/finder.hpp @@ -0,0 +1,266 @@ +// Boost string_algo library finder.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FINDER_HPP +#define BOOST_STRING_FINDER_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines Finder generators. Finder object is a functor which is able to + find a substring matching a specific criteria in the input. + Finders are used as a pluggable components for replace, find + and split facilities. This header contains generator functions + for finders provided in this library. +*/ + +namespace boost { + namespace algorithm { + +// Finder generators ------------------------------------------// + + //! "First" finder + /*! + Construct the \c first_finder. The finder searches for the first + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \return An instance of the \c first_finder object + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + first_finder( const RangeT& Search ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), is_equal() ) ; + } + + //! "First" finder + /*! + \overload + */ + template + inline detail::first_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + first_finder( + const RangeT& Search, PredicateT Comp ) + { + return + detail::first_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Comp ); + } + + //! "Last" finder + /*! + Construct the \c last_finder. The finder searches for the last + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \return An instance of the \c last_finder object + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + last_finder( const RangeT& Search ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), is_equal() ); + } + //! "Last" finder + /*! + \overload + */ + template + inline detail::last_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + last_finder( const RangeT& Search, PredicateT Comp ) + { + return + detail::last_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Comp ) ; + } + + //! "Nth" finder + /*! + Construct the \c nth_finder. The finder searches for the n-th (zero-indexed) + occurrence of the string in a given input. + The result is given as an \c iterator_range delimiting the match. + + \param Search A substring to be searched for. + \param Nth An index of the match to be find + \return An instance of the \c nth_finder object + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + is_equal> + nth_finder( + const RangeT& Search, + int Nth) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + is_equal>( ::boost::as_literal(Search), Nth, is_equal() ) ; + } + //! "Nth" finder + /*! + \overload + */ + template + inline detail::nth_finderF< + BOOST_STRING_TYPENAME range_const_iterator::type, + PredicateT> + nth_finder( + const RangeT& Search, + int Nth, + PredicateT Comp ) + { + return + detail::nth_finderF< + BOOST_STRING_TYPENAME + range_const_iterator::type, + PredicateT>( ::boost::as_literal(Search), Nth, Comp ); + } + + //! "Head" finder + /*! + Construct the \c head_finder. The finder returns a head of a given + input. The head is a prefix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c head_finder object + */ + inline detail::head_finderF + head_finder( int N ) + { + return detail::head_finderF(N); + } + + //! "Tail" finder + /*! + Construct the \c tail_finder. The finder returns a tail of a given + input. The tail is a suffix of a string up to n elements in + size. If an input has less then n elements, whole input is + considered a head. + The result is given as an \c iterator_range delimiting the match. + + \param N The size of the head + \return An instance of the \c tail_finder object + */ + inline detail::tail_finderF + tail_finder( int N ) + { + return detail::tail_finderF(N); + } + + //! "Token" finder + /*! + Construct the \c token_finder. The finder searches for a token + specified by a predicate. It is similar to std::find_if + algorithm, with an exception that it return a range of + instead of a single iterator. + + If "compress token mode" is enabled, adjacent matching tokens are + concatenated into one match. Thus the finder can be used to + search for continuous segments of characters satisfying the + given predicate. + + The result is given as an \c iterator_range delimiting the match. + + \param Pred An element selection predicate + \param eCompress Compress flag + \return An instance of the \c token_finder object + */ + template< typename PredicateT > + inline detail::token_finderF + token_finder( + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) + { + return detail::token_finderF( Pred, eCompress ); + } + + //! "Range" finder + /*! + Construct the \c range_finder. The finder does not perform + any operation. It simply returns the given range for + any input. + + \param Begin Beginning of the range + \param End End of the range + \return An instance of the \c range_finger object + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( + ForwardIteratorT Begin, + ForwardIteratorT End ) + { + return detail::range_finderF( Begin, End ); + } + + //! "Range" finder + /*! + \overload + */ + template< typename ForwardIteratorT > + inline detail::range_finderF + range_finder( iterator_range Range ) + { + return detail::range_finderF( Range ); + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::first_finder; + using algorithm::last_finder; + using algorithm::nth_finder; + using algorithm::head_finder; + using algorithm::tail_finder; + using algorithm::token_finder; + using algorithm::range_finder; + +} // namespace boost + + +#endif // BOOST_STRING_FINDER_HPP diff --git a/third-party/boost/boost/algorithm/string/formatter.hpp b/third-party/boost/boost/algorithm/string/formatter.hpp new file mode 100644 index 000000000..de8681bc3 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/formatter.hpp @@ -0,0 +1,120 @@ +// Boost string_algo library formatter.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_FORMATTER_HPP +#define BOOST_STRING_FORMATTER_HPP + +#include +#include +#include +#include + +#include + +/*! \file + Defines Formatter generators. Formatter is a functor which formats + a string according to given parameters. A Formatter works + in conjunction with a Finder. A Finder can provide additional information + for a specific Formatter. An example of such a cooperation is regex_finder + and regex_formatter. + + Formatters are used as pluggable components for replace facilities. + This header contains generator functions for the Formatters provided in this library. +*/ + +namespace boost { + namespace algorithm { + +// generic formatters ---------------------------------------------------------------// + + //! Constant formatter + /*! + Constructs a \c const_formatter. Const formatter always returns + the same value, regardless of the parameter. + + \param Format A predefined value used as a result for formatting + \return An instance of the \c const_formatter object. + */ + template + inline detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + const_formatter(const RangeT& Format) + { + return detail::const_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(::boost::as_literal(Format)); + } + + //! Identity formatter + /*! + Constructs an \c identity_formatter. Identity formatter always returns + the parameter. + + \return An instance of the \c identity_formatter object. + */ + template + inline detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> > + identity_formatter() + { + return detail::identity_formatF< + iterator_range< + BOOST_STRING_TYPENAME range_const_iterator::type> >(); + } + + //! Empty formatter + /*! + Constructs an \c empty_formatter. Empty formatter always returns an empty + sequence. + + \param Input container used to select a correct value_type for the + resulting empty_container<>. + \return An instance of the \c empty_formatter object. + */ + template + inline detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type> + empty_formatter(const RangeT&) + { + return detail::empty_formatF< + BOOST_STRING_TYPENAME range_value::type>(); + } + + //! Empty formatter + /*! + Constructs a \c dissect_formatter. Dissect formatter uses a specified finder + to extract a portion of the formatted sequence. The first finder's match is returned + as a result + + \param Finder a finder used to select a portion of the formatted sequence + \return An instance of the \c dissect_formatter object. + */ + template + inline detail::dissect_formatF< FinderT > + dissect_formatter(const FinderT& Finder) + { + return detail::dissect_formatF(Finder); + } + + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::const_formatter; + using algorithm::identity_formatter; + using algorithm::empty_formatter; + using algorithm::dissect_formatter; + +} // namespace boost + + +#endif // BOOST_FORMATTER_HPP diff --git a/third-party/boost/boost/algorithm/string/iter_find.hpp b/third-party/boost/boost/algorithm/string/iter_find.hpp new file mode 100644 index 000000000..10424abc7 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/iter_find.hpp @@ -0,0 +1,193 @@ +// Boost string_algo library iter_find.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ITER_FIND_HPP +#define BOOST_STRING_ITER_FIND_HPP + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines generic split algorithms. Split algorithms can be + used to divide a sequence into several part according + to a given criteria. Result is given as a 'container + of containers' where elements are copies or references + to extracted parts. + + There are two algorithms provided. One iterates over matching + substrings, the other one over the gaps between these matches. +*/ + +namespace boost { + namespace algorithm { + +// iterate find ---------------------------------------------------// + + //! Iter find algorithm + /*! + This algorithm executes a given finder in iteration on the input, + until the end of input is reached, or no match is found. + Iteration is done using built-in find_iterator, so the real + searching is performed only when needed. + In each iteration new match is found and added to the result. + + \param Result A 'container container' to contain the result of search. + Both outer and inner container must have constructor taking a pair + of iterators as an argument. + Typical type of the result is + \c std::vector> + (each element of such a vector will container a range delimiting + a match). + \param Input A container which will be searched. + \param Finder A Finder object used for searching + \return A reference to the result + + \note Prior content of the result will be overwritten. + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename FinderT > + inline SequenceSequenceT& + iter_find( + SequenceSequenceT& Result, + RangeT& Input, + FinderT Finder ) + { + BOOST_CONCEPT_ASSERT(( + FinderConcept< + FinderT, + BOOST_STRING_TYPENAME range_iterator::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef find_iterator find_iterator_type; + typedef detail::copy_iterator_rangeF< + BOOST_STRING_TYPENAME + range_value::type, + input_iterator_type> copy_range_type; + + input_iterator_type InputEnd=::boost::end(lit_input); + + typedef transform_iterator + transform_iter_type; + + transform_iter_type itBegin= + ::boost::make_transform_iterator( + find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ), + copy_range_type()); + + transform_iter_type itEnd= + ::boost::make_transform_iterator( + find_iterator_type(), + copy_range_type()); + + SequenceSequenceT Tmp(itBegin, itEnd); + + Result.swap(Tmp); + return Result; + } + +// iterate split ---------------------------------------------------// + + //! Split find algorithm + /*! + This algorithm executes a given finder in iteration on the input, + until the end of input is reached, or no match is found. + Iteration is done using built-in find_iterator, so the real + searching is performed only when needed. + Each match is used as a separator of segments. These segments are then + returned in the result. + + \param Result A 'container container' to contain the result of search. + Both outer and inner container must have constructor taking a pair + of iterators as an argument. + Typical type of the result is + \c std::vector> + (each element of such a vector will container a range delimiting + a match). + \param Input A container which will be searched. + \param Finder A finder object used for searching + \return A reference to the result + + \note Prior content of the result will be overwritten. + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename FinderT > + inline SequenceSequenceT& + iter_split( + SequenceSequenceT& Result, + RangeT& Input, + FinderT Finder ) + { + BOOST_CONCEPT_ASSERT(( + FinderConcept::type> + )); + + iterator_range::type> lit_input(::boost::as_literal(Input)); + + typedef BOOST_STRING_TYPENAME + range_iterator::type input_iterator_type; + typedef split_iterator find_iterator_type; + typedef detail::copy_iterator_rangeF< + BOOST_STRING_TYPENAME + range_value::type, + input_iterator_type> copy_range_type; + + input_iterator_type InputEnd=::boost::end(lit_input); + + typedef transform_iterator + transform_iter_type; + + transform_iter_type itBegin= + ::boost::make_transform_iterator( + find_iterator_type( ::boost::begin(lit_input), InputEnd, Finder ), + copy_range_type() ); + + transform_iter_type itEnd= + ::boost::make_transform_iterator( + find_iterator_type(), + copy_range_type() ); + + SequenceSequenceT Tmp(itBegin, itEnd); + + Result.swap(Tmp); + return Result; + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::iter_find; + using algorithm::iter_split; + +} // namespace boost + + +#endif // BOOST_STRING_ITER_FIND_HPP diff --git a/third-party/boost/boost/algorithm/string/join.hpp b/third-party/boost/boost/algorithm/string/join.hpp new file mode 100644 index 000000000..b871eb44f --- /dev/null +++ b/third-party/boost/boost/algorithm/string/join.hpp @@ -0,0 +1,145 @@ +// Boost string_algo library join.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_JOIN_HPP +#define BOOST_STRING_JOIN_HPP + +#include +#include +#include +#include + +/*! \file + Defines join algorithm. + + Join algorithm is a counterpart to split algorithms. + It joins strings from a 'list' by adding user defined separator. + Additionally there is a version that allows simple filtering + by providing a predicate. +*/ + +namespace boost { + namespace algorithm { + +// join --------------------------------------------------------------// + + //! Join algorithm + /*! + This algorithm joins all strings in a 'list' into one long string. + Segments are concatenated by given separator. + + \param Input A container that holds the input strings. It must be a container-of-containers. + \param Separator A string that will separate the joined segments. + \return Concatenated string. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T> + inline typename range_value::type + join( + const SequenceSequenceT& Input, + const Range1T& Separator) + { + // Define working types + typedef typename range_value::type ResultT; + typedef typename range_const_iterator::type InputIteratorT; + + // Parse input + InputIteratorT itBegin=::boost::begin(Input); + InputIteratorT itEnd=::boost::end(Input); + + // Construct container to hold the result + ResultT Result; + + // Append first element + if(itBegin!=itEnd) + { + detail::insert(Result, ::boost::end(Result), *itBegin); + ++itBegin; + } + + for(;itBegin!=itEnd; ++itBegin) + { + // Add separator + detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator)); + // Add element + detail::insert(Result, ::boost::end(Result), *itBegin); + } + + return Result; + } + +// join_if ----------------------------------------------------------// + + //! Conditional join algorithm + /*! + This algorithm joins all strings in a 'list' into one long string. + Segments are concatenated by given separator. Only segments that + satisfy the predicate will be added to the result. + + \param Input A container that holds the input strings. It must be a container-of-containers. + \param Separator A string that will separate the joined segments. + \param Pred A segment selection predicate + \return Concatenated string. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T, typename PredicateT> + inline typename range_value::type + join_if( + const SequenceSequenceT& Input, + const Range1T& Separator, + PredicateT Pred) + { + // Define working types + typedef typename range_value::type ResultT; + typedef typename range_const_iterator::type InputIteratorT; + + // Parse input + InputIteratorT itBegin=::boost::begin(Input); + InputIteratorT itEnd=::boost::end(Input); + + // Construct container to hold the result + ResultT Result; + + // Roll to the first element that will be added + while(itBegin!=itEnd && !Pred(*itBegin)) ++itBegin; + // Add this element + if(itBegin!=itEnd) + { + detail::insert(Result, ::boost::end(Result), *itBegin); + ++itBegin; + } + + for(;itBegin!=itEnd; ++itBegin) + { + if(Pred(*itBegin)) + { + // Add separator + detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator)); + // Add element + detail::insert(Result, ::boost::end(Result), *itBegin); + } + } + + return Result; + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::join; + using algorithm::join_if; + +} // namespace boost + + +#endif // BOOST_STRING_JOIN_HPP + diff --git a/third-party/boost/boost/algorithm/string/predicate.hpp b/third-party/boost/boost/algorithm/string/predicate.hpp new file mode 100644 index 000000000..0879829b5 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/predicate.hpp @@ -0,0 +1,475 @@ +// Boost string_algo library predicate.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_PREDICATE_HPP +#define BOOST_STRING_PREDICATE_HPP + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file boost/algorithm/string/predicate.hpp + Defines string-related predicates. + The predicates determine whether a substring is contained in the input string + under various conditions: a string starts with the substring, ends with the + substring, simply contains the substring or if both strings are equal. + Additionaly the algorithm \c all() checks all elements of a container to satisfy a + condition. + + All predicates provide the strong exception guarantee. +*/ + +namespace boost { + namespace algorithm { + +// starts_with predicate -----------------------------------------------// + + //! 'Starts with' predicate + /*! + This predicate holds when the test string is a prefix of the Input. + In other words, if the input starts with the test. + When the optional predicate is specified, it is used for character-wise + comparison. + + \param Input An input sequence + \param Test A test sequence + \param Comp An element comparison predicate + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool starts_with( + const Range1T& Input, + const Range2T& Test, + PredicateT Comp) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + iterator_range::type> lit_test(::boost::as_literal(Test)); + + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator1T; + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator2T; + + Iterator1T InputEnd=::boost::end(lit_input); + Iterator2T TestEnd=::boost::end(lit_test); + + Iterator1T it=::boost::begin(lit_input); + Iterator2T pit=::boost::begin(lit_test); + for(; + it!=InputEnd && pit!=TestEnd; + ++it,++pit) + { + if( !(Comp(*it,*pit)) ) + return false; + } + + return pit==TestEnd; + } + + //! 'Starts with' predicate + /*! + \overload + */ + template + inline bool starts_with( + const Range1T& Input, + const Range2T& Test) + { + return ::boost::algorithm::starts_with(Input, Test, is_equal()); + } + + //! 'Starts with' predicate ( case insensitive ) + /*! + This predicate holds when the test string is a prefix of the Input. + In other words, if the input starts with the test. + Elements are compared case insensitively. + + \param Input An input sequence + \param Test A test sequence + \param Loc A locale used for case insensitive comparison + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool istarts_with( + const Range1T& Input, + const Range2T& Test, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::starts_with(Input, Test, is_iequal(Loc)); + } + + +// ends_with predicate -----------------------------------------------// + + //! 'Ends with' predicate + /*! + This predicate holds when the test string is a suffix of the Input. + In other words, if the input ends with the test. + When the optional predicate is specified, it is used for character-wise + comparison. + + + \param Input An input sequence + \param Test A test sequence + \param Comp An element comparison predicate + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool ends_with( + const Range1T& Input, + const Range2T& Test, + PredicateT Comp) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + iterator_range::type> lit_test(::boost::as_literal(Test)); + + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator1T; + typedef BOOST_STRING_TYPENAME boost::detail:: + iterator_traits::iterator_category category; + + return detail:: + ends_with_iter_select( + ::boost::begin(lit_input), + ::boost::end(lit_input), + ::boost::begin(lit_test), + ::boost::end(lit_test), + Comp, + category()); + } + + + //! 'Ends with' predicate + /*! + \overload + */ + template + inline bool ends_with( + const Range1T& Input, + const Range2T& Test) + { + return ::boost::algorithm::ends_with(Input, Test, is_equal()); + } + + //! 'Ends with' predicate ( case insensitive ) + /*! + This predicate holds when the test container is a suffix of the Input. + In other words, if the input ends with the test. + Elements are compared case insensitively. + + \param Input An input sequence + \param Test A test sequence + \param Loc A locale used for case insensitive comparison + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool iends_with( + const Range1T& Input, + const Range2T& Test, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::ends_with(Input, Test, is_iequal(Loc)); + } + +// contains predicate -----------------------------------------------// + + //! 'Contains' predicate + /*! + This predicate holds when the test container is contained in the Input. + When the optional predicate is specified, it is used for character-wise + comparison. + + \param Input An input sequence + \param Test A test sequence + \param Comp An element comparison predicate + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool contains( + const Range1T& Input, + const Range2T& Test, + PredicateT Comp) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + iterator_range::type> lit_test(::boost::as_literal(Test)); + + if (::boost::empty(lit_test)) + { + // Empty range is contained always + return true; + } + + // Use the temporary variable to make VACPP happy + bool bResult=(::boost::algorithm::first_finder(lit_test,Comp)(::boost::begin(lit_input), ::boost::end(lit_input))); + return bResult; + } + + //! 'Contains' predicate + /*! + \overload + */ + template + inline bool contains( + const Range1T& Input, + const Range2T& Test) + { + return ::boost::algorithm::contains(Input, Test, is_equal()); + } + + //! 'Contains' predicate ( case insensitive ) + /*! + This predicate holds when the test container is contained in the Input. + Elements are compared case insensitively. + + \param Input An input sequence + \param Test A test sequence + \param Loc A locale used for case insensitive comparison + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool icontains( + const Range1T& Input, + const Range2T& Test, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::contains(Input, Test, is_iequal(Loc)); + } + +// equals predicate -----------------------------------------------// + + //! 'Equals' predicate + /*! + This predicate holds when the test container is equal to the + input container i.e. all elements in both containers are same. + When the optional predicate is specified, it is used for character-wise + comparison. + + \param Input An input sequence + \param Test A test sequence + \param Comp An element comparison predicate + \return The result of the test + + \note This is a two-way version of \c std::equal algorithm + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool equals( + const Range1T& Input, + const Range2T& Test, + PredicateT Comp) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + iterator_range::type> lit_test(::boost::as_literal(Test)); + + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator1T; + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator2T; + + Iterator1T InputEnd=::boost::end(lit_input); + Iterator2T TestEnd=::boost::end(lit_test); + + Iterator1T it=::boost::begin(lit_input); + Iterator2T pit=::boost::begin(lit_test); + for(; + it!=InputEnd && pit!=TestEnd; + ++it,++pit) + { + if( !(Comp(*it,*pit)) ) + return false; + } + + return (pit==TestEnd) && (it==InputEnd); + } + + //! 'Equals' predicate + /*! + \overload + */ + template + inline bool equals( + const Range1T& Input, + const Range2T& Test) + { + return ::boost::algorithm::equals(Input, Test, is_equal()); + } + + //! 'Equals' predicate ( case insensitive ) + /*! + This predicate holds when the test container is equal to the + input container i.e. all elements in both containers are same. + Elements are compared case insensitively. + + \param Input An input sequence + \param Test A test sequence + \param Loc A locale used for case insensitive comparison + \return The result of the test + + \note This is a two-way version of \c std::equal algorithm + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool iequals( + const Range1T& Input, + const Range2T& Test, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::equals(Input, Test, is_iequal(Loc)); + } + +// lexicographical_compare predicate -----------------------------// + + //! Lexicographical compare predicate + /*! + This predicate is an overload of std::lexicographical_compare + for range arguments + + It check whether the first argument is lexicographically less + then the second one. + + If the optional predicate is specified, it is used for character-wise + comparison + + \param Arg1 First argument + \param Arg2 Second argument + \param Pred Comparison predicate + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool lexicographical_compare( + const Range1T& Arg1, + const Range2T& Arg2, + PredicateT Pred) + { + iterator_range::type> lit_arg1(::boost::as_literal(Arg1)); + iterator_range::type> lit_arg2(::boost::as_literal(Arg2)); + + return std::lexicographical_compare( + ::boost::begin(lit_arg1), + ::boost::end(lit_arg1), + ::boost::begin(lit_arg2), + ::boost::end(lit_arg2), + Pred); + } + + //! Lexicographical compare predicate + /*! + \overload + */ + template + inline bool lexicographical_compare( + const Range1T& Arg1, + const Range2T& Arg2) + { + return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_less()); + } + + //! Lexicographical compare predicate (case-insensitive) + /*! + This predicate is an overload of std::lexicographical_compare + for range arguments. + It check whether the first argument is lexicographically less + then the second one. + Elements are compared case insensitively + + + \param Arg1 First argument + \param Arg2 Second argument + \param Loc A locale used for case insensitive comparison + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool ilexicographical_compare( + const Range1T& Arg1, + const Range2T& Arg2, + const std::locale& Loc=std::locale()) + { + return ::boost::algorithm::lexicographical_compare(Arg1, Arg2, is_iless(Loc)); + } + + +// all predicate -----------------------------------------------// + + //! 'All' predicate + /*! + This predicate holds it all its elements satisfy a given + condition, represented by the predicate. + + \param Input An input sequence + \param Pred A predicate + \return The result of the test + + \note This function provides the strong exception-safety guarantee + */ + template + inline bool all( + const RangeT& Input, + PredicateT Pred) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + + typedef BOOST_STRING_TYPENAME + range_const_iterator::type Iterator1T; + + Iterator1T InputEnd=::boost::end(lit_input); + for( Iterator1T It=::boost::begin(lit_input); It!=InputEnd; ++It) + { + if (!Pred(*It)) + return false; + } + + return true; + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::starts_with; + using algorithm::istarts_with; + using algorithm::ends_with; + using algorithm::iends_with; + using algorithm::contains; + using algorithm::icontains; + using algorithm::equals; + using algorithm::iequals; + using algorithm::all; + using algorithm::lexicographical_compare; + using algorithm::ilexicographical_compare; + +} // namespace boost + + +#endif // BOOST_STRING_PREDICATE_HPP diff --git a/third-party/boost/boost/algorithm/string/predicate_facade.hpp b/third-party/boost/boost/algorithm/string/predicate_facade.hpp new file mode 100644 index 000000000..a9753fc2a --- /dev/null +++ b/third-party/boost/boost/algorithm/string/predicate_facade.hpp @@ -0,0 +1,42 @@ +// Boost string_algo library predicate_facade.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_PREDICATE_FACADE_HPP +#define BOOST_STRING_PREDICATE_FACADE_HPP + +#include + +/* + \file boost/algorith/string/predicate_facade.hpp + This file contains predicate_facade definition. This template class is used + to identify classification predicates, so they can be combined using + composition operators. +*/ + +namespace boost { + namespace algorithm { + +// predicate facade ------------------------------------------------------// + + //! Predicate facade + /*! + This class allows to recognize classification + predicates, so that they can be combined using + composition operators. + Every classification predicate must be derived from this class. + */ + template + struct predicate_facade {}; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string/regex.hpp b/third-party/boost/boost/algorithm/string/regex.hpp new file mode 100644 index 000000000..a6c7c60ae --- /dev/null +++ b/third-party/boost/boost/algorithm/string/regex.hpp @@ -0,0 +1,646 @@ +// Boost string_algo library regex.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REGEX_HPP +#define BOOST_STRING_REGEX_HPP + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \file + Defines regex variants of the algorithms. +*/ + +namespace boost { + namespace algorithm { + +// find_regex -----------------------------------------------// + + //! Find regex algorithm + /*! + Search for a substring matching the given regex in the input. + + \param Input A container which will be searched. + \param Rx A regular expression + \param Flags Regex options + \return + An \c iterator_range delimiting the match. + Returned iterator is either \c RangeT::iterator or + \c RangeT::const_iterator, depending on the constness of + the input parameter. + + \note This function provides the strong exception-safety guarantee + */ + template< + typename RangeT, + typename CharT, + typename RegexTraitsT> + inline iterator_range< + BOOST_STRING_TYPENAME range_iterator::type > + find_regex( + RangeT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + iterator_range::type> lit_input(::boost::as_literal(Input)); + + return ::boost::algorithm::regex_finder(Rx,Flags)( + ::boost::begin(lit_input), ::boost::end(lit_input) ); + } + +// replace_regex --------------------------------------------------------------------// + + //! Replace regex algorithm + /*! + Search for a substring matching given regex and format it with + the specified format. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Rx A regular expression + \param Format Regex format definition + \param Flags Regex options + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline OutputIteratorT replace_regex_copy( + OutputIteratorT Output, + const RangeT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + + //! Replace regex algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline SequenceT replace_regex_copy( + const SequenceT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + + //! Replace regex algorithm + /*! + Search for a substring matching given regex and format it with + the specified format. The input string is modified in-place. + + \param Input An input string + \param Rx A regular expression + \param Format Regex format definition + \param Flags Regex options + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline void replace_regex( + SequenceT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + +// replace_all_regex --------------------------------------------------------------------// + + //! Replace all regex algorithm + /*! + Format all substrings, matching given regex, with the specified format. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Rx A regular expression + \param Format Regex format definition + \param Flags Regex options + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline OutputIteratorT replace_all_regex_copy( + OutputIteratorT Output, + const RangeT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + + //! Replace all regex algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline SequenceT replace_all_regex_copy( + const SequenceT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + + //! Replace all regex algorithm + /*! + Format all substrings, matching given regex, with the specified format. + The input string is modified in-place. + + \param Input An input string + \param Rx A regular expression + \param Format Regex format definition + \param Flags Regex options + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT, + typename FormatStringTraitsT, typename FormatStringAllocatorT > + inline void replace_all_regex( + SequenceT& Input, + const basic_regex& Rx, + const std::basic_string& Format, + match_flag_type Flags=match_default | format_default ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::regex_formatter( Format, Flags ) ); + } + +// erase_regex --------------------------------------------------------------------// + + //! Erase regex algorithm + /*! + Remove a substring matching given regex from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Rx A regular expression + \param Flags Regex options + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename CharT, + typename RegexTraitsT > + inline OutputIteratorT erase_regex_copy( + OutputIteratorT Output, + const RangeT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase regex algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT > + inline SequenceT erase_regex_copy( + const SequenceT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase regex algorithm + /*! + Remove a substring matching given regex from the input. + The input string is modified in-place. + + \param Input An input string + \param Rx A regular expression + \param Flags Regex options + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT > + inline void erase_regex( + SequenceT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + +// erase_all_regex --------------------------------------------------------------------// + + //! Erase all regex algorithm + /*! + Erase all substrings, matching given regex, from the input. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Rx A regular expression + \param Flags Regex options + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename RangeT, + typename CharT, + typename RegexTraitsT > + inline OutputIteratorT erase_all_regex_copy( + OutputIteratorT Output, + const RangeT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase all regex algorithm + /*! + \overload + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT > + inline SequenceT erase_all_regex_copy( + const SequenceT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + + //! Erase all regex algorithm + /*! + Erase all substrings, matching given regex, from the input. + The input string is modified in-place. + + \param Input An input string + \param Rx A regular expression + \param Flags Regex options + */ + template< + typename SequenceT, + typename CharT, + typename RegexTraitsT> + inline void erase_all_regex( + SequenceT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::regex_finder( Rx, Flags ), + ::boost::algorithm::empty_formatter( Input ) ); + } + +// find_all_regex ------------------------------------------------------------------// + + //! Find all regex algorithm + /*! + This algorithm finds all substrings matching the give regex + in the input. + + Each part is copied and added as a new element to the output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings. + \param Input A container which will be searched. + \param Rx A regular expression + \param Flags Regex options + \return A reference to the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename CharT, + typename RegexTraitsT > + inline SequenceSequenceT& find_all_regex( + SequenceSequenceT& Result, + const RangeT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::iter_find( + Result, + Input, + ::boost::algorithm::regex_finder(Rx,Flags) ); + } + +// split_regex ------------------------------------------------------------------// + + //! Split regex algorithm + /*! + Tokenize expression. This function is equivalent to C strtok. Input + sequence is split into tokens, separated by separators. Separator + is an every match of the given regex. + Each part is copied and added as a new element to the output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings. + \param Input A container which will be searched. + \param Rx A regular expression + \param Flags Regex options + \return A reference to the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< + typename SequenceSequenceT, + typename RangeT, + typename CharT, + typename RegexTraitsT > + inline SequenceSequenceT& split_regex( + SequenceSequenceT& Result, + const RangeT& Input, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + return ::boost::algorithm::iter_split( + Result, + Input, + ::boost::algorithm::regex_finder(Rx,Flags) ); + } + +// join_if ------------------------------------------------------------------// + +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + //! Conditional join algorithm + /*! + This algorithm joins all strings in a 'list' into one long string. + Segments are concatenated by given separator. Only segments that + match the given regular expression will be added to the result + + This is a specialization of join_if algorithm. + + \param Input A container that holds the input strings. It must be a container-of-containers. + \param Separator A string that will separate the joined segments. + \param Rx A regular expression + \param Flags Regex options + \return Concatenated string. + + \note This function provides the strong exception-safety guarantee + */ + template< + typename SequenceSequenceT, + typename Range1T, + typename CharT, + typename RegexTraitsT > + inline typename range_value::type + join_if( + const SequenceSequenceT& Input, + const Range1T& Separator, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + // Define working types + typedef typename range_value::type ResultT; + typedef typename range_const_iterator::type InputIteratorT; + + // Parse input + InputIteratorT itBegin=::boost::begin(Input); + InputIteratorT itEnd=::boost::end(Input); + + // Construct container to hold the result + ResultT Result; + + + // Roll to the first element that will be added + while( + itBegin!=itEnd && + !::boost::regex_match(::boost::begin(*itBegin), ::boost::end(*itBegin), Rx, Flags)) ++itBegin; + + // Add this element + if(itBegin!=itEnd) + { + detail::insert(Result, ::boost::end(Result), *itBegin); + ++itBegin; + } + + for(;itBegin!=itEnd; ++itBegin) + { + if(::boost::regex_match(::boost::begin(*itBegin), ::boost::end(*itBegin), Rx, Flags)) + { + // Add separator + detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator)); + // Add element + detail::insert(Result, ::boost::end(Result), *itBegin); + } + } + + return Result; + } + +#else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + //! Conditional join algorithm + /*! + This algorithm joins all strings in a 'list' into one long string. + Segments are concatenated by given separator. Only segments that + match the given regular expression will be added to the result + + This is a specialization of join_if algorithm. + + \param Input A container that holds the input strings. It must be a container-of-containers. + \param Separator A string that will separate the joined segments. + \param Rx A regular expression + \param Flags Regex options + \return Concatenated string. + + \note This function provides the strong exception-safety guarantee + */ + template< + typename SequenceSequenceT, + typename Range1T, + typename CharT, + typename RegexTraitsT > + inline typename range_value::type + join_if_regex( + const SequenceSequenceT& Input, + const Range1T& Separator, + const basic_regex& Rx, + match_flag_type Flags=match_default ) + { + // Define working types + typedef typename range_value::type ResultT; + typedef typename range_const_iterator::type InputIteratorT; + + // Parse input + InputIteratorT itBegin=::boost::begin(Input); + InputIteratorT itEnd=::boost::end(Input); + + // Construct container to hold the result + ResultT Result; + + + // Roll to the first element that will be added + while( + itBegin!=itEnd && + !::boost::regex_match(::boost::begin(*itBegin), ::boost::end(*itBegin), Rx, Flags)) ++itBegin; + + // Add this element + if(itBegin!=itEnd) + { + detail::insert(Result, ::boost::end(Result), *itBegin); + ++itBegin; + } + + for(;itBegin!=itEnd; ++itBegin) + { + if(::boost::regex_match(::boost::begin(*itBegin), ::boost::end(*itBegin), Rx, Flags)) + { + // Add separator + detail::insert(Result, ::boost::end(Result), ::boost::as_literal(Separator)); + // Add element + detail::insert(Result, ::boost::end(Result), *itBegin); + } + } + + return Result; + } + + +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + + } // namespace algorithm + + // pull names into the boost namespace + using algorithm::find_regex; + using algorithm::replace_regex; + using algorithm::replace_regex_copy; + using algorithm::replace_all_regex; + using algorithm::replace_all_regex_copy; + using algorithm::erase_regex; + using algorithm::erase_regex_copy; + using algorithm::erase_all_regex; + using algorithm::erase_all_regex_copy; + using algorithm::find_all_regex; + using algorithm::split_regex; + +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + using algorithm::join_if; +#else // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + using algorithm::join_if_regex; +#endif // BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +} // namespace boost + + +#endif // BOOST_STRING_REGEX_HPP diff --git a/third-party/boost/boost/algorithm/string/regex_find_format.hpp b/third-party/boost/boost/algorithm/string/regex_find_format.hpp new file mode 100644 index 000000000..409afc2ba --- /dev/null +++ b/third-party/boost/boost/algorithm/string/regex_find_format.hpp @@ -0,0 +1,90 @@ +// Boost string_algo library regex_find_format.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REGEX_FIND_FORMAT_HPP +#define BOOST_STRING_REGEX_FIND_FORMAT_HPP + +#include +#include +#include +#include + +/*! \file + Defines the \c regex_finder and \c regex_formatter generators. These two functors + are designed to work together. \c regex_formatter uses additional information + about a match contained in the regex_finder search result. +*/ + +namespace boost { + namespace algorithm { + +// regex_finder -----------------------------------------------// + + //! "Regex" finder + /*! + Construct the \c regex_finder. Finder uses the regex engine to search + for a match. + Result is given in \c regex_search_result. This is an extension + of the iterator_range. In addition it contains match results + from the \c regex_search algorithm. + + \param Rx A regular expression + \param MatchFlags Regex search options + \return An instance of the \c regex_finder object + */ + template< + typename CharT, + typename RegexTraitsT> + inline detail::find_regexF< basic_regex > + regex_finder( + const basic_regex& Rx, + match_flag_type MatchFlags=match_default ) + { + return detail:: + find_regexF< + basic_regex >( Rx, MatchFlags ); + } + +// regex_formater ---------------------------------------------// + + //! Regex formatter + /*! + Construct the \c regex_formatter. Regex formatter uses the regex engine to + format a match found by the \c regex_finder. + This formatted it designed to closely cooperate with \c regex_finder. + + \param Format Regex format definition + \param Flags Format flags + \return An instance of the \c regex_formatter functor + */ + template< + typename CharT, + typename TraitsT, typename AllocT > + inline detail::regex_formatF< std::basic_string< CharT, TraitsT, AllocT > > + regex_formatter( + const std::basic_string& Format, + match_flag_type Flags=format_default ) + { + return + detail::regex_formatF< std::basic_string >( + Format, + Flags ); + } + + } // namespace algorithm + + // pull the names to the boost namespace + using algorithm::regex_finder; + using algorithm::regex_formatter; + +} // namespace boost + + +#endif // BOOST_STRING_REGEX_FIND_FORMAT_HPP diff --git a/third-party/boost/boost/algorithm/string/replace.hpp b/third-party/boost/boost/algorithm/string/replace.hpp new file mode 100644 index 000000000..2adb031c5 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/replace.hpp @@ -0,0 +1,926 @@ +// Boost string_algo library replace.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_REPLACE_HPP +#define BOOST_STRING_REPLACE_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/*! \file + Defines various replace algorithms. Each algorithm replaces + part(s) of the input according to set of searching and replace criteria. +*/ + +namespace boost { + namespace algorithm { + +// replace_range --------------------------------------------------------------------// + + //! Replace range algorithm + /*! + Replace the given range in the input string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param SearchRange A range in the input to be substituted + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_range_copy( + OutputIteratorT Output, + const Range1T& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange, + const Range2T& Format) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + + //! Replace range algorithm + /*! + \overload + */ + template + inline SequenceT replace_range_copy( + const SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_const_iterator::type>& SearchRange, + const RangeT& Format) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + + //! Replace range algorithm + /*! + Replace the given range in the input string. + The input sequence is modified in-place. + + \param Input An input string + \param SearchRange A range in the input to be substituted + \param Format A substitute string + */ + template + inline void replace_range( + SequenceT& Input, + const iterator_range< + BOOST_STRING_TYPENAME + range_iterator::type>& SearchRange, + const RangeT& Format) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::range_finder(SearchRange), + ::boost::algorithm::const_formatter(Format)); + } + +// replace_first --------------------------------------------------------------------// + + //! Replace first algorithm + /*! + Replace the first match of the search substring in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm + /*! + \overload + */ + template + inline SequenceT replace_first_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm + /*! + replace the first match of the search substring in the input + with the format string. The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_first ( case insensitive ) ---------------------------------------------// + + //! Replace first algorithm ( case insensitive ) + /*! + Replace the first match of the search substring in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_first_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_first_copy( + const SequenceT& Input, + const Range2T& Search, + const Range1T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace first algorithm ( case insensitive ) + /*! + Replace the first match of the search substring in the input + with the format string. Input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_first( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_last --------------------------------------------------------------------// + + //! Replace last algorithm + /*! + Replace the last match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm + /*! + \overload + */ + template + inline SequenceT replace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm + /*! + Replace the last match of the search string in the input + with the format string. Input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_last ( case insensitive ) -----------------------------------------------// + + //! Replace last algorithm ( case insensitive ) + /*! + Replace the last match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_last_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_last_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace last algorithm ( case insensitive ) + /*! + Replace the last match of the search string in the input + with the format string.The input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_last( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::last_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_nth --------------------------------------------------------------------// + + //! Replace nth algorithm + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm + /*! + \overload + */ + template + inline SequenceT replace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. Input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + */ + template + inline void replace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_nth ( case insensitive ) -----------------------------------------------// + + //! Replace nth algorithm ( case insensitive ) + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_nth_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + int Nth, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc) ), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_nth_copy( + const SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace nth algorithm ( case insensitive ) + /*! + Replace an Nth (zero-indexed) match of the search string in the input + with the format string. Input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Nth An index of the match to be replaced. The index is 0-based. + For negative N, matches are counted from the end of string. + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_nth( + SequenceT& Input, + const Range1T& Search, + int Nth, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::nth_finder(Search, Nth, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_all --------------------------------------------------------------------// + + //! Replace all algorithm + /*! + Replace all occurrences of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT replace_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm + /*! + \overload + */ + template + inline SequenceT replace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm + /*! + Replace all occurrences of the search string in the input + with the format string. The input sequence is modified in-place. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + */ + template + inline void replace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_all ( case insensitive ) -----------------------------------------------// + + //! Replace all algorithm ( case insensitive ) + /*! + Replace all occurrences of the search string in the input + with the format string. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + Searching is case insensitive. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T, + typename Range3T> + inline OutputIteratorT ireplace_all_copy( + OutputIteratorT Output, + const Range1T& Input, + const Range2T& Search, + const Range3T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Output, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm ( case insensitive ) + /*! + \overload + */ + template + inline SequenceT ireplace_all_copy( + const SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::find_format_all_copy( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace all algorithm ( case insensitive ) + /*! + Replace all occurrences of the search string in the input + with the format string.The input sequence is modified in-place. + Searching is case insensitive. + + \param Input An input string + \param Search A substring to be searched for + \param Format A substitute string + \param Loc A locale used for case insensitive comparison + */ + template + inline void ireplace_all( + SequenceT& Input, + const Range1T& Search, + const Range2T& Format, + const std::locale& Loc=std::locale() ) + { + ::boost::algorithm::find_format_all( + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc)), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_head --------------------------------------------------------------------// + + //! Replace head algorithm + /*! + Replace the head of the input with the given format string. + The head is a prefix of a string of given size. + If the sequence is shorter then required, whole string if + considered to be the head. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_head_copy( + OutputIteratorT Output, + const Range1T& Input, + int N, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace head algorithm + /*! + \overload + */ + template + inline SequenceT replace_head_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace head algorithm + /*! + Replace the head of the input with the given format string. + The head is a prefix of a string of given size. + If the sequence is shorter then required, the whole string is + considered to be the head. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the head. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + */ + template + inline void replace_head( + SequenceT& Input, + int N, + const RangeT& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::head_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + +// replace_tail --------------------------------------------------------------------// + + //! Replace tail algorithm + /*! + Replace the tail of the input with the given format string. + The tail is a suffix of a string of given size. + If the sequence is shorter then required, whole string is + considered to be the tail. + The result is a modified copy of the input. It is returned as a sequence + or copied to the output iterator. + + \param Output An output iterator to which the result will be copied + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + \return An output iterator pointing just after the last inserted character or + a modified copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template< + typename OutputIteratorT, + typename Range1T, + typename Range2T> + inline OutputIteratorT replace_tail_copy( + OutputIteratorT Output, + const Range1T& Input, + int N, + const Range2T& Format ) + { + return ::boost::algorithm::find_format_copy( + Output, + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace tail algorithm + /*! + \overload + */ + template + inline SequenceT replace_tail_copy( + const SequenceT& Input, + int N, + const RangeT& Format ) + { + return ::boost::algorithm::find_format_copy( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + //! Replace tail algorithm + /*! + Replace the tail of the input with the given format sequence. + The tail is a suffix of a string of given size. + If the sequence is shorter then required, the whole string is + considered to be the tail. The input sequence is modified in-place. + + \param Input An input string + \param N Length of the tail. + For N>=0, at most N characters are extracted. + For N<0, size(Input)-|N| characters are extracted. + \param Format A substitute string + */ + template + inline void replace_tail( + SequenceT& Input, + int N, + const RangeT& Format ) + { + ::boost::algorithm::find_format( + Input, + ::boost::algorithm::tail_finder(N), + ::boost::algorithm::const_formatter(Format) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::replace_range_copy; + using algorithm::replace_range; + using algorithm::replace_first_copy; + using algorithm::replace_first; + using algorithm::ireplace_first_copy; + using algorithm::ireplace_first; + using algorithm::replace_last_copy; + using algorithm::replace_last; + using algorithm::ireplace_last_copy; + using algorithm::ireplace_last; + using algorithm::replace_nth_copy; + using algorithm::replace_nth; + using algorithm::ireplace_nth_copy; + using algorithm::ireplace_nth; + using algorithm::replace_all_copy; + using algorithm::replace_all; + using algorithm::ireplace_all_copy; + using algorithm::ireplace_all; + using algorithm::replace_head_copy; + using algorithm::replace_head; + using algorithm::replace_tail_copy; + using algorithm::replace_tail; + +} // namespace boost + +#endif // BOOST_REPLACE_HPP diff --git a/third-party/boost/boost/algorithm/string/sequence_traits.hpp b/third-party/boost/boost/algorithm/string/sequence_traits.hpp new file mode 100644 index 000000000..be151f8d3 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/sequence_traits.hpp @@ -0,0 +1,120 @@ +// Boost string_algo library sequence_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_SEQUENCE_TRAITS_HPP +#define BOOST_STRING_SEQUENCE_TRAITS_HPP + +#include +#include +#include + +/*! \file + Traits defined in this header are used by various algorithms to achieve + better performance for specific containers. + Traits provide fail-safe defaults. If a container supports some of these + features, it is possible to specialize the specific trait for this container. + For lacking compilers, it is possible of define an override for a specific tester + function. + + Due to a language restriction, it is not currently possible to define specializations for + stl containers without including the corresponding header. To decrease the overhead + needed by this inclusion, user can selectively include a specialization + header for a specific container. They are located in boost/algorithm/string/stl + directory. Alternatively she can include boost/algorithm/string/std_collection_traits.hpp + header which contains specializations for all stl containers. +*/ + +namespace boost { + namespace algorithm { + +// sequence traits -----------------------------------------------// + + + //! Native replace trait + /*! + This trait specifies that the sequence has \c std::string like replace method + */ + template< typename T > + class has_native_replace + { + + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + + typedef mpl::bool_::value> type; + }; + + + //! Stable iterators trait + /*! + This trait specifies that the sequence has stable iterators. It means + that operations like insert/erase/replace do not invalidate iterators. + */ + template< typename T > + class has_stable_iterators + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + + //! Const time insert trait + /*! + This trait specifies that the sequence's insert method has + constant time complexity. + */ + template< typename T > + class has_const_time_insert + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + + //! Const time erase trait + /*! + This trait specifies that the sequence's erase method has + constant time complexity. + */ + template< typename T > + class has_const_time_erase + { + public: +# if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = false }; +# else + BOOST_STATIC_CONSTANT(bool, value=false); +# endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_SEQUENCE_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/split.hpp b/third-party/boost/boost/algorithm/string/split.hpp new file mode 100644 index 000000000..cae712c07 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/split.hpp @@ -0,0 +1,163 @@ +// Boost string_algo library split.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2006. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_SPLIT_HPP +#define BOOST_STRING_SPLIT_HPP + +#include + +#include +#include +#include + +/*! \file + Defines basic split algorithms. + Split algorithms can be used to divide a string + into several parts according to given criteria. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> +*/ + +namespace boost { + namespace algorithm { + +// find_all ------------------------------------------------------------// + + //! Find all algorithm + /*! + This algorithm finds all occurrences of the search string + in the input. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Search A substring to be searched for. + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T, typename Range2T > + inline SequenceSequenceT& find_all( + SequenceSequenceT& Result, + Range1T& Input, + const Range2T& Search) + { + return ::boost::algorithm::iter_find( + Result, + Input, + ::boost::algorithm::first_finder(Search) ); + } + + //! Find all algorithm ( case insensitive ) + /*! + This algorithm finds all occurrences of the search string + in the input. + Each part is copied and added as a new element to the + output container. Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + Searching is case insensitive. + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Search A substring to be searched for. + \param Loc A locale used for case insensitive comparison + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename Range1T, typename Range2T > + inline SequenceSequenceT& ifind_all( + SequenceSequenceT& Result, + Range1T& Input, + const Range2T& Search, + const std::locale& Loc=std::locale() ) + { + return ::boost::algorithm::iter_find( + Result, + Input, + ::boost::algorithm::first_finder(Search, is_iequal(Loc) ) ); + } + + +// tokenize -------------------------------------------------------------// + + //! Split algorithm + /*! + Tokenize expression. This function is equivalent to C strtok. Input + sequence is split into tokens, separated by separators. Separators + are given by means of the predicate. + + Each part is copied and added as a new element to the + output container. + Thus the result container must be able to hold copies + of the matches (in a compatible structure like std::string) or + a reference to it (e.g. using the iterator range class). + Examples of such a container are \c std::vector + or \c std::list> + + \param Result A container that can hold copies of references to the substrings + \param Input A container which will be searched. + \param Pred A predicate to identify separators. This predicate is + supposed to return true if a given element is a separator. + \param eCompress If eCompress argument is set to token_compress_on, adjacent + separators are merged together. Otherwise, every two separators + delimit a token. + \return A reference the result + + \note Prior content of the result will be overwritten. + + \note This function provides the strong exception-safety guarantee + */ + template< typename SequenceSequenceT, typename RangeT, typename PredicateT > + inline SequenceSequenceT& split( + SequenceSequenceT& Result, + RangeT& Input, + PredicateT Pred, + token_compress_mode_type eCompress=token_compress_off ) + { + return ::boost::algorithm::iter_split( + Result, + Input, + ::boost::algorithm::token_finder( Pred, eCompress ) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::find_all; + using algorithm::ifind_all; + using algorithm::split; + +} // namespace boost + + +#endif // BOOST_STRING_SPLIT_HPP + diff --git a/third-party/boost/boost/algorithm/string/std/list_traits.hpp b/third-party/boost/boost/algorithm/string/std/list_traits.hpp new file mode 100644 index 000000000..a3cf7bb18 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/std/list_traits.hpp @@ -0,0 +1,68 @@ +// Boost string_algo library list_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_STD_LIST_TRAITS_HPP +#define BOOST_STRING_STD_LIST_TRAITS_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + +// std::list<> traits -----------------------------------------------// + + + // stable iterators trait + template + class has_stable_iterators< ::std::list > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + // const time insert trait + template + class has_const_time_insert< ::std::list > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + // const time erase trait + template + class has_const_time_erase< ::std::list > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_STD_LIST_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/std/rope_traits.hpp b/third-party/boost/boost/algorithm/string/std/rope_traits.hpp new file mode 100644 index 000000000..637059a55 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/std/rope_traits.hpp @@ -0,0 +1,81 @@ +// Boost string_algo library string_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_STD_ROPE_TRAITS_HPP +#define BOOST_STRING_STD_ROPE_TRAITS_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + +// SGI's std::rope<> traits -----------------------------------------------// + + + // native replace trait + template + class has_native_replace< std::rope > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_ type; + }; + + // stable iterators trait + template + class has_stable_iterators< std::rope > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_ type; + }; + + // const time insert trait + template + class has_const_time_insert< std::rope > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_ type; + }; + + // const time erase trait + template + class has_const_time_erase< std::rope > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_ type; + }; + + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_ROPE_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/std/slist_traits.hpp b/third-party/boost/boost/algorithm/string/std/slist_traits.hpp new file mode 100644 index 000000000..c30b93c73 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/std/slist_traits.hpp @@ -0,0 +1,69 @@ +// Boost string_algo library slist_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_STD_SLIST_TRAITS_HPP +#define BOOST_STRING_STD_SLIST_TRAITS_HPP + +#include +#include +#include BOOST_SLIST_HEADER +#include + +namespace boost { + namespace algorithm { + +// SGI's std::slist<> traits -----------------------------------------------// + + + // stable iterators trait + template + class has_stable_iterators< BOOST_STD_EXTENSION_NAMESPACE::slist > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + // const time insert trait + template + class has_const_time_insert< BOOST_STD_EXTENSION_NAMESPACE::slist > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + // const time erase trait + template + class has_const_time_erase< BOOST_STD_EXTENSION_NAMESPACE::slist > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true }; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + typedef mpl::bool_::value> type; + }; + + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_STD_LIST_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/std/string_traits.hpp b/third-party/boost/boost/algorithm/string/std/string_traits.hpp new file mode 100644 index 000000000..c9408307d --- /dev/null +++ b/third-party/boost/boost/algorithm/string/std/string_traits.hpp @@ -0,0 +1,44 @@ +// Boost string_algo library string_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_STD_STRING_TRAITS_HPP +#define BOOST_STRING_STD_STRING_TRAITS_HPP + +#include +#include +#include + +namespace boost { + namespace algorithm { + +// std::basic_string<> traits -----------------------------------------------// + + + // native replace trait + template + class has_native_replace< std::basic_string > + { + public: +#if BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + enum { value = true } ; +#else + BOOST_STATIC_CONSTANT(bool, value=true); +#endif // BOOST_WORKAROUND( __IBMCPP__, <= 600 ) + + typedef mpl::bool_::value> type; + }; + + + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_LIST_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/std_containers_traits.hpp b/third-party/boost/boost/algorithm/string/std_containers_traits.hpp new file mode 100644 index 000000000..3f02246fd --- /dev/null +++ b/third-party/boost/boost/algorithm/string/std_containers_traits.hpp @@ -0,0 +1,26 @@ +// Boost string_algo library std_containers_traits.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_STD_CONTAINERS_TRAITS_HPP +#define BOOST_STRING_STD_CONTAINERS_TRAITS_HPP + +/*!\file + This file includes sequence traits for stl containers. +*/ + +#include +#include +#include + +#ifdef BOOST_HAS_SLIST +# include +#endif + +#endif // BOOST_STRING_STD_CONTAINERS_TRAITS_HPP diff --git a/third-party/boost/boost/algorithm/string/trim.hpp b/third-party/boost/boost/algorithm/string/trim.hpp new file mode 100644 index 000000000..e740d57d9 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/trim.hpp @@ -0,0 +1,398 @@ +// Boost string_algo library trim.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_TRIM_HPP +#define BOOST_STRING_TRIM_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/*! \file + Defines trim algorithms. + Trim algorithms are used to remove trailing and leading spaces from a + sequence (string). Space is recognized using given locales. + + Parametric (\c _if) variants use a predicate (functor) to select which characters + are to be trimmed.. + Functions take a selection predicate as a parameter, which is used to determine + whether a character is a space. Common predicates are provided in classification.hpp header. + +*/ + +namespace boost { + namespace algorithm { + + // left trim -----------------------------------------------// + + + //! Left trim - parametric + /*! + Remove all leading spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed copy of the input. It is returned as a sequence + or copied to the output iterator + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param IsSpace A unary predicate identifying spaces + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT trim_left_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + std::copy( + ::boost::algorithm::detail::trim_begin( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace ), + ::boost::end(lit_range), + Output); + + return Output; + } + + //! Left trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_left_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + return SequenceT( + ::boost::algorithm::detail::trim_begin( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace ), + ::boost::end(Input)); + } + + //! Left trim - parametric + /*! + Remove all leading spaces from the input. + The result is a trimmed copy of the input. + + \param Input An input sequence + \param Loc a locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_left_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) + { + return + ::boost::algorithm::trim_left_copy_if( + Input, + is_space(Loc)); + } + + //! Left trim + /*! + Remove all leading spaces from the input. The supplied predicate is + used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_left_if(SequenceT& Input, PredicateT IsSpace) + { + Input.erase( + ::boost::begin(Input), + ::boost::algorithm::detail::trim_begin( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace)); + } + + //! Left trim + /*! + Remove all leading spaces from the input. + The Input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim_left(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_left_if( + Input, + is_space(Loc)); + } + + // right trim -----------------------------------------------// + + //! Right trim - parametric + /*! + Remove all trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed copy of the input. It is returned as a sequence + or copied to the output iterator + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param IsSpace A unary predicate identifying spaces + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT trim_right_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace ) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + std::copy( + ::boost::begin(lit_range), + ::boost::algorithm::detail::trim_end( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace ), + Output ); + + return Output; + } + + //! Right trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_right_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + return SequenceT( + ::boost::begin(Input), + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace) + ); + } + + //! Right trim + /*! + Remove all trailing spaces from the input. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_right_copy(const SequenceT& Input, const std::locale& Loc=std::locale()) + { + return + ::boost::algorithm::trim_right_copy_if( + Input, + is_space(Loc)); + } + + + //! Right trim - parametric + /*! + Remove all trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_right_if(SequenceT& Input, PredicateT IsSpace) + { + Input.erase( + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace ), + ::boost::end(Input) + ); + } + + + //! Right trim + /*! + Remove all trailing spaces from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim_right(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_right_if( + Input, + is_space(Loc) ); + } + + // both side trim -----------------------------------------------// + + //! Trim - parametric + /*! + Remove all trailing and leading spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The result is a trimmed copy of the input. It is returned as a sequence + or copied to the output iterator + + \param Output An output iterator to which the result will be copied + \param Input An input range + \param IsSpace A unary predicate identifying spaces + \return + An output iterator pointing just after the last inserted character or + a copy of the input + + \note The second variant of this function provides the strong exception-safety guarantee + */ + template + inline OutputIteratorT trim_copy_if( + OutputIteratorT Output, + const RangeT& Input, + PredicateT IsSpace) + { + iterator_range::type> lit_range(::boost::as_literal(Input)); + + BOOST_STRING_TYPENAME + range_const_iterator::type TrimEnd= + ::boost::algorithm::detail::trim_end( + ::boost::begin(lit_range), + ::boost::end(lit_range), + IsSpace); + + std::copy( + detail::trim_begin( + ::boost::begin(lit_range), TrimEnd, IsSpace), + TrimEnd, + Output + ); + + return Output; + } + + //! Trim - parametric + /*! + \overload + */ + template + inline SequenceT trim_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + BOOST_STRING_TYPENAME + range_const_iterator::type TrimEnd= + ::boost::algorithm::detail::trim_end( + ::boost::begin(Input), + ::boost::end(Input), + IsSpace); + + return SequenceT( + detail::trim_begin( + ::boost::begin(Input), + TrimEnd, + IsSpace), + TrimEnd + ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + + \note This function provides the strong exception-safety guarantee + */ + template + inline SequenceT trim_copy( const SequenceT& Input, const std::locale& Loc=std::locale() ) + { + return + ::boost::algorithm::trim_copy_if( + Input, + is_space(Loc) ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The supplied predicate is used to determine which characters are considered spaces. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_if(SequenceT& Input, PredicateT IsSpace) + { + ::boost::algorithm::trim_right_if( Input, IsSpace ); + ::boost::algorithm::trim_left_if( Input, IsSpace ); + } + + //! Trim + /*! + Remove all leading and trailing spaces from the input. + The input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + */ + template + inline void trim(SequenceT& Input, const std::locale& Loc=std::locale()) + { + ::boost::algorithm::trim_if( + Input, + is_space( Loc ) ); + } + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::trim_left; + using algorithm::trim_left_if; + using algorithm::trim_left_copy; + using algorithm::trim_left_copy_if; + using algorithm::trim_right; + using algorithm::trim_right_if; + using algorithm::trim_right_copy; + using algorithm::trim_right_copy_if; + using algorithm::trim; + using algorithm::trim_if; + using algorithm::trim_copy; + using algorithm::trim_copy_if; + +} // namespace boost + +#endif // BOOST_STRING_TRIM_HPP diff --git a/third-party/boost/boost/algorithm/string/trim_all.hpp b/third-party/boost/boost/algorithm/string/trim_all.hpp new file mode 100644 index 000000000..a616f7f33 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/trim_all.hpp @@ -0,0 +1,217 @@ +// Boost string_algo library trim.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_TRIM_ALL_HPP +#define BOOST_STRING_TRIM_ALL_HPP + +#include + +#include +#include +#include +#include +#include +#include + +/*! \file + Defines trim_all algorithms. + + Just like \c trim, \c trim_all removes all trailing and leading spaces from a + sequence (string). In addition, spaces in the middle of the sequence are truncated + to just one character. Space is recognized using given locales. + + \c trim_fill acts as trim_all, but the spaces in the middle are replaces with + a user-define sequence of character. + + Parametric (\c _if) variants use a predicate (functor) to select which characters + are to be trimmed.. + Functions take a selection predicate as a parameter, which is used to determine + whether a character is a space. Common predicates are provided in classification.hpp header. + +*/ + +namespace boost { + namespace algorithm { + + // multi line trim ----------------------------------------------- // + + //! Trim All - parametric + /*! + Remove all leading and trailing spaces from the input and + compress all other spaces to a single character. + The result is a trimmed copy of the input + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + \return A trimmed copy of the input + */ + template + inline SequenceT trim_all_copy_if(const SequenceT& Input, PredicateT IsSpace) + { + return + ::boost::find_format_all_copy( + ::boost::trim_copy_if(Input, IsSpace), + ::boost::token_finder(IsSpace, ::boost::token_compress_on), + ::boost::dissect_formatter(::boost::head_finder(1))); + } + + + //! Trim All + /*! + Remove all leading and trailing spaces from the input and + compress all other spaces to a single character. + The input sequence is modified in-place. + + \param Input An input sequence + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_all_if(SequenceT& Input, PredicateT IsSpace) + { + ::boost::trim_if(Input, IsSpace); + ::boost::find_format_all( + Input, + ::boost::token_finder(IsSpace, ::boost::token_compress_on), + ::boost::dissect_formatter(::boost::head_finder(1))); + } + + + //! Trim All + /*! + Remove all leading and trailing spaces from the input and + compress all other spaces to a single character. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + */ + template + inline SequenceT trim_all_copy(const SequenceT& Input, const std::locale& Loc =std::locale()) + { + return trim_all_copy_if(Input, ::boost::is_space(Loc)); + } + + + //! Trim All + /*! + Remove all leading and trailing spaces from the input and + compress all other spaces to a single character. + The input sequence is modified in-place. + + \param Input An input sequence + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + */ + template + inline void trim_all(SequenceT& Input, const std::locale& Loc =std::locale()) + { + trim_all_if(Input, ::boost::is_space(Loc)); + } + + + //! Trim Fill - parametric + /*! + Remove all leading and trailing spaces from the input and + replace all every block of consecutive spaces with a fill string + defined by user. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Fill A string used to fill the inner spaces + \param IsSpace A unary predicate identifying spaces + \return A trimmed copy of the input + */ + template + inline SequenceT trim_fill_copy_if(const SequenceT& Input, const RangeT& Fill, PredicateT IsSpace) + { + return + ::boost::find_format_all_copy( + ::boost::trim_copy_if(Input, IsSpace), + ::boost::token_finder(IsSpace, ::boost::token_compress_on), + ::boost::const_formatter(::boost::as_literal(Fill))); + } + + + //! Trim Fill + /*! + Remove all leading and trailing spaces from the input and + replace all every block of consecutive spaces with a fill string + defined by user. + The input sequence is modified in-place. + + \param Input An input sequence + \param Fill A string used to fill the inner spaces + \param IsSpace A unary predicate identifying spaces + */ + template + inline void trim_fill_if(SequenceT& Input, const RangeT& Fill, PredicateT IsSpace) + { + ::boost::trim_if(Input, IsSpace); + ::boost::find_format_all( + Input, + ::boost::token_finder(IsSpace, ::boost::token_compress_on), + ::boost::const_formatter(::boost::as_literal(Fill))); + } + + + //! Trim Fill + /*! + Remove all leading and trailing spaces from the input and + replace all every block of consecutive spaces with a fill string + defined by user. + The result is a trimmed copy of the input + + \param Input An input sequence + \param Fill A string used to fill the inner spaces + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + */ + template + inline SequenceT trim_fill_copy(const SequenceT& Input, const RangeT& Fill, const std::locale& Loc =std::locale()) + { + return trim_fill_copy_if(Input, Fill, ::boost::is_space(Loc)); + } + + + //! Trim Fill + /*! + Remove all leading and trailing spaces from the input and + replace all every block of consecutive spaces with a fill string + defined by user. + The input sequence is modified in-place. + + \param Input An input sequence + \param Fill A string used to fill the inner spaces + \param Loc A locale used for 'space' classification + \return A trimmed copy of the input + */ + template + inline void trim_fill(SequenceT& Input, const RangeT& Fill, const std::locale& Loc =std::locale()) + { + trim_fill_if(Input, Fill, ::boost::is_space(Loc)); + } + + + } // namespace algorithm + + // pull names to the boost namespace + using algorithm::trim_all; + using algorithm::trim_all_if; + using algorithm::trim_all_copy; + using algorithm::trim_all_copy_if; + using algorithm::trim_fill; + using algorithm::trim_fill_if; + using algorithm::trim_fill_copy; + using algorithm::trim_fill_copy_if; + +} // namespace boost + +#endif // BOOST_STRING_TRIM_ALL_HPP diff --git a/third-party/boost/boost/algorithm/string/yes_no_type.hpp b/third-party/boost/boost/algorithm/string/yes_no_type.hpp new file mode 100644 index 000000000..b76cc6c15 --- /dev/null +++ b/third-party/boost/boost/algorithm/string/yes_no_type.hpp @@ -0,0 +1,33 @@ +// Boost string_algo library yes_no_type.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_YES_NO_TYPE_DETAIL_HPP +#define BOOST_STRING_YES_NO_TYPE_DETAIL_HPP + +namespace boost { + namespace algorithm { + + // taken from boost mailing-list + // when yes_no_type will become officially + // a part of boost distribution, this header + // will be deprecated + template struct size_descriptor + { + typedef char (& type)[I]; + }; + + typedef size_descriptor<1>::type yes_type; + typedef size_descriptor<2>::type no_type; + + } // namespace algorithm +} // namespace boost + + +#endif // BOOST_STRING_YES_NO_TYPE_DETAIL_HPP diff --git a/third-party/boost/boost/algorithm/string_regex.hpp b/third-party/boost/boost/algorithm/string_regex.hpp new file mode 100644 index 000000000..791aa1848 --- /dev/null +++ b/third-party/boost/boost/algorithm/string_regex.hpp @@ -0,0 +1,23 @@ +// Boost string_algo library string_regex.hpp header file ---------------------------// + +// Copyright Pavol Droba 2002-2004. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for updates, documentation, and revision history. + +#ifndef BOOST_STRING_ALGO_REGEX_HPP +#define BOOST_STRING_ALGO_REGEX_HPP + +/*! \file + Cumulative include for string_algo library. + In addition to string.hpp contains also regex-related stuff. +*/ + +#include +#include +#include + +#endif // BOOST_STRING_ALGO_REGEX_HPP diff --git a/third-party/boost/boost/align.hpp b/third-party/boost/boost/align.hpp new file mode 100644 index 000000000..45fe36bbc --- /dev/null +++ b/third-party/boost/boost/align.hpp @@ -0,0 +1,22 @@ +/* +Copyright 2014-2015 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_ALIGN_HPP +#define BOOST_ALIGN_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/third-party/boost/boost/aligned_storage.hpp b/third-party/boost/boost/aligned_storage.hpp new file mode 100644 index 000000000..f400fa9e7 --- /dev/null +++ b/third-party/boost/boost/aligned_storage.hpp @@ -0,0 +1,18 @@ +//----------------------------------------------------------------------------- +// boost aligned_storage.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2002-2003 +// Eric Friedman, Itay Maman +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_ALIGNED_STORAGE_HPP +#define BOOST_ALIGNED_STORAGE_HPP + +#include + +#endif // BOOST_ALIGNED_STORAGE_HPP diff --git a/third-party/boost/boost/any.hpp b/third-party/boost/boost/any.hpp new file mode 100644 index 000000000..f161b3ff1 --- /dev/null +++ b/third-party/boost/boost/any.hpp @@ -0,0 +1,338 @@ +// See http://www.boost.org/libs/any for Documentation. + +#ifndef BOOST_ANY_INCLUDED +#define BOOST_ANY_INCLUDED + +#if defined(_MSC_VER) +# pragma once +#endif + +// what: variant type boost::any +// who: contributed by Kevlin Henney, +// with features contributed and bugs found by +// Antony Polukhin, Ed Brey, Mark Rodgers, +// Peter Dimov, and James Curran +// when: July 2001, April 2013 - 2019 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + class any + { + public: // structors + + any() BOOST_NOEXCEPT + : content(0) + { + } + + template + any(const ValueType & value) + : content(new holder< + BOOST_DEDUCED_TYPENAME remove_cv::type>::type + >(value)) + { + } + + any(const any & other) + : content(other.content ? other.content->clone() : 0) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move constructor + any(any&& other) BOOST_NOEXCEPT + : content(other.content) + { + other.content = 0; + } + + // Perfect forwarding of ValueType + template + any(ValueType&& value + , typename boost::disable_if >::type* = 0 // disable if value has type `any&` + , typename boost::disable_if >::type* = 0) // disable if value has type `const ValueType&&` + : content(new holder< typename decay::type >(static_cast(value))) + { + } +#endif + + ~any() BOOST_NOEXCEPT + { + delete content; + } + + public: // modifiers + + any & swap(any & rhs) BOOST_NOEXCEPT + { + std::swap(content, rhs.content); + return *this; + } + + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + any & operator=(const ValueType & rhs) + { + any(rhs).swap(*this); + return *this; + } + + any & operator=(any rhs) + { + any(rhs).swap(*this); + return *this; + } + +#else + any & operator=(const any& rhs) + { + any(rhs).swap(*this); + return *this; + } + + // move assignment + any & operator=(any&& rhs) BOOST_NOEXCEPT + { + rhs.swap(*this); + any().swap(rhs); + return *this; + } + + // Perfect forwarding of ValueType + template + any & operator=(ValueType&& rhs) + { + any(static_cast(rhs)).swap(*this); + return *this; + } +#endif + + public: // queries + + bool empty() const BOOST_NOEXCEPT + { + return !content; + } + + void clear() BOOST_NOEXCEPT + { + any().swap(*this); + } + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT + { + return content ? content->type() : boost::typeindex::type_id().type_info(); + } + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + private: // types +#else + public: // types (public so any_cast can be non-friend) +#endif + + class BOOST_SYMBOL_VISIBLE placeholder + { + public: // structors + + virtual ~placeholder() + { + } + + public: // queries + + virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0; + + virtual placeholder * clone() const = 0; + + }; + + template + class holder : public placeholder + { + public: // structors + + holder(const ValueType & value) + : held(value) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + holder(ValueType&& value) + : held(static_cast< ValueType&& >(value)) + { + } +#endif + public: // queries + + virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT + { + return boost::typeindex::type_id().type_info(); + } + + virtual placeholder * clone() const + { + return new holder(held); + } + + public: // representation + + ValueType held; + + private: // intentionally left unimplemented + holder & operator=(const holder &); + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + + private: // representation + + template + friend ValueType * any_cast(any *) BOOST_NOEXCEPT; + + template + friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; + +#else + + public: // representation (public so any_cast can be non-friend) + +#endif + + placeholder * content; + + }; + + inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + class BOOST_SYMBOL_VISIBLE bad_any_cast : +#ifndef BOOST_NO_RTTI + public std::bad_cast +#else + public std::exception +#endif + { + public: + virtual const char * what() const BOOST_NOEXCEPT_OR_NOTHROW + { + return "boost::bad_any_cast: " + "failed conversion using boost::any_cast"; + } + }; + + template + ValueType * any_cast(any * operand) BOOST_NOEXCEPT + { + return operand && operand->type() == boost::typeindex::type_id() + ? boost::addressof( + static_cast::type> *>(operand->content)->held + ) + : 0; + } + + template + inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT + { + return any_cast(const_cast(operand)); + } + + template + ValueType any_cast(any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + + + nonref * result = any_cast(boost::addressof(operand)); + if(!result) + boost::throw_exception(bad_any_cast()); + + // Attempt to avoid construction of a temporary object in cases when + // `ValueType` is not a reference. Example: + // `static_cast(*result);` + // which is equal to `std::string(*result);` + typedef BOOST_DEDUCED_TYPENAME boost::conditional< + boost::is_reference::value, + ValueType, + BOOST_DEDUCED_TYPENAME boost::add_reference::type + >::type ref_type; + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local! +#endif + return static_cast(*result); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif + } + + template + inline ValueType any_cast(const any & operand) + { + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + return any_cast(const_cast(operand)); + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + template + inline ValueType any_cast(any&& operand) + { + BOOST_STATIC_ASSERT_MSG( + boost::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ + || boost::is_const< typename boost::remove_reference::type >::value, + "boost::any_cast shall not be used for getting nonconst references to temporary objects" + ); + return any_cast(operand); + } +#endif + + + // Note: The "unsafe" versions of any_cast are not part of the + // public interface and may be removed at any time. They are + // required where we know what type is stored in the any and can't + // use typeid() comparison, e.g., when our types may travel across + // different shared libraries. + template + inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT + { + return boost::addressof( + static_cast *>(operand->content)->held + ); + } + + template + inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT + { + return unsafe_any_cast(const_cast(operand)); + } +} + +// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +// Copyright Antony Polukhin, 2013-2019. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#endif diff --git a/third-party/boost/boost/array.hpp b/third-party/boost/boost/array.hpp new file mode 100644 index 000000000..99dc2c6de --- /dev/null +++ b/third-party/boost/boost/array.hpp @@ -0,0 +1,457 @@ +/* The following code declares class array, + * an STL container (as wrapper) for arrays of constant size. + * + * See + * http://www.boost.org/libs/array/ + * for documentation. + * + * The original author site is at: http://www.josuttis.com/ + * + * (C) Copyright Nicolai M. Josuttis 2001. + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * 9 Jan 2013 - (mtc) Added constexpr + * 14 Apr 2012 - (mtc) Added support for boost::hash + * 28 Dec 2010 - (mtc) Added cbegin and cend (and crbegin and crend) for C++Ox compatibility. + * 10 Mar 2010 - (mtc) fill method added, matching resolution of the standard library working group. + * See or Trac issue #3168 + * Eventually, we should remove "assign" which is now a synonym for "fill" (Marshall Clow) + * 10 Mar 2010 - added workaround for SUNCC and !STLPort [trac #3893] (Marshall Clow) + * 29 Jan 2004 - c_array() added, BOOST_NO_PRIVATE_IN_AGGREGATE removed (Nico Josuttis) + * 23 Aug 2002 - fix for Non-MSVC compilers combined with MSVC libraries. + * 05 Aug 2001 - minor update (Nico Josuttis) + * 20 Jan 2001 - STLport fix (Beman Dawes) + * 29 Sep 2000 - Initial Revision (Nico Josuttis) + * + * Jan 29, 2004 + */ +#ifndef BOOST_ARRAY_HPP +#define BOOST_ARRAY_HPP + +#include + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +# pragma warning(push) +# pragma warning(disable:4996) // 'std::equal': Function call with parameters that may be unsafe +# pragma warning(disable:4510) // boost::array' : default constructor could not be generated +# pragma warning(disable:4610) // warning C4610: class 'boost::array' can never be instantiated - user defined constructor required +#endif + +#include +#include +#include +#include +#include + +// Handles broken standard libraries better than +#include +#include +#include + +// FIXES for broken compilers +#include + + +namespace boost { + + template + class array { + public: + T elems[N]; // fixed-size array of elements of type T + + public: + // type definitions + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // iterator support + iterator begin() { return elems; } + const_iterator begin() const { return elems; } + const_iterator cbegin() const { return elems; } + + iterator end() { return elems+N; } + const_iterator end() const { return elems+N; } + const_iterator cend() const { return elems+N; } + + // reverse iterator support +#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type i) + { + return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i]; + } + + /*BOOST_CONSTEXPR*/ const_reference operator[](size_type i) const + { + return BOOST_ASSERT_MSG( i < N, "out of range" ), elems[i]; + } + + // at() with range check + reference at(size_type i) { return rangecheck(i), elems[i]; } + /*BOOST_CONSTEXPR*/ const_reference at(size_type i) const { return rangecheck(i), elems[i]; } + + // front() and back() + reference front() + { + return elems[0]; + } + + BOOST_CONSTEXPR const_reference front() const + { + return elems[0]; + } + + reference back() + { + return elems[N-1]; + } + + BOOST_CONSTEXPR const_reference back() const + { + return elems[N-1]; + } + + // size is constant + static BOOST_CONSTEXPR size_type size() { return N; } + static BOOST_CONSTEXPR bool empty() { return false; } + static BOOST_CONSTEXPR size_type max_size() { return N; } + enum { static_size = N }; + + // swap (note: linear complexity) + void swap (array& y) { + for (size_type i = 0; i < N; ++i) + boost::swap(elems[i],y.elems[i]); + } + + // direct access to data (read-only) + const T* data() const { return elems; } + T* data() { return elems; } + + // use array as C array (direct read/write access to data) + T* c_array() { return elems; } + + // assignment with type conversion + template + array& operator= (const array& rhs) { + std::copy(rhs.begin(),rhs.end(), begin()); + return *this; + } + + // assign one value to all elements + void assign (const T& value) { fill ( value ); } // A synonym for fill + void fill (const T& value) + { + std::fill_n(begin(),size(),value); + } + + // check range (may be private because it is static) + static BOOST_CONSTEXPR bool rangecheck (size_type i) { + return i >= size() ? boost::throw_exception(std::out_of_range ("array<>: index out of range")), true : true; + } + + }; + + template< class T > + class array< T, 0 > { + + public: + // type definitions + typedef T value_type; + typedef T* iterator; + typedef const T* const_iterator; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + // iterator support + iterator begin() { return iterator( reinterpret_cast< T * >( this ) ); } + const_iterator begin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); } + const_iterator cbegin() const { return const_iterator( reinterpret_cast< const T * >( this ) ); } + + iterator end() { return begin(); } + const_iterator end() const { return begin(); } + const_iterator cend() const { return cbegin(); } + + // reverse iterator support +#if !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#else + // workaround for broken reverse_iterator implementations + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; +#endif + + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const { + return const_reverse_iterator(end()); + } + const_reverse_iterator crbegin() const { + return const_reverse_iterator(end()); + } + + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crend() const { + return const_reverse_iterator(begin()); + } + + // operator[] + reference operator[](size_type /*i*/) + { + return failed_rangecheck(); + } + + /*BOOST_CONSTEXPR*/ const_reference operator[](size_type /*i*/) const + { + return failed_rangecheck(); + } + + // at() with range check + reference at(size_type /*i*/) { return failed_rangecheck(); } + /*BOOST_CONSTEXPR*/ const_reference at(size_type /*i*/) const { return failed_rangecheck(); } + + // front() and back() + reference front() + { + return failed_rangecheck(); + } + + BOOST_CONSTEXPR const_reference front() const + { + return failed_rangecheck(); + } + + reference back() + { + return failed_rangecheck(); + } + + BOOST_CONSTEXPR const_reference back() const + { + return failed_rangecheck(); + } + + // size is constant + static BOOST_CONSTEXPR size_type size() { return 0; } + static BOOST_CONSTEXPR bool empty() { return true; } + static BOOST_CONSTEXPR size_type max_size() { return 0; } + enum { static_size = 0 }; + + void swap (array& /*y*/) { + } + + // direct access to data (read-only) + const T* data() const { return 0; } + T* data() { return 0; } + + // use array as C array (direct read/write access to data) + T* c_array() { return 0; } + + // assignment with type conversion + template + array& operator= (const array& ) { + return *this; + } + + // assign one value to all elements + void assign (const T& value) { fill ( value ); } + void fill (const T& ) {} + + // check range (may be private because it is static) + static reference failed_rangecheck () { + std::out_of_range e("attempt to access element of an empty array"); + boost::throw_exception(e); +#if defined(BOOST_NO_EXCEPTIONS) || (!defined(BOOST_MSVC) && !defined(__PATHSCALE__)) + // + // We need to return something here to keep + // some compilers happy: however we will never + // actually get here.... + // + static T placeholder; + return placeholder; +#endif + } + }; + + // comparisons + template + bool operator== (const array& x, const array& y) { + return std::equal(x.begin(), x.end(), y.begin()); + } + template + bool operator< (const array& x, const array& y) { + return std::lexicographical_compare(x.begin(),x.end(),y.begin(),y.end()); + } + template + bool operator!= (const array& x, const array& y) { + return !(x==y); + } + template + bool operator> (const array& x, const array& y) { + return y + bool operator<= (const array& x, const array& y) { + return !(y + bool operator>= (const array& x, const array& y) { + return !(x + inline void swap (array& x, array& y) { + x.swap(y); + } + +#if defined(__SUNPRO_CC) +// Trac ticket #4757; the Sun Solaris compiler can't handle +// syntax like 'T(&get_c_array(boost::array& arg))[N]' +// +// We can't just use this for all compilers, because the +// borland compilers can't handle this form. + namespace detail { + template struct c_array + { + typedef T type[N]; + }; + } + + // Specific for boost::array: simply returns its elems data member. + template + typename detail::c_array::type& get_c_array(boost::array& arg) + { + return arg.elems; + } + + // Specific for boost::array: simply returns its elems data member. + template + typename detail::c_array::type const& get_c_array(const boost::array& arg) + { + return arg.elems; + } +#else +// Specific for boost::array: simply returns its elems data member. + template + T(&get_c_array(boost::array& arg))[N] + { + return arg.elems; + } + + // Const version. + template + const T(&get_c_array(const boost::array& arg))[N] + { + return arg.elems; + } +#endif + +#if 0 + // Overload for std::array, assuming that std::array will have + // explicit conversion functions as discussed at the WG21 meeting + // in Summit, March 2009. + template + T(&get_c_array(std::array& arg))[N] + { + return static_cast(arg); + } + + // Const version. + template + const T(&get_c_array(const std::array& arg))[N] + { + return static_cast(arg); + } +#endif + + template std::size_t hash_range(It, It); + + template + std::size_t hash_value(const array& arr) + { + return boost::hash_range(arr.begin(), arr.end()); + } + + template + T &get(boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(boost::array &) index out of range" ); + return arr[Idx]; + } + + template + const T &get(const boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "boost::get<>(const boost::array &) index out of range" ); + return arr[Idx]; + } + +} /* namespace boost */ + +#ifndef BOOST_NO_CXX11_HDR_ARRAY +// If we don't have std::array, I'm assuming that we don't have std::get +namespace std { + template + T &get(boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(boost::array &) index out of range" ); + return arr[Idx]; + } + + template + const T &get(const boost::array &arr) BOOST_NOEXCEPT { + BOOST_STATIC_ASSERT_MSG ( Idx < N, "std::get<>(const boost::array &) index out of range" ); + return arr[Idx]; + } +} +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, >= 1400) +# pragma warning(pop) +#endif + +#endif /*BOOST_ARRAY_HPP*/ diff --git a/third-party/boost/boost/asio.hpp b/third-party/boost/boost/asio.hpp new file mode 100644 index 000000000..1ee7e12f2 --- /dev/null +++ b/third-party/boost/boost/asio.hpp @@ -0,0 +1,146 @@ +// +// asio.hpp +// ~~~~~~~~ +// +// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See www.boost.org/libs/asio for documentation. +// + +#ifndef BOOST_ASIO_HPP +#define BOOST_ASIO_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1200) +# pragma once +#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_ASIO_HPP diff --git a/third-party/boost/boost/assert.hpp b/third-party/boost/boost/assert.hpp new file mode 100644 index 000000000..9650d7a29 --- /dev/null +++ b/third-party/boost/boost/assert.hpp @@ -0,0 +1,85 @@ +// +// boost/assert.hpp - BOOST_ASSERT(expr) +// BOOST_ASSERT_MSG(expr, msg) +// BOOST_VERIFY(expr) +// BOOST_VERIFY_MSG(expr, msg) +// BOOST_ASSERT_IS_VOID +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2007, 2014 Peter Dimov +// Copyright (c) Beman Dawes 2011 +// Copyright (c) 2015 Ion Gaztanaga +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// Note: There are no include guards. This is intentional. +// +// See http://www.boost.org/libs/assert/assert.html for documentation. +// + +// +// Stop inspect complaining about use of 'assert': +// +// boostinspect:naassert_macro +// + +// +// BOOST_ASSERT, BOOST_ASSERT_MSG, BOOST_ASSERT_IS_VOID +// + +#undef BOOST_ASSERT +#undef BOOST_ASSERT_MSG +#undef BOOST_ASSERT_IS_VOID + +#if defined(BOOST_DISABLE_ASSERTS) || ( defined(BOOST_ENABLE_ASSERT_DEBUG_HANDLER) && defined(NDEBUG) ) + +# define BOOST_ASSERT(expr) ((void)0) +# define BOOST_ASSERT_MSG(expr, msg) ((void)0) +# define BOOST_ASSERT_IS_VOID + +#elif defined(BOOST_ENABLE_ASSERT_HANDLER) || ( defined(BOOST_ENABLE_ASSERT_DEBUG_HANDLER) && !defined(NDEBUG) ) + +#include // for BOOST_LIKELY +#include + +namespace boost +{ + void assertion_failed(char const * expr, char const * function, char const * file, long line); // user defined + void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line); // user defined +} // namespace boost + +#define BOOST_ASSERT(expr) (BOOST_LIKELY(!!(expr))? ((void)0): ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) +#define BOOST_ASSERT_MSG(expr, msg) (BOOST_LIKELY(!!(expr))? ((void)0): ::boost::assertion_failed_msg(#expr, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) + +#else + +# include // .h to support old libraries w/o - effect is the same + +# define BOOST_ASSERT(expr) assert(expr) +# define BOOST_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) +#if defined(NDEBUG) +# define BOOST_ASSERT_IS_VOID +#endif + +#endif + +// +// BOOST_VERIFY, BOOST_VERIFY_MSG +// + +#undef BOOST_VERIFY +#undef BOOST_VERIFY_MSG + +#if defined(BOOST_DISABLE_ASSERTS) || ( !defined(BOOST_ENABLE_ASSERT_HANDLER) && defined(NDEBUG) ) + +# define BOOST_VERIFY(expr) ((void)(expr)) +# define BOOST_VERIFY_MSG(expr, msg) ((void)(expr)) + +#else + +# define BOOST_VERIFY(expr) BOOST_ASSERT(expr) +# define BOOST_VERIFY_MSG(expr, msg) BOOST_ASSERT_MSG(expr,msg) + +#endif diff --git a/third-party/boost/boost/assign.hpp b/third-party/boost/boost/assign.hpp new file mode 100644 index 000000000..fffb7ecee --- /dev/null +++ b/third-party/boost/boost/assign.hpp @@ -0,0 +1,24 @@ +// Boost.Assign library +// +// Copyright Thorsten Ottosen 2003-2004. Use, modification and +// distribution is subject to the Boost Software License, Version +// 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// For more information, see http://www.boost.org/libs/assign/ +// + + +#ifndef BOOST_ASSIGN_HPP +#define BOOST_ASSIGN_HPP + +#if defined(_MSC_VER) +# pragma once +#endif + +#include +#include +#include +#include + +#endif diff --git a/third-party/boost/boost/atomic.hpp b/third-party/boost/boost/atomic.hpp new file mode 100644 index 000000000..cc28b1ab5 --- /dev/null +++ b/third-party/boost/boost/atomic.hpp @@ -0,0 +1,18 @@ +#ifndef BOOST_ATOMIC_HPP +#define BOOST_ATOMIC_HPP + +// Copyright (c) 2011 Helge Bahmann +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// This header includes all Boost.Atomic public headers + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif diff --git a/third-party/boost/boost/atomic/atomic.hpp b/third-party/boost/boost/atomic/atomic.hpp new file mode 100644 index 000000000..5a8058829 --- /dev/null +++ b/third-party/boost/boost/atomic/atomic.hpp @@ -0,0 +1,104 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/atomic.hpp + * + * This header contains definition of \c atomic template and \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +using atomics::atomic; + +using atomics::atomic_char; +using atomics::atomic_uchar; +using atomics::atomic_schar; +using atomics::atomic_uint8_t; +using atomics::atomic_int8_t; +using atomics::atomic_ushort; +using atomics::atomic_short; +using atomics::atomic_uint16_t; +using atomics::atomic_int16_t; +using atomics::atomic_uint; +using atomics::atomic_int; +using atomics::atomic_uint32_t; +using atomics::atomic_int32_t; +using atomics::atomic_ulong; +using atomics::atomic_long; +using atomics::atomic_uint64_t; +using atomics::atomic_int64_t; +#ifdef BOOST_HAS_LONG_LONG +using atomics::atomic_ullong; +using atomics::atomic_llong; +#endif +using atomics::atomic_address; +using atomics::atomic_bool; +using atomics::atomic_wchar_t; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +using atomics::atomic_char16_t; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +using atomics::atomic_char32_t; +#endif + +using atomics::atomic_int_least8_t; +using atomics::atomic_uint_least8_t; +using atomics::atomic_int_least16_t; +using atomics::atomic_uint_least16_t; +using atomics::atomic_int_least32_t; +using atomics::atomic_uint_least32_t; +using atomics::atomic_int_least64_t; +using atomics::atomic_uint_least64_t; +using atomics::atomic_int_fast8_t; +using atomics::atomic_uint_fast8_t; +using atomics::atomic_int_fast16_t; +using atomics::atomic_uint_fast16_t; +using atomics::atomic_int_fast32_t; +using atomics::atomic_uint_fast32_t; +using atomics::atomic_int_fast64_t; +using atomics::atomic_uint_fast64_t; +using atomics::atomic_intmax_t; +using atomics::atomic_uintmax_t; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +using atomics::atomic_float_t; +using atomics::atomic_double_t; +using atomics::atomic_long_double_t; +#endif + +using atomics::atomic_size_t; +using atomics::atomic_ptrdiff_t; + +#if defined(BOOST_HAS_INTPTR_T) +using atomics::atomic_intptr_t; +using atomics::atomic_uintptr_t; +#endif + +} // namespace boost + +#endif // BOOST_ATOMIC_ATOMIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/atomic_flag.hpp b/third-party/boost/boost/atomic/atomic_flag.hpp new file mode 100644 index 000000000..ac296bcc8 --- /dev/null +++ b/third-party/boost/boost/atomic/atomic_flag.hpp @@ -0,0 +1,33 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/atomic_flag.hpp + * + * This header contains definition of \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ +#define BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +using atomics::atomic_flag; + +} // namespace boost + +#endif // BOOST_ATOMIC_ATOMIC_FLAG_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/capabilities.hpp b/third-party/boost/boost/atomic/capabilities.hpp new file mode 100644 index 000000000..5c7434d9b --- /dev/null +++ b/third-party/boost/boost/atomic/capabilities.hpp @@ -0,0 +1,210 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/capabilities.hpp + * + * This header defines feature capabilities macros. + */ + +#ifndef BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ +#define BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ + +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#endif + +#if !defined(BOOST_ATOMIC_EMULATED) +#include BOOST_ATOMIC_DETAIL_BACKEND_HEADER(boost/atomic/detail/caps_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#ifndef BOOST_ATOMIC_INT8_LOCK_FREE +#define BOOST_ATOMIC_INT8_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT16_LOCK_FREE +#define BOOST_ATOMIC_INT16_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_INT32_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT64_LOCK_FREE +#define BOOST_ATOMIC_INT64_LOCK_FREE 0 +#endif + +#ifndef BOOST_ATOMIC_INT128_LOCK_FREE +#define BOOST_ATOMIC_INT128_LOCK_FREE 0 +#endif + + +#ifndef BOOST_ATOMIC_CHAR_LOCK_FREE +#define BOOST_ATOMIC_CHAR_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_CHAR16_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_CHAR32_T_LOCK_FREE +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_WCHAR_T_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_SHORT_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_SHORT_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_INT_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_INT_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_LONG_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_LONG_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_LLONG_LOCK_FREE +#if BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE 0 +#endif +#endif + +#ifndef BOOST_ATOMIC_POINTER_LOCK_FREE +#if (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 8 +#define BOOST_ATOMIC_POINTER_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_POINTER + 0) == 4 +#define BOOST_ATOMIC_POINTER_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#else +#define BOOST_ATOMIC_POINTER_LOCK_FREE 0 +#endif +#endif + +#define BOOST_ATOMIC_ADDRESS_LOCK_FREE BOOST_ATOMIC_POINTER_LOCK_FREE + +#ifndef BOOST_ATOMIC_BOOL_LOCK_FREE +// We store bools in 1-byte storage in all backends +#define BOOST_ATOMIC_BOOL_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#endif + +#ifndef BOOST_ATOMIC_FLAG_LOCK_FREE +#define BOOST_ATOMIC_FLAG_LOCK_FREE BOOST_ATOMIC_BOOL_LOCK_FREE +#endif + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#if !defined(BOOST_ATOMIC_FLOAT_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) +#if BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 2 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 4 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 8 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT == 16 +#define BOOST_ATOMIC_FLOAT_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_FLOAT_LOCK_FREE 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 2 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 4 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 8 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE == 16 +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_DOUBLE_LOCK_FREE 0 +#endif +#endif + +#if !defined(BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#if BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 2 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 4 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 8 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE == 16 +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#else +#define BOOST_ATOMIC_LONG_DOUBLE_LOCK_FREE 0 +#endif +#endif + +#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +#ifndef BOOST_ATOMIC_THREAD_FENCE +#define BOOST_ATOMIC_THREAD_FENCE 0 +#endif + +#ifndef BOOST_ATOMIC_SIGNAL_FENCE +#define BOOST_ATOMIC_SIGNAL_FENCE 0 +#endif + +#endif // BOOST_ATOMIC_CAPABILITIES_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/addressof.hpp b/third-party/boost/boost/atomic/detail/addressof.hpp new file mode 100644 index 000000000..38e876e31 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/addressof.hpp @@ -0,0 +1,58 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/addressof.hpp + * + * This header defines \c addressof helper function. It is similar to \c boost::addressof but it is more + * lightweight and also contains a workaround for some compiler warnings. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Detection logic is based on boost/core/addressof.hpp +#if defined(BOOST_MSVC_FULL_VER) && BOOST_MSVC_FULL_VER >= 190024215 +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#elif defined(BOOST_GCC) && BOOST_GCC >= 70000 +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#elif defined(__has_builtin) +#if __has_builtin(__builtin_addressof) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +BOOST_FORCEINLINE T* addressof(T& value) BOOST_NOEXCEPT +{ +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_ADDRESSOF) + return __builtin_addressof(value); +#else + // Note: The point of using a local struct as the intermediate type instead of char is to avoid gcc warnings + // if T is a const volatile char*: + // warning: casting 'const volatile char* const' to 'const volatile char&' does not dereference pointer + // The local struct makes sure T is not related to the cast target type. + struct opaque_type; + return reinterpret_cast< T* >(&const_cast< opaque_type& >(reinterpret_cast< const volatile opaque_type& >(value))); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_ADDRESSOF_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/atomic_flag.hpp b/third-party/boost/boost/atomic/detail/atomic_flag.hpp new file mode 100644 index 000000000..6f5fc8acc --- /dev/null +++ b/third-party/boost/boost/atomic/detail/atomic_flag.hpp @@ -0,0 +1,71 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/atomic_flag.hpp + * + * This header contains interface definition of \c atomic_flag. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { +namespace atomics { + +#if defined(BOOST_NO_CXX11_CONSTEXPR) || defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) +#define BOOST_ATOMIC_NO_ATOMIC_FLAG_INIT +#else +#define BOOST_ATOMIC_FLAG_INIT {} +#endif + +struct atomic_flag +{ + typedef atomics::detail::operations< 1u, false > operations; + typedef operations::storage_type storage_type; + + operations::aligned_storage_type m_storage; + + BOOST_FORCEINLINE BOOST_CONSTEXPR atomic_flag() BOOST_NOEXCEPT : m_storage(0) + { + } + + BOOST_FORCEINLINE bool test_and_set(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return operations::test_and_set(m_storage.value, order); + } + + BOOST_FORCEINLINE void clear(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + operations::clear(m_storage.value, order); + } + + BOOST_DELETED_FUNCTION(atomic_flag(atomic_flag const&)) + BOOST_DELETED_FUNCTION(atomic_flag& operator= (atomic_flag const&)) +}; + +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_ATOMIC_FLAG_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/atomic_template.hpp b/third-party/boost/boost/atomic/detail/atomic_template.hpp new file mode 100644 index 000000000..fb0a8f58f --- /dev/null +++ b/third-party/boost/boost/atomic/detail/atomic_template.hpp @@ -0,0 +1,1248 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/atomic_template.hpp + * + * This header contains interface definition of \c atomic template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +#include +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// 'boost::atomics::atomic' : multiple assignment operators specified +#pragma warning(disable: 4522) +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { +namespace atomics { +namespace detail { + +BOOST_FORCEINLINE BOOST_CONSTEXPR memory_order deduce_failure_order(memory_order order) BOOST_NOEXCEPT +{ + return order == memory_order_acq_rel ? memory_order_acquire : (order == memory_order_release ? memory_order_relaxed : order); +} + +BOOST_FORCEINLINE BOOST_CONSTEXPR bool cas_failure_order_must_not_be_stronger_than_success_order(memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT +{ + // 15 == (memory_order_seq_cst | memory_order_consume), see memory_order.hpp + // Given the enum values we can test the strength of memory order requirements with this single condition. + return (static_cast< unsigned int >(failure_order) & 15u) <= (static_cast< unsigned int >(success_order) & 15u); +} + +template< typename T, bool IsFunction = atomics::detail::is_function< T >::value > +struct classify_pointer +{ + typedef void* type; +}; + +template< typename T > +struct classify_pointer< T, true > +{ + typedef void type; +}; + +template< typename T, bool IsInt = atomics::detail::is_integral< T >::value, bool IsFloat = atomics::detail::is_floating_point< T >::value > +struct classify +{ + typedef void type; +}; + +template< typename T > +struct classify< T, true, false > { typedef int type; }; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +template< typename T > +struct classify< T, false, true > { typedef float type; }; +#endif + +template< typename T > +struct classify< T*, false, false > { typedef typename classify_pointer< T >::type type; }; + +template< > +struct classify< void*, false, false > { typedef void type; }; + +template< > +struct classify< const void*, false, false > { typedef void type; }; + +template< > +struct classify< volatile void*, false, false > { typedef void type; }; + +template< > +struct classify< const volatile void*, false, false > { typedef void type; }; + +template< typename T, typename U > +struct classify< T U::*, false, false > { typedef void type; }; + + +#if defined(BOOST_INTEL) || (defined(BOOST_GCC) && (BOOST_GCC+0) < 40700) ||\ + (defined(BOOST_CLANG) && !defined(__apple_build_version__) && ((__clang_major__+0) * 100 + (__clang_minor__+0)) < 302) ||\ + (defined(__clang__) && defined(__apple_build_version__) && ((__clang_major__+0) * 100 + (__clang_minor__+0)) < 402) +// Intel compiler (at least 18.0 update 1) breaks if noexcept specification is used in defaulted function declarations: +// error: the default constructor of "boost::atomics::atomic" cannot be referenced -- it is a deleted function +// GCC 4.6 doesn't seem to support that either. Clang 3.1 deduces wrong noexcept for the defaulted function and fails as well. +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL BOOST_NOEXCEPT +#else +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL BOOST_NOEXCEPT +#define BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL +#endif + +template< typename T, bool IsTriviallyDefaultConstructible = atomics::detail::is_trivially_default_constructible< T >::value > +class base_atomic_generic; + +template< typename T > +class base_atomic_generic< T, true > +{ +public: + typedef T value_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic_generic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic_generic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v)) + { + } +}; + +template< typename T > +class base_atomic_generic< T, false > +{ +public: + typedef T value_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef typename atomics::detail::conditional< sizeof(value_type) <= sizeof(void*), value_type, value_type const& >::type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_FORCEINLINE explicit base_atomic_generic(value_arg_type v = value_type()) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< storage_type >(v)) + { + } +}; + + +template< typename T, typename Kind > +class base_atomic; + +//! General template. Implementation for user-defined types, such as structs and enums, and pointers to non-object types +template< typename T > +class base_atomic< T, void > : + public base_atomic_generic< T > +{ +private: + typedef base_atomic_generic< T > base_type; + +public: + typedef typename base_type::value_type value_type; + typedef typename base_type::storage_type storage_type; + +protected: + typedef typename base_type::operations operations; + typedef typename base_type::value_arg_type value_arg_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) + { + } + + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(this->m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_cast< value_type >(operations::load(this->m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(operations::exchange(this->m_storage.value, atomics::detail::bitwise_cast< storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(this->m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(this->m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(this->m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(this->m_storage.value, old_value, atomics::detail::bitwise_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(old_value); + return res; + } +}; + + +//! Implementation for integers +template< typename T > +class base_atomic< T, int > +{ +public: + typedef T value_type; + typedef T difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, atomics::detail::is_signed< T >::value > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(v) {} + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::integral_truncate< value_type >(operations::load(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::exchange(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE value_type fetch_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type fetch_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(operations::fetch_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_negate(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::fetch_complement(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::negate(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type bitwise_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order)); + } + + BOOST_FORCEINLINE value_type bitwise_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::integral_truncate< value_type >(extra_operations::bitwise_complement(m_storage.value, order)); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_add(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_sub(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_negate(m_storage.value, order); + } + + BOOST_FORCEINLINE void opaque_and(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_and(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_or(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_or(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_xor(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_xor(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE void opaque_complement(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_complement(m_storage.value, order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::add_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::sub_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE bool negate_and_test(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::negate_and_test(m_storage.value, order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool and_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::and_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool or_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::or_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool xor_and_test(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::xor_and_test(m_storage.value, atomics::detail::integral_extend< operations::is_signed, storage_type >(v), order); + } + + BOOST_FORCEINLINE bool complement_and_test(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::complement_and_test(m_storage.value, order); + } + + BOOST_FORCEINLINE bool bit_test_and_set(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_set(m_storage.value, bit_number, order); + } + + BOOST_FORCEINLINE bool bit_test_and_reset(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_reset(m_storage.value, bit_number, order); + } + + BOOST_FORCEINLINE bool bit_test_and_complement(unsigned int bit_number, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(bit_number < sizeof(value_type) * 8u); + return extra_operations::bit_test_and_complement(m_storage.value, bit_number, order); + } + + // Operators + BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT + { + return fetch_add(1); + } + + BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT + { + return add(1); + } + + BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT + { + return fetch_sub(1); + } + + BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT + { + return sub(1); + } + + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_FORCEINLINE value_type operator&=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_and(v); + } + + BOOST_FORCEINLINE value_type operator|=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_or(v); + } + + BOOST_FORCEINLINE value_type operator^=(value_type v) volatile BOOST_NOEXCEPT + { + return bitwise_xor(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::integral_extend< operations::is_signed, storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); + expected = atomics::detail::integral_truncate< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::integral_extend< operations::is_signed, storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::integral_extend< operations::is_signed, storage_type >(desired), success_order, failure_order); + expected = atomics::detail::integral_truncate< value_type >(old_value); + return res; + } +}; + +//! Implementation for bool +template< > +class base_atomic< bool, int > +{ +public: + typedef bool value_type; + +protected: + typedef atomics::detail::operations< 1u, false > operations; + typedef value_type value_arg_type; + +public: + typedef operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + +protected: + operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(v) {} + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, static_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return !!operations::load(m_storage.value, order); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return !!operations::exchange(m_storage.value, static_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = static_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order); + expected = !!old_value; + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), static_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = static_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, static_cast< storage_type >(desired), success_order, failure_order); + expected = !!old_value; + return res; + } +}; + + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + +//! Implementation for floating point types +template< typename T > +class base_atomic< T, float > +{ +public: + typedef T value_type; + typedef T difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef atomics::detail::fp_operations< extra_operations, value_type, operations::storage_size > fp_operations; + typedef atomics::detail::extra_fp_operations< fp_operations, value_type, operations::storage_size > extra_fp_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, atomics::detail::value_sizeof< value_type >::value == sizeof(storage_type) > value_matches_storage; + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_fp_cast< storage_type >(v)) {} + + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_fp_cast< value_type >(operations::load(m_storage.value, order)); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return fp_operations::fetch_add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return fp_operations::fetch_sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type exchange(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_fp_cast< storage_type >(v), order)); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type fetch_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::fetch_negate(m_storage.value, order); + } + + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE value_type negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_fp_operations::negate(m_storage.value, order); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_add(m_storage.value, v, order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_sub(m_storage.value, v, order); + } + + BOOST_FORCEINLINE void opaque_negate(memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_fp_operations::opaque_negate(m_storage.value, order); + } + + // Operators + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_fp_cast< storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_fp_cast< storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_fp_cast< value_type >(old_value); + return res; + } +}; + +#endif // !defined(BOOST_ATOMIC_NO_FLOATING_POINT) + + +//! Implementation for pointers to object types +template< typename T > +class base_atomic< T*, void* > +{ +public: + typedef T* value_type; + typedef std::ptrdiff_t difference_type; + +protected: + typedef atomics::detail::operations< storage_size_of< value_type >::value, false > operations; + typedef atomics::detail::extra_operations< operations, operations::storage_size, operations::is_signed > extra_operations; + typedef value_type value_arg_type; + +public: + typedef typename operations::storage_type storage_type; + +private: + typedef atomics::detail::integral_constant< bool, sizeof(value_type) == sizeof(storage_type) > value_matches_storage; + + // uintptr_storage_type is the minimal storage type that is enough to store pointers. The actual storage_type theoretically may be larger, + // if the target architecture only supports atomic ops on larger data. Typically, though, they are the same type. +#if defined(BOOST_HAS_INTPTR_T) + typedef uintptr_t uintptr_storage_type; +#else + typedef typename atomics::detail::make_storage_type< sizeof(value_type) >::type uintptr_storage_type; +#endif + +protected: + typename operations::aligned_storage_type m_storage; + +public: + BOOST_DEFAULTED_FUNCTION(base_atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE explicit base_atomic(value_arg_type v) BOOST_NOEXCEPT : m_storage(atomics::detail::bitwise_cast< uintptr_storage_type >(v)) + { + } + + // Standard methods + BOOST_FORCEINLINE void store(value_arg_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_consume); + BOOST_ASSERT(order != memory_order_acquire); + BOOST_ASSERT(order != memory_order_acq_rel); + + operations::store(m_storage.value, atomics::detail::bitwise_cast< uintptr_storage_type >(v), order); + } + + BOOST_FORCEINLINE value_type load(memory_order order = memory_order_seq_cst) const volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(order != memory_order_release); + BOOST_ASSERT(order != memory_order_acq_rel); + + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::load(m_storage.value, order))); + } + + BOOST_FORCEINLINE value_type fetch_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type fetch_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::fetch_sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type exchange(value_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(operations::exchange(m_storage.value, atomics::detail::bitwise_cast< uintptr_storage_type >(v), order))); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_strong(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_strong(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order) volatile BOOST_NOEXCEPT + { + BOOST_ASSERT(failure_order != memory_order_release); + BOOST_ASSERT(failure_order != memory_order_acq_rel); + BOOST_ASSERT(cas_failure_order_must_not_be_stronger_than_success_order(success_order, failure_order)); + + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, value_matches_storage()); + } + + BOOST_FORCEINLINE bool compare_exchange_weak(value_type& expected, value_arg_type desired, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return compare_exchange_weak(expected, desired, order, atomics::detail::deduce_failure_order(order)); + } + + // Boost.Atomic extensions + BOOST_FORCEINLINE value_type add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE value_type sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(extra_operations::sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order))); + } + + BOOST_FORCEINLINE void opaque_add(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_add(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_FORCEINLINE void opaque_sub(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + extra_operations::opaque_sub(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool add_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::add_and_test(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST + BOOST_FORCEINLINE bool sub_and_test(difference_type v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT + { + return extra_operations::sub_and_test(m_storage.value, static_cast< uintptr_storage_type >(v * sizeof(T)), order); + } + + // Operators + BOOST_FORCEINLINE value_type operator++(int) volatile BOOST_NOEXCEPT + { + return fetch_add(1); + } + + BOOST_FORCEINLINE value_type operator++() volatile BOOST_NOEXCEPT + { + return add(1); + } + + BOOST_FORCEINLINE value_type operator--(int) volatile BOOST_NOEXCEPT + { + return fetch_sub(1); + } + + BOOST_FORCEINLINE value_type operator--() volatile BOOST_NOEXCEPT + { + return sub(1); + } + + BOOST_FORCEINLINE value_type operator+=(difference_type v) volatile BOOST_NOEXCEPT + { + return add(v); + } + + BOOST_FORCEINLINE value_type operator-=(difference_type v) volatile BOOST_NOEXCEPT + { + return sub(v); + } + + BOOST_DELETED_FUNCTION(base_atomic(base_atomic const&)) + BOOST_DELETED_FUNCTION(base_atomic& operator=(base_atomic const&)) + +private: + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_strong(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_strong_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_strong_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); + const bool res = operations::compare_exchange_strong(m_storage.value, old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); + return res; + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::true_type) volatile BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS) + return operations::compare_exchange_weak(m_storage.value, reinterpret_cast< storage_type& >(expected), atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); +#else + return compare_exchange_weak_impl(expected, desired, success_order, failure_order, atomics::detail::false_type()); +#endif + } + + BOOST_FORCEINLINE bool compare_exchange_weak_impl(value_type& expected, value_arg_type desired, memory_order success_order, memory_order failure_order, atomics::detail::false_type) volatile BOOST_NOEXCEPT + { + storage_type old_value = atomics::detail::bitwise_cast< uintptr_storage_type >(expected); + const bool res = operations::compare_exchange_weak(m_storage.value, old_value, atomics::detail::bitwise_cast< uintptr_storage_type >(desired), success_order, failure_order); + expected = atomics::detail::bitwise_cast< value_type >(static_cast< uintptr_storage_type >(old_value)); + return res; + } +}; + +} // namespace detail + +template< typename T > +class atomic : + public atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > +{ +private: + typedef atomics::detail::base_atomic< T, typename atomics::detail::classify< T >::type > base_type; + typedef typename base_type::value_arg_type value_arg_type; + +public: + typedef typename base_type::value_type value_type; + typedef typename base_type::storage_type storage_type; + +public: + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = base_type::operations::is_always_lock_free; + +public: + BOOST_DEFAULTED_FUNCTION(atomic() BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL, BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR atomic(value_arg_type v) BOOST_NOEXCEPT : base_type(v) {} + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE value_type operator= (value_arg_type v) volatile BOOST_NOEXCEPT + { + this->store(v); + return v; + } + + BOOST_FORCEINLINE operator value_type() const volatile BOOST_NOEXCEPT + { + return this->load(); + } + + BOOST_FORCEINLINE bool is_lock_free() const volatile BOOST_NOEXCEPT + { + // C++17 requires all instances of atomic<> return a value consistent with is_always_lock_free here + return is_always_lock_free; + } + + BOOST_FORCEINLINE storage_type& storage() BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type volatile& storage() volatile BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type const& storage() const BOOST_NOEXCEPT { return this->m_storage.value; } + BOOST_FORCEINLINE storage_type const volatile& storage() const volatile BOOST_NOEXCEPT { return this->m_storage.value; } + + BOOST_DELETED_FUNCTION(atomic(atomic const&)) + BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&)) + BOOST_DELETED_FUNCTION(atomic& operator= (atomic const&) volatile) +}; + +template< typename T > +BOOST_CONSTEXPR_OR_CONST bool atomic< T >::is_always_lock_free; + +#undef BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_DECL +#undef BOOST_ATOMIC_DETAIL_DEF_NOEXCEPT_IMPL + +typedef atomic< char > atomic_char; +typedef atomic< unsigned char > atomic_uchar; +typedef atomic< signed char > atomic_schar; +typedef atomic< uint8_t > atomic_uint8_t; +typedef atomic< int8_t > atomic_int8_t; +typedef atomic< unsigned short > atomic_ushort; +typedef atomic< short > atomic_short; +typedef atomic< uint16_t > atomic_uint16_t; +typedef atomic< int16_t > atomic_int16_t; +typedef atomic< unsigned int > atomic_uint; +typedef atomic< int > atomic_int; +typedef atomic< uint32_t > atomic_uint32_t; +typedef atomic< int32_t > atomic_int32_t; +typedef atomic< unsigned long > atomic_ulong; +typedef atomic< long > atomic_long; +typedef atomic< uint64_t > atomic_uint64_t; +typedef atomic< int64_t > atomic_int64_t; +#ifdef BOOST_HAS_LONG_LONG +typedef atomic< boost::ulong_long_type > atomic_ullong; +typedef atomic< boost::long_long_type > atomic_llong; +#endif +typedef atomic< void* > atomic_address; +typedef atomic< bool > atomic_bool; +typedef atomic< wchar_t > atomic_wchar_t; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +typedef atomic< char16_t > atomic_char16_t; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +typedef atomic< char32_t > atomic_char32_t; +#endif + +typedef atomic< int_least8_t > atomic_int_least8_t; +typedef atomic< uint_least8_t > atomic_uint_least8_t; +typedef atomic< int_least16_t > atomic_int_least16_t; +typedef atomic< uint_least16_t > atomic_uint_least16_t; +typedef atomic< int_least32_t > atomic_int_least32_t; +typedef atomic< uint_least32_t > atomic_uint_least32_t; +typedef atomic< int_least64_t > atomic_int_least64_t; +typedef atomic< uint_least64_t > atomic_uint_least64_t; +typedef atomic< int_fast8_t > atomic_int_fast8_t; +typedef atomic< uint_fast8_t > atomic_uint_fast8_t; +typedef atomic< int_fast16_t > atomic_int_fast16_t; +typedef atomic< uint_fast16_t > atomic_uint_fast16_t; +typedef atomic< int_fast32_t > atomic_int_fast32_t; +typedef atomic< uint_fast32_t > atomic_uint_fast32_t; +typedef atomic< int_fast64_t > atomic_int_fast64_t; +typedef atomic< uint_fast64_t > atomic_uint_fast64_t; +typedef atomic< intmax_t > atomic_intmax_t; +typedef atomic< uintmax_t > atomic_uintmax_t; + +#if !defined(BOOST_ATOMIC_NO_FLOATING_POINT) +typedef atomic< float > atomic_float_t; +typedef atomic< double > atomic_double_t; +typedef atomic< long double > atomic_long_double_t; +#endif + +typedef atomic< std::size_t > atomic_size_t; +typedef atomic< std::ptrdiff_t > atomic_ptrdiff_t; + +#if defined(BOOST_HAS_INTPTR_T) +typedef atomic< intptr_t > atomic_intptr_t; +typedef atomic< uintptr_t > atomic_uintptr_t; +#endif + +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_ATOMIC_TEMPLATE_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/bitwise_cast.hpp b/third-party/boost/boost/atomic/detail/bitwise_cast.hpp new file mode 100644 index 000000000..10d165e7c --- /dev/null +++ b/third-party/boost/boost/atomic/detail/bitwise_cast.hpp @@ -0,0 +1,68 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/bitwise_cast.hpp + * + * This header defines \c bitwise_cast used to convert between storage and value types + */ + +#ifndef BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t FromSize, typename To > +BOOST_FORCEINLINE void clear_padding(To& to, atomics::detail::true_type) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_MEMSET(reinterpret_cast< unsigned char* >(atomics::detail::addressof(to)) + FromSize, 0, sizeof(To) - FromSize); +} + +template< std::size_t FromSize, typename To > +BOOST_FORCEINLINE void clear_padding(To&, atomics::detail::false_type) BOOST_NOEXCEPT +{ +} + +template< typename To, std::size_t FromSize, typename From > +BOOST_FORCEINLINE To bitwise_cast(From const& from) BOOST_NOEXCEPT +{ + To to; + BOOST_ATOMIC_DETAIL_MEMCPY + ( + atomics::detail::addressof(to), + atomics::detail::addressof(from), + (FromSize < sizeof(To) ? FromSize : sizeof(To)) + ); + atomics::detail::clear_padding< FromSize >(to, atomics::detail::integral_constant< bool, FromSize < sizeof(To) >()); + return to; +} + +template< typename To, typename From > +BOOST_FORCEINLINE To bitwise_cast(From const& from) BOOST_NOEXCEPT +{ + return atomics::detail::bitwise_cast< To, sizeof(From) >(from); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_BITWISE_CAST_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/bitwise_fp_cast.hpp b/third-party/boost/boost/atomic/detail/bitwise_fp_cast.hpp new file mode 100644 index 000000000..a74b20b97 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/bitwise_fp_cast.hpp @@ -0,0 +1,86 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/bitwise_fp_cast.hpp + * + * This header defines \c bitwise_fp_cast used to convert between storage and floating point value types + */ + +#ifndef BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/*! + * \brief The type trait returns the size of the value of the specified floating point type + * + * This size may be less than sizeof(T) if the implementation uses padding bytes for a particular FP type. This is + * often the case with 80-bit extended double, which is stored in 12 or 16 bytes with padding filled with garbage. + */ +template< typename T > +struct value_sizeof +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = sizeof(T); +}; + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +template< > +struct value_sizeof< float > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE; +}; +#endif + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +template< > +struct value_sizeof< double > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE; +}; +#endif + +#if defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +template< > +struct value_sizeof< long double > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t value = BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE; +}; +#endif + +template< typename T > +struct value_sizeof< const T > : value_sizeof< T > {}; + +template< typename T > +struct value_sizeof< volatile T > : value_sizeof< T > {}; + +template< typename T > +struct value_sizeof< const volatile T > : value_sizeof< T > {}; + + +template< typename To, typename From > +BOOST_FORCEINLINE To bitwise_fp_cast(From const& from) BOOST_NOEXCEPT +{ + return atomics::detail::bitwise_cast< To, atomics::detail::value_sizeof< From >::value >(from); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_BITWISE_FP_CAST_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_alpha.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_alpha.hpp new file mode 100644 index 000000000..861432f58 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_alpha.hpp @@ -0,0 +1,34 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_alpha.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ALPHA_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_arm.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_arm.hpp new file mode 100644 index 000000000..a26ea56ee --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_arm.hpp @@ -0,0 +1,39 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * ARM Code by Phil Endecott, based on other architectures. + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_atomic.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_atomic.hpp new file mode 100644 index 000000000..3b518cf49 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_atomic.hpp @@ -0,0 +1,133 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_atomic.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#if defined(__i386__) || defined(__x86_64__) +#include +#elif defined(__arm__) +#include +#elif defined(__POWERPC__) || defined(__PPC__) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_INT128_LOCK_FREE 0 +#endif + +#if (__GCC_ATOMIC_LLONG_LOCK_FREE == 2) || (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) && BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8) +#define BOOST_ATOMIC_LLONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LLONG_LOCK_FREE BOOST_ATOMIC_INT128_LOCK_FREE +#endif + +#if (__GCC_ATOMIC_LONG_LOCK_FREE == 2) || (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) && BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8) +#define BOOST_ATOMIC_LONG_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_LONG_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#endif + +#if __GCC_ATOMIC_INT_LOCK_FREE == 2 +#define BOOST_ATOMIC_INT_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_INT_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#endif + +#if __GCC_ATOMIC_SHORT_LOCK_FREE == 2 +#define BOOST_ATOMIC_SHORT_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_SHORT_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#endif + +#if __GCC_ATOMIC_CHAR_LOCK_FREE == 2 +#define BOOST_ATOMIC_CHAR_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_CHAR_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#endif + +#if __GCC_ATOMIC_POINTER_LOCK_FREE == 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 +#else +#define BOOST_ATOMIC_POINTER_LOCK_FREE 0 +#endif + + +#define BOOST_ATOMIC_INT8_LOCK_FREE BOOST_ATOMIC_CHAR_LOCK_FREE + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT16_LOCK_FREE 0 +#endif + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 +#define BOOST_ATOMIC_INT32_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT32_LOCK_FREE 0 +#endif + +#if BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_SHORT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_INT_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_LONG_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 +#define BOOST_ATOMIC_INT64_LOCK_FREE BOOST_ATOMIC_LLONG_LOCK_FREE +#else +#define BOOST_ATOMIC_INT64_LOCK_FREE 0 +#endif + + +#if __GCC_ATOMIC_WCHAR_T_LOCK_FREE == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 2 +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT64_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE +#elif BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE BOOST_ATOMIC_INT8_LOCK_FREE +#else +#define BOOST_ATOMIC_WCHAR_T_LOCK_FREE 0 +#endif + +#define BOOST_ATOMIC_CHAR32_T_LOCK_FREE BOOST_ATOMIC_INT32_LOCK_FREE +#define BOOST_ATOMIC_CHAR16_T_LOCK_FREE BOOST_ATOMIC_INT16_LOCK_FREE + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_ATOMIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_ppc.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_ppc.hpp new file mode 100644 index 000000000..3e20fdee4 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_ppc.hpp @@ -0,0 +1,37 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_ppc.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_PPC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_sparc.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_sparc.hpp new file mode 100644 index 000000000..580668492 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_sparc.hpp @@ -0,0 +1,34 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2010 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_sparc.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_SPARC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_sync.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_sync.hpp new file mode 100644 index 000000000..ffbe605a1 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_sync.hpp @@ -0,0 +1,61 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_sync.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ + +#include +#if defined(__i386__) || defined(__x86_64__) +#include +#elif defined(__arm__) +#include +#elif defined(__POWERPC__) || defined(__PPC__) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8)\ + || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_SYNC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_gcc_x86.hpp b/third-party/boost/boost/atomic/detail/caps_gcc_x86.hpp new file mode 100644 index 000000000..70c64628a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_gcc_x86.hpp @@ -0,0 +1,40 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_gcc_x86.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#if defined(__x86_64__) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_GCC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_linux_arm.hpp b/third-party/boost/boost/atomic/detail/caps_linux_arm.hpp new file mode 100644 index 000000000..abe6fb81a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_linux_arm.hpp @@ -0,0 +1,35 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009, 2011 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * Linux-specific code by Phil Endecott + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_linux_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_LINUX_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_msvc_arm.hpp b/third-party/boost/boost/atomic/detail/caps_msvc_arm.hpp new file mode 100644 index 000000000..6b3c61fb3 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_msvc_arm.hpp @@ -0,0 +1,34 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_msvc_arm.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_msvc_x86.hpp b/third-party/boost/boost/atomic/detail/caps_msvc_x86.hpp new file mode 100644 index 000000000..2ee4c9211 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_msvc_x86.hpp @@ -0,0 +1,55 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_msvc_x86.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_M_IX86) && _M_IX86 >= 500 +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if _MSC_VER >= 1500 && defined(_M_AMD64) && !defined(BOOST_ATOMIC_NO_CMPXCHG16B) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif + +#if defined(_MSC_VER) && (defined(_M_AMD64) || (defined(_M_IX86) && defined(_M_IX86_FP) && _M_IX86_FP >= 2)) +// Use mfence only if SSE2 is available +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 + +#if defined(_M_AMD64) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) +#define BOOST_ATOMIC_INT64_LOCK_FREE 2 +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) && (defined(BOOST_HAS_INT128) || !defined(BOOST_NO_ALIGNMENT)) +#define BOOST_ATOMIC_INT128_LOCK_FREE 2 +#endif + +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_MSVC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/caps_windows.hpp b/third-party/boost/boost/atomic/detail/caps_windows.hpp new file mode 100644 index 000000000..1cc0ded83 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/caps_windows.hpp @@ -0,0 +1,33 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2012 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/caps_windows.hpp + * + * This header defines feature capabilities macros + */ + +#ifndef BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_INT8_LOCK_FREE 2 +#define BOOST_ATOMIC_INT16_LOCK_FREE 2 +#define BOOST_ATOMIC_INT32_LOCK_FREE 2 +#define BOOST_ATOMIC_POINTER_LOCK_FREE 2 + +#define BOOST_ATOMIC_THREAD_FENCE 2 +#define BOOST_ATOMIC_SIGNAL_FENCE 2 + +#endif // BOOST_ATOMIC_DETAIL_CAPS_WINDOWS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/config.hpp b/third-party/boost/boost/atomic/detail/config.hpp new file mode 100644 index 000000000..d2a6afd20 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/config.hpp @@ -0,0 +1,150 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2012 Hartmut Kaiser + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/config.hpp + * + * This header defines configuraion macros for Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__CUDACC__) +// nvcc does not support alternatives ("q,m") in asm statement constraints +#define BOOST_ATOMIC_DETAIL_NO_ASM_CONSTRAINT_ALTERNATIVES +// nvcc does not support condition code register ("cc") clobber in asm statements +#define BOOST_ATOMIC_DETAIL_NO_ASM_CLOBBER_CC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_NO_ASM_CLOBBER_CC) +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC "cc" +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "cc", +#else +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC +#define BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA +#endif + +#if (defined(__i386__) || defined(__x86_64__)) && (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) < 40500) || defined(__SUNPRO_CC)) +// This macro indicates that the compiler does not support allocating eax:edx or rax:rdx register pairs ("A") in asm blocks +#define BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS +#endif + +#if defined(__i386__) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 50100)) +// This macro indicates that asm blocks should preserve ebx value unchanged. Some compilers are able to maintain ebx themselves +// around the asm blocks. For those compilers we don't need to save/restore ebx in asm blocks. +#define BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX +#endif + +#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#if !(defined(BOOST_LIBSTDCXX11) && (BOOST_LIBSTDCXX_VERSION+0) >= 40700) /* libstdc++ from gcc >= 4.7 in C++11 mode */ +// This macro indicates that there is not even a basic standard header that is sufficient for most Boost.Atomic needs. +#define BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS +#endif +#endif // defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) + +// Enable pointer/reference casts between storage and value when possible. +// Note: Despite that MSVC does not employ strict aliasing rules for optimizations +// and does not require an explicit markup for types that may alias, we still don't +// enable the optimization for this compiler because at least MSVC-8 and 9 are known +// to generate broken code sometimes when casts are used. +#define BOOST_ATOMIC_DETAIL_MAY_ALIAS BOOST_MAY_ALIAS +#if !defined(BOOST_NO_MAY_ALIAS) +#define BOOST_ATOMIC_DETAIL_STORAGE_TYPE_MAY_ALIAS +#endif + +#if defined(__GCC_ASM_FLAG_OUTPUTS__) +// The compiler supports output values in flag registers. +// See: https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html, Section 6.44.3. +#define BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS +#endif + +#if defined(__has_builtin) +#if __has_builtin(__builtin_constant_p) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) __builtin_constant_p(x) +#endif +#elif defined(__GNUC__) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) __builtin_constant_p(x) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_IS_CONSTANT) +#define BOOST_ATOMIC_DETAIL_IS_CONSTANT(x) false +#endif + +#if (defined(__BYTE_ORDER__) && defined(__FLOAT_WORD_ORDER__) && (__BYTE_ORDER__+0) == (__FLOAT_WORD_ORDER__+0)) ||\ + defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64) +// This macro indicates that integer and floating point endianness is the same +#define BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH +#endif + +// Deprecated symbols markup +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(_MSC_VER) +#if (_MSC_VER) >= 1400 +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __declspec(deprecated(msg)) +#else +// MSVC 7.1 only supports the attribute without a message +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __declspec(deprecated) +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__has_extension) +#if __has_extension(attribute_deprecated_with_message) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated(msg))) +#endif +#endif + +// gcc since 4.5 supports deprecated attribute with a message; older versions support the attribute without a message. +// Oracle Studio 12.4 supports deprecated attribute with a message; this is the first release that supports the attribute. +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && (\ + (defined(__GNUC__) && ((__GNUC__ + 0) * 100 + (__GNUC_MINOR__ + 0)) >= 405) ||\ + (defined(__SUNPRO_CC) && (__SUNPRO_CC + 0) >= 0x5130)) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated(msg))) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && __cplusplus >= 201402 +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) [[deprecated(msg)]] +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__GNUC__) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated)) +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) && defined(__has_attribute) +#if __has_attribute(deprecated) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) __attribute__((deprecated)) +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_DEPRECATED) +#define BOOST_ATOMIC_DETAIL_DEPRECATED(msg) +#endif + +// In Boost.Atomic 1.67 we changed (op)_and_test methods to return true when the result is non-zero. This would be more consistent +// with the other names used in Boost.Atomic and the C++ standard library. Since the methods were announced as experimental and +// the previous behavior was released only in Boost 1.66, it was decided to change the result without changing the method names. +// By defining BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST the user has a way to highlight all uses of the affected functions so +// that it is easier to find and update the affected code (which is typically adding or removing negation of the result). This +// highlighting functionality is a temporary measure to help users upgrade from Boost 1.66 to newer Boost versions. It will +// be removed eventually. +// +// More info at: +// https://github.com/boostorg/atomic/issues/11 +// http://boost.2283326.n4.nabble.com/atomic-op-and-test-naming-tc4701445.html +#if defined(BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST) +#define BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST BOOST_ATOMIC_DETAIL_DEPRECATED("Boost.Atomic 1.67 has changed (op)_and_test result to the opposite. The functions now return true when the result is non-zero. Please, verify your use of the operation and undefine BOOST_ATOMIC_HIGHLIGHT_OP_AND_TEST.") +#else +#define BOOST_ATOMIC_DETAIL_HIGHLIGHT_OP_AND_TEST +#endif + +#endif // BOOST_ATOMIC_DETAIL_CONFIG_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_fp_operations.hpp b/third-party/boost/boost/atomic/detail/extra_fp_operations.hpp new file mode 100644 index 000000000..854d8c9be --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_fp_operations.hpp @@ -0,0 +1,28 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_operations.hpp + * + * This header defines extra floating point atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(boost/atomic/detail/extra_fp_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_fp_operations_fwd.hpp b/third-party/boost/boost/atomic/detail/extra_fp_operations_fwd.hpp new file mode 100644 index 000000000..79bca9d2c --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_fp_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_operations_fwd.hpp + * + * This header contains forward declaration of the \c extra_fp_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free > +struct extra_fp_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_fp_ops_emulated.hpp b/third-party/boost/boost/atomic/detail/extra_fp_ops_emulated.hpp new file mode 100644 index 000000000..e04b2f50f --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_fp_ops_emulated.hpp @@ -0,0 +1,107 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the extra floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra floating point operations +template< typename Base, typename Value, std::size_t Size > +struct emulated_extra_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = -old_val; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = -old_val; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val + v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val - v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } +}; + +template< typename Base, typename Value, std::size_t Size > +struct extra_fp_operations< Base, Value, Size, false > : + public emulated_extra_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_EMULATED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_fp_ops_generic.hpp b/third-party/boost/boost/atomic/detail/extra_fp_ops_generic.hpp new file mode 100644 index 000000000..34902c472 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_fp_ops_generic.hpp @@ -0,0 +1,189 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_fp_ops_generic.hpp + * + * This header contains generic implementation of the extra floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000 +#pragma GCC diagnostic push +// ignoring attributes on template argument X - this warning is because we need to pass storage_type as a template argument; no problem in this case +#pragma GCC diagnostic ignored "-Wignored-attributes" +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Negate implementation +template< + typename Base, + typename Value, + std::size_t Size +#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + , bool = atomics::detail::is_iec559< Value >::value && atomics::detail::is_integral< typename Base::storage_type >::value +#endif +> +struct generic_extra_fp_negate : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = -old_val; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = -old_val; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + +//! Negate implementation for IEEE 754 / IEC 559 floating point types. We leverage the fact that the sign bit is the most significant bit in the value. +template< typename Base, typename Value, std::size_t Size > +struct generic_extra_fp_negate< Base, Value, Size, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + //! The mask with only one sign bit set to 1 + static BOOST_CONSTEXPR_OR_CONST storage_type sign_mask = static_cast< storage_type >(1u) << (atomics::detail::value_sizeof< value_type >::value * 8u - 1u); + + static BOOST_FORCEINLINE value_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(base_type::fetch_xor(storage, sign_mask, order)); + } + + static BOOST_FORCEINLINE value_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return atomics::detail::bitwise_fp_cast< value_type >(base_type::bitwise_xor(storage, sign_mask, order)); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::opaque_xor(storage, sign_mask, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_INT_FP_ENDIAN_MATCH) + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct generic_extra_fp_operations : + public generic_extra_fp_negate< Base, Value, Size > +{ + typedef generic_extra_fp_negate< Base, Value, Size > base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val + v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE value_type sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val - v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } +}; + +// Default extra_fp_operations template definition will be used unless specialized for a specific platform +template< typename Base, typename Value, std::size_t Size > +struct extra_fp_operations< Base, Value, Size, true > : + public generic_extra_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_GCC) && (BOOST_GCC+0) >= 60000 +#pragma GCC diagnostic pop +#endif + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_operations.hpp b/third-party/boost/boost/atomic/detail/extra_operations.hpp new file mode 100644 index 000000000..c04f55cd8 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_operations.hpp @@ -0,0 +1,28 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_operations.hpp + * + * This header defines extra atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_HEADER(boost/atomic/detail/extra_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_operations_fwd.hpp b/third-party/boost/boost/atomic/detail/extra_operations_fwd.hpp new file mode 100644 index 000000000..399a82335 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_operations_fwd.hpp + * + * This header contains forward declaration of the \c extra_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, std::size_t Size, bool Signed, bool = Base::is_always_lock_free > +struct extra_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_emulated.hpp b/third-party/boost/boost/atomic/detail/extra_ops_emulated.hpp new file mode 100644 index 000000000..c0e483294 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_emulated.hpp @@ -0,0 +1,238 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the extra atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable: 4146) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra operations +template< typename Base, std::size_t Size, bool Signed > +struct emulated_extra_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = static_cast< storage_type >(-old_val); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = static_cast< storage_type >(-s); + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val += v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val -= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val &= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val |= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = s; + new_val ^= v; + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = static_cast< storage_type >(~old_val); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type new_val = static_cast< storage_type >(~s); + s = new_val; + return new_val; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Base::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + storage_type mask = static_cast< storage_type >(static_cast< storage_type >(1u) << bit_number); + storage_type old_val = Base::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, Size, Signed, false > : + public emulated_extra_operations< Base, Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_EMULATED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_gcc_arm.hpp b/third-party/boost/boost/atomic/detail/extra_ops_gcc_arm.hpp new file mode 100644 index 000000000..e84f1771d --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_gcc_arm.hpp @@ -0,0 +1,1111 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_arm.hpp + * + * This header contains implementation of the extra atomic operations for ARM. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_arm_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::negate(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_complement(storage, order); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct gcc_arm_extra_operations; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 1u, Signed > : + public generic_extra_operations< Base, 1u, Signed > +{ + typedef generic_extra_operations< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 1u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 2u, Signed > : + public generic_extra_operations< Base, 2u, Signed > +{ + typedef generic_extra_operations< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "mvn %[result], %[original]\n" // result = NOT original + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return static_cast< storage_type >(result); + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 2u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 4u, Signed > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "rsb %[result], %[original], #0\n" // result = 0 - original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "and %[result], %[original], %[value]\n" // result = original & value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "orr %[result], %[original], %[value]\n" // result = original | value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "mvn %[result], %[original]\n" // result = NOT original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "mvn %[result], %[original]\n" // result = NOT original + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_arm_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 4u, Signed > > +{ +}; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +template< typename Base, bool Signed > +struct gcc_arm_extra_operations< Base, 8u, Signed > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "adds %2, %2, #1\n" // result = result + 1 + "adc %H2, %H2, #0\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "adds %2, %2, #1\n" // result = result + 1 + "adc %H2, %H2, #0\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "adds %2, %1, %4\n" // result = original + value + "adc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "subs %2, %1, %4\n" // result = original - value + "sbc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "and %2, %1, %4\n" // result = original & value + "and %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "orr %2, %1, %4\n" // result = original | value + "orr %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "eor %2, %1, %4\n" // result = original ^ value + "eor %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_arm_operations_base::fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "mvn %2, %1\n" // result = NOT original + "mvn %H2, %H1\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + gcc_arm_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_arm_extra_operations_common< gcc_arm_extra_operations< Base, 8u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_gcc_ppc.hpp b/third-party/boost/boost/atomic/detail/extra_ops_gcc_ppc.hpp new file mode 100644 index 000000000..dc4bbdbf7 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_gcc_ppc.hpp @@ -0,0 +1,840 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_ppc.hpp + * + * This header contains implementation of the extra atomic operations for PowerPC. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_ppc_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::negate(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::add(storage, v, order); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::sub(storage, v, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!base_type::bitwise_complement(storage, order); + } +}; + +template< typename Base, std::size_t Size, bool Signed > +struct gcc_ppc_extra_operations; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 1u, Signed > : + public generic_extra_operations< Base, 1u, Signed > +{ + typedef generic_extra_operations< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 1u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 2u, Signed > : + public generic_extra_operations< Base, 2u, Signed > +{ + typedef generic_extra_operations< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "neg %1,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "neg %1,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 4u, Signed > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 4u, Signed > > +{ +}; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +template< typename Base, bool Signed > +struct gcc_ppc_extra_operations< Base, 8u, Signed > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "neg %1,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + gcc_ppc_operations_base::fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + gcc_ppc_operations_base::fence_before(order); + storage_type original, result; + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "nor %1,%0,%0\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + gcc_ppc_operations_base::fence_after(order); + return result; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_ppc_extra_operations_common< gcc_ppc_extra_operations< Base, 8u, Signed > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_ARM_PPC_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_gcc_x86.hpp b/third-party/boost/boost/atomic/detail/extra_ops_gcc_x86.hpp new file mode 100644 index 000000000..ee2cd02a8 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_gcc_x86.hpp @@ -0,0 +1,1656 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2015 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_gcc_x86.hpp + * + * This header contains implementation of the extra atomic operations for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct gcc_x86_extra_operations_common : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(Base::fetch_add(storage, v, order) + v); + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(Base::fetch_sub(storage, v, order) - v); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; bts %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; bts %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; btr %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; btr %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; btc %[bit_number], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccc" (res) + : [bit_number] "Kq" (bit_number) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; btc %[bit_number], %[storage]\n\t" + "setc %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [bit_number] "Kq" (bit_number) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movzbl %[orig], %2\n\t"\ + op " %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negb", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notb", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negb", original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notb", original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%al, %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andb", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orb", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorb", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negb %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notb %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incb %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decb %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorb %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movzwl %[orig], %2\n\t"\ + op " %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negw", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notw", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negw", original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notw", original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%ax, %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), "=&q" (result)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andw", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orw", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + temp_storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorw", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negw %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notw %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incw %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decw %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "iq" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorw %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "iq" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[orig], %[res]\n\t"\ + op " %[res]\n\t"\ + "lock; cmpxchgl %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negl", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notl", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negl", original, result); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notl", original, result); + return result; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[res]\n\t"\ + op " %%eax, %[res]\n\t"\ + "lock; cmpxchgl %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : [arg] "ir" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andl", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orl", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorl", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negl %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notl %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incl %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decl %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "ir" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorl %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "ir" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +#if defined(__x86_64__) + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public gcc_x86_extra_operations_common< Base > +{ + typedef gcc_x86_extra_operations_common< Base > base_type; + typedef typename base_type::storage_type storage_type; + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[orig], %[res]\n\t"\ + op " %[res]\n\t"\ + "lock; cmpxchgq %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : \ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negq", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notq", original, result); + return original; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("negq", original, result); + return result; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("notq", original, result); + return result; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, original, result)\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[res]\n\t"\ + op " %%rax, %[res]\n\t"\ + "lock; cmpxchgq %[res], %[storage]\n\t"\ + "jne 1b"\ + : [orig] "+a" (original), [storage] "+m" (storage), [res] "=&r" (result)\ + : [arg] "r" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andq", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orq", v, original, result); + return static_cast< storage_type >(result); + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type original = storage; + storage_type result; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorq", v, original, result); + return static_cast< storage_type >(result); + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_complement(storage, order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; negq %[storage]\n\t" + : [storage] "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + : [storage] "+m" (storage) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; notq %[storage]\n\t" + : [storage] "+m" (storage) + : + : "memory" + ); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; incq %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; addq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : + : "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); + } +#else + if (BOOST_ATOMIC_DETAIL_IS_CONSTANT(v) && v == 1) + { + __asm__ __volatile__ + ( + "lock; decq %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lock; subq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + } +#endif + return res; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; andq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; orq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + bool res; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + : [storage] "+m" (storage), [result] "=@ccnz" (res) + : [argument] "er" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "lock; xorq %[argument], %[storage]\n\t" + "setnz %[result]\n\t" + : [storage] "+m" (storage), [result] "=q" (res) + : [argument] "er" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif + return res; + } +}; + +#endif // defined(__x86_64__) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GCC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_generic.hpp b/third-party/boost/boost/atomic/detail/extra_ops_generic.hpp new file mode 100644 index 000000000..43842628a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_generic.hpp @@ -0,0 +1,402 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2015 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_generic.hpp + * + * This header contains generic implementation of the extra atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// unary minus operator applied to unsigned type, result still unsigned +#pragma warning(disable: 4146) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of extra operations +template< typename Base, std::size_t Size, bool Signed, bool = Base::full_cas_based > +struct generic_extra_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_add(storage, v, order) + v; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_sub(storage, v, order) - v; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_and(storage, v, order) & v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_or(storage, v, order) | v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, v, order) ^ v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))); + return base_type::fetch_xor(storage, mask, order) ^ mask; + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(add(storage, v, order)); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(sub(storage, v, order)); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order)); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +//! Specialization for cases when the platform only natively supports CAS +template< typename Base, std::size_t Size, bool Signed > +struct generic_extra_operations< Base, Size, Signed, true > : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!base_type::compare_exchange_weak(storage, old_val, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)), order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(-old_val)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val & v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val | v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_val); + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val ^ v)); + } + while (!base_type::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return new_val; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return base_type::fetch_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return bitwise_xor(storage, atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(~static_cast< emulated_storage_type >(0u))), order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_add(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_sub(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_negate(storage, order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_and(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_or(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fetch_xor(storage, v, order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + fetch_complement(storage, order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(add(storage, v, order)); + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(sub(storage, v, order)); + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!negate(storage, order); + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_and(storage, v, order); + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_or(storage, v, order); + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return !!bitwise_xor(storage, v, order); + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!static_cast< emulated_storage_type >(bitwise_complement(storage, order)); + } + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_or(storage, mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_and(storage, ~mask, order); + return !!(old_val & mask); + } + + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + const storage_type mask = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(static_cast< emulated_storage_type >(1u) << bit_number)); + storage_type old_val = base_type::fetch_xor(storage, mask, order); + return !!(old_val & mask); + } +}; + +// Default extra_operations template definition will be used unless specialized for a specific platform +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, Size, Signed, true > : + public generic_extra_operations< Base, Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_GENERIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_msvc_arm.hpp b/third-party/boost/boost/atomic/detail/extra_ops_msvc_arm.hpp new file mode 100644 index 000000000..b8eb5bcb3 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_msvc_arm.hpp @@ -0,0 +1,106 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_msvc_arm.hpp + * + * This header contains implementation of the extra atomic operations for ARM. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR) + +template< typename Base, std::size_t Size, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public generic_extra_operations< Base, 4u, Signed > +{ + typedef generic_extra_operations< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED) && defined(BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE) && defined(BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE) + bool result; + switch (order) + { + case memory_order_relaxed: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED(&storage, bit_number); + break; + case memory_order_consume: + case memory_order_acquire: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE(&storage, bit_number); + break; + case memory_order_release: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE(&storage, bit_number); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + result = !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); + break; + } + return result; +#else + return !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); +#endif + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED) && defined(BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE) && defined(BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE) + bool result; + switch (order) + { + case memory_order_relaxed: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED(&storage, bit_number); + break; + case memory_order_consume: + case memory_order_acquire: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE(&storage, bit_number); + break; + case memory_order_release: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE(&storage, bit_number); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + result = !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); + break; + } + return result; +#else + return !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); +#endif + } +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/extra_ops_msvc_x86.hpp b/third-party/boost/boost/atomic/detail/extra_ops_msvc_x86.hpp new file mode 100644 index 000000000..17451a83d --- /dev/null +++ b/third-party/boost/boost/atomic/detail/extra_ops_msvc_x86.hpp @@ -0,0 +1,1301 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/extra_ops_msvc_x86.hpp + * + * This header contains implementation of the extra atomic operations for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// frame pointer register 'ebx' modified by inline assembly code +#pragma warning(disable: 4731) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if defined(_M_IX86) || (defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR)) + +template< typename Base, std::size_t Size, bool Signed > +struct msvc_x86_extra_operations_common : + public generic_extra_operations< Base, Size, Signed > +{ + typedef generic_extra_operations< Base, Size, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS) + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTS(&storage, bit_number); + } +#else + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock bts [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTR) + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTR(&storage, bit_number); + } +#else + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock btr [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif + +#if defined(_M_IX86) + static BOOST_FORCEINLINE bool bit_test_and_complement(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, bit_number + lock btc [edx], eax + setc result + }; + base_type::fence_after(order); + return result; + } +#endif +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 1u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 1u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 1u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov old_val, al + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov new_val, dl + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + test dl, dl + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + neg dl + lock cmpxchg byte ptr [ecx], dl + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + and dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + or dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + xor dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, dl + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov old_val, al + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + mov new_val, dl + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + test dl, dl + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, byte ptr [ecx] + align 16 + again: + mov edx, eax + not dl + lock cmpxchg byte ptr [ecx], dl + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock add byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock sub byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg byte ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock and byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock or byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xor byte ptr [edx], al + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not byte ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock add byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock sub byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock and byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock or byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock xor byte ptr [edx], al + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 2u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 2u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 2u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + mov old_val, ax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + mov new_val, dx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + test dx, dx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + neg dx + lock cmpxchg word ptr [ecx], dx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + and dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + or dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + xor dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, dx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + mov old_val, ax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + mov new_val, dx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + test dx, dx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + movzx eax, word ptr [ecx] + align 16 + again: + mov edx, eax + not dx + lock cmpxchg word ptr [ecx], dx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock add word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock sub word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg word ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock and word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock or word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xor word ptr [edx], ax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not word ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock add word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock sub word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock and word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock or word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + movzx eax, v + lock xor word ptr [edx], ax + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +template< typename Base, bool Signed > +struct extra_operations< Base, 4u, Signed, true > : + public msvc_x86_extra_operations_common< Base, 4u, Signed > +{ + typedef msvc_x86_extra_operations_common< Base, 4u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + +#if defined(_M_IX86) + static BOOST_FORCEINLINE storage_type fetch_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov old_val, eax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov new_val, edx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool negate_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + test edx, edx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + neg edx + lock cmpxchg dword ptr [ecx], edx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE storage_type bitwise_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + and edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + or edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type bitwise_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + mov ecx, v + xor edx, edx + mov eax, dword ptr [edi] + align 16 + again: + mov edx, eax + xor edx, ecx + lock cmpxchg dword ptr [edi], edx + jne again + mov v, edx + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type old_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov old_val, eax + }; + base_type::fence_after(order); + return old_val; + } + + static BOOST_FORCEINLINE storage_type bitwise_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + storage_type new_val; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + mov new_val, edx + }; + base_type::fence_after(order); + return new_val; + } + + static BOOST_FORCEINLINE bool complement_and_test(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + test edx, edx + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov ecx, storage + mov eax, dword ptr [ecx] + align 16 + again: + mov edx, eax + not edx + lock cmpxchg dword ptr [ecx], edx + jne again + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock add dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock sub dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_negate(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock neg dword ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock and dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock or dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + mov eax, v + lock xor dword ptr [edx], eax + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE void opaque_complement(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + lock not dword ptr [edx] + }; + base_type::fence_after(order); + } + + static BOOST_FORCEINLINE bool add_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock add dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool sub_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock sub dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool and_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock and dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool or_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock or dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } + + static BOOST_FORCEINLINE bool xor_and_test(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + bool result; + __asm + { + mov edx, storage + mov eax, v + lock xor dword ptr [edx], eax + setnz result + }; + base_type::fence_after(order); + return result; + } +#endif // defined(_M_IX86) +}; + +#endif // defined(_M_IX86) || (defined(BOOST_ATOMIC_INTERLOCKED_BTS) && defined(BOOST_ATOMIC_INTERLOCKED_BTR)) + +#if defined(BOOST_ATOMIC_INTERLOCKED_BTS64) && defined(BOOST_ATOMIC_INTERLOCKED_BTR64) + +template< typename Base, bool Signed > +struct extra_operations< Base, 8u, Signed, true > : + public generic_extra_operations< Base, 8u, Signed > +{ + typedef generic_extra_operations< Base, 8u, Signed > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE bool bit_test_and_set(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTS64(&storage, bit_number); + } + + static BOOST_FORCEINLINE bool bit_test_and_reset(storage_type volatile& storage, unsigned int bit_number, memory_order order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_BTR64(&storage, bit_number); + } +}; + +#endif // defined(BOOST_ATOMIC_INTERLOCKED_BTS64) && defined(BOOST_ATOMIC_INTERLOCKED_BTR64) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_EXTRA_OPS_MSVC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/float_sizes.hpp b/third-party/boost/boost/atomic/detail/float_sizes.hpp new file mode 100644 index 000000000..4c3a346f1 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/float_sizes.hpp @@ -0,0 +1,142 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/float_sizes.hpp + * + * This header defines macros for testing buitin floating point type sizes + */ + +#ifndef BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Detect value sizes of the different floating point types. The value sizes may be less than the corresponding type sizes +// if the type contains padding bits. This is typical e.g. with 80-bit extended float types, which are often represented as 128-bit types. +// See: https://en.wikipedia.org/wiki/IEEE_754 +// For Intel x87 extended double see: https://en.wikipedia.org/wiki/Extended_precision#x86_Architecture_Extended_Precision_Format +// For IBM extended double (a.k.a. double-double) see: https://en.wikipedia.org/wiki/Long_double#Implementations, https://gcc.gnu.org/wiki/Ieee128PowerPC +#if (FLT_RADIX+0) == 2 + +#if ((FLT_MANT_DIG+0) == 11) && ((FLT_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 2 +#elif ((FLT_MANT_DIG+0) == 24) && ((FLT_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4 +#elif ((FLT_MANT_DIG+0) == 53) && ((FLT_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8 +#elif ((FLT_MANT_DIG+0) == 64) && ((FLT_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 10 +#elif ((FLT_MANT_DIG+0) == 106) && ((FLT_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#elif ((FLT_MANT_DIG+0) == 113) && ((FLT_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#elif ((FLT_MANT_DIG+0) == 237) && ((FLT_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 32 +#endif + +#if ((DBL_MANT_DIG+0) == 11) && ((DBL_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 2 +#elif ((DBL_MANT_DIG+0) == 24) && ((DBL_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4 +#elif ((DBL_MANT_DIG+0) == 53) && ((DBL_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8 +#elif ((DBL_MANT_DIG+0) == 64) && ((DBL_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 10 +#elif ((DBL_MANT_DIG+0) == 106) && ((DBL_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#elif ((DBL_MANT_DIG+0) == 113) && ((DBL_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#elif ((DBL_MANT_DIG+0) == 237) && ((DBL_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 32 +#endif + +#if ((LDBL_MANT_DIG+0) == 11) && ((LDBL_MAX_EXP+0) == 16) // IEEE 754 binary16 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 2 +#elif ((LDBL_MANT_DIG+0) == 24) && ((LDBL_MAX_EXP+0) == 128) // IEEE 754 binary32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4 +#elif ((LDBL_MANT_DIG+0) == 53) && ((LDBL_MAX_EXP+0) == 1024) // IEEE 754 binary64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8 +#elif ((LDBL_MANT_DIG+0) == 64) && ((LDBL_MAX_EXP+0) == 16384) // x87 extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 10 +#elif ((LDBL_MANT_DIG+0) == 106) && ((LDBL_MAX_EXP+0) == 1024) // IBM extended double +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#elif ((LDBL_MANT_DIG+0) == 113) && ((LDBL_MAX_EXP+0) == 16384) // IEEE 754 binary128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#elif ((LDBL_MANT_DIG+0) == 237) && ((LDBL_MAX_EXP+0) == 262144) // IEEE 754 binary256 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 32 +#endif + +#elif (FLT_RADIX+0) == 10 + +#if ((FLT_MANT_DIG+0) == 7) && ((FLT_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 4 +#elif ((FLT_MANT_DIG+0) == 16) && ((FLT_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 8 +#elif ((FLT_MANT_DIG+0) == 34) && ((FLT_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE 16 +#endif + +#if ((DBL_MANT_DIG+0) == 7) && ((DBL_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 4 +#elif ((DBL_MANT_DIG+0) == 16) && ((DBL_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 8 +#elif ((DBL_MANT_DIG+0) == 34) && ((DBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE 16 +#endif + +#if ((LDBL_MANT_DIG+0) == 7) && ((LDBL_MAX_EXP+0) == 97) // IEEE 754 decimal32 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 4 +#elif ((LDBL_MANT_DIG+0) == 16) && ((LDBL_MAX_EXP+0) == 385) // IEEE 754 decimal64 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 8 +#elif ((LDBL_MANT_DIG+0) == 34) && ((LDBL_MAX_EXP+0) == 6145) // IEEE 754 decimal128 +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE 16 +#endif + +#endif + +// GCC and compatible compilers define internal macros with builtin type traits +#if defined(__SIZEOF_FLOAT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT __SIZEOF_FLOAT__ +#endif +#if defined(__SIZEOF_DOUBLE__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE __SIZEOF_DOUBLE__ +#endif +#if defined(__SIZEOF_LONG_DOUBLE__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE __SIZEOF_LONG_DOUBLE__ +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) + +#define BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(x)\ + ((x) == 1u ? 1u : ((x) == 2u ? 2u : ((x) <= 4u ? 4u : ((x) <= 8u ? 8u : ((x) <= 16u ? 16u : ((x) <= 32u ? 32u : (x))))))) + +// Make our best guess. These sizes may not be accurate, but they are good enough to estimate the size of the storage required to hold these types. +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) +#endif +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) +#endif +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) && defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE BOOST_ATOMIC_DETAIL_ALIGN_SIZE_TO_POWER_OF_2(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) +#endif + +#endif // !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_FLOAT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_DOUBLE) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE_VALUE) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG_DOUBLE) +#error Boost.Atomic: Failed to determine builtin floating point type sizes, the target platform is not supported. Please, report to the developers (patches are welcome). +#endif + +#endif // BOOST_ATOMIC_DETAIL_FLOAT_SIZES_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/fp_operations.hpp b/third-party/boost/boost/atomic/detail/fp_operations.hpp new file mode 100644 index 000000000..69cb0d19a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/fp_operations.hpp @@ -0,0 +1,28 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_operations.hpp + * + * This header defines floating point atomic operations, including the generic version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC) +#include BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(boost/atomic/detail/fp_ops_) +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/fp_operations_fwd.hpp b/third-party/boost/boost/atomic/detail/fp_operations_fwd.hpp new file mode 100644 index 000000000..8696de31c --- /dev/null +++ b/third-party/boost/boost/atomic/detail/fp_operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_operations_fwd.hpp + * + * This header contains forward declaration of the \c fp_operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, typename Value, std::size_t Size, bool = Base::is_always_lock_free > +struct fp_operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/fp_ops_emulated.hpp b/third-party/boost/boost/atomic/detail/fp_ops_emulated.hpp new file mode 100644 index 000000000..a87f1814b --- /dev/null +++ b/third-party/boost/boost/atomic/detail/fp_ops_emulated.hpp @@ -0,0 +1,72 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_ops_emulated.hpp + * + * This header contains emulated (lock-based) implementation of the floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct emulated_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val + v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } + + static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + value_type old_val = atomics::detail::bitwise_fp_cast< value_type >(s); + value_type new_val = old_val - v; + s = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + return old_val; + } +}; + +template< typename Base, typename Value, std::size_t Size > +struct fp_operations< Base, Value, Size, false > : + public emulated_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_EMULATED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/fp_ops_generic.hpp b/third-party/boost/boost/atomic/detail/fp_ops_generic.hpp new file mode 100644 index 000000000..b83e85a35 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/fp_ops_generic.hpp @@ -0,0 +1,83 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/fp_ops_generic.hpp + * + * This header contains generic implementation of the floating point atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +//! Generic implementation of floating point operations +template< typename Base, typename Value, std::size_t Size > +struct generic_fp_operations : + public Base +{ + typedef Base base_type; + typedef typename base_type::storage_type storage_type; + typedef Value value_type; + + static BOOST_FORCEINLINE value_type fetch_add(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val + v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE value_type fetch_sub(storage_type volatile& storage, value_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_storage, new_storage; + value_type old_val, new_val; + atomics::detail::non_atomic_load(storage, old_storage); + do + { + old_val = atomics::detail::bitwise_fp_cast< value_type >(old_storage); + new_val = old_val - v; + new_storage = atomics::detail::bitwise_fp_cast< storage_type >(new_val); + } + while (!base_type::compare_exchange_weak(storage, old_storage, new_storage, order, memory_order_relaxed)); + return old_val; + } +}; + +// Default fp_operations template definition will be used unless specialized for a specific platform +template< typename Base, typename Value, std::size_t Size > +struct fp_operations< Base, Value, Size, true > : + public generic_fp_operations< Base, Value, Size > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_FP_OPS_GENERIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/hwcaps_gcc_arm.hpp b/third-party/boost/boost/atomic/detail/hwcaps_gcc_arm.hpp new file mode 100644 index 000000000..6d0c33862 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/hwcaps_gcc_arm.hpp @@ -0,0 +1,67 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_arm.hpp + * + * This header defines hardware capabilities macros for ARM + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#if BOOST_ATOMIC_DETAIL_ARM_ARCH > 6 +// ARMv7 and later have dmb instruction +#define BOOST_ATOMIC_DETAIL_ARM_HAS_DMB 1 +#endif + +#if defined(__ARM_FEATURE_LDREX) + +#if (__ARM_FEATURE_LDREX & 1) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1 +#endif +#if (__ARM_FEATURE_LDREX & 2) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1 +#endif +#if (__ARM_FEATURE_LDREX & 8) +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1 +#endif + +#else // defined(__ARM_FEATURE_LDREX) + +#if !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__)) + +// ARMv6k and ARMv7 have 8 and 16-bit ldrex/strex variants, but at least GCC 4.7 fails to compile them. GCC 4.9 is known to work. +#if (__GNUC__ * 100 + __GNUC_MINOR__) >= 409 +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB 1 +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH 1 +#endif + +#if !(((defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6ZK__)) && defined(__thumb__)) || defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7M__)) +// ARMv6k and ARMv7 except ARMv7-M have 64-bit ldrex/strex variants. +// Unfortunately, GCC (at least 4.7.3 on Ubuntu) does not allocate register pairs properly when targeting ARMv6k Thumb, +// which is required for ldrexd/strexd instructions, so we disable 64-bit support. When targeting ARMv6k ARM +// or ARMv7 (both ARM and Thumb 2) it works as expected. +#define BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD 1 +#endif + +#endif // !(defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6Z__)) + +#endif // defined(__ARM_FEATURE_LDREX) + +#endif // defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/hwcaps_gcc_ppc.hpp b/third-party/boost/boost/atomic/detail/hwcaps_gcc_ppc.hpp new file mode 100644 index 000000000..2ec1e327a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/hwcaps_gcc_ppc.hpp @@ -0,0 +1,42 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_ppc.hpp + * + * This header defines hardware capabilities macros for PowerPC + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__POWERPC__) || defined(__PPC__) + +#if defined(_ARCH_PWR8) +// Power8 and later architectures have 8 and 16-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX +#endif + +#if defined(__powerpc64__) || defined(__PPC64__) +// Power7 and later architectures in 64-bit mode have 64-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX +#if defined(_ARCH_PWR8) +// Power8 also has 128-bit instructions +#define BOOST_ATOMIC_DETAIL_PPC_HAS_LQARX_STQCX +#endif +#endif + +#endif // defined(__POWERPC__) || defined(__PPC__) + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_PPC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/hwcaps_gcc_x86.hpp b/third-party/boost/boost/atomic/detail/hwcaps_gcc_x86.hpp new file mode 100644 index 000000000..91a1aee3a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/hwcaps_gcc_x86.hpp @@ -0,0 +1,58 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/hwcaps_gcc_x86.hpp + * + * This header defines hardware capabilities macros for x86 + */ + +#ifndef BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) + +#if defined(__i386__) &&\ + (\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) ||\ + defined(__i586__) || defined(__i686__) || defined(__SSE__)\ + ) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif + +#if defined(__x86_64__) || defined(__SSE2__) +// Use mfence only if SSE2 is available +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#else // defined(__GNUC__) + +#if defined(__i386__) && !defined(BOOST_ATOMIC_NO_CMPXCHG8B) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B 1 +#endif + +#if defined(__x86_64__) && !defined(BOOST_ATOMIC_NO_CMPXCHG16B) +#define BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B 1 +#endif + +#if !defined(BOOST_ATOMIC_NO_MFENCE) +#define BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE 1 +#endif + +#endif // defined(__GNUC__) + +#endif // BOOST_ATOMIC_DETAIL_HWCAPS_GCC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/int_sizes.hpp b/third-party/boost/boost/atomic/detail/int_sizes.hpp new file mode 100644 index 000000000..2a9757c14 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/int_sizes.hpp @@ -0,0 +1,140 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/int_sizes.hpp + * + * This header defines macros for testing buitin integer type sizes + */ + +#ifndef BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// GCC and compatible compilers define internal macros with builtin type traits +#if defined(__SIZEOF_SHORT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT __SIZEOF_SHORT__ +#endif +#if defined(__SIZEOF_INT__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT __SIZEOF_INT__ +#endif +#if defined(__SIZEOF_LONG__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG __SIZEOF_LONG__ +#endif +#if defined(__SIZEOF_LONG_LONG__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG __SIZEOF_LONG_LONG__ +#endif +#if defined(__SIZEOF_WCHAR_T__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__ +#endif +#if defined(__SIZEOF_POINTER__) +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER __SIZEOF_POINTER__ +#elif defined(_MSC_VER) +#if defined(_M_AMD64) || defined(_M_ARM64) || defined(_M_IA64) +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 8 +#else +#define BOOST_ATOMIC_DETAIL_SIZEOF_POINTER 4 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_SHORT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_INT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LLONG) + +// Try to deduce sizes from limits +#include +#include + +#if (USHRT_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 1 +#elif (USHRT_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 2 +#elif (USHRT_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 4 +#elif (USHRT_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_SHORT 8 +#endif + +#if (UINT_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 1 +#elif (UINT_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 2 +#elif (UINT_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 4 +#elif (UINT_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_INT 8 +#endif + +#if (ULONG_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 1 +#elif (ULONG_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 2 +#elif (ULONG_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 4 +#elif (ULONG_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LONG 8 +#endif + +#if defined(__hpux) // HP-UX's value of ULONG_LONG_MAX is unusable in preprocessor expressions +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 8 +#else + +// The list of the non-standard macros (the ones except ULLONG_MAX) is taken from cstdint.hpp +#if defined(ULLONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULLONG_MAX +#elif defined(ULONG_LONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULONG_LONG_MAX +#elif defined(ULONGLONG_MAX) +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX ULONGLONG_MAX +#elif defined(_LLONG_MAX) // strangely enough, this one seems to be holding the limit for the unsigned integer +#define BOOST_ATOMIC_DETAIL_ULLONG_MAX _LLONG_MAX +#endif + +#if (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 1 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 2 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == 0xffffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 4 +#elif (BOOST_ATOMIC_DETAIL_ULLONG_MAX + 0) == UINT64_C(0xffffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_LLONG 8 +#endif + +#endif // defined(__hpux) + +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T) + +#include +#include + +#if defined(_MSC_VER) && (_MSC_VER <= 1310 || defined(UNDER_CE) && _MSC_VER <= 1500) +// MSVC 7.1 and MSVC 8 (arm) define WCHAR_MAX to a value not suitable for constant expressions +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 2 +#elif (WCHAR_MAX + 0) == 0xff || (WCHAR_MAX + 0) == 0x7f +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 1 +#elif (WCHAR_MAX + 0) == 0xffff || (WCHAR_MAX + 0) == 0x7fff +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 2 +#elif (WCHAR_MAX + 0) == 0xffffffff || (WCHAR_MAX + 0) == 0x7fffffff +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 4 +#elif (WCHAR_MAX + 0) == UINT64_C(0xffffffffffffffff) || (WCHAR_MAX + 0) == INT64_C(0x7fffffffffffffff) +#define BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T 8 +#endif +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_SIZEOF_SHORT) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_INT) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LONG) || !defined(BOOST_ATOMIC_DETAIL_SIZEOF_LLONG) ||\ + !defined(BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T) +#error Boost.Atomic: Failed to determine builtin integer sizes, the target platform is not supported. Please, report to the developers (patches are welcome). +#endif + +#endif // BOOST_ATOMIC_DETAIL_INT_SIZES_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/integral_extend.hpp b/third-party/boost/boost/atomic/detail/integral_extend.hpp new file mode 100644 index 000000000..dea48ac6f --- /dev/null +++ b/third-party/boost/boost/atomic/detail/integral_extend.hpp @@ -0,0 +1,105 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/integral_extend.hpp + * + * This header defines sign/zero extension utilities for Boost.Atomic. The tools assume two's complement signed integer representation. + */ + +#ifndef BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + // Note: If we are casting with truncation or to the same-sized output, don't cause signed integer overflow by this chain of conversions + return atomics::detail::bitwise_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Output >::type >( + static_cast< typename atomics::detail::make_unsigned< Input >::type >(input))); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return static_cast< Output >(static_cast< typename atomics::detail::make_unsigned< Input >::type >(input)); +} + +//! Zero-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output zero_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::zero_extend_impl< Output >(input, atomics::detail::integral_constant< bool, atomics::detail::is_signed< Output >::value >()); +} + +//! Truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_truncate(Input input) BOOST_NOEXCEPT +{ + // zero_extend does the truncation + return atomics::detail::zero_extend< Output >(input); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + return atomics::detail::integral_truncate< Output >(input); +} + +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend_impl(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return static_cast< Output >(atomics::detail::bitwise_cast< typename atomics::detail::make_signed< Input >::type >(input)); +} + +//! Sign-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output sign_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::sign_extend_impl< Output >(input, atomics::detail::integral_constant< bool, sizeof(Output) <= sizeof(Input) >()); +} + +//! Sign-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::true_type) BOOST_NOEXCEPT +{ + return atomics::detail::sign_extend< Output >(input); +} + +//! Zero-extends or truncates (wraps) input operand to fit in the output type +template< typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input, atomics::detail::false_type) BOOST_NOEXCEPT +{ + return atomics::detail::zero_extend< Output >(input); +} + +//! Sign- or zero-extends or truncates (wraps) input operand to fit in the output type +template< bool Signed, typename Output, typename Input > +BOOST_FORCEINLINE Output integral_extend(Input input) BOOST_NOEXCEPT +{ + return atomics::detail::integral_extend< Output >(input, atomics::detail::integral_constant< bool, Signed >()); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_INTEGRAL_EXTEND_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/interlocked.hpp b/third-party/boost/boost/atomic/detail/interlocked.hpp new file mode 100644 index 000000000..774354fb7 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/interlocked.hpp @@ -0,0 +1,522 @@ +#ifndef BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP +#define BOOST_ATOMIC_DETAIL_INTERLOCKED_HPP + +// Copyright (c) 2009 Helge Bahmann +// Copyright (c) 2012 - 2014, 2017 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_WIN32_WCE) + +#if _WIN32_WCE >= 0x600 + +extern "C" long __cdecl _InterlockedCompareExchange( long volatile *, long, long ); +extern "C" long __cdecl _InterlockedExchangeAdd( long volatile *, long ); +extern "C" long __cdecl _InterlockedExchange( long volatile *, long ); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) + +#else // _WIN32_WCE >= 0x600 + +extern "C" long __cdecl InterlockedCompareExchange( long*, long, long ); +extern "C" long __cdecl InterlockedExchangeAdd( long*, long ); +extern "C" long __cdecl InterlockedExchange( long*, long ); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) InterlockedExchange((long*)(dest), (long)(newval)) + +#endif // _WIN32_WCE >= 0x600 + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE((long*)(dest), (long)(exchange))) + +#elif defined(_MSC_VER) && _MSC_VER >= 1310 + +#if _MSC_VER < 1400 + +extern "C" long __cdecl _InterlockedCompareExchange( long volatile *, long, long ); +extern "C" long __cdecl _InterlockedExchangeAdd( long volatile *, long ); +extern "C" long __cdecl _InterlockedExchange( long volatile *, long ); + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchange) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), exchange, compare) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, exchange) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE((long*)(dest), (long)(exchange))) + +#else // _MSC_VER < 1400 + +#include + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange) +#pragma intrinsic(_InterlockedExchangeAdd) +#pragma intrinsic(_InterlockedExchange) +#pragma intrinsic(_InterlockedAnd) +#pragma intrinsic(_InterlockedOr) +#pragma intrinsic(_InterlockedXor) +#pragma intrinsic(_interlockedbittestandset) +#pragma intrinsic(_interlockedbittestandreset) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) _InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) _InterlockedExchangeAdd((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) _InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND(dest, arg) _InterlockedAnd((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR(dest, arg) _InterlockedOr((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR(dest, arg) _InterlockedXor((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS(dest, arg) _interlockedbittestandset((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR(dest, arg) _interlockedbittestandreset((long*)(dest), (long)(arg)) + +#if defined(_M_AMD64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandset64) +#pragma intrinsic(_interlockedbittestandreset64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTS64(dest, arg) _interlockedbittestandset64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR64(dest, arg) _interlockedbittestandreset64((__int64*)(dest), (__int64)(arg)) +#endif // defined(_M_AMD64) + +#if (defined(_M_IX86) && _M_IX86 >= 500) || defined(_M_AMD64) || defined(_M_IA64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange64) +#endif +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) _InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#endif + +#if _MSC_VER >= 1500 && defined(_M_AMD64) +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange128) +#endif +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(dest, exchange, compare) _InterlockedCompareExchange128((__int64*)(dest), ((const __int64*)(&exchange))[1], ((const __int64*)(&exchange))[0], (__int64*)(compare)) +#endif + +#if _MSC_VER >= 1600 + +// MSVC 2010 and later provide intrinsics for 8 and 16 bit integers. +// Note that for each bit count these macros must be either all defined or all not defined. +// Otherwise atomic<> operations will be implemented inconsistently. + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange8) +#pragma intrinsic(_InterlockedExchangeAdd8) +#pragma intrinsic(_InterlockedExchange8) +#pragma intrinsic(_InterlockedAnd8) +#pragma intrinsic(_InterlockedOr8) +#pragma intrinsic(_InterlockedXor8) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(dest, exchange, compare) _InterlockedCompareExchange8((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(dest, addend) _InterlockedExchangeAdd8((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(dest, newval) _InterlockedExchange8((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND8(dest, arg) _InterlockedAnd8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8(dest, arg) _InterlockedOr8((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8(dest, arg) _InterlockedXor8((char*)(dest), (char)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange16) +#pragma intrinsic(_InterlockedExchangeAdd16) +#pragma intrinsic(_InterlockedExchange16) +#pragma intrinsic(_InterlockedAnd16) +#pragma intrinsic(_InterlockedOr16) +#pragma intrinsic(_InterlockedXor16) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(dest, exchange, compare) _InterlockedCompareExchange16((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(dest, addend) _InterlockedExchangeAdd16((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(dest, newval) _InterlockedExchange16((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND16(dest, arg) _InterlockedAnd16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16(dest, arg) _InterlockedOr16((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16(dest, arg) _InterlockedXor16((short*)(dest), (short)(arg)) + +#endif // _MSC_VER >= 1600 + +#if defined(_M_AMD64) || defined(_M_IA64) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchange64) +#pragma intrinsic(_InterlockedAnd64) +#pragma intrinsic(_InterlockedOr64) +#pragma intrinsic(_InterlockedXor64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) _InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) _InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND64(dest, arg) _InterlockedAnd64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64(dest, arg) _InterlockedOr64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64(dest, arg) _InterlockedXor64((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchangePointer) +#pragma intrinsic(_InterlockedExchangePointer) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) _InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64((long*)(dest), byte_offset)) + +#elif defined(_M_IX86) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)_InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)_InterlockedExchange((long*)(dest), (long)(newval))) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) + +#endif + +#if _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd64) +#pragma intrinsic(_InterlockedExchange64) +#pragma intrinsic(_InterlockedAnd64) +#pragma intrinsic(_InterlockedOr64) +#pragma intrinsic(_InterlockedXor64) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) _InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) _InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_AND64(dest, arg) _InterlockedAnd64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64(dest, arg) _InterlockedOr64((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64(dest, arg) _InterlockedXor64((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedCompareExchange8_nf) +#pragma intrinsic(_InterlockedCompareExchange8_acq) +#pragma intrinsic(_InterlockedCompareExchange8_rel) +#pragma intrinsic(_InterlockedCompareExchange16_nf) +#pragma intrinsic(_InterlockedCompareExchange16_acq) +#pragma intrinsic(_InterlockedCompareExchange16_rel) +#pragma intrinsic(_InterlockedCompareExchange_nf) +#pragma intrinsic(_InterlockedCompareExchange_acq) +#pragma intrinsic(_InterlockedCompareExchange_rel) +#pragma intrinsic(_InterlockedCompareExchange64) +#pragma intrinsic(_InterlockedCompareExchange64_nf) +#pragma intrinsic(_InterlockedCompareExchange64_acq) +#pragma intrinsic(_InterlockedCompareExchange64_rel) +#pragma intrinsic(_InterlockedCompareExchangePointer) +#pragma intrinsic(_InterlockedCompareExchangePointer_nf) +#pragma intrinsic(_InterlockedCompareExchangePointer_acq) +#pragma intrinsic(_InterlockedCompareExchangePointer_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELAXED(dest, exchange, compare) _InterlockedCompareExchange8_nf((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange8_acq((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELEASE(dest, exchange, compare) _InterlockedCompareExchange8_rel((char*)(dest), (char)(exchange), (char)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELAXED(dest, exchange, compare) _InterlockedCompareExchange16_nf((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange16_acq((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELEASE(dest, exchange, compare) _InterlockedCompareExchange16_rel((short*)(dest), (short)(exchange), (short)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELAXED(dest, exchange, compare) _InterlockedCompareExchange_nf((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange_acq((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELEASE(dest, exchange, compare) _InterlockedCompareExchange_rel((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) _InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELAXED(dest, exchange, compare) _InterlockedCompareExchange64_nf((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchange64_acq((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELEASE(dest, exchange, compare) _InterlockedCompareExchange64_rel((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) _InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_RELAXED(dest, exchange, compare) _InterlockedCompareExchangePointer_nf((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_ACQUIRE(dest, exchange, compare) _InterlockedCompareExchangePointer_acq((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER_RELEASE(dest, exchange, compare) _InterlockedCompareExchangePointer_rel((void**)(dest), (void*)(exchange), (void*)(compare)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchangeAdd8_nf) +#pragma intrinsic(_InterlockedExchangeAdd8_acq) +#pragma intrinsic(_InterlockedExchangeAdd8_rel) +#pragma intrinsic(_InterlockedExchangeAdd16_nf) +#pragma intrinsic(_InterlockedExchangeAdd16_acq) +#pragma intrinsic(_InterlockedExchangeAdd16_rel) +#pragma intrinsic(_InterlockedExchangeAdd_nf) +#pragma intrinsic(_InterlockedExchangeAdd_acq) +#pragma intrinsic(_InterlockedExchangeAdd_rel) +#pragma intrinsic(_InterlockedExchangeAdd64_nf) +#pragma intrinsic(_InterlockedExchangeAdd64_acq) +#pragma intrinsic(_InterlockedExchangeAdd64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELAXED(dest, addend) _InterlockedExchangeAdd8_nf((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_ACQUIRE(dest, addend) _InterlockedExchangeAdd8_acq((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELEASE(dest, addend) _InterlockedExchangeAdd8_rel((char*)(dest), (char)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELAXED(dest, addend) _InterlockedExchangeAdd16_nf((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_ACQUIRE(dest, addend) _InterlockedExchangeAdd16_acq((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELEASE(dest, addend) _InterlockedExchangeAdd16_rel((short*)(dest), (short)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED(dest, addend) _InterlockedExchangeAdd_nf((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE(dest, addend) _InterlockedExchangeAdd_acq((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE(dest, addend) _InterlockedExchangeAdd_rel((long*)(dest), (long)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED(dest, addend) _InterlockedExchangeAdd64_nf((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE(dest, addend) _InterlockedExchangeAdd64_acq((__int64*)(dest), (__int64)(addend)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE(dest, addend) _InterlockedExchangeAdd64_rel((__int64*)(dest), (__int64)(addend)) + +#if defined(_M_ARM64) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELAXED(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_ACQUIRE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE((__int64*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELEASE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE((__int64*)(dest), byte_offset)) +#else +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELAXED(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_ACQUIRE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE((long*)(dest), byte_offset)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER_RELEASE(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE((long*)(dest), byte_offset)) +#endif + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedExchange8_nf) +#pragma intrinsic(_InterlockedExchange8_acq) +#pragma intrinsic(_InterlockedExchange16_nf) +#pragma intrinsic(_InterlockedExchange16_acq) +#pragma intrinsic(_InterlockedExchange_nf) +#pragma intrinsic(_InterlockedExchange_acq) +#pragma intrinsic(_InterlockedExchange64_nf) +#pragma intrinsic(_InterlockedExchange64_acq) +#pragma intrinsic(_InterlockedExchangePointer) +#pragma intrinsic(_InterlockedExchangePointer_nf) +#pragma intrinsic(_InterlockedExchangePointer_acq) +#if _MSC_VER >= 1800 +#pragma intrinsic(_InterlockedExchange8_rel) +#pragma intrinsic(_InterlockedExchange16_rel) +#pragma intrinsic(_InterlockedExchange_rel) +#pragma intrinsic(_InterlockedExchange64_rel) +#pragma intrinsic(_InterlockedExchangePointer_rel) +#endif +#endif + +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELAXED(dest, newval) _InterlockedExchange8_nf((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_ACQUIRE(dest, newval) _InterlockedExchange8_acq((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELAXED(dest, newval) _InterlockedExchange16_nf((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_ACQUIRE(dest, newval) _InterlockedExchange16_acq((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELAXED(dest, newval) _InterlockedExchange_nf((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ACQUIRE(dest, newval) _InterlockedExchange_acq((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELAXED(dest, newval) _InterlockedExchange64_nf((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_ACQUIRE(dest, newval) _InterlockedExchange64_acq((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) _InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELAXED(dest, newval) _InterlockedExchangePointer_nf((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_ACQUIRE(dest, newval) _InterlockedExchangePointer_acq((void**)(dest), (void*)(newval)) + +#if _MSC_VER >= 1800 +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(dest, newval) _InterlockedExchange8_rel((char*)(dest), (char)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(dest, newval) _InterlockedExchange16_rel((short*)(dest), (short)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(dest, newval) _InterlockedExchange_rel((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(dest, newval) _InterlockedExchange64_rel((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELEASE(dest, newval) _InterlockedExchangePointer_rel((void**)(dest), (void*)(newval)) +#else +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER_RELEASE(dest, newval) BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) +#endif + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedAnd8_nf) +#pragma intrinsic(_InterlockedAnd8_acq) +#pragma intrinsic(_InterlockedAnd8_rel) +#pragma intrinsic(_InterlockedAnd16_nf) +#pragma intrinsic(_InterlockedAnd16_acq) +#pragma intrinsic(_InterlockedAnd16_rel) +#pragma intrinsic(_InterlockedAnd_nf) +#pragma intrinsic(_InterlockedAnd_acq) +#pragma intrinsic(_InterlockedAnd_rel) +#pragma intrinsic(_InterlockedAnd64_nf) +#pragma intrinsic(_InterlockedAnd64_acq) +#pragma intrinsic(_InterlockedAnd64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_AND8_RELAXED(dest, arg) _InterlockedAnd8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND8_ACQUIRE(dest, arg) _InterlockedAnd8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND8_RELEASE(dest, arg) _InterlockedAnd8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_RELAXED(dest, arg) _InterlockedAnd16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_ACQUIRE(dest, arg) _InterlockedAnd16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND16_RELEASE(dest, arg) _InterlockedAnd16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_RELAXED(dest, arg) _InterlockedAnd_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_ACQUIRE(dest, arg) _InterlockedAnd_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND_RELEASE(dest, arg) _InterlockedAnd_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_RELAXED(dest, arg) _InterlockedAnd64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_ACQUIRE(dest, arg) _InterlockedAnd64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_AND64_RELEASE(dest, arg) _InterlockedAnd64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedOr8_nf) +#pragma intrinsic(_InterlockedOr8_acq) +#pragma intrinsic(_InterlockedOr8_rel) +#pragma intrinsic(_InterlockedOr16_nf) +#pragma intrinsic(_InterlockedOr16_acq) +#pragma intrinsic(_InterlockedOr16_rel) +#pragma intrinsic(_InterlockedOr_nf) +#pragma intrinsic(_InterlockedOr_acq) +#pragma intrinsic(_InterlockedOr_rel) +#pragma intrinsic(_InterlockedOr64_nf) +#pragma intrinsic(_InterlockedOr64_acq) +#pragma intrinsic(_InterlockedOr64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_OR8_RELAXED(dest, arg) _InterlockedOr8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8_ACQUIRE(dest, arg) _InterlockedOr8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR8_RELEASE(dest, arg) _InterlockedOr8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_RELAXED(dest, arg) _InterlockedOr16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_ACQUIRE(dest, arg) _InterlockedOr16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR16_RELEASE(dest, arg) _InterlockedOr16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_RELAXED(dest, arg) _InterlockedOr_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_ACQUIRE(dest, arg) _InterlockedOr_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR_RELEASE(dest, arg) _InterlockedOr_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_RELAXED(dest, arg) _InterlockedOr64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_ACQUIRE(dest, arg) _InterlockedOr64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_OR64_RELEASE(dest, arg) _InterlockedOr64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_InterlockedXor8_nf) +#pragma intrinsic(_InterlockedXor8_acq) +#pragma intrinsic(_InterlockedXor8_rel) +#pragma intrinsic(_InterlockedXor16_nf) +#pragma intrinsic(_InterlockedXor16_acq) +#pragma intrinsic(_InterlockedXor16_rel) +#pragma intrinsic(_InterlockedXor_nf) +#pragma intrinsic(_InterlockedXor_acq) +#pragma intrinsic(_InterlockedXor_rel) +#pragma intrinsic(_InterlockedXor64_nf) +#pragma intrinsic(_InterlockedXor64_acq) +#pragma intrinsic(_InterlockedXor64_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_XOR8_RELAXED(dest, arg) _InterlockedXor8_nf((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8_ACQUIRE(dest, arg) _InterlockedXor8_acq((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR8_RELEASE(dest, arg) _InterlockedXor8_rel((char*)(dest), (char)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_RELAXED(dest, arg) _InterlockedXor16_nf((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_ACQUIRE(dest, arg) _InterlockedXor16_acq((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR16_RELEASE(dest, arg) _InterlockedXor16_rel((short*)(dest), (short)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_RELAXED(dest, arg) _InterlockedXor_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_ACQUIRE(dest, arg) _InterlockedXor_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR_RELEASE(dest, arg) _InterlockedXor_rel((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_RELAXED(dest, arg) _InterlockedXor64_nf((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_ACQUIRE(dest, arg) _InterlockedXor64_acq((__int64*)(dest), (__int64)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_XOR64_RELEASE(dest, arg) _InterlockedXor64_rel((__int64*)(dest), (__int64)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandset_nf) +#pragma intrinsic(_interlockedbittestandset_acq) +#pragma intrinsic(_interlockedbittestandset_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTS_RELAXED(dest, arg) _interlockedbittestandset_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS_ACQUIRE(dest, arg) _interlockedbittestandset_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTS_RELEASE(dest, arg) _interlockedbittestandset_rel((long*)(dest), (long)(arg)) + +#if defined(BOOST_MSVC) +#pragma intrinsic(_interlockedbittestandreset_nf) +#pragma intrinsic(_interlockedbittestandreset_acq) +#pragma intrinsic(_interlockedbittestandreset_rel) +#endif + +#define BOOST_ATOMIC_INTERLOCKED_BTR_RELAXED(dest, arg) _interlockedbittestandreset_nf((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR_ACQUIRE(dest, arg) _interlockedbittestandreset_acq((long*)(dest), (long)(arg)) +#define BOOST_ATOMIC_INTERLOCKED_BTR_RELEASE(dest, arg) _interlockedbittestandreset_rel((long*)(dest), (long)(arg)) + +#endif // _MSC_VER >= 1700 && defined(_M_ARM) + +#endif // _MSC_VER < 1400 + +#else // defined(_MSC_VER) && _MSC_VER >= 1310 + +#if defined(BOOST_USE_WINDOWS_H) + +#include + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +#else // defined(BOOST_USE_WINDOWS_H) + +#if defined(__MINGW64__) +#define BOOST_ATOMIC_INTERLOCKED_IMPORT +#else +#define BOOST_ATOMIC_INTERLOCKED_IMPORT __declspec(dllimport) +#endif + +namespace boost { +namespace atomics { +namespace detail { + +extern "C" { + +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedCompareExchange(long volatile*, long, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchange(long volatile*, long); +BOOST_ATOMIC_INTERLOCKED_IMPORT long __stdcall InterlockedExchangeAdd(long volatile*, long); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange((long*)(dest), (long)(exchange), (long)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval) boost::atomics::detail::InterlockedExchange((long*)(dest), (long)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, addend) boost::atomics::detail::InterlockedExchangeAdd((long*)(dest), (long)(addend)) + +#if defined(_WIN64) + +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedCompareExchange64(__int64 volatile*, __int64, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchange64(__int64 volatile*, __int64); +BOOST_ATOMIC_INTERLOCKED_IMPORT __int64 __stdcall InterlockedExchangeAdd64(__int64 volatile*, __int64); + +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedCompareExchangePointer(void* volatile *, void*, void*); +BOOST_ATOMIC_INTERLOCKED_IMPORT void* __stdcall InterlockedExchangePointer(void* volatile *, void*); + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchange64((__int64*)(dest), (__int64)(exchange), (__int64)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(dest, newval) boost::atomics::detail::InterlockedExchange64((__int64*)(dest), (__int64)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, addend) boost::atomics::detail::InterlockedExchangeAdd64((__int64*)(dest), (__int64)(addend)) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) boost::atomics::detail::InterlockedCompareExchangePointer((void**)(dest), (void*)(exchange), (void*)(compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) boost::atomics::detail::InterlockedExchangePointer((void**)(dest), (void*)(newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(dest, byte_offset)) + +#else // defined(_WIN64) + +#define BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_POINTER(dest, exchange, compare) ((void*)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(dest, exchange, compare)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_POINTER(dest, newval) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE(dest, newval)) +#define BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_POINTER(dest, byte_offset) ((void*)BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(dest, byte_offset)) + +#endif // defined(_WIN64) + +} // extern "C" + +} // namespace detail +} // namespace atomics +} // namespace boost + +#undef BOOST_ATOMIC_INTERLOCKED_IMPORT + +#endif // defined(BOOST_USE_WINDOWS_H) + +#endif // defined(_MSC_VER) + +#endif diff --git a/third-party/boost/boost/atomic/detail/link.hpp b/third-party/boost/boost/atomic/detail/link.hpp new file mode 100644 index 000000000..4f522acbc --- /dev/null +++ b/third-party/boost/boost/atomic/detail/link.hpp @@ -0,0 +1,58 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2012 Hartmut Kaiser + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/config.hpp + * + * This header defines macros for linking with compiled library of Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_LINK_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_LINK_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Set up dll import/export options +#if (defined(BOOST_ATOMIC_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)) && \ + !defined(BOOST_ATOMIC_STATIC_LINK) + +#if defined(BOOST_ATOMIC_SOURCE) +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_EXPORT +#define BOOST_ATOMIC_BUILD_DLL +#else +#define BOOST_ATOMIC_DECL BOOST_SYMBOL_IMPORT +#endif + +#endif // building a shared library + +#ifndef BOOST_ATOMIC_DECL +#define BOOST_ATOMIC_DECL +#endif + +/////////////////////////////////////////////////////////////////////////////// +// Auto library naming +#if !defined(BOOST_ATOMIC_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \ + !defined(BOOST_ATOMIC_NO_LIB) + +#define BOOST_LIB_NAME boost_atomic + +// tell the auto-link code to select a dll when required: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_ATOMIC_DYN_LINK) +#define BOOST_DYN_LINK +#endif + +#include + +#endif // auto-linking disabled + +#endif diff --git a/third-party/boost/boost/atomic/detail/lockpool.hpp b/third-party/boost/boost/atomic/detail/lockpool.hpp new file mode 100644 index 000000000..4e249aa04 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/lockpool.hpp @@ -0,0 +1,51 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013-2014 Andrey Semashev + */ +/*! + * \file atomic/detail/lockpool.hpp + * + * This header contains declaration of the lockpool used to emulate atomic ops. + */ + +#ifndef BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct lockpool +{ + class scoped_lock + { + void* m_lock; + + public: + explicit BOOST_ATOMIC_DECL scoped_lock(const volatile void* addr) BOOST_NOEXCEPT; + BOOST_ATOMIC_DECL ~scoped_lock() BOOST_NOEXCEPT; + + BOOST_DELETED_FUNCTION(scoped_lock(scoped_lock const&)) + BOOST_DELETED_FUNCTION(scoped_lock& operator=(scoped_lock const&)) + }; + + static BOOST_ATOMIC_DECL void thread_fence() BOOST_NOEXCEPT; + static BOOST_ATOMIC_DECL void signal_fence() BOOST_NOEXCEPT; +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_LOCKPOOL_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/operations.hpp b/third-party/boost/boost/atomic/detail/operations.hpp new file mode 100644 index 000000000..d81399a8e --- /dev/null +++ b/third-party/boost/boost/atomic/detail/operations.hpp @@ -0,0 +1,24 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations.hpp + * + * This header defines atomic operations, including the emulated version. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/operations_fwd.hpp b/third-party/boost/boost/atomic/detail/operations_fwd.hpp new file mode 100644 index 000000000..efd497074 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/operations_fwd.hpp @@ -0,0 +1,35 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations_fwd.hpp + * + * This header contains forward declaration of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t Size, bool Signed > +struct operations; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_FWD_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/operations_lockfree.hpp b/third-party/boost/boost/atomic/detail/operations_lockfree.hpp new file mode 100644 index 000000000..62b45836b --- /dev/null +++ b/third-party/boost/boost/atomic/detail/operations_lockfree.hpp @@ -0,0 +1,30 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/operations_lockfree.hpp + * + * This header defines lockfree atomic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ + +#include +#include + +#if !defined(BOOST_ATOMIC_EMULATED) +#include BOOST_ATOMIC_DETAIL_BACKEND_HEADER(boost/atomic/detail/ops_) +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPERATIONS_LOCKFREE_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_cas_based.hpp b/third-party/boost/boost/atomic/detail/ops_cas_based.hpp new file mode 100644 index 000000000..e2e18aa38 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_cas_based.hpp @@ -0,0 +1,107 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_cas_based.hpp + * + * This header contains CAS-based implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base > +struct cas_based_exchange : + public Base +{ + typedef typename Base::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, v, order, memory_order_relaxed)) {} + return old_val; + } +}; + +template< typename Base > +struct cas_based_operations : + public Base +{ + typedef typename Base::storage_type storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val + v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val - v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val & v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val | v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + while (!Base::compare_exchange_weak(storage, old_val, old_val ^ v, order, memory_order_relaxed)) {} + return old_val; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Base::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + Base::store(storage, (storage_type)0, order); + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_CAS_BASED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_emulated.hpp b/third-party/boost/boost/atomic/detail/ops_emulated.hpp new file mode 100644 index 000000000..f30fbdab9 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_emulated.hpp @@ -0,0 +1,162 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_emulated.hpp + * + * This header contains lockpool-based implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< std::size_t Size, bool Signed > +struct emulated_operations +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = false; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + lockpool::scoped_lock lock(&storage); + const_cast< storage_type& >(storage) = v; + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + lockpool::scoped_lock lock(&storage); + return const_cast< storage_type const& >(storage); + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s += v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s -= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s = v; + return old_val; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + const bool res = old_val == expected; + if (res) + s = desired; + expected = old_val; + + return res; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + // Note: This function is the exact copy of compare_exchange_strong. The reason we're not just forwarding the call + // is that MSVC-12 ICEs in this case. + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + const bool res = old_val == expected; + if (res) + s = desired; + expected = old_val; + + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s &= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s |= v; + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type& s = const_cast< storage_type& >(storage); + lockpool::scoped_lock lock(&storage); + storage_type old_val = s; + s ^= v; + return old_val; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< std::size_t Size, bool Signed > +struct operations : + public emulated_operations< Size, Signed > +{ +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_EMULATED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_extending_cas_based.hpp b/third-party/boost/boost/atomic/detail/ops_extending_cas_based.hpp new file mode 100644 index 000000000..5f197cea4 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_extending_cas_based.hpp @@ -0,0 +1,69 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_extending_cas_based.hpp + * + * This header contains a boilerplate of the \c operations template implementation that requires sign/zero extension in arithmetic operations. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename Base, std::size_t Size, bool Signed > +struct extending_cas_based_operations : + public Base +{ + typedef typename Base::storage_type storage_type; + typedef typename make_storage_type< Size >::type emulated_storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + storage_type new_val; + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val + v)); + } + while (!Base::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return old_val; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type old_val; + atomics::detail::non_atomic_load(storage, old_val); + storage_type new_val; + do + { + new_val = atomics::detail::integral_extend< Signed, storage_type >(static_cast< emulated_storage_type >(old_val - v)); + } + while (!Base::compare_exchange_weak(storage, old_val, new_val, order, memory_order_relaxed)); + return old_val; + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_EXTENDING_CAS_BASED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_alpha.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_alpha.hpp new file mode 100644 index 000000000..85b134298 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_alpha.hpp @@ -0,0 +1,876 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_alpha.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* + Refer to http://h71000.www7.hp.com/doc/82final/5601/5601pro_004.html + (HP OpenVMS systems documentation) and the Alpha Architecture Reference Manual. + */ + +/* + NB: The most natural thing would be to write the increment/decrement + operators along the following lines: + + __asm__ __volatile__ + ( + "1: ldl_l %0,%1 \n" + "addl %0,1,%0 \n" + "stl_c %0,%1 \n" + "beq %0,1b\n" + : "=&b" (tmp) + : "m" (value) + : "cc" + ); + + However according to the comments on the HP website and matching + comments in the Linux kernel sources this defies branch prediction, + as the cpu assumes that backward branches are always taken; so + instead copy the trick from the Linux kernel, introduce a forward + branch and back again. + + I have, however, had a hard time measuring the difference between + the two versions in microbenchmarks -- I am leaving it in nevertheless + as it apparently does not hurt either. +*/ + +struct gcc_alpha_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("mb" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("mb" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("mb" ::: "memory"); + } +}; + + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_alpha_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, tmp; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "mov %3, %1\n" + "ldl_l %0, %2\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (tmp) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + int success; + storage_type current; + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stl_c %1, %4\n" // storage = desired; desired = store succeeded + "mov %1, %3\n" // success = desired + "2:\n" + : "+&r" (expected), // %0 + "+&r" (desired), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + storage_type current, tmp; + fence_before(success_order); + __asm__ __volatile__ + ( + "1:\n" + "mov %5, %1\n" // tmp = desired + "ldl_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stl_c %1, %4\n" // storage = tmp; tmp = store succeeded + "beq %1, 3f\n" // if (tmp == 0) goto retry + "mov %1, %3\n" // success = tmp + "2:\n" + + ".subsection 2\n" + "3: br 1b\n" + ".previous\n" + + : "+&r" (expected), // %0 + "=&r" (tmp), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage), // %4 + "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "and %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "bis %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "xor %0, %3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "zapnot %1, #1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "zapnot %1, #1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "sextb %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "sextb %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "zapnot %1, #3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "zapnot %1, #3, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "addl %0, %3, %1\n" + "sextw %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldl_l %0, %2\n" + "subl %0, %3, %1\n" + "sextw %1, %1\n" + "stl_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_alpha_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, tmp; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "mov %3, %1\n" + "ldq_l %0, %2\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (tmp) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + int success; + storage_type current; + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stq_c %1, %4\n" // storage = desired; desired = store succeeded + "mov %1, %3\n" // success = desired + "2:\n" + : "+&r" (expected), // %0 + "+&r" (desired), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + storage_type current, tmp; + fence_before(success_order); + __asm__ __volatile__ + ( + "1:\n" + "mov %5, %1\n" // tmp = desired + "ldq_l %2, %4\n" // current = *(&storage) + "cmpeq %2, %0, %3\n" // success = current == expected + "mov %2, %0\n" // expected = current + "beq %3, 2f\n" // if (success == 0) goto end + "stq_c %1, %4\n" // storage = tmp; tmp = store succeeded + "beq %1, 3f\n" // if (tmp == 0) goto retry + "mov %1, %3\n" // success = tmp + "2:\n" + + ".subsection 2\n" + "3: br 1b\n" + ".previous\n" + + : "+&r" (expected), // %0 + "=&r" (tmp), // %1 + "=&r" (current), // %2 + "=&r" (success) // %3 + : "m" (storage), // %4 + "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "addq %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "subq %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "and %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "bis %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, modified; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n" + "ldq_l %0, %2\n" + "xor %0, %3, %1\n" + "stq_c %1, %2\n" + "beq %1, 2f\n" + + ".subsection 2\n" + "2: br 1b\n" + ".previous\n" + + : "=&r" (original), // %0 + "=&r" (modified) // %1 + : "m" (storage), // %2 + "r" (v) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("mb" ::: "memory"); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ALPHA_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_arm.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_arm.hpp new file mode 100644 index 000000000..b32159536 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_arm.hpp @@ -0,0 +1,1397 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// From the ARM Architecture Reference Manual for architecture v6: +// +// LDREX{} , [] +// Specifies the destination register for the memory word addressed by +// Specifies the register containing the address. +// +// STREX{} , , [] +// Specifies the destination register for the returned status value. +// 0 if the operation updates memory +// 1 if the operation fails to update memory +// Specifies the register containing the word to be stored to memory. +// Specifies the register containing the address. +// Rd must not be the same register as Rm or Rn. +// +// ARM v7 is like ARM v6 plus: +// There are half-word and byte versions of the LDREX and STREX instructions, +// LDREXH, LDREXB, STREXH and STREXB. +// There are also double-word versions, LDREXD and STREXD. +// (Actually it looks like these are available from version 6k onwards.) +// FIXME these are not yet used; should be mostly a matter of copy-and-paste. +// I think you can supply an immediate offset to the address. + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // load the original value + "strex %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrex %[original], %[storage]\n" // original = *(&storage) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexeq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (expected), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strex %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (expected), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "and %[result], %[original], %[value]\n" // result = original & value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "orr %[result], %[original], %[value]\n" // result = original | value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 1u >::type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + extended_storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // load the original value and zero-extend to 32 bits + "strexb %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexbeq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strexb %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexb %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexb %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "uxtb %[result], %[result]\n" // zero extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "sxtb %[result], %[result]\n" // sign extend result from 8 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXB_STREXB) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 2u >::type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type extended_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + extended_storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // load the original value and zero-extend to 32 bits + "strexh %[tmp], %[value], %[storage]\n" // store the replacement, tmp = store failed + "teq %[tmp], #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [tmp] "=&l" (tmp), [original] "=&r" (original), [storage] "+Q" (storage) + : [value] "r" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "itt eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "strexheq %[success], %[desired], %[storage]\n" // if (flags.equal) *(&storage) = desired, success = store failed + "eoreq %[success], %[success], #1\n" // if (flags.equal) success ^= 1 (i.e. make it 1 if store succeeded) + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t success; + uint32_t tmp; + extended_storage_type original; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "mov %[success], #0\n" // success = 0 + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "cmp %[original], %[expected]\n" // flags = original==expected + "bne 2f\n" // if (!flags.equal) goto end + "strexh %[success], %[desired], %[storage]\n" // *(&storage) = desired, success = store failed + "eors %[success], %[success], #1\n" // success ^= 1 (i.e. make it 1 if store succeeded); flags.equal = success == 0 + "beq 1b\n" // if (flags.equal) goto retry + "2:\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [success] "=&r" (success), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [expected] "Ir" (atomics::detail::zero_extend< extended_storage_type >(expected)), // %4 + [desired] "r" (desired) // %5 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = static_cast< storage_type >(original); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "add %[result], %[original], %[value]\n" // result = original + value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "sub %[result], %[original], %[value]\n" // result = original - value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "and %[result], %[original], %[value]\n" // result = original & value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "orr %[result], %[original], %[value]\n" // result = original | value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + extended_storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrexh %[original], %[storage]\n" // original = zero_extend(*(&storage)) + "eor %[result], %[original], %[value]\n" // result = original ^ value + "strexh %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return static_cast< storage_type >(original); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "uxth %[result], %[result]\n" // zero extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "add %[result], %[original], %[value]\n" // result = original + value + "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + uint32_t tmp; + storage_type original, result; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%[tmp]) + "1:\n" + "ldrex %[original], %[storage]\n" // original = *(&storage) + "sub %[result], %[original], %[value]\n" // result = original - value + "sxth %[result], %[result]\n" // sign extend result from 16 to 32 bits + "strex %[tmp], %[result], %[storage]\n" // *(&storage) = result, tmp = store failed + "teq %[tmp], #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%[tmp]) + : [original] "=&r" (original), // %0 + [result] "=&r" (result), // %1 + [tmp] "=&l" (tmp), // %2 + [storage] "+Q" (storage) // %3 + : [value] "Ir" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXH_STREXH) + +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + +// Unlike 32-bit operations, for 64-bit loads and stores we must use ldrexd/strexd. +// Any other instructions result in a non-atomic sequence of 32-bit accesses. +// See "ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition", +// Section A3.5.3 "Atomicity in the ARM architecture". + +// In the asm blocks below we have to use 32-bit register pairs to compose 64-bit values. +// In order to pass the 64-bit operands to/from asm blocks, we use undocumented gcc feature: +// the lower half (Rt) of the operand is accessible normally, via the numbered placeholder (e.g. %0), +// and the upper half (Rt2) - via the same placeholder with an 'H' after the '%' sign (e.g. %H0). +// See: http://hardwarebug.org/2010/07/06/arm-inline-asm-secrets/ + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_arm_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + exchange(storage, v, order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "ldrexd %1, %H1, [%2]\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original) // %1 + : "r" (&storage) // %2 + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // load the original value + "strexd %0, %2, %H2, [%3]\n" // store the replacement, tmp = store failed + "teq %0, #0\n" // check if store succeeded + "bne 1b\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original) // %1 + : "r" (v), // %2 + "r" (&storage) // %3 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t tmp; + storage_type original, old_val = expected; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "cmp %1, %2\n" // flags = original.lo==old_val.lo + "ittt eq\n" // [hint that the following 3 instructions are conditional on flags.equal] + "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi + "strexdeq %0, %4, %H4, [%3]\n" // if (flags.equal) *(&storage) = desired, tmp = store failed + "teqeq %0, #0\n" // if (flags.equal) flags = tmp==0 + "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1 + "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0 + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "+r" (old_val) // %2 + : "r" (&storage), // %3 + "r" (desired) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + const uint32_t success = (uint32_t)old_val; + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + uint32_t tmp; + storage_type original, old_val = expected; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "cmp %1, %2\n" // flags = original.lo==old_val.lo + "it eq\n" // [hint that the following instruction is conditional on flags.equal] + "cmpeq %H1, %H2\n" // if (flags.equal) flags = original.hi==old_val.hi + "bne 2f\n" // if (!flags.equal) goto end + "strexd %0, %4, %H4, [%3]\n" // *(&storage) = desired, tmp = store failed + "teq %0, #0\n" // flags.equal = tmp == 0 + "bne 1b\n" // if (flags.equal) goto retry + "2:\n" + "ite eq\n" // [hint that the following 2 instructions are conditional on flags.equal] + "moveq %2, #1\n" // if (flags.equal) old_val.lo = 1 + "movne %2, #0\n" // if (!flags.equal) old_val.lo = 0 + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "+r" (old_val) // %2 + : "r" (&storage), // %3 + "r" (desired) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + const uint32_t success = (uint32_t)old_val; + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = original; + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "adds %2, %1, %4\n" // result = original + value + "adc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "subs %2, %1, %4\n" // result = original - value + "sbc %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "and %2, %1, %4\n" // result = original & value + "and %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "orr %2, %1, %4\n" // result = original | value + "orr %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage_type original, result; + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "1:\n" + "ldrexd %1, %H1, [%3]\n" // original = *(&storage) + "eor %2, %1, %4\n" // result = original ^ value + "eor %H2, %H1, %H4\n" + "strexd %0, %2, %H2, [%3]\n" // *(&storage) = result, tmp = store failed + "teq %0, #0\n" // flags = tmp==0 + "bne 1b\n" // if (!flags.equal) goto retry + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(tmp), // %0 + "=&r" (original), // %1 + "=&r" (result) // %2 + : "r" (&storage), // %3 + "r" (v) // %4 + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_ARM_HAS_LDREXD_STREXD) + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + gcc_arm_operations_base::hardware_full_fence(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_arm_common.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_arm_common.hpp new file mode 100644 index 000000000..73c04ffe1 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_arm_common.hpp @@ -0,0 +1,134 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_arm_common.hpp + * + * This header contains basic utilities for gcc ARM backend. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// A memory barrier is effected using a "co-processor 15" instruction, +// though a separate assembler mnemonic is available for it in v7. +// +// "Thumb 1" is a subset of the ARM instruction set that uses a 16-bit encoding. It +// doesn't include all instructions and in particular it doesn't include the co-processor +// instruction used for the memory barrier or the load-locked/store-conditional +// instructions. So, if we're compiling in "Thumb 1" mode, we need to wrap all of our +// asm blocks with code to temporarily change to ARM mode. +// +// You can only change between ARM and Thumb modes when branching using the bx instruction. +// bx takes an address specified in a register. The least significant bit of the address +// indicates the mode, so 1 is added to indicate that the destination code is Thumb. +// A temporary register is needed for the address and is passed as an argument to these +// macros. It must be one of the "low" registers accessible to Thumb code, specified +// using the "l" attribute in the asm statement. +// +// Architecture v7 introduces "Thumb 2", which does include (almost?) all of the ARM +// instruction set. (Actually, there was an extension of v6 called v6T2 which supported +// "Thumb 2" mode, but its architecture manual is no longer available, referring to v7.) +// So in v7 we don't need to change to ARM mode; we can write "universal +// assembler" which will assemble to Thumb 2 or ARM code as appropriate. The only thing +// we need to do to make this "universal" assembler mode work is to insert "IT" instructions +// to annotate the conditional instructions. These are ignored in other modes (e.g. v6), +// so they can always be present. + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +#if defined(__thumb__) && !defined(__thumb2__) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG) "adr " #TMPREG ", 8f\n" "bx " #TMPREG "\n" ".arm\n" ".align 4\n" "8:\n" +#define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG) "adr " #TMPREG ", 9f + 1\n" "bx " #TMPREG "\n" ".thumb\n" ".align 2\n" "9:\n" +#define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&l" (var) +#else +// The tmpreg may be wasted in this case, which is non-optimal. +#define BOOST_ATOMIC_DETAIL_ARM_ASM_START(TMPREG) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_END(TMPREG) +#define BOOST_ATOMIC_DETAIL_ARM_ASM_TMPREG_CONSTRAINT(var) "=&r" (var) +#endif + +struct gcc_arm_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_ARM_HAS_DMB) + // Older binutils (supposedly, older than 2.21.1) didn't support symbolic or numeric arguments of the "dmb" instruction such as "ish" or "#11". + // As a workaround we have to inject encoded bytes of the instruction. There are two encodings for the instruction: ARM and Thumb. See ARM Architecture Reference Manual, A8.8.43. + // Since we cannot detect binutils version at compile time, we'll have to always use this hack. + __asm__ __volatile__ + ( +#if defined(__thumb2__) + ".short 0xF3BF, 0x8F5B\n" // dmb ish +#else + ".word 0xF57FF05B\n" // dmb ish +#endif + : + : + : "memory" + ); +#else + uint32_t tmp; + __asm__ __volatile__ + ( + BOOST_ATOMIC_DETAIL_ARM_ASM_START(%0) + "mcr\tp15, 0, r0, c7, c10, 5\n" + BOOST_ATOMIC_DETAIL_ARM_ASM_END(%0) + : "=&l" (tmp) + : + : "memory" + ); +#endif + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ARM_COMMON_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_atomic.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_atomic.hpp new file mode 100644 index 000000000..ce40e3b2b --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_atomic.hpp @@ -0,0 +1,392 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_atomic.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 70000)) && (defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B)) +#include +#include +#endif + +#if __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE || __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE ||\ + __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE || __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE ||\ + __GCC_ATOMIC_CHAR_LOCK_FREE != BOOST_ATOMIC_CHAR_LOCK_FREE || __GCC_ATOMIC_BOOL_LOCK_FREE != BOOST_ATOMIC_BOOL_LOCK_FREE ||\ + __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE +// There are platforms where we need to use larger storage types +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__INTEL_COMPILER) +// This is used to suppress warning #32013 described below for Intel Compiler. +// In debug builds the compiler does not inline any functions, so basically +// every atomic function call results in this warning. I don't know any other +// way to selectively disable just this one warning. +#pragma system_header +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/*! + * The function converts \c boost::memory_order values to the compiler-specific constants. + * + * NOTE: The intention is that the function is optimized away by the compiler, and the + * compiler-specific constants are passed to the intrinsics. Unfortunately, constexpr doesn't + * work in this case because the standard atomics interface require memory ordering + * constants to be passed as function arguments, at which point they stop being constexpr. + * However, it is crucial that the compiler sees constants and not runtime values, + * because otherwise it just ignores the ordering value and always uses seq_cst. + * This is the case with Intel C++ Compiler 14.0.3 (Composer XE 2013 SP1, update 3) and + * gcc 4.8.2. Intel Compiler issues a warning in this case: + * + * warning #32013: Invalid memory order specified. Defaulting to seq_cst memory order. + * + * while gcc acts silently. + * + * To mitigate the problem ALL functions, including the atomic<> members must be + * declared with BOOST_FORCEINLINE. In this case the compilers are able to see that + * all functions are called with constant orderings and call intrinstcts properly. + * + * Unfortunately, this still doesn't work in debug mode as the compiler doesn't + * propagate constants even when functions are marked with BOOST_FORCEINLINE. In this case + * all atomic operaions will be executed with seq_cst semantics. + */ +BOOST_FORCEINLINE BOOST_CONSTEXPR int convert_memory_order_to_gcc(memory_order order) BOOST_NOEXCEPT +{ + return (order == memory_order_relaxed ? __ATOMIC_RELAXED : (order == memory_order_consume ? __ATOMIC_CONSUME : + (order == memory_order_acquire ? __ATOMIC_ACQUIRE : (order == memory_order_release ? __ATOMIC_RELEASE : + (order == memory_order_acq_rel ? __ATOMIC_ACQ_REL : __ATOMIC_SEQ_CST))))); +} + +template< std::size_t Size, bool Signed > +struct gcc_atomic_operations +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + + // Note: In the current implementation, gcc_atomic_operations are used only when the particularly sized __atomic + // intrinsics are always lock-free (i.e. the corresponding LOCK_FREE macro is 2). Therefore it is safe to + // always set is_always_lock_free to true here. + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + __atomic_store_n(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return __atomic_load_n(&storage, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_add(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_sub(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_exchange_n(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return __atomic_compare_exchange_n + ( + &storage, &expected, desired, false, + atomics::detail::convert_memory_order_to_gcc(success_order), + atomics::detail::convert_memory_order_to_gcc(failure_order) + ); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return __atomic_compare_exchange_n + ( + &storage, &expected, desired, true, + atomics::detail::convert_memory_order_to_gcc(success_order), + atomics::detail::convert_memory_order_to_gcc(failure_order) + ); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_and(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_or(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return __atomic_fetch_xor(&storage, v, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return __atomic_test_and_set(&storage, atomics::detail::convert_memory_order_to_gcc(order)); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + __atomic_clear(const_cast< storage_type* >(&storage), atomics::detail::convert_memory_order_to_gcc(order)); + } +}; + +#if BOOST_ATOMIC_INT128_LOCK_FREE > 0 +#if (defined(__clang__) || (defined(BOOST_GCC) && (BOOST_GCC+0) >= 70000)) && defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +// Workaround for clang bug: http://llvm.org/bugs/show_bug.cgi?id=19149 +// Clang 3.4 does not implement 128-bit __atomic* intrinsics even though it defines __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 +// A similar problem exists with gcc 7 as well, as it requires to link with libatomic to use 16-byte intrinsics: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878 +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< gcc_dcas_x86_64< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#else + +template< bool Signed > +struct operations< 16u, Signed > : + public gcc_atomic_operations< 16u, Signed > +{ +}; + +#endif +#endif + + +#if BOOST_ATOMIC_INT64_LOCK_FREE > 0 +#if defined(__clang__) && defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +// Workaround for clang bug http://llvm.org/bugs/show_bug.cgi?id=19355 +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< gcc_dcas_x86< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#elif (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 8 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 8 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 8 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 8 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 8 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT64_EXTENDED + +template< bool Signed > +struct operations< 8u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 8u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_atomic_operations< 8u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT32_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 4 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 4 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 4 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 4 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 4 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT32_EXTENDED + +#if !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 4u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 4u, Signed > +{ +}; + +#else // !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 4u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 4u, Signed > +{ +}; + +#endif // !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +#else + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_atomic_operations< 4u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT16_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 2 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 2 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 2 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 2 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 2 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) + +#define BOOST_ATOMIC_DETAIL_INT16_EXTENDED + +#if !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 2u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 2u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 2u, Signed > +{ +}; + +#endif + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_atomic_operations< 2u, Signed > +{ +}; + +#endif +#endif + +#if BOOST_ATOMIC_INT8_LOCK_FREE > 0 +#if (BOOST_ATOMIC_DETAIL_SIZEOF_LLONG == 1 && __GCC_ATOMIC_LLONG_LOCK_FREE != BOOST_ATOMIC_LLONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_LONG == 1 && __GCC_ATOMIC_LONG_LOCK_FREE != BOOST_ATOMIC_LONG_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_INT == 1 && __GCC_ATOMIC_INT_LOCK_FREE != BOOST_ATOMIC_INT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_SHORT == 1 && __GCC_ATOMIC_SHORT_LOCK_FREE != BOOST_ATOMIC_SHORT_LOCK_FREE) ||\ + (BOOST_ATOMIC_DETAIL_SIZEOF_WCHAR_T == 1 && __GCC_ATOMIC_WCHAR_T_LOCK_FREE != BOOST_ATOMIC_WCHAR_T_LOCK_FREE) ||\ + (__GCC_ATOMIC_CHAR_LOCK_FREE != BOOST_ATOMIC_CHAR_LOCK_FREE) ||\ + (__GCC_ATOMIC_BOOL_LOCK_FREE != BOOST_ATOMIC_BOOL_LOCK_FREE) + +#if !defined(BOOST_ATOMIC_DETAIL_INT16_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 2u, Signed >, 1u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT32_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 4u, Signed >, 1u, Signed > +{ +}; + +#elif !defined(BOOST_ATOMIC_DETAIL_INT64_EXTENDED) + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 8u, Signed >, 1u, Signed > +{ +}; + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< gcc_atomic_operations< 16u, Signed >, 1u, Signed > +{ +}; + +#endif + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_atomic_operations< 1u, Signed > +{ +}; + +#endif +#endif + +#undef BOOST_ATOMIC_DETAIL_INT16_EXTENDED +#undef BOOST_ATOMIC_DETAIL_INT32_EXTENDED +#undef BOOST_ATOMIC_DETAIL_INT64_EXTENDED + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + __atomic_thread_fence(atomics::detail::convert_memory_order_to_gcc(order)); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + __atomic_signal_fence(atomics::detail::convert_memory_order_to_gcc(order)); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_ATOMIC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_ppc.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_ppc.hpp new file mode 100644 index 000000000..a826736d1 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_ppc.hpp @@ -0,0 +1,1232 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_ppc.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// The implementation below uses information from this document: +// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2010.02.19a.html + +/* + Refer to: Motorola: "Programming Environments Manual for 32-Bit + Implementations of the PowerPC Architecture", Appendix E: + "Synchronization Programming Examples" for an explanation of what is + going on here (can be found on the web at various places by the + name "MPCFPE32B.pdf", Google is your friend...) + + Most of the atomic operations map to instructions in a relatively + straight-forward fashion, but "load"s may at first glance appear + a bit strange as they map to: + + lwz %rX, addr + cmpw %rX, %rX + bne- 1f + 1: + + That is, the CPU is forced to perform a branch that "formally" depends + on the value retrieved from memory. This scheme has an overhead of + about 1-2 clock cycles per load, but it allows to map "acquire" to + the "isync" instruction instead of "sync" uniformly and for all type + of atomic operations. Since "isync" has a cost of about 15 clock + cycles, while "sync" hast a cost of about 50 clock cycles, the small + penalty to atomic loads more than compensates for this. + + Byte- and halfword-sized atomic values are implemented in two ways. + When 8 and 16-bit instructions are available (in Power8 and later), + they are used. Otherwise operations are realized by encoding the + value to be represented into a word, performing sign/zero extension + as appropriate. This means that after add/sub operations the value + needs fixing up to accurately preserve the wrap-around semantic of + the smaller type. (Nothing special needs to be done for the bit-wise + and the "exchange type" operators as the compiler already sees to + it that values carried in registers are extended appropriately and + everything falls into place naturally). + + The register constraint "b" instructs gcc to use any register + except r0; this is sometimes required because the encoding for + r0 is used to signify "constant zero" in a number of instructions, + making r0 unusable in this place. For simplicity this constraint + is used everywhere since I am to lazy to look this up on a + per-instruction basis, and ppc has enough registers for this not + to pose a problem. +*/ + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "stw %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lwz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lwz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y1\n\t" + "stwcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lwarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stwcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lwarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stwcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 1u >::type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "stb %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lbz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lbz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y1\n\t" + "stbcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lbarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stbcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lbarx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "stbcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lbarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stbcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +template< > +struct operations< 1u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 1u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "extsb %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "extsb %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LBARX_STBCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 2u >::type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "sth %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "lhz %0, %1\n\t" + "cmpw %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&r" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "lhz %0, %1\n\t" + : "=&r" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y1\n\t" + "sthcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "lharx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "sthcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: lharx %0,%y2\n\t" + "cmpw %0, %3\n\t" + "bne- 1f\n\t" + "sthcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lharx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "sthcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#else // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +template< > +struct operations< 2u, false > : + public operations< 4u, false > +{ + typedef operations< 4u, false > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xffff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "rlwinm %1, %1, 0, 0xffff\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +template< > +struct operations< 2u, true > : + public operations< 4u, true > +{ + typedef operations< 4u, true > base_type; + typedef base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "extsh %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "lwarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "extsh %1, %1\n\t" + "stwcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LHARX_STHCX) + +#if defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_ppc_operations_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "std %1, %0\n\t" + : "+m" (storage) + : "r" (v) + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v; + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + { + __asm__ __volatile__ + ( + "ld %0, %1\n\t" + "cmpd %0, %0\n\t" + "bne- 1f\n\t" + "1:\n\t" + "isync\n\t" + : "=&b" (v) + : "m" (storage) + : "cr0", "memory" + ); + } + else + { + __asm__ __volatile__ + ( + "ld %0, %1\n\t" + : "=&b" (v) + : "m" (storage) + ); + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y1\n\t" + "stdcx. %2,%y1\n\t" + "bne- 1b\n\t" + : "=&b" (original), "+Z" (storage) + : "b" (v) + : "cr0" + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "ldarx %0,%y2\n\t" + "cmpd %0, %3\n\t" + "bne- 1f\n\t" + "stdcx. %4,%y2\n\t" + "bne- 1f\n\t" + "li %1, 1\n\t" + "1:" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + int success; + fence_before(success_order); + __asm__ __volatile__ + ( + "li %1, 0\n\t" + "0: ldarx %0,%y2\n\t" + "cmpd %0, %3\n\t" + "bne- 1f\n\t" + "stdcx. %4,%y2\n\t" + "bne- 0b\n\t" + "li %1, 1\n\t" + "1:\n\t" + : "=&b" (expected), "=&b" (success), "+Z" (storage) + : "b" (expected), "b" (desired) + : "cr0" + ); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + return !!success; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "add %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "sub %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "and %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "or %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type original, result; + fence_before(order); + __asm__ __volatile__ + ( + "1:\n\t" + "ldarx %0,%y2\n\t" + "xor %1,%0,%3\n\t" + "stdcx. %1,%y2\n\t" + "bne- 1b\n\t" + : "=&b" (original), "=&b" (result), "+Z" (storage) + : "b" (v) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC + ); + fence_after(order); + return original; + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, 0, order); + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_PPC_HAS_LDARX_STDCX) + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + { +#if defined(__powerpc64__) || defined(__PPC64__) + if (order != memory_order_seq_cst) + __asm__ __volatile__ ("lwsync" ::: "memory"); + else + __asm__ __volatile__ ("sync" ::: "memory"); +#else + __asm__ __volatile__ ("sync" ::: "memory"); +#endif + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) +#if defined(__ibmxl__) || defined(__IBMCPP__) + __fence(); +#else + __asm__ __volatile__ ("" ::: "memory"); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_ppc_common.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_ppc_common.hpp new file mode 100644 index 000000000..e5c9303bf --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_ppc_common.hpp @@ -0,0 +1,70 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_ppc_common.hpp + * + * This header contains basic utilities for gcc PowerPC backend. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// The implementation below uses information from this document: +// http://www.rdrop.com/users/paulmck/scalability/paper/N2745r.2010.02.19a.html + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +struct gcc_ppc_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { +#if defined(__powerpc64__) || defined(__PPC64__) + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("lwsync" ::: "memory"); +#else + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("sync" ::: "memory"); +#endif + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("isync" ::: "memory"); + } +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_PPC_COMMON_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_sparc.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_sparc.hpp new file mode 100644 index 000000000..19b9b1fa8 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_sparc.hpp @@ -0,0 +1,240 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2010 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_sparc.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_sparc_cas_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + else if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + } +}; + +template< bool Signed > +struct gcc_sparc_cas32 : + public gcc_sparc_cas_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + storage_type previous = expected; + __asm__ __volatile__ + ( + "cas [%1], %2, %0" + : "+r" (desired) + : "r" (&storage), "r" (previous) + : "memory" + ); + const bool success = (desired == previous); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = desired; + return success; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + __asm__ __volatile__ + ( + "swap [%1], %0" + : "+r" (v) + : "r" (&storage) + : "memory" + ); + fence_after(order); + return v; + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public cas_based_operations< gcc_sparc_cas32< Signed > > +{ +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +template< bool Signed > +struct gcc_sparc_cas64 : + public gcc_sparc_cas_base +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + fence_before(success_order); + storage_type previous = expected; + __asm__ __volatile__ + ( + "casx [%1], %2, %0" + : "+r" (desired) + : "r" (&storage), "r" (previous) + : "memory" + ); + const bool success = (desired == previous); + if (success) + fence_after(success_order); + else + fence_after(failure_order); + expected = desired; + return success; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< cas_based_exchange< gcc_sparc_cas64< Signed > > > +{ +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + switch (order) + { + case memory_order_release: + __asm__ __volatile__ ("membar #StoreStore | #LoadStore" ::: "memory"); + break; + case memory_order_consume: + case memory_order_acquire: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore" ::: "memory"); + break; + case memory_order_acq_rel: + __asm__ __volatile__ ("membar #LoadLoad | #LoadStore | #StoreStore" ::: "memory"); + break; + case memory_order_seq_cst: + __asm__ __volatile__ ("membar #Sync" ::: "memory"); + break; + case memory_order_relaxed: + default: + break; + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_SPARC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_sync.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_sync.hpp new file mode 100644 index 000000000..1597de852 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_sync.hpp @@ -0,0 +1,240 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_sync.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_sync_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + __sync_synchronize(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_acquire) | static_cast< unsigned int >(memory_order_consume))) != 0u) + __sync_synchronize(); + } +}; + +template< std::size_t Size, bool Signed > +struct gcc_sync_operations : + public gcc_sync_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before_store(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_add(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_sub(&storage, v); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + // GCC docs mention that not all architectures may support full exchange semantics for this intrinsic. However, GCC's implementation of + // std::atomic<> uses this intrinsic unconditionally. We do so as well. In case if some architectures actually don't support this, we can always + // add a check here and fall back to a CAS loop. + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + return __sync_lock_test_and_set(&storage, v); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type expected2 = expected; + storage_type old_val = __sync_val_compare_and_swap(&storage, expected2, desired); + + if (old_val == expected2) + { + return true; + } + else + { + expected = old_val; + return false; + } + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_and(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_or(&storage, v); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return __sync_fetch_and_xor(&storage, v); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __sync_synchronize(); + return !!__sync_lock_test_and_set(&storage, 1); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + __sync_lock_release(&storage); + if (order == memory_order_seq_cst) + __sync_synchronize(); + } +}; + +#if BOOST_ATOMIC_INT8_LOCK_FREE > 0 +template< bool Signed > +struct operations< 1u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) + public gcc_sync_operations< 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) + public extending_cas_based_operations< gcc_sync_operations< 2u, Signed >, 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 1u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 1u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 1u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT16_LOCK_FREE > 0 +template< bool Signed > +struct operations< 2u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) + public gcc_sync_operations< 2u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public extending_cas_based_operations< gcc_sync_operations< 4u, Signed >, 2u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 2u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 2u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT32_LOCK_FREE > 0 +template< bool Signed > +struct operations< 4u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + public gcc_sync_operations< 4u, Signed > +#elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public extending_cas_based_operations< gcc_sync_operations< 8u, Signed >, 4u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 4u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT64_LOCK_FREE > 0 +template< bool Signed > +struct operations< 8u, Signed > : +#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) + public gcc_sync_operations< 8u, Signed > +#else + public extending_cas_based_operations< gcc_sync_operations< 16u, Signed >, 8u, Signed > +#endif +{ +}; +#endif + +#if BOOST_ATOMIC_INT128_LOCK_FREE > 0 +template< bool Signed > +struct operations< 16u, Signed > : + public gcc_sync_operations< 16u, Signed > +{ +}; +#endif + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __sync_synchronize(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_SYNC_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_x86.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_x86.hpp new file mode 100644 index 000000000..007d4eeee --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_x86.hpp @@ -0,0 +1,563 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_x86.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) +#include +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct gcc_x86_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + __asm__ __volatile__ ("" ::: "memory"); + } + + static BOOST_FORCEINLINE void fence_after(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + __asm__ __volatile__ ("" ::: "memory"); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct gcc_x86_operations : + public gcc_x86_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + if (order != memory_order_seq_cst) + { + fence_before(order); + storage = v; + fence_after(order); + } + else + { + Derived::exchange(storage, v, order); + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + return Derived::fetch_add(storage, -v, order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef gcc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 1u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 1u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddb %0, %1" + : "+q" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgb %0, %1" + : "+q" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgb %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgb %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + temp_storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%al, %b2\n\t"\ + "lock; cmpxchgb %b2, %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), "=&q" (new_val)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andb", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orb", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorb", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef gcc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 2u >::aligned aligned_storage_type; + typedef typename make_storage_type< 4u >::type temp_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 2u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddw %0, %1" + : "+q" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgw %0, %1" + : "+q" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgw %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgw %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "q" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + temp_storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %2\n\t"\ + op " %%ax, %w2\n\t"\ + "lock; cmpxchgw %w2, %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), "=&q" (new_val)\ + : [arg] "ir" ((temp_storage_type)argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andw", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orw", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorw", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef gcc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddl %0, %1" + : "+r" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgl %0, %1" + : "+r" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgl %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgl %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: mov %[arg], %[new_val]\n\t"\ + op " %%eax, %[new_val]\n\t"\ + "lock; cmpxchgl %[new_val], %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), [new_val] "=&r" (new_val)\ + : [arg] "ir" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andl", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orl", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorl", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< gcc_dcas_x86< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#elif defined(__x86_64__) + +template< bool Signed > +struct operations< 8u, Signed > : + public gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef gcc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "lock; xaddq %0, %1" + : "+r" (v), "+m" (storage) + : + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "xchgq %0, %1" + : "+r" (v), "+m" (storage) + : + : "memory" + ); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + bool success; +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgq %3, %1" + : "+a" (previous), "+m" (storage), "=@ccz" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchgq %3, %1\n\t" + "sete %2" + : "+a" (previous), "+m" (storage), "=q" (success) + : "r" (desired) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + expected = previous; + return success; + } + +#define BOOST_ATOMIC_DETAIL_CAS_LOOP(op, argument, result)\ + storage_type new_val;\ + __asm__ __volatile__\ + (\ + ".align 16\n\t"\ + "1: movq %[arg], %[new_val]\n\t"\ + op " %%rax, %[new_val]\n\t"\ + "lock; cmpxchgq %[new_val], %[storage]\n\t"\ + "jne 1b"\ + : [res] "+a" (result), [storage] "+m" (storage), [new_val] "=&r" (new_val)\ + : [arg] "r" (argument)\ + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory"\ + ) + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("andq", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("orq", v, res); + return res; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type res = storage; + BOOST_ATOMIC_DETAIL_CAS_LOOP("xorq", v, res); + return res; + } + +#undef BOOST_ATOMIC_DETAIL_CAS_LOOP +}; + +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< gcc_dcas_x86_64< Signed > > +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order == memory_order_seq_cst) + { + __asm__ __volatile__ + ( +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) + "mfence\n" +#else + "lock; addl $0, (%%esp)\n" +#endif + ::: "memory" + ); + } + else if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_acquire) | static_cast< unsigned int >(memory_order_release))) != 0u) + { + __asm__ __volatile__ ("" ::: "memory"); + } +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_gcc_x86_dcas.hpp b/third-party/boost/boost/atomic/detail/ops_gcc_x86_dcas.hpp new file mode 100644 index 000000000..4206bb39e --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_gcc_x86_dcas.hpp @@ -0,0 +1,556 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 - 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_gcc_x86_dcas.hpp + * + * This header contains implementation of the double-width CAS primitive for x86. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// Note: In the 32-bit PIC code guarded with BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX below we have to avoid using memory +// operand constraints because the compiler may choose to use ebx as the base register for that operand. At least, clang +// is known to do that. For this reason we have to pre-compute a pointer to storage and pass it in edi. For the same reason +// we cannot save ebx to the stack with a mov instruction, so we use esi as a scratch register and restore it afterwards. +// Alternatively, we could push/pop the register to the stack, but exchanging the registers is faster. +// The need to pass a pointer in edi is a bit wasteful because normally the memory operand would use a base pointer +// with an offset (e.g. `this` + offset). But unfortunately, there seems to be no way around it. + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct gcc_dcas_x86 +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + typedef uint32_t BOOST_ATOMIC_DETAIL_MAY_ALIAS aliasing_uint32_t; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + if (BOOST_LIKELY((((uint32_t)&storage) & 0x00000007) == 0u)) + { +#if defined(__SSE__) + typedef float xmm_t __attribute__((__vector_size__(16))); + xmm_t xmm_scratch; + __asm__ __volatile__ + ( +#if defined(__AVX__) + "vmovq %[value], %[xmm_scratch]\n\t" + "vmovq %[xmm_scratch], %[storage]\n\t" +#elif defined(__SSE2__) + "movq %[value], %[xmm_scratch]\n\t" + "movq %[xmm_scratch], %[storage]\n\t" +#else + "xorps %[xmm_scratch], %[xmm_scratch]\n\t" + "movlps %[value], %[xmm_scratch]\n\t" + "movlps %[xmm_scratch], %[storage]\n\t" +#endif + : [storage] "=m" (storage), [xmm_scratch] "=x" (xmm_scratch) + : [value] "m" (v) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "fildll %[value]\n\t" + "fistpll %[storage]\n\t" + : [storage] "=m" (storage) + : [value] "m" (v) + : "memory" + ); +#endif + } + else + { +#if defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl %%eax, %%ebx\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : + : "a" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "edx", "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "=m" (storage), [dest_hi] "=m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : [value_lo] "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "eax", "edx", "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type value; + + if (BOOST_LIKELY((((uint32_t)&storage) & 0x00000007) == 0u)) + { +#if defined(__SSE__) + typedef float xmm_t __attribute__((__vector_size__(16))); + xmm_t xmm_scratch; + __asm__ __volatile__ + ( +#if defined(__AVX__) + "vmovq %[storage], %[xmm_scratch]\n\t" + "vmovq %[xmm_scratch], %[value]\n\t" +#elif defined(__SSE2__) + "movq %[storage], %[xmm_scratch]\n\t" + "movq %[xmm_scratch], %[value]\n\t" +#else + "xorps %[xmm_scratch], %[xmm_scratch]\n\t" + "movlps %[storage], %[xmm_scratch]\n\t" + "movlps %[xmm_scratch], %[value]\n\t" +#endif + : [value] "=m" (value), [xmm_scratch] "=x" (xmm_scratch) + : [storage] "m" (storage) + : "memory" + ); +#else + __asm__ __volatile__ + ( + "fildll %[storage]\n\t" + "fistpll %[value]\n\t" + : [value] "=m" (value) + : [storage] "m" (storage) + : "memory" + ); +#endif + } + else + { + // Note that despite const qualification cmpxchg8b below may issue a store to the storage. The storage value + // will not change, but this prevents the storage to reside in read-only memory. + +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t value_bits[2]; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm__ __volatile__ + ( + "movl %%ebx, %%eax\n\t" + "movl %%ecx, %%edx\n\t" + "lock; cmpxchg8b %[storage]\n\t" + : "=&a" (value_bits[0]), "=&d" (value_bits[1]) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + BOOST_ATOMIC_DETAIL_MEMCPY(&value, value_bits, sizeof(value)); + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm__ __volatile__ + ( + "movl %%ebx, %%eax\n\t" + "movl %%ecx, %%edx\n\t" + "lock; cmpxchg8b %[storage]\n\t" + : "=&A" (value) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { +#if defined(__clang__) + + // Clang cannot allocate eax:edx register pairs but it has sync intrinsics + storage_type old_expected = expected; + expected = __sync_val_compare_and_swap(&storage, old_expected, desired); + return expected == old_expected; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "lock; cmpxchg8b (%[dest])\n\t" + "xchgl %%ebx, %%esi\n\t" + : "+A" (expected), [success] "=@ccz" (success) + : "S" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "lock; cmpxchg8b (%[dest])\n\t" + "xchgl %%ebx, %%esi\n\t" + "sete %[success]\n\t" + : "+A" (expected), [success] "=qm" (success) + : "S" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg8b %[dest]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=@ccz" (success) + : "b" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg8b %[dest]\n\t" + "sete %[success]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=qm" (success) + : "b" ((uint32_t)desired), "c" ((uint32_t)(desired >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : "=a" (old_bits[0]), "=d" (old_bits[1]) + : "S" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type old_value; + __asm__ __volatile__ + ( + "xchgl %%ebx, %%esi\n\t" + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + "xchgl %%ebx, %%esi\n\t" + : "=A" (old_value) + : "S" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "D" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return old_value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) +#else // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) +#if defined(__MINGW32__) && ((__GNUC__+0) * 100 + (__GNUC_MINOR__+0)) < 407 + + // MinGW gcc up to 4.6 has problems with allocating registers in the asm blocks below + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "movl (%[dest]), %%eax\n\t" + "movl 4(%[dest]), %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b (%[dest])\n\t" + "jne 1b\n\t" + : "=&a" (old_bits[0]), "=&d" (old_bits[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)), [dest] "DS" (&storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint32_t old_bits[2]; + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&a" (old_bits[0]), "=&d" (old_bits[1]), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type old_value; + __asm__ __volatile__ + ( + "movl %[dest_lo], %%eax\n\t" + "movl %[dest_hi], %%edx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg8b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&A" (old_value), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint32_t* >(&storage)[1]) + : "b" ((uint32_t)v), "c" ((uint32_t)(v >> 32)) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + return old_value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) +#endif // defined(BOOST_ATOMIC_DETAIL_X86_ASM_PRESERVE_EBX) + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct gcc_dcas_x86_64 +{ + typedef typename make_storage_type< 16u >::type storage_type; + typedef typename make_storage_type< 16u >::aligned aligned_storage_type; + typedef uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS aliasing_uint64_t; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "=m" (storage), [dest_hi] "=m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "rax", "rdx", "memory" + ); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + // Note that despite const qualification cmpxchg16b below may issue a store to the storage. The storage value + // will not change, but this prevents the storage to reside in read-only memory. + +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + uint64_t value_bits[2]; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for rbx and rcx values, they just have to be equal to rax and rdx before cmpxchg16b. + __asm__ __volatile__ + ( + "movq %%rbx, %%rax\n\t" + "movq %%rcx, %%rdx\n\t" + "lock; cmpxchg16b %[storage]\n\t" + : "=&a" (value_bits[0]), "=&d" (value_bits[1]) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type value; + BOOST_ATOMIC_DETAIL_MEMCPY(&value, value_bits, sizeof(value)); + return value; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + storage_type value; + + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for rbx and rcx values, they just have to be equal to rax and rdx before cmpxchg16b. + __asm__ __volatile__ + ( + "movq %%rbx, %%rax\n\t" + "movq %%rcx, %%rdx\n\t" + "lock; cmpxchg16b %[storage]\n\t" + : "=&A" (value) + : [storage] "m" (storage) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return value; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { +#if defined(__clang__) + + // Clang cannot allocate rax:rdx register pairs but it has sync intrinsics + storage_type old_expected = expected; + expected = __sync_val_compare_and_swap(&storage, old_expected, desired); + return expected == old_expected; + +#elif defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + // Some compilers can't allocate rax:rdx register pair either but also don't support 128-bit __sync_val_compare_and_swap + bool success; + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + "sete %[success]\n\t" + : [dest] "+m" (storage), "+a" (reinterpret_cast< aliasing_uint64_t* >(&expected)[0]), "+d" (reinterpret_cast< aliasing_uint64_t* >(&expected)[1]), [success] "=q" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return success; + +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + + bool success; + +#if defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + : "+A" (expected), [dest] "+m" (storage), "=@ccz" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#else // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + __asm__ __volatile__ + ( + "lock; cmpxchg16b %[dest]\n\t" + "sete %[success]\n\t" + : "+A" (expected), [dest] "+m" (storage), [success] "=qm" (success) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&desired)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); +#endif // defined(BOOST_ATOMIC_DETAIL_ASM_HAS_FLAG_OUTPUTS) + + return success; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + uint64_t old_bits[2]; + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]), "=&a" (old_bits[0]), "=&d" (old_bits[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + storage_type old_value; + BOOST_ATOMIC_DETAIL_MEMCPY(&old_value, old_bits, sizeof(old_value)); + return old_value; +#else // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + storage_type old_value; + __asm__ __volatile__ + ( + "movq %[dest_lo], %%rax\n\t" + "movq %[dest_hi], %%rdx\n\t" + ".align 16\n\t" + "1: lock; cmpxchg16b %[dest_lo]\n\t" + "jne 1b\n\t" + : "=&A" (old_value), [dest_lo] "+m" (storage), [dest_hi] "+m" (reinterpret_cast< volatile aliasing_uint64_t* >(&storage)[1]) + : "b" (reinterpret_cast< const aliasing_uint64_t* >(&v)[0]), "c" (reinterpret_cast< const aliasing_uint64_t* >(&v)[1]) + : BOOST_ATOMIC_DETAIL_ASM_CLOBBER_CC_COMMA "memory" + ); + + return old_value; +#endif // defined(BOOST_ATOMIC_DETAIL_X86_NO_ASM_AX_DX_PAIRS) + } +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_GCC_X86_DCAS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_linux_arm.hpp b/third-party/boost/boost/atomic/detail/ops_linux_arm.hpp new file mode 100644 index 000000000..16af1732c --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_linux_arm.hpp @@ -0,0 +1,180 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009, 2011 Helge Bahmann + * Copyright (c) 2009 Phil Endecott + * Copyright (c) 2013 Tim Blechmann + * Linux-specific code by Phil Endecott + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_linux_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +// Different ARM processors have different atomic instructions. In particular, +// architecture versions before v6 (which are still in widespread use, e.g. the +// Intel/Marvell XScale chips like the one in the NSLU2) have only atomic swap. +// On Linux the kernel provides some support that lets us abstract away from +// these differences: it provides emulated CAS and barrier functions at special +// addresses that are guaranteed not to be interrupted by the kernel. Using +// this facility is slightly slower than inline assembler would be, but much +// faster than a system call. +// +// While this emulated CAS is "strong" in the sense that it does not fail +// "spuriously" (i.e.: it never fails to perform the exchange when the value +// found equals the value expected), it does not return the found value on +// failure. To satisfy the atomic API, compare_exchange_{weak|strong} must +// return the found value on failure, and we have to manually load this value +// after the emulated CAS reports failure. This in turn introduces a race +// between the CAS failing (due to the "wrong" value being found) and subsequently +// loading (which might turn up the "right" value). From an application's +// point of view this looks like "spurious failure", and therefore the +// emulated CAS is only good enough to provide compare_exchange_weak +// semantics. + +struct linux_arm_cas_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + if (order == memory_order_seq_cst) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + } + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + typedef void (*kernel_dmb_t)(void); + ((kernel_dmb_t)0xffff0fa0)(); + } +}; + +template< bool Signed > +struct linux_arm_cas : + public linux_arm_cas_base +{ + typedef typename make_storage_type< 4u >::type storage_type; + typedef typename make_storage_type< 4u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 4u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + fence_before_store(order); + storage = v; + fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + while (true) + { + storage_type tmp = expected; + if (compare_exchange_weak(storage, tmp, desired, success_order, failure_order)) + return true; + if (tmp != expected) + { + expected = tmp; + return false; + } + } + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + typedef storage_type (*kernel_cmpxchg32_t)(storage_type oldval, storage_type newval, volatile storage_type* ptr); + + if (((kernel_cmpxchg32_t)0xffff0fc0)(expected, desired, &storage) == 0) + { + return true; + } + else + { + expected = storage; + return false; + } + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > >, 2u, Signed > +{ +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public cas_based_operations< cas_based_exchange< linux_arm_cas< Signed > > > +{ +}; + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + linux_arm_cas_base::hardware_full_fence(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + __asm__ __volatile__ ("" ::: "memory"); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_LINUX_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_msvc_arm.hpp b/third-party/boost/boost/atomic/detail/ops_msvc_arm.hpp new file mode 100644 index 000000000..608c6fddf --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_msvc_arm.hpp @@ -0,0 +1,824 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_arm.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#define BOOST_ATOMIC_DETAIL_ARM_LOAD8(p) __iso_volatile_load8((const volatile __int8*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD16(p) __iso_volatile_load16((const volatile __int16*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD32(p) __iso_volatile_load32((const volatile __int32*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_LOAD64(p) __iso_volatile_load64((const volatile __int64*)(p)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE8(p, v) __iso_volatile_store8((volatile __int8*)(p), (__int8)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE16(p, v) __iso_volatile_store16((volatile __int16*)(p), (__int16)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE32(p, v) __iso_volatile_store32((volatile __int32*)(p), (__int32)(v)) +#define BOOST_ATOMIC_DETAIL_ARM_STORE64(p, v) __iso_volatile_store64((volatile __int64*)(p), (__int64)(v)) + +namespace boost { +namespace atomics { +namespace detail { + +// A note about memory_order_consume. Technically, this architecture allows to avoid +// unnecessary memory barrier after consume load since it supports data dependency ordering. +// However, some compiler optimizations may break a seemingly valid code relying on data +// dependency tracking by injecting bogus branches to aid out of order execution. +// This may happen not only in Boost.Atomic code but also in user's code, which we have no +// control of. See this thread: http://lists.boost.org/Archives/boost/2014/06/213890.php. +// For this reason we promote memory_order_consume to memory_order_acquire. + +struct msvc_arm_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + __dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later + } + + static BOOST_FORCEINLINE void fence_before_store(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if ((static_cast< unsigned int >(order) & static_cast< unsigned int >(memory_order_release)) != 0u) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_store(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if (order == memory_order_seq_cst) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + if ((static_cast< unsigned int >(order) & (static_cast< unsigned int >(memory_order_consume) | static_cast< unsigned int >(memory_order_acquire))) != 0u) + hardware_full_fence(); + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE BOOST_CONSTEXPR memory_order cas_common_order(memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + // Combine order flags together and promote memory_order_consume to memory_order_acquire + return static_cast< memory_order >(((static_cast< unsigned int >(failure_order) | static_cast< unsigned int >(success_order)) & ~static_cast< unsigned int >(memory_order_consume)) + | (((static_cast< unsigned int >(failure_order) | static_cast< unsigned int >(success_order)) & static_cast< unsigned int >(memory_order_consume)) << 1u)); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct msvc_arm_operations : + public msvc_arm_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + Derived::store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_arm_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE8(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD8(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_arm_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE16(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD16(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef msvc_arm_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE32(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD32(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + break; + } + return v; + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef msvc_arm_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before_store(order); + BOOST_ATOMIC_DETAIL_ARM_STORE64(&storage, v); + base_type::fence_after_store(order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = BOOST_ATOMIC_DETAIL_ARM_LOAD64(&storage); + base_type::fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected, old_val; + + switch (cas_common_order(success_order, failure_order)) + { + case memory_order_relaxed: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELAXED(&storage, desired, previous)); + break; + case memory_order_consume: + case memory_order_acquire: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_ACQUIRE(&storage, desired, previous)); + break; + case memory_order_release: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64_RELEASE(&storage, desired, previous)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&storage, desired, previous)); + break; + } + expected = old_val; + + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&storage, v)); + break; + } + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + switch (order) + { + case memory_order_relaxed: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_RELAXED(&storage, v)); + break; + case memory_order_consume: + case memory_order_acquire: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_ACQUIRE(&storage, v)); + break; + case memory_order_release: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64_RELEASE(&storage, v)); + break; + case memory_order_acq_rel: + case memory_order_seq_cst: + default: + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&storage, v)); + break; + } + return v; + } +}; + + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order != memory_order_relaxed) + msvc_arm_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD8 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD16 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD32 +#undef BOOST_ATOMIC_DETAIL_ARM_LOAD64 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE8 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE16 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE32 +#undef BOOST_ATOMIC_DETAIL_ARM_STORE64 + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_ARM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_msvc_common.hpp b/third-party/boost/boost/atomic/detail/ops_msvc_common.hpp new file mode 100644 index 000000000..53628f360 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_msvc_common.hpp @@ -0,0 +1,38 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_common.hpp + * + * This header contains common tools for MSVC implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +// Define compiler barriers +#if defined(__INTEL_COMPILER) +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() __memory_barrier() +#elif defined(_MSC_VER) && !defined(_WIN32_WCE) +extern "C" void _ReadWriteBarrier(void); +#pragma intrinsic(_ReadWriteBarrier) +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() _ReadWriteBarrier() +#endif + +#ifndef BOOST_ATOMIC_DETAIL_COMPILER_BARRIER +#define BOOST_ATOMIC_DETAIL_COMPILER_BARRIER() +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_COMMON_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_msvc_x86.hpp b/third-party/boost/boost/atomic/detail/ops_msvc_x86.hpp new file mode 100644 index 000000000..70b0ea994 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_msvc_x86.hpp @@ -0,0 +1,908 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_msvc_x86.hpp + * + * This header contains implementation of the \c operations template. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) || defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) +#include +#include +#endif +#include +#if !defined(_M_IX86) && !(defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) && defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16)) +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(BOOST_MSVC) +#pragma warning(push) +// frame pointer register 'ebx' modified by inline assembly code. See the note below. +#pragma warning(disable: 4731) +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) +extern "C" void _mm_mfence(void); +#if defined(BOOST_MSVC) +#pragma intrinsic(_mm_mfence) +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +/* + * Implementation note for asm blocks. + * + * http://msdn.microsoft.com/en-us/data/k1a8ss06%28v=vs.105%29 + * + * Some SSE types require eight-byte stack alignment, forcing the compiler to emit dynamic stack-alignment code. + * To be able to access both the local variables and the function parameters after the alignment, the compiler + * maintains two frame pointers. If the compiler performs frame pointer omission (FPO), it will use EBP and ESP. + * If the compiler does not perform FPO, it will use EBX and EBP. To ensure code runs correctly, do not modify EBX + * in asm code if the function requires dynamic stack alignment as it could modify the frame pointer. + * Either move the eight-byte aligned types out of the function, or avoid using EBX. + * + * Since we have no way of knowing that the compiler uses FPO, we have to always save and restore ebx + * whenever we have to clobber it. Additionally, we disable warning C4731 above so that the compiler + * doesn't spam about ebx use. + */ + +struct msvc_x86_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_MFENCE) + _mm_mfence(); +#else + long tmp; + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0); +#endif + } + + static BOOST_FORCEINLINE void fence_before(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after_load(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + // On x86 and x86_64 there is no need for a hardware barrier, + // even if seq_cst memory order is requested, because all + // seq_cst writes are implemented with lock-prefixed operations + // or xchg which has implied lock prefix. Therefore normal loads + // are already ordered with seq_cst stores on these architectures. + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct msvc_x86_operations : + public msvc_x86_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + if (order != memory_order_seq_cst) + { + fence_before(order); + storage = v; + fence_after(order); + } + else + { + Derived::exchange(storage, v, order); + } + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + storage_type v = storage; + fence_after_load(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef msvc_x86_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + +#if defined(BOOST_ATOMIC_INTERLOCKED_AND) + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res & v, order, memory_order_relaxed)) {} + return res; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_OR) + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res | v, order, memory_order_relaxed)) {} + return res; + } +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR) + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + } +#else + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res ^ v, order, memory_order_relaxed)) {} + return res; + } +#endif +}; + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8) + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE8(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE8(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR8(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR8(&storage, v)); + } +}; + +#elif defined(_M_IX86) + +template< bool Signed > +struct operations< 1u, Signed > : + public msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > +{ + typedef msvc_x86_operations< 1u, Signed, operations< 1u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xadd byte ptr [edx], al + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + xchg byte ptr [edx], al + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT + { + base_type::fence_before(success_order); + bool success; + __asm + { + mov esi, expected + mov edi, storage + movzx eax, byte ptr [esi] + movzx edx, desired + lock cmpxchg byte ptr [edi], dl + mov byte ptr [esi], al + sete success + }; + // The success and failure fences are equivalent anyway + base_type::fence_after(success_order); + return success; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + and dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + or dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, byte ptr [edi] + align 16 + again: + mov dl, al + xor dl, cl + lock cmpxchg byte ptr [edi], dl + jne again + mov v, al + }; + base_type::fence_after(order); + return v; + } +}; + +#else + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +#endif + +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16) + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE16(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE16(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR16(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR16(&storage, v)); + } +}; + +#elif defined(_M_IX86) + +template< bool Signed > +struct operations< 2u, Signed > : + public msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > +{ + typedef msvc_x86_operations< 2u, Signed, operations< 2u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + lock xadd word ptr [edx], ax + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edx, storage + movzx eax, v + xchg word ptr [edx], ax + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order) BOOST_NOEXCEPT + { + base_type::fence_before(success_order); + bool success; + __asm + { + mov esi, expected + mov edi, storage + movzx eax, word ptr [esi] + movzx edx, desired + lock cmpxchg word ptr [edi], dx + mov word ptr [esi], ax + sete success + }; + // The success and failure fences are equivalent anyway + base_type::fence_after(success_order); + return success; + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + and dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + or dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + __asm + { + mov edi, storage + movzx ecx, v + xor edx, edx + movzx eax, word ptr [edi] + align 16 + again: + mov dx, ax + xor dx, cx + lock cmpxchg word ptr [edi], dx + jne again + mov v, ax + }; + base_type::fence_after(order); + return v; + } +}; + +#else + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +#endif + + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG8B) + +template< bool Signed > +struct msvc_dcas_x86 +{ + typedef typename make_storage_type< 8u >::type storage_type; + typedef typename make_storage_type< 8u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 8u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + // Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 3A, 8.1.1. Guaranteed Atomic Operations: + // + // The Pentium processor (and newer processors since) guarantees that the following additional memory operations will always be carried out atomically: + // * Reading or writing a quadword aligned on a 64-bit boundary + // + // Luckily, the memory is almost always 8-byte aligned in our case because atomic<> uses 64 bit native types for storage and dynamic memory allocations + // have at least 8 byte alignment. The only unfortunate case is when atomic is placed on the stack and it is not 8-byte aligned (like on 32 bit Windows). + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; + if (((uint32_t)p & 0x00000007) == 0) + { +#if defined(_M_IX86_FP) && _M_IX86_FP >= 2 +#if defined(__AVX__) + __asm + { + mov edx, p + vmovq xmm4, v + vmovq qword ptr [edx], xmm4 + }; +#else + __asm + { + mov edx, p + movq xmm4, v + movq qword ptr [edx], xmm4 + }; +#endif +#else + __asm + { + mov edx, p + fild v + fistp qword ptr [edx] + }; +#endif + } + else + { + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov ebx, dword ptr [v] + mov ecx, dword ptr [v + 4] + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + align 16 + again: + lock cmpxchg8b qword ptr [edi] + jne again + mov ebx, backup + }; + } + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type const volatile* p = &storage; + storage_type value; + + if (((uint32_t)p & 0x00000007) == 0) + { +#if defined(_M_IX86_FP) && _M_IX86_FP >= 2 +#if defined(__AVX__) + __asm + { + mov edx, p + vmovq xmm4, qword ptr [edx] + vmovq value, xmm4 + }; +#else + __asm + { + mov edx, p + movq xmm4, qword ptr [edx] + movq value, xmm4 + }; +#endif +#else + __asm + { + mov edx, p + fild qword ptr [edx] + fistp value + }; +#endif + } + else + { + // We don't care for comparison result here; the previous value will be stored into value anyway. + // Also we don't care for ebx and ecx values, they just have to be equal to eax and edx before cmpxchg8b. + __asm + { + mov edi, p + mov eax, ebx + mov edx, ecx + lock cmpxchg8b qword ptr [edi] + mov dword ptr [value], eax + mov dword ptr [value + 4], edx + }; + } + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + // MSVC-11 in 32-bit mode sometimes generates messed up code without compiler barriers, + // even though the _InterlockedCompareExchange64 intrinsic already provides one. + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; +#if defined(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64) + const storage_type old_val = (storage_type)BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(p, desired, expected); + const bool result = (old_val == expected); + expected = old_val; +#else + bool result; + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov esi, expected + mov ebx, dword ptr [desired] + mov ecx, dword ptr [desired + 4] + mov eax, dword ptr [esi] + mov edx, dword ptr [esi + 4] + lock cmpxchg8b qword ptr [edi] + mov dword ptr [esi], eax + mov dword ptr [esi + 4], edx + mov ebx, backup + sete result + }; +#endif + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return result; + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + storage_type volatile* p = &storage; + uint32_t backup; + __asm + { + mov backup, ebx + mov edi, p + mov ebx, dword ptr [v] + mov ecx, dword ptr [v + 4] + mov eax, dword ptr [edi] + mov edx, dword ptr [edi + 4] + align 16 + again: + lock cmpxchg8b qword ptr [edi] + jne again + mov ebx, backup + mov dword ptr [v], eax + mov dword ptr [v + 4], edx + }; + + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + + return v; + } +}; + +template< bool Signed > +struct operations< 8u, Signed > : + public cas_based_operations< msvc_dcas_x86< Signed > > +{ +}; + +#elif defined(_M_AMD64) + +template< bool Signed > +struct operations< 8u, Signed > : + public msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > +{ + typedef msvc_x86_operations< 8u, Signed, operations< 8u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE64(&storage, v)); + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE64(&storage, desired, previous)); + expected = old_val; + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR64(&storage, v)); + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + return static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR64(&storage, v)); + } +}; + +#endif + +#if defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +template< bool Signed > +struct msvc_dcas_x86_64 +{ + typedef typename make_storage_type< 16u >::type storage_type; + typedef typename make_storage_type< 16u >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = true; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = 16u; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order) BOOST_NOEXCEPT + { + storage_type value = const_cast< storage_type& >(storage); + while (!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, v, &value)) {} + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order) BOOST_NOEXCEPT + { + storage_type value = storage_type(); + BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, value, &value); + return value; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order, memory_order) BOOST_NOEXCEPT + { + return !!BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE128(&storage, desired, &expected); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } +}; + +template< bool Signed > +struct operations< 16u, Signed > : + public cas_based_operations< cas_based_exchange< msvc_dcas_x86_64< Signed > > > +{ +}; + +#endif // defined(BOOST_ATOMIC_DETAIL_X86_HAS_CMPXCHG16B) + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order == memory_order_seq_cst) + msvc_x86_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + +#endif // BOOST_ATOMIC_DETAIL_OPS_MSVC_X86_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/ops_windows.hpp b/third-party/boost/boost/atomic/detail/ops_windows.hpp new file mode 100644 index 000000000..d4ce6d95e --- /dev/null +++ b/third-party/boost/boost/atomic/detail/ops_windows.hpp @@ -0,0 +1,218 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/ops_windows.hpp + * + * This header contains implementation of the \c operations template. + * + * This implementation is the most basic version for Windows. It should + * work for any non-MSVC-like compilers as long as there are Interlocked WinAPI + * functions available. This version is also used for WinCE. + * + * Notably, this implementation is not as efficient as other + * versions based on compiler intrinsics. + */ + +#ifndef BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +struct windows_operations_base +{ + static BOOST_CONSTEXPR_OR_CONST bool full_cas_based = false; + static BOOST_CONSTEXPR_OR_CONST bool is_always_lock_free = true; + + static BOOST_FORCEINLINE void hardware_full_fence() BOOST_NOEXCEPT + { + long tmp; + BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&tmp, 0); + } + + static BOOST_FORCEINLINE void fence_before(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } + + static BOOST_FORCEINLINE void fence_after(memory_order) BOOST_NOEXCEPT + { + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + } +}; + +template< std::size_t Size, bool Signed, typename Derived > +struct windows_operations : + public windows_operations_base +{ + typedef typename make_storage_type< Size >::type storage_type; + typedef typename make_storage_type< Size >::aligned aligned_storage_type; + + static BOOST_CONSTEXPR_OR_CONST std::size_t storage_size = Size; + static BOOST_CONSTEXPR_OR_CONST bool is_signed = Signed; + + static BOOST_FORCEINLINE void store(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + Derived::exchange(storage, v, order); + } + + static BOOST_FORCEINLINE storage_type load(storage_type const volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return Derived::fetch_add(const_cast< storage_type volatile& >(storage), (storage_type)0, order); + } + + static BOOST_FORCEINLINE storage_type fetch_sub(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + typedef typename boost::atomics::detail::make_signed< storage_type >::type signed_storage_type; + return Derived::fetch_add(storage, static_cast< storage_type >(-static_cast< signed_storage_type >(v)), order); + } + + static BOOST_FORCEINLINE bool compare_exchange_weak( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + return Derived::compare_exchange_strong(storage, expected, desired, success_order, failure_order); + } + + static BOOST_FORCEINLINE bool test_and_set(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + return !!Derived::exchange(storage, (storage_type)1, order); + } + + static BOOST_FORCEINLINE void clear(storage_type volatile& storage, memory_order order) BOOST_NOEXCEPT + { + store(storage, (storage_type)0, order); + } +}; + +template< bool Signed > +struct operations< 4u, Signed > : + public windows_operations< 4u, Signed, operations< 4u, Signed > > +{ + typedef windows_operations< 4u, Signed, operations< 4u, Signed > > base_type; + typedef typename base_type::storage_type storage_type; + + static BOOST_FORCEINLINE storage_type fetch_add(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE_ADD(&storage, v)); + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE storage_type exchange(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_EXCHANGE(&storage, v)); + base_type::fence_after(order); + return v; + } + + static BOOST_FORCEINLINE bool compare_exchange_strong( + storage_type volatile& storage, storage_type& expected, storage_type desired, memory_order success_order, memory_order failure_order) BOOST_NOEXCEPT + { + storage_type previous = expected; + base_type::fence_before(success_order); + storage_type old_val = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_COMPARE_EXCHANGE(&storage, desired, previous)); + expected = old_val; + // The success and failure fences are the same anyway + base_type::fence_after(success_order); + return (previous == old_val); + } + + static BOOST_FORCEINLINE storage_type fetch_and(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_AND) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_AND(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res & v, order, memory_order_relaxed)) {} + return res; +#endif + } + + static BOOST_FORCEINLINE storage_type fetch_or(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_OR) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_OR(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res | v, order, memory_order_relaxed)) {} + return res; +#endif + } + + static BOOST_FORCEINLINE storage_type fetch_xor(storage_type volatile& storage, storage_type v, memory_order order) BOOST_NOEXCEPT + { +#if defined(BOOST_ATOMIC_INTERLOCKED_XOR) + base_type::fence_before(order); + v = static_cast< storage_type >(BOOST_ATOMIC_INTERLOCKED_XOR(&storage, v)); + base_type::fence_after(order); + return v; +#else + storage_type res = storage; + while (!compare_exchange_strong(storage, res, res ^ v, order, memory_order_relaxed)) {} + return res; +#endif + } +}; + +template< bool Signed > +struct operations< 1u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 1u, Signed > +{ +}; + +template< bool Signed > +struct operations< 2u, Signed > : + public extending_cas_based_operations< operations< 4u, Signed >, 2u, Signed > +{ +}; + +BOOST_FORCEINLINE void thread_fence(memory_order order) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); + if (order == memory_order_seq_cst) + windows_operations_base::hardware_full_fence(); + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +BOOST_FORCEINLINE void signal_fence(memory_order order) BOOST_NOEXCEPT +{ + if (order != memory_order_relaxed) + BOOST_ATOMIC_DETAIL_COMPILER_BARRIER(); +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_OPS_WINDOWS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/pause.hpp b/third-party/boost/boost/atomic/detail/pause.hpp new file mode 100644 index 000000000..37aa5ca84 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/pause.hpp @@ -0,0 +1,43 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * (C) Copyright 2013 Tim Blechmann + * (C) Copyright 2013 Andrey Semashev + */ + +#ifndef BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86)) +extern "C" void _mm_pause(void); +#if defined(BOOST_MSVC) +#pragma intrinsic(_mm_pause) +#endif +#endif + +namespace boost { +namespace atomics { +namespace detail { + +BOOST_FORCEINLINE void pause() BOOST_NOEXCEPT +{ +#if defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_IX86)) + _mm_pause(); +#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + __asm__ __volatile__("pause;"); +#endif +} + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_PAUSE_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/platform.hpp b/third-party/boost/boost/atomic/detail/platform.hpp new file mode 100644 index 000000000..df4cc305a --- /dev/null +++ b/third-party/boost/boost/atomic/detail/platform.hpp @@ -0,0 +1,163 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/platform.hpp + * + * This header defines macros for the target platform detection + */ + +#ifndef BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__GNUC__) && defined(__arm__) + +// Newer gcc versions define __ARM_ARCH. Older ones don't, so we have to deduce ARM arch version from a bunch of version-specific macros. +#if defined(__ARM_ARCH) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH __ARM_ARCH +#elif defined(__ARM_ARCH_8A__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 8 +#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) ||\ + defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) ||\ + defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7S__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 7 +#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) ||\ + defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) ||\ + defined(__ARM_ARCH_6ZK__) +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 6 +#else +// We are not interested in older versions - they don't support atomic ops +#define BOOST_ATOMIC_DETAIL_ARM_ARCH 0 +#endif + +#endif // defined(__GNUC__) && defined(__arm__) + +#if !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +// Determine the target platform. +// The target platform describes the compiler and target architecture. It can be used by more generic backends, such as the ones +// based on compiler intrinsics, to implement specialized operations in a non-generic way. + +#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_x86 +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_x86 + +#elif defined(__GNUC__) && (defined(__POWERPC__) || defined(__PPC__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_ppc +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_ppc + +#elif defined(__GNUC__) && defined(__arm__) && (BOOST_ATOMIC_DETAIL_ARM_ARCH+0) >= 6 + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_arm +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND gcc_arm + +#elif (defined(__GNUC__) || defined(__SUNPRO_CC)) && (defined(__sparcv8plus) || defined(__sparc_v9__)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_sparc + +#elif defined(__GNUC__) && defined(__alpha__) + +#define BOOST_ATOMIC_DETAIL_PLATFORM gcc_alpha + +#elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM msvc_x86 + +#elif defined(_MSC_VER) && _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64)) + +#define BOOST_ATOMIC_DETAIL_PLATFORM msvc_arm + +#endif + +// Compiler-based backends + +// IBM XL C++ Compiler has to be checked before GCC/Clang as it pretends to be one but does not support __atomic* intrinsics. +// It does support GCC inline assembler though. +#if !(defined(__ibmxl__) || defined(__IBMCPP__)) &&\ + ((defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 407)) ||\ + (defined(BOOST_CLANG) && ((__clang_major__ * 100 + __clang_minor__) >= 302))) &&\ + (\ + (__GCC_ATOMIC_BOOL_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_CHAR_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_SHORT_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_INT_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_LONG_LOCK_FREE + 0) == 2 ||\ + (__GCC_ATOMIC_LLONG_LOCK_FREE + 0) == 2\ + ) + +#define BOOST_ATOMIC_DETAIL_BACKEND gcc_atomic + +#elif defined(BOOST_ATOMIC_DETAIL_PLATFORM) + +#define BOOST_ATOMIC_DETAIL_BACKEND BOOST_ATOMIC_DETAIL_PLATFORM + +#elif defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 401) &&\ + (\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) ||\ + defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)\ + ) + +#define BOOST_ATOMIC_DETAIL_BACKEND gcc_sync + +#endif + +// OS-based backends + +#if !defined(BOOST_ATOMIC_DETAIL_BACKEND) + +#if defined(__linux__) && defined(__arm__) + +#define BOOST_ATOMIC_DETAIL_BACKEND linux_arm + +#elif defined(BOOST_WINDOWS) || defined(_WIN32_CE) + +#define BOOST_ATOMIC_DETAIL_BACKEND windows + +#endif + +#endif // !defined(BOOST_ATOMIC_DETAIL_BACKEND) + +#endif // !defined(BOOST_ATOMIC_FORCE_FALLBACK) + +#if !defined(BOOST_ATOMIC_DETAIL_BACKEND) +#define BOOST_ATOMIC_DETAIL_BACKEND emulated +#define BOOST_ATOMIC_EMULATED +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_FP_BACKEND) +#define BOOST_ATOMIC_DETAIL_FP_BACKEND generic +#define BOOST_ATOMIC_DETAIL_FP_BACKEND_GENERIC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_BACKEND) +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND generic +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_GENERIC +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND) +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND generic +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_GENERIC +#endif + +#define BOOST_ATOMIC_DETAIL_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_FP_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_EXTRA_BACKEND_HEADER(prefix) +#define BOOST_ATOMIC_DETAIL_EXTRA_FP_BACKEND_HEADER(prefix) + +#endif // BOOST_ATOMIC_DETAIL_PLATFORM_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/storage_type.hpp b/third-party/boost/boost/atomic/detail/storage_type.hpp new file mode 100644 index 000000000..5d824d3a2 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/storage_type.hpp @@ -0,0 +1,207 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2009 Helge Bahmann + * Copyright (c) 2012 Tim Blechmann + * Copyright (c) 2013 - 2014 Andrey Semashev + */ +/*! + * \file atomic/detail/storage_type.hpp + * + * This header defines underlying types used as storage + */ + +#ifndef BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ + +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +BOOST_FORCEINLINE void non_atomic_load(T const volatile& from, T& to) BOOST_NOEXCEPT +{ + to = from; +} + +template< std::size_t Size > +struct BOOST_ATOMIC_DETAIL_MAY_ALIAS buffer_storage +{ + BOOST_ALIGNMENT(16) unsigned char data[Size]; + + BOOST_FORCEINLINE bool operator! () const BOOST_NOEXCEPT + { + return (data[0] == 0u && BOOST_ATOMIC_DETAIL_MEMCMP(data, data + 1, Size - 1) == 0); + } + + BOOST_FORCEINLINE bool operator== (buffer_storage const& that) const BOOST_NOEXCEPT + { + return BOOST_ATOMIC_DETAIL_MEMCMP(data, that.data, Size) == 0; + } + + BOOST_FORCEINLINE bool operator!= (buffer_storage const& that) const BOOST_NOEXCEPT + { + return BOOST_ATOMIC_DETAIL_MEMCMP(data, that.data, Size) != 0; + } +}; + +template< std::size_t Size > +BOOST_FORCEINLINE void non_atomic_load(buffer_storage< Size > const volatile& from, buffer_storage< Size >& to) BOOST_NOEXCEPT +{ + BOOST_ATOMIC_DETAIL_MEMCPY(to.data, const_cast< unsigned char const* >(from.data), Size); +} + +template< std::size_t Size > +struct make_storage_type +{ + typedef buffer_storage< Size > type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type const& v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 1u > +{ + typedef boost::uint8_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 2u > +{ + typedef boost::uint16_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(2) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 4u > +{ + typedef boost::uint32_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(4) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +template< > +struct make_storage_type< 8u > +{ + typedef boost::uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(8) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#if defined(BOOST_HAS_INT128) + +template< > +struct make_storage_type< 16u > +{ + typedef boost::uint128_type BOOST_ATOMIC_DETAIL_MAY_ALIAS type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(16) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#elif !defined(BOOST_NO_ALIGNMENT) + +struct BOOST_ATOMIC_DETAIL_MAY_ALIAS storage128_t +{ + typedef boost::uint64_t BOOST_ATOMIC_DETAIL_MAY_ALIAS element_type; + + element_type data[2]; + + BOOST_FORCEINLINE bool operator! () const BOOST_NOEXCEPT + { + return (data[0] | data[1]) == 0u; + } +}; + +BOOST_FORCEINLINE bool operator== (storage128_t const& left, storage128_t const& right) BOOST_NOEXCEPT +{ + return ((left.data[0] ^ right.data[0]) | (left.data[1] ^ right.data[1])) == 0u; +} +BOOST_FORCEINLINE bool operator!= (storage128_t const& left, storage128_t const& right) BOOST_NOEXCEPT +{ + return !(left == right); +} + +BOOST_FORCEINLINE void non_atomic_load(storage128_t const volatile& from, storage128_t& to) BOOST_NOEXCEPT +{ + to.data[0] = from.data[0]; + to.data[1] = from.data[1]; +} + +template< > +struct make_storage_type< 16u > +{ + typedef storage128_t type; + + struct BOOST_ATOMIC_DETAIL_MAY_ALIAS aligned + { + BOOST_ALIGNMENT(16) type value; + + BOOST_DEFAULTED_FUNCTION(aligned(), {}) + BOOST_FORCEINLINE BOOST_CONSTEXPR explicit aligned(type const& v) BOOST_NOEXCEPT : value(v) {} + }; +}; + +#endif + +template< typename T > +struct storage_size_of +{ + static BOOST_CONSTEXPR_OR_CONST std::size_t size = sizeof(T); + static BOOST_CONSTEXPR_OR_CONST std::size_t value = (size == 3u ? 4u : (size >= 5u && size <= 7u ? 8u : (size >= 9u && size <= 15u ? 16u : size))); +}; + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_STORAGE_TYPE_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/string_ops.hpp b/third-party/boost/boost/atomic/detail/string_ops.hpp new file mode 100644 index 000000000..ce145b98f --- /dev/null +++ b/third-party/boost/boost/atomic/detail/string_ops.hpp @@ -0,0 +1,61 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/string_ops.hpp + * + * This header defines string operations for Boost.Atomic + */ + +#ifndef BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ + +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#if defined(__has_builtin) +#if __has_builtin(__builtin_memcpy) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY +#endif +#if __has_builtin(__builtin_memcmp) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP +#endif +#if __has_builtin(__builtin_memset) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET +#endif +#elif defined(BOOST_GCC) +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP +#define BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) +#define BOOST_ATOMIC_DETAIL_MEMCPY __builtin_memcpy +#else +#define BOOST_ATOMIC_DETAIL_MEMCPY std::memcpy +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP) +#define BOOST_ATOMIC_DETAIL_MEMCMP __builtin_memcmp +#else +#define BOOST_ATOMIC_DETAIL_MEMCMP std::memcmp +#endif + +#if defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET) +#define BOOST_ATOMIC_DETAIL_MEMSET __builtin_memset +#else +#define BOOST_ATOMIC_DETAIL_MEMSET std::memset +#endif + +#if !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCPY) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMCMP) || !defined(BOOST_ATOMIC_DETAIL_HAS_BUILTIN_MEMSET) +#include +#endif + +#endif // BOOST_ATOMIC_DETAIL_STRING_OPS_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/conditional.hpp b/third-party/boost/boost/atomic/detail/type_traits/conditional.hpp new file mode 100644 index 000000000..6b9e89672 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/conditional.hpp @@ -0,0 +1,42 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/conditional.hpp + * + * This header defines \c conditional type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::conditional; +#else +using boost::conditional; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_CONDITIONAL_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/integral_constant.hpp b/third-party/boost/boost/atomic/detail/type_traits/integral_constant.hpp new file mode 100644 index 000000000..eac86491e --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/integral_constant.hpp @@ -0,0 +1,46 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/integral_constant.hpp + * + * This header defines \c integral_constant wrapper + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::integral_constant; +using std::true_type; +using std::false_type; +#else +using boost::integral_constant; +using boost::true_type; +using boost::false_type; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_INTEGRAL_CONSTANT_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_floating_point.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_floating_point.hpp new file mode 100644 index 000000000..c425112b8 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_floating_point.hpp @@ -0,0 +1,42 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_floating_point.hpp + * + * This header defines \c is_floating_point type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::is_floating_point; +#else +using boost::is_floating_point; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FLOATING_POINT_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_function.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_function.hpp new file mode 100644 index 000000000..e7205356e --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_function.hpp @@ -0,0 +1,42 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_function.hpp + * + * This header defines \c is_function type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ + +#include +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) +using std::is_function; +#else +using boost::is_function; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_FUNCTION_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_iec559.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_iec559.hpp new file mode 100644 index 000000000..299c4f0f4 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_iec559.hpp @@ -0,0 +1,47 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_iec559.hpp + * + * This header defines \c is_iec559 type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +template< typename T > +struct is_iec559 +{ + static BOOST_CONSTEXPR_OR_CONST bool value = !!std::numeric_limits< T >::is_iec559; +}; + +#if defined(BOOST_HAS_FLOAT128) +// libstdc++ does not specialize numeric_limits for __float128 +template< > +struct is_iec559< boost::float128_type > +{ + static BOOST_CONSTEXPR_OR_CONST bool value = true; +}; +#endif // defined(BOOST_HAS_FLOAT128) + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_IEC559_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_integral.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_integral.hpp new file mode 100644 index 000000000..ef3e2e347 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_integral.hpp @@ -0,0 +1,43 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_integral.hpp + * + * This header defines \c is_integral type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::is_integral; +#else +using boost::is_integral; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_INTEGRAL_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_signed.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_signed.hpp new file mode 100644 index 000000000..2dc1df726 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_signed.hpp @@ -0,0 +1,43 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_signed.hpp + * + * This header defines \c is_signed type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::is_signed; +#else +using boost::is_signed; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_SIGNED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp b/third-party/boost/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp new file mode 100644 index 000000000..5f88b88e4 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/is_trivially_default_constructible.hpp @@ -0,0 +1,46 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2018 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/is_trivially_default_constructible.hpp + * + * This header defines \c is_trivially_default_constructible type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ + +#include +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) +using std::is_trivially_default_constructible; +#elif !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) +template< typename T > +using is_trivially_default_constructible = boost::has_trivial_constructor< T >; +#else +template< typename T > +struct is_trivially_default_constructible : public boost::has_trivial_constructor< T > {}; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_IS_TRIVIALLY_DEFAULT_CONSTRUCTIBLE_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/make_signed.hpp b/third-party/boost/boost/atomic/detail/type_traits/make_signed.hpp new file mode 100644 index 000000000..82f61b33c --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/make_signed.hpp @@ -0,0 +1,43 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/make_signed.hpp + * + * This header defines \c make_signed type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::make_signed; +#else +using boost::make_signed; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_SIGNED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/detail/type_traits/make_unsigned.hpp b/third-party/boost/boost/atomic/detail/type_traits/make_unsigned.hpp new file mode 100644 index 000000000..573a16169 --- /dev/null +++ b/third-party/boost/boost/atomic/detail/type_traits/make_unsigned.hpp @@ -0,0 +1,43 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2017 Andrey Semashev + */ +/*! + * \file atomic/detail/type_traits/make_unsigned.hpp + * + * This header defines \c make_unsigned type trait + */ + +#ifndef BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ +#define BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ + +#include +// Some versions of libstdc++ don't consider __int128 an integral type. Use Boost.TypeTraits because of that. +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +#include +#else +#include +#endif + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { +namespace atomics { +namespace detail { + +#if !defined(BOOST_ATOMIC_DETAIL_NO_CXX11_BASIC_HDR_TYPE_TRAITS) && !defined(BOOST_HAS_INT128) +using std::make_unsigned; +#else +using boost::make_unsigned; +#endif + +} // namespace detail +} // namespace atomics +} // namespace boost + +#endif // BOOST_ATOMIC_DETAIL_TYPE_TRAITS_MAKE_UNSIGNED_HPP_INCLUDED_ diff --git a/third-party/boost/boost/atomic/fences.hpp b/third-party/boost/boost/atomic/fences.hpp new file mode 100644 index 000000000..31e304057 --- /dev/null +++ b/third-party/boost/boost/atomic/fences.hpp @@ -0,0 +1,67 @@ +/* + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * Copyright (c) 2011 Helge Bahmann + * Copyright (c) 2013 Tim Blechmann + * Copyright (c) 2014 Andrey Semashev + */ +/*! + * \file atomic/fences.hpp + * + * This header contains definition of \c atomic_thread_fence and \c atomic_signal_fence functions. + */ + +#ifndef BOOST_ATOMIC_FENCES_HPP_INCLUDED_ +#define BOOST_ATOMIC_FENCES_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +/* + * IMPLEMENTATION NOTE: All interface functions MUST be declared with BOOST_FORCEINLINE, + * see comment for convert_memory_order_to_gcc in ops_gcc_atomic.hpp. + */ + +namespace boost { + +namespace atomics { + +#if BOOST_ATOMIC_THREAD_FENCE > 0 +BOOST_FORCEINLINE void atomic_thread_fence(memory_order order) BOOST_NOEXCEPT +{ + detail::thread_fence(order); +} +#else +BOOST_FORCEINLINE void atomic_thread_fence(memory_order) BOOST_NOEXCEPT +{ + detail::lockpool::thread_fence(); +} +#endif + +#if BOOST_ATOMIC_SIGNAL_FENCE > 0 +BOOST_FORCEINLINE void atomic_signal_fence(memory_order order) BOOST_NOEXCEPT +{ + detail::signal_fence(order); +} +#else +BOOST_FORCEINLINE void atomic_signal_fence(memory_order) BOOST_NOEXCEPT +{ + detail::lockpool::signal_fence(); +} +#endif + +} // namespace atomics + +using atomics::atomic_thread_fence; +using atomics::atomic_signal_fence; + +} // namespace boost + +#endif // BOOST_ATOMIC_FENCES_HPP_INCLUDED_ diff --git a/third-party/boost/boost/beast.hpp b/third-party/boost/boost/beast.hpp new file mode 100644 index 000000000..458f20a71 --- /dev/null +++ b/third-party/boost/boost/beast.hpp @@ -0,0 +1,21 @@ +// +// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/boostorg/beast +// + +#ifndef BOOST_BEAST_HPP +#define BOOST_BEAST_HPP + +#include // must come first + +#include +#include +#include +#include +#include + +#endif diff --git a/third-party/boost/boost/bimap.hpp b/third-party/boost/boost/bimap.hpp new file mode 100644 index 000000000..51d726dd3 --- /dev/null +++ b/third-party/boost/boost/bimap.hpp @@ -0,0 +1,19 @@ +// Boost.Bimap +// +// Copyright (c) 2006-2007 Matias Capeletto +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See www.boost.org/libs/bimap for documentation. + +// Convenience header + +#include + +namespace boost +{ + using ::boost::bimaps::bimap; +} + diff --git a/third-party/boost/boost/bind.hpp b/third-party/boost/boost/bind.hpp new file mode 100644 index 000000000..450120c7a --- /dev/null +++ b/third-party/boost/boost/bind.hpp @@ -0,0 +1,41 @@ +#ifndef BOOST_BIND_HPP_INCLUDED +#define BOOST_BIND_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// bind.hpp - binds function objects to arguments +// +// Copyright (c) 2009, 2015 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +#include + +#ifndef BOOST_BIND_NO_PLACEHOLDERS + +#if defined(BOOST_CLANG) +# pragma clang diagnostic push +# if __has_warning("-Wheader-hygiene") +# pragma clang diagnostic ignored "-Wheader-hygiene" +# endif +#endif + +using namespace boost::placeholders; + +#if defined(BOOST_CLANG) +# pragma clang diagnostic pop +#endif + +#endif // #ifndef BOOST_BIND_NO_PLACEHOLDERS + +#endif // #ifndef BOOST_BIND_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/apply.hpp b/third-party/boost/boost/bind/apply.hpp new file mode 100644 index 000000000..6a43a89ac --- /dev/null +++ b/third-party/boost/boost/bind/apply.hpp @@ -0,0 +1,74 @@ +#ifndef BOOST_BIND_APPLY_HPP_INCLUDED +#define BOOST_BIND_APPLY_HPP_INCLUDED + +// +// apply.hpp +// +// Copyright (c) 2002, 2003 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +namespace boost +{ + +template struct apply +{ + typedef R result_type; + + template result_type operator()(F & f) const + { + return f(); + } + + template result_type operator()(F & f, A1 & a1) const + { + return f(a1); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2) const + { + return f(a1, a2); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3) const + { + return f(a1, a2, a3); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4) const + { + return f(a1, a2, a3, a4); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) const + { + return f(a1, a2, a3, a4, a5); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) const + { + return f(a1, a2, a3, a4, a5, a6); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) const + { + return f(a1, a2, a3, a4, a5, a6, a7); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) const + { + return f(a1, a2, a3, a4, a5, a6, a7, a8); + } + + template result_type operator()(F & f, A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) const + { + return f(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } +}; + +} // namespace boost + +#endif // #ifndef BOOST_BIND_APPLY_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/arg.hpp b/third-party/boost/boost/bind/arg.hpp new file mode 100644 index 000000000..cb52e6689 --- /dev/null +++ b/third-party/boost/boost/bind/arg.hpp @@ -0,0 +1,69 @@ +#ifndef BOOST_BIND_ARG_HPP_INCLUDED +#define BOOST_BIND_ARG_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// bind/arg.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +#include +#include + +namespace boost +{ + +template struct _arg_eq +{ +}; + +template<> struct _arg_eq +{ + typedef void type; +}; + +template< int I > struct arg +{ + BOOST_CONSTEXPR arg() + { + } + + template< class T > BOOST_CONSTEXPR arg( T const & /* t */, typename _arg_eq< I == is_placeholder::value >::type * = 0 ) + { + } +}; + +template< int I > BOOST_CONSTEXPR bool operator==( arg const &, arg const & ) +{ + return true; +} + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< int I > struct is_placeholder< arg > +{ + enum _vt { value = I }; +}; + +template< int I > struct is_placeholder< arg (*) () > +{ + enum _vt { value = I }; +}; + +#endif + +} // namespace boost + +#endif // #ifndef BOOST_BIND_ARG_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/bind.hpp b/third-party/boost/boost/bind/bind.hpp new file mode 100644 index 000000000..4cedc5e9a --- /dev/null +++ b/third-party/boost/boost/bind/bind.hpp @@ -0,0 +1,2365 @@ +#ifndef BOOST_BIND_BIND_HPP_INCLUDED +#define BOOST_BIND_BIND_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// bind.hpp - binds function objects to arguments +// +// Copyright (c) 2001-2004 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2001 David Abrahams +// Copyright (c) 2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) +#include // std::forward +#endif + +// Borland-specific bug, visit_each() silently fails to produce code + +#if defined(__BORLANDC__) +# define BOOST_BIND_VISIT_EACH boost::visit_each +#else +# define BOOST_BIND_VISIT_EACH visit_each +#endif + +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace boost +{ + +template class weak_ptr; + +namespace _bi // implementation details +{ + +// result_traits + +template struct result_traits +{ + typedef R type; +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +struct unspecified {}; + +template struct result_traits +{ + typedef typename F::result_type type; +}; + +template struct result_traits< unspecified, reference_wrapper > +{ + typedef typename F::result_type type; +}; + +#endif + +// ref_compare + +template bool ref_compare( T const & a, T const & b, long ) +{ + return a == b; +} + +template bool ref_compare( arg const &, arg const &, int ) +{ + return true; +} + +template bool ref_compare( arg (*) (), arg (*) (), int ) +{ + return true; +} + +template bool ref_compare( reference_wrapper const & a, reference_wrapper const & b, int ) +{ + return a.get_pointer() == b.get_pointer(); +} + +// bind_t forward declaration for listN + +template class bind_t; + +template bool ref_compare( bind_t const & a, bind_t const & b, int ) +{ + return a.compare( b ); +} + +// value + +template class value +{ +public: + + value(T const & t): t_(t) {} + + T & get() { return t_; } + T const & get() const { return t_; } + + bool operator==(value const & rhs) const + { + return t_ == rhs.t_; + } + +private: + + T t_; +}; + +// ref_compare for weak_ptr + +template bool ref_compare( value< weak_ptr > const & a, value< weak_ptr > const & b, int ) +{ + return !(a.get() < b.get()) && !(b.get() < a.get()); +} + +// type + +template class type {}; + +// unwrap + +template struct unwrapper +{ + static inline F & unwrap( F & f, long ) + { + return f; + } + + template static inline F2 & unwrap( reference_wrapper rf, int ) + { + return rf.get(); + } + + template static inline _mfi::dm unwrap( R T::* pm, int ) + { + return _mfi::dm( pm ); + } +}; + +// listN + +class list0 +{ +public: + + list0() {} + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A &, long) + { + return unwrapper::unwrap(f, 0)(); + } + + template R operator()(type, F const & f, A &, long) const + { + return unwrapper::unwrap(f, 0)(); + } + + template void operator()(type, F & f, A &, int) + { + unwrapper::unwrap(f, 0)(); + } + + template void operator()(type, F const & f, A &, int) const + { + unwrapper::unwrap(f, 0)(); + } + + template void accept(V &) const + { + } + + bool operator==(list0 const &) const + { + return true; + } +}; + +#ifdef BOOST_MSVC +// MSVC is bright enough to realise that the parameter rhs +// in operator==may be unused for some template argument types: +#pragma warning(push) +#pragma warning(disable:4100) +#endif + +template< class A1 > class list1: private storage1< A1 > +{ +private: + + typedef storage1< A1 > base_type; + +public: + + explicit list1( A1 a1 ): base_type( a1 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list1 const & rhs) const + { + return ref_compare(base_type::a1_, rhs.a1_, 0); + } +}; + +struct logical_and; +struct logical_or; + +template< class A1, class A2 > class list2: private storage2< A1, A2 > +{ +private: + + typedef storage2< A1, A2 > base_type; + +public: + + list2( A1 a1, A2 a2 ): base_type( a1, a2 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_]); + } + + template bool operator()( type, logical_and & /*f*/, A & a, int ) + { + return a[ base_type::a1_ ] && a[ base_type::a2_ ]; + } + + template bool operator()( type, logical_and const & /*f*/, A & a, int ) const + { + return a[ base_type::a1_ ] && a[ base_type::a2_ ]; + } + + template bool operator()( type, logical_or & /*f*/, A & a, int ) + { + return a[ base_type::a1_ ] || a[ base_type::a2_ ]; + } + + template bool operator()( type, logical_or const & /*f*/, A & a, int ) const + { + return a[ base_type::a1_ ] || a[ base_type::a2_ ]; + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list2 const & rhs) const + { + return ref_compare(base_type::a1_, rhs.a1_, 0) && ref_compare(base_type::a2_, rhs.a2_, 0); + } +}; + +template< class A1, class A2, class A3 > class list3: private storage3< A1, A2, A3 > +{ +private: + + typedef storage3< A1, A2, A3 > base_type; + +public: + + list3( A1 a1, A2 a2, A3 a3 ): base_type( a1, a2, a3 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list3 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ); + } +}; + +template< class A1, class A2, class A3, class A4 > class list4: private storage4< A1, A2, A3, A4 > +{ +private: + + typedef storage4< A1, A2, A3, A4 > base_type; + +public: + + list4( A1 a1, A2 a2, A3 a3, A4 a4 ): base_type( a1, a2, a3, a4 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list4 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5 > class list5: private storage5< A1, A2, A3, A4, A5 > +{ +private: + + typedef storage5< A1, A2, A3, A4, A5 > base_type; + +public: + + list5( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5 ): base_type( a1, a2, a3, a4, a5 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + A5 operator[] (boost::arg<5>) const { return base_type::a5_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + A5 operator[] (boost::arg<5> (*) ()) const { return base_type::a5_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list5 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ) && + ref_compare( base_type::a5_, rhs.a5_, 0 ); + } +}; + +template class list6: private storage6< A1, A2, A3, A4, A5, A6 > +{ +private: + + typedef storage6< A1, A2, A3, A4, A5, A6 > base_type; + +public: + + list6( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6 ): base_type( a1, a2, a3, a4, a5, a6 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + A5 operator[] (boost::arg<5>) const { return base_type::a5_; } + A6 operator[] (boost::arg<6>) const { return base_type::a6_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + A5 operator[] (boost::arg<5> (*) ()) const { return base_type::a5_; } + A6 operator[] (boost::arg<6> (*) ()) const { return base_type::a6_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list6 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ) && + ref_compare( base_type::a5_, rhs.a5_, 0 ) && + ref_compare( base_type::a6_, rhs.a6_, 0 ); + } +}; + +template class list7: private storage7< A1, A2, A3, A4, A5, A6, A7 > +{ +private: + + typedef storage7< A1, A2, A3, A4, A5, A6, A7 > base_type; + +public: + + list7( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7 ): base_type( a1, a2, a3, a4, a5, a6, a7 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + A5 operator[] (boost::arg<5>) const { return base_type::a5_; } + A6 operator[] (boost::arg<6>) const { return base_type::a6_; } + A7 operator[] (boost::arg<7>) const { return base_type::a7_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + A5 operator[] (boost::arg<5> (*) ()) const { return base_type::a5_; } + A6 operator[] (boost::arg<6> (*) ()) const { return base_type::a6_; } + A7 operator[] (boost::arg<7> (*) ()) const { return base_type::a7_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list7 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ) && + ref_compare( base_type::a5_, rhs.a5_, 0 ) && + ref_compare( base_type::a6_, rhs.a6_, 0 ) && + ref_compare( base_type::a7_, rhs.a7_, 0 ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > class list8: private storage8< A1, A2, A3, A4, A5, A6, A7, A8 > +{ +private: + + typedef storage8< A1, A2, A3, A4, A5, A6, A7, A8 > base_type; + +public: + + list8( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8 ): base_type( a1, a2, a3, a4, a5, a6, a7, a8 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + A5 operator[] (boost::arg<5>) const { return base_type::a5_; } + A6 operator[] (boost::arg<6>) const { return base_type::a6_; } + A7 operator[] (boost::arg<7>) const { return base_type::a7_; } + A8 operator[] (boost::arg<8>) const { return base_type::a8_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + A5 operator[] (boost::arg<5> (*) ()) const { return base_type::a5_; } + A6 operator[] (boost::arg<6> (*) ()) const { return base_type::a6_; } + A7 operator[] (boost::arg<7> (*) ()) const { return base_type::a7_; } + A8 operator[] (boost::arg<8> (*) ()) const { return base_type::a8_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list8 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ) && + ref_compare( base_type::a5_, rhs.a5_, 0 ) && + ref_compare( base_type::a6_, rhs.a6_, 0 ) && + ref_compare( base_type::a7_, rhs.a7_, 0 ) && + ref_compare( base_type::a8_, rhs.a8_, 0 ); + } +}; + +template class list9: private storage9< A1, A2, A3, A4, A5, A6, A7, A8, A9 > +{ +private: + + typedef storage9< A1, A2, A3, A4, A5, A6, A7, A8, A9 > base_type; + +public: + + list9( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9 ): base_type( a1, a2, a3, a4, a5, a6, a7, a8, a9 ) {} + + A1 operator[] (boost::arg<1>) const { return base_type::a1_; } + A2 operator[] (boost::arg<2>) const { return base_type::a2_; } + A3 operator[] (boost::arg<3>) const { return base_type::a3_; } + A4 operator[] (boost::arg<4>) const { return base_type::a4_; } + A5 operator[] (boost::arg<5>) const { return base_type::a5_; } + A6 operator[] (boost::arg<6>) const { return base_type::a6_; } + A7 operator[] (boost::arg<7>) const { return base_type::a7_; } + A8 operator[] (boost::arg<8>) const { return base_type::a8_; } + A9 operator[] (boost::arg<9>) const { return base_type::a9_; } + + A1 operator[] (boost::arg<1> (*) ()) const { return base_type::a1_; } + A2 operator[] (boost::arg<2> (*) ()) const { return base_type::a2_; } + A3 operator[] (boost::arg<3> (*) ()) const { return base_type::a3_; } + A4 operator[] (boost::arg<4> (*) ()) const { return base_type::a4_; } + A5 operator[] (boost::arg<5> (*) ()) const { return base_type::a5_; } + A6 operator[] (boost::arg<6> (*) ()) const { return base_type::a6_; } + A7 operator[] (boost::arg<7> (*) ()) const { return base_type::a7_; } + A8 operator[] (boost::arg<8> (*) ()) const { return base_type::a8_; } + A9 operator[] (boost::arg<9> (*) ()) const { return base_type::a9_; } + + template T & operator[] (_bi::value & v) const { return v.get(); } + + template T const & operator[] (_bi::value const & v) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const { return b.eval(*this); } + + template typename result_traits::type operator[] (bind_t const & b) const { return b.eval(*this); } + + template R operator()(type, F & f, A & a, long) + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_], a[base_type::a9_]); + } + + template R operator()(type, F const & f, A & a, long) const + { + return unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_], a[base_type::a9_]); + } + + template void operator()(type, F & f, A & a, int) + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_], a[base_type::a9_]); + } + + template void operator()(type, F const & f, A & a, int) const + { + unwrapper::unwrap(f, 0)(a[base_type::a1_], a[base_type::a2_], a[base_type::a3_], a[base_type::a4_], a[base_type::a5_], a[base_type::a6_], a[base_type::a7_], a[base_type::a8_], a[base_type::a9_]); + } + + template void accept(V & v) const + { + base_type::accept(v); + } + + bool operator==(list9 const & rhs) const + { + return + + ref_compare( base_type::a1_, rhs.a1_, 0 ) && + ref_compare( base_type::a2_, rhs.a2_, 0 ) && + ref_compare( base_type::a3_, rhs.a3_, 0 ) && + ref_compare( base_type::a4_, rhs.a4_, 0 ) && + ref_compare( base_type::a5_, rhs.a5_, 0 ) && + ref_compare( base_type::a6_, rhs.a6_, 0 ) && + ref_compare( base_type::a7_, rhs.a7_, 0 ) && + ref_compare( base_type::a8_, rhs.a8_, 0 ) && + ref_compare( base_type::a9_, rhs.a9_, 0 ); + } +}; + +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + +// bind_t + +#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) + +template< class A1 > class rrlist1 +{ +private: + + A1 & a1_; // not A1&& because of msvc-10.0 + +public: + + explicit rrlist1( A1 & a1 ): a1_( a1 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } // not static_cast because of g++ 4.9 + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist1 a( a1_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist1 a( a1_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2 > class rrlist2 +{ +private: + + A1 & a1_; + A2 & a2_; + +public: + + rrlist2( A1 & a1, A2 & a2 ): a1_( a1 ), a2_( a2 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist2 a( a1_, a2_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist2 a( a1_, a2_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3 > class rrlist3 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + +public: + + rrlist3( A1 & a1, A2 & a2, A3 & a3 ): a1_( a1 ), a2_( a2 ), a3_( a3 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist3 a( a1_, a2_, a3_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist3 a( a1_, a2_, a3_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4 > class rrlist4 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + +public: + + rrlist4( A1 & a1, A2 & a2, A3 & a3, A4 & a4 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist4 a( a1_, a2_, a3_, a4_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist4 a( a1_, a2_, a3_, a4_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5 > class rrlist5 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + A5 & a5_; + +public: + + rrlist5( A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ), a5_( a5 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5>) const { return std::forward( a5_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5> (*) ()) const { return std::forward( a5_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist5 a( a1_, a2_, a3_, a4_, a5_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist5 a( a1_, a2_, a3_, a4_, a5_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5, class A6 > class rrlist6 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + A5 & a5_; + A6 & a6_; + +public: + + rrlist6( A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ), a5_( a5 ), a6_( a6 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5>) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6>) const { return std::forward( a6_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5> (*) ()) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6> (*) ()) const { return std::forward( a6_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist6 a( a1_, a2_, a3_, a4_, a5_, a6_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist6 a( a1_, a2_, a3_, a4_, a5_, a6_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5, class A6, class A7 > class rrlist7 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + A5 & a5_; + A6 & a6_; + A7 & a7_; + +public: + + rrlist7( A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ), a5_( a5 ), a6_( a6 ), a7_( a7 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5>) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6>) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7>) const { return std::forward( a7_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5> (*) ()) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6> (*) ()) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7> (*) ()) const { return std::forward( a7_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist7 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist7 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 > class rrlist8 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + A5 & a5_; + A6 & a6_; + A7 & a7_; + A8 & a8_; + +public: + + rrlist8( A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ), a5_( a5 ), a6_( a6 ), a7_( a7 ), a8_( a8 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5>) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6>) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7>) const { return std::forward( a7_ ); } + A8 && operator[] (boost::arg<8>) const { return std::forward( a8_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5> (*) ()) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6> (*) ()) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7> (*) ()) const { return std::forward( a7_ ); } + A8 && operator[] (boost::arg<8> (*) ()) const { return std::forward( a8_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist8 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist8 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_ ); + return b.eval( a ); + } +}; + +template< class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 > class rrlist9 +{ +private: + + A1 & a1_; + A2 & a2_; + A3 & a3_; + A4 & a4_; + A5 & a5_; + A6 & a6_; + A7 & a7_; + A8 & a8_; + A9 & a9_; + +public: + + rrlist9( A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9 ): a1_( a1 ), a2_( a2 ), a3_( a3 ), a4_( a4 ), a5_( a5 ), a6_( a6 ), a7_( a7 ), a8_( a8 ), a9_( a9 ) {} + + A1 && operator[] (boost::arg<1>) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2>) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3>) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4>) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5>) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6>) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7>) const { return std::forward( a7_ ); } + A8 && operator[] (boost::arg<8>) const { return std::forward( a8_ ); } + A9 && operator[] (boost::arg<9>) const { return std::forward( a9_ ); } + + A1 && operator[] (boost::arg<1> (*) ()) const { return std::forward( a1_ ); } + A2 && operator[] (boost::arg<2> (*) ()) const { return std::forward( a2_ ); } + A3 && operator[] (boost::arg<3> (*) ()) const { return std::forward( a3_ ); } + A4 && operator[] (boost::arg<4> (*) ()) const { return std::forward( a4_ ); } + A5 && operator[] (boost::arg<5> (*) ()) const { return std::forward( a5_ ); } + A6 && operator[] (boost::arg<6> (*) ()) const { return std::forward( a6_ ); } + A7 && operator[] (boost::arg<7> (*) ()) const { return std::forward( a7_ ); } + A8 && operator[] (boost::arg<8> (*) ()) const { return std::forward( a8_ ); } + A9 && operator[] (boost::arg<9> (*) ()) const { return std::forward( a9_ ); } + + template T & operator[] ( _bi::value & v ) const { return v.get(); } + + template T const & operator[] ( _bi::value const & v ) const { return v.get(); } + + template T & operator[] (reference_wrapper const & v) const { return v.get(); } + + template typename result_traits::type operator[] (bind_t & b) const + { + rrlist9 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_ ); + return b.eval( a ); + } + + template typename result_traits::type operator[] (bind_t const & b) const + { + rrlist9 a( a1_, a2_, a3_, a4_, a5_, a6_, a7_, a8_, a9_ ); + return b.eval( a ); + } +}; + +template class bind_t +{ +private: + + F f_; + L l_; + +public: + + typedef typename result_traits::type result_type; + typedef bind_t this_type; + + bind_t( F f, L const & l ): f_( f ), l_( l ) {} + + // + + result_type operator()() + { + list0 a; + return l_( type(), f_, a, 0 ); + } + + result_type operator()() const + { + list0 a; + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1 ) + { + rrlist1< A1 > a( a1 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1 ) const + { + rrlist1< A1 > a( a1 ); + return l_(type(), f_, a, 0); + } + + template result_type operator()( A1 && a1, A2 && a2 ) + { + rrlist2< A1, A2 > a( a1, a2 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2 ) const + { + rrlist2< A1, A2 > a( a1, a2 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3 ) + { + rrlist3< A1, A2, A3 > a( a1, a2, a3 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3 ) const + { + rrlist3< A1, A2, A3 > a( a1, a2, a3 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4 ) + { + rrlist4< A1, A2, A3, A4 > a( a1, a2, a3, a4 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4 ) const + { + rrlist4< A1, A2, A3, A4 > a( a1, a2, a3, a4 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 ) + { + rrlist5< A1, A2, A3, A4, A5 > a( a1, a2, a3, a4, a5 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 ) const + { + rrlist5< A1, A2, A3, A4, A5 > a( a1, a2, a3, a4, a5 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 ) + { + rrlist6< A1, A2, A3, A4, A5, A6 > a( a1, a2, a3, a4, a5, a6 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 ) const + { + rrlist6< A1, A2, A3, A4, A5, A6 > a( a1, a2, a3, a4, a5, a6 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 ) + { + rrlist7< A1, A2, A3, A4, A5, A6, A7 > a( a1, a2, a3, a4, a5, a6, a7 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 ) const + { + rrlist7< A1, A2, A3, A4, A5, A6, A7 > a( a1, a2, a3, a4, a5, a6, a7 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 ) + { + rrlist8< A1, A2, A3, A4, A5, A6, A7, A8 > a( a1, a2, a3, a4, a5, a6, a7, a8 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 ) const + { + rrlist8< A1, A2, A3, A4, A5, A6, A7, A8 > a( a1, a2, a3, a4, a5, a6, a7, a8 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 ) + { + rrlist9< A1, A2, A3, A4, A5, A6, A7, A8, A9 > a( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + return l_( type(), f_, a, 0 ); + } + + template result_type operator()( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 ) const + { + rrlist9< A1, A2, A3, A4, A5, A6, A7, A8, A9 > a( a1, a2, a3, a4, a5, a6, a7, a8, a9 ); + return l_( type(), f_, a, 0 ); + } + + // + + template result_type eval( A & a ) + { + return l_( type(), f_, a, 0 ); + } + + template result_type eval( A & a ) const + { + return l_( type(), f_, a, 0 ); + } + + template void accept( V & v ) const + { +#if !defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) && !defined( __BORLANDC__ ) + using boost::visit_each; +#endif + + BOOST_BIND_VISIT_EACH( v, f_, 0 ); + l_.accept( v ); + } + + bool compare( this_type const & rhs ) const + { + return ref_compare( f_, rhs.f_, 0 ) && l_ == rhs.l_; + } +}; + +#elif !defined( BOOST_NO_VOID_RETURNS ) + +template class bind_t +{ +public: + + typedef bind_t this_type; + + bind_t(F f, L const & l): f_(f), l_(l) {} + +#define BOOST_BIND_RETURN return +#include +#undef BOOST_BIND_RETURN + +}; + +#else // no void returns + +template struct bind_t_generator +{ + +template class implementation +{ +public: + + typedef implementation this_type; + + implementation(F f, L const & l): f_(f), l_(l) {} + +#define BOOST_BIND_RETURN return +#include +#undef BOOST_BIND_RETURN + +}; + +}; + +template<> struct bind_t_generator +{ + +template class implementation +{ +private: + + typedef void R; + +public: + + typedef implementation this_type; + + implementation(F f, L const & l): f_(f), l_(l) {} + +#define BOOST_BIND_RETURN +#include +#undef BOOST_BIND_RETURN + +}; + +}; + +template class bind_t: public bind_t_generator::BOOST_NESTED_TEMPLATE implementation +{ +public: + + bind_t(F f, L const & l): bind_t_generator::BOOST_NESTED_TEMPLATE implementation(f, l) {} + +}; + +#endif + +// function_equal + +#ifndef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP + +// put overloads in _bi, rely on ADL + +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +template bool function_equal( bind_t const & a, bind_t const & b ) +{ + return a.compare(b); +} + +# else + +template bool function_equal_impl( bind_t const & a, bind_t const & b, int ) +{ + return a.compare(b); +} + +# endif // #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +#else // BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP + +// put overloads in boost + +} // namespace _bi + +# ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +template bool function_equal( _bi::bind_t const & a, _bi::bind_t const & b ) +{ + return a.compare(b); +} + +# else + +template bool function_equal_impl( _bi::bind_t const & a, _bi::bind_t const & b, int ) +{ + return a.compare(b); +} + +# endif // #ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING + +namespace _bi +{ + +#endif // BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP + +// add_value + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || (__SUNPRO_CC >= 0x530) + +#if defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT(0x582) ) + +template struct add_value +{ + typedef _bi::value type; +}; + +#else + +template< class T, int I > struct add_value_2 +{ + typedef boost::arg type; +}; + +template< class T > struct add_value_2< T, 0 > +{ + typedef _bi::value< T > type; +}; + +template struct add_value +{ + typedef typename add_value_2< T, boost::is_placeholder< T >::value >::type type; +}; + +#endif + +template struct add_value< value > +{ + typedef _bi::value type; +}; + +template struct add_value< reference_wrapper > +{ + typedef reference_wrapper type; +}; + +template struct add_value< arg > +{ + typedef boost::arg type; +}; + +template struct add_value< arg (*) () > +{ + typedef boost::arg (*type) (); +}; + +template struct add_value< bind_t > +{ + typedef bind_t type; +}; + +#else + +template struct _avt_0; + +template<> struct _avt_0<1> +{ + template struct inner + { + typedef T type; + }; +}; + +template<> struct _avt_0<2> +{ + template struct inner + { + typedef value type; + }; +}; + +typedef char (&_avt_r1) [1]; +typedef char (&_avt_r2) [2]; + +template _avt_r1 _avt_f(value); +template _avt_r1 _avt_f(reference_wrapper); +template _avt_r1 _avt_f(arg); +template _avt_r1 _avt_f(arg (*) ()); +template _avt_r1 _avt_f(bind_t); + +_avt_r2 _avt_f(...); + +template struct add_value +{ + static T t(); + typedef typename _avt_0::template inner::type type; +}; + +#endif + +// list_av_N + +template struct list_av_1 +{ + typedef typename add_value::type B1; + typedef list1 type; +}; + +template struct list_av_2 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef list2 type; +}; + +template struct list_av_3 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef list3 type; +}; + +template struct list_av_4 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef list4 type; +}; + +template struct list_av_5 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef typename add_value::type B5; + typedef list5 type; +}; + +template struct list_av_6 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef typename add_value::type B5; + typedef typename add_value::type B6; + typedef list6 type; +}; + +template struct list_av_7 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef typename add_value::type B5; + typedef typename add_value::type B6; + typedef typename add_value::type B7; + typedef list7 type; +}; + +template struct list_av_8 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef typename add_value::type B5; + typedef typename add_value::type B6; + typedef typename add_value::type B7; + typedef typename add_value::type B8; + typedef list8 type; +}; + +template struct list_av_9 +{ + typedef typename add_value::type B1; + typedef typename add_value::type B2; + typedef typename add_value::type B3; + typedef typename add_value::type B4; + typedef typename add_value::type B5; + typedef typename add_value::type B6; + typedef typename add_value::type B7; + typedef typename add_value::type B8; + typedef typename add_value::type B9; + typedef list9 type; +}; + +// operator! + +struct logical_not +{ + template bool operator()(V const & v) const { return !v; } +}; + +template + bind_t< bool, logical_not, list1< bind_t > > + operator! (bind_t const & f) +{ + typedef list1< bind_t > list_type; + return bind_t ( logical_not(), list_type(f) ); +} + +// relational operators + +#define BOOST_BIND_OPERATOR( op, name ) \ +\ +struct name \ +{ \ + template bool operator()(V const & v, W const & w) const { return v op w; } \ +}; \ + \ +template \ + bind_t< bool, name, list2< bind_t, typename add_value::type > > \ + operator op (bind_t const & f, A2 a2) \ +{ \ + typedef typename add_value::type B2; \ + typedef list2< bind_t, B2> list_type; \ + return bind_t ( name(), list_type(f, a2) ); \ +} + +BOOST_BIND_OPERATOR( ==, equal ) +BOOST_BIND_OPERATOR( !=, not_equal ) + +BOOST_BIND_OPERATOR( <, less ) +BOOST_BIND_OPERATOR( <=, less_equal ) + +BOOST_BIND_OPERATOR( >, greater ) +BOOST_BIND_OPERATOR( >=, greater_equal ) + +BOOST_BIND_OPERATOR( &&, logical_and ) +BOOST_BIND_OPERATOR( ||, logical_or ) + +#undef BOOST_BIND_OPERATOR + +#if defined(__GNUC__) && BOOST_WORKAROUND(__GNUC__, < 3) + +// resolve ambiguity with rel_ops + +#define BOOST_BIND_OPERATOR( op, name ) \ +\ +template \ + bind_t< bool, name, list2< bind_t, bind_t > > \ + operator op (bind_t const & f, bind_t const & g) \ +{ \ + typedef list2< bind_t, bind_t > list_type; \ + return bind_t ( name(), list_type(f, g) ); \ +} + +BOOST_BIND_OPERATOR( !=, not_equal ) +BOOST_BIND_OPERATOR( <=, less_equal ) +BOOST_BIND_OPERATOR( >, greater ) +BOOST_BIND_OPERATOR( >=, greater_equal ) + +#endif + +// visit_each, ADL + +#if !defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) && !defined( __BORLANDC__ ) \ + && !(defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3) + +template void visit_each( V & v, value const & t, int ) +{ + using boost::visit_each; + BOOST_BIND_VISIT_EACH( v, t.get(), 0 ); +} + +template void visit_each( V & v, bind_t const & t, int ) +{ + t.accept( v ); +} + +#endif + +} // namespace _bi + +// visit_each, no ADL + +#if defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) || defined( __BORLANDC__ ) \ + || (defined(__GNUC__) && __GNUC__ == 3 && __GNUC_MINOR__ <= 3) + +template void visit_each( V & v, _bi::value const & t, int ) +{ + BOOST_BIND_VISIT_EACH( v, t.get(), 0 ); +} + +template void visit_each( V & v, _bi::bind_t const & t, int ) +{ + t.accept( v ); +} + +#endif + +// is_bind_expression + +template< class T > struct is_bind_expression +{ + enum _vt { value = 0 }; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template< class R, class F, class L > struct is_bind_expression< _bi::bind_t< R, F, L > > +{ + enum _vt { value = 1 }; +}; + +#endif + +// bind + +#ifndef BOOST_BIND +#define BOOST_BIND bind +#endif + +// generic function objects + +template + _bi::bind_t + BOOST_BIND(F f) +{ + typedef _bi::list0 list_type; + return _bi::bind_t (f, list_type()); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1) +{ + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t (f, list_type(a1)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2) +{ + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t (f, list_type(a1, a2)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3) +{ + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +// generic function objects, alternative syntax + +template + _bi::bind_t + BOOST_BIND(boost::type, F f) +{ + typedef _bi::list0 list_type; + return _bi::bind_t (f, list_type()); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1) +{ + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t (f, list_type(a1)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2) +{ + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t (f, list_type(a1, a2)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3) +{ + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t::type> + BOOST_BIND(boost::type, F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +// adaptable function objects + +template + _bi::bind_t<_bi::unspecified, F, _bi::list0> + BOOST_BIND(F f) +{ + typedef _bi::list0 list_type; + return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type()); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_1::type> + BOOST_BIND(F f, A1 a1) +{ + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type(a1)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_2::type> + BOOST_BIND(F f, A1 a1, A2 a2) +{ + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type> (f, list_type(a1, a2)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_3::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3) +{ + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_4::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_5::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_6::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_7::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_8::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t<_bi::unspecified, F, typename _bi::list_av_9::type> + BOOST_BIND(F f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t<_bi::unspecified, F, list_type>(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +#endif // !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) + +// function pointers + +#define BOOST_BIND_CC +#define BOOST_BIND_ST +#define BOOST_BIND_NOEXCEPT + +#include + +# if defined( __cpp_noexcept_function_type ) || defined( _NOEXCEPT_TYPES_SUPPORTED ) +# undef BOOST_BIND_NOEXCEPT +# define BOOST_BIND_NOEXCEPT noexcept +# include +# endif + +#undef BOOST_BIND_CC +#undef BOOST_BIND_ST +#undef BOOST_BIND_NOEXCEPT + +#ifdef BOOST_BIND_ENABLE_STDCALL + +#define BOOST_BIND_CC __stdcall +#define BOOST_BIND_ST +#define BOOST_BIND_NOEXCEPT + +#include + +#undef BOOST_BIND_CC +#undef BOOST_BIND_ST +#undef BOOST_BIND_NOEXCEPT + +#endif + +#ifdef BOOST_BIND_ENABLE_FASTCALL + +#define BOOST_BIND_CC __fastcall +#define BOOST_BIND_ST +#define BOOST_BIND_NOEXCEPT + +#include + +#undef BOOST_BIND_CC +#undef BOOST_BIND_ST +#undef BOOST_BIND_NOEXCEPT + +#endif + +#ifdef BOOST_BIND_ENABLE_PASCAL + +#define BOOST_BIND_ST pascal +#define BOOST_BIND_CC +#define BOOST_BIND_NOEXCEPT + +#include + +#undef BOOST_BIND_ST +#undef BOOST_BIND_CC +#undef BOOST_BIND_NOEXCEPT + +#endif + +// member function pointers + +#define BOOST_BIND_MF_NAME(X) X +#define BOOST_BIND_MF_CC +#define BOOST_BIND_MF_NOEXCEPT + +#include +#include + +# if defined( __cpp_noexcept_function_type ) || defined( _NOEXCEPT_TYPES_SUPPORTED ) +# undef BOOST_BIND_MF_NOEXCEPT +# define BOOST_BIND_MF_NOEXCEPT noexcept +# include +# endif + +#undef BOOST_BIND_MF_NAME +#undef BOOST_BIND_MF_CC +#undef BOOST_BIND_MF_NOEXCEPT + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_BIND_MF_NAME(X) X##_cdecl +#define BOOST_BIND_MF_CC __cdecl +#define BOOST_BIND_MF_NOEXCEPT + +#include +#include + +#undef BOOST_BIND_MF_NAME +#undef BOOST_BIND_MF_CC +#undef BOOST_BIND_MF_NOEXCEPT + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_BIND_MF_NAME(X) X##_stdcall +#define BOOST_BIND_MF_CC __stdcall +#define BOOST_BIND_MF_NOEXCEPT + +#include +#include + +#undef BOOST_BIND_MF_NAME +#undef BOOST_BIND_MF_CC +#undef BOOST_BIND_MF_NOEXCEPT + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_BIND_MF_NAME(X) X##_fastcall +#define BOOST_BIND_MF_CC __fastcall +#define BOOST_BIND_MF_NOEXCEPT + +#include +#include + +#undef BOOST_BIND_MF_NAME +#undef BOOST_BIND_MF_CC +#undef BOOST_BIND_MF_NOEXCEPT + +#endif + +// data member pointers + +#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) || defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + || ( defined(__BORLANDC__) && BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x620 ) ) ) + +template +_bi::bind_t< R, _mfi::dm, typename _bi::list_av_1::type > + BOOST_BIND(R T::*f, A1 a1) +{ + typedef _mfi::dm F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t( F(f), list_type(a1) ); +} + +#else + +namespace _bi +{ + +template< class Pm, int I > struct add_cref; + +template< class M, class T > struct add_cref< M T::*, 0 > +{ + typedef M type; +}; + +template< class M, class T > struct add_cref< M T::*, 1 > +{ +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4180) +#endif + typedef M const & type; +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif +}; + +template< class R, class T > struct add_cref< R (T::*) (), 1 > +{ + typedef void type; +}; + +#if !defined(__IBMCPP__) || __IBMCPP_FUNC_CV_TMPL_ARG_DEDUCTION + +template< class R, class T > struct add_cref< R (T::*) () const, 1 > +{ + typedef void type; +}; + +#if defined( __cpp_noexcept_function_type ) || defined( _NOEXCEPT_TYPES_SUPPORTED ) + +template< class R, class T > struct add_cref< R (T::*) () const noexcept, 1 > +{ + typedef void type; +}; + +#endif // __cpp_noexcept_function_type + +#endif // __IBMCPP__ + +template struct isref +{ + enum value_type { value = 0 }; +}; + +template struct isref< R& > +{ + enum value_type { value = 1 }; +}; + +template struct isref< R* > +{ + enum value_type { value = 1 }; +}; + +template struct dm_result +{ + typedef typename add_cref< Pm, 1 >::type type; +}; + +template struct dm_result< Pm, bind_t > +{ + typedef typename bind_t::result_type result_type; + typedef typename add_cref< Pm, isref< result_type >::value >::type type; +}; + +} // namespace _bi + +template< class A1, class M, class T > + +_bi::bind_t< + typename _bi::dm_result< M T::*, A1 >::type, + _mfi::dm, + typename _bi::list_av_1::type +> + +BOOST_BIND( M T::*f, A1 a1 ) +{ + typedef typename _bi::dm_result< M T::*, A1 >::type result_type; + typedef _mfi::dm F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t< result_type, F, list_type >( F( f ), list_type( a1 ) ); +} + +#endif + +} // namespace boost + +#ifndef BOOST_BIND_NO_PLACEHOLDERS + +# include + +#endif + +#ifdef BOOST_MSVC +# pragma warning(default: 4512) // assignment operator could not be generated +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_BIND_BIND_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/bind_cc.hpp b/third-party/boost/boost/bind/bind_cc.hpp new file mode 100644 index 000000000..278aa9a2a --- /dev/null +++ b/third-party/boost/boost/bind/bind_cc.hpp @@ -0,0 +1,117 @@ +// +// bind/bind_cc.hpp - support for different calling conventions +// +// Do not include this header directly. +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +template + _bi::bind_t + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) () BOOST_BIND_NOEXCEPT) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) () BOOST_BIND_NOEXCEPT; + typedef _bi::list0 list_type; + return _bi::bind_t (f, list_type()); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1) BOOST_BIND_NOEXCEPT, A1 a1) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t (f, list_type(a1)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t (f, list_type(a1, a2)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4, B5) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4, B5) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4, B5, B6) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4, B5, B6) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4, B5, B6, B7) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4, B5, B6, B7) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4, B5, B6, B7, B8) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4, B5, B6, B7, B8) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t::type> + BOOST_BIND(BOOST_BIND_ST R (BOOST_BIND_CC *f) (B1, B2, B3, B4, B5, B6, B7, B8, B9) BOOST_BIND_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef BOOST_BIND_ST R (BOOST_BIND_CC *F) (B1, B2, B3, B4, B5, B6, B7, B8, B9) BOOST_BIND_NOEXCEPT; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(f, list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} diff --git a/third-party/boost/boost/bind/bind_mf2_cc.hpp b/third-party/boost/boost/bind/bind_mf2_cc.hpp new file mode 100644 index 000000000..66476bc19 --- /dev/null +++ b/third-party/boost/boost/bind/bind_mf2_cc.hpp @@ -0,0 +1,228 @@ +// +// bind/bind_mf2_cc.hpp - member functions, type<> syntax +// +// Do not include this header directly. +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2008 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +// 0 + +template + _bi::bind_t, typename _bi::list_av_1::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (), A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +template + _bi::bind_t, typename _bi::list_av_1::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) () const, A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +// 1 + +template + _bi::bind_t, typename _bi::list_av_2::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1), A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +template + _bi::bind_t, typename _bi::list_av_2::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1) const, A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +// 2 + +template + _bi::bind_t, typename _bi::list_av_3::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2), A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +template + _bi::bind_t, typename _bi::list_av_3::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2) const, A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +// 3 + +template + _bi::bind_t, typename _bi::list_av_4::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3), A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t, typename _bi::list_av_4::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3) const, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +// 4 + +template + _bi::bind_t, typename _bi::list_av_5::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t, typename _bi::list_av_5::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +// 5 + +template + _bi::bind_t, typename _bi::list_av_6::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t, typename _bi::list_av_6::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +// 6 + +template + _bi::bind_t, typename _bi::list_av_7::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t, typename _bi::list_av_7::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +// 7 + +template + _bi::bind_t, typename _bi::list_av_8::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t, typename _bi::list_av_8::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +// 8 + +template + _bi::bind_t, typename _bi::list_av_9::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8), A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template + _bi::bind_t, typename _bi::list_av_9::type> + BOOST_BIND(boost::type, R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) const, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} diff --git a/third-party/boost/boost/bind/bind_mf_cc.hpp b/third-party/boost/boost/bind/bind_mf_cc.hpp new file mode 100644 index 000000000..bbfd3719b --- /dev/null +++ b/third-party/boost/boost/bind/bind_mf_cc.hpp @@ -0,0 +1,441 @@ +// +// bind/bind_mf_cc.hpp - support for different calling conventions +// +// Do not include this header directly. +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +// 0 + +template + _bi::bind_t, typename _bi::list_av_1::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) () BOOST_BIND_MF_NOEXCEPT, A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +template + _bi::bind_t, typename _bi::list_av_1::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) () const BOOST_BIND_MF_NOEXCEPT, A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_1::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) () BOOST_BIND_MF_NOEXCEPT, A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_1::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) () const BOOST_BIND_MF_NOEXCEPT, A1 a1) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf0) F; + typedef typename _bi::list_av_1::type list_type; + return _bi::bind_t(F(f), list_type(a1)); +} + +// 1 + +template + _bi::bind_t, typename _bi::list_av_2::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +template + _bi::bind_t, typename _bi::list_av_2::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_2::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_2::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf1) F; + typedef typename _bi::list_av_2::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2)); +} + +// 2 + +template + _bi::bind_t, typename _bi::list_av_3::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +template + _bi::bind_t, typename _bi::list_av_3::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_3::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_3::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf2) F; + typedef typename _bi::list_av_3::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3)); +} + +// 3 + +template + _bi::bind_t, typename _bi::list_av_4::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +template + _bi::bind_t, typename _bi::list_av_4::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_4::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_4::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf3) F; + typedef typename _bi::list_av_4::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4)); +} + +// 4 + +template + _bi::bind_t, typename _bi::list_av_5::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +template + _bi::bind_t, typename _bi::list_av_5::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_5::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_5::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf4) F; + typedef typename _bi::list_av_5::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5)); +} + +// 5 + +template + _bi::bind_t, typename _bi::list_av_6::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +template + _bi::bind_t, typename _bi::list_av_6::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_6::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_6::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf5) F; + typedef typename _bi::list_av_6::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6)); +} + +// 6 + +template + _bi::bind_t, typename _bi::list_av_7::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + _bi::bind_t, typename _bi::list_av_7::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_7::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_7::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf6) F; + typedef typename _bi::list_av_7::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7)); +} + +// 7 + +template + _bi::bind_t, typename _bi::list_av_8::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + _bi::bind_t, typename _bi::list_av_8::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_8::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_8::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf7) F; + typedef typename _bi::list_av_8::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8)); +} + +// 8 + +template + _bi::bind_t, typename _bi::list_av_9::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template + _bi::bind_t, typename _bi::list_av_9::type> + BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_9::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(mf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} + +template + typename boost::enable_if_c::value, + _bi::bind_t, typename _bi::list_av_9::type> + >::type BOOST_BIND(R (BOOST_BIND_MF_CC T::*f) (B1, B2, B3, B4, B5, B6, B7, B8) const BOOST_BIND_MF_NOEXCEPT, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9) +{ + typedef _mfi::BOOST_BIND_MF_NAME(cmf8) F; + typedef typename _bi::list_av_9::type list_type; + return _bi::bind_t(F(f), list_type(a1, a2, a3, a4, a5, a6, a7, a8, a9)); +} diff --git a/third-party/boost/boost/bind/bind_template.hpp b/third-party/boost/boost/bind/bind_template.hpp new file mode 100644 index 000000000..411d20c74 --- /dev/null +++ b/third-party/boost/boost/bind/bind_template.hpp @@ -0,0 +1,345 @@ +// +// bind/bind_template.hpp +// +// Do not include this header directly. +// +// Copyright (c) 2001-2004 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + + typedef typename result_traits::type result_type; + + result_type operator()() + { + list0 a; + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + result_type operator()() const + { + list0 a; + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1) + { + list1 a(a1); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1) const + { + list1 a(a1); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1) + { + list1 a(a1); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1) const + { + list1 a(a1); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2) + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2) const + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 & a2) + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 & a2) const + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + + template result_type operator()(A1 & a1, A2 const & a2) + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 const & a2) const + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + + template result_type operator()(A1 const & a1, A2 const & a2) + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2) const + { + list2 a(a1, a2); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3) + { + list3 a(a1, a2, a3); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3) const + { + list3 a(a1, a2, a3); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3) + { + list3 a(a1, a2, a3); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3) const + { + list3 a(a1, a2, a3); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4) + { + list4 a(a1, a2, a3, a4); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4) const + { + list4 a(a1, a2, a3, a4); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4) + { + list4 a(a1, a2, a3, a4); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4) const + { + list4 a(a1, a2, a3, a4); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) + { + list5 a(a1, a2, a3, a4, a5); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) const + { + list5 a(a1, a2, a3, a4, a5); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5) + { + list5 a(a1, a2, a3, a4, a5); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5) const + { + list5 a(a1, a2, a3, a4, a5); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) + { + list6 a(a1, a2, a3, a4, a5, a6); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) const + { + list6 a(a1, a2, a3, a4, a5, a6); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6) + { + list6 a(a1, a2, a3, a4, a5, a6); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6) const + { + list6 a(a1, a2, a3, a4, a5, a6); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) + { + list7 a(a1, a2, a3, a4, a5, a6, a7); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) const + { + list7 a(a1, a2, a3, a4, a5, a6, a7); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7) + { + list7 a(a1, a2, a3, a4, a5, a6, a7); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7) const + { + list7 a(a1, a2, a3, a4, a5, a6, a7); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) + { + list8 a(a1, a2, a3, a4, a5, a6, a7, a8); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) const + { + list8 a(a1, a2, a3, a4, a5, a6, a7, a8); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8) + { + list8 a(a1, a2, a3, a4, a5, a6, a7, a8); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8) const + { + list8 a(a1, a2, a3, a4, a5, a6, a7, a8); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) + { + list9 a(a1, a2, a3, a4, a5, a6, a7, a8, a9); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) const + { + list9 a(a1, a2, a3, a4, a5, a6, a7, a8, a9); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9) + { + list9 a(a1, a2, a3, a4, a5, a6, a7, a8, a9); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9) const + { + list9 a(a1, a2, a3, a4, a5, a6, a7, a8, a9); + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + +#endif + + template result_type eval(A & a) + { + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template result_type eval(A & a) const + { + BOOST_BIND_RETURN l_(type(), f_, a, 0); + } + + template void accept(V & v) const + { +#if !defined( BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP ) && !defined( __BORLANDC__ ) + + using boost::visit_each; + +#endif + BOOST_BIND_VISIT_EACH(v, f_, 0); + l_.accept(v); + } + + bool compare(this_type const & rhs) const + { + return ref_compare(f_, rhs.f_, 0) && l_ == rhs.l_; + } + +private: + + F f_; + L l_; diff --git a/third-party/boost/boost/bind/make_adaptable.hpp b/third-party/boost/boost/bind/make_adaptable.hpp new file mode 100644 index 000000000..b9f083e30 --- /dev/null +++ b/third-party/boost/boost/bind/make_adaptable.hpp @@ -0,0 +1,187 @@ +#ifndef BOOST_BIND_MAKE_ADAPTABLE_HPP_INCLUDED +#define BOOST_BIND_MAKE_ADAPTABLE_HPP_INCLUDED + +// +// make_adaptable.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +namespace boost +{ + +namespace _bi +{ + +template class af0 +{ +public: + + typedef R result_type; + + explicit af0(F f): f_(f) + { + } + + result_type operator()() + { + return f_(); + } + + result_type operator()() const + { + return f_(); + } + +private: + + F f_; +}; + +template class af1 +{ +public: + + typedef R result_type; + typedef A1 argument_type; + typedef A1 arg1_type; + + explicit af1(F f): f_(f) + { + } + + result_type operator()(A1 a1) + { + return f_(a1); + } + + result_type operator()(A1 a1) const + { + return f_(a1); + } + +private: + + F f_; +}; + +template class af2 +{ +public: + + typedef R result_type; + typedef A1 first_argument_type; + typedef A2 second_argument_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + + explicit af2(F f): f_(f) + { + } + + result_type operator()(A1 a1, A2 a2) + { + return f_(a1, a2); + } + + result_type operator()(A1 a1, A2 a2) const + { + return f_(a1, a2); + } + +private: + + F f_; +}; + +template class af3 +{ +public: + + typedef R result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + + explicit af3(F f): f_(f) + { + } + + result_type operator()(A1 a1, A2 a2, A3 a3) + { + return f_(a1, a2, a3); + } + + result_type operator()(A1 a1, A2 a2, A3 a3) const + { + return f_(a1, a2, a3); + } + +private: + + F f_; +}; + +template class af4 +{ +public: + + typedef R result_type; + typedef A1 arg1_type; + typedef A2 arg2_type; + typedef A3 arg3_type; + typedef A4 arg4_type; + + explicit af4(F f): f_(f) + { + } + + result_type operator()(A1 a1, A2 a2, A3 a3, A4 a4) + { + return f_(a1, a2, a3, a4); + } + + result_type operator()(A1 a1, A2 a2, A3 a3, A4 a4) const + { + return f_(a1, a2, a3, a4); + } + +private: + + F f_; +}; + +} // namespace _bi + +template _bi::af0 make_adaptable(F f) +{ + return _bi::af0(f); +} + +template _bi::af1 make_adaptable(F f) +{ + return _bi::af1(f); +} + +template _bi::af2 make_adaptable(F f) +{ + return _bi::af2(f); +} + +template _bi::af3 make_adaptable(F f) +{ + return _bi::af3(f); +} + +template _bi::af4 make_adaptable(F f) +{ + return _bi::af4(f); +} + +} // namespace boost + +#endif // #ifndef BOOST_BIND_MAKE_ADAPTABLE_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/mem_fn.hpp b/third-party/boost/boost/bind/mem_fn.hpp new file mode 100644 index 000000000..956e7d888 --- /dev/null +++ b/third-party/boost/boost/bind/mem_fn.hpp @@ -0,0 +1,389 @@ +#ifndef BOOST_BIND_MEM_FN_HPP_INCLUDED +#define BOOST_BIND_MEM_FN_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// mem_fn.hpp - a generalization of std::mem_fun[_ref] +// +// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2001 David Abrahams +// Copyright (c) 2003-2005 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/mem_fn.html for documentation. +// + +#include +#include +#include + +namespace boost +{ + +#if defined(BOOST_NO_VOID_RETURNS) + +#define BOOST_MEM_FN_CLASS_F , class F +#define BOOST_MEM_FN_TYPEDEF(X) + +namespace _mfi // mem_fun_impl +{ + +template struct mf +{ + +#define BOOST_MEM_FN_RETURN return + +#define BOOST_MEM_FN_NAME(X) inner_##X +#define BOOST_MEM_FN_CC + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_cdecl +#define BOOST_MEM_FN_CC __cdecl + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_stdcall +#define BOOST_MEM_FN_CC __stdcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_fastcall +#define BOOST_MEM_FN_CC __fastcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#undef BOOST_MEM_FN_RETURN + +}; // struct mf + +template<> struct mf +{ + +#define BOOST_MEM_FN_RETURN + +#define BOOST_MEM_FN_NAME(X) inner_##X +#define BOOST_MEM_FN_CC + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_cdecl +#define BOOST_MEM_FN_CC __cdecl + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_stdcall +#define BOOST_MEM_FN_CC __stdcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_MEM_FN_NAME(X) inner_##X##_fastcall +#define BOOST_MEM_FN_CC __fastcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#undef BOOST_MEM_FN_RETURN + +}; // struct mf + +#undef BOOST_MEM_FN_CLASS_F +#undef BOOST_MEM_FN_TYPEDEF_F + +#define BOOST_MEM_FN_NAME(X) X +#define BOOST_MEM_FN_NAME2(X) inner_##X +#define BOOST_MEM_FN_CC + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_NAME2 +#undef BOOST_MEM_FN_CC + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_MEM_FN_NAME(X) X##_cdecl +#define BOOST_MEM_FN_NAME2(X) inner_##X##_cdecl +#define BOOST_MEM_FN_CC __cdecl + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_NAME2 +#undef BOOST_MEM_FN_CC + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_MEM_FN_NAME(X) X##_stdcall +#define BOOST_MEM_FN_NAME2(X) inner_##X##_stdcall +#define BOOST_MEM_FN_CC __stdcall + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_NAME2 +#undef BOOST_MEM_FN_CC + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_MEM_FN_NAME(X) X##_fastcall +#define BOOST_MEM_FN_NAME2(X) inner_##X##_fastcall +#define BOOST_MEM_FN_CC __fastcall + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_NAME2 +#undef BOOST_MEM_FN_CC + +#endif + +} // namespace _mfi + +#else // #ifdef BOOST_NO_VOID_RETURNS + +#define BOOST_MEM_FN_CLASS_F +#define BOOST_MEM_FN_TYPEDEF(X) typedef X; + +namespace _mfi +{ + +#define BOOST_MEM_FN_RETURN return + +#define BOOST_MEM_FN_NAME(X) X +#define BOOST_MEM_FN_CC + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_MEM_FN_NAME(X) X##_cdecl +#define BOOST_MEM_FN_CC __cdecl + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_MEM_FN_NAME(X) X##_stdcall +#define BOOST_MEM_FN_CC __stdcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_MEM_FN_NAME(X) X##_fastcall +#define BOOST_MEM_FN_CC __fastcall + +#include + +#undef BOOST_MEM_FN_CC +#undef BOOST_MEM_FN_NAME + +#endif + +#undef BOOST_MEM_FN_RETURN + +} // namespace _mfi + +#undef BOOST_MEM_FN_CLASS_F +#undef BOOST_MEM_FN_TYPEDEF + +#endif // #ifdef BOOST_NO_VOID_RETURNS + +#define BOOST_MEM_FN_NAME(X) X +#define BOOST_MEM_FN_CC + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_CC + +#ifdef BOOST_MEM_FN_ENABLE_CDECL + +#define BOOST_MEM_FN_NAME(X) X##_cdecl +#define BOOST_MEM_FN_CC __cdecl + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_CC + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_STDCALL + +#define BOOST_MEM_FN_NAME(X) X##_stdcall +#define BOOST_MEM_FN_CC __stdcall + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_CC + +#endif + +#ifdef BOOST_MEM_FN_ENABLE_FASTCALL + +#define BOOST_MEM_FN_NAME(X) X##_fastcall +#define BOOST_MEM_FN_CC __fastcall + +#include + +#undef BOOST_MEM_FN_NAME +#undef BOOST_MEM_FN_CC + +#endif + +// data member support + +namespace _mfi +{ + +template class dm +{ +public: + + typedef R const & result_type; + typedef T const * argument_type; + +private: + + typedef R (T::*F); + F f_; + + template R const & call(U & u, T const *) const + { + return (u.*f_); + } + + template R const & call(U & u, void const *) const + { + return (get_pointer(u)->*f_); + } + +public: + + explicit dm(F f): f_(f) {} + + R & operator()(T * p) const + { + return (p->*f_); + } + + R const & operator()(T const * p) const + { + return (p->*f_); + } + + template R const & operator()(U const & u) const + { + return call(u, &u); + } + +#if !BOOST_WORKAROUND(BOOST_MSVC, <= 1300) && !BOOST_WORKAROUND(__MWERKS__, < 0x3200) + + R & operator()(T & t) const + { + return (t.*f_); + } + + R const & operator()(T const & t) const + { + return (t.*f_); + } + +#endif + + bool operator==(dm const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(dm const & rhs) const + { + return f_ != rhs.f_; + } +}; + +} // namespace _mfi + +template _mfi::dm mem_fn(R T::*f) +{ + return _mfi::dm(f); +} + +} // namespace boost + +#endif // #ifndef BOOST_BIND_MEM_FN_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/mem_fn_cc.hpp b/third-party/boost/boost/bind/mem_fn_cc.hpp new file mode 100644 index 000000000..8b6ea0ba1 --- /dev/null +++ b/third-party/boost/boost/bind/mem_fn_cc.hpp @@ -0,0 +1,103 @@ +// +// bind/mem_fn_cc.hpp - support for different calling conventions +// +// Do not include this header directly. +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/mem_fn.html for documentation. +// + +template _mfi::BOOST_MEM_FN_NAME(mf0) mem_fn(R (BOOST_MEM_FN_CC T::*f) ()) +{ + return _mfi::BOOST_MEM_FN_NAME(mf0)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf0) mem_fn(R (BOOST_MEM_FN_CC T::*f) () const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf0)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf1) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf1)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf1) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf1)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf2) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf2)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf2) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf2)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf3) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf3)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf3) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf3)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf4) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf4)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf4) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf4)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf5) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf5)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf5) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf5)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf6) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf6)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf6) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf6)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf7) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6, A7)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf7)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf7) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6, A7) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf7)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(mf8) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6, A7, A8)) +{ + return _mfi::BOOST_MEM_FN_NAME(mf8)(f); +} + +template _mfi::BOOST_MEM_FN_NAME(cmf8) mem_fn(R (BOOST_MEM_FN_CC T::*f) (A1, A2, A3, A4, A5, A6, A7, A8) const) +{ + return _mfi::BOOST_MEM_FN_NAME(cmf8)(f); +} diff --git a/third-party/boost/boost/bind/mem_fn_template.hpp b/third-party/boost/boost/bind/mem_fn_template.hpp new file mode 100644 index 000000000..b26d585db --- /dev/null +++ b/third-party/boost/boost/bind/mem_fn_template.hpp @@ -0,0 +1,1047 @@ +// +// bind/mem_fn_template.hpp +// +// Do not include this header directly +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/mem_fn.html for documentation. +// + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) +# define BOOST_MEM_FN_ENABLE_CONST_OVERLOADS +#endif + +// mf0 + +template class BOOST_MEM_FN_NAME(mf0) +{ +public: + + typedef R result_type; + typedef T * argument_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) ()) + F f_; + + template R call(U & u, T const *) const + { + BOOST_MEM_FN_RETURN (u.*f_)(); + } + + template R call(U & u, void const *) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf0)(F f): f_(f) {} + + R operator()(T * p) const + { + BOOST_MEM_FN_RETURN (p->*f_)(); + } + + template R operator()(U & u) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p); + } + +#endif + + R operator()(T & t) const + { + BOOST_MEM_FN_RETURN (t.*f_)(); + } + + bool operator==(BOOST_MEM_FN_NAME(mf0) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf0) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf0 + +template class BOOST_MEM_FN_NAME(cmf0) +{ +public: + + typedef R result_type; + typedef T const * argument_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) () const) + F f_; + + template R call(U & u, T const *) const + { + BOOST_MEM_FN_RETURN (u.*f_)(); + } + + template R call(U & u, void const *) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf0)(F f): f_(f) {} + + template R operator()(U const & u) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p); + } + + R operator()(T const & t) const + { + BOOST_MEM_FN_RETURN (t.*f_)(); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf0) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf0) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf1 + +template class BOOST_MEM_FN_NAME(mf1) +{ +public: + + typedef R result_type; + typedef T * first_argument_type; + typedef A1 second_argument_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1)) + F f_; + + template R call(U & u, T const *, B1 & b1) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1); + } + + template R call(U & u, void const *, B1 & b1) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf1)(F f): f_(f) {} + + R operator()(T * p, A1 a1) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1); + } + + template R operator()(U & u, A1 a1) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1); + } + +#endif + + R operator()(T & t, A1 a1) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1); + } + + bool operator==(BOOST_MEM_FN_NAME(mf1) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf1) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf1 + +template class BOOST_MEM_FN_NAME(cmf1) +{ +public: + + typedef R result_type; + typedef T const * first_argument_type; + typedef A1 second_argument_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1) const) + F f_; + + template R call(U & u, T const *, B1 & b1) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1); + } + + template R call(U & u, void const *, B1 & b1) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf1)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1); + } + + R operator()(T const & t, A1 a1) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf1) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf1) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf2 + +template class BOOST_MEM_FN_NAME(mf2) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf2)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2); + } + + template R operator()(U & u, A1 a1, A2 a2) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2); + } + + bool operator==(BOOST_MEM_FN_NAME(mf2) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf2) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf2 + +template class BOOST_MEM_FN_NAME(cmf2) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf2)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2); + } + + R operator()(T const & t, A1 a1, A2 a2) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf2) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf2) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf3 + +template class BOOST_MEM_FN_NAME(mf3) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf3)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3); + } + + bool operator==(BOOST_MEM_FN_NAME(mf3) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf3) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf3 + +template class BOOST_MEM_FN_NAME(cmf3) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf3)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf3) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf3) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf4 + +template class BOOST_MEM_FN_NAME(mf4) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf4)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3, A4 a4) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3, A4 a4) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3, A4 a4) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4); + } + + bool operator==(BOOST_MEM_FN_NAME(mf4) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf4) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf4 + +template class BOOST_MEM_FN_NAME(cmf4) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf4)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3, A4 a4) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf4) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf4) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf5 + +template class BOOST_MEM_FN_NAME(mf5) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf5)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4, a5); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5); + } + + bool operator==(BOOST_MEM_FN_NAME(mf5) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf5) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf5 + +template class BOOST_MEM_FN_NAME(cmf5) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf5)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf5) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf5) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf6 + +template class BOOST_MEM_FN_NAME(mf6) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf6)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4, a5, a6); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6); + } + + bool operator==(BOOST_MEM_FN_NAME(mf6) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf6) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf6 + +template class BOOST_MEM_FN_NAME(cmf6) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf6)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf6) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf6) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf7 + +template class BOOST_MEM_FN_NAME(mf7) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6, b7); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6, b7); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf7)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4, a5, a6, a7); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6, a7); + } + + bool operator==(BOOST_MEM_FN_NAME(mf7) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf7) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf7 + +template class BOOST_MEM_FN_NAME(cmf7) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6, b7); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6, b7); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf7)(F f): f_(f) {} + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6, a7); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf7) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf7) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// mf8 + +template class BOOST_MEM_FN_NAME(mf8) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7, A8)) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7, B8 & b8) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6, b7, b8); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7, B8 & b8) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6, b7, b8); + } + +public: + + explicit BOOST_MEM_FN_NAME(mf8)(F f): f_(f) {} + + R operator()(T * p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + template R operator()(U & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7, a8); + } + +#ifdef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7, a8); + } + +#endif + + R operator()(T & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + bool operator==(BOOST_MEM_FN_NAME(mf8) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(mf8) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +// cmf8 + +template class BOOST_MEM_FN_NAME(cmf8) +{ +public: + + typedef R result_type; + +private: + + BOOST_MEM_FN_TYPEDEF(R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7, A8) const) + F f_; + + template R call(U & u, T const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7, B8 & b8) const + { + BOOST_MEM_FN_RETURN (u.*f_)(b1, b2, b3, b4, b5, b6, b7, b8); + } + + template R call(U & u, void const *, B1 & b1, B2 & b2, B3 & b3, B4 & b4, B5 & b5, B6 & b6, B7 & b7, B8 & b8) const + { + BOOST_MEM_FN_RETURN (get_pointer(u)->*f_)(b1, b2, b3, b4, b5, b6, b7, b8); + } + +public: + + explicit BOOST_MEM_FN_NAME(cmf8)(F f): f_(f) {} + + R operator()(T const * p, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + BOOST_MEM_FN_RETURN (p->*f_)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + template R operator()(U const & u, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + U const * p = 0; + BOOST_MEM_FN_RETURN call(u, p, a1, a2, a3, a4, a5, a6, a7, a8); + } + + R operator()(T const & t, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8) const + { + BOOST_MEM_FN_RETURN (t.*f_)(a1, a2, a3, a4, a5, a6, a7, a8); + } + + bool operator==(BOOST_MEM_FN_NAME(cmf8) const & rhs) const + { + return f_ == rhs.f_; + } + + bool operator!=(BOOST_MEM_FN_NAME(cmf8) const & rhs) const + { + return f_ != rhs.f_; + } +}; + +#undef BOOST_MEM_FN_ENABLE_CONST_OVERLOADS diff --git a/third-party/boost/boost/bind/mem_fn_vw.hpp b/third-party/boost/boost/bind/mem_fn_vw.hpp new file mode 100644 index 000000000..f3fc58db0 --- /dev/null +++ b/third-party/boost/boost/bind/mem_fn_vw.hpp @@ -0,0 +1,130 @@ +// +// bind/mem_fn_vw.hpp - void return helper wrappers +// +// Do not include this header directly +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/bind/mem_fn.html for documentation. +// + +template struct BOOST_MEM_FN_NAME(mf0): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf0) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (); + explicit BOOST_MEM_FN_NAME(mf0)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf0)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf0): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf0) +{ + typedef R (BOOST_MEM_FN_CC T::*F) () const; + explicit BOOST_MEM_FN_NAME(cmf0)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf0)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf1): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf1) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1); + explicit BOOST_MEM_FN_NAME(mf1)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf1)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf1): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf1) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1) const; + explicit BOOST_MEM_FN_NAME(cmf1)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf1)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf2): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf2) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2); + explicit BOOST_MEM_FN_NAME(mf2)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf2)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf2): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf2) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2) const; + explicit BOOST_MEM_FN_NAME(cmf2)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf2)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf3): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf3) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3); + explicit BOOST_MEM_FN_NAME(mf3)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf3)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf3): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf3) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3) const; + explicit BOOST_MEM_FN_NAME(cmf3)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf3)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf4): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf4) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4); + explicit BOOST_MEM_FN_NAME(mf4)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf4)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf4): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf4) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4) const; + explicit BOOST_MEM_FN_NAME(cmf4)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf4)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf5): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf5) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5); + explicit BOOST_MEM_FN_NAME(mf5)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf5)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf5): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf5) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5) const; + explicit BOOST_MEM_FN_NAME(cmf5)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf5)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf6): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf6) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6); + explicit BOOST_MEM_FN_NAME(mf6)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf6)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf6): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf6) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6) const; + explicit BOOST_MEM_FN_NAME(cmf6)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf6)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf7): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf7) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7); + explicit BOOST_MEM_FN_NAME(mf7)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf7)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf7): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf7) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7) const; + explicit BOOST_MEM_FN_NAME(cmf7)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf7)(f) {} +}; + + +template struct BOOST_MEM_FN_NAME(mf8): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf8) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7, A8); + explicit BOOST_MEM_FN_NAME(mf8)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(mf8)(f) {} +}; + +template struct BOOST_MEM_FN_NAME(cmf8): public mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf8) +{ + typedef R (BOOST_MEM_FN_CC T::*F) (A1, A2, A3, A4, A5, A6, A7, A8) const; + explicit BOOST_MEM_FN_NAME(cmf8)(F f): mf::BOOST_NESTED_TEMPLATE BOOST_MEM_FN_NAME2(cmf8)(f) {} +}; + diff --git a/third-party/boost/boost/bind/placeholders.hpp b/third-party/boost/boost/bind/placeholders.hpp new file mode 100644 index 000000000..b819ef4c4 --- /dev/null +++ b/third-party/boost/boost/bind/placeholders.hpp @@ -0,0 +1,62 @@ +#ifndef BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED +#define BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// bind/placeholders.hpp - _N definitions +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright 2015 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +#include +#include + +namespace boost +{ + +namespace placeholders +{ + +#if defined(__BORLANDC__) || defined(__GNUC__) && (__GNUC__ < 4) + +inline boost::arg<1> _1() { return boost::arg<1>(); } +inline boost::arg<2> _2() { return boost::arg<2>(); } +inline boost::arg<3> _3() { return boost::arg<3>(); } +inline boost::arg<4> _4() { return boost::arg<4>(); } +inline boost::arg<5> _5() { return boost::arg<5>(); } +inline boost::arg<6> _6() { return boost::arg<6>(); } +inline boost::arg<7> _7() { return boost::arg<7>(); } +inline boost::arg<8> _8() { return boost::arg<8>(); } +inline boost::arg<9> _9() { return boost::arg<9>(); } + +#else + +BOOST_STATIC_CONSTEXPR boost::arg<1> _1; +BOOST_STATIC_CONSTEXPR boost::arg<2> _2; +BOOST_STATIC_CONSTEXPR boost::arg<3> _3; +BOOST_STATIC_CONSTEXPR boost::arg<4> _4; +BOOST_STATIC_CONSTEXPR boost::arg<5> _5; +BOOST_STATIC_CONSTEXPR boost::arg<6> _6; +BOOST_STATIC_CONSTEXPR boost::arg<7> _7; +BOOST_STATIC_CONSTEXPR boost::arg<8> _8; +BOOST_STATIC_CONSTEXPR boost::arg<9> _9; + +#endif + +} // namespace placeholders + +} // namespace boost + +#endif // #ifndef BOOST_BIND_PLACEHOLDERS_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/protect.hpp b/third-party/boost/boost/bind/protect.hpp new file mode 100644 index 000000000..749e158c3 --- /dev/null +++ b/third-party/boost/boost/bind/protect.hpp @@ -0,0 +1,304 @@ +#ifndef BOOST_BIND_PROTECT_HPP_INCLUDED +#define BOOST_BIND_PROTECT_HPP_INCLUDED + +// +// protect.hpp +// +// Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (c) 2009 Steven Watanabe +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include + +namespace boost +{ + +namespace _bi +{ + +template class protected_bind_t +{ +public: + + typedef typename F::result_type result_type; + + explicit protected_bind_t(F f): f_(f) + { + } + + result_type operator()() + { + return f_(); + } + + result_type operator()() const + { + return f_(); + } + + template result_type operator()(A1 & a1) + { + return f_(a1); + } + + template result_type operator()(A1 & a1) const + { + return f_(a1); + } + + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(const A1 & a1) + { + return f_(a1); + } + + template result_type operator()(const A1 & a1) const + { + return f_(a1); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2) + { + return f_(a1, a2); + } + + template result_type operator()(A1 & a1, A2 & a2) const + { + return f_(a1, a2); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 & a2) + { + return f_(a1, a2); + } + + template result_type operator()(A1 const & a1, A2 & a2) const + { + return f_(a1, a2); + } + + template result_type operator()(A1 & a1, A2 const & a2) + { + return f_(a1, a2); + } + + template result_type operator()(A1 & a1, A2 const & a2) const + { + return f_(a1, a2); + } + + template result_type operator()(A1 const & a1, A2 const & a2) + { + return f_(a1, a2); + } + + template result_type operator()(A1 const & a1, A2 const & a2) const + { + return f_(a1, a2); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3) + { + return f_(a1, a2, a3); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3) const + { + return f_(a1, a2, a3); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3) + { + return f_(a1, a2, a3); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3) const + { + return f_(a1, a2, a3); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4) + { + return f_(a1, a2, a3, a4); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4) const + { + return f_(a1, a2, a3, a4); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4) + { + return f_(a1, a2, a3, a4); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4) const + { + return f_(a1, a2, a3, a4); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) + { + return f_(a1, a2, a3, a4, a5); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5) const + { + return f_(a1, a2, a3, a4, a5); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5) + { + return f_(a1, a2, a3, a4, a5); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5) const + { + return f_(a1, a2, a3, a4, a5); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) + { + return f_(a1, a2, a3, a4, a5, a6); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6) const + { + return f_(a1, a2, a3, a4, a5, a6); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6) + { + return f_(a1, a2, a3, a4, a5, a6); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6) const + { + return f_(a1, a2, a3, a4, a5, a6); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) + { + return f_(a1, a2, a3, a4, a5, a6, a7); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7) const + { + return f_(a1, a2, a3, a4, a5, a6, a7); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7) + { + return f_(a1, a2, a3, a4, a5, a6, a7); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7) const + { + return f_(a1, a2, a3, a4, a5, a6, a7); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8) const + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8) + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8) const + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8); + } + +#endif + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + template result_type operator()(A1 & a1, A2 & a2, A3 & a3, A4 & a4, A5 & a5, A6 & a6, A7 & a7, A8 & a8, A9 & a9) const + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + +#if !defined(BOOST_NO_FUNCTION_TEMPLATE_ORDERING) \ + && !BOOST_WORKAROUND(__EDG_VERSION__, <= 238) + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9) + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + + template result_type operator()(A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9) const + { + return f_(a1, a2, a3, a4, a5, a6, a7, a8, a9); + } + +#endif + +private: + + F f_; +}; + +} // namespace _bi + +template _bi::protected_bind_t protect(F f) +{ + return _bi::protected_bind_t(f); +} + +} // namespace boost + +#endif // #ifndef BOOST_BIND_PROTECT_HPP_INCLUDED diff --git a/third-party/boost/boost/bind/storage.hpp b/third-party/boost/boost/bind/storage.hpp new file mode 100644 index 000000000..be490b0f5 --- /dev/null +++ b/third-party/boost/boost/bind/storage.hpp @@ -0,0 +1,475 @@ +#ifndef BOOST_BIND_STORAGE_HPP_INCLUDED +#define BOOST_BIND_STORAGE_HPP_INCLUDED + +// MS compatible compilers support #pragma once + +#if defined(_MSC_VER) && (_MSC_VER >= 1020) +# pragma once +#endif + +// +// bind/storage.hpp +// +// boost/bind.hpp support header, optimized storage +// +// Copyright (c) 2006 Peter Dimov +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://www.boost.org/libs/bind/bind.html for documentation. +// + +#include +#include + +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4512) // assignment operator could not be generated +#endif + +namespace boost +{ + +namespace _bi +{ + +// 1 + +template struct storage1 +{ + explicit storage1( A1 a1 ): a1_( a1 ) {} + + template void accept(V & v) const + { + BOOST_BIND_VISIT_EACH(v, a1_, 0); + } + + A1 a1_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) && !defined( __BORLANDC__ ) + +template struct storage1< boost::arg > +{ + explicit storage1( boost::arg ) {} + + template void accept(V &) const { } + + static boost::arg a1_() { return boost::arg(); } +}; + +template struct storage1< boost::arg (*) () > +{ + explicit storage1( boost::arg (*) () ) {} + + template void accept(V &) const { } + + static boost::arg a1_() { return boost::arg(); } +}; + +#endif + +// 2 + +template struct storage2: public storage1 +{ + typedef storage1 inherited; + + storage2( A1 a1, A2 a2 ): storage1( a1 ), a2_( a2 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a2_, 0); + } + + A2 a2_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage2< A1, boost::arg >: public storage1 +{ + typedef storage1 inherited; + + storage2( A1 a1, boost::arg ): storage1( a1 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a2_() { return boost::arg(); } +}; + +template struct storage2< A1, boost::arg (*) () >: public storage1 +{ + typedef storage1 inherited; + + storage2( A1 a1, boost::arg (*) () ): storage1( a1 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a2_() { return boost::arg(); } +}; + +#endif + +// 3 + +template struct storage3: public storage2< A1, A2 > +{ + typedef storage2 inherited; + + storage3( A1 a1, A2 a2, A3 a3 ): storage2( a1, a2 ), a3_( a3 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a3_, 0); + } + + A3 a3_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage3< A1, A2, boost::arg >: public storage2< A1, A2 > +{ + typedef storage2 inherited; + + storage3( A1 a1, A2 a2, boost::arg ): storage2( a1, a2 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a3_() { return boost::arg(); } +}; + +template struct storage3< A1, A2, boost::arg (*) () >: public storage2< A1, A2 > +{ + typedef storage2 inherited; + + storage3( A1 a1, A2 a2, boost::arg (*) () ): storage2( a1, a2 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a3_() { return boost::arg(); } +}; + +#endif + +// 4 + +template struct storage4: public storage3< A1, A2, A3 > +{ + typedef storage3 inherited; + + storage4( A1 a1, A2 a2, A3 a3, A4 a4 ): storage3( a1, a2, a3 ), a4_( a4 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a4_, 0); + } + + A4 a4_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage4< A1, A2, A3, boost::arg >: public storage3< A1, A2, A3 > +{ + typedef storage3 inherited; + + storage4( A1 a1, A2 a2, A3 a3, boost::arg ): storage3( a1, a2, a3 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a4_() { return boost::arg(); } +}; + +template struct storage4< A1, A2, A3, boost::arg (*) () >: public storage3< A1, A2, A3 > +{ + typedef storage3 inherited; + + storage4( A1 a1, A2 a2, A3 a3, boost::arg (*) () ): storage3( a1, a2, a3 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a4_() { return boost::arg(); } +}; + +#endif + +// 5 + +template struct storage5: public storage4< A1, A2, A3, A4 > +{ + typedef storage4 inherited; + + storage5( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5 ): storage4( a1, a2, a3, a4 ), a5_( a5 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a5_, 0); + } + + A5 a5_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage5< A1, A2, A3, A4, boost::arg >: public storage4< A1, A2, A3, A4 > +{ + typedef storage4 inherited; + + storage5( A1 a1, A2 a2, A3 a3, A4 a4, boost::arg ): storage4( a1, a2, a3, a4 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a5_() { return boost::arg(); } +}; + +template struct storage5< A1, A2, A3, A4, boost::arg (*) () >: public storage4< A1, A2, A3, A4 > +{ + typedef storage4 inherited; + + storage5( A1 a1, A2 a2, A3 a3, A4 a4, boost::arg (*) () ): storage4( a1, a2, a3, a4 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a5_() { return boost::arg(); } +}; + +#endif + +// 6 + +template struct storage6: public storage5< A1, A2, A3, A4, A5 > +{ + typedef storage5 inherited; + + storage6( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6 ): storage5( a1, a2, a3, a4, a5 ), a6_( a6 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a6_, 0); + } + + A6 a6_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage6< A1, A2, A3, A4, A5, boost::arg >: public storage5< A1, A2, A3, A4, A5 > +{ + typedef storage5 inherited; + + storage6( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, boost::arg ): storage5( a1, a2, a3, a4, a5 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a6_() { return boost::arg(); } +}; + +template struct storage6< A1, A2, A3, A4, A5, boost::arg (*) () >: public storage5< A1, A2, A3, A4, A5 > +{ + typedef storage5 inherited; + + storage6( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, boost::arg (*) () ): storage5( a1, a2, a3, a4, a5 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a6_() { return boost::arg(); } +}; + +#endif + +// 7 + +template struct storage7: public storage6< A1, A2, A3, A4, A5, A6 > +{ + typedef storage6 inherited; + + storage7( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7 ): storage6( a1, a2, a3, a4, a5, a6 ), a7_( a7 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a7_, 0); + } + + A7 a7_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage7< A1, A2, A3, A4, A5, A6, boost::arg >: public storage6< A1, A2, A3, A4, A5, A6 > +{ + typedef storage6 inherited; + + storage7( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, boost::arg ): storage6( a1, a2, a3, a4, a5, a6 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a7_() { return boost::arg(); } +}; + +template struct storage7< A1, A2, A3, A4, A5, A6, boost::arg (*) () >: public storage6< A1, A2, A3, A4, A5, A6 > +{ + typedef storage6 inherited; + + storage7( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, boost::arg (*) () ): storage6( a1, a2, a3, a4, a5, a6 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a7_() { return boost::arg(); } +}; + +#endif + +// 8 + +template struct storage8: public storage7< A1, A2, A3, A4, A5, A6, A7 > +{ + typedef storage7 inherited; + + storage8( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8 ): storage7( a1, a2, a3, a4, a5, a6, a7 ), a8_( a8 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a8_, 0); + } + + A8 a8_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage8< A1, A2, A3, A4, A5, A6, A7, boost::arg >: public storage7< A1, A2, A3, A4, A5, A6, A7 > +{ + typedef storage7 inherited; + + storage8( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, boost::arg ): storage7( a1, a2, a3, a4, a5, a6, a7 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a8_() { return boost::arg(); } +}; + +template struct storage8< A1, A2, A3, A4, A5, A6, A7, boost::arg (*) () >: public storage7< A1, A2, A3, A4, A5, A6, A7 > +{ + typedef storage7 inherited; + + storage8( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, boost::arg (*) () ): storage7( a1, a2, a3, a4, a5, a6, a7 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a8_() { return boost::arg(); } +}; + +#endif + +// 9 + +template struct storage9: public storage8< A1, A2, A3, A4, A5, A6, A7, A8 > +{ + typedef storage8 inherited; + + storage9( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9 ): storage8( a1, a2, a3, a4, a5, a6, a7, a8 ), a9_( a9 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + BOOST_BIND_VISIT_EACH(v, a9_, 0); + } + + A9 a9_; +}; + +#if !defined( BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION ) + +template struct storage9< A1, A2, A3, A4, A5, A6, A7, A8, boost::arg >: public storage8< A1, A2, A3, A4, A5, A6, A7, A8 > +{ + typedef storage8 inherited; + + storage9( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, boost::arg ): storage8( a1, a2, a3, a4, a5, a6, a7, a8 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a9_() { return boost::arg(); } +}; + +template struct storage9< A1, A2, A3, A4, A5, A6, A7, A8, boost::arg (*) () >: public storage8< A1, A2, A3, A4, A5, A6, A7, A8 > +{ + typedef storage8 inherited; + + storage9( A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, boost::arg (*) () ): storage8( a1, a2, a3, a4, a5, a6, a7, a8 ) {} + + template void accept(V & v) const + { + inherited::accept(v); + } + + static boost::arg a9_() { return boost::arg(); } +}; + +#endif + +} // namespace _bi + +} // namespace boost + +#ifdef BOOST_MSVC +# pragma warning(default: 4512) // assignment operator could not be generated +# pragma warning(pop) +#endif + +#endif // #ifndef BOOST_BIND_STORAGE_HPP_INCLUDED diff --git a/third-party/boost/boost/blank.hpp b/third-party/boost/boost/blank.hpp new file mode 100644 index 000000000..918723ca9 --- /dev/null +++ b/third-party/boost/boost/blank.hpp @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// boost blank.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_BLANK_HPP +#define BOOST_BLANK_HPP + +#include "boost/blank_fwd.hpp" + +#if !defined(BOOST_NO_IOSTREAM) +#include // for std::basic_ostream forward declare +#include "boost/detail/templated_streams.hpp" +#endif // BOOST_NO_IOSTREAM + +#include "boost/type_traits/integral_constant.hpp" +#include "boost/type_traits/is_empty.hpp" +#include "boost/type_traits/is_pod.hpp" +#include "boost/type_traits/is_stateless.hpp" + +namespace boost { + +struct blank +{ +}; + +// type traits specializations +// + +template <> +struct is_pod< blank > + : boost::true_type +{ +}; + +template <> +struct is_empty< blank > + : boost::true_type +{ +}; + +template <> +struct is_stateless< blank > + : boost::true_type +{ +}; + +// relational operators +// + +inline bool operator==(const blank&, const blank&) +{ + return true; +} + +inline bool operator<=(const blank&, const blank&) +{ + return true; +} + +inline bool operator>=(const blank&, const blank&) +{ + return true; +} + +inline bool operator!=(const blank&, const blank&) +{ + return false; +} + +inline bool operator<(const blank&, const blank&) +{ + return false; +} + +inline bool operator>(const blank&, const blank&) +{ + return false; +} + +// streaming support +// +#if !defined(BOOST_NO_IOSTREAM) + +BOOST_TEMPLATED_STREAM_TEMPLATE(E,T) +inline BOOST_TEMPLATED_STREAM(ostream, E,T)& operator<<( + BOOST_TEMPLATED_STREAM(ostream, E,T)& out + , const blank& + ) +{ + // (output nothing) + return out; +} + +#endif // BOOST_NO_IOSTREAM + +} // namespace boost + +#endif // BOOST_BLANK_HPP diff --git a/third-party/boost/boost/blank_fwd.hpp b/third-party/boost/boost/blank_fwd.hpp new file mode 100644 index 000000000..8bfe97c46 --- /dev/null +++ b/third-party/boost/boost/blank_fwd.hpp @@ -0,0 +1,22 @@ +//----------------------------------------------------------------------------- +// boost blank_fwd.hpp header file +// See http://www.boost.org for updates, documentation, and revision history. +//----------------------------------------------------------------------------- +// +// Copyright (c) 2003 +// Eric Friedman +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_BLANK_FWD_HPP +#define BOOST_BLANK_FWD_HPP + +namespace boost { + +struct blank; + +} // namespace boost + +#endif // BOOST_BLANK_FWD_HPP diff --git a/third-party/boost/boost/call_traits.hpp b/third-party/boost/boost/call_traits.hpp new file mode 100644 index 000000000..2c1328e94 --- /dev/null +++ b/third-party/boost/boost/call_traits.hpp @@ -0,0 +1,20 @@ +// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000. +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// See http://www.boost.org/libs/utility for most recent version including documentation. + +// See boost/detail/call_traits.hpp +// for full copyright notices. + +#ifndef BOOST_CALL_TRAITS_HPP +#define BOOST_CALL_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#include + +#endif // BOOST_CALL_TRAITS_HPP diff --git a/third-party/boost/boost/callable_traits.hpp b/third-party/boost/boost/callable_traits.hpp new file mode 100644 index 000000000..87f0fa622 --- /dev/null +++ b/third-party/boost/boost/callable_traits.hpp @@ -0,0 +1,47 @@ +/* + +@Copyright Barrett Adair 2015-2017 +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +*/ + +#ifndef BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP +#define BOOST_CLBL_TRTS_BOOST_CLBL_TRTS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif diff --git a/third-party/boost/boost/cast.hpp b/third-party/boost/boost/cast.hpp new file mode 100644 index 000000000..ab452bdf1 --- /dev/null +++ b/third-party/boost/boost/cast.hpp @@ -0,0 +1,20 @@ +// boost cast.hpp header file +// +// (C) Copyright Antony Polukhin 2014. +// +// Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/conversion for Documentation. + +// This is a DEPRECATED header file! +// Use or instead + +#ifndef BOOST_CAST_HPP +#define BOOST_CAST_HPP + +# include +# include + +#endif // BOOST_CAST_HPP diff --git a/third-party/boost/boost/cerrno.hpp b/third-party/boost/boost/cerrno.hpp new file mode 100644 index 000000000..57278f5ce --- /dev/null +++ b/third-party/boost/boost/cerrno.hpp @@ -0,0 +1,331 @@ +// Boost cerrno.hpp header -------------------------------------------------// + +// Copyright Beman Dawes 2005. +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/system + +#ifndef BOOST_SYSTEM_CERRNO_HPP +#define BOOST_SYSTEM_CERRNO_HPP + +#include + +// supply errno values likely to be missing, particularly on Windows + +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 9901 +#endif + +#ifndef EADDRINUSE +#define EADDRINUSE 9902 +#endif + +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL 9903 +#endif + +#ifndef EISCONN +#define EISCONN 9904 +#endif + +#ifndef EBADMSG +#define EBADMSG 9905 +#endif + +#ifndef ECONNABORTED +#define ECONNABORTED 9906 +#endif + +#ifndef EALREADY +#define EALREADY 9907 +#endif + +#ifndef ECONNREFUSED +#define ECONNREFUSED 9908 +#endif + +#ifndef ECONNRESET +#define ECONNRESET 9909 +#endif + +#ifndef EDESTADDRREQ +#define EDESTADDRREQ 9910 +#endif + +#ifndef EHOSTUNREACH +#define EHOSTUNREACH 9911 +#endif + +#ifndef EIDRM +#define EIDRM 9912 +#endif + +#ifndef EMSGSIZE +#define EMSGSIZE 9913 +#endif + +#ifndef ENETDOWN +#define ENETDOWN 9914 +#endif + +#ifndef ENETRESET +#define ENETRESET 9915 +#endif + +#ifndef ENETUNREACH +#define ENETUNREACH 9916 +#endif + +#ifndef ENOBUFS +#define ENOBUFS 9917 +#endif + +#ifndef ENOLINK +#define ENOLINK 9918 +#endif + +#ifndef ENODATA +#define ENODATA 9919 +#endif + +#ifndef ENOMSG +#define ENOMSG 9920 +#endif + +#ifndef ENOPROTOOPT +#define ENOPROTOOPT 9921 +#endif + +#ifndef ENOSR +#define ENOSR 9922 +#endif + +#ifndef ENOTSOCK +#define ENOTSOCK 9923 +#endif + +#ifndef ENOSTR +#define ENOSTR 9924 +#endif + +#ifndef ENOTCONN +#define ENOTCONN 9925 +#endif + +#ifndef ENOTSUP +#define ENOTSUP 9926 +#endif + +#ifndef ECANCELED +#define ECANCELED 9927 +#endif + +#ifndef EINPROGRESS +#define EINPROGRESS 9928 +#endif + +#ifndef EOPNOTSUPP +#define EOPNOTSUPP 9929 +#endif + +#ifndef EWOULDBLOCK +#define EWOULDBLOCK 9930 +#endif + +#ifndef EOWNERDEAD +#define EOWNERDEAD 9931 +#endif + +#ifndef EPROTO +#define EPROTO 9932 +#endif + +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT 9933 +#endif + +#ifndef ENOTRECOVERABLE +#define ENOTRECOVERABLE 9934 +#endif + +#ifndef ETIME +#define ETIME 9935 +#endif + +#ifndef ETXTBSY +#define ETXTBSY 9936 +#endif + +#ifndef ETIMEDOUT +#define ETIMEDOUT 9938 +#endif + +#ifndef ELOOP +#define ELOOP 9939 +#endif + +#ifndef EOVERFLOW +#define EOVERFLOW 9940 +#endif + +#ifndef EPROTOTYPE +#define EPROTOTYPE 9941 +#endif + +#ifndef ENOSYS +#define ENOSYS 9942 +#endif + +#ifndef EINVAL +#define EINVAL 9943 +#endif + +#ifndef ERANGE +#define ERANGE 9944 +#endif + +#ifndef EILSEQ +#define EILSEQ 9945 +#endif + +// Windows Mobile doesn't appear to define these: + +#ifndef E2BIG +#define E2BIG 9946 +#endif + +#ifndef EDOM +#define EDOM 9947 +#endif + +#ifndef EFAULT +#define EFAULT 9948 +#endif + +#ifndef EBADF +#define EBADF 9949 +#endif + +#ifndef EPIPE +#define EPIPE 9950 +#endif + +#ifndef EXDEV +#define EXDEV 9951 +#endif + +#ifndef EBUSY +#define EBUSY 9952 +#endif + +#ifndef ENOTEMPTY +#define ENOTEMPTY 9953 +#endif + +#ifndef ENOEXEC +#define ENOEXEC 9954 +#endif + +#ifndef EEXIST +#define EEXIST 9955 +#endif + +#ifndef EFBIG +#define EFBIG 9956 +#endif + +#ifndef ENAMETOOLONG +#define ENAMETOOLONG 9957 +#endif + +#ifndef ENOTTY +#define ENOTTY 9958 +#endif + +#ifndef EINTR +#define EINTR 9959 +#endif + +#ifndef ESPIPE +#define ESPIPE 9960 +#endif + +#ifndef EIO +#define EIO 9961 +#endif + +#ifndef EISDIR +#define EISDIR 9962 +#endif + +#ifndef ECHILD +#define ECHILD 9963 +#endif + +#ifndef ENOLCK +#define ENOLCK 9964 +#endif + +#ifndef ENOSPC +#define ENOSPC 9965 +#endif + +#ifndef ENXIO +#define ENXIO 9966 +#endif + +#ifndef ENODEV +#define ENODEV 9967 +#endif + +#ifndef ENOENT +#define ENOENT 9968 +#endif + +#ifndef ESRCH +#define ESRCH 9969 +#endif + +#ifndef ENOTDIR +#define ENOTDIR 9970 +#endif + +#ifndef ENOMEM +#define ENOMEM 9971 +#endif + +#ifndef EPERM +#define EPERM 9972 +#endif + +#ifndef EACCES +#define EACCES 9973 +#endif + +#ifndef EROFS +#define EROFS 9974 +#endif + +#ifndef EDEADLK +#define EDEADLK 9975 +#endif + +#ifndef EAGAIN +#define EAGAIN 9976 +#endif + +#ifndef ENFILE +#define ENFILE 9977 +#endif + +#ifndef EMFILE +#define EMFILE 9978 +#endif + +#ifndef EMLINK +#define EMLINK 9979 +#endif + +#endif // include guard diff --git a/third-party/boost/boost/checked_delete.hpp b/third-party/boost/boost/checked_delete.hpp new file mode 100644 index 000000000..fb71c789c --- /dev/null +++ b/third-party/boost/boost/checked_delete.hpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2014 Glen Fernandes + * + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#ifndef BOOST_CHECKED_DELETE_HPP +#define BOOST_CHECKED_DELETE_HPP + +// The header file at this path is deprecated; +// use boost/core/checked_delete.hpp instead. + +#include + +#endif diff --git a/third-party/boost/boost/chrono.hpp b/third-party/boost/boost/chrono.hpp new file mode 100644 index 000000000..a3a352290 --- /dev/null +++ b/third-party/boost/boost/chrono.hpp @@ -0,0 +1,20 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2010. +// Distributed under the Boost +// Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/stm for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CHRONO_HPP +#define BOOST_CHRONO_HPP + +//----------------------------------------------------------------------------- +#include +//----------------------------------------------------------------------------- + +#endif // BOOST_CHRONO_HPP diff --git a/third-party/boost/boost/chrono/ceil.hpp b/third-party/boost/boost/chrono/ceil.hpp new file mode 100644 index 000000000..7fbf9ddc2 --- /dev/null +++ b/third-party/boost/boost/chrono/ceil.hpp @@ -0,0 +1,36 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_CEIL_HPP +#define BOOST_CHRONO_CEIL_HPP + +#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds up + */ + template + To ceil(const duration& d) + { + To t = duration_cast(d); + if (t < d) + ++t; + return t; + } + + } // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/chrono.hpp b/third-party/boost/boost/chrono/chrono.hpp new file mode 100644 index 000000000..ebc29d8d4 --- /dev/null +++ b/third-party/boost/boost/chrono/chrono.hpp @@ -0,0 +1,15 @@ +// chrono.hpp --------------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_CHRONO_HPP +#define BOOST_CHRONO_CHRONO_HPP + +#include +#include +#include + +#endif // BOOST_CHRONO_CHRONO_HPP diff --git a/third-party/boost/boost/chrono/chrono_io.hpp b/third-party/boost/boost/chrono/chrono_io.hpp new file mode 100644 index 000000000..ebd18a3da --- /dev/null +++ b/third-party/boost/boost/chrono/chrono_io.hpp @@ -0,0 +1,34 @@ + +// chrono_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_CHRONO_IO_HPP +#define BOOST_CHRONO_CHRONO_IO_HPP + +#include + +//#if BOOST_CHRONO_VERSION == 2 +//#include +//#include +//#elif BOOST_CHRONO_VERSION == 1 +//#include +//#endif + +#if defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#include +#include +#else +#include +#endif + +#include + +#endif // BOOST_CHRONO_CHRONO_IO_HPP diff --git a/third-party/boost/boost/chrono/clock_string.hpp b/third-party/boost/boost/chrono/clock_string.hpp new file mode 100644 index 000000000..af025f27e --- /dev/null +++ b/third-party/boost/boost/chrono/clock_string.hpp @@ -0,0 +1,25 @@ +// +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_CLOCK_STRING_HPP +#define BOOST_CHRONO_CLOCK_STRING_HPP + +#include + +namespace boost +{ + namespace chrono + { + + template + struct clock_string; + + } // chrono + +} // boost + +#endif // BOOST_CHRONO_CLOCK_STRING_HPP diff --git a/third-party/boost/boost/chrono/config.hpp b/third-party/boost/boost/chrono/config.hpp new file mode 100644 index 000000000..1045ba3a7 --- /dev/null +++ b/third-party/boost/boost/chrono/config.hpp @@ -0,0 +1,216 @@ +// boost/chrono/config.hpp -------------------------------------------------// + +// Copyright Beman Dawes 2003, 2006, 2008 +// Copyright 2009-2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_CONFIG_HPP +#define BOOST_CHRONO_CONFIG_HPP + +#include +#include + +#if !defined BOOST_CHRONO_VERSION +#define BOOST_CHRONO_VERSION 1 +#else +#if BOOST_CHRONO_VERSION!=1 && BOOST_CHRONO_VERSION!=2 +#error "BOOST_CHRONO_VERSION must be 1 or 2" +#endif +#endif + +#if defined(BOOST_CHRONO_SOURCE) && !defined(BOOST_USE_WINDOWS_H) +#define BOOST_USE_WINDOWS_H +#endif + +#if ! defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT \ + && ! defined BOOST_CHRONO_DONT_PROVIDE_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + +# define BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + +#endif + +// BOOST_CHRONO_POSIX_API, BOOST_CHRONO_MAC_API, or BOOST_CHRONO_WINDOWS_API +// can be defined by the user to specify which API should be used + +#if defined(BOOST_CHRONO_WINDOWS_API) +# warning Boost.Chrono will use the Windows API +#elif defined(BOOST_CHRONO_MAC_API) +# warning Boost.Chrono will use the Mac API +#elif defined(BOOST_CHRONO_POSIX_API) +# warning Boost.Chrono will use the POSIX API +#endif + +# if defined( BOOST_CHRONO_WINDOWS_API ) && defined( BOOST_CHRONO_POSIX_API ) +# error both BOOST_CHRONO_WINDOWS_API and BOOST_CHRONO_POSIX_API are defined +# elif defined( BOOST_CHRONO_WINDOWS_API ) && defined( BOOST_CHRONO_MAC_API ) +# error both BOOST_CHRONO_WINDOWS_API and BOOST_CHRONO_MAC_API are defined +# elif defined( BOOST_CHRONO_MAC_API ) && defined( BOOST_CHRONO_POSIX_API ) +# error both BOOST_CHRONO_MAC_API and BOOST_CHRONO_POSIX_API are defined +# elif !defined( BOOST_CHRONO_WINDOWS_API ) && !defined( BOOST_CHRONO_MAC_API ) && !defined( BOOST_CHRONO_POSIX_API ) +# if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) +# define BOOST_CHRONO_WINDOWS_API +# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_CHRONO_MAC_API +# else +# define BOOST_CHRONO_POSIX_API +# endif +# endif + +# if defined( BOOST_CHRONO_WINDOWS_API ) +# ifndef UNDER_CE +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# endif +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# if BOOST_PLAT_WINDOWS_DESKTOP +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# endif +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif + +# if defined( BOOST_CHRONO_MAC_API ) +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif + +# if defined( BOOST_CHRONO_POSIX_API ) +# define BOOST_CHRONO_HAS_PROCESS_CLOCKS +# include //to check for CLOCK_REALTIME and CLOCK_MONOTONIC and _POSIX_THREAD_CPUTIME +# if defined(CLOCK_MONOTONIC) +# define BOOST_CHRONO_HAS_CLOCK_STEADY +# endif +# if defined(_POSIX_THREAD_CPUTIME) && !defined(BOOST_DISABLE_THREADS) +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif +# if defined(CLOCK_THREAD_CPUTIME_ID) && !defined(BOOST_DISABLE_THREADS) +# define BOOST_CHRONO_HAS_THREAD_CLOCK +# define BOOST_CHRONO_THREAD_CLOCK_IS_STEADY true +# endif +# if defined(sun) || defined(__sun) +# undef BOOST_CHRONO_HAS_THREAD_CLOCK +# undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +# endif +# if (defined(__HP_aCC) || defined(__GNUC__)) && defined(__hpux) +# undef BOOST_CHRONO_HAS_THREAD_CLOCK +# undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +# endif +# if defined(__VXWORKS__) +# undef BOOST_CHRONO_HAS_PROCESS_CLOCKS +# endif +# endif + +#if defined(BOOST_CHRONO_THREAD_DISABLED) && defined(BOOST_CHRONO_HAS_THREAD_CLOCK) +#undef BOOST_CHRONO_HAS_THREAD_CLOCK +#undef BOOST_CHRONO_THREAD_CLOCK_IS_STEADY +#endif + +// unicode support ------------------------------// + +#if defined(BOOST_NO_CXX11_UNICODE_LITERALS) || defined(BOOST_NO_CXX11_CHAR16_T) || defined(BOOST_NO_CXX11_CHAR32_T) +//~ #define BOOST_CHRONO_HAS_UNICODE_SUPPORT +#else +#define BOOST_CHRONO_HAS_UNICODE_SUPPORT 1 +#endif + +#ifndef BOOST_CHRONO_LIB_CONSTEXPR +#if defined( BOOST_NO_CXX11_NUMERIC_LIMITS ) +#define BOOST_CHRONO_LIB_CONSTEXPR +#elif defined(_LIBCPP_VERSION) && !defined(_LIBCPP_CONSTEXPR) + #define BOOST_CHRONO_LIB_CONSTEXPR +#else + #define BOOST_CHRONO_LIB_CONSTEXPR BOOST_CONSTEXPR +#endif +#endif + +#if defined( BOOST_NO_CXX11_NUMERIC_LIMITS ) +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW throw() +#else +#ifdef BOOST_NO_CXX11_NOEXCEPT +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW throw() +#else +# define BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW noexcept +#endif +#endif + +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING \ + && defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +#error "BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING && BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING defined" +#endif + +#if defined BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 \ + && defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#error "BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 && BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 defined" +#endif + +#if ! defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING \ + && ! defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +#define BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#endif + +#if (BOOST_CHRONO_VERSION == 2) +#if ! defined BOOST_CHRONO_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 \ + && ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#define BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 +#endif +#endif + +#ifdef BOOST_CHRONO_HEADER_ONLY +#define BOOST_CHRONO_INLINE inline +#define BOOST_CHRONO_STATIC inline +#define BOOST_CHRONO_DECL + +#else +#define BOOST_CHRONO_INLINE +#define BOOST_CHRONO_STATIC static + +// enable dynamic linking on Windows ---------------------------------------// + +// we need to import/export our code only if the user has specifically +// asked for it by defining either BOOST_ALL_DYN_LINK if they want all boost +// libraries to be dynamically linked, or BOOST_CHRONO_DYN_LINK +// if they want just this one to be dynamically liked: +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHRONO_DYN_LINK) +// export if this is our own source, otherwise import: +#ifdef BOOST_CHRONO_SOURCE +# define BOOST_CHRONO_DECL BOOST_SYMBOL_EXPORT +#else +# define BOOST_CHRONO_DECL BOOST_SYMBOL_IMPORT +#endif // BOOST_CHRONO_SOURCE +#endif // DYN_LINK +// +// if BOOST_CHRONO_DECL isn't defined yet define it now: +#ifndef BOOST_CHRONO_DECL +#define BOOST_CHRONO_DECL +#endif + + + +// enable automatic library variant selection ------------------------------// + +#if !defined(BOOST_CHRONO_SOURCE) && !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CHRONO_NO_LIB) +// +// Set the name of our library; this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_chrono +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CHRONO_DYN_LINK) +# define BOOST_DYN_LINK +#endif +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled +#endif // BOOST_CHRONO_HEADER_ONLY +#endif // BOOST_CHRONO_CONFIG_HPP + diff --git a/third-party/boost/boost/chrono/detail/inlined/chrono.hpp b/third-party/boost/boost/chrono/detail/inlined/chrono.hpp new file mode 100644 index 000000000..3bad546d4 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/chrono.hpp @@ -0,0 +1,46 @@ +// chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_INLINED_CHRONO_HPP +#define BOOST_CHRONO_DETAIL_INLINED_CHRONO_HPP + +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +#include +#include + +//----------------------------------------------------------------------------// +// // +// Platform-specific Implementations // +// // +//----------------------------------------------------------------------------// + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif diff --git a/third-party/boost/boost/chrono/detail/inlined/mac/chrono.hpp b/third-party/boost/boost/chrono/detail/inlined/mac/chrono.hpp new file mode 100644 index 000000000..9bf6c2bb1 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/mac/chrono.hpp @@ -0,0 +1,242 @@ +// mac/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// + +#include //for gettimeofday and timeval +#include // mach_absolute_time, mach_timebase_info_data_t +#include + +namespace boost +{ +namespace chrono +{ + +// system_clock + +// gettimeofday is the most precise "system time" available on this platform. +// It returns the number of microseconds since New Years 1970 in a struct called timeval +// which has a field for seconds and a field for microseconds. +// Fill in the timeval and then convert that to the time_point +system_clock::time_point +system_clock::now() BOOST_NOEXCEPT +{ + timeval tv; + gettimeofday(&tv, 0); + return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +system_clock::time_point +system_clock::now(system::error_code & ec) +{ + timeval tv; + gettimeofday(&tv, 0); + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(seconds(tv.tv_sec) + microseconds(tv.tv_usec)); +} +#endif +// Take advantage of the fact that on this platform time_t is nothing but +// an integral count of seconds since New Years 1970 (same epoch as timeval). +// Just get the duration out of the time_point and truncate it to seconds. +time_t +system_clock::to_time_t(const time_point& t) BOOST_NOEXCEPT +{ + return time_t(duration_cast(t.time_since_epoch()).count()); +} + +// Just turn the time_t into a count of seconds and construct a time_point with it. +system_clock::time_point +system_clock::from_time_t(time_t t) BOOST_NOEXCEPT +{ + return system_clock::time_point(seconds(t)); +} + +namespace chrono_detail +{ + +// steady_clock + +// Note, in this implementation steady_clock and high_resolution_clock +// are the same clock. They are both based on mach_absolute_time(). +// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of +// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom +// are run time constants supplied by the OS. This clock has no relationship +// to the Gregorian calendar. It's main use is as a high resolution timer. + +// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize +// for that case as an optimization. +BOOST_CHRONO_STATIC +steady_clock::rep +steady_simplified() +{ + return mach_absolute_time(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +steady_clock::rep +steady_simplified_ec(system::error_code & ec) +{ + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return mach_absolute_time(); +} +#endif + +BOOST_CHRONO_STATIC +double +compute_steady_factor(kern_return_t& err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) { + return 0; + } + return static_cast(MachInfo.numer) / MachInfo.denom; +} + +BOOST_CHRONO_STATIC +steady_clock::rep +steady_full() +{ + kern_return_t err; + const double factor = chrono_detail::compute_steady_factor(err); + if (err != 0) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return static_cast(mach_absolute_time() * factor); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +steady_clock::rep +steady_full_ec(system::error_code & ec) +{ + kern_return_t err; + const double factor = chrono_detail::compute_steady_factor(err); + if (err != 0) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + err, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return steady_clock::rep(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return static_cast(mach_absolute_time() * factor); +} +#endif + +typedef steady_clock::rep (*FP)(); +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +typedef steady_clock::rep (*FP_ec)(system::error_code &); +#endif + +BOOST_CHRONO_STATIC +FP +init_steady_clock(kern_return_t & err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) + { + return 0; + } + + if (MachInfo.numer == MachInfo.denom) + { + return &chrono_detail::steady_simplified; + } + return &chrono_detail::steady_full; +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +BOOST_CHRONO_STATIC +FP_ec +init_steady_clock_ec(kern_return_t & err) +{ + mach_timebase_info_data_t MachInfo; + err = mach_timebase_info(&MachInfo); + if ( err != 0 ) + { + return 0; + } + + if (MachInfo.numer == MachInfo.denom) + { + return &chrono_detail::steady_simplified_ec; + } + return &chrono_detail::steady_full_ec; +} +#endif +} + +steady_clock::time_point +steady_clock::now() BOOST_NOEXCEPT +{ + kern_return_t err; + chrono_detail::FP fp = chrono_detail::init_steady_clock(err); + if ( err != 0 ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + return time_point(duration(fp())); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +steady_clock::time_point +steady_clock::now(system::error_code & ec) +{ + kern_return_t err; + chrono_detail::FP_ec fp = chrono_detail::init_steady_clock_ec(err); + if ( err != 0 ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + err, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( err, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration(fp(ec))); +} +#endif +} // namespace chrono +} // namespace boost diff --git a/third-party/boost/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp b/third-party/boost/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp new file mode 100644 index 000000000..29fe86ccf --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/mac/process_cpu_clocks.hpp @@ -0,0 +1,356 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include + +#include //for gettimeofday and timeval +#include //for times +# include + +namespace boost +{ + namespace chrono + { + namespace chrono_detail + { + + inline long tick_factor() // multiplier to convert ticks + // to nanoseconds; -1 if unknown + { + long factor = 0; + if (!factor) + { + if ((factor = ::sysconf(_SC_CLK_TCK)) <= 0) + factor = -1; + else + { + BOOST_ASSERT(factor <= 1000000000l); // doesn't handle large ticks + factor = 1000000000l / factor; // compute factor + if (!factor) + factor = -1; + } + } + return factor; + } + } + + + process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT + { +#if 1 + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds(c * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +#else + clock_t c = ::clock(); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds(c * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +#endif + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_real_cpu_clock::time_point process_real_cpu_clock::now(system::error_code & ec) + { + +#if 1 + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds(c * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } +#else + clock_t c = ::clock(); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds(c * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_real_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } +#endif + + } +#endif + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_user_cpu_clock::time_point process_user_cpu_clock::now(system::error_code & ec) + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_user_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds((tm.tms_utime + tm.tms_cutime) * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_user_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + } +#endif + + process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds((tm.tms_utime + tm.tms_cutime) + * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + return time_point(nanoseconds((tm.tms_stime + tm.tms_cstime) + * factor)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_system_cpu_clock::time_point process_system_cpu_clock::now(system::error_code & ec) + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_system_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(nanoseconds((tm.tms_stime + tm.tms_cstime) * factor)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_system_cpu_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + } +#endif + + process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT + { + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + time_point::rep + r(c * factor, (tm.tms_utime + tm.tms_cutime) * factor, (tm.tms_stime + + tm.tms_cstime) * factor); + return time_point(duration(r)); + } else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + process_cpu_clock::time_point process_cpu_clock::now(system::error_code & ec) + { + + tms tm; + clock_t c = ::times(&tm); + if (c == clock_t(-1)) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } else + { + long factor = chrono_detail::tick_factor(); + if (factor != -1) + { + time_point::rep + r(c * factor, (tm.tms_utime + tm.tms_cutime) * factor, (tm.tms_stime + + tm.tms_cstime) * factor); + return time_point(duration(r)); + } else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception(system::system_error(errno, ::boost::system::system_category(), "chrono::process_clock")); + } else + { + ec.assign(errno, ::boost::system::system_category()); + return time_point(); + } + } + } + + } +#endif + + } +} diff --git a/third-party/boost/boost/chrono/detail/inlined/mac/thread_clock.hpp b/third-party/boost/boost/chrono/detail/inlined/mac/thread_clock.hpp new file mode 100644 index 000000000..74b820ace --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/mac/thread_clock.hpp @@ -0,0 +1,92 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009-2011 +// Copyright Christopher Brown 2013 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include +#include + +# include +# include + +namespace boost { namespace chrono { + + thread_clock::time_point thread_clock::now( ) BOOST_NOEXCEPT + { + // get the thread port (borrowing pthread's reference) + mach_port_t port = pthread_mach_thread_np(pthread_self()); + + // get the thread info + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + if ( thread_info(port, THREAD_BASIC_INFO, (thread_info_t)&info, &count) != KERN_SUCCESS ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + + // convert to nanoseconds + duration user = duration( + static_cast( info.user_time.seconds ) * 1000000000 + + static_cast(info.user_time.microseconds ) * 1000); + + duration system = duration( + static_cast( info.system_time.seconds ) * 1000000000 + + static_cast( info.system_time.microseconds ) * 1000); + + return time_point( user + system ); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + thread_clock::time_point thread_clock::now( system::error_code & ec ) + { + // get the thread port (borrowing pthread's reference) + mach_port_t port = pthread_mach_thread_np(pthread_self()); + + // get the thread info + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + if ( thread_info(port, THREAD_BASIC_INFO, (thread_info_t)&info, &count) != KERN_SUCCESS ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + EINVAL, + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + + // convert to nanoseconds + duration user = duration( + static_cast( info.user_time.seconds ) * 1000000000 + + static_cast(info.user_time.microseconds ) * 1000); + + duration system = duration( + static_cast( info.system_time.seconds ) * 1000000000 + + static_cast( info.system_time.microseconds ) * 1000); + + return time_point( user + system ); + } +#endif +} } diff --git a/third-party/boost/boost/chrono/detail/inlined/posix/chrono.hpp b/third-party/boost/boost/chrono/detail/inlined/posix/chrono.hpp new file mode 100644 index 000000000..8baac39f3 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/posix/chrono.hpp @@ -0,0 +1,141 @@ +// posix/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// + +#include // for clock_gettime +#include +#include + +namespace boost +{ +namespace chrono +{ + + system_clock::time_point system_clock::now() BOOST_NOEXCEPT + { + timespec ts; + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + system_clock::time_point system_clock::now(system::error_code & ec) + { + timespec ts; + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::system_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } +#endif + + std::time_t system_clock::to_time_t(const system_clock::time_point& t) BOOST_NOEXCEPT + { + return static_cast( t.time_since_epoch().count() / 1000000000 ); + } + + system_clock::time_point system_clock::from_time_t(std::time_t t) BOOST_NOEXCEPT + { + return time_point(duration(static_cast(t) * 1000000000)); + } + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + + steady_clock::time_point steady_clock::now() BOOST_NOEXCEPT + { + timespec ts; +#if BOOST_OS_CYGWIN + // lack of thread safety in high resolution timer initialization + // can lead to a timespec of zero without an error; was reported + // to the cygwin mailing list and can be removed once fixed + do + { +#endif + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } +#if BOOST_OS_CYGWIN + } while (ts.tv_sec == 0 && ts.tv_nsec == 0); +#endif + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + steady_clock::time_point steady_clock::now(system::error_code & ec) + { + timespec ts; +#if BOOST_OS_CYGWIN + // lack of thread safety in high resolution timer initialization + // can lead to a timespec of zero without an error; was reported + // to the cygwin mailing list and can be removed once fixed + do + { +#endif + if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) ) + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } +#if BOOST_OS_CYGWIN + } while (ts.tv_sec == 0 && ts.tv_nsec == 0); +#endif + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + } +#endif +#endif + +} // namespace chrono +} // namespace boost + + diff --git a/third-party/boost/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp b/third-party/boost/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp new file mode 100644 index 000000000..f9a9e1293 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/posix/process_cpu_clocks.hpp @@ -0,0 +1,354 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include + +#include +#include +#include // for clock_gettime + + +namespace boost { namespace chrono { +namespace chrono_detail +{ + inline nanoseconds::rep tick_factor() // multiplier to convert ticks + // to nanoseconds; -1 if unknown + { + long factor = 0; + if ( !factor ) + { + if ( (factor = ::sysconf( _SC_CLK_TCK )) <= 0 ) + factor = -1; + else + { + BOOST_ASSERT( factor <= 1000000000l ); // doesn't handle large ticks + factor = 1000000000l / factor; // compute factor + if ( !factor ) factor = -1; + } + } + return factor; + } +} + +process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds(c*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_real_cpu_clock::time_point process_real_cpu_clock::now( + system::error_code & ec) +{ + + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds(c*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_user_cpu_clock::time_point process_user_cpu_clock::now( + system::error_code & ec) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds((tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + return time_point( + nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor())); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + } +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_system_cpu_clock::time_point process_system_cpu_clock::now( + system::error_code & ec) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point( + nanoseconds((tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor())); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } +} +#endif + +process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + else + { + nanoseconds::rep factor = chrono_detail::tick_factor(); + if ( factor != -1 ) + { + time_point::rep r( + c*factor, + (tm.tms_utime + tm.tms_cutime)*factor, + (tm.tms_stime + tm.tms_cstime)*factor); + return time_point(duration(r)); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + } + return time_point(); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_cpu_clock::time_point process_cpu_clock::now( + system::error_code & ec ) +{ + tms tm; + clock_t c = ::times( &tm ); + if ( c == clock_t(-1) ) // error + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + else + { + if ( chrono_detail::tick_factor() != -1 ) + { + time_point::rep r( + c*chrono_detail::tick_factor(), + (tm.tms_utime + tm.tms_cutime)*chrono_detail::tick_factor(), + (tm.tms_stime + tm.tms_cstime)*chrono_detail::tick_factor()); + return time_point(duration(r)); + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + } + +} +#endif + +} } diff --git a/third-party/boost/boost/chrono/detail/inlined/posix/thread_clock.hpp b/third-party/boost/boost/chrono/detail/inlined/posix/thread_clock.hpp new file mode 100644 index 000000000..a2a2d9cf6 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/posix/thread_clock.hpp @@ -0,0 +1,92 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright Vicente J. Botet Escriba 2009-2011 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// + +#include +#include +#include +#include + +#if !defined(__VXWORKS__) +# include +#endif +# include +# include + +namespace boost { namespace chrono { + + thread_clock::time_point thread_clock::now( ) BOOST_NOEXCEPT + { + struct timespec ts; +#if defined CLOCK_THREAD_CPUTIME_ID + // get the timespec associated to the thread clock + if ( ::clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ) ) +#else + // get the current thread + pthread_t pth=pthread_self(); + // get the clock_id associated to the current thread + clockid_t clock_id; + pthread_getcpuclockid(pth, &clock_id); + // get the timespec associated to the thread clock + if ( ::clock_gettime( clock_id, &ts ) ) +#endif + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + + // transform to nanoseconds + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + thread_clock::time_point thread_clock::now( system::error_code & ec ) + { + struct timespec ts; +#if defined CLOCK_THREAD_CPUTIME_ID + // get the timespec associated to the thread clock + if ( ::clock_gettime( CLOCK_THREAD_CPUTIME_ID, &ts ) ) +#else + // get the current thread + pthread_t pth=pthread_self(); + // get the clock_id associated to the current thread + clockid_t clock_id; + pthread_getcpuclockid(pth, &clock_id); + // get the timespec associated to the thread clock + if ( ::clock_gettime( clock_id, &ts ) ) +#endif + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( errno, ::boost::system::system_category() ); + return time_point(); + } + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + // transform to nanoseconds + return time_point(duration( + static_cast( ts.tv_sec ) * 1000000000 + ts.tv_nsec)); + + } +#endif +} } diff --git a/third-party/boost/boost/chrono/detail/inlined/process_cpu_clocks.hpp b/third-party/boost/boost/chrono/detail/inlined/process_cpu_clocks.hpp new file mode 100644 index 000000000..fad60361a --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/process_cpu_clocks.hpp @@ -0,0 +1,46 @@ +// boost process_cpu_clocks.cpp -----------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_PROCESS_CPU_CLOCKS_HPP +#define BOOST_CHRONO_DETAIL_INLINED_PROCESS_CPU_CLOCKS_HPP + + +#include +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + +#include +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif + +#endif diff --git a/third-party/boost/boost/chrono/detail/inlined/thread_clock.hpp b/third-party/boost/boost/chrono/detail/inlined/thread_clock.hpp new file mode 100644 index 000000000..e4f8317ec --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/thread_clock.hpp @@ -0,0 +1,46 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_THREAD_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_THREAD_CLOCK_HPP + +#include +#include +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) +#include +#include +#if defined BOOST_CHRONO_PROVIDE_HYBRID_ERROR_HANDLING +#include +#endif +#include +#include + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#if defined(BOOST_CHRONO_WINDOWS_API) +#include + +//----------------------------------------------------------------------------// +// Mac // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_MAC_API) +#include + +//----------------------------------------------------------------------------// +// POSIX // +//----------------------------------------------------------------------------// +#elif defined(BOOST_CHRONO_POSIX_API) +#include + +#endif // POSIX + +#endif +#endif diff --git a/third-party/boost/boost/chrono/detail/inlined/win/chrono.hpp b/third-party/boost/boost/chrono/detail/inlined/win/chrono.hpp new file mode 100644 index 000000000..570dc02a1 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/win/chrono.hpp @@ -0,0 +1,150 @@ +// win/chrono.cpp --------------------------------------------------------------// + +// Copyright Beman Dawes 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +//----------------------------------------------------------------------------// +// Windows // +//----------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_CHRONO_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_CHRONO_HPP + +#include +#include +#include +#include + +namespace boost +{ +namespace chrono +{ +namespace chrono_detail +{ + + BOOST_CHRONO_INLINE double get_nanosecs_per_tic() BOOST_NOEXCEPT + { + boost::winapi::LARGE_INTEGER_ freq; + if ( !boost::winapi::QueryPerformanceFrequency( &freq ) ) + return 0.0L; + return double(1000000000.0L / freq.QuadPart); + } + +} + + steady_clock::time_point steady_clock::now() BOOST_NOEXCEPT + { + double nanosecs_per_tic = chrono_detail::get_nanosecs_per_tic(); + + boost::winapi::LARGE_INTEGER_ pcount; + if ( nanosecs_per_tic <= 0.0L ) + { + BOOST_ASSERT(0 && "Boost::Chrono - get_nanosecs_per_tic Internal Error"); + return steady_clock::time_point(); + } + unsigned times=0; + while ( ! boost::winapi::QueryPerformanceCounter( &pcount ) ) + { + if ( ++times > 3 ) + { + BOOST_ASSERT(0 && "Boost::Chrono - QueryPerformanceCounter Internal Error"); + return steady_clock::time_point(); + } + } + + return steady_clock::time_point(steady_clock::duration( + static_cast((nanosecs_per_tic) * pcount.QuadPart))); + } + + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + steady_clock::time_point steady_clock::now( system::error_code & ec ) + { + double nanosecs_per_tic = chrono_detail::get_nanosecs_per_tic(); + + boost::winapi::LARGE_INTEGER_ pcount; + if ( (nanosecs_per_tic <= 0.0L) + || (!boost::winapi::QueryPerformanceCounter( &pcount )) ) + { + boost::winapi::DWORD_ cause = + ((nanosecs_per_tic <= 0.0L) + ? ERROR_NOT_SUPPORTED + : boost::winapi::GetLastError()); + if (::boost::chrono::is_throws(ec)) { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::steady_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return steady_clock::time_point(duration(0)); + } + } + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + static_cast(nanosecs_per_tic * pcount.QuadPart))); + } +#endif + + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::now() BOOST_NOEXCEPT + { + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime( &ft ); // never fails + return system_clock::time_point( + system_clock::duration( + ((static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime) + - 116444736000000000LL + //- (134775LL*864000000000LL) + ) + ); + } + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::now( system::error_code & ec ) + { + boost::winapi::FILETIME_ ft; + boost::winapi::GetSystemTimeAsFileTime( &ft ); // never fails + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return system_clock::time_point( + system_clock::duration( + ((static_cast<__int64>( ft.dwHighDateTime ) << 32) | ft.dwLowDateTime) + - 116444736000000000LL + //- (134775LL*864000000000LL) + )); + } +#endif + + BOOST_CHRONO_INLINE + std::time_t system_clock::to_time_t(const system_clock::time_point& t) BOOST_NOEXCEPT + { + __int64 temp = t.time_since_epoch().count(); + temp /= 10000000; + return static_cast( temp ); + } + + BOOST_CHRONO_INLINE + system_clock::time_point system_clock::from_time_t(std::time_t t) BOOST_NOEXCEPT + { + __int64 temp = t; + temp *= 10000000; + return time_point(duration(temp)); + } + +} // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp b/third-party/boost/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp new file mode 100644 index 000000000..a3a838a5c --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/win/process_cpu_clocks.hpp @@ -0,0 +1,281 @@ +// boost process_timer.cpp -----------------------------------------------------------// + +// Copyright Beman Dawes 1994, 2006, 2008 +// Copyright 2009-2010 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_PROCESS_CLOCK_HPP + +#include +#include +#include +#include +#include + +#include +#include +#if BOOST_PLAT_WINDOWS_DESKTOP +#include +#endif + +namespace boost +{ +namespace chrono +{ + +process_real_cpu_clock::time_point process_real_cpu_clock::now() BOOST_NOEXCEPT +{ + clock_t c = ::clock(); + if ( c == clock_t(-1) ) // error + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + } + typedef ratio_divide >::type R; + return time_point( + duration(static_cast(c)*R::num/R::den) + ); +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_real_cpu_clock::time_point process_real_cpu_clock::now( + system::error_code & ec) +{ + clock_t c = ::clock(); + if ( c == clock_t(-1) ) // error + { + boost::throw_exception( + system::system_error( + errno, + ::boost::system::system_category(), + "chrono::process_real_cpu_clock" )); + } + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + typedef ratio_divide >::type R; + return time_point( + duration(static_cast(c)*R::num/R::den) + ); +} +#endif + +#if BOOST_PLAT_WINDOWS_DESKTOP +process_user_cpu_clock::time_point process_user_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + return time_point(duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 + )); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_user_cpu_clock::time_point process_user_cpu_clock::now( + system::error_code & ec) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 + )); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_user_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif + +process_system_cpu_clock::time_point process_system_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + return time_point(duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 + )); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_system_cpu_clock::time_point process_system_cpu_clock::now( + system::error_code & ec) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 + )); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_system_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif + +process_cpu_clock::time_point process_cpu_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count() + , + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime + ) * 100, + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime + ) * 100 + ); + return time_point(duration(r)); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +process_cpu_clock::time_point process_cpu_clock::now( + system::error_code & ec ) +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetProcessTimes( + boost::detail::winapi::GetCurrentProcess(), &creation, &exit, + &system_time, &user_time ) ) + { + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + time_point::rep r(process_real_cpu_clock::now().time_since_epoch().count() + , + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime + ) * 100, + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime + ) * 100 + ); + return time_point(duration(r)); + } + else + { + boost::detail::winapi::DWORD_ cause = boost::detail::winapi::GetLastError(); + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + cause, + ::boost::system::system_category(), + "chrono::process_cpu_clock" )); + } + else + { + ec.assign( cause, ::boost::system::system_category() ); + return time_point(); + } + } + +} +#endif +#endif +} // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/detail/inlined/win/thread_clock.hpp b/third-party/boost/boost/chrono/detail/inlined/win/thread_clock.hpp new file mode 100644 index 000000000..776e5b4cd --- /dev/null +++ b/third-party/boost/boost/chrono/detail/inlined/win/thread_clock.hpp @@ -0,0 +1,103 @@ +// boost thread_clock.cpp -----------------------------------------------------------// + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/chrono for documentation. + +//--------------------------------------------------------------------------------------// +#ifndef BOOST_CHRONO_DETAIL_INLINED_WIN_THREAD_CLOCK_HPP +#define BOOST_CHRONO_DETAIL_INLINED_WIN_THREAD_CLOCK_HPP + +#include +#include +#include +#include + +#include +#include +#include + +namespace boost +{ +namespace chrono +{ + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING +thread_clock::time_point thread_clock::now( system::error_code & ec ) +{ + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetThreadTimes( + boost::detail::winapi::GetCurrentThread (), &creation, &exit, + &system_time, &user_time ) ) + { + duration user = duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 ); + + duration system = duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 ); + + if (!::boost::chrono::is_throws(ec)) + { + ec.clear(); + } + return time_point(system+user); + + } + else + { + if (::boost::chrono::is_throws(ec)) + { + boost::throw_exception( + system::system_error( + boost::detail::winapi::GetLastError(), + ::boost::system::system_category(), + "chrono::thread_clock" )); + } + else + { + ec.assign( boost::detail::winapi::GetLastError(), ::boost::system::system_category() ); + return thread_clock::time_point(duration(0)); + } + } +} +#endif + +thread_clock::time_point thread_clock::now() BOOST_NOEXCEPT +{ + + // note that Windows uses 100 nanosecond ticks for FILETIME + boost::detail::winapi::FILETIME_ creation, exit, user_time, system_time; + + if ( boost::detail::winapi::GetThreadTimes( + boost::detail::winapi::GetCurrentThread (), &creation, &exit, + &system_time, &user_time ) ) + { + duration user = duration( + ((static_cast(user_time.dwHighDateTime) << 32) + | user_time.dwLowDateTime) * 100 ); + + duration system = duration( + ((static_cast(system_time.dwHighDateTime) << 32) + | system_time.dwLowDateTime) * 100 ); + + return time_point(system+user); + } + else + { + BOOST_ASSERT(0 && "Boost::Chrono - Internal Error"); + return time_point(); + } + +} + +} // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/detail/is_evenly_divisible_by.hpp b/third-party/boost/boost/chrono/detail/is_evenly_divisible_by.hpp new file mode 100644 index 000000000..960a208a7 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/is_evenly_divisible_by.hpp @@ -0,0 +1,31 @@ +// is_evenly_divisible_by.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP +#define BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP + +#include + +#include +#include + +namespace boost { +namespace chrono { +namespace chrono_detail { + +// template +// struct is_evenly_divisible_by : public boost::mpl::bool_ < ratio_divide::type::den == 1 > +// {}; + template + struct is_evenly_divisible_by : public boost::ratio_detail::is_evenly_divisible_by + {}; + +} // namespace chrono_detail +} // namespace detail +} // namespace chrono + +#endif // BOOST_CHRONO_DETAIL_IS_EVENLY_DIVISIBLE_BY_HPP diff --git a/third-party/boost/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp b/third-party/boost/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp new file mode 100644 index 000000000..94936c8ba --- /dev/null +++ b/third-party/boost/boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp @@ -0,0 +1,54 @@ +// is_evenly_divisible_by.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP +#define BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP + +// +// We simply cannot include this header on gcc without getting copious warnings of the kind: +// +//../../../boost/chrono/detail/no_warning/signed_unsigned_cmp.hpp:37: warning: comparison between signed and unsigned integer expressions +// +// And yet there is no other reasonable implementation, so we declare this a system header +// to suppress these warnings. +// + +#if defined(__GNUC__) && (__GNUC__ >= 4) +#pragma GCC system_header +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif + +namespace boost { +namespace chrono { +namespace detail { + + template + bool lt(T t, U u) + { + return t < u; + } + + template + bool gt(T t, U u) + { + return t > u; + } + +} // namespace detail +} // namespace detail +} // namespace chrono + +#if defined __SUNPRO_CC +#pragma enable_warn +#elif defined _MSC_VER +#pragma warning(pop) +#endif + +#endif // BOOST_CHRONO_DETAIL_NO_WARNING_SIGNED_UNSIGNED_CMP_HPP diff --git a/third-party/boost/boost/chrono/detail/scan_keyword.hpp b/third-party/boost/boost/chrono/detail/scan_keyword.hpp new file mode 100644 index 000000000..aa4e2e87b --- /dev/null +++ b/third-party/boost/boost/chrono/detail/scan_keyword.hpp @@ -0,0 +1,163 @@ +// scan_keyword.hpp --------------------------------------------------------------// +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// Adaptation to Boost of the libcxx + +// Copyright 2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP +#define BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP + +#include + +#include +#include +#include +#include +#include + +namespace boost { + using movelib::unique_ptr; + +namespace chrono { +namespace chrono_detail { + +inline void free_aux(void* ptr) { free(ptr); } + +// scan_keyword +// Scans [b, e) until a match is found in the basic_strings range +// [kb, ke) or until it can be shown that there is no match in [kb, ke). +// b will be incremented (visibly), consuming CharT until a match is found +// or proved to not exist. A keyword may be "", in which will match anything. +// If one keyword is a prefix of another, and the next CharT in the input +// might match another keyword, the algorithm will attempt to find the longest +// matching keyword. If the longer matching keyword ends up not matching, then +// no keyword match is found. If no keyword match is found, ke is returned +// and failbit is set in err. +// Else an iterator pointing to the matching keyword is found. If more than +// one keyword matches, an iterator to the first matching keyword is returned. +// If on exit b == e, eofbit is set in err. +// Examples: +// Keywords: "a", "abb" +// If the input is "a", the first keyword matches and eofbit is set. +// If the input is "abc", no match is found and "ab" are consumed. + +template +ForwardIterator +scan_keyword(InputIterator& b, InputIterator e, + ForwardIterator kb, ForwardIterator ke, + std::ios_base::iostate& err + ) +{ + typedef typename std::iterator_traits::value_type CharT; + size_t nkw = std::distance(kb, ke); + const unsigned char doesnt_match = '\0'; + const unsigned char might_match = '\1'; + const unsigned char does_match = '\2'; + unsigned char statbuf[100]; + unsigned char* status = statbuf; + // Change free by free_aux to avoid + // Error: Could not find a match for boost::interprocess::unique_ptr::unique_ptr(int, extern "C" void(void*)) + unique_ptr stat_hold(0, free_aux); + if (nkw > sizeof(statbuf)) + { + status = (unsigned char*)malloc(nkw); + if (status == 0) + throw_exception(std::bad_alloc()); + stat_hold.reset(status); + } + size_t n_might_match = nkw; // At this point, any keyword might match + size_t n_does_match = 0; // but none of them definitely do + // Initialize all statuses to might_match, except for "" keywords are does_match + unsigned char* st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (!ky->empty()) + *st = might_match; + else + { + *st = does_match; + --n_might_match; + ++n_does_match; + } + } + // While there might be a match, test keywords against the next CharT + for (size_t indx = 0; b != e && n_might_match > 0; ++indx) + { + // Peek at the next CharT but don't consume it + CharT c = *b; + bool consume = false; + // For each keyword which might match, see if the indx character is c + // If a match if found, consume c + // If a match is found, and that is the last character in the keyword, + // then that keyword matches. + // If the keyword doesn't match this character, then change the keyword + // to doesn't match + st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (*st == might_match) + { + CharT kc = (*ky)[indx]; + if (c == kc) + { + consume = true; + if (ky->size() == indx+1) + { + *st = does_match; + --n_might_match; + ++n_does_match; + } + } + else + { + *st = doesnt_match; + --n_might_match; + } + } + } + // consume if we matched a character + if (consume) + { + ++b; + // If we consumed a character and there might be a matched keyword that + // was marked matched on a previous iteration, then such keywords + // which are now marked as not matching. + if (n_might_match + n_does_match > 1) + { + st = status; + for (ForwardIterator ky = kb; ky != ke; ++ky, ++st) + { + if (*st == does_match && ky->size() != indx+1) + { + *st = doesnt_match; + --n_does_match; + } + } + } + } + } + // We've exited the loop because we hit eof and/or we have no more "might matches". + if (b == e) + err |= std::ios_base::eofbit; + // Return the first matching result + for (st = status; kb != ke; ++kb, ++st) + if (*st == does_match) + break; + if (kb == ke) + err |= std::ios_base::failbit; + return kb; +} +} +} +} +#endif // BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP diff --git a/third-party/boost/boost/chrono/detail/static_assert.hpp b/third-party/boost/boost/chrono/detail/static_assert.hpp new file mode 100644 index 000000000..861519475 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/static_assert.hpp @@ -0,0 +1,30 @@ +// static_assert.hpp --------------------------------------------------------------// + +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + + +#ifndef BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP +#define BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP + +#include + +#ifndef BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) static_assert(CND,MSG) +#elif defined(BOOST_CHRONO_USES_STATIC_ASSERT) +#include +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) BOOST_STATIC_ASSERT(CND) +#elif defined(BOOST_CHRONO_USES_MPL_ASSERT) +#include +#include +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) \ + BOOST_MPL_ASSERT_MSG(boost::mpl::bool_< (CND) >::type::value, MSG, TYPES) +#else +//~ #elif defined(BOOST_CHRONO_USES_ARRAY_ASSERT) +#define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) static char BOOST_JOIN(boost_chrono_test_,__LINE__)[(CND)?1:-1] +//~ #define BOOST_CHRONO_STATIC_ASSERT(CND, MSG, TYPES) +#endif + +#endif // BOOST_CHRONO_DETAIL_STATIC_ASSERT_HPP diff --git a/third-party/boost/boost/chrono/detail/system.hpp b/third-party/boost/boost/chrono/detail/system.hpp new file mode 100644 index 000000000..3d82006a0 --- /dev/null +++ b/third-party/boost/boost/chrono/detail/system.hpp @@ -0,0 +1,20 @@ +// Copyright 2009-2010 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHRONO_DETAIL_SYSTEM_HPP +#define BOOST_CHRONO_DETAIL_SYSTEM_HPP + +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + +#include + +namespace boost { +namespace chrono { + inline bool is_throws(system::error_code & ec) { return (&ec==&boost::throws()); } +} +} + +#endif +#endif diff --git a/third-party/boost/boost/chrono/duration.hpp b/third-party/boost/boost/chrono/duration.hpp new file mode 100644 index 000000000..0a09674f1 --- /dev/null +++ b/third-party/boost/boost/chrono/duration.hpp @@ -0,0 +1,798 @@ +// duration.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + + +#ifndef BOOST_CHRONO_DURATION_HPP +#define BOOST_CHRONO_DURATION_HPP + +#include +#include + +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if !defined(BOOST_NO_CXX11_STATIC_ASSERT) || !defined(BOOST_CHRONO_USES_MPL_ASSERT) +#define BOOST_CHRONO_A_DURATION_REPRESENTATION_CAN_NOT_BE_A_DURATION "A duration representation can not be a duration" +#define BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_DURATION_MUST_BE_A_STD_RATIO "Second template parameter of duration must be a boost::ratio" +#define BOOST_CHRONO_DURATION_PERIOD_MUST_BE_POSITIVE "duration period must be positive" +#define BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_TIME_POINT_MUST_BE_A_BOOST_CHRONO_DURATION "Second template parameter of time_point must be a boost::chrono::duration" +#endif + +#ifndef BOOST_CHRONO_HEADER_ONLY +// this must occur after all of the includes and before any code appears: +#include // must be the last #include +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + template > + class duration; + + namespace detail + { + template + struct is_duration + : boost::false_type {}; + + template + struct is_duration > + : boost::true_type {}; + + template ::value> + struct duration_divide_result + { + }; + + template ::type>::value)) + && ((boost::is_convertible::type>::value)) + ) + > + struct duration_divide_imp + { + }; + + template + struct duration_divide_imp, Rep2, true> + { + typedef duration::type, Period> type; + }; + + template + struct duration_divide_result, Rep2, false> + : duration_divide_imp, Rep2> + { + }; + +/// + template ::value> + struct duration_divide_result2 + { + }; + + template ::type>::value)) + && ((boost::is_convertible::type>::value)) + ) + > + struct duration_divide_imp2 + { + }; + + template + struct duration_divide_imp2, true> + { + //typedef typename common_type::type type; + typedef double type; + }; + + template + struct duration_divide_result2, false> + : duration_divide_imp2 > + { + }; + +/// + template ::value> + struct duration_modulo_result + { + }; + + template ::type>::value + //&& + boost::is_convertible::type>::value + ) + > + struct duration_modulo_imp + { + }; + + template + struct duration_modulo_imp, Rep2, true> + { + typedef duration::type, Period> type; + }; + + template + struct duration_modulo_result, Rep2, false> + : duration_modulo_imp, Rep2> + { + }; + +} // namespace detail +} // namespace chrono + + +// common_type trait specializations + +template +struct common_type, + chrono::duration >; + + +namespace chrono { + + // customization traits + template struct treat_as_floating_point; + template struct duration_values; + + // convenience typedefs + typedef duration nanoseconds; // at least 64 bits needed + typedef duration microseconds; // at least 55 bits needed + typedef duration milliseconds; // at least 45 bits needed + typedef duration seconds; // at least 35 bits needed + typedef duration > minutes; // at least 29 bits needed + typedef duration > hours; // at least 23 bits needed + +//----------------------------------------------------------------------------// +// duration helpers // +//----------------------------------------------------------------------------// + +namespace detail +{ + + // duration_cast + + // duration_cast is the heart of this whole prototype. It can convert any + // duration to any other. It is also (implicitly) used in converting + // time_points. The conversion is always exact if possible. And it is + // always as efficient as hand written code. If different representations + // are involved, care is taken to never require implicit conversions. + // Instead static_cast is used explicitly for every required conversion. + // If there are a mixture of integral and floating point representations, + // the use of common_type ensures that the most logical "intermediate" + // representation is used. + template + struct duration_cast_aux; + + // When the two periods are the same, all that is left to do is static_cast from + // the source representation to the target representation (which may be a no-op). + // This conversion is always exact as long as the static_cast from the source + // representation to the destination representation is exact. + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + return ToDuration(static_cast(fd.count())); + } + }; + + // When the numerator of FromPeriod / ToPeriod is 1, then all we need to do is + // divide by the denominator of FromPeriod / ToPeriod. The common_type of + // the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is generally not exact because of the division (but could be + // if you get lucky on the run time value of fd.count()). + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) / static_cast(Period::den))); + } + }; + + // When the denominator of FromPeriod / ToPeriod is 1, then all we need to do is + // multiply by the numerator of FromPeriod / ToPeriod. The common_type of + // the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is always exact as long as the static_cast's involved are exact. + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) * static_cast(Period::num))); + } + }; + + // When neither the numerator or denominator of FromPeriod / ToPeriod is 1, then we need to + // multiply by the numerator and divide by the denominator of FromPeriod / ToPeriod. The + // common_type of the two representations is used for the intermediate computation before + // static_cast'ing to the destination. + // This conversion is generally not exact because of the division (but could be + // if you get lucky on the run time value of fd.count()). + template + struct duration_cast_aux + { + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + typedef typename common_type< + typename ToDuration::rep, + typename FromDuration::rep, + boost::intmax_t>::type C; + return ToDuration(static_cast( + static_cast(fd.count()) * static_cast(Period::num) + / static_cast(Period::den))); + } + }; + + template + struct duration_cast { + typedef typename ratio_divide::type Period; + typedef duration_cast_aux< + FromDuration, + ToDuration, + Period, + Period::num == 1, + Period::den == 1 + > Aux; + BOOST_CONSTEXPR ToDuration operator()(const FromDuration& fd) const + { + return Aux()(fd); + } + }; + +} // namespace detail + +//----------------------------------------------------------------------------// +// // +// 20.9.2 Time-related traits [time.traits] // +// // +//----------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +// 20.9.2.1 treat_as_floating_point [time.traits.is_fp] // +// Probably should have been treat_as_floating_point. Editor notifed. // +//----------------------------------------------------------------------------// + + // Support bidirectional (non-exact) conversions for floating point rep types + // (or user defined rep types which specialize treat_as_floating_point). + template + struct treat_as_floating_point : boost::is_floating_point {}; + +//----------------------------------------------------------------------------// +// 20.9.2.2 duration_values [time.traits.duration_values] // +//----------------------------------------------------------------------------// + +namespace detail { + template ::value> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR T lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW {return (std::numeric_limits::min) ();} + }; + + template + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR T lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW {return (std::numeric_limits::min) ();} + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR float lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max) (); + } + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR double lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max) (); + } + }; + + template <> + struct chrono_numeric_limits { + static BOOST_CHRONO_LIB_CONSTEXPR long double lowest() BOOST_CHRONO_LIB_NOEXCEPT_OR_THROW + { + return -(std::numeric_limits::max)(); + } + }; + + template + struct numeric_limits : chrono_numeric_limits::type> + {}; + +} +template +struct duration_values +{ + static BOOST_CONSTEXPR Rep zero() {return Rep(0);} + static BOOST_CHRONO_LIB_CONSTEXPR Rep max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return (std::numeric_limits::max)(); + } + + static BOOST_CHRONO_LIB_CONSTEXPR Rep min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return detail::numeric_limits::lowest(); + } +}; + +} // namespace chrono + +//----------------------------------------------------------------------------// +// 20.9.2.3 Specializations of common_type [time.traits.specializations] // +//----------------------------------------------------------------------------// + +template +struct common_type, + chrono::duration > +{ + typedef chrono::duration::type, + typename boost::ratio_gcd::type> type; +}; + + +//----------------------------------------------------------------------------// +// // +// 20.9.3 Class template duration [time.duration] // +// // +//----------------------------------------------------------------------------// + + +namespace chrono { + + template + class BOOST_SYMBOL_VISIBLE duration + { + //BOOST_CHRONO_STATIC_ASSERT(boost::is_integral::value, BOOST_CHRONO_A_DURATION_REPRESENTATION_MUST_BE_INTEGRAL, ()); + BOOST_CHRONO_STATIC_ASSERT(!boost::chrono::detail::is_duration::value, + BOOST_CHRONO_A_DURATION_REPRESENTATION_CAN_NOT_BE_A_DURATION, ()); + BOOST_CHRONO_STATIC_ASSERT(boost::ratio_detail::is_ratio::value, + BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_DURATION_MUST_BE_A_STD_RATIO, ()); + BOOST_CHRONO_STATIC_ASSERT(Period::num>0, + BOOST_CHRONO_DURATION_PERIOD_MUST_BE_POSITIVE, ()); + public: + typedef Rep rep; + typedef Period period; + private: + rep rep_; + public: + +#if defined BOOST_CHRONO_DURATION_DEFAULTS_TO_ZERO + BOOST_FORCEINLINE BOOST_CONSTEXPR + duration() : rep_(duration_values::zero()) { } +#elif defined BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + BOOST_CONSTEXPR duration() {} +#else + BOOST_CONSTEXPR duration() = default; +#endif + template + BOOST_SYMBOL_VISIBLE BOOST_FORCEINLINE BOOST_CONSTEXPR + explicit duration(const Rep2& r + , typename boost::enable_if < + mpl::and_ < + boost::is_convertible, + mpl::or_ < + treat_as_floating_point, + mpl::and_ < + mpl::not_ < treat_as_floating_point >, + mpl::not_ < treat_as_floating_point > + > + > + > + >::type* = 0 + ) : rep_(r) { } +#if defined BOOST_NO_CXX11_DEFAULTED_FUNCTIONS + duration& operator=(const duration& rhs) + { + if (&rhs != this) rep_= rhs.rep_; + return *this; + } +#else + duration& operator=(const duration& rhs) = default; +#endif + // conversions + template + BOOST_FORCEINLINE BOOST_CONSTEXPR + duration(const duration& d + , typename boost::enable_if < + mpl::or_ < + treat_as_floating_point, + mpl::and_ < + chrono_detail::is_evenly_divisible_by, + mpl::not_ < treat_as_floating_point > + > + > + >::type* = 0 + ) + : rep_(chrono::detail::duration_cast, duration>()(d).count()) {} + + // observer + + BOOST_CONSTEXPR + rep count() const {return rep_;} + + // arithmetic + + BOOST_CONSTEXPR + duration operator+() const {return duration(rep_);;} + BOOST_CONSTEXPR + duration operator-() const {return duration(-rep_);} + duration& operator++() {++rep_; return *this;} + duration operator++(int) {return duration(rep_++);} + duration& operator--() {--rep_; return *this;} + duration operator--(int) {return duration(rep_--);} + + duration& operator+=(const duration& d) + { + rep_ += d.count(); return *this; + } + duration& operator-=(const duration& d) + { + rep_ -= d.count(); return *this; + } + + duration& operator*=(const rep& rhs) {rep_ *= rhs; return *this;} + duration& operator/=(const rep& rhs) {rep_ /= rhs; return *this;} + duration& operator%=(const rep& rhs) {rep_ %= rhs; return *this;} + duration& operator%=(const duration& rhs) + { + rep_ %= rhs.count(); return *this; + } + // 20.9.3.4 duration special values [time.duration.special] + + static BOOST_CONSTEXPR duration zero() + { + return duration(duration_values::zero()); + } + static BOOST_CHRONO_LIB_CONSTEXPR duration min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return duration((duration_values::min)()); + } + static BOOST_CHRONO_LIB_CONSTEXPR duration max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return duration((duration_values::max)()); + } + }; + +//----------------------------------------------------------------------------// +// 20.9.3.5 duration non-member arithmetic [time.duration.nonmember] // +//----------------------------------------------------------------------------// + + // Duration + + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator+(const duration& lhs, + const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(common_duration(lhs).count()+common_duration(rhs).count()); + } + + // Duration - + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator-(const duration& lhs, + const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(common_duration(lhs).count()-common_duration(rhs).count()); + } + + // Duration * + + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + mpl::and_ < + boost::is_convertible::type>, + boost::is_convertible::type> + >, + duration::type, Period> + >::type + operator*(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()*static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + mpl::and_ < + boost::is_convertible::type>, + boost::is_convertible::type> + >, + duration::type, Period> + >::type + operator*(const Rep1& s, const duration& d) + { + return d * s; + } + + // Duration / + + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_divide_result< + duration, Rep2>::type + >::type + operator/(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()/static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename common_type::type + operator/(const duration& lhs, const duration& rhs) + { + typedef typename common_type, + duration >::type common_duration; + return common_duration(lhs).count() / common_duration(rhs).count(); + } + + #ifdef BOOST_CHRONO_EXTENSIONS + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_divide_result2< + Rep1, duration >::type + >::type + operator/(const Rep1& s, const duration& d) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return static_cast(s)/common_duration(d).count(); + } + #endif + // Duration % + + template + inline BOOST_CONSTEXPR + typename boost::disable_if , + typename boost::chrono::detail::duration_modulo_result< + duration, Rep2>::type + >::type + operator%(const duration& d, const Rep2& s) + { + typedef typename common_type::type common_rep; + typedef duration common_duration; + return common_duration(common_duration(d).count()%static_cast(s)); + } + + template + inline BOOST_CONSTEXPR + typename common_type, duration >::type + operator%(const duration& lhs, + const duration& rhs) { + typedef typename common_type, + duration >::type common_duration; + + return common_duration(common_duration(lhs).count()%common_duration(rhs).count()); + } + + +//----------------------------------------------------------------------------// +// 20.9.3.6 duration comparisons [time.duration.comparisons] // +//----------------------------------------------------------------------------// + +namespace detail +{ + template + struct duration_eq + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const RhsDuration& rhs) const + { + typedef typename common_type::type common_duration; + return common_duration(lhs).count() == common_duration(rhs).count(); + } + }; + + template + struct duration_eq + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const LhsDuration& rhs) const + { + return lhs.count() == rhs.count(); + } + }; + + template + struct duration_lt + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const RhsDuration& rhs) const + { + typedef typename common_type::type common_duration; + return common_duration(lhs).count() < common_duration(rhs).count(); + } + }; + + template + struct duration_lt + { + BOOST_CONSTEXPR bool operator()(const LhsDuration& lhs, const LhsDuration& rhs) const + { + return lhs.count() < rhs.count(); + } + }; + +} // namespace detail + + // Duration == + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration >()(lhs, rhs); + } + + // Duration != + + template + inline BOOST_CONSTEXPR + bool + operator!=(const duration& lhs, + const duration& rhs) + { + return !(lhs == rhs); + } + + // Duration < + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(lhs, rhs); + } + + // Duration > + + template + inline BOOST_CONSTEXPR + bool + operator> (const duration& lhs, + const duration& rhs) + { + return rhs < lhs; + } + + // Duration <= + + template + inline BOOST_CONSTEXPR + bool + operator<=(const duration& lhs, + const duration& rhs) + { + return !(rhs < lhs); + } + + // Duration >= + + template + inline BOOST_CONSTEXPR + bool + operator>=(const duration& lhs, + const duration& rhs) + { + return !(lhs < rhs); + } + +//----------------------------------------------------------------------------// +// 20.9.3.7 duration_cast [time.duration.cast] // +//----------------------------------------------------------------------------// + + // Compile-time select the most efficient algorithm for the conversion... + template + inline BOOST_CONSTEXPR + typename boost::enable_if < + boost::chrono::detail::is_duration, ToDuration>::type + duration_cast(const duration& fd) + { + return boost::chrono::detail::duration_cast< + duration, ToDuration>()(fd); + } + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#endif + +#endif // BOOST_CHRONO_DURATION_HPP diff --git a/third-party/boost/boost/chrono/floor.hpp b/third-party/boost/boost/chrono/floor.hpp new file mode 100644 index 000000000..eb85fa744 --- /dev/null +++ b/third-party/boost/boost/chrono/floor.hpp @@ -0,0 +1,36 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_FLOOR_HPP +#define BOOST_CHRONO_FLOOR_HPP + +#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds down + */ + template + To floor(const duration& d) + { + To t = duration_cast(d); + if (t>d) --t; + return t; + } + + + } // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/include.hpp b/third-party/boost/boost/chrono/include.hpp new file mode 100644 index 000000000..b58f76bef --- /dev/null +++ b/third-party/boost/boost/chrono/include.hpp @@ -0,0 +1,23 @@ + +// include +// +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_INCLUDE_HPP +#define BOOST_CHRONO_INCLUDE_HPP + +#include +#include +#include +#include +#include +#include +#include + +#endif // BOOST_CHRONO_INCLUDE_HPP diff --git a/third-party/boost/boost/chrono/io/duration_get.hpp b/third-party/boost/boost/chrono/io/duration_get.hpp new file mode 100644 index 000000000..081f07108 --- /dev/null +++ b/third-party/boost/boost/chrono/io/duration_get.hpp @@ -0,0 +1,591 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_IO_DURATION_GET_HPP +#define BOOST_CHRONO_IO_DURATION_GET_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + * Duration formatting facet for input. + */ +namespace boost +{ + namespace chrono + { + + namespace detail + { + template ::value> + struct duration_io_intermediate + { + typedef Rep type; + }; + + template + struct duration_io_intermediate + { + typedef typename mpl::if_c::value, long double, typename mpl::if_c< + is_signed::value, long long, unsigned long long>::type>::type type; + }; + + template + struct duration_io_intermediate, false> + { + typedef process_times::type> type; + }; + + template + typename enable_if , bool>::type reduce(intermediate_type& r, + unsigned long long& den, std::ios_base::iostate& err) + { + typedef typename common_type::type common_type_t; + + // Reduce r * num / den + common_type_t t = integer::gcd(common_type_t(r), common_type_t(den)); + r /= t; + den /= t; + if (den != 1) + { + // Conversion to Period is integral and not exact + err |= std::ios_base::failbit; + return false; + } + return true; + } + template + typename disable_if , bool>::type reduce(intermediate_type&, unsigned long long&, + std::ios_base::iostate&) + { + return true; + } + + } + + /** + * @c duration_get is used to parse a character sequence, extracting + * components of a duration into a class duration. + * Each get member parses a format as produced by a corresponding format specifier to time_put<>::put. + * If the sequence being parsed matches the correct format, the + * corresponding member of the class duration argument are set to the + * value used to produce the sequence; + * otherwise either an error is reported or unspecified values are assigned. + * In other words, user confirmation is required for reliable parsing of + * user-entered durations, but machine-generated formats can be parsed + * reliably. This allows parsers to be aggressive about interpreting user + * variations on standard formats. + * + * If the end iterator is reached during parsing of the get() member + * function, the member sets std::ios_base::eofbit in err. + */ + template > + class duration_get: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to scan the character buffer. + */ + typedef InputIterator iter_type; + + /** + * Construct a @c duration_get facet. + * @param refs + * @Effects Construct a @c duration_get facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + + explicit duration_get(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * Requires: [pattern,pat_end) shall be a valid range. + * + * Effects: The function starts by evaluating err = std::ios_base::goodbit. + * It then enters a loop, reading zero or more characters from s at + * each iteration. Unless otherwise specified below, the loop + * terminates when the first of the following conditions holds: + * - The expression pattern == pat_end evaluates to true. + * - The expression err == std::ios_base::goodbit evaluates to false. + * - The expression s == end evaluates to true, in which case the + * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. + * - The next element of pattern is equal to '%', followed by a conversion + * specifier character, format. + * If the number of elements in the range [pattern,pat_end) is not + * sufficient to unambiguously determine whether the conversion + * specification is complete and valid, the function evaluates + * err = std::ios_base::failbit. Otherwise, the function evaluates + * s = get_value(s, end, ios, err, r) when the conversion specification is 'v' and + * s = get_value(s, end, ios, err, rt) when the conversion specification is 'u'. + * If err == std::ios_base::goodbit holds after + * the evaluation of the expression, the function increments pattern to + * point just past the end of the conversion specification and continues + * looping. + * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in + * which case the function first increments pattern until + * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, + * then advances s until s == end || !isspace(*s, ios.getloc()) is true, + * and finally resumes looping. + * - The next character read from s matches the element pointed to by + * pattern in a case-insensitive comparison, in which case the function + * evaluates ++pattern, ++s and continues looping. Otherwise, the function + * evaluates err = std::ios_base::failbit. + * + * Once r and rt are retrieved, + * Returns: s + */ + template + iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, + duration &d, const char_type *pattern, const char_type *pat_end) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >(ios.getloc()); + return get(facet, s, end, ios, err, d, pattern, pat_end); + } + else + { + duration_units_default facet; + return get(facet, s, end, ios, err, d, pattern, pat_end); + } + } + + template + iter_type get(duration_units const&facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, duration &d, const char_type *pattern, const char_type *pat_end) const + { + + typedef typename detail::duration_io_intermediate::type intermediate_type; + intermediate_type r; + rt_ratio rt; + bool value_found = false, unit_found = false; + + const std::ctype& ct = std::use_facet >(ios.getloc()); + while (pattern != pat_end && err == std::ios_base::goodbit) + { + if (s == end) + { + err |= std::ios_base::eofbit; + break; + } + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + err |= std::ios_base::failbit; + return s; + } + char cmd = ct.narrow(*pattern, 0); + switch (cmd) + { + case 'v': + { + if (value_found) + { + err |= std::ios_base::failbit; + return s; + } + value_found = true; + s = get_value(s, end, ios, err, r); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + case 'u': + { + if (unit_found) + { + err |= std::ios_base::failbit; + return s; + } + unit_found = true; + s = get_unit(facet, s, end, ios, err, rt); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + + ++pattern; + } + else if (ct.is(std::ctype_base::space, *pattern)) + { + for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) + ; + for (; s != end && ct.is(std::ctype_base::space, *s); ++s) + ; + } + else if (ct.toupper(*s) == ct.toupper(*pattern)) + { + ++s; + ++pattern; + } + else + { + err |= std::ios_base::failbit; + return s; + } + + } + + unsigned long long num = rt.num; + unsigned long long den = rt.den; + + // r should be multiplied by (num/den) / Period + // Reduce (num/den) / Period to lowest terms + unsigned long long gcd_n1_n2 = integer::gcd(num, Period::num); + unsigned long long gcd_d1_d2 = integer::gcd(den, Period::den); + num /= gcd_n1_n2; + den /= gcd_d1_d2; + unsigned long long n2 = Period::num / gcd_n1_n2; + unsigned long long d2 = Period::den / gcd_d1_d2; + if (num > (std::numeric_limits::max)() / d2 || den + > (std::numeric_limits::max)() / n2) + { + // (num/den) / Period overflows + err |= std::ios_base::failbit; + return s; + } + num *= d2; + den *= n2; + + typedef typename common_type::type common_type_t; + + // num / den is now factor to multiply by r + if (!detail::reduce(r, den, err)) return s; + + if (chrono::detail::gt(r, ( (duration_values::max)() / num))) + { + // Conversion to Period overflowed + err |= std::ios_base::failbit; + return s; + } + common_type_t t = r * num; + t /= den; + if (t > duration_values::zero()) + { + if ( (duration_values::max)() < Rep(t)) + { + // Conversion to Period overflowed + err |= std::ios_base::failbit; + return s; + } + } + // Success! Store it. + d = duration (Rep(t)); + + return s; + } + + /** + * + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); + * @codeend + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, + duration & d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >(ios.getloc()); + std::basic_string str = facet.get_pattern(); + return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); + } + else + { + duration_units_default facet; + std::basic_string str = facet.get_pattern(); + return get(facet, s, end, ios, err, d, str.data(), str.data() + str.size()); + } + } + + /** + * + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param r a reference to the duration representation. + * @Effects As if + * @code + * return std::use_facet >(ios.getloc()).get(s, end, ios, err, r); + * @endcode + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, Rep& r) const + { + return std::use_facet >(ios.getloc()).get(s, end, ios, err, r); + } + template + iter_type get_value(iter_type s, iter_type end, std::ios_base& ios, std::ios_base::iostate& err, process_times& r) const + { + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != '{') { // mandatory '{' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.real); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != ';') { // mandatory ';' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.user); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != ';') { // mandatory ';' + err |= std::ios_base::failbit; + return s; + } + ++s; + s = std::use_facet >(ios.getloc()).get(s, end, ios, err, r.system); + if (s == end) { + err |= std::ios_base::eofbit; + return s; + } else if (*s != '}') { // mandatory '}' + err |= std::ios_base::failbit; + return s; + } + return s; + } + + /** + * + * @param s start input stream iterator + * @param e end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param rt a reference to the duration run-time ratio. + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + iter_type get_unit(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, rt_ratio &rt) const + { + if (std::has_facet >(is.getloc())) + { + return get_unit(std::use_facet >(is.getloc()), i, e, is, err, rt); + } + else + { + duration_units_default facet; + return get_unit(facet, i, e, is, err, rt); + } + } + + + iter_type get_unit(duration_units const &facet, iter_type i, iter_type e, std::ios_base& is, + std::ios_base::iostate& err, rt_ratio &rt) const + { + + if (*i == '[') + { + // parse [N/D]s or [N/D]second or [N/D]seconds format + ++i; + i = std::use_facet >(is.getloc()).get(i, e, is, err, rt.num); + if ( (err & std::ios_base::failbit) != 0) + { + return i; + } + + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + CharT x = *i++; + if (x != '/') + { + err |= std::ios_base::failbit; + return i; + } + i = std::use_facet >(is.getloc()).get(i, e, is, err, rt.den); + if ( (err & std::ios_base::failbit) != 0) + { + return i; + } + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + if (*i != ']') + { + err |= std::ios_base::failbit; + return i; + } + ++i; + if (i == e) + { + err |= std::ios_base::failbit; + return i; + } + // parse s or second or seconds + return do_get_n_d_valid_unit(facet, i, e, is, err); + } + else + { + return do_get_valid_unit(facet, i, e, is, err, rt); + } + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~duration_get() + { + } + + protected: + + /** + * Extracts the run-time ratio associated to the duration when it is given in prefix form. + * + * This is an extension point of this facet so that we can take in account other periods that can have a useful + * translation in other contexts, as e.g. days and weeks. + * + * @param facet the duration_units facet + * @param i start input stream iterator. + * @param e end input stream iterator. + * @param ios a reference to a ios_base. + * @param err the ios_base state. + * @return @c s + */ + iter_type do_get_n_d_valid_unit(duration_units const &facet, iter_type i, iter_type e, + std::ios_base&, std::ios_base::iostate& err) const + { + // parse SI name, short or long + + const string_type* units = facet.get_n_d_valid_units_start(); + const string_type* units_end = facet.get_n_d_valid_units_end(); + + const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, + //~ std::use_facet >(loc), + err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return i; + } + if (!facet.match_n_d_valid_unit(k)) + { + err |= std::ios_base::failbit; + } + return i; + } + + /** + * Extracts the run-time ratio associated to the duration when it is given in prefix form. + * + * This is an extension point of this facet so that we can take in account other periods that can have a useful + * translation in other contexts, as e.g. days and weeks. + * + * @param facet the duration_units facet + * @param i start input stream iterator. + * @param e end input stream iterator. + * @param ios a reference to a ios_base. + * @param err the ios_base state. + * @param rt a reference to the duration run-time ratio. + * @Effects + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name. + */ + iter_type do_get_valid_unit(duration_units const &facet, iter_type i, iter_type e, + std::ios_base&, std::ios_base::iostate& err, rt_ratio &rt) const + { + // parse SI name, short or long + + const string_type* units = facet.get_valid_units_start(); + const string_type* units_end = facet.get_valid_units_end(); + + err = std::ios_base::goodbit; + const string_type* k = chrono_detail::scan_keyword(i, e, units, units_end, + //~ std::use_facet >(loc), + err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return i; + } + if (!facet.match_valid_unit(k, rt)) + { + err |= std::ios_base::failbit; + } + return i; + } + }; + + /** + * Unique identifier for this type of facet. + */ + template + std::locale::id duration_get::id; + + } // chrono +} +// boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/duration_io.hpp b/third-party/boost/boost/chrono/io/duration_io.hpp new file mode 100644 index 000000000..f3aca6adf --- /dev/null +++ b/third-party/boost/boost/chrono/io/duration_io.hpp @@ -0,0 +1,295 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_DURATION_IO_HPP +#define BOOST_CHRONO_IO_DURATION_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + /** + * duration parameterized manipulator. + */ + + class duration_fmt: public manip + { + duration_style style_; + public: + + /** + * explicit manipulator constructor from a @c duration_style + */ + explicit duration_fmt(duration_style style)BOOST_NOEXCEPT + : style_(style) + {} + + /** + * Change the duration_style ios state; + */ + void operator()(std::ios_base &ios) const + + { + set_duration_style(ios, style_); + } + }; + + /** + * duration_style i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + struct duration_style_io_saver + { + + //! the type of the state to restore + typedef std::ios_base state_type; + //! the type of aspect to save + typedef duration_style aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c duration_style. + */ + explicit duration_style_io_saver(state_type &s) : + s_save_(s), a_save_(get_duration_style(s)) + { + } + + /** + * Construction from an i/o stream and a @c duration_style to restore. + * + * Stores a reference to the i/o stream and the value @c new_value @c duration_style to set. + */ + duration_style_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_duration_style(s)) + { + set_duration_style(s, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the duration_style to be restored. + */ + ~duration_style_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the duration_style to be restored. + */ + void restore() + { + set_duration_style(s_save_, a_save_); + } + + private: + duration_style_io_saver& operator=(duration_style_io_saver const& rhs) ; + + state_type& s_save_; + aspect_type a_save_; + }; + + template + struct duration_put_enabled + : integral_constant::value || is_floating_point::value + > + {}; + + + /** + * duration stream inserter + * @param os the output stream + * @param d to value to insert + * @return @c os + */ + + template + typename boost::enable_if_c< ! duration_put_enabled::value, std::basic_ostream& >::type + operator<<(std::basic_ostream& os, const duration& d) + { + std::basic_ostringstream ostr; + ostr << d.count(); + duration dd(0); + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (duration_put ().put(os, os, os.fill(), dd, ostr.str().c_str()) .failed()) + { + err = std::ios_base::badbit; + } + } + else if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), dd, ostr.str().c_str()) .failed()) + { + err = std::ios_base::badbit; + } + os.width(0); + } + } + BOOST_CATCH(...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH(...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + + } + + template + typename boost::enable_if_c< duration_put_enabled::value, std::basic_ostream& >::type + operator<<(std::basic_ostream& os, const duration& d) + { + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (duration_put ().put(os, os, os.fill(), d) .failed()) + { + err = std::ios_base::badbit; + } + } + else if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), d) .failed()) + { + err = std::ios_base::badbit; + } + os.width(0); + } + } + BOOST_CATCH(...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH(...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + } + + /** + * + * @param is the input stream + * @param d the duration + * @return @c is + */ + template + std::basic_istream& + operator>>(std::basic_istream& is, duration& d) + { + std::ios_base::iostate err = std::ios_base::goodbit; + + BOOST_TRY + { + typename std::basic_istream::sentry ipfx(is); + if (bool(ipfx)) + { + if (!std::has_facet >(is.getloc())) + { + duration_get ().get(is, std::istreambuf_iterator(), is, err, d); + } + else + { + std::use_facet >(is.getloc()) .get(is, std::istreambuf_iterator(), is, + err, d); + } + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + is.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) { BOOST_RETHROW } + } + BOOST_CATCH_END + if (err) is.setstate(err); + return is; + } + + } // chrono + +} + +#endif // header diff --git a/third-party/boost/boost/chrono/io/duration_put.hpp b/third-party/boost/boost/chrono/io/duration_put.hpp new file mode 100644 index 000000000..623eae1bf --- /dev/null +++ b/third-party/boost/boost/chrono/io/duration_put.hpp @@ -0,0 +1,317 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +/** + * Duration formatting facet for output. + */ +#ifndef BOOST_CHRONO_IO_DURATION_PUT_HPP +#define BOOST_CHRONO_IO_DURATION_PUT_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + namespace detail + { + template + struct propagate { + typedef T type; + }; + template <> + struct propagate { + typedef boost::int_least64_t type; + }; + } + /** + * @tparam ChatT a character type + * @tparam OutputIterator a model of @c OutputIterator + * + * The @c duration_put facet provides facilities for formatted output of duration values. + * The member function of @c duration_put take a duration and format it into character string representation. + * + */ + template > + class duration_put: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to write in the character buffer. + */ + typedef OutputIterator iter_type; + + /** + * Construct a duration_put facet. + * @param refs + * @Effects Construct a duration_put facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_put(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Steps through the sequence from @c pattern to @c pat_end, + * identifying characters that are part of a pattern sequence. Each character + * that is not part of a pattern sequence is written to @c s immediately, and + * each pattern sequence, as it is identified, results in a call to + * @c put_value or @c put_unit; + * thus, pattern elements and other characters are interleaved in the output + * in the order in which they appear in the pattern. Pattern sequences are + * identified by converting each character @c c to a @c char value as if by + * @c ct.narrow(c,0), where @c ct is a reference to @c ctype obtained from + * @c ios.getloc(). The first character of each sequence is equal to @c '%', + * followed by a pattern specifier character @c spec, which can be @c 'v' for + * the duration value or @c 'u' for the duration unit. . + * For each valid pattern sequence identified, calls + * put_value(s, ios, fill, d) or put_unit(s, ios, fill, d). + * + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const CharT* pattern, + const CharT* pat_end, const char_type* val = 0) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + return put(facet, s, ios, fill, d, pattern, pat_end, val); + } + else + { + duration_units_default facet; + return put(facet, s, ios, fill, d, pattern, pat_end, val); + } + } + + template + iter_type put(duration_units const& units_facet, iter_type s, std::ios_base& ios, char_type fill, + duration const& d, const CharT* pattern, const CharT* pat_end, const char_type* val = 0) const + { + + const std::ctype& ct = std::use_facet >(ios.getloc()); + for (; pattern != pat_end; ++pattern) + { + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + *s++ = pattern[-1]; + break; + } + char fmt = ct.narrow(*pattern, 0); + switch (fmt) + { + case 'v': + { + s = put_value(s, ios, fill, d, val); + break; + } + case 'u': + { + s = put_unit(units_facet, s, ios, fill, d); + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + } + else + *s++ = *pattern; + } + return s; + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects imbue in @c ios the @c duration_units_default facet if not already present. + * Retrieves Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return put(s, ios, d, str.data(), str.data() + str.size()); + * @endcode + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const char_type* val = 0) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + std::basic_string str = facet.get_pattern(); + return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val); + } + else + { + duration_units_default facet; + std::basic_string str = facet.get_pattern(); + + return put(facet, s, ios, fill, d, str.data(), str.data() + str.size(), val); + } + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects As if s=std::use_facet >(ios.getloc()).put(s, ios, fill, static_cast (d.count())). + * @Returns s, iterator pointing immediately after the last character produced. + */ + template + iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration const& d, const char_type* val = 0) const + { + if (val) + { + while (*val) { + *s = *val; + s++; val++; + } + return s; + } + return std::use_facet >(ios.getloc()).put(s, ios, fill, + static_cast::type> (d.count())); + } + + template + iter_type put_value(iter_type s, std::ios_base& ios, char_type fill, duration, Period> const& d, const char_type* = 0) const + { + *s++ = CharT('{'); + s = put_value(s, ios, fill, process_real_cpu_clock::duration(d.count().real)); + *s++ = CharT(';'); + s = put_value(s, ios, fill, process_user_cpu_clock::duration(d.count().user)); + *s++ = CharT(';'); + s = put_value(s, ios, fill, process_system_cpu_clock::duration(d.count().system)); + *s++ = CharT('}'); + return s; + } + + /** + * + * @param s an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the duration + * @Effects Let facet be the duration_units facet associated to ios. If the associated unit is named, + * as if + * @code + string_type str = facet.get_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + * @endcode + * Otherwise, format the unit as "[Period::num/Period::den]" followed by the unit associated to [N/D] obtained using facet.get_n_d_unit(get_duration_style(ios), d) + * @Returns s, iterator pointing immediately after the last character produced. + */ + template + iter_type put_unit(iter_type s, std::ios_base& ios, char_type fill, duration const& d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_units const&facet = std::use_facet >( + ios.getloc()); + return put_unit(facet, s, ios, fill, d); + } + else + { + duration_units_default facet; + return put_unit(facet, s, ios, fill, d); + } + } + + template + iter_type put_unit(duration_units const& facet, iter_type s, std::ios_base& ios, char_type fill, + duration const& d) const + { + if (facet.template is_named_unit()) { + string_type str = facet.get_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + } else { + *s++ = CharT('['); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::num); + *s++ = CharT('/'); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::den); + *s++ = CharT(']'); + string_type str = facet.get_n_d_unit(get_duration_style(ios), d); + s=std::copy(str.begin(), str.end(), s); + } + return s; + } + template + iter_type put_unit(duration_units const& facet, iter_type s, std::ios_base& ios, char_type fill, + duration, Period> const& d) const + { + duration real(d.count().real); + if (facet.template is_named_unit()) { + string_type str = facet.get_unit(get_duration_style(ios), real); + s=std::copy(str.begin(), str.end(), s); + } else { + *s++ = CharT('['); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::num); + *s++ = CharT('/'); + std::use_facet >(ios.getloc()).put(s, ios, fill, Period::den); + *s++ = CharT(']'); + string_type str = facet.get_n_d_unit(get_duration_style(ios), real); + s=std::copy(str.begin(), str.end(), s); + } + return s; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~duration_put() + { + } + + }; + + template + std::locale::id duration_put::id; + + } // chrono +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/duration_style.hpp b/third-party/boost/boost/chrono/io/duration_style.hpp new file mode 100644 index 000000000..65b76a902 --- /dev/null +++ b/third-party/boost/boost/chrono/io/duration_style.hpp @@ -0,0 +1,35 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_DURATION_STYLE_HPP +#define BOOST_CHRONO_IO_DURATION_STYLE_HPP + +#include + +namespace boost +{ + namespace chrono + { + /** + * Scoped enumeration emulation stating whether the duration I/O style is long or short. + * prefix means duration::rep with whatever stream/locale settings are set for it followed by a long name representing the unit + * symbol means duration::rep with whatever stream/locale settings are set for it followed by a SI unit abbreviation + */ + BOOST_SCOPED_ENUM_DECLARE_BEGIN(duration_style) + { + prefix, symbol + } + BOOST_SCOPED_ENUM_DECLARE_END(duration_style) + + + } // chrono + +} + +#endif // header diff --git a/third-party/boost/boost/chrono/io/duration_units.hpp b/third-party/boost/boost/chrono/io/duration_units.hpp new file mode 100644 index 000000000..84faa819a --- /dev/null +++ b/third-party/boost/boost/chrono/io/duration_units.hpp @@ -0,0 +1,1003 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_IO_DURATION_UNITS_HPP +#define BOOST_CHRONO_IO_DURATION_UNITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + class rt_ratio + { + public: + template + rt_ratio(Period const&) : + num(Period::type::num), den(Period::type::den) + { + } + + rt_ratio(intmax_t n = 0, intmax_t d = 0) : + num(n), den(d) + { + } + + intmax_t num; + intmax_t den; + }; + + /** + * @c duration_units facet gives useful information about the duration units, + * as the number of plural forms, the plural form associated to a duration, + * the text associated to a plural form and a duration's period, + */ + template + class duration_units: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * Construct a @c duration_units facet. + * @param refs + * @Effects Construct a @c duration_units facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_units(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @return pointer to the start of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_start() const =0; + /** + * @effect calls the do_... + * @return pointer to the end of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_end() const=0; + + /** + * @return pointer to the start of valid units, symbol or prefix with its different plural forms. + */ + virtual const string_type* get_valid_units_start() const=0; + /** + * @return pointer to the end of valid units. + */ + virtual const string_type* get_valid_units_end() const=0; + + /** + * @param k the found pointer to the [N/D] unit. + * @return true if @c k matches a valid unit. + */ + virtual bool match_n_d_valid_unit(const string_type* k) const = 0; + /** + * @param k the found pointer to the unit. + * @Effects @c rt is set to the valid Period when the @c k matches a valid unit. + * @return true if @c k matches a valid unit. + */ + virtual bool match_valid_unit(const string_type* k, rt_ratio& rt) const = 0; + + /** + * @effect calls the do_... + * @return the pattern to be used by default. + */ + virtual string_type get_pattern() const=0; + + /** + * @effect calls the do_... + * @return the unit associated to this duration. + */ + template + string_type get_unit(duration_style style, duration const& d) const + { + return do_get_unit(style, rt_ratio(Period()), static_cast(d.count())); + } + /** + * @effect calls the do_... + * @return the [N/D] suffix unit associated to this duration. + */ + template + string_type get_n_d_unit(duration_style style, duration const& d) const + { + return do_get_n_d_unit(style, rt_ratio(Period()), static_cast(d.count())); + } + + /** + * @effect calls the do_... + * @return true if the unit associated to the given Period is named, false otherwise. + */ + template + bool is_named_unit() const + { + return do_is_named_unit(rt_ratio(Period())); + } + + + protected: + + /** + * @Effects Destroys the facet + */ + virtual ~duration_units() + { + } + /** + * @return the [N/D] suffix unit associated to this duration. + */ + virtual string_type do_get_n_d_unit(duration_style style, rt_ratio rt, intmax_t v) const = 0; + /** + * @return the unit associated to this duration. + */ + virtual string_type do_get_unit(duration_style style,rt_ratio rt, intmax_t v) const = 0; + /** + * @return true if the unit associated to the given Period is named, false otherwise. + */ + virtual bool do_is_named_unit(rt_ratio rt) const =0; + + }; + + template + std::locale::id duration_units::id; + + namespace detail + { + template + struct duration_units_default_holder + { + typedef std::basic_string string_type; + static string_type* n_d_valid_units_; + static string_type* valid_units_; + static bool initialized_; + }; + template + typename duration_units_default_holder::string_type* duration_units_default_holder::n_d_valid_units_=0; + template + typename duration_units_default_holder::string_type* duration_units_default_holder::valid_units_=0; + template + bool duration_units_default_holder::initialized_ = false; + } + + /** + * This class is used to define the strings for the default English + */ + template + class duration_units_default: public duration_units + { + protected: + static const std::size_t pfs_ = 2; + + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + + /** + * Construct a @c duration_units_default facet. + * @param refs + * @Effects Construct a @c duration_units_default facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit duration_units_default(size_t refs = 0) : + duration_units (refs) + { + } + + /** + * Destroys the facet. + */ + ~duration_units_default() + { + } + + public: + + /** + * @param k the found pointer to the [N/D] unit. + * @return true if @c k matches a valid unit. + */ + bool match_n_d_valid_unit(const string_type* k) const + { + std::size_t index = (k - get_n_d_valid_units_start()) / (pfs_ + 1); + switch (index) + { + case 0: + break; + default: + return false; + } + return true; + } + /** + * @param k the found pointer to the unit. + * @Effects @c rt is set to the valid Period when the @c k matches a valid unit. + * @return true if @c k matches a valid unit. + */ + bool match_valid_unit(const string_type* k, rt_ratio& rt) const + { + std::size_t index = (k - get_valid_units_start()) / (pfs_ + 1); + switch (index) + { + case 0: + rt = rt_ratio(atto()); + break; + case 1: + rt = rt_ratio(femto()); + break; + case 2: + rt = rt_ratio(pico()); + break; + case 3: + rt = rt_ratio(nano()); + break; + case 4: + rt = rt_ratio(micro()); + break; + case 5: + rt = rt_ratio(milli()); + break; + case 6: + rt = rt_ratio(centi()); + break; + case 7: + rt = rt_ratio(deci()); + break; + case 8: + rt = rt_ratio(deca()); + break; + case 9: + rt = rt_ratio(hecto()); + break; + case 10: + rt = rt_ratio(kilo()); + break; + case 11: + rt = rt_ratio(mega()); + break; + case 12: + rt = rt_ratio(giga()); + break; + case 13: + rt = rt_ratio(tera()); + break; + case 14: + rt = rt_ratio(peta()); + break; + case 15: + rt = rt_ratio(exa()); + break; + case 16: + rt = rt_ratio(ratio<1> ()); + break; + case 17: + rt = rt_ratio(ratio<60> ()); + break; + case 18: + rt = rt_ratio(ratio<3600> ()); + break; + default: + return false; + } + return true; + } + + /** + * @return pointer to the start of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_start()const + { + return detail::duration_units_default_holder::n_d_valid_units_; + } + /** + * @return pointer to the end of valid [N/D] units. + */ + virtual const string_type* get_n_d_valid_units_end()const + { + return detail::duration_units_default_holder::n_d_valid_units_ + (pfs_ + 1); + } + + /** + * @return pointer to the start of valid units. + */ + virtual const string_type* get_valid_units_start() const + { + return detail::duration_units_default_holder::valid_units_; + } + /** + * @return pointer to the end of valid units. + */ + virtual const string_type* get_valid_units_end() const + { + return detail::duration_units_default_holder::valid_units_ + 19 * (pfs_ + 1); + } + + string_type get_pattern() const + { + static const CharT t[] = + { '%', 'v', ' ', '%', 'u' }; + static const string_type pattern(t, t + sizeof (t) / sizeof (t[0])); + + return pattern; + } + + protected: + /** + * + * This facet names the units associated to the following periods: + * atto,femto,pico,nano,micro,milli,centi,deci,ratio<1>,deca,hecto,kilo,mega,giga,tera,peta,exa,ratio<60> and ratio<3600>. + * @return true if the unit associated to the given Period is named, false otherwise. + */ + bool do_is_named_unit(rt_ratio rt) const + { + if (rt.num==1) { + switch (rt.den) + { + case BOOST_RATIO_INTMAX_C(1): + case BOOST_RATIO_INTMAX_C(10): + case BOOST_RATIO_INTMAX_C(100): + case BOOST_RATIO_INTMAX_C(1000): + case BOOST_RATIO_INTMAX_C(1000000): + case BOOST_RATIO_INTMAX_C(1000000000): + case BOOST_RATIO_INTMAX_C(1000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return true; + default: + return false; + } + } else if (rt.den==1) { + switch (rt.num) + { + case BOOST_RATIO_INTMAX_C(10): + case BOOST_RATIO_INTMAX_C(60): + case BOOST_RATIO_INTMAX_C(100): + case BOOST_RATIO_INTMAX_C(1000): + case BOOST_RATIO_INTMAX_C(3600): + case BOOST_RATIO_INTMAX_C(1000000): + case BOOST_RATIO_INTMAX_C(1000000000): + case BOOST_RATIO_INTMAX_C(1000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000): + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return true; + default: + return false; + } + } + return false; + + } + + /** + * In English the suffix used after [N/D] is the one associated to the period ratio<1>. + * @return the [N/D] suffix unit associated to this duration. + */ + string_type do_get_n_d_unit(duration_style style, rt_ratio, intmax_t v) const + { + return do_get_unit(style, ratio<1>(), do_get_plural_form(v)); + } + + /** + * @return the unit associated to this duration if it is named, "" otherwise. + */ + string_type do_get_unit(duration_style style, rt_ratio rt, intmax_t v) const + { + if (rt.num==1) { + switch (rt.den) + { + case BOOST_RATIO_INTMAX_C(1): + return do_get_unit(style, ratio<1>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(10): + return do_get_unit(style, deci(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(100): + return do_get_unit(style, centi(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000): + return do_get_unit(style, milli(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000): + return do_get_unit(style, micro(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000): + return do_get_unit(style, nano(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000): + return do_get_unit(style, pico(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000): + return do_get_unit(style, femto(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return do_get_unit(style, atto(), do_get_plural_form(v)); + default: + ; + } + } else if (rt.den==1) { + switch (rt.num) + { + case BOOST_RATIO_INTMAX_C(10): + return do_get_unit(style, deca(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(60): + return do_get_unit(style, ratio<60>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(100): + return do_get_unit(style, hecto(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000): + return do_get_unit(style, kilo(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(3600): + return do_get_unit(style, ratio<3600>(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000): + return do_get_unit(style, mega(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000): + return do_get_unit(style, giga(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000): + return do_get_unit(style, tera(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000): + return do_get_unit(style, peta(), do_get_plural_form(v)); + case BOOST_RATIO_INTMAX_C(1000000000000000000): + return do_get_unit(style, exa(), do_get_plural_form(v)); + default: + ; + } + } + BOOST_ASSERT(false&&"ratio parameter can not be translated"); + //throw "exception"; + return string_type(); + } + + protected: + /** + * @return the number of associated plural forms this facet manages. + */ + virtual std::size_t do_get_plural_forms() const + { + return static_get_plural_forms(); + } + static std::size_t static_get_plural_forms() + { + return pfs_; + } + /** + * Gets the associated plural form. + * @param value the duration representation + * @return the plural form associated to the @c value parameter. In English there are 2 plural forms + * 0 singular (-1 or 1) + * 1 plural for all others + */ + virtual std::size_t do_get_plural_form(int_least64_t value) const + { + return static_get_plural_form(value); + } + static std::size_t static_get_plural_form(int_least64_t value) + { + return (value == -1 || value == 1) ? 0 : 1; + } + + /** + * @param style the duration style. + * @param period the period associated to the duration seconds. + * @param pf the requested plural form. + * @return if style is symbol returns "s", otherwise if pf is 0 return "second", if pf is 1 "seconds" + */ + virtual string_type do_get_unit(duration_style style, ratio<1> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<1> , std::size_t pf) + { + static const CharT t[] = + { 's' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + static const CharT u[] = + { 's', 'e', 'c', 'o', 'n', 'd' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 's', 'e', 'c', 'o', 'n', 'd', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) + { + return symbol; + } + if (pf == 0) + { + return singular; + } + if (pf == 1) + { + return plural; + } + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + } + + /** + * @param style the duration style. + * @param period the period associated to the duration minutes. + * @param pf the requested plural form. + * @return if style is symbol returns "min", otherwise if pf is 0 return "minute", if pf is 1 "minutes" + */ + virtual string_type do_get_unit(duration_style style, ratio<60> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<60> , std::size_t pf) + { + static const CharT t[] = + { 'm', 'i', 'n' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + + static const CharT u[] = + { 'm', 'i', 'n', 'u', 't', 'e' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 'm', 'i', 'n', 'u', 't', 'e', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) return symbol; + if (pf == 0) return singular; + if (pf == 1) return plural; + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + + } + + /** + * @param style the duration style. + * @param period the period associated to the duration hours. + * @param pf the requested plural form. + * @return if style is symbol returns "h", otherwise if pf is 0 return "hour", if pf is 1 "hours" + */ + virtual string_type do_get_unit(duration_style style, ratio<3600> u, std::size_t pf) const + { + return static_get_unit(style,u,pf); + } + static string_type static_get_unit(duration_style style, ratio<3600> , std::size_t pf) + { + static const CharT t[] = + { 'h' }; + static const string_type symbol(t, t + sizeof (t) / sizeof (t[0])); + static const CharT u[] = + { 'h', 'o', 'u', 'r' }; + static const string_type singular(u, u + sizeof (u) / sizeof (u[0])); + static const CharT v[] = + { 'h', 'o', 'u', 'r', 's' }; + static const string_type plural(v, v + sizeof (v) / sizeof (v[0])); + + if (style == duration_style::symbol) return symbol; + if (pf == 0) return singular; + if (pf == 1) return plural; + BOOST_ASSERT(false&&"style/pf parameters not valid"); + //throw "exception"; + return string_type(); + + } + /** + * @param style the duration style. + * @param u the period tag atto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to @c period + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, atto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, atto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + /** + * @param style the duration style. + * @param u the period tag femto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to period @c u + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, femto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, femto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + /** + * @param style the duration style. + * @param u the period tag femto. + * @param pf the requested plural form. + * @return the concatenation of the prefix associated to period @c u + the one associated to seconds. + */ + virtual string_type do_get_unit(duration_style style, pico u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, pico u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, nano u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, nano u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, micro u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, micro u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, milli u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, milli u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, centi u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, centi u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, deci u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, deci u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, deca u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, deca u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, hecto u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, hecto u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, kilo u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, kilo u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, mega u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, mega u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, giga u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, giga u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, tera u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, tera u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, peta u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, peta u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + virtual string_type do_get_unit(duration_style style, exa u, std::size_t pf) const + { + return do_get_ratio_prefix(style, u) + do_get_unit(style, ratio<1> (), pf); + } + static string_type static_get_unit(duration_style style, exa u, std::size_t pf) + { + return static_get_ratio_prefix(style, u) + static_get_unit(style, ratio<1> (), pf); + } + + protected: + + /** + * @param style the duration style. + * @param u the period tag atto. + * @return depending on the value of @c style return the ratio_string symbol or prefix. + */ + virtual string_type do_get_ratio_prefix(duration_style style, atto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, atto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, femto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, femto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, pico u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, pico) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, nano u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, nano) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, micro u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, micro) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, milli u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, milli) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, centi u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, centi) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, deci u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, deci) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, deca u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, deca) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, hecto u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, hecto) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, kilo u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, kilo) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, mega u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, mega) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, giga u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, giga) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, tera u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, tera) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, peta u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, peta) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + virtual string_type do_get_ratio_prefix(duration_style style, exa u) const + { + return static_get_ratio_prefix(style, u); + } + static string_type static_get_ratio_prefix(duration_style style, exa) + { + if (style == duration_style::symbol) return ratio_string::symbol(); + return ratio_string::prefix(); + } + + protected: + template + string_type* fill_units(string_type* it, Period) const + { + std::size_t pfs = do_get_plural_forms(); + for (std::size_t pf = 0; pf < pfs; ++pf) + { + *it++ = do_get_unit(duration_style::prefix, Period(), pf); + } + *it++ = do_get_unit(duration_style::symbol, Period(), 0); + return it; + } + public: + template + static string_type* static_fill_units(string_type* it, Period) + { + std::size_t pfs = static_get_plural_forms(); + for (std::size_t pf = 0; pf < pfs; ++pf) + { + *it++ = static_get_unit(duration_style::prefix, Period(), pf); + } + *it++ = static_get_unit(duration_style::symbol, Period(), 0); + return it; + } + static string_type* static_init_valid_units(string_type* it) + { + it = static_fill_units(it, atto()); + it = static_fill_units(it, femto()); + it = static_fill_units(it, pico()); + it = static_fill_units(it, nano()); + it = static_fill_units(it, micro()); + it = static_fill_units(it, milli()); + it = static_fill_units(it, centi()); + it = static_fill_units(it, deci()); + it = static_fill_units(it, deca()); + it = static_fill_units(it, hecto()); + it = static_fill_units(it, kilo()); + it = static_fill_units(it, mega()); + it = static_fill_units(it, giga()); + it = static_fill_units(it, tera()); + it = static_fill_units(it, peta()); + it = static_fill_units(it, exa()); + it = static_fill_units(it, ratio<1> ()); + it = static_fill_units(it, ratio<60> ()); + it = static_fill_units(it, ratio<3600> ()); + return it; + } + }; + + namespace detail + { + + template + struct duration_units_default_initializer_t + { + duration_units_default_initializer_t() + { + if (!duration_units_default_holder::initialized_) + { + typedef typename duration_units_default_holder::string_type string_type; + duration_units_default_holder::n_d_valid_units_ = new string_type[3]; + duration_units_default_holder::valid_units_ = new string_type[19 * 3]; + + string_type* it = duration_units_default_holder::n_d_valid_units_; + it = duration_units_default::static_fill_units(it, ratio<1> ()); + it = duration_units_default::static_init_valid_units(duration_units_default_holder::valid_units_); + + duration_units_default_holder::initialized_ = true; + } + } + ~duration_units_default_initializer_t() + { + if (duration_units_default_holder::initialized_) + { + delete[] duration_units_default_holder::n_d_valid_units_; + duration_units_default_holder::n_d_valid_units_ = 0; + delete[] duration_units_default_holder::valid_units_; + duration_units_default_holder::valid_units_ = 0; + duration_units_default_holder::initialized_ = false; + } + } + }; + namespace /**/ + { + duration_units_default_initializer_t duration_units_default_initializer; + duration_units_default_initializer_t wduration_units_default_initializer; + } // namespace + } + } // chrono + +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/ios_base_state.hpp b/third-party/boost/boost/chrono/io/ios_base_state.hpp new file mode 100644 index 000000000..1393e2e69 --- /dev/null +++ b/third-party/boost/boost/chrono/io/ios_base_state.hpp @@ -0,0 +1,152 @@ +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_IOS_BASE_STATE_HPP +#define BOOST_CHRONO_IO_IOS_BASE_STATE_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + class fmt_masks : public ios_flags + { + typedef ios_flags base_type; + fmt_masks& operator=(fmt_masks const& rhs) ; + + public: + fmt_masks(std::ios_base& ios): base_type(ios) {} + enum type + { + uses_symbol = 1 << 0, + uses_local = 1 << 1 + }; + + inline duration_style get_duration_style() + { + return (flags() & uses_symbol) ? duration_style::symbol : duration_style::prefix; + } + inline void set_duration_style(duration_style style) + { + if (style == duration_style::symbol) + setf(uses_symbol); + else + unsetf(uses_symbol); + } + + inline timezone get_timezone() + { + return (flags() & uses_local) ? timezone::local : timezone::utc; + } + inline void set_timezone(timezone tz) + { + if (tz == timezone::local) + setf(uses_local); + else + unsetf(uses_local); + } + }; + namespace detail + { + namespace /**/ { + xalloc_key_initializer fmt_masks_xalloc_key_initializer; + } // namespace + } // namespace detail + + inline duration_style get_duration_style(std::ios_base & ios) + { + return fmt_masks(ios).get_duration_style(); + } + inline void set_duration_style(std::ios_base& ios, duration_style style) + { + fmt_masks(ios).set_duration_style(style); + } + inline std::ios_base& symbol_format(std::ios_base& ios) + { + fmt_masks(ios).setf(fmt_masks::uses_symbol); + return ios; + } + inline std::ios_base& name_format(std::ios_base& ios) + { + fmt_masks(ios).unsetf(fmt_masks::uses_symbol); + return ios; + } + + inline timezone get_timezone(std::ios_base & ios) + { + return fmt_masks(ios).get_timezone(); + } + inline void set_timezone(std::ios_base& ios, timezone tz) + { + fmt_masks(ios).set_timezone(tz); + } + inline std::ios_base& local_timezone(std::ios_base& ios) + { + fmt_masks(ios).setf(fmt_masks::uses_local); + return ios; + } + + inline std::ios_base& utc_timezone(std::ios_base& ios) + { + fmt_masks(ios).unsetf(fmt_masks::uses_local); + return ios; + } + + namespace detail + { + + template + struct ios_base_data_aux + { + std::basic_string time_fmt; + std::basic_string duration_fmt; + public: + + ios_base_data_aux() + //: + // time_fmt(""), + // duration_fmt("") + { + } + }; + template + struct ios_base_data {}; + namespace /**/ { + xalloc_key_initializer > ios_base_data_aux_xalloc_key_initializer; + xalloc_key_initializer > wios_base_data_aux_xalloc_key_initializer; +#if BOOST_CHRONO_HAS_UNICODE_SUPPORT + xalloc_key_initializer > u16ios_base_data_aux_xalloc_key_initializer; + xalloc_key_initializer > u32ios_base_data_aux_xalloc_key_initializer; +#endif + } // namespace + } // namespace detail + + template + inline std::basic_string get_time_fmt(std::ios_base & ios) + { + ios_state_not_null_ptr, detail::ios_base_data_aux > ptr(ios); + return ptr->time_fmt; + } + template + inline void set_time_fmt(std::ios_base& ios, std::basic_string< + CharT> const& fmt) + { + ios_state_not_null_ptr, detail::ios_base_data_aux > ptr(ios); + ptr->time_fmt = fmt; + } + + } // chrono +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/time_point_get.hpp b/third-party/boost/boost/chrono/io/time_point_get.hpp new file mode 100644 index 000000000..44c641e6d --- /dev/null +++ b/third-party/boost/boost/chrono/io/time_point_get.hpp @@ -0,0 +1,330 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_IO_TIME_POINT_GET_HPP +#define BOOST_CHRONO_IO_TIME_POINT_GET_HPP + +#include +#include +#include +#include +#include +#include +#include + +/** + * Duration formatting facet for input. + */ +namespace boost +{ + namespace chrono + { + + template > + class time_point_get: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of iterator used to scan the character buffer. + */ + typedef InputIterator iter_type; + + /** + * Construct a @c time_point_get facet. + * @param refs + * @Effects Construct a @c time_point_get facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + + explicit time_point_get(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param s start input stream iterator + * @param end end input stream iterator + * @param ios a reference to a ios_base + * @param err the ios_base state + * @param d the duration + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * Requires: [pattern,pat_end) shall be a valid range. + * + * Effects: The function starts by evaluating err = std::ios_base::goodbit. + * It then enters a loop, reading zero or more characters from s at + * each iteration. Unless otherwise specified below, the loop + * terminates when the first of the following conditions holds: + * - The expression pattern == pat_end evaluates to true. + * - The expression err == std::ios_base::goodbit evaluates to false. + * - The expression s == end evaluates to true, in which case the + * function evaluates err = std::ios_base::eofbit | std::ios_base::failbit. + * - The next element of pattern is equal to '%', followed by a conversion + * specifier character, the functions @c get_duration or @c get_epoch are called depending on + * whether the format is @c 'd' or @c 'e'. + * If the number of elements in the range [pattern,pat_end) is not + * sufficient to unambiguously determine whether the conversion + * specification is complete and valid, the function evaluates + * err = std::ios_base::failbit. Otherwise, the function evaluates + * s = do_get(s, end, ios, err, d). If err == std::ios_base::goodbit holds after + * the evaluation of the expression, the function increments pattern to + * point just past the end of the conversion specification and continues + * looping. + * - The expression isspace(*pattern, ios.getloc()) evaluates to true, in + * which case the function first increments pattern until + * pattern == pat_end || !isspace(*pattern, ios.getloc()) evaluates to true, + * then advances s until s == end || !isspace(*s, ios.getloc()) is true, + * and finally resumes looping. + * - The next character read from s matches the element pointed to by + * pattern in a case-insensitive comparison, in which case the function + * evaluates ++pattern, ++s and continues looping. Otherwise, the function + * evaluates err = std::ios_base::failbit. + * + * Returns: s + */ + + template + iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + time_point &tp, const char_type *pattern, const char_type *pat_end) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + return get(facet, i, e, is, err, tp, pattern, pat_end); + } + else + { + time_point_units_default facet; + return get(facet, i, e, is, err, tp, pattern, pat_end); + } + } + + template + iter_type get(time_point_units const &facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, time_point &tp, const char_type *pattern, + const char_type *pat_end) const + { + + Duration d; + bool duration_found = false, epoch_found = false; + + const std::ctype& ct = std::use_facet >(ios.getloc()); + err = std::ios_base::goodbit; + while (pattern != pat_end && err == std::ios_base::goodbit) + { + if (s == end) + { + err |= std::ios_base::eofbit; + break; + } + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + err |= std::ios_base::failbit; + return s; + } + char cmd = ct.narrow(*pattern, 0); + switch (cmd) + { + case 'd': + { + if (duration_found) + { + err |= std::ios_base::failbit; + return s; + } + duration_found = true; + s = get_duration(s, end, ios, err, d); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + case 'e': + { + if (epoch_found) + { + err |= std::ios_base::failbit; + return s; + } + epoch_found = true; + s = get_epoch (facet, s, end, ios, err); + if (err & (std::ios_base::badbit | std::ios_base::failbit)) + { + return s; + } + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + + ++pattern; + } + else if (ct.is(std::ctype_base::space, *pattern)) + { + for (++pattern; pattern != pat_end && ct.is(std::ctype_base::space, *pattern); ++pattern) + ; + for (; s != end && ct.is(std::ctype_base::space, *s); ++s) + ; + } + else if (ct.toupper(*s) == ct.toupper(*pattern)) + { + ++s; + ++pattern; + } + else + { + err |= std::ios_base::failbit; + } + } + + // Success! Store it. + tp = time_point (d); + return s; + } + + /** + * + * @param s an input stream iterator + * @param ios a reference to a ios_base + * @param d the duration + * Stores the duration pattern from the @c duration_unit facet in let say @c str. Last as if + * @code + * return get(s, end, ios, err, ios, d, str.data(), str.data() + str.size()); + * @codeend + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid name + */ + template + iter_type get(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + time_point &tp) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + std::basic_string str = facet.get_pattern(); + return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); + } + else + { + time_point_units_default facet; + std::basic_string str = facet.get_pattern(); + return get(facet, i, e, is, err, tp, str.data(), str.data() + str.size()); + } + } + + /** + * As if + * @code + * return facet.get(s, end, ios, err, d); + * @endcode + * where @c facet is either the @c duration_get facet associated to the @c ios or an instance of the default @c duration_get facet. + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid duration. + */ + template + iter_type get_duration(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err, + duration& d) const + { + if (std::has_facet >(is.getloc())) + { + duration_get const &facet = std::use_facet >(is.getloc()); + return get_duration(facet, i, e, is, err, d); + } + else + { + duration_get facet; + return get_duration(facet, i, e, is, err, d); + } + } + + template + iter_type get_duration(duration_get const& facet, iter_type s, iter_type end, std::ios_base& ios, + std::ios_base::iostate& err, duration& d) const + { + return facet.get(s, end, ios, err, d); + } + + /** + * + * @Effects Let @c facet be the @c time_point_units facet associated to @c is or a new instance of the default @c time_point_units_default facet. + * Let @c epoch be the epoch string associated to the Clock using this facet. + * Scans @c i to match @c epoch or @c e is reached. + * + * If not match before the @c e is reached @c std::ios_base::failbit is set in @c err. + * If @c e is reached @c std::ios_base::failbit is set in @c err. + * + * @Returns An iterator pointing just beyond the last character that can be determined to be part of a valid epoch. + */ + template + iter_type get_epoch(iter_type i, iter_type e, std::ios_base& is, std::ios_base::iostate& err) const + { + if (std::has_facet >(is.getloc())) + { + time_point_units const &facet = std::use_facet >(is.getloc()); + return get_epoch(facet, i, e, is, err); + } + else + { + time_point_units_default facet; + return get_epoch(facet, i, e, is, err); + } + } + + template + iter_type get_epoch(time_point_units const &facet, iter_type i, iter_type e, std::ios_base&, + std::ios_base::iostate& err) const + { + const std::basic_string epoch = facet.template get_epoch (); + std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, &epoch, &epoch + 1, + //~ std::use_facet >(ios.getloc()), + err) - &epoch; + if (k == 1) + { + err |= std::ios_base::failbit; + return i; + } + return i; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~time_point_get() + { + } + }; + + /** + * Unique identifier for this type of facet. + */ + template + std::locale::id time_point_get::id; + + } // chrono +} +// boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/time_point_io.hpp b/third-party/boost/boost/chrono/io/time_point_io.hpp new file mode 100644 index 000000000..d0f854cfb --- /dev/null +++ b/third-party/boost/boost/chrono/io/time_point_io.hpp @@ -0,0 +1,1249 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). + +//===-------------------------- locale ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost and some functions from libc++/locale to emulate the missing time_get::get() + +#ifndef BOOST_CHRONO_IO_TIME_POINT_IO_HPP +#define BOOST_CHRONO_IO_TIME_POINT_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if ( defined BOOST_WINDOWS && ! defined(__CYGWIN__) ) \ + || (defined(sun) || defined(__sun)) \ + || (defined __IBMCPP__) \ + || defined __ANDROID__ \ + || defined __QNXNTO__ \ + || (defined(_AIX) && defined __GNUC__) +#define BOOST_CHRONO_INTERNAL_TIMEGM +#endif + +#if (defined BOOST_WINDOWS && ! defined(__CYGWIN__)) \ + || ( (defined(sun) || defined(__sun)) && defined __GNUC__) \ + || (defined __IBMCPP__) \ + || defined __ANDROID__ \ + || (defined(_AIX) && defined __GNUC__) +#define BOOST_CHRONO_INTERNAL_GMTIME +#endif + +#define BOOST_CHRONO_USES_INTERNAL_TIME_GET + +namespace boost +{ + namespace chrono + { + typedef double fractional_seconds; + namespace detail + { + + + template > + struct time_get + { + std::time_get const &that_; + time_get(std::time_get const& that) : that_(that) {} + + typedef std::time_get facet; + typedef typename facet::iter_type iter_type; + typedef typename facet::char_type char_type; + typedef std::basic_string string_type; + + static int + get_up_to_n_digits( + InputIterator& b, InputIterator e, + std::ios_base::iostate& err, + const std::ctype& ct, + int n) + { + // Precondition: n >= 1 + if (b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return 0; + } + // get first digit + CharT c = *b; + if (!ct.is(std::ctype_base::digit, c)) + { + err |= std::ios_base::failbit; + return 0; + } + int r = ct.narrow(c, 0) - '0'; + for (++b, --n; b != e && n > 0; ++b, --n) + { + // get next digit + c = *b; + if (!ct.is(std::ctype_base::digit, c)) + return r; + r = r * 10 + ct.narrow(c, 0) - '0'; + } + if (b == e) + err |= std::ios_base::eofbit; + return r; + } + + + void get_day( + int& d, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 31) + d = t; + else + err |= std::ios_base::failbit; + } + + void get_month( + int& m, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) + m = --t; + else + err |= std::ios_base::failbit; + } + + + void get_year4(int& y, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 4); + if (!(err & std::ios_base::failbit)) + y = t - 1900; + } + + void + get_hour(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 23) + h = t; + else + err |= std::ios_base::failbit; + } + + void + get_minute(int& m, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 59) + m = t; + else + err |= std::ios_base::failbit; + } + + void get_second(int& s, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && t <= 60) + s = t; + else + err |= std::ios_base::failbit; + } + + void get_white_space(iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + for (; b != e && ct.is(std::ctype_base::space, *b); ++b) + ; + if (b == e) + err |= std::ios_base::eofbit; + } + + void get_12_hour(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 2); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 12) + h = t; + else + err |= std::ios_base::failbit; + } + + void get_percent(iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + if (b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return; + } + if (ct.narrow(*b, 0) != '%') + err |= std::ios_base::failbit; + else if(++b == e) + err |= std::ios_base::eofbit; + } + + void get_day_year_num(int& d, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 3); + if (!(err & std::ios_base::failbit) && 1 <= t && t <= 366) + d = --t; + else + err |= std::ios_base::failbit; + } + + void + get_weekday(int& w, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + int t = get_up_to_n_digits(b, e, err, ct, 1); + if (!(err & std::ios_base::failbit) && t <= 6) + w = t; + else + err |= std::ios_base::failbit; + } +#if 0 + + void + get_am_pm(int& h, + iter_type& b, iter_type e, + std::ios_base::iostate& err, + const std::ctype& ct) const + { + const string_type* ap = am_pm(); + if (ap[0].size() + ap[1].size() == 0) + { + err |= ios_base::failbit; + return; + } + ptrdiff_t i = detail::scan_keyword(b, e, ap, ap+2, ct, err, false) - ap; + if (i == 0 && h == 12) + h = 0; + else if (i == 1 && h < 12) + h += 12; + } + +#endif + + InputIterator get( + iter_type b, iter_type e, + std::ios_base& iob, + std::ios_base::iostate& err, + std::tm* tm, + char fmt, char) const + { + err = std::ios_base::goodbit; + const std::ctype& ct = std::use_facet >(iob.getloc()); + + switch (fmt) + { + case 'a': + case 'A': + { + std::tm tm2; + std::memset(&tm2, 0, sizeof(std::tm)); + that_.get_weekday(b, e, iob, err, &tm2); + //tm->tm_wday = tm2.tm_wday; + } + break; + case 'b': + case 'B': + case 'h': + { + std::tm tm2; + std::memset(&tm2, 0, sizeof(std::tm)); + that_.get_monthname(b, e, iob, err, &tm2); + //tm->tm_mon = tm2.tm_mon; + } + break; +// case 'c': +// { +// const string_type& fm = c(); +// b = get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); +// } +// break; + case 'd': + case 'e': + get_day(tm->tm_mday, b, e, err, ct); + break; + case 'D': + { + const char_type fm[] = {'%', 'm', '/', '%', 'd', '/', '%', 'y'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'F': + { + const char_type fm[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'H': + get_hour(tm->tm_hour, b, e, err, ct); + break; + case 'I': + get_12_hour(tm->tm_hour, b, e, err, ct); + break; + case 'j': + get_day_year_num(tm->tm_yday, b, e, err, ct); + break; + case 'm': + get_month(tm->tm_mon, b, e, err, ct); + break; + case 'M': + get_minute(tm->tm_min, b, e, err, ct); + break; + case 'n': + case 't': + get_white_space(b, e, err, ct); + break; +// case 'p': +// get_am_pm(tm->tm_hour, b, e, err, ct); +// break; + case 'r': + { + const char_type fm[] = {'%', 'I', ':', '%', 'M', ':', '%', 'S', ' ', '%', 'p'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'R': + { + const char_type fm[] = {'%', 'H', ':', '%', 'M'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'S': + get_second(tm->tm_sec, b, e, err, ct); + break; + case 'T': + { + const char_type fm[] = {'%', 'H', ':', '%', 'M', ':', '%', 'S'}; + b = get(b, e, iob, err, tm, fm, fm + sizeof(fm)/sizeof(fm[0])); + } + break; + case 'w': + { + get_weekday(tm->tm_wday, b, e, err, ct); + } + break; + case 'x': + return that_.get_date(b, e, iob, err, tm); +// case 'X': +// return that_.get_time(b, e, iob, err, tm); +// { +// const string_type& fm = X(); +// b = that_.get(b, e, iob, err, tm, fm.data(), fm.data() + fm.size()); +// } +// break; +// case 'y': +// get_year(tm->tm_year, b, e, err, ct); + break; + case 'Y': + get_year4(tm->tm_year, b, e, err, ct); + break; + case '%': + get_percent(b, e, err, ct); + break; + default: + err |= std::ios_base::failbit; + } + return b; + } + + + InputIterator get( + iter_type b, iter_type e, + std::ios_base& iob, + std::ios_base::iostate& err, std::tm* tm, + const char_type* fmtb, const char_type* fmte) const + { + const std::ctype& ct = std::use_facet >(iob.getloc()); + err = std::ios_base::goodbit; + while (fmtb != fmte && err == std::ios_base::goodbit) + { + if (b == e) + { + err = std::ios_base::failbit; + break; + } + if (ct.narrow(*fmtb, 0) == '%') + { + if (++fmtb == fmte) + { + err = std::ios_base::failbit; + break; + } + char cmd = ct.narrow(*fmtb, 0); + char opt = '\0'; + if (cmd == 'E' || cmd == '0') + { + if (++fmtb == fmte) + { + err = std::ios_base::failbit; + break; + } + opt = cmd; + cmd = ct.narrow(*fmtb, 0); + } + b = get(b, e, iob, err, tm, cmd, opt); + ++fmtb; + } + else if (ct.is(std::ctype_base::space, *fmtb)) + { + for (++fmtb; fmtb != fmte && ct.is(std::ctype_base::space, *fmtb); ++fmtb) + ; + for ( ; b != e && ct.is(std::ctype_base::space, *b); ++b) + ; + } + else if (ct.toupper(*b) == ct.toupper(*fmtb)) + { + ++b; + ++fmtb; + } + else + err = std::ios_base::failbit; + } + if (b == e) + err |= std::ios_base::eofbit; + return b; + } + + }; + + + template + class time_manip: public manip > + { + std::basic_string fmt_; + timezone tz_; + public: + + time_manip(timezone tz, std::basic_string fmt) + // todo move semantics + : + fmt_(fmt), tz_(tz) + { + } + + /** + * Change the timezone and time format ios state; + */ + void operator()(std::ios_base &ios) const + { + set_time_fmt (ios, fmt_); + set_timezone(ios, tz_); + } + }; + + class time_man: public manip + { + timezone tz_; + public: + + time_man(timezone tz) + // todo move semantics + : + tz_(tz) + { + } + + /** + * Change the timezone and time format ios state; + */ + void operator()(std::ios_base &ios) const + { + //set_time_fmt(ios, ""); + set_timezone(ios, tz_); + } + }; + + } + + template + inline detail::time_manip time_fmt(timezone tz, const CharT* fmt) + { + return detail::time_manip(tz, fmt); + } + + template + inline detail::time_manip time_fmt(timezone tz, std::basic_string fmt) + { + // todo move semantics + return detail::time_manip(tz, fmt); + } + + inline detail::time_man time_fmt(timezone f) + { + return detail::time_man(f); + } + + /** + * time_fmt_io_saver i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + template > + struct time_fmt_io_saver + { + + //! the type of the state to restore + //typedef std::basic_ostream state_type; + typedef std::ios_base state_type; + + //! the type of aspect to save + typedef std::basic_string aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c time format . + */ + explicit time_fmt_io_saver(state_type &s) : + s_save_(s), a_save_(get_time_fmt(s_save_)) + { + } + + /** + * Construction from an i/o stream and a @c time format to restore. + * + * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. + */ + time_fmt_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_time_fmt(s_save_)) + { + set_time_fmt(s_save_, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the format to be restored. + */ + ~time_fmt_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the time format to be restored. + */ + void restore() + { + set_time_fmt(s_save_, a_save_); + } + private: + state_type& s_save_; + aspect_type a_save_; + }; + + /** + * timezone_io_saver i/o saver. + * + * See Boost.IO i/o state savers for a motivating compression. + */ + struct timezone_io_saver + { + + //! the type of the state to restore + typedef std::ios_base state_type; + //! the type of aspect to save + typedef timezone aspect_type; + + /** + * Explicit construction from an i/o stream. + * + * Store a reference to the i/o stream and the value of the associated @c timezone. + */ + explicit timezone_io_saver(state_type &s) : + s_save_(s), a_save_(get_timezone(s_save_)) + { + } + + /** + * Construction from an i/o stream and a @c timezone to restore. + * + * Stores a reference to the i/o stream and the value @c new_value to restore given as parameter. + */ + timezone_io_saver(state_type &s, aspect_type new_value) : + s_save_(s), a_save_(get_timezone(s_save_)) + { + set_timezone(s_save_, new_value); + } + + /** + * Destructor. + * + * Restores the i/o stream with the format to be restored. + */ + ~timezone_io_saver() + { + this->restore(); + } + + /** + * Restores the i/o stream with the timezone to be restored. + */ + void restore() + { + set_timezone(s_save_, a_save_); + } + private: + timezone_io_saver& operator=(timezone_io_saver const& rhs) ; + + state_type& s_save_; + aspect_type a_save_; + }; + + /** + * + * @param os + * @param tp + * @Effects Behaves as a formatted output function. After constructing a @c sentry object, if the @ sentry + * converts to true, calls to @c facet.put(os,os,os.fill(),tp) where @c facet is the @c time_point_put + * facet associated to @c os or a new created instance of the default @c time_point_put facet. + * @return @c os. + */ + template + std::basic_ostream& + operator<<(std::basic_ostream& os, const time_point& tp) + { + + bool failed = false; + BOOST_TRY + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + typename std::basic_ostream::sentry opfx(os); + if (bool(opfx)) + { + if (!std::has_facet >(os.getloc())) + { + if (time_point_put ().put(os, os, os.fill(), tp) .failed()) + { + err = std::ios_base::badbit; + } + } + else + { + if (std::use_facet >(os.getloc()) .put(os, os, os.fill(), tp).failed()) + { + err = std::ios_base::badbit; + } + } + os.width(0); + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + os.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) os.setstate(err); + return os; + } + BOOST_CATCH (...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) os.setstate(std::ios_base::failbit | std::ios_base::badbit); + return os; + } + + template + std::basic_istream& + operator>>(std::basic_istream& is, time_point& tp) + { + std::ios_base::iostate err = std::ios_base::goodbit; + + BOOST_TRY + { + typename std::basic_istream::sentry ipfx(is); + if (bool(ipfx)) + { + if (!std::has_facet >(is.getloc())) + { + time_point_get ().get(is, std::istreambuf_iterator(), is, err, tp); + } + else + { + std::use_facet >(is.getloc()).get(is, std::istreambuf_iterator(), is, + err, tp); + } + } + } + BOOST_CATCH (...) + { + bool flag = false; + BOOST_TRY + { + is.setstate(std::ios_base::failbit); + } + BOOST_CATCH (std::ios_base::failure ) + { + flag = true; + } + BOOST_CATCH_END + if (flag) throw; + } + BOOST_CATCH_END + if (err) is.setstate(err); + return is; + } + + + namespace detail + { + +//#if defined BOOST_CHRONO_INTERNAL_TIMEGM + + inline int32_t is_leap(int32_t year) + { + if(year % 400 == 0) + return 1; + if(year % 100 == 0) + return 0; + if(year % 4 == 0) + return 1; + return 0; + } + inline int32_t days_from_0(int32_t year) + { + year--; + return 365 * year + (year / 400) - (year/100) + (year / 4); + } + inline int32_t days_from_1970(int32_t year) + { + static const int32_t days_from_0_to_1970 = days_from_0(1970); + return days_from_0(year) - days_from_0_to_1970; + } + inline int32_t days_from_1jan(int32_t year,int32_t month,int32_t day) + { + static const int32_t days[2][12] = + { + { 0,31,59,90,120,151,181,212,243,273,304,334}, + { 0,31,60,91,121,152,182,213,244,274,305,335} + }; + + return days[is_leap(year)][month-1] + day - 1; + } + + inline time_t internal_timegm(std::tm const *t) + { + int year = t->tm_year + 1900; + int month = t->tm_mon; + if(month > 11) + { + year += month/12; + month %= 12; + } + else if(month < 0) + { + int years_diff = (-month + 11)/12; + year -= years_diff; + month+=12 * years_diff; + } + month++; + int day = t->tm_mday; + int day_of_year = days_from_1jan(year,month,day); + int days_since_epoch = days_from_1970(year) + day_of_year ; + + time_t seconds_in_day = 3600 * 24; + time_t result = seconds_in_day * days_since_epoch + 3600 * t->tm_hour + 60 * t->tm_min + t->tm_sec; + + return result; + } +//#endif + + /** + * from_ymd could be made more efficient by using a table + * day_count_table indexed by the y%400. + * This table could contain the day_count + * by*365 + by/4 - by/100 + by/400 + * + * from_ymd = (by/400)*days_by_400_years+day_count_table[by%400] + + * days_in_year_before[is_leap_table[by%400]][m-1] + d; + */ + inline unsigned days_before_years(int32_t y) + { + return y * 365 + y / 4 - y / 100 + y / 400; + } + + // Returns year/month/day triple in civil calendar + // Preconditions: z is number of days since 1970-01-01 and is in the range: + // [numeric_limits::min(), numeric_limits::max()-719468]. + template + //constexpr + void + inline civil_from_days(Int z, Int& y, unsigned& m, unsigned& d) BOOST_NOEXCEPT + { + BOOST_STATIC_ASSERT_MSG(std::numeric_limits::digits >= 18, + "This algorithm has not been ported to a 16 bit unsigned integer"); + BOOST_STATIC_ASSERT_MSG(std::numeric_limits::digits >= 20, + "This algorithm has not been ported to a 16 bit signed integer"); + z += 719468; + const Int era = (z >= 0 ? z : z - 146096) / 146097; + const unsigned doe = static_cast(z - era * 146097); // [0, 146096] + const unsigned yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] + y = static_cast(yoe) + era * 400; + const unsigned doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] + const unsigned mp = (5*doy + 2)/153; // [0, 11] + d = doy - (153*mp+2)/5 + 1; // [1, 31] + m = mp + (mp < 10 ? 3 : -9); // [1, 12] + y += (m <= 2); + --m; + } + inline std::tm * internal_gmtime(std::time_t const* t, std::tm *tm) + { + if (t==0) return 0; + if (tm==0) return 0; + +#if 0 + static const unsigned char + day_of_year_month[2][366] = + { + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 }, + + { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 + + } }; + + static const int32_t days_in_year_before[2][13] = + { + { -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364 }, + { -1, 30, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 } + }; +#endif + + const time_t seconds_in_day = 3600 * 24; + int32_t days_since_epoch = static_cast(*t / seconds_in_day); + int32_t hms = static_cast(*t - seconds_in_day*days_since_epoch); + if (hms < 0) { + days_since_epoch-=1; + hms = seconds_in_day+hms; + } + +#if 0 + int32_t x = days_since_epoch; + int32_t y = static_cast (static_cast (x + 2) * 400 + / 146097); + const int32_t ym1 = y - 1; + int32_t doy = x - days_before_years(y); + const int32_t doy1 = x - days_before_years(ym1); + const int32_t N = std::numeric_limits::digits - 1; + const int32_t mask1 = doy >> N; // arithmetic rshift - not portable - but nearly universal + const int32_t mask0 = ~mask1; + doy = (doy & mask0) | (doy1 & mask1); + y = (y & mask0) | (ym1 & mask1); + //y -= 32767 + 2; + y += 70; + tm->tm_year=y; + const int32_t leap = is_leap(y); + tm->tm_mon = day_of_year_month[leap][doy]-1; + tm->tm_mday = doy - days_in_year_before[leap][tm->tm_mon] ; +#else + int32_t y; + unsigned m, d; + civil_from_days(days_since_epoch, y, m, d); + tm->tm_year=y-1900; tm->tm_mon=m; tm->tm_mday=d; +#endif + + tm->tm_hour = hms / 3600; + const int ms = hms % 3600; + tm->tm_min = ms / 60; + tm->tm_sec = ms % 60; + + tm->tm_isdst = -1; + (void)mktime(tm); + return tm; + } + + } // detail +#ifndef BOOST_CHRONO_NO_UTC_TIMEPOINT + +#if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + + template + std::basic_ostream& + operator<<(std::basic_ostream& os, const time_point& tp) + { + typename std::basic_ostream::sentry ok(os); + if (bool(ok)) + { + bool failed = false; + BOOST_TRY + { + const CharT* pb = 0; //nullptr; + const CharT* pe = pb; + std::basic_string fmt = get_time_fmt (os); + pb = fmt.data(); + pe = pb + fmt.size(); + + timezone tz = get_timezone(os); + std::locale loc = os.getloc(); + time_t t = system_clock::to_time_t(time_point_cast(tp)); + std::tm tm; + std::memset(&tm, 0, sizeof(std::tm)); + if (tz == timezone::local) + { +#if defined BOOST_WINDOWS && ! defined(__CYGWIN__) +#if BOOST_MSVC < 1400 // localtime_s doesn't exist in vc7.1 + std::tm *tmp = 0; + if ((tmp=localtime(&t)) == 0) + failed = true; + else + tm =*tmp; +# else + if (localtime_s(&tm, &t) != 0) failed = true; +# endif +#else + if (localtime_r(&t, &tm) == 0) failed = true; +#endif + } + else + { +#if defined BOOST_CHRONO_INTERNAL_GMTIME + if (detail::internal_gmtime(&t, &tm) == 0) failed = true; + +#elif defined BOOST_WINDOWS && ! defined(__CYGWIN__) + std::tm *tmp = 0; + if((tmp = gmtime(&t)) == 0) + failed = true; + else + tm = *tmp; +#else + if (gmtime_r(&t, &tm) == 0) failed = true; + tm.tm_isdst = -1; + (void)mktime(&tm); + +#endif + + } + if (!failed) + { + const std::time_put& tpf = std::use_facet >(loc); + if (pb == pe) + { + CharT pattern[] = + { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; + pb = pattern; + pe = pb + sizeof (pattern) / sizeof(CharT); + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + if (!failed) + { + duration d = tp - system_clock::from_time_t(t) + seconds(tm.tm_sec); + if (d.count() < 10) os << CharT('0'); + //if (! os.good()) { + // throw "exception"; + //} + std::ios::fmtflags flgs = os.flags(); + os.setf(std::ios::fixed, std::ios::floatfield); + //if (! os.good()) { + //throw "exception"; + //} + os.precision(9); + os << d.count(); + //if (! os.good()) { + //throw "exception"; + //} + os.flags(flgs); + if (tz == timezone::local) + { + CharT sub_pattern[] = + { ' ', '%', 'z' }; + pb = sub_pattern; + pe = pb + +sizeof (sub_pattern) / sizeof(CharT); + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + } + else + { + CharT sub_pattern[] = + { ' ', '+', '0', '0', '0', '0', 0 }; + os << sub_pattern; + } + } + } + else + { + failed = tpf.put(os, os, os.fill(), &tm, pb, pe).failed(); + } + } + } + BOOST_CATCH (...) + { + failed = true; + } + BOOST_CATCH_END + if (failed) + { + os.setstate(std::ios_base::failbit | std::ios_base::badbit); + } + } + return os; + } +#endif + + namespace detail + { + + template + minutes extract_z(InputIterator& b, InputIterator e, std::ios_base::iostate& err, const std::ctype& ct) + { + int min = 0; + if (b != e) + { + char cn = ct.narrow(*b, 0); + if (cn != '+' && cn != '-') + { + err |= std::ios_base::failbit; + return minutes(0); + } + int sn = cn == '-' ? -1 : 1; + int hr = 0; + for (int i = 0; i < 2; ++i) + { + if (++b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return minutes(0); + } + cn = ct.narrow(*b, 0); + if (! ('0' <= cn && cn <= '9')) + { + err |= std::ios_base::failbit; + return minutes(0); + } + hr = hr * 10 + cn - '0'; + } + for (int i = 0; i < 2; ++i) + { + if (++b == e) + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + return minutes(0); + } + cn = ct.narrow(*b, 0); + if (! ('0' <= cn && cn <= '9')) + { + err |= std::ios_base::failbit; + return minutes(0); + } + min = min * 10 + cn - '0'; + } + if (++b == e) { + err |= std::ios_base::eofbit; + } + min += hr * 60; + min *= sn; + } + else + { + err |= std::ios_base::eofbit | std::ios_base::failbit; + } + return minutes(min); + } + + } // detail + +#if defined BOOST_CHRONO_PROVIDES_DATE_IO_FOR_SYSTEM_CLOCK_TIME_POINT + + template + std::basic_istream& + operator>>(std::basic_istream& is, time_point& tp) + { + typename std::basic_istream::sentry ok(is); + if (bool(ok)) + { + std::ios_base::iostate err = std::ios_base::goodbit; + BOOST_TRY + { + const CharT* pb = 0; //nullptr; + const CharT* pe = pb; + std::basic_string fmt = get_time_fmt (is); + pb = fmt.data(); + pe = pb + fmt.size(); + + timezone tz = get_timezone(is); + std::locale loc = is.getloc(); + const std::time_get& tg = std::use_facet >(loc); + const std::ctype& ct = std::use_facet >(loc); + tm tm; // {0} + std::memset(&tm, 0, sizeof(std::tm)); + + typedef std::istreambuf_iterator It; + if (pb == pe) + { + CharT pattern[] = + { '%', 'Y', '-', '%', 'm', '-', '%', 'd', ' ', '%', 'H', ':', '%', 'M', ':' }; + pb = pattern; + pe = pb + sizeof (pattern) / sizeof(CharT); + +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, pb, pe); +#else + tg.get(is, 0, is, err, &tm, pb, pe); +#endif + if (err & std::ios_base::failbit) goto exit; + fractional_seconds sec; + CharT c = CharT(); + std::ios::fmtflags flgs = is.flags(); + is.setf(std::ios::fixed, std::ios::floatfield); + is.precision(9); + is >> sec; + is.flags(flgs); + if (is.fail()) + { + err |= std::ios_base::failbit; + goto exit; + } + It i(is); + It eof; + c = *i; + if (++i == eof || c != ' ') + { + err |= std::ios_base::failbit; + goto exit; + } + minutes min = detail::extract_z(i, eof, err, ct); + + if (err & std::ios_base::failbit) goto exit; + time_t t; + +#if defined BOOST_CHRONO_INTERNAL_TIMEGM + t = detail::internal_timegm(&tm); +#else + t = timegm(&tm); +#endif + tp = time_point_cast( + system_clock::from_time_t(t) - min + round (duration (sec)) + ); + } + else + { + const CharT z[2] = + { '%', 'z' }; + const CharT* fz = std::search(pb, pe, z, z + 2); +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, pb, fz); +#else + tg.get(is, 0, is, err, &tm, pb, fz); +#endif + minutes minu(0); + if (fz != pe) + { + if (err != std::ios_base::goodbit) + { + err |= std::ios_base::failbit; + goto exit; + } + It i(is); + It eof; + minu = detail::extract_z(i, eof, err, ct); + if (err & std::ios_base::failbit) goto exit; + if (fz + 2 != pe) + { + if (err != std::ios_base::goodbit) + { + err |= std::ios_base::failbit; + goto exit; + } +#if defined BOOST_CHRONO_USES_INTERNAL_TIME_GET + const detail::time_get& dtg(tg); + dtg.get(is, 0, is, err, &tm, fz + 2, pe); +#else + tg.get(is, 0, is, err, &tm, fz + 2, pe); +#endif + if (err & std::ios_base::failbit) goto exit; + } + } + tm.tm_isdst = -1; + time_t t; + if (tz == timezone::utc || fz != pe) + { +#if defined BOOST_CHRONO_INTERNAL_TIMEGM + t = detail::internal_timegm(&tm); +#else + t = timegm(&tm); +#endif + } + else + { + t = mktime(&tm); + } + tp = time_point_cast( + system_clock::from_time_t(t) - minu + ); + } + } + BOOST_CATCH (...) + { + err |= std::ios_base::badbit | std::ios_base::failbit; + } + BOOST_CATCH_END + exit: is.setstate(err); + } + return is; + } + +#endif +#endif //UTC + } // chrono + +} + +#endif // header diff --git a/third-party/boost/boost/chrono/io/time_point_put.hpp b/third-party/boost/boost/chrono/io/time_point_put.hpp new file mode 100644 index 000000000..9c8c7cadd --- /dev/null +++ b/third-party/boost/boost/chrono/io/time_point_put.hpp @@ -0,0 +1,261 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +/** + * Duration formatting facet for output. + */ +#ifndef BOOST_CHRONO_IO_TIME_POINT_PUT_HPP +#define BOOST_CHRONO_IO_TIME_POINT_PUT_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + + /** + * @tparam ChatT a character type + * @tparam OutputIterator a model of @c OutputIterator + * + * The @c time_point_put facet provides facilities for formatted output of @c time_point values. + * The member function of @c time_point_put take a @c time_point and format it into character string representation. + * + */ + template > + class time_point_put: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string passed to member functions. + */ + typedef std::basic_string string_type; + /** + * Type of iterator used to write in the character buffer. + */ + typedef OutputIterator iter_type; + + /** + * Construct a time_point_put facet. + * @param refs + * @Effects Construct a time_point_put facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit time_point_put(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param tp the @c time_point + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Steps through the sequence from @c pattern to @c pat_end, + * identifying characters that are part of a pattern sequence. Each character + * that is not part of a pattern sequence is written to @c s immediately, and + * each pattern sequence, as it is identified, results in a call to + * @c put_duration or @c put_epoch; + * thus, pattern elements and other characters are interleaved in the output + * in the order in which they appear in the pattern. Pattern sequences are + * identified by converting each character @c c to a @c char value as if by + * @c ct.narrow(c,0), where @c ct is a reference to @c ctype obtained from + * @c ios.getloc(). The first character of each sequence is equal to @c '%', + * followed by a pattern specifier character @c spec, which can be @c 'd' for + * the duration value or @c 'e' for the epoch. + * For each valid pattern sequence identified, calls + * put_duration(s, ios, fill, tp.time_since_epoch()) or put_epoch(s, ios). + * + * @Returns An iterator pointing immediately after the last character produced. + */ + + template + iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point const& tp, const CharT* pattern, + const CharT* pat_end) const + { + if (std::has_facet >(ios.getloc())) + { + time_point_units const &facet = + std::use_facet >(ios.getloc()); + return put(facet, i, ios, fill, tp, pattern, pat_end); + } + else + { + time_point_units_default facet; + return put(facet, i, ios, fill, tp, pattern, pat_end); + } + } + + template + iter_type put(time_point_units const& units_facet, iter_type s, std::ios_base& ios, char_type fill, + time_point const& tp, const CharT* pattern, const CharT* pat_end) const + { + + const std::ctype& ct = std::use_facet >(ios.getloc()); + for (; pattern != pat_end; ++pattern) + { + if (ct.narrow(*pattern, 0) == '%') + { + if (++pattern == pat_end) + { + *s++ = pattern[-1]; + break; + } + char fmt = ct.narrow(*pattern, 0); + switch (fmt) + { + case 'd': + { + s = put_duration(s, ios, fill, tp.time_since_epoch()); + break; + } + case 'e': + { + s = put_epoch (units_facet, s, ios); + break; + } + default: + BOOST_ASSERT(false && "Boost::Chrono internal error."); + break; + } + } + else + *s++ = *pattern; + } + return s; + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param tp the @c time_point + * @param pattern begin of the formatting pattern + * @param pat_end end of the formatting pattern + * + * @Effects Stores the time_point pattern from the @c time_point_unit facet in let say @c str. Last as if + * @code + * return put(s, ios, dill, tp, str.data(), str.data() + str.size()); + * @endcode + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put(iter_type i, std::ios_base& ios, char_type fill, time_point const& tp) const + { + if (std::has_facet >(ios.getloc())) + { + time_point_units const &facet = + std::use_facet >(ios.getloc()); + std::basic_string str = facet.get_pattern(); + return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size()); + } + else + { + time_point_units_default facet; + std::basic_string str = facet.get_pattern(); + return put(facet, i, ios, fill, tp, str.data(), str.data() + str.size()); + } + } + + /** + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @param fill the character used as filler + * @param d the @c duration + * @Effects As if facet.put(s, ios, fill, d) where facet is the @c duration_put facet associated + * to the @c ios or a new instance of @c duration_put. + * @Returns An iterator pointing immediately after the last character produced. + */ + template + iter_type put_duration(iter_type i, std::ios_base& ios, char_type fill, duration const& d) const + { + if (std::has_facet >(ios.getloc())) + { + duration_put const &facet = std::use_facet >(ios.getloc()); + return facet.put(i, ios, fill, d); + } + else + { + duration_put facet; + return facet.put(i, ios, fill, d); + } + } + + /** + * + * @param i an output stream iterator + * @param ios a reference to a ios_base + * @Effects As if + * @code + * string_type str = facet.template get_epoch(); + * s=std::copy(str.begin(), str.end(), s); + * @endcode + * where facet is the @c time_point_units facet associated + * to the @c ios or a new instance of @c time_point_units_default. + * @Returns s, iterator pointing immediately after the last character produced. + */ + + template + iter_type put_epoch(iter_type i, std::ios_base& os) const + { + if (std::has_facet >(os.getloc())) + { + time_point_units const &facet = std::use_facet >(os.getloc()); + return put_epoch (facet, i, os); + } + else + { + time_point_units_default facet; + return put_epoch (facet, i, os); + } + } + + template + iter_type put_epoch(time_point_units const& facet, iter_type s, std::ios_base&) const + { + string_type str = facet.template get_epoch(); + s= std::copy(str.begin(), str.end(), s); + return s; + } + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * @Effects Destroy the facet + */ + ~time_point_put() + { + } + + }; + + template + std::locale::id time_point_put::id; + + } // chrono +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/time_point_units.hpp b/third-party/boost/boost/chrono/io/time_point_units.hpp new file mode 100644 index 000000000..6a4999a5e --- /dev/null +++ b/third-party/boost/boost/chrono/io/time_point_units.hpp @@ -0,0 +1,260 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// + +#ifndef BOOST_CHRONO_IO_TIME_POINT_UNITS_HPP +#define BOOST_CHRONO_IO_TIME_POINT_UNITS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + namespace chrono + { + /** + * customization point to the epoch associated to the clock @c Clock + * The default calls @c f.do_get_epoch(Clock()). The user can overload this function. + * @return the string epoch associated to the @c Clock + */ + template + std::basic_string get_epoch_custom(Clock, TPUFacet& f) + { + return f.do_get_epoch(Clock()); + } + + /** + * @c time_point_units facet gives useful information about the time_point pattern, + * the text associated to a time_point's epoch, + */ + template + class time_point_units: public std::locale::facet + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string used by member functions. + */ + typedef std::basic_string string_type; + + /** + * Unique identifier for this type of facet. + */ + static std::locale::id id; + + /** + * Construct a @c time_point_units facet. + * @param refs + * @Effects Construct a @c time_point_units facet. + * If the @c refs argument is @c 0 then destruction of the object is + * delegated to the @c locale, or locales, containing it. This allows + * the user to ignore lifetime management issues. On the other had, + * if @c refs is @c 1 then the object must be explicitly deleted; + * the @c locale will not do so. In this case, the object can be + * maintained across the lifetime of multiple locales. + */ + explicit time_point_units(size_t refs = 0) : + std::locale::facet(refs) + { + } + + /** + * @return the pattern to be used by default. + */ + virtual string_type get_pattern() const =0; + + /** + * @return the epoch associated to the clock @c Clock calling @c do_get_epoch(Clock()) + */ + template + string_type get_epoch() const + { + return get_epoch_custom(Clock(), *this); + } + + protected: + /** + * Destroy the facet. + */ + virtual ~time_point_units() {} + + public: + + /** + * + * @param c a dummy instance of @c system_clock. + * @return The epoch string associated to the @c system_clock. + */ + virtual string_type do_get_epoch(system_clock) const=0; + + /** + * + * @param c a dummy instance of @c steady_clock. + * @return The epoch string associated to the @c steady_clock. + */ + virtual string_type do_get_epoch(steady_clock) const=0; + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + /** + * + * @param c a dummy instance of @c process_real_cpu_clock. + * @return The epoch string associated to the @c process_real_cpu_clock. + */ + virtual string_type do_get_epoch(process_real_cpu_clock) const=0; +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + /** + * + * @param c a dummy instance of @c process_user_cpu_clock. + * @return The epoch string associated to the @c process_user_cpu_clock. + */ + virtual string_type do_get_epoch(process_user_cpu_clock) const=0; + /** + * + * @param c a dummy instance of @c process_system_cpu_clock. + * @return The epoch string associated to the @c process_system_cpu_clock. + */ + virtual string_type do_get_epoch(process_system_cpu_clock) const=0; + /** + * + * @param c a dummy instance of @c process_cpu_clock. + * @return The epoch string associated to the @c process_cpu_clock. + */ + virtual string_type do_get_epoch(process_cpu_clock) const=0; +#endif +#endif +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + /** + * + * @param c a dummy instance of @c thread_clock. + * @return The epoch string associated to the @c thread_clock. + */ + virtual string_type do_get_epoch(thread_clock) const=0; +#endif + + }; + + template + std::locale::id time_point_units::id; + + + // This class is used to define the strings for the default English + template + class time_point_units_default: public time_point_units + { + public: + /** + * Type of character the facet is instantiated on. + */ + typedef CharT char_type; + /** + * Type of character string returned by member functions. + */ + typedef std::basic_string string_type; + + explicit time_point_units_default(size_t refs = 0) : + time_point_units (refs) + { + } + ~time_point_units_default() {} + + /** + * @return the default pattern "%d%e". + */ + string_type get_pattern() const + { + static const CharT t[] = + { '%', 'd', '%', 'e' }; + static const string_type pattern(t, t + sizeof (t) / sizeof (t[0])); + + return pattern; + } + + //protected: + /** + * @param c a dummy instance of @c system_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(system_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c steady_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(steady_clock ) const + { + return clock_string::since(); + } + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + /** + * @param c a dummy instance of @c process_real_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_real_cpu_clock ) const + { + return clock_string::since(); + } +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + /** + * @param c a dummy instance of @c process_user_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_user_cpu_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c process_system_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_system_cpu_clock ) const + { + return clock_string::since(); + } + /** + * @param c a dummy instance of @c process_cpu_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(process_cpu_clock ) const + { + return clock_string::since(); + } + +#endif +#endif +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + /** + * @param c a dummy instance of @c thread_clock. + * @return The epoch string returned by @c clock_string::since(). + */ + string_type do_get_epoch(thread_clock ) const + { + return clock_string::since(); + } +#endif + + }; + + + } // chrono + +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/timezone.hpp b/third-party/boost/boost/chrono/io/timezone.hpp new file mode 100644 index 000000000..67975da96 --- /dev/null +++ b/third-party/boost/boost/chrono/io/timezone.hpp @@ -0,0 +1,30 @@ +// (C) Copyright Howard Hinnant +// (C) Copyright 2010-2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o to Boost + +#ifndef BOOST_CHRONO_IO_TIMEZONE_HPP +#define BOOST_CHRONO_IO_TIMEZONE_HPP +#include + +namespace boost +{ + namespace chrono + { + /** + * Scoped enumeration emulation stating whether the time_point for system_clock I/O is UTC or local. + */ + BOOST_SCOPED_ENUM_DECLARE_BEGIN(timezone) + { + utc, local + } + BOOST_SCOPED_ENUM_DECLARE_END(timezone) + + } // chrono +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/utility/ios_base_state_ptr.hpp b/third-party/boost/boost/chrono/io/utility/ios_base_state_ptr.hpp new file mode 100644 index 000000000..15c8ac4d6 --- /dev/null +++ b/third-party/boost/boost/chrono/io/utility/ios_base_state_ptr.hpp @@ -0,0 +1,437 @@ +// boost/chrono/utility/ios_base_pword_ptr.hpp ------------------------------------------------------------// + +// Copyright 2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP +#define BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP + +#include +#include + +/** + * + + + */ +namespace boost +{ + namespace chrono + { + namespace detail + { + + /** + * xalloc key holder. + */ + template + struct xalloc_key_holder + { + static int value; //< the xalloc value associated to T. + static bool initialized; //< whether the value has been initialized or not. + }; + + template + int xalloc_key_holder::value = 0; + + template + bool xalloc_key_holder::initialized = false; + + } + + /** + * xalloc key initialiazer. + * + * Declare a static variable of this type to ensure that the xalloc_key_holder is initialized correctly. + */ + template + struct xalloc_key_initializer + { + xalloc_key_initializer() + { + if (!detail::xalloc_key_holder::initialized) + { + detail::xalloc_key_holder::value = std::ios_base::xalloc(); + detail::xalloc_key_holder::initialized = true; + } + } + }; + /** + * @c ios_state_ptr is a smart pointer to a ios_base specific state. + */ + template + class ios_state_ptr + { + ios_state_ptr& operator=(ios_state_ptr const& rhs) ; + + public: + /** + * The pointee type + */ + typedef T element_type; + /** + * Explicit constructor. + * @param ios the ios + * @Effects Constructs a @c ios_state_ptr by storing the associated @c ios. + */ + explicit ios_state_ptr(std::ios_base& ios) : + ios_(ios) + { + + } + /** + * Nothing to do as xalloc index can not be removed. + */ + ~ios_state_ptr() + { + } + + /** + * @Effects Allocates the index if not already done. + * Registers the callback responsible of maintaining the state pointer coherency, if not already done. + * Retrieves the associated ios pointer + * @return the retrieved pointer statically casted to const. + */ + T const* get() const BOOST_NOEXCEPT + { + register_once(index(), ios_); + void* &pw = ios_.pword(index()); + if (pw == 0) + { + return 0; + } + return static_cast (pw); + } + /** + * @Effects Allocates the index if not already done. + * Registers the callback responsible of maintaining the state pointer coherency, if not already done. + * Retrieves the associated ios pointer + * @return the retrieved pointer. + */ + T * get() BOOST_NOEXCEPT + { + register_once(index(), ios_); + void* &pw = ios_.pword(index()); + if (pw == 0) + { + return 0; + } + return static_cast (pw); + } + /** + * @Effects as if @c return get(); + * @return the retrieved pointer. + */ + T * operator->()BOOST_NOEXCEPT + { + return get(); + } + /** + * @Effects as if @c return get(); + * @return the retrieved pointer. + */ + T const * operator->() const BOOST_NOEXCEPT + { + return get(); + } + + /** + * @Effects as if @c return *get(); + * @return a reference to the retrieved state. + * @Remark The behavior is undefined if @c get()==0. + */ + T & operator*() BOOST_NOEXCEPT + { + return *get(); + } + /** + * @Effects as if @c return *get(); + * @return a reference to the retrieved state. + * @Remark The behavior is undefined if @c get()==0. + */ + T const & operator *() const BOOST_NOEXCEPT + { + return *get(); + } + + /** + * @Effects reset the current pointer after storing in a temporary variable the pointer to the current state. + * @return the stored state pointer. + */ + T * release() BOOST_NOEXCEPT + { + void*& pw = ios_.pword(index()); + T* ptr = static_cast (pw); + pw = 0; + return ptr; + } + + /** + * + * @param new_ptr the new pointer. + * @Effects deletes the current state and replace it with the new one. + */ + void reset(T* new_ptr = 0)BOOST_NOEXCEPT + { + register_once(index(), ios_); + void*& pw = ios_.pword(index()); + delete static_cast (pw); + pw = new_ptr; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef T* (ios_state_ptr::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return (get()!=0)?&ios_state_ptr::release:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return (get()==0)?&ios_state_ptr::release:0; + } +#else + /** + * Explicit conversion to bool. + */ + explicit operator bool() const BOOST_NOEXCEPT + { + return get()!=0; + } +#endif + + std::ios_base& getios()BOOST_NOEXCEPT + { + return ios_; + } + std::ios_base& getios() const BOOST_NOEXCEPT + { + return ios_; + } + /** + * Implicit conversion to the ios_base + */ + operator std::ios_base&() BOOST_NOEXCEPT + { + return ios_; + } + /** + * Implicit conversion to the ios_base const + */ + operator std::ios_base&() const BOOST_NOEXCEPT + { + return ios_; + } + private: + static inline bool is_registerd(std::ios_base& ios) + { + long iw = ios.iword(index()); + return (iw == 1); + } + static inline void set_registered(std::ios_base& ios) + { + long& iw = ios.iword(index()); + iw = 1; + } + static inline void callback(std::ios_base::event evt, std::ios_base& ios, int index) + { + switch (evt) + { + case std::ios_base::erase_event: + { + void*& pw = ios.pword(index); + if (pw != 0) + { + T* ptr = static_cast (pw); + delete ptr; + pw = 0; + } + break; + } + case std::ios_base::copyfmt_event: + { + void*& pw = ios.pword(index); + if (pw != 0) + { + pw = new T(*static_cast (pw)); + } + break; + } + default: + break; + } + } + + static inline int index() + { + return detail::xalloc_key_holder::value; + } + + static inline void register_once(int indx, std::ios_base& ios) + { + // needs a mask registered + if (!is_registerd(ios)) + { + set_registered(ios); + ios.register_callback(callback, indx); + } + } + + + protected: + std::ios_base& ios_; + //static detail::xalloc_key_initializer xalloc_key_initializer_; + + }; + //template + //detail::xalloc_key_initializer ios_state_ptr::xalloc_key_initializer_; + + + /** + * @c ios_state_not_null_ptr is a non null variant of @c ios_state_ptr. + * @tparm T + * @Requires @c T must be @c DefaultConstructible and @c HeapAllocatable + */ + template + class ios_state_not_null_ptr: public ios_state_ptr + { + typedef ios_state_ptr base_type; + public: + explicit ios_state_not_null_ptr(std::ios_base& ios) : + base_type(ios) + { + if (this->get() == 0) + { + this->base_type::reset(new T()); + } + } + ~ios_state_not_null_ptr() + { + } + + void reset(T* new_value) BOOST_NOEXCEPT + { + BOOST_ASSERT(new_value!=0); + this->base_type::reset(new_value); + } + + }; + + /** + * This class is useful to associate some flags to an std::ios_base. + */ + template + class ios_flags + { + public: + /** + * + * @param ios the associated std::ios_base. + * @Postcondition flags()==0 + */ + explicit ios_flags(std::ios_base& ios) : + ios_(ios) + { + } + ~ios_flags() + { + } + /** + * @Returns The format control information. + */ + long flags() const BOOST_NOEXCEPT + { + return value(); + } + + /** + * @param v the new bit mask. + * @Postcondition v == flags(). + * @Returns The previous value of @c flags(). + */ + long flags(long v)BOOST_NOEXCEPT + { + long tmp = flags(); + ref() = v; + return tmp; + } + + /** + * @param v the new value + * @Effects: Sets @c v in @c flags(). + * @Returns: The previous value of @c flags(). + */ + long setf(long v) + { + long tmp = value(); + ref() |= v; + return tmp; + } + + /** + * @param mask the bit mask to clear. + * @Effects: Clears @c mask in @c flags(). + */ + void unsetf(long mask) + { + ref() &= ~mask; + } + + /** + * + * @param v + * @param mask + * @Effects: Clears @c mask in @c flags(), sets v & mask in @c flags(). + * @Returns: The previous value of flags(). + */ + long setf(long v, long mask) + { + long tmp = value(); + unsetf(mask); + ref() |= v & mask; + return tmp; + } + + /** + * implicit conversion to the @c ios_base + */ + operator std::ios_base&()BOOST_NOEXCEPT + { + return ios_; + } + /** + * implicit conversion to the @c ios_base const + */ + operator std::ios_base const&() const BOOST_NOEXCEPT + { + return ios_; + } + private: + long value() const BOOST_NOEXCEPT + { + return ios_.iword(index()); + } + long& ref()BOOST_NOEXCEPT + { + return ios_.iword(index()); + } + static inline int index() + { + return detail::xalloc_key_holder::value; + } + ios_flags& operator=(ios_flags const& rhs) ; + + std::ios_base& ios_; + //static detail::xalloc_key_initializer xalloc_key_initializer_; + + }; + //template + //detail::xalloc_key_initializer ios_flags::xalloc_key_initializer_; + + } // namespace chrono +} // namespace boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/utility/manip_base.hpp b/third-party/boost/boost/chrono/io/utility/manip_base.hpp new file mode 100644 index 000000000..f4a5f562c --- /dev/null +++ b/third-party/boost/boost/chrono/io/utility/manip_base.hpp @@ -0,0 +1,101 @@ +// boost/chrono/utility/manip_base.hpp ------------------------------------------------------------// + +// Copyright 2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_UTILITY_MANIP_BASE_PTR_HPP +#define BOOST_CHRONO_UTILITY_MANIP_BASE_PTR_HPP + +#include + +/** + * + + */ + +namespace boost +{ + namespace chrono + { + + /** + * manip is a manipulator mixin class following the CRTP. + * @tparam Final the derived from manip and final type + * + * @Example + * @code + + class mendl: public manip + { + public: + explicit mendl(size_t how_many) : + count(how_many) {} + template + void operator()(out_stream &out) const + { + for (size_t line = 0; line < count; ++line) + { + out.put(out.widen('\n')); + } + out.flush(); + } + private: + size_t count; + }; + + * @codeend + */ + template + class manip + { + public: + /** + * + * @param ios the io stream or ios_base. + * @Effects calls to the manipulator final functor. + */ + //template + void operator()(std::ios_base &ios) const + { + (*static_cast (this))(ios); + } + }; + + /** + * @c manip stream inserter + * @param out the io stream or ios_base. + * @param op the manipulator instance. + * @Effects if @c out is good calls to the manipulator functor @op. + * @return @c out + */ + template + out_stream &operator<<(out_stream &out, const manip &op) + { + if (out.good()) + op(out); + return out; + } + + /** + * @c manip stream extractor + * @param in the io stream or ios_base. + * @param op the manipulator instance. + * @Effects if @c in is good calls to the manipulator functor @op. + * @return @c in + */ + template + in_stream &operator>>(in_stream &in, const manip &op) + { + if (in.good()) + op(in); + return in; + } + + } // namespace chrono +} // namespace boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io/utility/to_string.hpp b/third-party/boost/boost/chrono/io/utility/to_string.hpp new file mode 100644 index 000000000..4717ba6ad --- /dev/null +++ b/third-party/boost/boost/chrono/io/utility/to_string.hpp @@ -0,0 +1,50 @@ +// boost/chrono/utility/to_string.hpp +// +// Copyright 2011 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). + +#ifndef BOOST_CHRONO_UTILITY_TO_STRING_HPP +#define BOOST_CHRONO_UTILITY_TO_STRING_HPP + +#include +#include +#include + +namespace boost +{ + namespace chrono + { + template + std::basic_string to_basic_string(T const&v) { + std::basic_stringstream sstr; + sstr << v; + return sstr.str(); + } + + template + std::string to_string(T const&v) { + return to_basic_string(v); + } +#ifndef BOOST_NO_STD_WSTRING + template + std::wstring to_wstring(T const&v) { + return to_basic_string(v); + } +#endif +#if BOOST_CHRONO_HAS_UNICODE_SUPPORT + template + std::basic_string to_u16string(T const&v) { + return to_basic_string(v); + } + template + std::basic_string to_u32string(T const&v) { + return to_basic_string(v); + } +#endif + } // chrono + +} // boost + +#endif // header diff --git a/third-party/boost/boost/chrono/io_v1/chrono_io.hpp b/third-party/boost/boost/chrono/io_v1/chrono_io.hpp new file mode 100644 index 000000000..afcc9ed7c --- /dev/null +++ b/third-party/boost/boost/chrono/io_v1/chrono_io.hpp @@ -0,0 +1,635 @@ + +// chrono_io +// +// (C) Copyright Howard Hinnant +// (C) Copyright 2010 Vicente J. Botet Escriba +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// This code was adapted by Vicente from Howard Hinnant's experimental work +// on chrono i/o under lvm/libc++ to Boost + +#ifndef BOOST_CHRONO_IO_V1_CHRONO_IO_HPP +#define BOOST_CHRONO_IO_V1_CHRONO_IO_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + +namespace chrono +{ + +template +class duration_punct + : public std::locale::facet +{ +public: + typedef std::basic_string string_type; + enum {use_long, use_short}; + +private: + bool use_short_; + string_type long_seconds_; + string_type long_minutes_; + string_type long_hours_; + string_type short_seconds_; + string_type short_minutes_; + string_type short_hours_; + + template + string_type short_name(Period) const + {return ::boost::ratio_string::short_name() + short_seconds_;} + + string_type short_name(ratio<1>) const {return short_seconds_;} + string_type short_name(ratio<60>) const {return short_minutes_;} + string_type short_name(ratio<3600>) const {return short_hours_;} + + template + string_type long_name(Period) const + {return ::boost::ratio_string::long_name() + long_seconds_;} + + string_type long_name(ratio<1>) const {return long_seconds_;} + string_type long_name(ratio<60>) const {return long_minutes_;} + string_type long_name(ratio<3600>) const {return long_hours_;} + + void init_C(); +public: + static std::locale::id id; + + explicit duration_punct(int use = use_long) + : use_short_(use==use_short) {init_C();} + + duration_punct(int use, + const string_type& long_seconds, const string_type& long_minutes, + const string_type& long_hours, const string_type& short_seconds, + const string_type& short_minutes, const string_type& short_hours); + + duration_punct(int use, const duration_punct& d); + + template + string_type short_name() const + {return short_name(typename Period::type());} + + template + string_type long_name() const + {return long_name(typename Period::type());} + + template + string_type plural() const + {return long_name(typename Period::type());} + + template + string_type singular() const + { + return string_type(long_name(typename Period::type()), 0, long_name(typename Period::type()).size()-1); + } + + template + string_type name() const + { + if (use_short_) return short_name(); + else { + return long_name(); + } + } + template + string_type name(D v) const + { + if (use_short_) return short_name(); + else + { + if (v==-1 || v==1) + return singular(); + else + return plural(); + } + } + + bool is_short_name() const {return use_short_;} + bool is_long_name() const {return !use_short_;} +}; + +template +std::locale::id +duration_punct::id; + +template +void +duration_punct::init_C() +{ + short_seconds_ = CharT('s'); + short_minutes_ = CharT('m'); + short_hours_ = CharT('h'); + const CharT s[] = {'s', 'e', 'c', 'o', 'n', 'd', 's'}; + const CharT m[] = {'m', 'i', 'n', 'u', 't', 'e', 's'}; + const CharT h[] = {'h', 'o', 'u', 'r', 's'}; + long_seconds_.assign(s, s + sizeof(s)/sizeof(s[0])); + long_minutes_.assign(m, m + sizeof(m)/sizeof(m[0])); + long_hours_.assign(h, h + sizeof(h)/sizeof(h[0])); +} + +template +duration_punct::duration_punct(int use, + const string_type& long_seconds, const string_type& long_minutes, + const string_type& long_hours, const string_type& short_seconds, + const string_type& short_minutes, const string_type& short_hours) + : use_short_(use==use_short), + long_seconds_(long_seconds), + long_minutes_(long_minutes), + long_hours_(long_hours), + short_seconds_(short_seconds), + short_minutes_(short_minutes), + short_hours_(short_hours) +{} + +template +duration_punct::duration_punct(int use, const duration_punct& d) + : use_short_(use==use_short), + long_seconds_(d.long_seconds_), + long_minutes_(d.long_minutes_), + long_hours_(d.long_hours_), + short_seconds_(d.short_seconds_), + short_minutes_(d.short_minutes_), + short_hours_(d.short_hours_) +{} + +template +std::basic_ostream& +duration_short(std::basic_ostream& os) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (std::has_facet(loc)) + { + const Facet& f = std::use_facet(loc); + if (f.is_long_name()) + os.imbue(std::locale(loc, new Facet(Facet::use_short, f))); + } + else + os.imbue(std::locale(loc, new Facet(Facet::use_short))); + return os; +} + +template +std::basic_ostream& +duration_long(std::basic_ostream& os) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (std::has_facet(loc)) + { + const Facet& f = std::use_facet(loc); + if (f.is_short_name()) + os.imbue(std::locale(loc, new Facet(Facet::use_long, f))); + } + return os; +} + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, const duration& d) +{ + typedef duration_punct Facet; + std::locale loc = os.getloc(); + if (!std::has_facet(loc)) + os.imbue(std::locale(loc, new Facet)); + const Facet& f = std::use_facet(os.getloc()); + return os << d.count() << ' ' << f.template name(d.count()); +} + +namespace chrono_detail { +template ::value> +struct duration_io_intermediate +{ + typedef Rep type; +}; + +template +struct duration_io_intermediate +{ + typedef typename mpl::if_c + < + is_floating_point::value, + long double, + typename mpl::if_c + < + is_signed::value, + long long, + unsigned long long + >::type + >::type type; +}; + +template +typename enable_if, bool>::type +reduce(intermediate_type& r, unsigned long long& den, std::ios_base::iostate& err) +{ + typedef typename common_type::type common_type_t; + + // Reduce r * num / den + common_type_t t = integer::gcd(common_type_t(r), common_type_t(den)); + r /= t; + den /= t; + if (den != 1) + { + // Conversion to Period is integral and not exact + err |= std::ios_base::failbit; + return false; + } + return true; +} +template +typename disable_if, bool>::type +reduce(intermediate_type& , unsigned long long& , std::ios_base::iostate& ) +{ + return true; +} + +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, duration& d) +{ + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + typedef duration_punct Facet; + std::locale loc = is.getloc(); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (!std::has_facet(loc)) { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.imbue(std::locale(loc, new Facet)); + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + loc = is.getloc(); + const Facet& f = std::use_facet(loc); + typedef typename chrono_detail::duration_io_intermediate::type intermediate_type; + intermediate_type r; + std::ios_base::iostate err = std::ios_base::goodbit; + // read value into r + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is >> r; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (is.good()) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // now determine unit + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (i != e && *i == ' ') // mandatory ' ' after value + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + ++i; + if (i != e) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // unit is num / den (yet to be determined) + unsigned long long num = 0; + unsigned long long den = 0; + if (*i == '[') + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // parse [N/D]s or [N/D]seconds format + ++i; + CharT x; + is >> num >> x >> den; + if (!is.good() || (x != '/')) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit); + return is; + } + i = in_iterator(is); + if (*i != ']') + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit); + return is; + } + ++i; + const std::basic_string units[] = + { + f.template singular >(), + f.template plural >(), + f.template short_name >() + }; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + const std::basic_string* k = chrono_detail::scan_keyword(i, e, + units, units + sizeof(units)/sizeof(units[0]), + //~ std::use_facet >(loc), + err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err); + switch ((k - units) / 3) + { + case 0: + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + break; + default: + is.setstate(err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + } + else + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // parse SI name, short or long + const std::basic_string units[] = + { + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular(), + f.template plural(), + f.template short_name(), + f.template singular >(), + f.template plural >(), + f.template short_name >(), + f.template singular >(), + f.template plural >(), + f.template short_name >(), + f.template singular >(), + f.template plural >(), + f.template short_name >() + }; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + const std::basic_string* k = chrono_detail::scan_keyword(i, e, + units, units + sizeof(units)/sizeof(units[0]), + //~ std::use_facet >(loc), + err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + switch ((k - units) / 3) + { + case 0: + num = 1ULL; + den = 1000000000000000000ULL; + break; + case 1: + num = 1ULL; + den = 1000000000000000ULL; + break; + case 2: + num = 1ULL; + den = 1000000000000ULL; + break; + case 3: + num = 1ULL; + den = 1000000000ULL; + break; + case 4: + num = 1ULL; + den = 1000000ULL; + break; + case 5: + num = 1ULL; + den = 1000ULL; + break; + case 6: + num = 1ULL; + den = 100ULL; + break; + case 7: + num = 1ULL; + den = 10ULL; + break; + case 8: + num = 10ULL; + den = 1ULL; + break; + case 9: + num = 100ULL; + den = 1ULL; + break; + case 10: + num = 1000ULL; + den = 1ULL; + break; + case 11: + num = 1000000ULL; + den = 1ULL; + break; + case 12: + num = 1000000000ULL; + den = 1ULL; + break; + case 13: + num = 1000000000000ULL; + den = 1ULL; + break; + case 14: + num = 1000000000000000ULL; + den = 1ULL; + break; + case 15: + num = 1000000000000000000ULL; + den = 1ULL; + break; + case 16: + num = 1; + den = 1; + break; + case 17: + num = 60; + den = 1; + break; + case 18: + num = 3600; + den = 1; + break; + default: + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // unit is num/den + // r should be multiplied by (num/den) / Period + // Reduce (num/den) / Period to lowest terms + unsigned long long gcd_n1_n2 = integer::gcd(num, Period::num); + unsigned long long gcd_d1_d2 = integer::gcd(den, Period::den); + num /= gcd_n1_n2; + den /= gcd_d1_d2; + unsigned long long n2 = Period::num / gcd_n1_n2; + unsigned long long d2 = Period::den / gcd_d1_d2; + if (num > (std::numeric_limits::max)() / d2 || + den > (std::numeric_limits::max)() / n2) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // (num/den) / Period overflows + is.setstate(err|is.failbit); + return is; + } + num *= d2; + den *= n2; + + typedef typename common_type::type common_type_t; + + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // num / den is now factor to multiply by r + if (!chrono_detail::reduce(r, den, err)) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + + //if (r > ((duration_values::max)() / num)) + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (chrono::detail::gt(r,((duration_values::max)() / num))) + { + // Conversion to Period overflowed + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(err|is.failbit); + return is; + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + common_type_t t = r * num; + t /= den; + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + + if (t > duration_values::zero()) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if ( (duration_values::max)() < Rep(t)) + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // Conversion to Period overflowed + is.setstate(err|is.failbit); + return is; + } + } + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + // Success! Store it. + d = duration(Rep(t)); + is.setstate(err); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + else { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + is.setstate(is.failbit | is.eofbit); + return is; + } + } + else + { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + if (i == e) + is.setstate(is.failbit|is.eofbit); + else + is.setstate(is.failbit); + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + return is; + } + } + else { + //std::cerr << __FILE__ << "[" << __LINE__ << "]"<< std::endl; + //is.setstate(is.failbit); + return is; + } +} + + +template +std::basic_ostream& +operator<<(std::basic_ostream& os, + const time_point& tp) +{ + return os << tp.time_since_epoch() << clock_string::since(); +} + +template +std::basic_istream& +operator>>(std::basic_istream& is, + time_point& tp) +{ + Duration d; + is >> d; + if (is.good()) + { + const std::basic_string units=clock_string::since(); + std::ios_base::iostate err = std::ios_base::goodbit; + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + std::ptrdiff_t k = chrono_detail::scan_keyword(i, e, + &units, &units + 1, + //~ std::use_facet >(is.getloc()), + err) - &units; + is.setstate(err); + if (k == 1) + { + is.setstate(err | is.failbit); + // failed to read epoch string + return is; + } + tp = time_point(d); + } + else + is.setstate(is.failbit); + return is; +} +} // chrono + +} + +#endif // BOOST_CHRONO_CHRONO_IO_HPP diff --git a/third-party/boost/boost/chrono/process_cpu_clocks.hpp b/third-party/boost/boost/chrono/process_cpu_clocks.hpp new file mode 100644 index 000000000..93d3c94ac --- /dev/null +++ b/third-party/boost/boost/chrono/process_cpu_clocks.hpp @@ -0,0 +1,525 @@ +// boost/chrono/process_cpu_clocks.hpp -----------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba +// Copyright (c) Microsoft Corporation 2014 + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/system for documentation. + +#ifndef BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP +#define BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP + +#include + + +#if defined(BOOST_CHRONO_HAS_PROCESS_CLOCKS) + +#include +#include +#include +#include +#include +#include +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + +namespace boost { namespace chrono { + + class BOOST_CHRONO_DECL process_real_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; + +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + class BOOST_CHRONO_DECL process_user_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; + + class BOOST_CHRONO_DECL process_system_cpu_clock { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; +#endif + + template + struct process_times + : arithmetic, + multiplicative, Rep, + less_than_comparable > > > + { + //typedef process_real_cpu_clock::rep rep; + typedef Rep rep; + process_times() + : real(0) + , user(0) + , system(0){} + +#if ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 + template + explicit process_times( + Rep2 r) + : real(r) + , user(r) + , system(r){} +#endif + template + explicit process_times( + process_times const& rhs) + : real(rhs.real) + , user(rhs.user) + , system(rhs.system){} + process_times( + rep r, + rep u, + rep s) + : real(r) + , user(u) + , system(s){} + + rep real; // real (i.e wall clock) time + rep user; // user cpu time + rep system; // system cpu time + +#if ! defined BOOST_CHRONO_DONT_PROVIDES_DEPRECATED_IO_SINCE_V2_0_0 + operator rep() const + { + return real; + } +#endif + template + bool operator==(process_times const& rhs) { + return (real==rhs.real && + user==rhs.user && + system==rhs.system); + } + + process_times& operator+=( + process_times const& rhs) + { + real+=rhs.real; + user+=rhs.user; + system+=rhs.system; + return *this; + } + process_times& operator-=( + process_times const& rhs) + { + real-=rhs.real; + user-=rhs.user; + system-=rhs.system; + return *this; + } + process_times& operator*=( + process_times const& rhs) + { + real*=rhs.real; + user*=rhs.user; + system*=rhs.system; + return *this; + } + process_times& operator*=(rep const& rhs) + { + real*=rhs; + user*=rhs; + system*=rhs; + return *this; + } + process_times& operator/=(process_times const& rhs) + { + real/=rhs.real; + user/=rhs.user; + system/=rhs.system; + return *this; + } + process_times& operator/=(rep const& rhs) + { + real/=rhs; + user/=rhs; + system/=rhs; + return *this; + } + bool operator<(process_times const & rhs) const + { + if (real < rhs.real) return true; + if (real > rhs.real) return false; + if (user < rhs.user) return true; + if (user > rhs.user) return false; + if (system < rhs.system) return true; + else return false; + } + + template + void print(std::basic_ostream& os) const + { + os << "{"<< real <<";"<< user <<";"<< system << "}"; + } + + template + void read(std::basic_istream& is) + { + typedef std::istreambuf_iterator in_iterator; + in_iterator i(is); + in_iterator e; + if (i == e || *i++ != '{') // mandatory '{' + { + is.setstate(is.failbit | is.eofbit); + return; + } + CharT x,y,z; + is >> real >> x >> user >> y >> system >> z; + if (!is.good() || (x != ';')|| (y != ';')|| (z != '}')) + { + is.setstate(is.failbit); + } + } + }; +} +template +struct common_type< + chrono::process_times, + chrono::process_times +> +{ + typedef chrono::process_times::type> type; +}; + +template +struct common_type< + chrono::process_times, + Rep2 +> +{ + typedef chrono::process_times::type> type; +}; + +template +struct common_type< + Rep1, + chrono::process_times +> +{ + typedef chrono::process_times::type> type; +}; + + +namespace chrono +{ + template + inline BOOST_CONSTEXPR + bool + operator==(const duration, Period1>& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration + >()(duration(lhs.count().real), duration(rhs.count().real)); + } + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration, Period1>& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_eq< + duration, duration >()(duration(lhs.count().real), rhs); + } + + template + inline BOOST_CONSTEXPR + bool + operator==(const duration& lhs, + const duration, Period2>& rhs) + { + return rhs == lhs; + } + + + // Duration < + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration, Period1>& lhs, + const duration& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(duration(lhs.count().real), rhs); + } + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration >()(lhs, duration(rhs.count().real)); + } + + template + inline BOOST_CONSTEXPR + bool + operator< (const duration, Period1>& lhs, + const duration, Period2>& rhs) + { + return boost::chrono::detail::duration_lt< + duration, duration + >()(duration(lhs.count().real), duration(rhs.count().real)); + } + + + typedef process_times process_cpu_clock_times; +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + class BOOST_CHRONO_DECL process_cpu_clock + { + public: + + typedef process_cpu_clock_times times; + typedef boost::chrono::duration duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec ); +#endif + }; +#endif + + template + std::basic_ostream& + operator<<(std::basic_ostream& os, + process_times const& rhs) + { + rhs.print(os); + return os; + } + + template + std::basic_istream& + operator>>(std::basic_istream& is, + process_times& rhs) + { + rhs.read(is); + return is; + } + + template + struct duration_values > + { + typedef process_times Res; + public: + static Res zero() + { + return Res(); + } + static Res max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::max)()); + } + static Res min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::min)(), + (std::numeric_limits::min)(), + (std::numeric_limits::min)()); + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'r', 'e', 'a', 'l', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + +#if ! BOOST_OS_WINDOWS || BOOST_PLAT_WINDOWS_DESKTOP + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'u', 's', 'e', 'r', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT u[] = + { 'p', 'r', 'o', 'c', 'e', 's', 's', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'p', 'r', 'o', 'c', 'e', 's', 's', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; +#endif + +} // namespace chrono +} // namespace boost + +namespace std { + + template + struct numeric_limits > + { + typedef boost::chrono::process_times Res; + + public: + static const bool is_specialized = true; + static Res min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::min)(), + (std::numeric_limits::min)(), + (std::numeric_limits::min)()); + } + static Res max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return Res((std::numeric_limits::max)(), + (std::numeric_limits::max)(), + (std::numeric_limits::max)()); + } + static Res lowest() BOOST_NOEXCEPT_OR_NOTHROW + { + return (min)(); + } + static const int digits = std::numeric_limits::digits+ + std::numeric_limits::digits+ + std::numeric_limits::digits; + static const int digits10 = std::numeric_limits::digits10+ + std::numeric_limits::digits10+ + std::numeric_limits::digits10; + static const bool is_signed = Rep::is_signed; + static const bool is_integer = Rep::is_integer; + static const bool is_exact = Rep::is_exact; + static const int radix = 0; + //~ static Res epsilon() throw() { return 0; } + //~ static Res round_error() throw() { return 0; } + //~ static const int min_exponent = 0; + //~ static const int min_exponent10 = 0; + //~ static const int max_exponent = 0; + //~ static const int max_exponent10 = 0; + //~ static const bool has_infinity = false; + //~ static const bool has_quiet_NaN = false; + //~ static const bool has_signaling_NaN = false; + //~ static const float_denorm_style has_denorm = denorm_absent; + //~ static const bool has_denorm_loss = false; + //~ static Res infinity() throw() { return 0; } + //~ static Res quiet_NaN() throw() { return 0; } + //~ static Res signaling_NaN() throw() { return 0; } + //~ static Res denorm_min() throw() { return 0; } + //~ static const bool is_iec559 = false; + //~ static const bool is_bounded = true; + //~ static const bool is_modulo = false; + //~ static const bool traps = false; + //~ static const bool tinyness_before = false; + //~ static const float_round_style round_style = round_toward_zero; + + }; +} + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif +#endif + +#endif // BOOST_CHRONO_PROCESS_CPU_CLOCKS_HPP diff --git a/third-party/boost/boost/chrono/round.hpp b/third-party/boost/boost/chrono/round.hpp new file mode 100644 index 000000000..09741fcf0 --- /dev/null +++ b/third-party/boost/boost/chrono/round.hpp @@ -0,0 +1,59 @@ +// boost/chrono/round.hpp ------------------------------------------------------------// + +// (C) Copyright Howard Hinnant +// Copyright 2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/chrono for documentation. + +#ifndef BOOST_CHRONO_ROUND_HPP +#define BOOST_CHRONO_ROUND_HPP + +#include +#include +//#include + +namespace boost +{ + namespace chrono + { + + /** + * rounds to nearest, to even on tie + */ + template + To round(const duration& d) + { + typedef typename common_type >::type result_type; + result_type diff0; + result_type diff1; + + To t0 = duration_cast(d); + To t1 = t0; + if (t0>d) { + --t1; + diff0 = t0 - d; + diff1 = d - t1; + } else { + ++t1; + diff0 = d - t0; + diff1 = t1 - d; + } + + if (diff0 == diff1) + { + if (t0.count() & 1) + return t1; + return t0; + } + else if (diff0 < diff1) + return t0; + return t1; + } + + } // namespace chrono +} // namespace boost + +#endif diff --git a/third-party/boost/boost/chrono/system_clocks.hpp b/third-party/boost/boost/chrono/system_clocks.hpp new file mode 100644 index 000000000..3087311ff --- /dev/null +++ b/third-party/boost/boost/chrono/system_clocks.hpp @@ -0,0 +1,233 @@ +// boost/chrono/system_clocks.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + +/* + +TODO: + + * Fully implement error handling, with test cases. + * Consider issues raised by Michael Marcin: + + > In the past I've seen QueryPerformanceCounter give incorrect results, + > especially with SpeedStep processors on laptops. This was many years ago and + > might have been fixed by service packs and drivers. + > + > Typically you check the results of QPC against GetTickCount to see if the + > results are reasonable. + > http://support.microsoft.com/kb/274323 + > + > I've also heard of problems with QueryPerformanceCounter in multi-processor + > systems. + > + > I know some people SetThreadAffinityMask to 1 for the current thread call + > their QueryPerformance* functions then restore SetThreadAffinityMask. This + > seems horrible to me because it forces your program to jump to another + > physical processor if it isn't already on cpu0 but they claim it worked well + > in practice because they called the timing functions infrequently. + > + > In the past I have chosen to use timeGetTime with timeBeginPeriod(1) for + > high resolution timers to avoid these issues. + +*/ + +#ifndef BOOST_CHRONO_SYSTEM_CLOCKS_HPP +#define BOOST_CHRONO_SYSTEM_CLOCKS_HPP + +#include +#include +#include +#include +#include + +#include + +# if defined( BOOST_CHRONO_POSIX_API ) +# if ! defined(CLOCK_REALTIME) && ! defined (__hpux__) +# error does not supply CLOCK_REALTIME +# endif +# endif + +#ifdef BOOST_CHRONO_WINDOWS_API +// The system_clock tick is 100 nanoseconds +# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::duration > +#else +# define BOOST_SYSTEM_CLOCK_DURATION boost::chrono::nanoseconds +#endif + +// this must occur after all of the includes and before any code appears: +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + // Clocks + class system_clock; +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + class steady_clock; +#endif + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + typedef steady_clock high_resolution_clock; // as permitted by [time.clock.hires] +#else + typedef system_clock high_resolution_clock; // as permitted by [time.clock.hires] +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9.5 Clocks [time.clock] // +// // +//----------------------------------------------------------------------------// + +// If you're porting, clocks are the system-specific (non-portable) part. +// You'll need to know how to get the current time and implement that under now(). +// You'll need to know what units (tick period) and representation makes the most +// sense for your clock and set those accordingly. +// If you know how to map this clock to time_t (perhaps your clock is std::time, which +// makes that trivial), then you can fill out system_clock's to_time_t() and from_time_t(). + +//----------------------------------------------------------------------------// +// 20.9.5.1 Class system_clock [time.clock.system] // +//----------------------------------------------------------------------------// + + class BOOST_CHRONO_DECL system_clock + { + public: + typedef BOOST_SYSTEM_CLOCK_DURATION duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = false; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec); +#endif + + static BOOST_CHRONO_INLINE std::time_t to_time_t(const time_point& t) BOOST_NOEXCEPT; + static BOOST_CHRONO_INLINE time_point from_time_t(std::time_t t) BOOST_NOEXCEPT; + }; + +//----------------------------------------------------------------------------// +// 20.9.5.2 Class steady_clock [time.clock.steady] // +//----------------------------------------------------------------------------// + +// As permitted by [time.clock.steady] +// The class steady_clock is conditionally supported. + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + class BOOST_CHRONO_DECL steady_clock + { + public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = true; + + static BOOST_CHRONO_INLINE time_point now() BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now(system::error_code & ec); +#endif + }; +#endif +//----------------------------------------------------------------------------// +// 20.9.5.3 Class high_resolution_clock [time.clock.hires] // +//----------------------------------------------------------------------------// + +// As permitted, steady_clock or system_clock is a typedef for high_resolution_clock. +// See synopsis. + + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT u[] = + { 's', 'y', 's', 't', 'e', 'm', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + static const CharT + u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'J', 'a', 'n', ' ', '1', ',', ' ', '1', '9', '7', '0' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + }; + +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY + + template + struct clock_string + { + static std::basic_string name() + { + static const CharT + u[] = + { 's', 't', 'e', 'a', 'd', 'y', '_', 'c', 'l', 'o', 'c', 'k' }; + static const std::basic_string str(u, u + sizeof(u) + / sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 'b', 'o', 'o', 't' }; + const std::basic_string str(u, u + sizeof(u) / sizeof(u[0])); + return str; + } + }; + +#endif + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif + +#endif // BOOST_CHRONO_SYSTEM_CLOCKS_HPP diff --git a/third-party/boost/boost/chrono/thread_clock.hpp b/third-party/boost/boost/chrono/thread_clock.hpp new file mode 100644 index 000000000..207697b4c --- /dev/null +++ b/third-party/boost/boost/chrono/thread_clock.hpp @@ -0,0 +1,75 @@ +// boost/chrono/thread_clock.hpp -----------------------------------------------------------// + +// Copyright 2009-2011 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org/libs/system for documentation. + +#include + +#ifndef BOOST_CHRONO_THREAD_CLOCK_HPP +#define BOOST_CHRONO_THREAD_CLOCK_HPP + +#if defined(BOOST_CHRONO_HAS_THREAD_CLOCK) + +#include +#include +#include +#include +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // must be the last #include +#endif + +namespace boost { namespace chrono { + +class BOOST_CHRONO_DECL thread_clock { +public: + typedef nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + BOOST_STATIC_CONSTEXPR bool is_steady = BOOST_CHRONO_THREAD_CLOCK_IS_STEADY; + + static BOOST_CHRONO_INLINE time_point now( ) BOOST_NOEXCEPT; +#if !defined BOOST_CHRONO_DONT_PROVIDE_HYBRID_ERROR_HANDLING + static BOOST_CHRONO_INLINE time_point now( system::error_code & ec ); +#endif +}; + +template +struct clock_string +{ + static std::basic_string name() + { + static const CharT u[] = + { 't', 'h', 'r', 'e', 'a', 'd', '_', + 'c', 'l','o', 'c', 'k'}; + static const std::basic_string str(u, u + sizeof(u)/sizeof(u[0])); + return str; + } + static std::basic_string since() + { + const CharT u[] = + { ' ', 's', 'i', 'n', 'c', 'e', ' ', 't', 'h', 'r', 'e', 'a', 'd', ' ', 's', 't', 'a', 'r', 't', '-', 'u', 'p'}; + const std::basic_string str(u, u + sizeof(u)/sizeof(u[0])); + return str; + } +}; + +} // namespace chrono +} // namespace boost + + +#ifndef BOOST_CHRONO_HEADER_ONLY +#include // pops abi_prefix.hpp pragmas +#else +#include +#endif + +#endif + +#endif // BOOST_CHRONO_THREAD_CLOCK_HPP diff --git a/third-party/boost/boost/chrono/time_point.hpp b/third-party/boost/boost/chrono/time_point.hpp new file mode 100644 index 000000000..fc230955d --- /dev/null +++ b/third-party/boost/boost/chrono/time_point.hpp @@ -0,0 +1,379 @@ +// duration.hpp --------------------------------------------------------------// + +// Copyright 2008 Howard Hinnant +// Copyright 2008 Beman Dawes +// Copyright 2009-2012 Vicente J. Botet Escriba + +// Distributed under the Boost Software License, Version 1.0. +// See http://www.boost.org/LICENSE_1_0.txt + +/* + +This code was derived by Beman Dawes from Howard Hinnant's time2_demo prototype. +Many thanks to Howard for making his code available under the Boost license. +The original code was modified to conform to Boost conventions and to section +20.9 Time utilities [time] of the C++ committee's working paper N2798. +See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2798.pdf. + +time2_demo contained this comment: + + Much thanks to Andrei Alexandrescu, + Walter Brown, + Peter Dimov, + Jeff Garland, + Terry Golubiewski, + Daniel Krugler, + Anthony Williams. +*/ + + +#ifndef BOOST_CHRONO_TIME_POINT_HPP +#define BOOST_CHRONO_TIME_POINT_HPP + +#include + +#ifndef BOOST_CHRONO_HEADER_ONLY +// this must occur after all of the includes and before any code appears: +#include // must be the last #include +#endif + +//----------------------------------------------------------------------------// +// // +// 20.9 Time utilities [time] // +// synopsis // +// // +//----------------------------------------------------------------------------// + +namespace boost { +namespace chrono { + + template + class time_point; + + +} // namespace chrono + + +// common_type trait specializations + +template + struct common_type, + chrono::time_point >; + + +//----------------------------------------------------------------------------// +// 20.9.2.3 Specializations of common_type [time.traits.specializations] // +//----------------------------------------------------------------------------// + + +template +struct common_type, + chrono::time_point > +{ + typedef chrono::time_point::type> type; +}; + + + +namespace chrono { + + // time_point arithmetic + template + inline BOOST_CONSTEXPR + time_point >::type> + operator+( + const time_point& lhs, + const duration& rhs); + template + inline BOOST_CONSTEXPR + time_point, Duration2>::type> + operator+( + const duration& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + time_point >::type> + operator-( + const time_point& lhs, + const duration& rhs); + template + inline BOOST_CONSTEXPR + typename common_type::type + operator-( + const time_point& lhs, + const time_point& rhs); + + // time_point comparisons + template + inline BOOST_CONSTEXPR + bool operator==( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator!=( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator< ( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator<=( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator> ( + const time_point& lhs, + const time_point& rhs); + template + inline BOOST_CONSTEXPR + bool operator>=( + const time_point& lhs, + const time_point& rhs); + + // time_point_cast + template + inline BOOST_CONSTEXPR + time_point time_point_cast(const time_point& t); + +//----------------------------------------------------------------------------// +// // +// 20.9.4 Class template time_point [time.point] // +// // +//----------------------------------------------------------------------------// + + template + class time_point + { + BOOST_CHRONO_STATIC_ASSERT(boost::chrono::detail::is_duration::value, + BOOST_CHRONO_SECOND_TEMPLATE_PARAMETER_OF_TIME_POINT_MUST_BE_A_BOOST_CHRONO_DURATION, (Duration)); + public: + typedef Clock clock; + typedef Duration duration; + typedef typename duration::rep rep; + typedef typename duration::period period; + typedef Duration difference_type; + + private: + duration d_; + + public: + BOOST_FORCEINLINE BOOST_CONSTEXPR + time_point() : d_(duration::zero()) + {} + BOOST_FORCEINLINE BOOST_CONSTEXPR + explicit time_point(const duration& d) + : d_(d) + {} + + // conversions + template + BOOST_FORCEINLINE BOOST_CONSTEXPR + time_point(const time_point& t + , typename boost::enable_if + < + boost::is_convertible + >::type* = 0 + ) + : d_(t.time_since_epoch()) + { + } + // observer + + BOOST_CONSTEXPR + duration time_since_epoch() const + { + return d_; + } + + // arithmetic + +#ifdef BOOST_CHRONO_EXTENSIONS + BOOST_CONSTEXPR + time_point operator+() const {return *this;} + BOOST_CONSTEXPR + time_point operator-() const {return time_point(-d_);} + time_point& operator++() {++d_; return *this;} + time_point operator++(int) {return time_point(d_++);} + time_point& operator--() {--d_; return *this;} + time_point operator--(int) {return time_point(d_--);} + + time_point& operator+=(const rep& r) {d_ += duration(r); return *this;} + time_point& operator-=(const rep& r) {d_ -= duration(r); return *this;} + +#endif + + time_point& operator+=(const duration& d) {d_ += d; return *this;} + time_point& operator-=(const duration& d) {d_ -= d; return *this;} + + // special values + + static BOOST_CHRONO_LIB_CONSTEXPR time_point + min BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return time_point((duration::min)()); + } + static BOOST_CHRONO_LIB_CONSTEXPR time_point + max BOOST_PREVENT_MACRO_SUBSTITUTION () + { + return time_point((duration::max)()); + } + }; + +//----------------------------------------------------------------------------// +// 20.9.4.5 time_point non-member arithmetic [time.point.nonmember] // +//----------------------------------------------------------------------------// + + // time_point operator+(time_point x, duration y); + + template + inline BOOST_CONSTEXPR + time_point >::type> + operator+(const time_point& lhs, + const duration& rhs) + { + typedef typename common_type >::type CDuration; + typedef time_point< + Clock, + CDuration + > TimeResult; + return TimeResult(lhs.time_since_epoch() + CDuration(rhs)); + } + + // time_point operator+(duration x, time_point y); + + template + inline BOOST_CONSTEXPR + time_point, Duration2>::type> + operator+(const duration& lhs, + const time_point& rhs) + { + return rhs + lhs; + } + + // time_point operator-(time_point x, duration y); + + template + inline BOOST_CONSTEXPR + time_point >::type> + operator-(const time_point& lhs, + const duration& rhs) + { + return lhs + (-rhs); + } + + // duration operator-(time_point x, time_point y); + + template + inline BOOST_CONSTEXPR + typename common_type::type + operator-(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() - rhs.time_since_epoch(); + } + +//----------------------------------------------------------------------------// +// 20.9.4.6 time_point comparisons [time.point.comparisons] // +//----------------------------------------------------------------------------// + + // time_point == + + template + inline BOOST_CONSTEXPR + bool + operator==(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() == rhs.time_since_epoch(); + } + + // time_point != + + template + inline BOOST_CONSTEXPR + bool + operator!=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs == rhs); + } + + // time_point < + + template + inline BOOST_CONSTEXPR + bool + operator<(const time_point& lhs, + const time_point& rhs) + { + return lhs.time_since_epoch() < rhs.time_since_epoch(); + } + + // time_point > + + template + inline BOOST_CONSTEXPR + bool + operator>(const time_point& lhs, + const time_point& rhs) + { + return rhs < lhs; + } + + // time_point <= + + template + inline BOOST_CONSTEXPR + bool + operator<=(const time_point& lhs, + const time_point& rhs) + { + return !(rhs < lhs); + } + + // time_point >= + + template + inline BOOST_CONSTEXPR + bool + operator>=(const time_point& lhs, + const time_point& rhs) + { + return !(lhs < rhs); + } + +//----------------------------------------------------------------------------// +// 20.9.4.7 time_point_cast [time.point.cast] // +//----------------------------------------------------------------------------// + + template + inline BOOST_CONSTEXPR + time_point + time_point_cast(const time_point& t) + { + return time_point( + duration_cast(t.time_since_epoch())); + } + +} // namespace chrono +} // namespace boost + +#ifndef BOOST_CHRONO_HEADER_ONLY +// the suffix header occurs after all of our code: +#include // pops abi_prefix.hpp pragmas +#endif + +#endif // BOOST_CHRONO_TIME_POINT_HPP diff --git a/third-party/boost/boost/chrono/typeof/boost/chrono/chrono.hpp b/third-party/boost/boost/chrono/typeof/boost/chrono/chrono.hpp new file mode 100644 index 000000000..0b0d27480 --- /dev/null +++ b/third-party/boost/boost/chrono/typeof/boost/chrono/chrono.hpp @@ -0,0 +1,32 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 20010. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Based on the unique_threader/unique_joiner design from of Kevlin Henney (n1883) +// +// See http://www.boost.org/libs/chrono for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CHRONO_TYPEOF_CHRONO_HPP +#define BOOST_CHRONO_TYPEOF_CHRONO_HPP + +#include +#include + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::chrono::duration, (typename)(typename)) +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::chrono::time_point, (typename)(typename)) +#if 0 +BOOST_TYPEOF_REGISTER_TYPE(boost::chrono::system_clock) +#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY +BOOST_TYPEOF_REGISTER_TYPE(boost::chrono::steady_clock) +#endif +BOOST_TYPEOF_REGISTER_TYPE(boost::chrono::high_resolution_clock) + +#endif +#endif diff --git a/third-party/boost/boost/chrono/typeof/boost/ratio.hpp b/third-party/boost/boost/chrono/typeof/boost/ratio.hpp new file mode 100644 index 000000000..d61ce2440 --- /dev/null +++ b/third-party/boost/boost/chrono/typeof/boost/ratio.hpp @@ -0,0 +1,24 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 20010. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or +// copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Based on the unique_threader/unique_joiner design from of Kevlin Henney (n1883) +// +// See http://www.boost.org/libs/chrono for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CHRONO_TYPEOF_RATIO_HPP +#define BOOST_CHRONO_TYPEOF_RATIO_HPP + +#include +#include + +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() + +BOOST_TYPEOF_REGISTER_TEMPLATE(boost::ratio, (boost::intmax_t)(boost::intmax_t)) + +#endif diff --git a/third-party/boost/boost/circular_buffer.hpp b/third-party/boost/boost/circular_buffer.hpp new file mode 100644 index 000000000..f0530805e --- /dev/null +++ b/third-party/boost/boost/circular_buffer.hpp @@ -0,0 +1,62 @@ +// Circular buffer library header file. + +// Copyright (c) 2003-2008 Jan Gaspar + +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See www.boost.org/libs/circular_buffer for documentation. + +#if !defined(BOOST_CIRCULAR_BUFFER_HPP) +#define BOOST_CIRCULAR_BUFFER_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#include +#include + +// BOOST_CB_ENABLE_DEBUG: Debug support control. +#if !defined(BOOST_CB_ENABLE_DEBUG) + #define BOOST_CB_ENABLE_DEBUG 0 +#endif + +// BOOST_CB_ASSERT: Runtime assertion. +#if BOOST_CB_ENABLE_DEBUG + #include + #define BOOST_CB_ASSERT(Expr) BOOST_ASSERT(Expr) +#else + #define BOOST_CB_ASSERT(Expr) ((void)0) +#endif + +// BOOST_CB_IS_CONVERTIBLE: Check if Iterator::value_type is convertible to Type. +#if BOOST_WORKAROUND(__BORLANDC__, <= 0x0550) || BOOST_WORKAROUND(__MWERKS__, <= 0x2407) + #define BOOST_CB_IS_CONVERTIBLE(Iterator, Type) ((void)0) +#else + #include + #include + #define BOOST_CB_IS_CONVERTIBLE(Iterator, Type) \ + BOOST_STATIC_ASSERT((is_convertible::value_type, Type>::value)) +#endif + +// BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS: +// Check if the STL provides templated iterator constructors for its containers. +#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) + #define BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS BOOST_STATIC_ASSERT(false); +#else + #define BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS ((void)0); +#endif + +#include +#include +#include +#include + +#undef BOOST_CB_ASSERT_TEMPLATED_ITERATOR_CONSTRUCTORS +#undef BOOST_CB_IS_CONVERTIBLE +#undef BOOST_CB_ASSERT + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_HPP) diff --git a/third-party/boost/boost/circular_buffer_fwd.hpp b/third-party/boost/boost/circular_buffer_fwd.hpp new file mode 100644 index 000000000..621fb953e --- /dev/null +++ b/third-party/boost/boost/circular_buffer_fwd.hpp @@ -0,0 +1,43 @@ +// Forward declaration of the circular buffer and its adaptor. + +// Copyright (c) 2003-2008 Jan Gaspar + +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See www.boost.org/libs/circular_buffer for documentation. + +#if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP) +#define BOOST_CIRCULAR_BUFFER_FWD_HPP + +#if defined(_MSC_VER) + #pragma once +#endif + +#include +#if !defined(BOOST_NO_STD_ALLOCATOR) + #include +#else + #include +#endif + +namespace boost { + +#if !defined(BOOST_NO_STD_ALLOCATOR) + #define BOOST_CB_DEFAULT_ALLOCATOR(T) std::allocator +#else + #define BOOST_CB_DEFAULT_ALLOCATOR(T) BOOST_DEDUCED_TYPENAME std::vector::allocator_type +#endif + +template +class circular_buffer; + +template +class circular_buffer_space_optimized; + +#undef BOOST_CB_DEFAULT_ALLOCATOR + +} // namespace boost + +#endif // #if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP) diff --git a/third-party/boost/boost/compressed_pair.hpp b/third-party/boost/boost/compressed_pair.hpp new file mode 100644 index 000000000..a7be0f2ba --- /dev/null +++ b/third-party/boost/boost/compressed_pair.hpp @@ -0,0 +1,20 @@ +// (C) Copyright Steve Cleary, Beman Dawes, Howard Hinnant & John Maddock 2000. +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). +// +// See http://www.boost.org/libs/utility for most recent version including documentation. + +// See boost/detail/compressed_pair.hpp +// for full copyright notices. + +#ifndef BOOST_COMPRESSED_PAIR_HPP +#define BOOST_COMPRESSED_PAIR_HPP + +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#include + +#endif // BOOST_COMPRESSED_PAIR_HPP diff --git a/third-party/boost/boost/compute.hpp b/third-party/boost/boost/compute.hpp new file mode 100644 index 000000000..83e17acc1 --- /dev/null +++ b/third-party/boost/boost/compute.hpp @@ -0,0 +1,44 @@ +//---------------------------------------------------------------------------// +// Copyright (c) 2013 Kyle Lutz +// +// Distributed under the Boost Software License, Version 1.0 +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// See http://boostorg.github.com/compute for more information. +//---------------------------------------------------------------------------// + +#ifndef BOOST_COMPUTE_HPP +#define BOOST_COMPUTE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_COMPUTE_HAVE_HDR_CL_EXT +#include +#endif + +#endif // BOOST_COMPUTE_HPP diff --git a/third-party/boost/boost/concept/assert.hpp b/third-party/boost/boost/concept/assert.hpp new file mode 100644 index 000000000..36c3b03f3 --- /dev/null +++ b/third-party/boost/boost/concept/assert.hpp @@ -0,0 +1,45 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_ASSERT_DWA2006430_HPP +# define BOOST_CONCEPT_ASSERT_DWA2006430_HPP + +# include +# include + +// The old protocol used a constraints() member function in concept +// checking classes. If the compiler supports SFINAE, we can detect +// that function and seamlessly support the old concept checking +// classes. In this release, backward compatibility with the old +// concept checking classes is enabled by default, where available. +// The old protocol is deprecated, though, and backward compatibility +// will no longer be the default in the next release. + +# if !defined(BOOST_NO_OLD_CONCEPT_SUPPORT) \ + && !defined(BOOST_NO_SFINAE) \ + \ + && !(BOOST_WORKAROUND(__GNUC__, == 3) && BOOST_WORKAROUND(__GNUC_MINOR__, < 4)) + +// Note: gcc-2.96 through 3.3.x have some SFINAE, but no ability to +// check for the presence of particularmember functions. + +# define BOOST_OLD_CONCEPT_SUPPORT + +# endif + +# ifdef BOOST_MSVC +# include +# elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) +# include +# else +# include +# endif + + // Usage, in class or function context: + // + // BOOST_CONCEPT_ASSERT((UnaryFunctionConcept)); + // +# define BOOST_CONCEPT_ASSERT(ModelInParens) \ + BOOST_CONCEPT_ASSERT_FN(void(*)ModelInParens) + +#endif // BOOST_CONCEPT_ASSERT_DWA2006430_HPP diff --git a/third-party/boost/boost/concept/detail/backward_compatibility.hpp b/third-party/boost/boost/concept/detail/backward_compatibility.hpp new file mode 100644 index 000000000..66d573ef4 --- /dev/null +++ b/third-party/boost/boost/concept/detail/backward_compatibility.hpp @@ -0,0 +1,16 @@ +// Copyright David Abrahams 2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_BACKWARD_COMPATIBILITY_DWA200968_HPP +# define BOOST_CONCEPT_BACKWARD_COMPATIBILITY_DWA200968_HPP + +namespace boost +{ + namespace concepts {} + +# if defined(BOOST_HAS_CONCEPTS) && !defined(BOOST_CONCEPT_NO_BACKWARD_KEYWORD) + namespace concept = concepts; +# endif +} // namespace boost::concept + +#endif // BOOST_CONCEPT_BACKWARD_COMPATIBILITY_DWA200968_HPP diff --git a/third-party/boost/boost/concept/detail/borland.hpp b/third-party/boost/boost/concept/detail/borland.hpp new file mode 100644 index 000000000..300d5d405 --- /dev/null +++ b/third-party/boost/boost/concept/detail/borland.hpp @@ -0,0 +1,30 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_DETAIL_BORLAND_DWA2006429_HPP +# define BOOST_CONCEPT_DETAIL_BORLAND_DWA2006429_HPP + +# include +# include + +namespace boost { namespace concepts { + +template +struct require; + +template +struct require +{ + enum { instantiate = sizeof((((Model*)0)->~Model()), 3) }; +}; + +# define BOOST_CONCEPT_ASSERT_FN( ModelFnPtr ) \ + enum \ + { \ + BOOST_PP_CAT(boost_concept_check,__LINE__) = \ + boost::concepts::require::instantiate \ + } + +}} // namespace boost::concept + +#endif // BOOST_CONCEPT_DETAIL_BORLAND_DWA2006429_HPP diff --git a/third-party/boost/boost/concept/detail/concept_def.hpp b/third-party/boost/boost/concept/detail/concept_def.hpp new file mode 100644 index 000000000..750561ee3 --- /dev/null +++ b/third-party/boost/boost/concept/detail/concept_def.hpp @@ -0,0 +1,34 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_DETAIL_CONCEPT_DEF_DWA200651_HPP +# define BOOST_CONCEPT_DETAIL_CONCEPT_DEF_DWA200651_HPP +# include +# include +# include +# include +#endif // BOOST_CONCEPT_DETAIL_CONCEPT_DEF_DWA200651_HPP + +// BOOST_concept(SomeName, (p1)(p2)...(pN)) +// +// Expands to "template struct SomeName" +// +// Also defines an equivalent SomeNameConcept for backward compatibility. +// Maybe in the next release we can kill off the "Concept" suffix for good. +# define BOOST_concept(name, params) \ + template < BOOST_PP_SEQ_FOR_EACH_I(BOOST_CONCEPT_typename,~,params) > \ + struct name; /* forward declaration */ \ + \ + template < BOOST_PP_SEQ_FOR_EACH_I(BOOST_CONCEPT_typename,~,params) > \ + struct BOOST_PP_CAT(name,Concept) \ + : name< BOOST_PP_SEQ_ENUM(params) > \ + { \ + }; \ + \ + template < BOOST_PP_SEQ_FOR_EACH_I(BOOST_CONCEPT_typename,~,params) > \ + struct name + +// Helper for BOOST_concept, above. +# define BOOST_CONCEPT_typename(r, ignored, index, t) \ + BOOST_PP_COMMA_IF(index) typename t + diff --git a/third-party/boost/boost/concept/detail/concept_undef.hpp b/third-party/boost/boost/concept/detail/concept_undef.hpp new file mode 100644 index 000000000..713db8912 --- /dev/null +++ b/third-party/boost/boost/concept/detail/concept_undef.hpp @@ -0,0 +1,5 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# undef BOOST_concept_typename +# undef BOOST_concept diff --git a/third-party/boost/boost/concept/detail/general.hpp b/third-party/boost/boost/concept/detail/general.hpp new file mode 100644 index 000000000..eeb08750f --- /dev/null +++ b/third-party/boost/boost/concept/detail/general.hpp @@ -0,0 +1,77 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_DETAIL_GENERAL_DWA2006429_HPP +# define BOOST_CONCEPT_DETAIL_GENERAL_DWA2006429_HPP + +# include +# include +# include + +# ifdef BOOST_OLD_CONCEPT_SUPPORT +# include +# include +# endif + +// This implementation works on Comeau and GCC, all the way back to +// 2.95 +namespace boost { namespace concepts { + +template +struct requirement_; + +namespace detail +{ + template struct instantiate {}; +} + +template +struct requirement +{ + static void failed() { ((Model*)0)->~Model(); } +}; + +struct failed {}; + +template +struct requirement +{ + static void failed() { ((Model*)0)->~Model(); } +}; + +# ifdef BOOST_OLD_CONCEPT_SUPPORT + +template +struct constraint +{ + static void failed() { ((Model*)0)->constraints(); } +}; + +template +struct requirement_ + : boost::conditional< + concepts::not_satisfied::value + , constraint + , requirement + >::type +{}; + +# else + +// For GCC-2.x, these can't have exactly the same name +template +struct requirement_ + : requirement +{}; + +# endif + +# define BOOST_CONCEPT_ASSERT_FN( ModelFnPtr ) \ + typedef ::boost::concepts::detail::instantiate< \ + &::boost::concepts::requirement_::failed> \ + BOOST_PP_CAT(boost_concept_check,__LINE__) \ + BOOST_ATTRIBUTE_UNUSED + +}} + +#endif // BOOST_CONCEPT_DETAIL_GENERAL_DWA2006429_HPP diff --git a/third-party/boost/boost/concept/detail/has_constraints.hpp b/third-party/boost/boost/concept/detail/has_constraints.hpp new file mode 100644 index 000000000..dc2c20714 --- /dev/null +++ b/third-party/boost/boost/concept/detail/has_constraints.hpp @@ -0,0 +1,50 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_DETAIL_HAS_CONSTRAINTS_DWA2006429_HPP +# define BOOST_CONCEPT_DETAIL_HAS_CONSTRAINTS_DWA2006429_HPP + +# include +# include +# include + +namespace boost { namespace concepts { + +namespace detail +{ + +// Here we implement the metafunction that detects whether a +// constraints metafunction exists + typedef char yes; + typedef char (&no)[2]; + + template + struct wrap_constraints {}; + +#if BOOST_WORKAROUND(__SUNPRO_CC, <= 0x580) || defined(__CUDACC__) + // Work around the following bogus error in Sun Studio 11, by + // turning off the has_constraints function entirely: + // Error: complex expression not allowed in dependent template + // argument expression + inline no has_constraints_(...); +#else + template + inline yes has_constraints_(Model*, wrap_constraints* = 0); + inline no has_constraints_(...); +#endif +} + +// This would be called "detail::has_constraints," but it has a strong +// tendency to show up in error messages. +template +struct not_satisfied +{ + BOOST_STATIC_CONSTANT( + bool + , value = sizeof( detail::has_constraints_((Model*)0) ) == sizeof(detail::yes) ); + typedef boost::integral_constant type; +}; + +}} // namespace boost::concepts::detail + +#endif // BOOST_CONCEPT_DETAIL_HAS_CONSTRAINTS_DWA2006429_HPP diff --git a/third-party/boost/boost/concept/detail/msvc.hpp b/third-party/boost/boost/concept/detail/msvc.hpp new file mode 100644 index 000000000..933ac02a5 --- /dev/null +++ b/third-party/boost/boost/concept/detail/msvc.hpp @@ -0,0 +1,123 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_CHECK_MSVC_DWA2006429_HPP +# define BOOST_CONCEPT_CHECK_MSVC_DWA2006429_HPP + +# include +# include +# include + +# ifdef BOOST_OLD_CONCEPT_SUPPORT +# include +# include +# endif + +# ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable:4100) +# endif + +namespace boost { namespace concepts { + + +template +struct check +{ + virtual void failed(Model* x) + { + x->~Model(); + } +}; + +# ifndef BOOST_NO_PARTIAL_SPECIALIZATION +struct failed {}; +template +struct check +{ + virtual void failed(Model* x) + { + x->~Model(); + } +}; +# endif + +# ifdef BOOST_OLD_CONCEPT_SUPPORT + +namespace detail +{ + // No need for a virtual function here, since evaluating + // not_satisfied below will have already instantiated the + // constraints() member. + struct constraint {}; +} + +template +struct require + : boost::conditional< + not_satisfied::value + , detail::constraint +# ifndef BOOST_NO_PARTIAL_SPECIALIZATION + , check +# else + , check +# endif + >::type +{}; + +# else + +template +struct require +# ifndef BOOST_NO_PARTIAL_SPECIALIZATION + : check +# else + : check +# endif +{}; + +# endif + +# if BOOST_WORKAROUND(BOOST_MSVC, == 1310) + +// +// The iterator library sees some really strange errors unless we +// do things this way. +// +template +struct require +{ + virtual void failed(Model*) + { + require(); + } +}; + +# define BOOST_CONCEPT_ASSERT_FN( ModelFnPtr ) \ +enum \ +{ \ + BOOST_PP_CAT(boost_concept_check,__LINE__) = \ + sizeof(::boost::concepts::require) \ +} + +# else // Not vc-7.1 + +template +require +require_(void(*)(Model)); + +# define BOOST_CONCEPT_ASSERT_FN( ModelFnPtr ) \ +enum \ +{ \ + BOOST_PP_CAT(boost_concept_check,__LINE__) = \ + sizeof(::boost::concepts::require_((ModelFnPtr)0)) \ +} + +# endif +}} + +# ifdef BOOST_MSVC +# pragma warning(pop) +# endif + +#endif // BOOST_CONCEPT_CHECK_MSVC_DWA2006429_HPP diff --git a/third-party/boost/boost/concept/requires.hpp b/third-party/boost/boost/concept/requires.hpp new file mode 100644 index 000000000..365ce1004 --- /dev/null +++ b/third-party/boost/boost/concept/requires.hpp @@ -0,0 +1,93 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_REQUIRES_DWA2006430_HPP +# define BOOST_CONCEPT_REQUIRES_DWA2006430_HPP + +# include +# include +# include + +namespace boost { + +// unaryfunptr_arg_type from parameter/aux_/parenthesized_type.hpp + +namespace ccheck_aux { + +// A metafunction that transforms void(*)(T) -> T +template +struct unaryfunptr_arg_type; + +template +struct unaryfunptr_arg_type +{ + typedef Arg type; +}; + +template <> +struct unaryfunptr_arg_type +{ + typedef void type; +}; + +} // namespace ccheck_aux + +// Template for use in handwritten assertions +template +struct requires_ : More +{ + BOOST_CONCEPT_ASSERT((Model)); +}; + +// Template for use by macros, where models must be wrapped in parens. +// This isn't in namespace detail to keep extra cruft out of resulting +// error messages. +template +struct _requires_ +{ + enum { value = 0 }; + BOOST_CONCEPT_ASSERT_FN(ModelFn); +}; + +template +struct Requires_ : ::boost::ccheck_aux::unaryfunptr_arg_type +{ +}; + +# if BOOST_WORKAROUND(BOOST_INTEL_WIN, BOOST_TESTED_AT(1010)) +# define BOOST_CONCEPT_REQUIRES_(r,data,t) | (::boost::_requires_::value) +# else +# define BOOST_CONCEPT_REQUIRES_(r,data,t) + (::boost::_requires_::value) +# endif + +#if defined(NDEBUG) + +# define BOOST_CONCEPT_REQUIRES(models, result) \ + typename ::boost::ccheck_aux::unaryfunptr_arg_type::type + +#elif BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + +// Same thing as below without the initial typename +# define BOOST_CONCEPT_REQUIRES(models, result) \ + ::boost::Requires_< \ + (0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \ + ::boost::ccheck_aux::unaryfunptr_arg_type \ + >::type + +#else + +// This just ICEs on MSVC6 :( +# define BOOST_CONCEPT_REQUIRES(models, result) \ + typename ::boost::Requires_< \ + (0 BOOST_PP_SEQ_FOR_EACH(BOOST_CONCEPT_REQUIRES_, ~, models)), \ + void(*)result \ + >::type + +#endif + +// C++0x proposed syntax changed. This supports an older usage +#define BOOST_CONCEPT_WHERE(models,result) BOOST_CONCEPT_REQUIRES(models,result) + +} // namespace boost::concept_check + +#endif // BOOST_CONCEPT_REQUIRES_DWA2006430_HPP diff --git a/third-party/boost/boost/concept/usage.hpp b/third-party/boost/boost/concept/usage.hpp new file mode 100644 index 000000000..373de63a9 --- /dev/null +++ b/third-party/boost/boost/concept/usage.hpp @@ -0,0 +1,36 @@ +// Copyright David Abrahams 2006. Distributed under the Boost +// Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONCEPT_USAGE_DWA2006919_HPP +# define BOOST_CONCEPT_USAGE_DWA2006919_HPP + +# include +# include +# include + +namespace boost { namespace concepts { + +template +struct usage_requirements +{ + ~usage_requirements() { ((Model*)0)->~Model(); } +}; + +# if BOOST_WORKAROUND(__GNUC__, <= 3) + +# define BOOST_CONCEPT_USAGE(model) \ + model(); /* at least 2.96 and 3.4.3 both need this :( */ \ + BOOST_CONCEPT_ASSERT((boost::concepts::usage_requirements)); \ + ~model() + +# else + +# define BOOST_CONCEPT_USAGE(model) \ + BOOST_CONCEPT_ASSERT((boost::concepts::usage_requirements)); \ + ~model() + +# endif + +}} // namespace boost::concepts + +#endif // BOOST_CONCEPT_USAGE_DWA2006919_HPP diff --git a/third-party/boost/boost/concept_archetype.hpp b/third-party/boost/boost/concept_archetype.hpp new file mode 100644 index 000000000..a9d1808f3 --- /dev/null +++ b/third-party/boost/boost/concept_archetype.hpp @@ -0,0 +1,670 @@ +// +// (C) Copyright Jeremy Siek 2000. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Revision History: +// +// 17 July 2001: Added const to some member functions. (Jeremy Siek) +// 05 May 2001: Removed static dummy_cons object. (Jeremy Siek) + +// See http://www.boost.org/libs/concept_check for documentation. + +#ifndef BOOST_CONCEPT_ARCHETYPES_HPP +#define BOOST_CONCEPT_ARCHETYPES_HPP + +#include +#include +#include +#include // iterator tags +#include // std::ptrdiff_t + +namespace boost { + + //=========================================================================== + // Basic Archetype Classes + + namespace detail { + class dummy_constructor { }; + } + + // A type that models no concept. The template parameter + // is only there so that null_archetype types can be created + // that have different type. + template + class null_archetype { + private: + null_archetype() { } + null_archetype(const null_archetype&) { } + null_archetype& operator=(const null_archetype&) { return *this; } + public: + null_archetype(detail::dummy_constructor) { } +#ifndef __MWERKS__ + template + friend void dummy_friend(); // just to avoid warnings +#endif + }; + + // This is a helper class that provides a way to get a reference to + // an object. The get() function will never be called at run-time + // (nothing in this file will) so this seemingly very bad function + // is really quite innocent. The name of this class needs to be + // changed. + template + class static_object + { + public: + static T& get() + { +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) + return *reinterpret_cast(0); +#else + static char d[sizeof(T)]; + return *reinterpret_cast(d); +#endif + } + }; + + template > + class default_constructible_archetype : public Base { + public: + default_constructible_archetype() + : Base(static_object::get()) { } + default_constructible_archetype(detail::dummy_constructor x) : Base(x) { } + }; + + template > + class assignable_archetype : public Base { + assignable_archetype() { } + assignable_archetype(const assignable_archetype&) { } + public: + assignable_archetype& operator=(const assignable_archetype&) { + return *this; + } + assignable_archetype(detail::dummy_constructor x) : Base(x) { } + }; + + template > + class copy_constructible_archetype : public Base { + public: + copy_constructible_archetype() + : Base(static_object::get()) { } + copy_constructible_archetype(const copy_constructible_archetype&) + : Base(static_object::get()) { } + copy_constructible_archetype(detail::dummy_constructor x) : Base(x) { } + }; + + template > + class sgi_assignable_archetype : public Base { + public: + sgi_assignable_archetype(const sgi_assignable_archetype&) + : Base(static_object::get()) { } + sgi_assignable_archetype& operator=(const sgi_assignable_archetype&) { + return *this; + } + sgi_assignable_archetype(const detail::dummy_constructor& x) : Base(x) { } + }; + + struct default_archetype_base { + default_archetype_base(detail::dummy_constructor) { } + }; + + // Careful, don't use same type for T and Base. That results in the + // conversion operator being invalid. Since T is often + // null_archetype, can't use null_archetype for Base. + template + class convertible_to_archetype : public Base { + private: + convertible_to_archetype() { } + convertible_to_archetype(const convertible_to_archetype& ) { } + convertible_to_archetype& operator=(const convertible_to_archetype&) + { return *this; } + public: + convertible_to_archetype(detail::dummy_constructor x) : Base(x) { } + operator const T&() const { return static_object::get(); } + }; + + template + class convertible_from_archetype : public Base { + private: + convertible_from_archetype() { } + convertible_from_archetype(const convertible_from_archetype& ) { } + convertible_from_archetype& operator=(const convertible_from_archetype&) + { return *this; } + public: + convertible_from_archetype(detail::dummy_constructor x) : Base(x) { } + convertible_from_archetype(const T&) { } + convertible_from_archetype& operator=(const T&) + { return *this; } + }; + + class boolean_archetype { + public: + boolean_archetype(const boolean_archetype&) { } + operator bool() const { return true; } + boolean_archetype(detail::dummy_constructor) { } + private: + boolean_archetype() { } + boolean_archetype& operator=(const boolean_archetype&) { return *this; } + }; + + template > + class equality_comparable_archetype : public Base { + public: + equality_comparable_archetype(detail::dummy_constructor x) : Base(x) { } + }; + template + boolean_archetype + operator==(const equality_comparable_archetype&, + const equality_comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + template + boolean_archetype + operator!=(const equality_comparable_archetype&, + const equality_comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + + + template > + class equality_comparable2_first_archetype : public Base { + public: + equality_comparable2_first_archetype(detail::dummy_constructor x) + : Base(x) { } + }; + template > + class equality_comparable2_second_archetype : public Base { + public: + equality_comparable2_second_archetype(detail::dummy_constructor x) + : Base(x) { } + }; + template + boolean_archetype + operator==(const equality_comparable2_first_archetype&, + const equality_comparable2_second_archetype&) + { + return boolean_archetype(static_object::get()); + } + template + boolean_archetype + operator!=(const equality_comparable2_first_archetype&, + const equality_comparable2_second_archetype&) + { + return boolean_archetype(static_object::get()); + } + + + template > + class less_than_comparable_archetype : public Base { + public: + less_than_comparable_archetype(detail::dummy_constructor x) : Base(x) { } + }; + template + boolean_archetype + operator<(const less_than_comparable_archetype&, + const less_than_comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + + + + template > + class comparable_archetype : public Base { + public: + comparable_archetype(detail::dummy_constructor x) : Base(x) { } + }; + template + boolean_archetype + operator<(const comparable_archetype&, + const comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + template + boolean_archetype + operator<=(const comparable_archetype&, + const comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + template + boolean_archetype + operator>(const comparable_archetype&, + const comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + template + boolean_archetype + operator>=(const comparable_archetype&, + const comparable_archetype&) + { + return boolean_archetype(static_object::get()); + } + + + // The purpose of the optags is so that one can specify + // exactly which types the operator< is defined between. + // This is useful for allowing the operations: + // + // A a; B b; + // a < b + // b < a + // + // without also allowing the combinations: + // + // a < a + // b < b + // + struct optag1 { }; + struct optag2 { }; + struct optag3 { }; + +#define BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(OP, NAME) \ + template , class Tag = optag1 > \ + class NAME##_first_archetype : public Base { \ + public: \ + NAME##_first_archetype(detail::dummy_constructor x) : Base(x) { } \ + }; \ + \ + template , class Tag = optag1 > \ + class NAME##_second_archetype : public Base { \ + public: \ + NAME##_second_archetype(detail::dummy_constructor x) : Base(x) { } \ + }; \ + \ + template \ + boolean_archetype \ + operator OP (const NAME##_first_archetype&, \ + const NAME##_second_archetype&) \ + { \ + return boolean_archetype(static_object::get()); \ + } + + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(==, equal_op) + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(!=, not_equal_op) + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(<, less_than_op) + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(<=, less_equal_op) + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(>, greater_than_op) + BOOST_DEFINE_BINARY_PREDICATE_ARCHETYPE(>=, greater_equal_op) + +#define BOOST_DEFINE_OPERATOR_ARCHETYPE(OP, NAME) \ + template > \ + class NAME##_archetype : public Base { \ + public: \ + NAME##_archetype(detail::dummy_constructor x) : Base(x) { } \ + NAME##_archetype(const NAME##_archetype&) \ + : Base(static_object::get()) { } \ + NAME##_archetype& operator=(const NAME##_archetype&) { return *this; } \ + }; \ + template \ + NAME##_archetype \ + operator OP (const NAME##_archetype&,\ + const NAME##_archetype&) \ + { \ + return \ + NAME##_archetype(static_object::get()); \ + } + + BOOST_DEFINE_OPERATOR_ARCHETYPE(+, addable) + BOOST_DEFINE_OPERATOR_ARCHETYPE(-, subtractable) + BOOST_DEFINE_OPERATOR_ARCHETYPE(*, multipliable) + BOOST_DEFINE_OPERATOR_ARCHETYPE(/, dividable) + BOOST_DEFINE_OPERATOR_ARCHETYPE(%, modable) + + // As is, these are useless because of the return type. + // Need to invent a better way... +#define BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(OP, NAME) \ + template > \ + class NAME##_first_archetype : public Base { \ + public: \ + NAME##_first_archetype(detail::dummy_constructor x) : Base(x) { } \ + }; \ + \ + template > \ + class NAME##_second_archetype : public Base { \ + public: \ + NAME##_second_archetype(detail::dummy_constructor x) : Base(x) { } \ + }; \ + \ + template \ + Return \ + operator OP (const NAME##_first_archetype&, \ + const NAME##_second_archetype&) \ + { \ + return Return(static_object::get()); \ + } + + BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(+, plus_op) + BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(*, time_op) + BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(/, divide_op) + BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(-, subtract_op) + BOOST_DEFINE_BINARY_OPERATOR_ARCHETYPE(%, mod_op) + + //=========================================================================== + // Function Object Archetype Classes + + template + class generator_archetype { + public: + const Return& operator()() { + return static_object::get(); + } + }; + + class void_generator_archetype { + public: + void operator()() { } + }; + + template + class unary_function_archetype { + private: + unary_function_archetype() { } + public: + unary_function_archetype(detail::dummy_constructor) { } + const Return& operator()(const Arg&) const { + return static_object::get(); + } + }; + + template + class binary_function_archetype { + private: + binary_function_archetype() { } + public: + binary_function_archetype(detail::dummy_constructor) { } + const Return& operator()(const Arg1&, const Arg2&) const { + return static_object::get(); + } + }; + + template + class unary_predicate_archetype { + typedef boolean_archetype Return; + unary_predicate_archetype() { } + public: + unary_predicate_archetype(detail::dummy_constructor) { } + const Return& operator()(const Arg&) const { + return static_object::get(); + } + }; + + template > + class binary_predicate_archetype { + typedef boolean_archetype Return; + binary_predicate_archetype() { } + public: + binary_predicate_archetype(detail::dummy_constructor) { } + const Return& operator()(const Arg1&, const Arg2&) const { + return static_object::get(); + } + }; + + //=========================================================================== + // Iterator Archetype Classes + + template + class input_iterator_archetype + { + private: + typedef input_iterator_archetype self; + public: + typedef std::input_iterator_tag iterator_category; + typedef T value_type; + struct reference { + operator const value_type&() const { return static_object::get(); } + }; + typedef const T* pointer; + typedef std::ptrdiff_t difference_type; + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return reference(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + }; + + template + class input_iterator_archetype_no_proxy + { + private: + typedef input_iterator_archetype_no_proxy self; + public: + typedef std::input_iterator_tag iterator_category; + typedef T value_type; + typedef const T& reference; + typedef const T* pointer; + typedef std::ptrdiff_t difference_type; + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + }; + + template + struct output_proxy { + output_proxy& operator=(const T&) { return *this; } + }; + + template + class output_iterator_archetype + { + public: + typedef output_iterator_archetype self; + public: + typedef std::output_iterator_tag iterator_category; + typedef output_proxy value_type; + typedef output_proxy reference; + typedef void pointer; + typedef void difference_type; + output_iterator_archetype(detail::dummy_constructor) { } + output_iterator_archetype(const self&) { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return output_proxy(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + private: + output_iterator_archetype() { } + }; + + template + class input_output_iterator_archetype + { + private: + typedef input_output_iterator_archetype self; + struct in_out_tag : public std::input_iterator_tag, public std::output_iterator_tag { }; + public: + typedef in_out_tag iterator_category; + typedef T value_type; + struct reference { + reference& operator=(const T&) { return *this; } + operator value_type() { return static_object::get(); } + }; + typedef const T* pointer; + typedef std::ptrdiff_t difference_type; + input_output_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return reference(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + }; + + template + class forward_iterator_archetype + { + public: + typedef forward_iterator_archetype self; + public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef const T& reference; + typedef T const* pointer; + typedef std::ptrdiff_t difference_type; + forward_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + }; + + template + class mutable_forward_iterator_archetype + { + public: + typedef mutable_forward_iterator_archetype self; + public: + typedef std::forward_iterator_tag iterator_category; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef std::ptrdiff_t difference_type; + mutable_forward_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + }; + + template + class bidirectional_iterator_archetype + { + public: + typedef bidirectional_iterator_archetype self; + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef T value_type; + typedef const T& reference; + typedef T* pointer; + typedef std::ptrdiff_t difference_type; + bidirectional_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + self& operator--() { return *this; } + self operator--(int) { return *this; } + }; + + template + class mutable_bidirectional_iterator_archetype + { + public: + typedef mutable_bidirectional_iterator_archetype self; + public: + typedef std::bidirectional_iterator_tag iterator_category; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef std::ptrdiff_t difference_type; + mutable_bidirectional_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + self& operator--() { return *this; } + self operator--(int) { return *this; } + }; + + template + class random_access_iterator_archetype + { + public: + typedef random_access_iterator_archetype self; + public: + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef const T& reference; + typedef T* pointer; + typedef std::ptrdiff_t difference_type; + random_access_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + self& operator--() { return *this; } + self operator--(int) { return *this; } + reference operator[](difference_type) const + { return static_object::get(); } + self& operator+=(difference_type) { return *this; } + self& operator-=(difference_type) { return *this; } + difference_type operator-(const self&) const + { return difference_type(); } + self operator+(difference_type) const { return *this; } + self operator-(difference_type) const { return *this; } + bool operator<(const self&) const { return true; } + bool operator<=(const self&) const { return true; } + bool operator>(const self&) const { return true; } + bool operator>=(const self&) const { return true; } + }; + template + random_access_iterator_archetype + operator+(typename random_access_iterator_archetype::difference_type, + const random_access_iterator_archetype& x) + { return x; } + + + template + class mutable_random_access_iterator_archetype + { + public: + typedef mutable_random_access_iterator_archetype self; + public: + typedef std::random_access_iterator_tag iterator_category; + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef std::ptrdiff_t difference_type; + mutable_random_access_iterator_archetype() { } + self& operator=(const self&) { return *this; } + bool operator==(const self&) const { return true; } + bool operator!=(const self&) const { return true; } + reference operator*() const { return static_object::get(); } + self& operator++() { return *this; } + self operator++(int) { return *this; } + self& operator--() { return *this; } + self operator--(int) { return *this; } + reference operator[](difference_type) const + { return static_object::get(); } + self& operator+=(difference_type) { return *this; } + self& operator-=(difference_type) { return *this; } + difference_type operator-(const self&) const + { return difference_type(); } + self operator+(difference_type) const { return *this; } + self operator-(difference_type) const { return *this; } + bool operator<(const self&) const { return true; } + bool operator<=(const self&) const { return true; } + bool operator>(const self&) const { return true; } + bool operator>=(const self&) const { return true; } + }; + template + mutable_random_access_iterator_archetype + operator+ + (typename mutable_random_access_iterator_archetype::difference_type, + const mutable_random_access_iterator_archetype& x) + { return x; } + +} // namespace boost + +#endif // BOOST_CONCEPT_ARCHETYPES_H diff --git a/third-party/boost/boost/concept_check.hpp b/third-party/boost/boost/concept_check.hpp new file mode 100644 index 000000000..abbadb76b --- /dev/null +++ b/third-party/boost/boost/concept_check.hpp @@ -0,0 +1,1082 @@ +// +// (C) Copyright Jeremy Siek 2000. +// Copyright 2002 The Trustees of Indiana University. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Revision History: +// 05 May 2001: Workarounds for HP aCC from Thomas Matelich. (Jeremy Siek) +// 02 April 2001: Removed limits header altogether. (Jeremy Siek) +// 01 April 2001: Modified to use new header. (JMaddock) +// + +// See http://www.boost.org/libs/concept_check for documentation. + +#ifndef BOOST_CONCEPT_CHECKS_HPP +# define BOOST_CONCEPT_CHECKS_HPP + +# include + +# include +# include +# include +# include +# include +# include +# include +# include + +# include +# include + +#if (defined _MSC_VER) +# pragma warning( push ) +# pragma warning( disable : 4510 ) // default constructor could not be generated +# pragma warning( disable : 4610 ) // object 'class' can never be instantiated - user-defined constructor required +#endif + +namespace boost +{ + + // + // Backward compatibility + // + + template + inline void function_requires(Model* = 0) + { + BOOST_CONCEPT_ASSERT((Model)); + } + template inline void ignore_unused_variable_warning(T const&) {} + +# define BOOST_CLASS_REQUIRE(type_var, ns, concept) \ + BOOST_CONCEPT_ASSERT((ns::concept)) + +# define BOOST_CLASS_REQUIRE2(type_var1, type_var2, ns, concept) \ + BOOST_CONCEPT_ASSERT((ns::concept)) + +# define BOOST_CLASS_REQUIRE3(tv1, tv2, tv3, ns, concept) \ + BOOST_CONCEPT_ASSERT((ns::concept)) + +# define BOOST_CLASS_REQUIRE4(tv1, tv2, tv3, tv4, ns, concept) \ + BOOST_CONCEPT_ASSERT((ns::concept)) + + + // + // Begin concept definitions + // + BOOST_concept(Integer, (T)) + { + BOOST_CONCEPT_USAGE(Integer) + { + x.error_type_must_be_an_integer_type(); + } + private: + T x; + }; + + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; + template <> struct Integer {}; +# if defined(BOOST_HAS_LONG_LONG) + template <> struct Integer< ::boost::long_long_type> {}; + template <> struct Integer< ::boost::ulong_long_type> {}; +# elif defined(BOOST_HAS_MS_INT64) + template <> struct Integer<__int64> {}; + template <> struct Integer {}; +# endif + + BOOST_concept(SignedInteger,(T)) { + BOOST_CONCEPT_USAGE(SignedInteger) { + x.error_type_must_be_a_signed_integer_type(); + } + private: + T x; + }; + template <> struct SignedInteger { }; + template <> struct SignedInteger {}; + template <> struct SignedInteger {}; + template <> struct SignedInteger {}; +# if defined(BOOST_HAS_LONG_LONG) + template <> struct SignedInteger< ::boost::long_long_type> {}; +# elif defined(BOOST_HAS_MS_INT64) + template <> struct SignedInteger<__int64> {}; +# endif + + BOOST_concept(UnsignedInteger,(T)) { + BOOST_CONCEPT_USAGE(UnsignedInteger) { + x.error_type_must_be_an_unsigned_integer_type(); + } + private: + T x; + }; + + template <> struct UnsignedInteger {}; + template <> struct UnsignedInteger {}; + template <> struct UnsignedInteger {}; + template <> struct UnsignedInteger {}; +# if defined(BOOST_HAS_LONG_LONG) + template <> struct UnsignedInteger< ::boost::ulong_long_type> {}; +# elif defined(BOOST_HAS_MS_INT64) + template <> struct UnsignedInteger {}; +# endif + + //=========================================================================== + // Basic Concepts + + BOOST_concept(DefaultConstructible,(TT)) + { + BOOST_CONCEPT_USAGE(DefaultConstructible) { + TT a; // require default constructor + ignore_unused_variable_warning(a); + } + }; + + BOOST_concept(Assignable,(TT)) + { + BOOST_CONCEPT_USAGE(Assignable) { +#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL + a = b; // require assignment operator +#endif + const_constraints(b); + } + private: + void const_constraints(const TT& x) { +#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL + a = x; // const required for argument to assignment +#else + ignore_unused_variable_warning(x); +#endif + } + private: + TT a; + TT b; + }; + + + BOOST_concept(CopyConstructible,(TT)) + { + BOOST_CONCEPT_USAGE(CopyConstructible) { + TT a(b); // require copy constructor + TT* ptr = &a; // require address of operator + const_constraints(a); + ignore_unused_variable_warning(ptr); + } + private: + void const_constraints(const TT& a) { + TT c(a); // require const copy constructor + const TT* ptr = &a; // require const address of operator + ignore_unused_variable_warning(c); + ignore_unused_variable_warning(ptr); + } + TT b; + }; + + // The SGI STL version of Assignable requires copy constructor and operator= + BOOST_concept(SGIAssignable,(TT)) + { + BOOST_CONCEPT_USAGE(SGIAssignable) { + TT c(a); +#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL + a = b; // require assignment operator +#endif + const_constraints(b); + ignore_unused_variable_warning(c); + } + private: + void const_constraints(const TT& x) { + TT c(x); +#if !defined(_ITERATOR_) // back_insert_iterator broken for VC++ STL + a = x; // const required for argument to assignment +#endif + ignore_unused_variable_warning(c); + } + TT a; + TT b; + }; + + BOOST_concept(Convertible,(X)(Y)) + { + BOOST_CONCEPT_USAGE(Convertible) { + Y y = x; + ignore_unused_variable_warning(y); + } + private: + X 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 require_boolean_expr(const TT& t) { + bool x = t; + ignore_unused_variable_warning(x); + } + + BOOST_concept(EqualityComparable,(TT)) + { + BOOST_CONCEPT_USAGE(EqualityComparable) { + require_boolean_expr(a == b); + require_boolean_expr(a != b); + } + private: + TT a, b; + }; + + BOOST_concept(LessThanComparable,(TT)) + { + BOOST_CONCEPT_USAGE(LessThanComparable) { + require_boolean_expr(a < b); + } + private: + TT a, b; + }; + + // This is equivalent to SGI STL's LessThanComparable. + BOOST_concept(Comparable,(TT)) + { + BOOST_CONCEPT_USAGE(Comparable) { + require_boolean_expr(a < b); + require_boolean_expr(a > b); + require_boolean_expr(a <= b); + require_boolean_expr(a >= b); + } + private: + TT a, b; + }; + +#define BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(OP,NAME) \ + BOOST_concept(NAME, (First)(Second)) \ + { \ + BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \ + private: \ + bool constraints_() { return a OP b; } \ + First a; \ + Second b; \ + } + +#define BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(OP,NAME) \ + BOOST_concept(NAME, (Ret)(First)(Second)) \ + { \ + BOOST_CONCEPT_USAGE(NAME) { (void)constraints_(); } \ + private: \ + Ret constraints_() { return a OP b; } \ + First a; \ + Second b; \ + } + + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(==, EqualOp); + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(!=, NotEqualOp); + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(<, LessThanOp); + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(<=, LessEqualOp); + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(>, GreaterThanOp); + BOOST_DEFINE_BINARY_PREDICATE_OP_CONSTRAINT(>=, GreaterEqualOp); + + BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(+, PlusOp); + BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(*, TimesOp); + BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(/, DivideOp); + BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(-, SubtractOp); + BOOST_DEFINE_BINARY_OPERATOR_CONSTRAINT(%, ModOp); + + //=========================================================================== + // Function Object Concepts + + BOOST_concept(Generator,(Func)(Return)) + { + BOOST_CONCEPT_USAGE(Generator) { test(is_void()); } + + private: + void test(boost::false_type) + { + // Do we really want a reference here? + const Return& r = f(); + ignore_unused_variable_warning(r); + } + + void test(boost::true_type) + { + f(); + } + + Func f; + }; + + BOOST_concept(UnaryFunction,(Func)(Return)(Arg)) + { + BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void()); } + + private: + void test(boost::false_type) + { + f(arg); // "priming the pump" this way keeps msvc6 happy (ICE) + Return r = f(arg); + ignore_unused_variable_warning(r); + } + + void test(boost::true_type) + { + f(arg); + } + +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. + // (warning: non-static reference "const double& boost::UnaryFunction::arg" + // in class without a constructor [-Wuninitialized]) + UnaryFunction(); +#endif + + Func f; + Arg arg; + }; + + BOOST_concept(BinaryFunction,(Func)(Return)(First)(Second)) + { + BOOST_CONCEPT_USAGE(BinaryFunction) { test(is_void()); } + private: + void test(boost::false_type) + { + f(first,second); + Return r = f(first, second); // require operator() + (void)r; + } + + void test(boost::true_type) + { + f(first,second); + } + +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. + // (warning: non-static reference "const double& boost::BinaryFunction::arg" + // in class without a constructor [-Wuninitialized]) + BinaryFunction(); +#endif + + Func f; + First first; + Second second; + }; + + BOOST_concept(UnaryPredicate,(Func)(Arg)) + { + BOOST_CONCEPT_USAGE(UnaryPredicate) { + require_boolean_expr(f(arg)); // require operator() returning bool + } + private: +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. + // (warning: non-static reference "const double& boost::UnaryPredicate::arg" + // in class without a constructor [-Wuninitialized]) + UnaryPredicate(); +#endif + + Func f; + Arg arg; + }; + + BOOST_concept(BinaryPredicate,(Func)(First)(Second)) + { + BOOST_CONCEPT_USAGE(BinaryPredicate) { + require_boolean_expr(f(a, b)); // require operator() returning bool + } + private: +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. + // (warning: non-static reference "const double& boost::BinaryPredicate::arg" + // in class without a constructor [-Wuninitialized]) + BinaryPredicate(); +#endif + Func f; + First a; + Second b; + }; + + // use this when functor is used inside a container class like std::set + BOOST_concept(Const_BinaryPredicate,(Func)(First)(Second)) + : BinaryPredicate + { + BOOST_CONCEPT_USAGE(Const_BinaryPredicate) { + const_constraints(f); + } + private: + void const_constraints(const Func& fun) { + // operator() must be a const member function + require_boolean_expr(fun(a, b)); + } +#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \ + && BOOST_WORKAROUND(__GNUC__, > 3))) + // Declare a dummy constructor to make gcc happy. + // It seems the compiler can not generate a sensible constructor when this is instantiated with a reference type. + // (warning: non-static reference "const double& boost::Const_BinaryPredicate::arg" + // in class without a constructor [-Wuninitialized]) + Const_BinaryPredicate(); +#endif + + Func f; + First a; + Second b; + }; + + BOOST_concept(AdaptableGenerator,(Func)(Return)) + : Generator + { + typedef typename Func::result_type result_type; + + BOOST_CONCEPT_USAGE(AdaptableGenerator) + { + BOOST_CONCEPT_ASSERT((Convertible)); + } + }; + + BOOST_concept(AdaptableUnaryFunction,(Func)(Return)(Arg)) + : UnaryFunction + { + typedef typename Func::argument_type argument_type; + typedef typename Func::result_type result_type; + + ~AdaptableUnaryFunction() + { + BOOST_CONCEPT_ASSERT((Convertible)); + BOOST_CONCEPT_ASSERT((Convertible)); + } + }; + + BOOST_concept(AdaptableBinaryFunction,(Func)(Return)(First)(Second)) + : BinaryFunction< + Func + , typename Func::result_type + , typename Func::first_argument_type + , typename Func::second_argument_type + > + { + typedef typename Func::first_argument_type first_argument_type; + typedef typename Func::second_argument_type second_argument_type; + typedef typename Func::result_type result_type; + + ~AdaptableBinaryFunction() + { + BOOST_CONCEPT_ASSERT((Convertible)); + BOOST_CONCEPT_ASSERT((Convertible)); + BOOST_CONCEPT_ASSERT((Convertible)); + } + }; + + BOOST_concept(AdaptablePredicate,(Func)(Arg)) + : UnaryPredicate + , AdaptableUnaryFunction + { + }; + + BOOST_concept(AdaptableBinaryPredicate,(Func)(First)(Second)) + : BinaryPredicate + , AdaptableBinaryFunction + { + }; + + //=========================================================================== + // Iterator Concepts + + BOOST_concept(InputIterator,(TT)) + : Assignable + , EqualityComparable + { + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::pointer pointer; + typedef typename std::iterator_traits::iterator_category iterator_category; + + BOOST_CONCEPT_USAGE(InputIterator) + { + BOOST_CONCEPT_ASSERT((SignedInteger)); + BOOST_CONCEPT_ASSERT((Convertible)); + + TT j(i); + (void)*i; // require dereference operator + ++j; // require preincrement operator + i++; // require postincrement operator + } + private: + TT i; + }; + + BOOST_concept(OutputIterator,(TT)(ValueT)) + : Assignable + { + BOOST_CONCEPT_USAGE(OutputIterator) { + + ++i; // require preincrement operator + i++; // require postincrement operator + *i++ = t; // require postincrement and assignment + } + private: + TT i, j; + ValueT t; + }; + + BOOST_concept(ForwardIterator,(TT)) + : InputIterator + { + BOOST_CONCEPT_USAGE(ForwardIterator) + { + BOOST_CONCEPT_ASSERT((Convertible< + BOOST_DEDUCED_TYPENAME ForwardIterator::iterator_category + , std::forward_iterator_tag + >)); + + typename InputIterator::reference r = *i; + ignore_unused_variable_warning(r); + } + + private: + TT i; + }; + + BOOST_concept(Mutable_ForwardIterator,(TT)) + : ForwardIterator + { + BOOST_CONCEPT_USAGE(Mutable_ForwardIterator) { + *i++ = *j; // require postincrement and assignment + } + private: + TT i, j; + }; + + BOOST_concept(BidirectionalIterator,(TT)) + : ForwardIterator + { + BOOST_CONCEPT_USAGE(BidirectionalIterator) + { + BOOST_CONCEPT_ASSERT((Convertible< + BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category + , std::bidirectional_iterator_tag + >)); + + --i; // require predecrement operator + i--; // require postdecrement operator + } + private: + TT i; + }; + + BOOST_concept(Mutable_BidirectionalIterator,(TT)) + : BidirectionalIterator + , Mutable_ForwardIterator + { + BOOST_CONCEPT_USAGE(Mutable_BidirectionalIterator) + { + *i-- = *j; // require postdecrement and assignment + } + private: + TT i, j; + }; + + BOOST_concept(RandomAccessIterator,(TT)) + : BidirectionalIterator + , Comparable + { + BOOST_CONCEPT_USAGE(RandomAccessIterator) + { + BOOST_CONCEPT_ASSERT((Convertible< + BOOST_DEDUCED_TYPENAME BidirectionalIterator::iterator_category + , std::random_access_iterator_tag + >)); + + i += n; // require assignment addition operator + i = i + n; i = n + i; // require addition with difference type + i -= n; // require assignment subtraction operator + i = i - n; // require subtraction with difference type + n = i - j; // require difference operator + (void)i[n]; // require element access operator + } + + private: + TT a, b; + TT i, j; + typename std::iterator_traits::difference_type n; + }; + + BOOST_concept(Mutable_RandomAccessIterator,(TT)) + : RandomAccessIterator + , Mutable_BidirectionalIterator + { + BOOST_CONCEPT_USAGE(Mutable_RandomAccessIterator) + { + i[n] = *i; // require element access and assignment + } + private: + TT i; + typename std::iterator_traits::difference_type n; + }; + + //=========================================================================== + // Container s + + BOOST_concept(Container,(C)) + : Assignable + { + typedef typename C::value_type value_type; + typedef typename C::difference_type difference_type; + typedef typename C::size_type size_type; + typedef typename C::const_reference const_reference; + typedef typename C::const_pointer const_pointer; + typedef typename C::const_iterator const_iterator; + + BOOST_CONCEPT_USAGE(Container) + { + BOOST_CONCEPT_ASSERT((InputIterator)); + const_constraints(c); + } + + private: + void const_constraints(const C& cc) { + i = cc.begin(); + i = cc.end(); + n = cc.size(); + n = cc.max_size(); + b = cc.empty(); + } + C c; + bool b; + const_iterator i; + size_type n; + }; + + BOOST_concept(Mutable_Container,(C)) + : Container + { + typedef typename C::reference reference; + typedef typename C::iterator iterator; + typedef typename C::pointer pointer; + + BOOST_CONCEPT_USAGE(Mutable_Container) + { + BOOST_CONCEPT_ASSERT(( + Assignable)); + + BOOST_CONCEPT_ASSERT((InputIterator)); + + i = c.begin(); + i = c.end(); + c.swap(c2); + } + + private: + iterator i; + C c, c2; + }; + + BOOST_concept(ForwardContainer,(C)) + : Container + { + BOOST_CONCEPT_USAGE(ForwardContainer) + { + BOOST_CONCEPT_ASSERT(( + ForwardIterator< + typename ForwardContainer::const_iterator + >)); + } + }; + + BOOST_concept(Mutable_ForwardContainer,(C)) + : ForwardContainer + , Mutable_Container + { + BOOST_CONCEPT_USAGE(Mutable_ForwardContainer) + { + BOOST_CONCEPT_ASSERT(( + Mutable_ForwardIterator< + typename Mutable_ForwardContainer::iterator + >)); + } + }; + + BOOST_concept(ReversibleContainer,(C)) + : ForwardContainer + { + typedef typename + C::const_reverse_iterator + const_reverse_iterator; + + BOOST_CONCEPT_USAGE(ReversibleContainer) + { + BOOST_CONCEPT_ASSERT(( + BidirectionalIterator< + typename ReversibleContainer::const_iterator>)); + + BOOST_CONCEPT_ASSERT((BidirectionalIterator)); + + const_constraints(c); + } + private: + void const_constraints(const C& cc) + { + const_reverse_iterator _i = cc.rbegin(); + _i = cc.rend(); + } + C c; + }; + + BOOST_concept(Mutable_ReversibleContainer,(C)) + : Mutable_ForwardContainer + , ReversibleContainer + { + typedef typename C::reverse_iterator reverse_iterator; + + BOOST_CONCEPT_USAGE(Mutable_ReversibleContainer) + { + typedef typename Mutable_ForwardContainer::iterator iterator; + BOOST_CONCEPT_ASSERT((Mutable_BidirectionalIterator)); + BOOST_CONCEPT_ASSERT((Mutable_BidirectionalIterator)); + + reverse_iterator i = c.rbegin(); + i = c.rend(); + } + private: + C c; + }; + + BOOST_concept(RandomAccessContainer,(C)) + : ReversibleContainer + { + typedef typename C::size_type size_type; + typedef typename C::const_reference const_reference; + + BOOST_CONCEPT_USAGE(RandomAccessContainer) + { + BOOST_CONCEPT_ASSERT(( + RandomAccessIterator< + typename RandomAccessContainer::const_iterator + >)); + + const_constraints(c); + } + private: + void const_constraints(const C& cc) + { + const_reference r = cc[n]; + ignore_unused_variable_warning(r); + } + + C c; + size_type n; + }; + + BOOST_concept(Mutable_RandomAccessContainer,(C)) + : Mutable_ReversibleContainer + , RandomAccessContainer + { + private: + typedef Mutable_RandomAccessContainer self; + public: + BOOST_CONCEPT_USAGE(Mutable_RandomAccessContainer) + { + BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator)); + BOOST_CONCEPT_ASSERT((Mutable_RandomAccessIterator)); + + typename self::reference r = c[i]; + ignore_unused_variable_warning(r); + } + + private: + typename Mutable_ReversibleContainer::size_type i; + C c; + }; + + // A Sequence is inherently mutable + BOOST_concept(Sequence,(S)) + : Mutable_ForwardContainer + // Matt Austern's book puts DefaultConstructible here, the C++ + // standard places it in Container --JGS + // ... so why aren't we following the standard? --DWA + , DefaultConstructible + { + BOOST_CONCEPT_USAGE(Sequence) + { + S + c(n, t), + c2(first, last); + + c.insert(p, t); + c.insert(p, n, t); + c.insert(p, first, last); + + c.erase(p); + c.erase(p, q); + + typename Sequence::reference r = c.front(); + + ignore_unused_variable_warning(c); + ignore_unused_variable_warning(c2); + ignore_unused_variable_warning(r); + const_constraints(c); + } + private: + void const_constraints(const S& c) { + typename Sequence::const_reference r = c.front(); + ignore_unused_variable_warning(r); + } + + typename S::value_type t; + typename S::size_type n; + typename S::value_type* first, *last; + typename S::iterator p, q; + }; + + BOOST_concept(FrontInsertionSequence,(S)) + : Sequence + { + BOOST_CONCEPT_USAGE(FrontInsertionSequence) + { + c.push_front(t); + c.pop_front(); + } + private: + S c; + typename S::value_type t; + }; + + BOOST_concept(BackInsertionSequence,(S)) + : Sequence + { + BOOST_CONCEPT_USAGE(BackInsertionSequence) + { + c.push_back(t); + c.pop_back(); + typename BackInsertionSequence::reference r = c.back(); + ignore_unused_variable_warning(r); + const_constraints(c); + } + private: + void const_constraints(const S& cc) { + typename BackInsertionSequence::const_reference + r = cc.back(); + ignore_unused_variable_warning(r); + } + S c; + typename S::value_type t; + }; + + BOOST_concept(AssociativeContainer,(C)) + : ForwardContainer + , DefaultConstructible + { + typedef typename C::key_type key_type; + typedef typename C::key_compare key_compare; + typedef typename C::value_compare value_compare; + typedef typename C::iterator iterator; + + BOOST_CONCEPT_USAGE(AssociativeContainer) + { + i = c.find(k); + r = c.equal_range(k); + c.erase(k); + c.erase(i); + c.erase(r.first, r.second); + const_constraints(c); + BOOST_CONCEPT_ASSERT((BinaryPredicate)); + + typedef typename AssociativeContainer::value_type value_type_; + BOOST_CONCEPT_ASSERT((BinaryPredicate)); + } + + // Redundant with the base concept, but it helps below. + typedef typename C::const_iterator const_iterator; + private: + void const_constraints(const C& cc) + { + ci = cc.find(k); + n = cc.count(k); + cr = cc.equal_range(k); + } + + C c; + iterator i; + std::pair r; + const_iterator ci; + std::pair cr; + typename C::key_type k; + typename C::size_type n; + }; + + BOOST_concept(UniqueAssociativeContainer,(C)) + : AssociativeContainer + { + BOOST_CONCEPT_USAGE(UniqueAssociativeContainer) + { + C c(first, last); + + pos_flag = c.insert(t); + c.insert(first, last); + + ignore_unused_variable_warning(c); + } + private: + std::pair pos_flag; + typename C::value_type t; + typename C::value_type* first, *last; + }; + + BOOST_concept(MultipleAssociativeContainer,(C)) + : AssociativeContainer + { + BOOST_CONCEPT_USAGE(MultipleAssociativeContainer) + { + C c(first, last); + + pos = c.insert(t); + c.insert(first, last); + + ignore_unused_variable_warning(c); + ignore_unused_variable_warning(pos); + } + private: + typename C::iterator pos; + typename C::value_type t; + typename C::value_type* first, *last; + }; + + BOOST_concept(SimpleAssociativeContainer,(C)) + : AssociativeContainer + { + BOOST_CONCEPT_USAGE(SimpleAssociativeContainer) + { + typedef typename C::key_type key_type; + typedef typename C::value_type value_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + }; + + BOOST_concept(PairAssociativeContainer,(C)) + : AssociativeContainer + { + BOOST_CONCEPT_USAGE(PairAssociativeContainer) + { + typedef typename C::key_type key_type; + typedef typename C::value_type value_type; + typedef typename C::mapped_type mapped_type; + typedef std::pair required_value_type; + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + }; + + BOOST_concept(SortedAssociativeContainer,(C)) + : AssociativeContainer + , ReversibleContainer + { + BOOST_CONCEPT_USAGE(SortedAssociativeContainer) + { + C + c(kc), + c2(first, last), + c3(first, last, kc); + + p = c.upper_bound(k); + p = c.lower_bound(k); + r = c.equal_range(k); + + c.insert(p, t); + + ignore_unused_variable_warning(c); + ignore_unused_variable_warning(c2); + ignore_unused_variable_warning(c3); + const_constraints(c); + } + + void const_constraints(const C& c) + { + kc = c.key_comp(); + vc = c.value_comp(); + + cp = c.upper_bound(k); + cp = c.lower_bound(k); + cr = c.equal_range(k); + } + + private: + typename C::key_compare kc; + typename C::value_compare vc; + typename C::value_type t; + typename C::key_type k; + typedef typename C::iterator iterator; + typedef typename C::const_iterator const_iterator; + + typedef SortedAssociativeContainer self; + iterator p; + const_iterator cp; + std::pair r; + std::pair cr; + typename C::value_type* first, *last; + }; + + // HashedAssociativeContainer + + BOOST_concept(Collection,(C)) + { + BOOST_CONCEPT_USAGE(Collection) + { + boost::function_requires >(); + boost::function_requires >(); + boost::function_requires >(); + const_constraints(c); + i = c.begin(); + i = c.end(); + c.swap(c); + } + + void const_constraints(const C& cc) { + ci = cc.begin(); + ci = cc.end(); + n = cc.size(); + b = cc.empty(); + } + + private: + typedef typename C::value_type value_type; + typedef typename C::iterator iterator; + typedef typename C::const_iterator const_iterator; + typedef typename C::reference reference; + typedef typename C::const_reference const_reference; + // typedef typename C::pointer pointer; + typedef typename C::difference_type difference_type; + typedef typename C::size_type size_type; + + C c; + bool b; + iterator i; + const_iterator ci; + size_type n; + }; +} // namespace boost + +#if (defined _MSC_VER) +# pragma warning( pop ) +#endif + +# include + +#endif // BOOST_CONCEPT_CHECKS_HPP + diff --git a/third-party/boost/boost/config.hpp b/third-party/boost/boost/config.hpp new file mode 100644 index 000000000..f00a98057 --- /dev/null +++ b/third-party/boost/boost/config.hpp @@ -0,0 +1,67 @@ +// Boost config.hpp configuration header file ------------------------------// + +// (C) Copyright John Maddock 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/libs/config for most recent version. + +// Boost config.hpp policy and rationale documentation has been moved to +// http://www.boost.org/libs/config +// +// CAUTION: This file is intended to be completely stable - +// DO NOT MODIFY THIS FILE! +// + +#ifndef BOOST_CONFIG_HPP +#define BOOST_CONFIG_HPP + +// if we don't have a user config, then use the default location: +#if !defined(BOOST_USER_CONFIG) && !defined(BOOST_NO_USER_CONFIG) +# define BOOST_USER_CONFIG +#if 0 +// For dependency trackers: +# include +#endif +#endif +// include it first: +#ifdef BOOST_USER_CONFIG +# include BOOST_USER_CONFIG +#endif + +// if we don't have a compiler config set, try and find one: +#if !defined(BOOST_COMPILER_CONFIG) && !defined(BOOST_NO_COMPILER_CONFIG) && !defined(BOOST_NO_CONFIG) +# include +#endif +// if we have a compiler config, include it now: +#ifdef BOOST_COMPILER_CONFIG +# include BOOST_COMPILER_CONFIG +#endif + +// if we don't have a std library config set, try and find one: +#if !defined(BOOST_STDLIB_CONFIG) && !defined(BOOST_NO_STDLIB_CONFIG) && !defined(BOOST_NO_CONFIG) && defined(__cplusplus) +# include +#endif +// if we have a std library config, include it now: +#ifdef BOOST_STDLIB_CONFIG +# include BOOST_STDLIB_CONFIG +#endif + +// if we don't have a platform config set, try and find one: +#if !defined(BOOST_PLATFORM_CONFIG) && !defined(BOOST_NO_PLATFORM_CONFIG) && !defined(BOOST_NO_CONFIG) +# include +#endif +// if we have a platform config, include it now: +#ifdef BOOST_PLATFORM_CONFIG +# include BOOST_PLATFORM_CONFIG +#endif + +// get config suffix code: +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +#endif // BOOST_CONFIG_HPP diff --git a/third-party/boost/boost/config/abi/borland_prefix.hpp b/third-party/boost/boost/config/abi/borland_prefix.hpp new file mode 100644 index 000000000..3a0e5ae2d --- /dev/null +++ b/third-party/boost/boost/config/abi/borland_prefix.hpp @@ -0,0 +1,27 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// for C++ Builder the following options effect the ABI: +// +// -b (on or off - effect emum sizes) +// -Vx (on or off - empty members) +// -Ve (on or off - empty base classes) +// -aX (alignment - 5 options). +// -pX (Calling convention - 4 options) +// -VmX (member pointer size and layout - 5 options) +// -VC (on or off, changes name mangling) +// -Vl (on or off, changes struct layout). + +// In addition the following warnings are sufficiently annoying (and +// unfixable) to have them turned off by default: +// +// 8027 - functions containing [for|while] loops are not expanded inline +// 8026 - functions taking class by value arguments are not expanded inline + +#pragma nopushoptwarn +# pragma option push -a8 -Vx- -Ve- -b- -pc -Vmv -VC- -Vl- -w-8027 -w-8026 + + + diff --git a/third-party/boost/boost/config/abi/borland_suffix.hpp b/third-party/boost/boost/config/abi/borland_suffix.hpp new file mode 100644 index 000000000..940535f38 --- /dev/null +++ b/third-party/boost/boost/config/abi/borland_suffix.hpp @@ -0,0 +1,12 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +# pragma option pop +#pragma nopushoptwarn + + + + + diff --git a/third-party/boost/boost/config/abi/msvc_prefix.hpp b/third-party/boost/boost/config/abi/msvc_prefix.hpp new file mode 100644 index 000000000..97f06cdc0 --- /dev/null +++ b/third-party/boost/boost/config/abi/msvc_prefix.hpp @@ -0,0 +1,22 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// +// Boost binaries are built with the compiler's default ABI settings, +// if the user changes their default alignment in the VS IDE then their +// code will no longer be binary compatible with the bjam built binaries +// unless this header is included to force Boost code into a consistent ABI. +// +// Note that inclusion of this header is only necessary for libraries with +// separate source, header only libraries DO NOT need this as long as all +// translation units are built with the same options. +// +#if defined(_M_X64) +# pragma pack(push,16) +#else +# pragma pack(push,8) +#endif + + diff --git a/third-party/boost/boost/config/abi/msvc_suffix.hpp b/third-party/boost/boost/config/abi/msvc_suffix.hpp new file mode 100644 index 000000000..a64d783eb --- /dev/null +++ b/third-party/boost/boost/config/abi/msvc_suffix.hpp @@ -0,0 +1,8 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma pack(pop) + + diff --git a/third-party/boost/boost/config/abi_prefix.hpp b/third-party/boost/boost/config/abi_prefix.hpp new file mode 100644 index 000000000..3b1347492 --- /dev/null +++ b/third-party/boost/boost/config/abi_prefix.hpp @@ -0,0 +1,25 @@ +// abi_prefix header -------------------------------------------------------// + +// (c) Copyright John Maddock 2003 + +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). + +#ifndef BOOST_CONFIG_ABI_PREFIX_HPP +# define BOOST_CONFIG_ABI_PREFIX_HPP +#else +# error double inclusion of header boost/config/abi_prefix.hpp is an error +#endif + +#include + +// this must occur after all other includes and before any code appears: +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_PREFIX +#endif + +#if defined( __BORLANDC__ ) +#pragma nopushoptwarn +#endif + diff --git a/third-party/boost/boost/config/abi_suffix.hpp b/third-party/boost/boost/config/abi_suffix.hpp new file mode 100644 index 000000000..939161662 --- /dev/null +++ b/third-party/boost/boost/config/abi_suffix.hpp @@ -0,0 +1,27 @@ +// abi_sufffix header -------------------------------------------------------// + +// (c) Copyright John Maddock 2003 + +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt). + +// This header should be #included AFTER code that was preceded by a #include +// . + +#ifndef BOOST_CONFIG_ABI_PREFIX_HPP +# error Header boost/config/abi_suffix.hpp must only be used after boost/config/abi_prefix.hpp +#else +# undef BOOST_CONFIG_ABI_PREFIX_HPP +#endif + +// the suffix header occurs after all of our code: +#ifdef BOOST_HAS_ABI_HEADERS +# include BOOST_ABI_SUFFIX +#endif + +#if defined( __BORLANDC__ ) +#pragma nopushoptwarn +#endif + + diff --git a/third-party/boost/boost/config/auto_link.hpp b/third-party/boost/boost/config/auto_link.hpp new file mode 100644 index 000000000..d0079d9bc --- /dev/null +++ b/third-party/boost/boost/config/auto_link.hpp @@ -0,0 +1,479 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + /* + * LOCATION: see http://www.boost.org for most recent version. + * FILE auto_link.hpp + * VERSION see + * DESCRIPTION: Automatic library inclusion for Borland/Microsoft compilers. + */ + +/************************************************************************* + +USAGE: +~~~~~~ + +Before including this header you must define one or more of define the following macros: + +BOOST_LIB_NAME: Required: A string containing the basename of the library, + for example boost_regex. +BOOST_LIB_TOOLSET: Optional: the base name of the toolset. +BOOST_DYN_LINK: Optional: when set link to dll rather than static library. +BOOST_LIB_DIAGNOSTIC: Optional: when set the header will print out the name + of the library selected (useful for debugging). +BOOST_AUTO_LINK_NOMANGLE: Specifies that we should link to BOOST_LIB_NAME.lib, + rather than a mangled-name version. +BOOST_AUTO_LINK_TAGGED: Specifies that we link to libraries built with the --layout=tagged option. + This is essentially the same as the default name-mangled version, but without + the compiler name and version, or the Boost version. Just the build options. +BOOST_AUTO_LINK_SYSTEM: Specifies that we link to libraries built with the --layout=system option. + This is essentially the same as the non-name-mangled version, but with + the prefix to differentiate static and dll builds + +These macros will be undef'ed at the end of the header, further this header +has no include guards - so be sure to include it only once from your library! + +Algorithm: +~~~~~~~~~~ + +Libraries for Borland and Microsoft compilers are automatically +selected here, the name of the lib is selected according to the following +formula: + +BOOST_LIB_PREFIX + + BOOST_LIB_NAME + + "_" + + BOOST_LIB_TOOLSET + + BOOST_LIB_THREAD_OPT + + BOOST_LIB_RT_OPT + + BOOST_LIB_ARCH_AND_MODEL_OPT + "-" + + BOOST_LIB_VERSION + +These are defined as: + +BOOST_LIB_PREFIX: "lib" for static libraries otherwise "". + +BOOST_LIB_NAME: The base name of the lib ( for example boost_regex). + +BOOST_LIB_TOOLSET: The compiler toolset name (vc6, vc7, bcb5 etc). + +BOOST_LIB_THREAD_OPT: "-mt" for multithread builds, otherwise nothing. + +BOOST_LIB_RT_OPT: A suffix that indicates the runtime library used, + contains one or more of the following letters after + a hyphen: + + s static runtime (dynamic if not present). + g debug/diagnostic runtime (release if not present). + y Python debug/diagnostic runtime (release if not present). + d debug build (release if not present). + p STLport build. + n STLport build without its IOStreams. + +BOOST_LIB_ARCH_AND_MODEL_OPT: The architecture and address model + (-x32 or -x64 for x86/32 and x86/64 respectively) + +BOOST_LIB_VERSION: The Boost version, in the form x_y, for Boost version x.y. + + +***************************************************************************/ + +#ifdef __cplusplus +# ifndef BOOST_CONFIG_HPP +# include +# endif +#elif defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__EDG_VERSION__) +// +// C language compatability (no, honestly) +// +# define BOOST_MSVC _MSC_VER +# define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X) +# define BOOST_DO_STRINGIZE(X) #X +#endif +// +// Only include what follows for known and supported compilers: +// +#if defined(BOOST_MSVC) \ + || defined(__BORLANDC__) \ + || (defined(__MWERKS__) && defined(_WIN32) && (__MWERKS__ >= 0x3000)) \ + || (defined(__ICL) && defined(_MSC_EXTENSIONS) && (_MSC_VER >= 1200)) + +#ifndef BOOST_VERSION_HPP +# include +#endif + +#ifndef BOOST_LIB_NAME +# error "Macro BOOST_LIB_NAME not set (internal error)" +#endif + +// +// error check: +// +#if defined(__MSVC_RUNTIME_CHECKS) && !defined(_DEBUG) +# pragma message("Using the /RTC option without specifying a debug runtime will lead to linker errors") +# pragma message("Hint: go to the code generation options and switch to one of the debugging runtimes") +# error "Incompatible build options" +#endif +// +// select toolset if not defined already: +// +#ifndef BOOST_LIB_TOOLSET +# if defined(BOOST_MSVC) && (BOOST_MSVC < 1200) + // Note: no compilers before 1200 are supported +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1300) + +# ifdef UNDER_CE + // eVC4: +# define BOOST_LIB_TOOLSET "evc4" +# else + // vc6: +# define BOOST_LIB_TOOLSET "vc6" +# endif + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1310) + + // vc7: +# define BOOST_LIB_TOOLSET "vc7" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1400) + + // vc71: +# define BOOST_LIB_TOOLSET "vc71" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1500) + + // vc80: +# define BOOST_LIB_TOOLSET "vc80" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1600) + + // vc90: +# define BOOST_LIB_TOOLSET "vc90" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1700) + + // vc10: +# define BOOST_LIB_TOOLSET "vc100" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1800) + + // vc11: +# define BOOST_LIB_TOOLSET "vc110" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1900) + + // vc12: +# define BOOST_LIB_TOOLSET "vc120" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1910) + + // vc14: +# define BOOST_LIB_TOOLSET "vc140" + +# elif defined(BOOST_MSVC) && (BOOST_MSVC < 1920) + + // vc14.1: +# define BOOST_LIB_TOOLSET "vc141" + +# elif defined(BOOST_MSVC) + + // vc14.2: +# define BOOST_LIB_TOOLSET "vc142" + +# elif defined(__BORLANDC__) + + // CBuilder 6: +# define BOOST_LIB_TOOLSET "bcb" + +# elif defined(__ICL) + + // Intel C++, no version number: +# define BOOST_LIB_TOOLSET "iw" + +# elif defined(__MWERKS__) && (__MWERKS__ <= 0x31FF ) + + // Metrowerks CodeWarrior 8.x +# define BOOST_LIB_TOOLSET "cw8" + +# elif defined(__MWERKS__) && (__MWERKS__ <= 0x32FF ) + + // Metrowerks CodeWarrior 9.x +# define BOOST_LIB_TOOLSET "cw9" + +# endif +#endif // BOOST_LIB_TOOLSET + +// +// select thread opt: +// +#if defined(_MT) || defined(__MT__) +# define BOOST_LIB_THREAD_OPT "-mt" +#else +# define BOOST_LIB_THREAD_OPT +#endif + +#if defined(_MSC_VER) || defined(__MWERKS__) + +# ifdef _DLL + +# if (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) && (defined(_STLP_OWN_IOSTREAMS) || defined(__STL_OWN_IOSTREAMS)) + +# if defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG))\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-gydp" +# elif defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG)) +# define BOOST_LIB_RT_OPT "-gdp" +# elif defined(_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-gydp" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-gdp" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# else +# define BOOST_LIB_RT_OPT "-p" +# endif + +# elif defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) + +# if defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG))\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-gydpn" +# elif defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG)) +# define BOOST_LIB_RT_OPT "-gdpn" +# elif defined(_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-gydpn" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-gdpn" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# else +# define BOOST_LIB_RT_OPT "-pn" +# endif + +# else + +# if defined(_DEBUG) && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-gyd" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-gd" +# else +# define BOOST_LIB_RT_OPT +# endif + +# endif + +# else + +# if (defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)) && (defined(_STLP_OWN_IOSTREAMS) || defined(__STL_OWN_IOSTREAMS)) + +# if defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG))\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sgydp" +# elif defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG)) +# define BOOST_LIB_RT_OPT "-sgdp" +# elif defined(_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sgydp" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-sgdp" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# else +# define BOOST_LIB_RT_OPT "-sp" +# endif + +# elif defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) + +# if defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG))\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sgydpn" +# elif defined(_DEBUG) && (defined(__STL_DEBUG) || defined(_STLP_DEBUG)) +# define BOOST_LIB_RT_OPT "-sgdpn" +# elif defined(_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sgydpn" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-sgdpn" +# pragma message("warning: STLport debug versions are built with /D_STLP_DEBUG=1") +# error "Build options aren't compatible with pre-built libraries" +# else +# define BOOST_LIB_RT_OPT "-spn" +# endif + +# else + +# if defined(_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sgyd" +# elif defined(_DEBUG) +# define BOOST_LIB_RT_OPT "-sgd" +# else +# define BOOST_LIB_RT_OPT "-s" +# endif + +# endif + +# endif + +#elif defined(__BORLANDC__) + +// +// figure out whether we want the debug builds or not: +// +#if __BORLANDC__ > 0x561 +#pragma defineonoption BOOST_BORLAND_DEBUG -v +#endif +// +// sanity check: +// +#if defined(__STL_DEBUG) || defined(_STLP_DEBUG) +#error "Pre-built versions of the Boost libraries are not provided in STLport-debug form" +#endif + +# ifdef _RTLDLL + +# if defined(BOOST_BORLAND_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-yd" +# elif defined(BOOST_BORLAND_DEBUG) +# define BOOST_LIB_RT_OPT "-d" +# elif defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT -y +# else +# define BOOST_LIB_RT_OPT +# endif + +# else + +# if defined(BOOST_BORLAND_DEBUG)\ + && defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-syd" +# elif defined(BOOST_BORLAND_DEBUG) +# define BOOST_LIB_RT_OPT "-sd" +# elif defined(BOOST_DEBUG_PYTHON) && defined(BOOST_LINKING_PYTHON) +# define BOOST_LIB_RT_OPT "-sy" +# else +# define BOOST_LIB_RT_OPT "-s" +# endif + +# endif + +#endif + +// +// BOOST_LIB_ARCH_AND_MODEL_OPT +// + +#if defined( _M_IX86 ) +# define BOOST_LIB_ARCH_AND_MODEL_OPT "-x32" +#elif defined( _M_X64 ) +# define BOOST_LIB_ARCH_AND_MODEL_OPT "-x64" +#elif defined( _M_ARM ) +# define BOOST_LIB_ARCH_AND_MODEL_OPT "-a32" +#elif defined( _M_ARM64 ) +# define BOOST_LIB_ARCH_AND_MODEL_OPT "-a64" +#endif + +// +// select linkage opt: +// +#if (defined(_DLL) || defined(_RTLDLL)) && defined(BOOST_DYN_LINK) +# define BOOST_LIB_PREFIX +#elif defined(BOOST_DYN_LINK) +# error "Mixing a dll boost library with a static runtime is a really bad idea..." +#else +# define BOOST_LIB_PREFIX "lib" +#endif + +// +// now include the lib: +// +#if defined(BOOST_LIB_NAME) \ + && defined(BOOST_LIB_PREFIX) \ + && defined(BOOST_LIB_TOOLSET) \ + && defined(BOOST_LIB_THREAD_OPT) \ + && defined(BOOST_LIB_RT_OPT) \ + && defined(BOOST_LIB_ARCH_AND_MODEL_OPT) \ + && defined(BOOST_LIB_VERSION) + +#ifdef BOOST_AUTO_LINK_TAGGED +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT ".lib") +# endif +#elif defined(BOOST_AUTO_LINK_SYSTEM) +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") +# endif +#elif defined(BOOST_AUTO_LINK_NOMANGLE) +# pragma comment(lib, BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_STRINGIZE(BOOST_LIB_NAME) ".lib") +# endif +#elif defined(BOOST_LIB_BUILDID) +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) "-" BOOST_LIB_TOOLSET BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT "-" BOOST_LIB_VERSION "-" BOOST_STRINGIZE(BOOST_LIB_BUILDID) ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) "-" BOOST_LIB_TOOLSET BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT "-" BOOST_LIB_VERSION "-" BOOST_STRINGIZE(BOOST_LIB_BUILDID) ".lib") +# endif +#else +# pragma comment(lib, BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) "-" BOOST_LIB_TOOLSET BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT "-" BOOST_LIB_VERSION ".lib") +# ifdef BOOST_LIB_DIAGNOSTIC +# pragma message ("Linking to lib file: " BOOST_LIB_PREFIX BOOST_STRINGIZE(BOOST_LIB_NAME) "-" BOOST_LIB_TOOLSET BOOST_LIB_THREAD_OPT BOOST_LIB_RT_OPT BOOST_LIB_ARCH_AND_MODEL_OPT "-" BOOST_LIB_VERSION ".lib") +# endif +#endif + +#else +# error "some required macros where not defined (internal logic error)." +#endif + + +#endif // _MSC_VER || __BORLANDC__ + +// +// finally undef any macros we may have set: +// +#ifdef BOOST_LIB_PREFIX +# undef BOOST_LIB_PREFIX +#endif +#if defined(BOOST_LIB_NAME) +# undef BOOST_LIB_NAME +#endif +// Don't undef this one: it can be set by the user and should be the +// same for all libraries: +//#if defined(BOOST_LIB_TOOLSET) +//# undef BOOST_LIB_TOOLSET +//#endif +#if defined(BOOST_LIB_THREAD_OPT) +# undef BOOST_LIB_THREAD_OPT +#endif +#if defined(BOOST_LIB_RT_OPT) +# undef BOOST_LIB_RT_OPT +#endif +#if defined(BOOST_LIB_ARCH_AND_MODEL_OPT) +# undef BOOST_LIB_ARCH_AND_MODEL_OPT +#endif +#if defined(BOOST_LIB_LINK_OPT) +# undef BOOST_LIB_LINK_OPT +#endif +#if defined(BOOST_LIB_DEBUG_OPT) +# undef BOOST_LIB_DEBUG_OPT +#endif +#if defined(BOOST_DYN_LINK) +# undef BOOST_DYN_LINK +#endif + + diff --git a/third-party/boost/boost/config/compiler/borland.hpp b/third-party/boost/boost/config/compiler/borland.hpp new file mode 100644 index 000000000..beec94621 --- /dev/null +++ b/third-party/boost/boost/config/compiler/borland.hpp @@ -0,0 +1,335 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Aleksey Gurtovoy 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Borland C++ compiler setup: + +// +// versions check: +// we don't support Borland prior to version 5.4: +#if __BORLANDC__ < 0x540 +# error "Compiler not supported or configured - please reconfigure" +#endif + +// last known compiler version: +#if (__BORLANDC__ > 0x613) +//# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +//# else +//# pragma message( "boost: Unknown compiler version - please run the configure tests and report the results") +//# endif +#elif (__BORLANDC__ == 0x600) +# error "CBuilderX preview compiler is no longer supported" +#endif + +// +// Support macros to help with standard library detection +#if (__BORLANDC__ < 0x560) || defined(_USE_OLD_RW_STL) +# define BOOST_BCB_WITH_ROGUE_WAVE +#elif __BORLANDC__ < 0x570 +# define BOOST_BCB_WITH_STLPORT +#else +# define BOOST_BCB_WITH_DINKUMWARE +#endif + +// +// Version 5.0 and below: +# if __BORLANDC__ <= 0x0550 +// Borland C++Builder 4 and 5: +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +# if __BORLANDC__ == 0x0550 +// Borland C++Builder 5, command-line compiler 5.5: +# define BOOST_NO_OPERATORS_IN_NAMESPACE +# endif +// Variadic macros do not exist for C++ Builder versions 5 and below +#define BOOST_NO_CXX11_VARIADIC_MACROS +# endif + +// Version 5.51 and below: +#if (__BORLANDC__ <= 0x551) +# define BOOST_NO_CV_SPECIALIZATIONS +# define BOOST_NO_CV_VOID_SPECIALIZATIONS +# define BOOST_NO_DEDUCED_TYPENAME +// workaround for missing WCHAR_MAX/WCHAR_MIN: +#ifdef __cplusplus +#include +#include +#else +#include +#include +#endif // __cplusplus +#ifndef WCHAR_MAX +# define WCHAR_MAX 0xffff +#endif +#ifndef WCHAR_MIN +# define WCHAR_MIN 0 +#endif +#endif + +// Borland C++ Builder 6 and below: +#if (__BORLANDC__ <= 0x564) + +# if defined(NDEBUG) && defined(__cplusplus) + // fix broken so that Boost.test works: +# include +# undef strcmp +# endif + // fix broken errno declaration: +# include +# ifndef errno +# define errno errno +# endif + +#endif + +// +// new bug in 5.61: +#if (__BORLANDC__ >= 0x561) && (__BORLANDC__ <= 0x580) + // this seems to be needed by the command line compiler, but not the IDE: +# define BOOST_NO_MEMBER_FUNCTION_SPECIALIZATIONS +#endif + +// Borland C++ Builder 2006 Update 2 and below: +#if (__BORLANDC__ <= 0x582) +# define BOOST_NO_SFINAE +# define BOOST_BCB_PARTIAL_SPECIALIZATION_BUG +# define BOOST_NO_TEMPLATE_TEMPLATES + +# define BOOST_NO_PRIVATE_IN_AGGREGATE + +# ifdef _WIN32 +# define BOOST_NO_SWPRINTF +# elif defined(linux) || defined(__linux__) || defined(__linux) + // we should really be able to do without this + // but the wcs* functions aren't imported into std:: +# define BOOST_NO_STDC_NAMESPACE + // _CPPUNWIND doesn't get automatically set for some reason: +# pragma defineonoption BOOST_CPPUNWIND -x +# endif +#endif + +#if (__BORLANDC__ <= 0x613) // Beman has asked Alisdair for more info + // we shouldn't really need this - but too many things choke + // without it, this needs more investigation: +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +# define BOOST_NO_IS_ABSTRACT +# define BOOST_NO_FUNCTION_TYPE_SPECIALIZATIONS +# define BOOST_NO_USING_TEMPLATE +# define BOOST_SP_NO_SP_CONVERTIBLE + +// Temporary workaround +#define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS +#endif + +// Borland C++ Builder 2008 and below: +# define BOOST_NO_INTEGRAL_INT64_T +# define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +# define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +# define BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE +# define BOOST_NO_NESTED_FRIENDSHIP +# define BOOST_NO_TYPENAME_WITH_CTOR +#if (__BORLANDC__ < 0x600) +# define BOOST_ILLEGAL_CV_REFERENCES +#endif + +// +// Positive Feature detection +// +// Borland C++ Builder 2008 and below: +#if (__BORLANDC__ >= 0x599) +# pragma defineonoption BOOST_CODEGEAR_0X_SUPPORT -Ax +#endif +// +// C++0x Macros: +// +#if !defined( BOOST_CODEGEAR_0X_SUPPORT ) || (__BORLANDC__ < 0x610) +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +# define BOOST_NO_CXX11_DECLTYPE +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_EXTERN_TEMPLATE +# define BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_NO_CXX11_SCOPED_ENUMS +# define BOOST_NO_CXX11_STATIC_ASSERT +#else +# define BOOST_HAS_ALIGNOF +# define BOOST_HAS_CHAR16_T +# define BOOST_HAS_CHAR32_T +# define BOOST_HAS_DECLTYPE +# define BOOST_HAS_EXPLICIT_CONVERSION_OPS +# define BOOST_HAS_REF_QUALIFIER +# define BOOST_HAS_RVALUE_REFS +# define BOOST_HAS_STATIC_ASSERT +#endif + +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DEFAULTED_MOVES +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS // UTF-8 still not supported +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#if __BORLANDC__ >= 0x590 +# define BOOST_HAS_TR1_HASH + +# define BOOST_HAS_MACRO_USE_FACET +#endif + +// +// Post 0x561 we have long long and stdint.h: +#if __BORLANDC__ >= 0x561 +# ifndef __NO_LONG_LONG +# define BOOST_HAS_LONG_LONG +# else +# define BOOST_NO_LONG_LONG +# endif + // On non-Win32 platforms let the platform config figure this out: +# ifdef _WIN32 +# define BOOST_HAS_STDINT_H +# endif +#endif + +// Borland C++Builder 6 defaults to using STLPort. If _USE_OLD_RW_STL is +// defined, then we have 0x560 or greater with the Rogue Wave implementation +// which presumably has the std::DBL_MAX bug. +#if defined( BOOST_BCB_WITH_ROGUE_WAVE ) +// is partly broken, some macros define symbols that are really in +// namespace std, so you end up having to use illegal constructs like +// std::DBL_MAX, as a fix we'll just include float.h and have done with: +#include +#endif +// +// __int64: +// +#if (__BORLANDC__ >= 0x530) && !defined(__STRICT_ANSI__) +# define BOOST_HAS_MS_INT64 +#endif +// +// check for exception handling support: +// +#if !defined(_CPPUNWIND) && !defined(BOOST_CPPUNWIND) && !defined(__EXCEPTIONS) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif +// +// all versions have a : +// +#ifndef __STRICT_ANSI__ +# define BOOST_HAS_DIRENT_H +#endif +// +// all versions support __declspec: +// +#if defined(__STRICT_ANSI__) +// config/platform/win32.hpp will define BOOST_SYMBOL_EXPORT, etc., unless already defined +# define BOOST_SYMBOL_EXPORT +#endif +// +// ABI fixing headers: +// +#if __BORLANDC__ != 0x600 // not implemented for version 6 compiler yet +#ifndef BOOST_ABI_PREFIX +# define BOOST_ABI_PREFIX "boost/config/abi/borland_prefix.hpp" +#endif +#ifndef BOOST_ABI_SUFFIX +# define BOOST_ABI_SUFFIX "boost/config/abi/borland_suffix.hpp" +#endif +#endif +// +// Disable Win32 support in ANSI mode: +// +#if __BORLANDC__ < 0x600 +# pragma defineonoption BOOST_DISABLE_WIN32 -A +#elif defined(__STRICT_ANSI__) +# define BOOST_DISABLE_WIN32 +#endif +// +// MSVC compatibility mode does some nasty things: +// TODO: look up if this doesn't apply to the whole 12xx range +// +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +# define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +# define BOOST_NO_VOID_RETURNS +#endif + +// Borland did not implement value-initialization completely, as I reported +// in 2007, Borland Report 51854, "Value-initialization: POD struct should be +// zero-initialized", http://qc.embarcadero.com/wc/qcmain.aspx?d=51854 +// See also: http://www.boost.org/libs/utility/value_init.htm#compiler_issues +// (Niels Dekker, LKEB, April 2010) +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION + +#define BOOST_COMPILER "Borland C++ version " BOOST_STRINGIZE(__BORLANDC__) diff --git a/third-party/boost/boost/config/compiler/clang.hpp b/third-party/boost/boost/config/compiler/clang.hpp new file mode 100644 index 000000000..52b23d9d0 --- /dev/null +++ b/third-party/boost/boost/config/compiler/clang.hpp @@ -0,0 +1,348 @@ +// (C) Copyright Douglas Gregor 2010 +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Clang compiler setup. + +#define BOOST_HAS_PRAGMA_ONCE + +// Detecting `-fms-extension` compiler flag assuming that _MSC_VER defined when that flag is used. +#if defined (_MSC_VER) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 4)) +# define BOOST_HAS_PRAGMA_DETECT_MISMATCH +#endif + +// When compiling with clang before __has_extension was defined, +// even if one writes 'defined(__has_extension) && __has_extension(xxx)', +// clang reports a compiler error. So the only workaround found is: + +#ifndef __has_extension +#define __has_extension __has_feature +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +#if !__has_feature(cxx_exceptions) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +#if !__has_feature(cxx_rtti) && !defined(BOOST_NO_RTTI) +# define BOOST_NO_RTTI +#endif + +#if !__has_feature(cxx_rtti) && !defined(BOOST_NO_TYPEID) +# define BOOST_NO_TYPEID +#endif + +#if !__has_feature(cxx_thread_local) +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +#ifdef __is_identifier +#if !__is_identifier(__int64) && !defined(__GNUC__) +# define BOOST_HAS_MS_INT64 +#endif +#endif + +#if __has_include() +# define BOOST_HAS_STDINT_H +#endif + +#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +#if (__clang_major__ >= 4) && defined(__has_include) +#if __has_include() +# define BOOST_HAS_FLOAT128 +#endif +#endif +#endif + + +#define BOOST_HAS_NRVO + +// Branch prediction hints +#if !defined (__c2__) && defined(__has_builtin) +#if __has_builtin(__builtin_expect) +#define BOOST_LIKELY(x) __builtin_expect(x, 1) +#define BOOST_UNLIKELY(x) __builtin_expect(x, 0) +#endif +#endif + +// Clang supports "long long" in all compilation modes. +#define BOOST_HAS_LONG_LONG + +// +// We disable this if the compiler is really nvcc with C++03 as it +// doesn't actually support __int128 as of CUDA_VERSION=7500 +// even though it defines __SIZEOF_INT128__. +// See https://svn.boost.org/trac/boost/ticket/10418 +// https://svn.boost.org/trac/boost/ticket/11852 +// Only re-enable this for nvcc if you're absolutely sure +// of the circumstances under which it's supported. +// Similarly __SIZEOF_INT128__ is defined when targetting msvc +// compatibility even though the required support functions are absent. +// +#if defined(__CUDACC__) +# if defined(BOOST_GCC_CXX11) +# define BOOST_NVCC_CXX11 +# else +# define BOOST_NVCC_CXX03 +# endif +#endif + +#if defined(__SIZEOF_INT128__) && !defined(BOOST_NVCC_CXX03) && !defined(_MSC_VER) +# define BOOST_HAS_INT128 +#endif + + +// +// Dynamic shared object (DSO) and dynamic-link library (DLL) support +// +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) +# define BOOST_HAS_DECLSPEC +# define BOOST_SYMBOL_EXPORT __attribute__((__dllexport__)) +# define BOOST_SYMBOL_IMPORT __attribute__((__dllimport__)) +#else +# define BOOST_SYMBOL_EXPORT __attribute__((__visibility__("default"))) +# define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) +# define BOOST_SYMBOL_IMPORT +#endif + +// +// The BOOST_FALLTHROUGH macro can be used to annotate implicit fall-through +// between switch labels. +// +#if __cplusplus >= 201103L && defined(__has_warning) +# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +# define BOOST_FALLTHROUGH [[clang::fallthrough]] +# endif +#endif + +#if !__has_feature(cxx_auto_type) +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#endif + +// +// Currently clang on Windows using VC++ RTL does not support C++11's char16_t or char32_t +// +#if (defined(_MSC_VER) && (_MSC_VER < 1900)) || !(defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(__GNUC__) +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_LOG1P +#endif + +#if !__has_feature(cxx_constexpr) +# define BOOST_NO_CXX11_CONSTEXPR +#endif + +#if !__has_feature(cxx_decltype) +# define BOOST_NO_CXX11_DECLTYPE +#endif + +#if !__has_feature(cxx_decltype_incomplete_return_types) +# define BOOST_NO_CXX11_DECLTYPE_N3276 +#endif + +#if !__has_feature(cxx_defaulted_functions) +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#endif + +#if !__has_feature(cxx_deleted_functions) +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +#endif + +#if !__has_feature(cxx_explicit_conversions) +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#endif + +#if !__has_feature(cxx_default_function_template_args) +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif + +#if !__has_feature(cxx_generalized_initializers) +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#endif + +#if !__has_feature(cxx_lambdas) +# define BOOST_NO_CXX11_LAMBDAS +#endif + +#if !__has_feature(cxx_local_type_template_args) +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#endif + +#if !__has_feature(cxx_noexcept) +# define BOOST_NO_CXX11_NOEXCEPT +#endif + +#if !__has_feature(cxx_nullptr) +# define BOOST_NO_CXX11_NULLPTR +#endif + +#if !__has_feature(cxx_range_for) +# define BOOST_NO_CXX11_RANGE_BASED_FOR +#endif + +#if !__has_feature(cxx_raw_string_literals) +# define BOOST_NO_CXX11_RAW_LITERALS +#endif + +#if !__has_feature(cxx_reference_qualified_functions) +# define BOOST_NO_CXX11_REF_QUALIFIERS +#endif + +#if !__has_feature(cxx_generalized_initializers) +# define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#endif + +#if !__has_feature(cxx_rvalue_references) +# define BOOST_NO_CXX11_RVALUE_REFERENCES +#endif + +#if !__has_feature(cxx_strong_enums) +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +#if !__has_feature(cxx_static_assert) +# define BOOST_NO_CXX11_STATIC_ASSERT +#endif + +#if !__has_feature(cxx_alias_templates) +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +#endif + +#if !__has_feature(cxx_unicode_literals) +# define BOOST_NO_CXX11_UNICODE_LITERALS +#endif + +#if !__has_feature(cxx_variadic_templates) +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif + +#if !__has_feature(cxx_user_literals) +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#endif + +#if !__has_feature(cxx_alignas) +# define BOOST_NO_CXX11_ALIGNAS +#endif + +#if !__has_feature(cxx_trailing_return) +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#endif + +#if !__has_feature(cxx_inline_namespaces) +# define BOOST_NO_CXX11_INLINE_NAMESPACES +#endif + +#if !__has_feature(cxx_override_control) +# define BOOST_NO_CXX11_FINAL +#endif + +#if !(__has_feature(__cxx_binary_literals__) || __has_extension(__cxx_binary_literals__)) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif + +#if !__has_feature(__cxx_decltype_auto__) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif + +#if !__has_feature(__cxx_aggregate_nsdmi__) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif + +#if !__has_feature(__cxx_init_captures__) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif + +#if !__has_feature(__cxx_generic_lambdas__) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif + +// clang < 3.5 has a defect with dependent type, like following. +// +// template +// constexpr typename enable_if >::type foo(T &) +// { } // error: no return statement in constexpr function +// +// This issue also affects C++11 mode, but C++11 constexpr requires return stmt. +// Therefore we don't care such case. +// +// Note that we can't check Clang version directly as the numbering system changes depending who's +// creating the Clang release (see https://github.com/boostorg/config/pull/39#issuecomment-59927873) +// so instead verify that we have a feature that was introduced at the same time as working C++14 +// constexpr (generic lambda's in this case): +// +#if !__has_feature(__cxx_generic_lambdas__) || !__has_feature(__cxx_relaxed_constexpr__) +# define BOOST_NO_CXX14_CONSTEXPR +#endif + +#if !__has_feature(__cxx_return_type_deduction__) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif + +#if !__has_feature(__cxx_variable_templates__) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif + +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +// Clang 3.9+ in c++1z +#if !__has_cpp_attribute(fallthrough) || __cplusplus < 201406L +# define BOOST_NO_CXX17_INLINE_VARIABLES +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif + +#if __cplusplus < 201103L +#define BOOST_NO_CXX11_SFINAE_EXPR +#endif + +#if __cplusplus < 201400 +// All versions with __cplusplus above this value seem to support this: +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +// +// __builtin_unreachable: +#if defined(__has_builtin) && __has_builtin(__builtin_unreachable) +#define BOOST_UNREACHABLE_RETURN(x) __builtin_unreachable(); +#endif + +#if (__clang_major__ == 3) && (__clang_minor__ == 0) +// Apparently a clang bug: +# define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#endif + +// Clang has supported the 'unused' attribute since the first release. +#define BOOST_ATTRIBUTE_UNUSED __attribute__((__unused__)) + +// Type aliasing hint. +#if __has_attribute(__may_alias__) +# define BOOST_MAY_ALIAS __attribute__((__may_alias__)) +#endif + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "Clang version " __clang_version__ +#endif + +// Macro used to identify the Clang compiler. +#define BOOST_CLANG 1 + diff --git a/third-party/boost/boost/config/compiler/codegear.hpp b/third-party/boost/boost/config/compiler/codegear.hpp new file mode 100644 index 000000000..52531d2f0 --- /dev/null +++ b/third-party/boost/boost/config/compiler/codegear.hpp @@ -0,0 +1,239 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Aleksey Gurtovoy 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// CodeGear C++ compiler setup: + +#if !defined( BOOST_WITH_CODEGEAR_WARNINGS ) +// these warnings occur frequently in optimized template code +# pragma warn -8004 // var assigned value, but never used +# pragma warn -8008 // condition always true/false +# pragma warn -8066 // dead code can never execute +# pragma warn -8104 // static members with ctors not threadsafe +# pragma warn -8105 // reference member in class without ctors +#endif +// +// versions check: +// last known and checked version is 0x621 +#if (__CODEGEARC__ > 0x621) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# else +# pragma message( "boost: Unknown compiler version - please run the configure tests and report the results") +# endif +#endif + +// CodeGear C++ Builder 2009 +#if (__CODEGEARC__ <= 0x613) +# define BOOST_NO_INTEGRAL_INT64_T +# define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS +# define BOOST_NO_PRIVATE_IN_AGGREGATE +# define BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE + // we shouldn't really need this - but too many things choke + // without it, this needs more investigation: +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +# define BOOST_SP_NO_SP_CONVERTIBLE +#endif + +// CodeGear C++ Builder 2010 +#if (__CODEGEARC__ <= 0x621) +# define BOOST_NO_TYPENAME_WITH_CTOR // Cannot use typename keyword when making temporaries of a dependant type +# define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +# define BOOST_NO_NESTED_FRIENDSHIP // TC1 gives nested classes access rights as any other member +# define BOOST_NO_USING_TEMPLATE +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +// Temporary hack, until specific MPL preprocessed headers are generated +# define BOOST_MPL_CFG_NO_PREPROCESSED_HEADERS + +// CodeGear has not yet completely implemented value-initialization, for +// example for array types, as I reported in 2010: Embarcadero Report 83751, +// "Value-initialization: arrays should have each element value-initialized", +// http://qc.embarcadero.com/wc/qcmain.aspx?d=83751 +// Last checked version: Embarcadero C++ 6.21 +// See also: http://www.boost.org/libs/utility/value_init.htm#compiler_issues +// (Niels Dekker, LKEB, April 2010) +# define BOOST_NO_COMPLETE_VALUE_INITIALIZATION + +# if defined(NDEBUG) && defined(__cplusplus) + // fix broken so that Boost.test works: +# include +# undef strcmp +# endif + // fix broken errno declaration: +# include +# ifndef errno +# define errno errno +# endif + +#endif + +// Reportedly, #pragma once is supported since C++ Builder 2010 +#if (__CODEGEARC__ >= 0x620) +# define BOOST_HAS_PRAGMA_ONCE +#endif + +// +// C++0x macros: +// +#if (__CODEGEARC__ <= 0x620) +#define BOOST_NO_CXX11_STATIC_ASSERT +#else +#define BOOST_HAS_STATIC_ASSERT +#endif +#define BOOST_HAS_CHAR16_T +#define BOOST_HAS_CHAR32_T +#define BOOST_HAS_LONG_LONG +// #define BOOST_HAS_ALIGNOF +#define BOOST_HAS_DECLTYPE +#define BOOST_HAS_EXPLICIT_CONVERSION_OPS +// #define BOOST_HAS_RVALUE_REFS +#define BOOST_HAS_SCOPED_ENUM +// #define BOOST_HAS_STATIC_ASSERT +#define BOOST_HAS_STD_TYPE_TRAITS + +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif + +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif + +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif + +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +// +// TR1 macros: +// +#define BOOST_HAS_TR1_HASH +#define BOOST_HAS_TR1_TYPE_TRAITS +#define BOOST_HAS_TR1_UNORDERED_MAP +#define BOOST_HAS_TR1_UNORDERED_SET + +#define BOOST_HAS_MACRO_USE_FACET + +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +// On non-Win32 platforms let the platform config figure this out: +#ifdef _WIN32 +# define BOOST_HAS_STDINT_H +#endif + +// +// __int64: +// +#if !defined(__STRICT_ANSI__) +# define BOOST_HAS_MS_INT64 +#endif +// +// check for exception handling support: +// +#if !defined(_CPPUNWIND) && !defined(BOOST_CPPUNWIND) && !defined(__EXCEPTIONS) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif +// +// all versions have a : +// +#if !defined(__STRICT_ANSI__) +# define BOOST_HAS_DIRENT_H +#endif +// +// all versions support __declspec: +// +#if defined(__STRICT_ANSI__) +// config/platform/win32.hpp will define BOOST_SYMBOL_EXPORT, etc., unless already defined +# define BOOST_SYMBOL_EXPORT +#endif +// +// ABI fixing headers: +// +#ifndef BOOST_ABI_PREFIX +# define BOOST_ABI_PREFIX "boost/config/abi/borland_prefix.hpp" +#endif +#ifndef BOOST_ABI_SUFFIX +# define BOOST_ABI_SUFFIX "boost/config/abi/borland_suffix.hpp" +#endif +// +// Disable Win32 support in ANSI mode: +// +# pragma defineonoption BOOST_DISABLE_WIN32 -A +// +// MSVC compatibility mode does some nasty things: +// TODO: look up if this doesn't apply to the whole 12xx range +// +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +# define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +# define BOOST_NO_VOID_RETURNS +#endif + +#define BOOST_COMPILER "CodeGear C++ version " BOOST_STRINGIZE(__CODEGEARC__) + diff --git a/third-party/boost/boost/config/compiler/comeau.hpp b/third-party/boost/boost/config/compiler/comeau.hpp new file mode 100644 index 000000000..ca80fac37 --- /dev/null +++ b/third-party/boost/boost/config/compiler/comeau.hpp @@ -0,0 +1,59 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright Douglas Gregor 2001. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright Aleksey Gurtovoy 2003. +// (C) Copyright Beman Dawes 2003. +// (C) Copyright Jens Maurer 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Comeau C++ compiler setup: + +#include + +#if (__COMO_VERSION__ <= 4245) + +# if defined(_MSC_VER) && _MSC_VER <= 1300 +# if _MSC_VER > 100 + // only set this in non-strict mode: +# define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +# endif +# endif + +// Void returns don't work when emulating VC 6 (Peter Dimov) +// TODO: look up if this doesn't apply to the whole 12xx range +# if defined(_MSC_VER) && (_MSC_VER < 1300) +# define BOOST_NO_VOID_RETURNS +# endif + +#endif // version 4245 + +// +// enable __int64 support in VC emulation mode +// +# if defined(_MSC_VER) && (_MSC_VER >= 1200) +# define BOOST_HAS_MS_INT64 +# endif + +#define BOOST_COMPILER "Comeau compiler version " BOOST_STRINGIZE(__COMO_VERSION__) + +// +// versions check: +// we don't know Comeau prior to version 4245: +#if __COMO_VERSION__ < 4245 +# error "Compiler not configured - please reconfigure" +#endif +// +// last known and checked version is 4245: +#if (__COMO_VERSION__ > 4245) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + + + + diff --git a/third-party/boost/boost/config/compiler/common_edg.hpp b/third-party/boost/boost/config/compiler/common_edg.hpp new file mode 100644 index 000000000..88aba9ac8 --- /dev/null +++ b/third-party/boost/boost/config/compiler/common_edg.hpp @@ -0,0 +1,160 @@ +// (C) Copyright John Maddock 2001 - 2002. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright David Abrahams 2002. +// (C) Copyright Aleksey Gurtovoy 2002. +// (C) Copyright Markus Schoepflin 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// +// Options common to all edg based compilers. +// +// This is included from within the individual compiler mini-configs. + +#ifndef __EDG_VERSION__ +# error This file requires that __EDG_VERSION__ be defined. +#endif + +#if (__EDG_VERSION__ <= 238) +# define BOOST_NO_INTEGRAL_INT64_T +# define BOOST_NO_SFINAE +#endif + +#if (__EDG_VERSION__ <= 240) +# define BOOST_NO_VOID_RETURNS +#endif + +#if (__EDG_VERSION__ <= 241) && !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) +# define BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP +#endif + +#if (__EDG_VERSION__ <= 244) && !defined(BOOST_NO_TEMPLATE_TEMPLATES) +# define BOOST_NO_TEMPLATE_TEMPLATES +#endif + +#if (__EDG_VERSION__ < 300) && !defined(BOOST_NO_IS_ABSTRACT) +# define BOOST_NO_IS_ABSTRACT +#endif + +#if (__EDG_VERSION__ <= 303) && !defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) +# define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +#endif + +// See also kai.hpp which checks a Kai-specific symbol for EH +# if !defined(__KCC) && !defined(__EXCEPTIONS) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +# endif + +# if !defined(__NO_LONG_LONG) +# define BOOST_HAS_LONG_LONG +# else +# define BOOST_NO_LONG_LONG +# endif + +// Not sure what version was the first to support #pragma once, but +// different EDG-based compilers (e.g. Intel) supported it for ages. +// Add a proper version check if it causes problems. +#define BOOST_HAS_PRAGMA_ONCE + +// +// C++0x features +// +// See above for BOOST_NO_LONG_LONG +// +#if (__EDG_VERSION__ < 310) +# define BOOST_NO_CXX11_EXTERN_TEMPLATE +#endif +#if (__EDG_VERSION__ <= 310) +// No support for initializer lists +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#endif +#if (__EDG_VERSION__ < 400) +# define BOOST_NO_CXX11_VARIADIC_MACROS +#endif + +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif + +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#ifdef c_plusplus +// EDG has "long long" in non-strict mode +// However, some libraries have insufficient "long long" support +// #define BOOST_HAS_LONG_LONG +#endif diff --git a/third-party/boost/boost/config/compiler/compaq_cxx.hpp b/third-party/boost/boost/config/compiler/compaq_cxx.hpp new file mode 100644 index 000000000..4d6b8ab3a --- /dev/null +++ b/third-party/boost/boost/config/compiler/compaq_cxx.hpp @@ -0,0 +1,19 @@ +// (C) Copyright John Maddock 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Tru64 C++ compiler setup (now HP): + +#define BOOST_COMPILER "HP Tru64 C++ " BOOST_STRINGIZE(__DECCXX_VER) + +#include + +// +// versions check: +// Nothing to do here? + + + diff --git a/third-party/boost/boost/config/compiler/cray.hpp b/third-party/boost/boost/config/compiler/cray.hpp new file mode 100644 index 000000000..412ef9efa --- /dev/null +++ b/third-party/boost/boost/config/compiler/cray.hpp @@ -0,0 +1,440 @@ +// Copyright 2011 John Maddock +// Copyright 2013, 2017-2018 Cray, Inc. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Cray C++ compiler setup. +// +// There are a few parameters that affect the macros defined in this file: +// +// - What version of CCE (Cray Compiling Environment) are we running? This +// comes from the '_RELEASE_MAJOR', '_RELEASE_MINOR', and +// '_RELEASE_PATCHLEVEL' macros. +// - What C++ standards conformance level are we using (e.g. '-h +// std=c++14')? This comes from the '__cplusplus' macro. +// - Are we using GCC extensions ('-h gnu' or '-h nognu')? If we have '-h +// gnu' then CCE emulates GCC, and the macros '__GNUC__', +// '__GNUC_MINOR__', and '__GNUC_PATCHLEVEL__' are defined. +// +// This file is organized as follows: +// +// - Verify that the combination of parameters listed above is supported. +// If we have an unsupported combination, we abort with '#error'. +// - Establish baseline values for all Boost macros. +// - Apply changes to the baseline macros based on compiler version. These +// changes are cummulative so each version section only describes the +// changes since the previous version. +// - Within each version section, we may also apply changes based on +// other parameters (i.e. C++ standards conformance level and GCC +// extensions). +// +// To test changes to this file: +// +// ``` +// module load cce/8.6.5 # Pick the version you want to test. +// cd boost/libs/config/test/all +// b2 -j 8 toolset=cray cxxstd=03 cxxstd=11 cxxstd=14 cxxstd-dialect=gnu linkflags=-lrt +// ``` +// Note: Using 'cxxstd-dialect=iso' is not supported at this time (the +// tests run, but many tests fail). +// +// Note: 'linkflags=-lrt' is needed in Cray Linux Environment. Otherwise +// you get an 'undefined reference to clock_gettime' error. +// +// Note: If a test '*_fail.cpp' file compiles, but fails to run, then it is +// reported as a defect. However, this is not actually a defect. This is an +// area where the test system is somewhat broken. Tests that are failing +// because of this problem are noted in the comments. +// +// Pay attention to the macro definitions for the macros you wish to +// modify. For example, only macros categorized as compiler macros should +// appear in this file; platform macros should not appear in this file. +// Also, some macros have to be defined to specific values; it is not +// always enough to define or undefine a macro. +// +// Macro definitions are available in the source code at: +// +// `boost/libs/config/doc/html/boost_config/boost_macro_reference.html` +// +// Macro definitions are also available online at: +// +// http://www.boost.org/doc/libs/master/libs/config/doc/html/boost_config/boost_macro_reference.html +// +// Typically, if you enable a feature, and the tests pass, then you have +// nothing to worry about. However, it's sometimes hard to figure out if a +// disabled feature needs to stay disabled. To get a list of disabled +// features, run 'b2' in 'boost/libs/config/checks'. These are the macros +// you should pay attention to (in addition to macros that cause test +// failures). + +//// +//// Front matter +//// + +// In a developer build of the Cray compiler (i.e. a compiler built by a +// Cray employee), the release patch level is reported as "x". This gives +// versions that look like e.g. "8.6.x". +// +// To accomplish this, the the Cray compiler preprocessor inserts: +// +// #define _RELEASE_PATCHLEVEL x +// +// If we are using a developer build of the compiler, we want to use the +// configuration macros for the most recent patch level of the release. To +// accomplish this, we'll pretend that _RELEASE_PATCHLEVEL is 99. +// +// However, it's difficult to detect if _RELEASE_PATCHLEVEL is x. We must +// consider that the x will be expanded if x is defined as a macro +// elsewhere. For example, imagine if someone put "-D x=3" on the command +// line, and _RELEASE_PATCHLEVEL is x. Then _RELEASE_PATCHLEVEL would +// expand to 3, and we could not distinguish it from an actual +// _RELEASE_PATCHLEVEL of 3. This problem only affects developer builds; in +// production builds, _RELEASE_PATCHLEVEL is always an integer. +// +// IMPORTANT: In developer builds, if x is defined as a macro, you will get +// an incorrect configuration. The behavior in this case is undefined. +// +// Even if x is not defined, we have to use some trickery to detect if +// _RELEASE_PATCHLEVEL is x. First we define BOOST_CRAY_x to some arbitrary +// magic value, 9867657. Then we use BOOST_CRAY_APPEND to append the +// expanded value of _RELEASE_PATCHLEVEL to the string "BOOST_CRAY_". +// +// - If _RELEASE_PATCHLEVEL is undefined, we get "BOOST_CRAY_". +// - If _RELEASE_PATCHLEVEL is 5, we get "BOOST_CRAY_5". +// - If _RELEASE_PATCHLEVEL is x (and x is not defined) we get +// "BOOST_CRAY_x": +// +// Then we check if BOOST_CRAY_x is equal to the output of +// BOOST_CRAY_APPEND. In other words, the output of BOOST_CRAY_APPEND is +// treated as a macro name, and expanded again. If we can safely assume +// that BOOST_CRAY_ is not a macro defined as our magic number, and +// BOOST_CRAY_5 is not a macro defined as our magic number, then the only +// way the equality test can pass is if _RELEASE_PATCHLEVEL expands to x. +// +// So, that is how we detect if we are using a developer build of the Cray +// compiler. + +#define BOOST_CRAY_x 9867657 // Arbitrary number +#define BOOST_CRAY_APPEND(MACRO) BOOST_CRAY_APPEND_INTERNAL(MACRO) +#define BOOST_CRAY_APPEND_INTERNAL(MACRO) BOOST_CRAY_##MACRO + +#if BOOST_CRAY_x == BOOST_CRAY_APPEND(_RELEASE_PATCHLEVEL) + + // This is a developer build. + // + // - _RELEASE_PATCHLEVEL is defined as x, and x is not defined as a macro. + + // Pretend _RELEASE_PATCHLEVEL is 99, so we get the configuration for the + // most recent patch level in this release. + + #define BOOST_CRAY_VERSION (_RELEASE_MAJOR * 10000 + _RELEASE_MINOR * 100 + 99) + +#else + + // This is a production build. + // + // _RELEASE_PATCHLEVEL is not defined as x, or x is defined as a macro. + + #define BOOST_CRAY_VERSION (_RELEASE_MAJOR * 10000 + _RELEASE_MINOR * 100 + _RELEASE_PATCHLEVEL) + +#endif // BOOST_CRAY_x == BOOST_CRAY_APPEND(_RELEASE_PATCHLEVEL) + +#undef BOOST_CRAY_APPEND_INTERNAL +#undef BOOST_CRAY_APPEND +#undef BOOST_CRAY_x + + +#ifdef __GNUC__ +# define BOOST_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "Cray C++ version " BOOST_STRINGIZE(_RELEASE_MAJOR) "." BOOST_STRINGIZE(_RELEASE_MINOR) "." BOOST_STRINGIZE(_RELEASE_PATCHLEVEL) +#endif + +// Since the Cray compiler defines '__GNUC__', we have to emulate some +// additional GCC macros in order to make everything work. +// +// FIXME: Perhaps Cray should fix the compiler to define these additional +// macros for GCC emulation? + +#if __cplusplus >= 201103L && defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__) +# define __GXX_EXPERIMENTAL_CXX0X__ 1 +#endif + +//// +//// Parameter validation +//// + +// FIXME: Do we really need to support compilers before 8.5? Do they pass +// the Boost.Config tests? + +#if BOOST_CRAY_VERSION < 80000 +# error "Boost is not configured for Cray compilers prior to version 8, please try the configure script." +#endif + +// We only support recent EDG based compilers. + +#ifndef __EDG__ +# error "Unsupported Cray compiler, please try running the configure script." +#endif + +//// +//// Baseline values +//// + +#include + +#define BOOST_HAS_NRVO +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_THREAD_LOCAL +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_VARIADIC_MACROS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP + +//#define BOOST_BCB_PARTIAL_SPECIALIZATION_BUG +#define BOOST_MATH_DISABLE_STD_FPCLASSIFY +//#define BOOST_HAS_FPCLASSIFY + +#define BOOST_SP_USE_PTHREADS +#define BOOST_AC_USE_PTHREADS + +// +// Everything that follows is working around what are thought to be +// compiler shortcomings. Revist all of these regularly. +// + +//#define BOOST_USE_ENUM_STATIC_ASSERT +//#define BOOST_BUGGY_INTEGRAL_CONSTANT_EXPRESSIONS //(this may be implied by the previous #define + +// These constants should be provided by the compiler. + +#ifndef __ATOMIC_RELAXED +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 +#endif + +//// +//// Version changes +//// + +// +// 8.5.0 +// + +#if BOOST_CRAY_VERSION >= 80500 + +#if __cplusplus >= 201103L + +#undef BOOST_HAS_NRVO +#undef BOOST_NO_COMPLETE_VALUE_INITIALIZATION +#undef BOOST_NO_CXX11_AUTO_DECLARATIONS +#undef BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#undef BOOST_NO_CXX11_CHAR16_T +#undef BOOST_NO_CXX11_CHAR32_T +#undef BOOST_NO_CXX11_CONSTEXPR +#undef BOOST_NO_CXX11_DECLTYPE +#undef BOOST_NO_CXX11_DECLTYPE_N3276 +#undef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#undef BOOST_NO_CXX11_DELETED_FUNCTIONS +#undef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#undef BOOST_NO_CXX11_FINAL +#undef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#undef BOOST_NO_CXX11_LAMBDAS +#undef BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#undef BOOST_NO_CXX11_NOEXCEPT +#undef BOOST_NO_CXX11_NULLPTR +#undef BOOST_NO_CXX11_RANGE_BASED_FOR +#undef BOOST_NO_CXX11_RAW_LITERALS +#undef BOOST_NO_CXX11_REF_QUALIFIERS +#undef BOOST_NO_CXX11_RVALUE_REFERENCES +#undef BOOST_NO_CXX11_SCOPED_ENUMS +#undef BOOST_NO_CXX11_SFINAE_EXPR +#undef BOOST_NO_CXX11_STATIC_ASSERT +#undef BOOST_NO_CXX11_TEMPLATE_ALIASES +#undef BOOST_NO_CXX11_THREAD_LOCAL +#undef BOOST_NO_CXX11_UNICODE_LITERALS +#undef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#undef BOOST_NO_CXX11_USER_DEFINED_LITERALS +#undef BOOST_NO_CXX11_VARIADIC_MACROS +#undef BOOST_NO_CXX11_VARIADIC_TEMPLATES +#undef BOOST_NO_SFINAE_EXPR +#undef BOOST_NO_TWO_PHASE_NAME_LOOKUP +#undef BOOST_MATH_DISABLE_STD_FPCLASSIFY +#undef BOOST_SP_USE_PTHREADS +#undef BOOST_AC_USE_PTHREADS + +#define BOOST_HAS_VARIADIC_TMPL +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG +#define BOOST_HAS_TR1_COMPLEX_OVERLOADS +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_STATIC_ASSERT +#define BOOST_HAS_SIGACTION +#define BOOST_HAS_SCHED_YIELD +#define BOOST_HAS_RVALUE_REFS +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_PTHREAD_YIELD +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#define BOOST_HAS_PARTIAL_STD_ALLOCATOR +#define BOOST_HAS_NRVO +#define BOOST_HAS_NL_TYPES_H +#define BOOST_HAS_NANOSLEEP +#define BOOST_NO_CXX11_SMART_PTR +#define BOOST_NO_CXX11_HDR_FUNCTIONAL +#define BOOST_NO_CXX14_CONSTEXPR +#define BOOST_HAS_LONG_LONG +#define BOOST_HAS_FLOAT128 + +#if __cplusplus < 201402L +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#endif // __cplusplus < 201402L + +#endif // __cplusplus >= 201103L + +#endif // BOOST_CRAY_VERSION >= 80500 + +// +// 8.6.4 +// (versions prior to 8.6.5 do not define _RELEASE_PATCHLEVEL) +// + +#if BOOST_CRAY_VERSION >= 80600 + +#if __cplusplus >= 199711L +#define BOOST_HAS_FLOAT128 +#define BOOST_HAS_PTHREAD_YIELD // This is a platform macro, but it improves test results. +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION // This is correct. Test compiles, but fails to run. +#undef BOOST_NO_CXX11_CHAR16_T +#undef BOOST_NO_CXX11_CHAR32_T +#undef BOOST_NO_CXX11_INLINE_NAMESPACES +#undef BOOST_NO_CXX11_FINAL +#undef BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#undef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_SFINAE_EXPR // This is correct, even though '*_fail.cpp' test fails. +#undef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#undef BOOST_NO_CXX11_VARIADIC_MACROS +#undef BOOST_NO_CXX11_VARIADIC_TEMPLATES +// 'BOOST_NO_DEDUCED_TYPENAME' test is broken. The test files are enabled / +// disabled with an '#ifdef BOOST_DEDUCED_TYPENAME'. However, +// 'boost/libs/config/include/boost/config/detail/suffix.hpp' ensures that +// 'BOOST_DEDUCED_TYPENAME' is always defined (the value it is defined as +// depends on 'BOOST_NO_DEDUCED_TYPENAME'). So, modifying +// 'BOOST_NO_DEDUCED_TYPENAME' has no effect on which tests are run. +// +// The 'no_ded_typename_pass.cpp' test should always compile and run +// successfully, because 'BOOST_DEDUCED_TYPENAME' must always have an +// appropriate value (it's not just something that you turn on or off). +// Therefore, if you wish to test changes to 'BOOST_NO_DEDUCED_TYPENAME', +// you have to modify 'no_ded_typename_pass.cpp' to unconditionally include +// 'boost_no_ded_typename.ipp'. +#undef BOOST_NO_DEDUCED_TYPENAME // This is correct. Test is broken. +#undef BOOST_NO_SFINAE_EXPR +#undef BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif // __cplusplus >= 199711L + +#if __cplusplus >= 201103L +#undef BOOST_NO_CXX11_ALIGNAS +#undef BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_HDR_ATOMIC +#undef BOOST_NO_CXX11_HDR_FUNCTIONAL +#define BOOST_NO_CXX11_HDR_REGEX // This is correct. Test compiles, but fails to run. +#undef BOOST_NO_CXX11_SFINAE_EXPR +#undef BOOST_NO_CXX11_SMART_PTR +#undef BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#endif // __cplusplus >= 201103L + +#if __cplusplus >= 201402L +#undef BOOST_NO_CXX14_CONSTEXPR +#define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif // __cplusplus == 201402L + +#endif // BOOST_CRAY_VERSION >= 80600 + +// +// 8.6.5 +// (no change from 8.6.4) +// + +// +// 8.7.0 +// + +#if BOOST_CRAY_VERSION >= 80700 + +#if __cplusplus >= 199711L +#endif // __cplusplus >= 199711L + +#if __cplusplus >= 201103L +#undef BOOST_NO_CXX11_HDR_ATOMIC +#undef BOOST_NO_CXX11_HDR_REGEX +#endif // __cplusplus >= 201103L + +#if __cplusplus >= 201402L +#endif // __cplusplus == 201402L + +#endif // BOOST_CRAY_VERSION >= 80700 + +// +// Next release +// + +#if BOOST_CRAY_VERSION > 80799 + +#if __cplusplus >= 199711L +#endif // __cplusplus >= 199711L + +#if __cplusplus >= 201103L +#endif // __cplusplus >= 201103L + +#if __cplusplus >= 201402L +#endif // __cplusplus == 201402L + +#endif // BOOST_CRAY_VERSION > 80799 + +//// +//// Remove temporary macros +//// + +// I've commented out some '#undef' statements to signify that we purposely +// want to keep certain macros. + +//#undef __GXX_EXPERIMENTAL_CXX0X__ +//#undef BOOST_COMPILER +#undef BOOST_GCC_VERSION +#undef BOOST_CRAY_VERSION diff --git a/third-party/boost/boost/config/compiler/diab.hpp b/third-party/boost/boost/config/compiler/diab.hpp new file mode 100644 index 000000000..943db83fd --- /dev/null +++ b/third-party/boost/boost/config/compiler/diab.hpp @@ -0,0 +1,26 @@ +// (C) Copyright Brian Kuhl 2016. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Check this is a recent EDG based compiler, otherwise we don't support it here: + + +#ifndef __EDG_VERSION__ +# error "Unknown Diab compiler version - please run the configure tests and report the results" +#endif + +#include "boost/config/compiler/common_edg.hpp" + +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#define BOOST_BUGGY_INTEGRAL_CONSTANT_EXPRESSIONS + +#define BOOST_MPL_CFG_NO_HAS_XXX_TEMPLATE +#define BOOST_LOG_NO_MEMBER_TEMPLATE_FRIENDS +#define BOOST_REGEX_NO_EXTERNAL_TEMPLATES + +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_HDR_CODECVT +#define BOOST_NO_CXX11_NUMERIC_LIMITS + +#define BOOST_COMPILER "Wind River Diab " BOOST_STRINGIZE(__VERSION_NUMBER__) diff --git a/third-party/boost/boost/config/compiler/digitalmars.hpp b/third-party/boost/boost/config/compiler/digitalmars.hpp new file mode 100644 index 000000000..146637319 --- /dev/null +++ b/third-party/boost/boost/config/compiler/digitalmars.hpp @@ -0,0 +1,140 @@ +// Copyright (C) Christof Meerwald 2003 +// Copyright (C) Dan Watkins 2003 +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Digital Mars C++ compiler setup: +#define BOOST_COMPILER __DMC_VERSION_STRING__ + +#define BOOST_HAS_LONG_LONG +#define BOOST_HAS_PRAGMA_ONCE + +#if !defined(BOOST_STRICT_CONFIG) +#define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +#define BOOST_NO_OPERATORS_IN_NAMESPACE +#define BOOST_NO_UNREACHABLE_RETURN_DETECTION +#define BOOST_NO_SFINAE +#define BOOST_NO_USING_TEMPLATE +#define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +#endif + +// +// has macros: +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_WINTHREADS + +#if (__DMC__ >= 0x847) +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_LOG1P +#endif + +// +// Is this really the best way to detect whether the std lib is in namespace std? +// +#ifdef __cplusplus +#include +#endif +#if !defined(__STL_IMPORT_VENDOR_CSTD) && !defined(_STLP_IMPORT_VENDOR_CSTD) +# define BOOST_NO_STDC_NAMESPACE +#endif + + +// check for exception handling support: +#if !defined(_CPPUNWIND) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +// +// C++0x features +// +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#if (__DMC__ <= 0x840) +#error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version is ...: +#if (__DMC__ > 0x848) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif diff --git a/third-party/boost/boost/config/compiler/gcc.hpp b/third-party/boost/boost/config/compiler/gcc.hpp new file mode 100644 index 000000000..9ae6072ee --- /dev/null +++ b/third-party/boost/boost/config/compiler/gcc.hpp @@ -0,0 +1,361 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001 - 2002. +// (C) Copyright Jens Maurer 2001 - 2002. +// (C) Copyright Beman Dawes 2001 - 2003. +// (C) Copyright Douglas Gregor 2002. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Synge Todo 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// GNU C++ compiler setup. + +// +// Define BOOST_GCC so we know this is "real" GCC and not some pretender: +// +#define BOOST_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#if !defined(__CUDACC__) +#define BOOST_GCC BOOST_GCC_VERSION +#endif + +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) +# define BOOST_GCC_CXX11 +#endif + +#if __GNUC__ == 3 +# if defined (__PATHSCALE__) +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +# define BOOST_NO_IS_ABSTRACT +# endif + +# if __GNUC_MINOR__ < 4 +# define BOOST_NO_IS_ABSTRACT +# endif +# define BOOST_NO_CXX11_EXTERN_TEMPLATE +#endif +#if __GNUC__ < 4 +// +// All problems to gcc-3.x and earlier here: +// +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP +# ifdef __OPEN64__ +# define BOOST_NO_IS_ABSTRACT +# endif +#endif + +// GCC prior to 3.4 had #pragma once too but it didn't work well with filesystem links +#if BOOST_GCC_VERSION >= 30400 +#define BOOST_HAS_PRAGMA_ONCE +#endif + +#if BOOST_GCC_VERSION < 40400 +// Previous versions of GCC did not completely implement value-initialization: +// GCC Bug 30111, "Value-initialization of POD base class doesn't initialize +// members", reported by Jonathan Wakely in 2006, +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30111 (fixed for GCC 4.4) +// GCC Bug 33916, "Default constructor fails to initialize array members", +// reported by Michael Elizabeth Chastain in 2007, +// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916 (fixed for GCC 4.2.4) +// See also: http://www.boost.org/libs/utility/value_init.htm#compiler_issues +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +#endif + +#if !defined(__EXCEPTIONS) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + + +// +// Threading support: Turn this on unconditionally here (except for +// those platforms where we can know for sure). It will get turned off again +// later if no threading API is detected. +// +#if !defined(__MINGW32__) && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_HAS_THREADS +#endif + +// +// gcc has "long long" +// Except on Darwin with standard compliance enabled (-pedantic) +// Apple gcc helpfully defines this macro we can query +// +#if !defined(__DARWIN_NO_LONG_LONG) +# define BOOST_HAS_LONG_LONG +#endif + +// +// gcc implements the named return value optimization since version 3.1 +// +#define BOOST_HAS_NRVO + +// Branch prediction hints +#define BOOST_LIKELY(x) __builtin_expect(x, 1) +#define BOOST_UNLIKELY(x) __builtin_expect(x, 0) + +// +// Dynamic shared object (DSO) and dynamic-link library (DLL) support +// +#if __GNUC__ >= 4 +# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__) + // All Win32 development environments, including 64-bit Windows and MinGW, define + // _WIN32 or one of its variant spellings. Note that Cygwin is a POSIX environment, + // so does not define _WIN32 or its variants, but still supports dllexport/dllimport. +# define BOOST_HAS_DECLSPEC +# define BOOST_SYMBOL_EXPORT __attribute__((__dllexport__)) +# define BOOST_SYMBOL_IMPORT __attribute__((__dllimport__)) +# else +# define BOOST_SYMBOL_EXPORT __attribute__((__visibility__("default"))) +# define BOOST_SYMBOL_IMPORT +# endif +# define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) +#else +// config/platform/win32.hpp will define BOOST_SYMBOL_EXPORT, etc., unless already defined +# define BOOST_SYMBOL_EXPORT +#endif + +// +// RTTI and typeinfo detection is possible post gcc-4.3: +// +#if BOOST_GCC_VERSION > 40300 +# ifndef __GXX_RTTI +# ifndef BOOST_NO_TYPEID +# define BOOST_NO_TYPEID +# endif +# ifndef BOOST_NO_RTTI +# define BOOST_NO_RTTI +# endif +# endif +#endif + +// +// Recent GCC versions have __int128 when in 64-bit mode. +// +// We disable this if the compiler is really nvcc with C++03 as it +// doesn't actually support __int128 as of CUDA_VERSION=7500 +// even though it defines __SIZEOF_INT128__. +// See https://svn.boost.org/trac/boost/ticket/8048 +// https://svn.boost.org/trac/boost/ticket/11852 +// Only re-enable this for nvcc if you're absolutely sure +// of the circumstances under which it's supported: +// +#if defined(__CUDACC__) +# if defined(BOOST_GCC_CXX11) +# define BOOST_NVCC_CXX11 +# else +# define BOOST_NVCC_CXX03 +# endif +#endif + +#if defined(__SIZEOF_INT128__) && !defined(BOOST_NVCC_CXX03) +# define BOOST_HAS_INT128 +#endif +// +// Recent GCC versions have a __float128 native type, we need to +// include a std lib header to detect this - not ideal, but we'll +// be including later anyway when we select the std lib. +// +// Nevertheless, as of CUDA 7.5, using __float128 with the host +// compiler in pre-C++11 mode is still not supported. +// See https://svn.boost.org/trac/boost/ticket/11852 +// +#ifdef __cplusplus +#include +#else +#include +#endif +#if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__) && !defined(BOOST_NVCC_CXX03) +# define BOOST_HAS_FLOAT128 +#endif + +// C++0x features in 4.3.n and later +// +#if (BOOST_GCC_VERSION >= 40300) && defined(BOOST_GCC_CXX11) +// C++0x features are only enabled when -std=c++0x or -std=gnu++0x are +// passed on the command line, which in turn defines +// __GXX_EXPERIMENTAL_CXX0X__. +# define BOOST_HAS_DECLTYPE +# define BOOST_HAS_RVALUE_REFS +# define BOOST_HAS_STATIC_ASSERT +# define BOOST_HAS_VARIADIC_TMPL +#else +# define BOOST_NO_CXX11_DECLTYPE +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +# define BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_NO_CXX11_STATIC_ASSERT +#endif + +// C++0x features in 4.4.n and later +// +#if (BOOST_GCC_VERSION < 40400) || !defined(BOOST_GCC_CXX11) +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +# define BOOST_NO_CXX11_INLINE_NAMESPACES +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif + +#if BOOST_GCC_VERSION < 40500 +# define BOOST_NO_SFINAE_EXPR +#endif + +// GCC 4.5 forbids declaration of defaulted functions in private or protected sections +#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ == 5) || !defined(BOOST_GCC_CXX11) +# define BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS +#endif + +// C++0x features in 4.5.0 and later +// +#if (BOOST_GCC_VERSION < 40500) || !defined(BOOST_GCC_CXX11) +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_LAMBDAS +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +# define BOOST_NO_CXX11_RAW_LITERALS +# define BOOST_NO_CXX11_UNICODE_LITERALS +#endif + +// C++0x features in 4.5.1 and later +// +#if (BOOST_GCC_VERSION < 40501) || !defined(BOOST_GCC_CXX11) +// scoped enums have a serious bug in 4.4.0, so define BOOST_NO_CXX11_SCOPED_ENUMS before 4.5.1 +// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38064 +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +// C++0x features in 4.6.n and later +// +#if (BOOST_GCC_VERSION < 40600) || !defined(BOOST_GCC_CXX11) +#define BOOST_NO_CXX11_DEFAULTED_MOVES +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#endif + +// C++0x features in 4.7.n and later +// +#if (BOOST_GCC_VERSION < 40700) || !defined(BOOST_GCC_CXX11) +// Note that while constexpr is partly supported in gcc-4.6 it's a +// pre-std version with several bugs: +# define BOOST_NO_CXX11_CONSTEXPR +# define BOOST_NO_CXX11_FINAL +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +# define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#endif + +// C++0x features in 4.8.n and later +// +#if (BOOST_GCC_VERSION < 40800) || !defined(BOOST_GCC_CXX11) +# define BOOST_NO_CXX11_ALIGNAS +# define BOOST_NO_CXX11_THREAD_LOCAL +# define BOOST_NO_CXX11_SFINAE_EXPR +#endif + +// C++0x features in 4.8.1 and later +// +#if (BOOST_GCC_VERSION < 40801) || !defined(BOOST_GCC_CXX11) +# define BOOST_NO_CXX11_DECLTYPE_N3276 +# define BOOST_NO_CXX11_REF_QUALIFIERS +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif + +// C++14 features in 4.9.0 and later +// +#if (BOOST_GCC_VERSION < 40900) || (__cplusplus < 201300) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +# define BOOST_NO_CXX14_DECLTYPE_AUTO +# if !((BOOST_GCC_VERSION >= 40801) && (BOOST_GCC_VERSION < 40900) && defined(BOOST_GCC_CXX11)) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +# endif +#endif + + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if (BOOST_GCC_VERSION < 50200) || !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#if __GNUC__ >= 7 +# define BOOST_FALLTHROUGH __attribute__((fallthrough)) +#endif + +#ifdef __MINGW32__ +// Currently (June 2017) thread_local is broken on mingw for all current compiler releases, see +// https://sourceforge.net/p/mingw-w64/bugs/527/ +// Not setting this causes program termination on thread exit. +#define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +// +// Unused attribute: +#if __GNUC__ >= 4 +# define BOOST_ATTRIBUTE_UNUSED __attribute__((__unused__)) +#endif + +// Type aliasing hint. Supported since gcc 3.3. +#define BOOST_MAY_ALIAS __attribute__((__may_alias__)) + +// +// __builtin_unreachable: +#if BOOST_GCC_VERSION >= 40800 +#define BOOST_UNREACHABLE_RETURN(x) __builtin_unreachable(); +#endif + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "GNU C++ version " __VERSION__ +#endif + +// ConceptGCC compiler: +// http://www.generic-programming.org/software/ConceptGCC/ +#ifdef __GXX_CONCEPTS__ +# define BOOST_HAS_CONCEPTS +# define BOOST_COMPILER "ConceptGCC version " __VERSION__ +#endif + +// versions check: +// we don't know gcc prior to version 3.30: +#if (BOOST_GCC_VERSION< 30300) +# error "Compiler not configured - please reconfigure" +#endif +// +// last known and checked version is 8.1: +#if (BOOST_GCC_VERSION > 80100) +# if defined(BOOST_ASSERT_CONFIG) +# error "Boost.Config is older than your compiler - please check for an updated Boost release." +# else +// we don't emit warnings here anymore since there are no defect macros defined for +// gcc post 3.4, so any failures are gcc regressions... +//# warning "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + diff --git a/third-party/boost/boost/config/compiler/gcc_xml.hpp b/third-party/boost/boost/config/compiler/gcc_xml.hpp new file mode 100644 index 000000000..bdba4ed09 --- /dev/null +++ b/third-party/boost/boost/config/compiler/gcc_xml.hpp @@ -0,0 +1,111 @@ +// (C) Copyright John Maddock 2006. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// GCC-XML C++ compiler setup: + +# if !defined(__GCCXML_GNUC__) || ((__GCCXML_GNUC__ <= 3) && (__GCCXML_GNUC_MINOR__ <= 3)) +# define BOOST_NO_IS_ABSTRACT +# endif + +// +// Threading support: Turn this on unconditionally here (except for +// those platforms where we can know for sure). It will get turned off again +// later if no threading API is detected. +// +#if !defined(__MINGW32__) && !defined(_MSC_VER) && !defined(linux) && !defined(__linux) && !defined(__linux__) +# define BOOST_HAS_THREADS +#endif + +// +// gcc has "long long" +// +#define BOOST_HAS_LONG_LONG + +// C++0x features: +// +# define BOOST_NO_CXX11_CONSTEXPR +# define BOOST_NO_CXX11_NULLPTR +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +# define BOOST_NO_CXX11_DECLTYPE +# define BOOST_NO_CXX11_DECLTYPE_N3276 +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +# define BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_NO_CXX11_STATIC_ASSERT +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +# define BOOST_NO_CXX11_VARIADIC_MACROS +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_SCOPED_ENUMS +# define BOOST_NO_SFINAE_EXPR +# define BOOST_NO_CXX11_SFINAE_EXPR +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_LAMBDAS +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +# define BOOST_NO_CXX11_RANGE_BASED_FOR +# define BOOST_NO_CXX11_RAW_LITERALS +# define BOOST_NO_CXX11_UNICODE_LITERALS +# define BOOST_NO_CXX11_NOEXCEPT +# define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +# define BOOST_NO_CXX11_ALIGNAS +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +# define BOOST_NO_CXX11_INLINE_NAMESPACES +# define BOOST_NO_CXX11_REF_QUALIFIERS +# define BOOST_NO_CXX11_FINAL +# define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#define BOOST_COMPILER "GCC-XML C++ version " __GCCXML__ + + diff --git a/third-party/boost/boost/config/compiler/greenhills.hpp b/third-party/boost/boost/config/compiler/greenhills.hpp new file mode 100644 index 000000000..39112c2c1 --- /dev/null +++ b/third-party/boost/boost/config/compiler/greenhills.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Greenhills C++ compiler setup: + +#define BOOST_COMPILER "Greenhills C++ version " BOOST_STRINGIZE(__ghs) + +#include + +// +// versions check: +// we don't support Greenhills prior to version 0: +#if __ghs < 0 +# error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version is 0: +#if (__ghs > 0) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + + diff --git a/third-party/boost/boost/config/compiler/hp_acc.hpp b/third-party/boost/boost/config/compiler/hp_acc.hpp new file mode 100644 index 000000000..49d676fa2 --- /dev/null +++ b/third-party/boost/boost/config/compiler/hp_acc.hpp @@ -0,0 +1,147 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2003. +// (C) Copyright Aleksey Gurtovoy 2002. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Toon Knapen 2003. +// (C) Copyright Boris Gubenko 2006 - 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// HP aCC C++ compiler setup: + +#if defined(__EDG__) +#include +#endif + +#if (__HP_aCC <= 33100) +# define BOOST_NO_INTEGRAL_INT64_T +# define BOOST_NO_OPERATORS_IN_NAMESPACE +# if !defined(_NAMESPACE_STD) +# define BOOST_NO_STD_LOCALE +# define BOOST_NO_STRINGSTREAM +# endif +#endif + +#if (__HP_aCC <= 33300) +// member templates are sufficiently broken that we disable them for now +# define BOOST_NO_MEMBER_TEMPLATES +# define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS +# define BOOST_NO_USING_DECLARATION_OVERLOADS_FROM_TYPENAME_BASE +#endif + +#if (__HP_aCC <= 38000) +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif + +#if (__HP_aCC > 50000) && (__HP_aCC < 60000) +# define BOOST_NO_UNREACHABLE_RETURN_DETECTION +# define BOOST_NO_TEMPLATE_TEMPLATES +# define BOOST_NO_SWPRINTF +# define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS +# define BOOST_NO_IS_ABSTRACT +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +#endif + +// optional features rather than defects: +#if (__HP_aCC >= 33900) +# define BOOST_HAS_LONG_LONG +# define BOOST_HAS_PARTIAL_STD_ALLOCATOR +#endif + +#if (__HP_aCC >= 50000 ) && (__HP_aCC <= 53800 ) || (__HP_aCC < 31300 ) +# define BOOST_NO_MEMBER_TEMPLATE_KEYWORD +#endif + +// This macro should not be defined when compiling in strict ansi +// mode, but, currently, we don't have the ability to determine +// what standard mode we are compiling with. Some future version +// of aCC6 compiler will provide predefined macros reflecting the +// compilation options, including the standard mode. +#if (__HP_aCC >= 60000) || ((__HP_aCC > 38000) && defined(__hpxstd98)) +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif + +#define BOOST_COMPILER "HP aCC version " BOOST_STRINGIZE(__HP_aCC) + +// +// versions check: +// we don't support HP aCC prior to version 33000: +#if __HP_aCC < 33000 +# error "Compiler not supported or configured - please reconfigure" +#endif + +// +// Extended checks for supporting aCC on PA-RISC +#if __HP_aCC > 30000 && __HP_aCC < 50000 +# if __HP_aCC < 38000 + // versions prior to version A.03.80 not supported +# error "Compiler version not supported - version A.03.80 or higher is required" +# elif !defined(__hpxstd98) + // must compile using the option +hpxstd98 with version A.03.80 and above +# error "Compiler option '+hpxstd98' is required for proper support" +# endif //PA-RISC +#endif + +// +// C++0x features +// +// See boost\config\suffix.hpp for BOOST_NO_LONG_LONG +// +#if !defined(__EDG__) + +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_THREAD_LOCAL + +/* + See https://forums13.itrc.hp.com/service/forums/questionanswer.do?threadId=1443331 and + https://forums13.itrc.hp.com/service/forums/questionanswer.do?threadId=1443436 +*/ + +#if (__HP_aCC < 62500) || !defined(HP_CXX0x_SOURCE) + #define BOOST_NO_CXX11_VARIADIC_MACROS +#endif + +#endif + +// +// last known and checked version for HP-UX/ia64 is 61300 +// last known and checked version for PA-RISC is 38000 +#if ((__HP_aCC > 61300) || ((__HP_aCC > 38000) && defined(__hpxstd98))) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif diff --git a/third-party/boost/boost/config/compiler/intel.hpp b/third-party/boost/boost/config/compiler/intel.hpp new file mode 100644 index 000000000..f56807dbb --- /dev/null +++ b/third-party/boost/boost/config/compiler/intel.hpp @@ -0,0 +1,569 @@ +// (C) Copyright John Maddock 2001-8. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Aleksey Gurtovoy 2002 - 2003. +// (C) Copyright Guillaume Melquiond 2002 - 2003. +// (C) Copyright Beman Dawes 2003. +// (C) Copyright Martin Wille 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Intel compiler setup: + +#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) && (defined(_MSC_VER) || defined(__GNUC__)) + +#ifdef _MSC_VER + +#include + +#undef BOOST_MSVC +#undef BOOST_MSVC_FULL_VER + +#if (__INTEL_COMPILER >= 1500) && (_MSC_VER >= 1900) +// +// These appear to be supported, even though VC++ may not support them: +// +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_LOG1P +#undef BOOST_NO_CXX14_BINARY_LITERALS +// This one may be a little risky to enable?? +#undef BOOST_NO_SFINAE_EXPR + +#endif + +#if (__INTEL_COMPILER <= 1600) && !defined(BOOST_NO_CXX14_VARIABLE_TEMPLATES) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +#else // defined(_MSC_VER) + +#include + +#undef BOOST_GCC_VERSION +#undef BOOST_GCC_CXX11 +#undef BOOST_GCC +#undef BOOST_FALLTHROUGH + +// Broken in all versions up to 17 (newer versions not tested) +#if (__INTEL_COMPILER <= 1700) && !defined(BOOST_NO_CXX14_CONSTEXPR) +# define BOOST_NO_CXX14_CONSTEXPR +#endif + +#if (__INTEL_COMPILER >= 1800) && (__cplusplus >= 201703) +# define BOOST_FALLTHROUGH [[fallthrough]] +#endif + +#endif // defined(_MSC_VER) + +#undef BOOST_COMPILER + +#if defined(__INTEL_COMPILER) +#if __INTEL_COMPILER == 9999 +# define BOOST_INTEL_CXX_VERSION 1200 // Intel bug in 12.1. +#else +# define BOOST_INTEL_CXX_VERSION __INTEL_COMPILER +#endif +#elif defined(__ICL) +# define BOOST_INTEL_CXX_VERSION __ICL +#elif defined(__ICC) +# define BOOST_INTEL_CXX_VERSION __ICC +#elif defined(__ECC) +# define BOOST_INTEL_CXX_VERSION __ECC +#endif + +// Flags determined by comparing output of 'icpc -dM -E' with and without '-std=c++0x' +#if (!(defined(_WIN32) || defined(_WIN64)) && defined(__STDC_HOSTED__) && (__STDC_HOSTED__ && (BOOST_INTEL_CXX_VERSION <= 1200))) || defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_INTEL_STDCXX0X +#endif +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# define BOOST_INTEL_STDCXX0X +#endif + +#ifdef __GNUC__ +# define BOOST_INTEL_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if !defined(BOOST_COMPILER) +# if defined(BOOST_INTEL_STDCXX0X) +# define BOOST_COMPILER "Intel C++ C++0x mode version " BOOST_STRINGIZE(BOOST_INTEL_CXX_VERSION) +# else +# define BOOST_COMPILER "Intel C++ version " BOOST_STRINGIZE(BOOST_INTEL_CXX_VERSION) +# endif +#endif + +#define BOOST_INTEL BOOST_INTEL_CXX_VERSION + +#if defined(_WIN32) || defined(_WIN64) +# define BOOST_INTEL_WIN BOOST_INTEL +#else +# define BOOST_INTEL_LINUX BOOST_INTEL +#endif + +#else // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) && (defined(_MSC_VER) || defined(__GNUC__)) + +#include + +#if defined(__INTEL_COMPILER) +#if __INTEL_COMPILER == 9999 +# define BOOST_INTEL_CXX_VERSION 1200 // Intel bug in 12.1. +#else +# define BOOST_INTEL_CXX_VERSION __INTEL_COMPILER +#endif +#elif defined(__ICL) +# define BOOST_INTEL_CXX_VERSION __ICL +#elif defined(__ICC) +# define BOOST_INTEL_CXX_VERSION __ICC +#elif defined(__ECC) +# define BOOST_INTEL_CXX_VERSION __ECC +#endif + +// Flags determined by comparing output of 'icpc -dM -E' with and without '-std=c++0x' +#if (!(defined(_WIN32) || defined(_WIN64)) && defined(__STDC_HOSTED__) && (__STDC_HOSTED__ && (BOOST_INTEL_CXX_VERSION <= 1200))) || defined(__GXX_EXPERIMENTAL_CPP0X__) || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define BOOST_INTEL_STDCXX0X +#endif +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# define BOOST_INTEL_STDCXX0X +#endif + +#ifdef __GNUC__ +# define BOOST_INTEL_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +#if !defined(BOOST_COMPILER) +# if defined(BOOST_INTEL_STDCXX0X) +# define BOOST_COMPILER "Intel C++ C++0x mode version " BOOST_STRINGIZE(BOOST_INTEL_CXX_VERSION) +# else +# define BOOST_COMPILER "Intel C++ version " BOOST_STRINGIZE(BOOST_INTEL_CXX_VERSION) +# endif +#endif + +#define BOOST_INTEL BOOST_INTEL_CXX_VERSION + +#if defined(_WIN32) || defined(_WIN64) +# define BOOST_INTEL_WIN BOOST_INTEL +#else +# define BOOST_INTEL_LINUX BOOST_INTEL +#endif + +#if (BOOST_INTEL_CXX_VERSION <= 600) + +# if defined(_MSC_VER) && (_MSC_VER <= 1300) // added check for <= VC 7 (Peter Dimov) + +// Boost libraries assume strong standard conformance unless otherwise +// indicated by a config macro. As configured by Intel, the EDG front-end +// requires certain compiler options be set to achieve that strong conformance. +// Particularly /Qoption,c,--arg_dep_lookup (reported by Kirk Klobe & Thomas Witt) +// and /Zc:wchar_t,forScope. See boost-root/tools/build/intel-win32-tools.jam for +// details as they apply to particular versions of the compiler. When the +// compiler does not predefine a macro indicating if an option has been set, +// this config file simply assumes the option has been set. +// Thus BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP will not be defined, even if +// the compiler option is not enabled. + +# define BOOST_NO_SWPRINTF +# endif + +// Void returns, 64 bit integrals don't work when emulating VC 6 (Peter Dimov) + +# if defined(_MSC_VER) && (_MSC_VER <= 1200) +# define BOOST_NO_VOID_RETURNS +# define BOOST_NO_INTEGRAL_INT64_T +# endif + +#endif + +#if (BOOST_INTEL_CXX_VERSION <= 710) && defined(_WIN32) +# define BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS +#endif + +// See http://aspn.activestate.com/ASPN/Mail/Message/boost/1614864 +#if BOOST_INTEL_CXX_VERSION < 600 +# define BOOST_NO_INTRINSIC_WCHAR_T +#else +// We should test the macro _WCHAR_T_DEFINED to check if the compiler +// supports wchar_t natively. *BUT* there is a problem here: the standard +// headers define this macro if they typedef wchar_t. Anyway, we're lucky +// because they define it without a value, while Intel C++ defines it +// to 1. So we can check its value to see if the macro was defined natively +// or not. +// Under UNIX, the situation is exactly the same, but the macro _WCHAR_T +// is used instead. +# if ((_WCHAR_T_DEFINED + 0) == 0) && ((_WCHAR_T + 0) == 0) +# define BOOST_NO_INTRINSIC_WCHAR_T +# endif +#endif + +#if defined(__GNUC__) && !defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) +// +// Figure out when Intel is emulating this gcc bug +// (All Intel versions prior to 9.0.26, and versions +// later than that if they are set up to emulate gcc 3.2 +// or earlier): +// +# if ((__GNUC__ == 3) && (__GNUC_MINOR__ <= 2)) || (BOOST_INTEL < 900) || (__INTEL_COMPILER_BUILD_DATE < 20050912) +# define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +# endif +#endif +#if (defined(__GNUC__) && (__GNUC__ < 4)) || (defined(_WIN32) && (BOOST_INTEL_CXX_VERSION <= 1200)) || (BOOST_INTEL_CXX_VERSION <= 1200) +// GCC or VC emulation: +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif +// +// Verify that we have actually got BOOST_NO_INTRINSIC_WCHAR_T +// set correctly, if we don't do this now, we will get errors later +// in type_traits code among other things, getting this correct +// for the Intel compiler is actually remarkably fragile and tricky: +// +#ifdef __cplusplus +#if defined(BOOST_NO_INTRINSIC_WCHAR_T) +#include +template< typename T > struct assert_no_intrinsic_wchar_t; +template<> struct assert_no_intrinsic_wchar_t { typedef void type; }; +// if you see an error here then you need to unset BOOST_NO_INTRINSIC_WCHAR_T +// where it is defined above: +typedef assert_no_intrinsic_wchar_t::type assert_no_intrinsic_wchar_t_; +#else +template< typename T > struct assert_intrinsic_wchar_t; +template<> struct assert_intrinsic_wchar_t {}; +// if you see an error here then define BOOST_NO_INTRINSIC_WCHAR_T on the command line: +template<> struct assert_intrinsic_wchar_t {}; +#endif +#endif + +#if defined(_MSC_VER) && (_MSC_VER+0 >= 1000) +# if _MSC_VER >= 1200 +# define BOOST_HAS_MS_INT64 +# endif +# define BOOST_NO_SWPRINTF +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#elif defined(_WIN32) +# define BOOST_DISABLE_WIN32 +#endif + +// I checked version 6.0 build 020312Z, it implements the NRVO. +// Correct this as you find out which version of the compiler +// implemented the NRVO first. (Daniel Frey) +#if (BOOST_INTEL_CXX_VERSION >= 600) +# define BOOST_HAS_NRVO +#endif + +// Branch prediction hints +// I'm not sure 8.0 was the first version to support these builtins, +// update the condition if the version is not accurate. (Andrey Semashev) +#if defined(__GNUC__) && BOOST_INTEL_CXX_VERSION >= 800 +#define BOOST_LIKELY(x) __builtin_expect(x, 1) +#define BOOST_UNLIKELY(x) __builtin_expect(x, 0) +#endif + +// RTTI +// __RTTI is the EDG macro +// __INTEL_RTTI__ is the Intel macro +// __GXX_RTTI is the g++ macro +// _CPPRTTI is the MSVC++ macro +#if !defined(__RTTI) && !defined(__INTEL_RTTI__) && !defined(__GXX_RTTI) && !defined(_CPPRTTI) + +#if !defined(BOOST_NO_RTTI) +# define BOOST_NO_RTTI +#endif + +// in MS mode, static typeid works even when RTTI is off +#if !defined(_MSC_VER) && !defined(BOOST_NO_TYPEID) +# define BOOST_NO_TYPEID +#endif + +#endif + +// +// versions check: +// we don't support Intel prior to version 6.0: +#if BOOST_INTEL_CXX_VERSION < 600 +# error "Compiler not supported or configured - please reconfigure" +#endif + +// Intel on MacOS requires +#if defined(__APPLE__) && defined(__INTEL_COMPILER) +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif + +// Intel on Altix Itanium +#if defined(__itanium__) && defined(__INTEL_COMPILER) +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#endif + +// +// An attempt to value-initialize a pointer-to-member may trigger an +// internal error on Intel <= 11.1 (last checked version), as was +// reported by John Maddock, Intel support issue 589832, May 2010. +// Moreover, according to test results from Huang-Vista-x86_32_intel, +// intel-vc9-win-11.1 may leave a non-POD array uninitialized, in some +// cases when it should be value-initialized. +// (Niels Dekker, LKEB, May 2010) +// Apparently Intel 12.1 (compiler version number 9999 !!) has the same issue (compiler regression). +#if defined(__INTEL_COMPILER) +# if (__INTEL_COMPILER <= 1110) || (__INTEL_COMPILER == 9999) || (defined(_WIN32) && (__INTEL_COMPILER < 1600)) +# define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +# endif +#endif + +// +// Dynamic shared object (DSO) and dynamic-link library (DLL) support +// +#if defined(__GNUC__) && (__GNUC__ >= 4) +# define BOOST_SYMBOL_EXPORT __attribute__((visibility("default"))) +# define BOOST_SYMBOL_IMPORT +# define BOOST_SYMBOL_VISIBLE __attribute__((visibility("default"))) +#endif + +// Type aliasing hint +#if defined(__GNUC__) && (BOOST_INTEL_CXX_VERSION >= 1300) +# define BOOST_MAY_ALIAS __attribute__((__may_alias__)) +#endif + +// +// C++0x features +// For each feature we need to check both the Intel compiler version, +// and the version of MSVC or GCC that we are emulating. +// See http://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler/ +// for a list of which features were implemented in which Intel releases. +// +#if defined(BOOST_INTEL_STDCXX0X) +// BOOST_NO_CXX11_CONSTEXPR: +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40600)) && !defined(_MSC_VER) +// Available in earlier Intel versions, but fail our tests: +# undef BOOST_NO_CXX11_CONSTEXPR +#endif +// BOOST_NO_CXX11_NULLPTR: +#if (BOOST_INTEL_CXX_VERSION >= 1210) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40600)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_NULLPTR +#endif +// BOOST_NO_CXX11_TEMPLATE_ALIASES +#if (BOOST_INTEL_CXX_VERSION >= 1210) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40700)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_TEMPLATE_ALIASES +#endif + +// BOOST_NO_CXX11_DECLTYPE +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40300)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_DECLTYPE +#endif + +// BOOST_NO_CXX11_DECLTYPE_N3276 +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40800)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_DECLTYPE_N3276 +#endif + +// BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40300)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif + +// BOOST_NO_CXX11_RVALUE_REFERENCES +#if (BOOST_INTEL_CXX_VERSION >= 1300) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40300)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +// This is available from earlier Intel versions, but breaks Filesystem and other libraries: +# undef BOOST_NO_CXX11_RVALUE_REFERENCES +#endif + +// BOOST_NO_CXX11_STATIC_ASSERT +#if (BOOST_INTEL_CXX_VERSION >= 1110) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40300)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_STATIC_ASSERT +#endif + +// BOOST_NO_CXX11_VARIADIC_TEMPLATES +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif + +// BOOST_NO_CXX11_VARIADIC_MACROS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40200)) && (!defined(_MSC_VER) || (_MSC_VER >= 1400)) +# undef BOOST_NO_CXX11_VARIADIC_MACROS +#endif + +// BOOST_NO_CXX11_AUTO_DECLARATIONS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_AUTO_DECLARATIONS +#endif + +// BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#endif + +// BOOST_NO_CXX11_CHAR16_T +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +# undef BOOST_NO_CXX11_CHAR16_T +#endif + +// BOOST_NO_CXX11_CHAR32_T +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +# undef BOOST_NO_CXX11_CHAR32_T +#endif + +// BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#endif + +// BOOST_NO_CXX11_DELETED_FUNCTIONS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_DELETED_FUNCTIONS +#endif + +// BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_VER >= 1700)) +# undef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#endif + +// BOOST_NO_CXX11_SCOPED_ENUMS +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40501)) && (!defined(_MSC_VER) || (_MSC_VER >= 1700)) +// This is available but broken in earlier Intel releases. +# undef BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +// BOOST_NO_SFINAE_EXPR +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +# undef BOOST_NO_SFINAE_EXPR +#endif + +// BOOST_NO_CXX11_SFINAE_EXPR +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40800)) && !defined(_MSC_VER) +# undef BOOST_NO_CXX11_SFINAE_EXPR +#endif + +// BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +// This is available in earlier Intel releases, but breaks Multiprecision: +# undef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#endif + +// BOOST_NO_CXX11_LAMBDAS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) && (!defined(_MSC_VER) || (_MSC_VER >= 1600)) +# undef BOOST_NO_CXX11_LAMBDAS +#endif + +// BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) +# undef BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#endif + +// BOOST_NO_CXX11_RANGE_BASED_FOR +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40600)) && (!defined(_MSC_VER) || (_MSC_VER >= 1700)) +# undef BOOST_NO_CXX11_RANGE_BASED_FOR +#endif + +// BOOST_NO_CXX11_RAW_LITERALS +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_RAW_LITERALS +#endif + +// BOOST_NO_CXX11_UNICODE_LITERALS +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40500)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +# undef BOOST_NO_CXX11_UNICODE_LITERALS +#endif + +// BOOST_NO_CXX11_NOEXCEPT +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40600)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +// Available in earlier Intel release, but generates errors when used with +// conditional exception specifications, for example in multiprecision: +# undef BOOST_NO_CXX11_NOEXCEPT +#endif + +// BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40600)) && (!defined(_MSC_VER) || (_MSC_VER >= 9999)) +# undef BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#endif + +// BOOST_NO_CXX11_USER_DEFINED_LITERALS +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40700)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 190021730)) +# undef BOOST_NO_CXX11_USER_DEFINED_LITERALS +#endif + +// BOOST_NO_CXX11_ALIGNAS +#if (BOOST_INTEL_CXX_VERSION >= 1500) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40800)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 190021730)) +# undef BOOST_NO_CXX11_ALIGNAS +#endif + +// BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#if (BOOST_INTEL_CXX_VERSION >= 1200) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 180020827)) +# undef BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#endif + +// BOOST_NO_CXX11_INLINE_NAMESPACES +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40400)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 190021730)) +# undef BOOST_NO_CXX11_INLINE_NAMESPACES +#endif + +// BOOST_NO_CXX11_REF_QUALIFIERS +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40800)) && (!defined(_MSC_VER) || (_MSC_FULL_VER >= 190021730)) +# undef BOOST_NO_CXX11_REF_QUALIFIERS +#endif + +// BOOST_NO_CXX11_FINAL +#if (BOOST_INTEL_CXX_VERSION >= 1400) && (!defined(BOOST_INTEL_GCC_VERSION) || (BOOST_INTEL_GCC_VERSION >= 40700)) && (!defined(_MSC_VER) || (_MSC_VER >= 1700)) +# undef BOOST_NO_CXX11_FINAL +#endif + +#endif // defined(BOOST_INTEL_STDCXX0X) + +// +// Broken in all versions up to 15: +#define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS + +#if defined(BOOST_INTEL_STDCXX0X) && (BOOST_INTEL_CXX_VERSION <= 1310) +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#endif + +#if defined(BOOST_INTEL_STDCXX0X) && (BOOST_INTEL_CXX_VERSION == 1400) +// A regression in Intel's compiler means that seems to be broken in this release as well as : +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_TUPLE +#endif + +#if (BOOST_INTEL_CXX_VERSION < 1200) +// +// fenv.h appears not to work with Intel prior to 12.0: +// +# define BOOST_NO_FENV_H +#endif + +// Intel 13.10 fails to access defaulted functions of a base class declared in private or protected sections, +// producing the following errors: +// error #453: protected function "..." (declared at ...") is not accessible through a "..." pointer or object +#if (BOOST_INTEL_CXX_VERSION <= 1310) +# define BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS +#endif + +#if defined(_MSC_VER) && (_MSC_VER >= 1600) +# define BOOST_HAS_STDINT_H +#endif + +#if defined(__CUDACC__) +# if defined(BOOST_GCC_CXX11) +# define BOOST_NVCC_CXX11 +# else +# define BOOST_NVCC_CXX03 +# endif +#endif + +#if defined(__LP64__) && defined(__GNUC__) && (BOOST_INTEL_CXX_VERSION >= 1310) && !defined(BOOST_NVCC_CXX03) +# define BOOST_HAS_INT128 +#endif + +#endif // defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1500) && (defined(_MSC_VER) || defined(__GNUC__)) +// +// last known and checked version: +#if (BOOST_INTEL_CXX_VERSION > 1700) +# if defined(BOOST_ASSERT_CONFIG) +# error "Boost.Config is older than your compiler - please check for an updated Boost release." +# elif defined(_MSC_VER) +// +// We don't emit this warning any more, since we have so few +// defect macros set anyway (just the one). +// +//# pragma message("boost: Unknown compiler version - please run the configure tests and report the results") +# endif +#endif + diff --git a/third-party/boost/boost/config/compiler/kai.hpp b/third-party/boost/boost/config/compiler/kai.hpp new file mode 100644 index 000000000..0b22ec1d6 --- /dev/null +++ b/third-party/boost/boost/config/compiler/kai.hpp @@ -0,0 +1,33 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright David Abrahams 2002. +// (C) Copyright Aleksey Gurtovoy 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Kai C++ compiler setup: + +#include + +# if (__KCC_VERSION <= 4001) || !defined(BOOST_STRICT_CONFIG) + // at least on Sun, the contents of is not in namespace std +# define BOOST_NO_STDC_NAMESPACE +# endif + +// see also common_edg.hpp which needs a special check for __KCC +# if !defined(_EXCEPTIONS) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +# endif + +// +// last known and checked version is 4001: +#if (__KCC_VERSION > 4001) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + + + diff --git a/third-party/boost/boost/config/compiler/metrowerks.hpp b/third-party/boost/boost/config/compiler/metrowerks.hpp new file mode 100644 index 000000000..0e18e1809 --- /dev/null +++ b/third-party/boost/boost/config/compiler/metrowerks.hpp @@ -0,0 +1,195 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright David Abrahams 2001 - 2002. +// (C) Copyright Beman Dawes 2001 - 2003. +// (C) Copyright Stefan Slapeta 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Metrowerks C++ compiler setup: + +// locale support is disabled when linking with the dynamic runtime +# ifdef _MSL_NO_LOCALE +# define BOOST_NO_STD_LOCALE +# endif + +# if __MWERKS__ <= 0x2301 // 5.3 +# define BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# define BOOST_NO_POINTER_TO_MEMBER_CONST +# define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS +# define BOOST_NO_MEMBER_TEMPLATE_KEYWORD +# endif + +# if __MWERKS__ <= 0x2401 // 6.2 +//# define BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# endif + +# if(__MWERKS__ <= 0x2407) // 7.x +# define BOOST_NO_MEMBER_FUNCTION_SPECIALIZATIONS +# define BOOST_NO_UNREACHABLE_RETURN_DETECTION +# endif + +# if(__MWERKS__ <= 0x3003) // 8.x +# define BOOST_NO_SFINAE +# endif + +// the "|| !defined(BOOST_STRICT_CONFIG)" part should apply to the last +// tested version *only*: +# if(__MWERKS__ <= 0x3207) || !defined(BOOST_STRICT_CONFIG) // 9.6 +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +# define BOOST_NO_IS_ABSTRACT +# endif + +#if !__option(wchar_type) +# define BOOST_NO_INTRINSIC_WCHAR_T +#endif + +#if !__option(exceptions) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +#if (__INTEL__ && _WIN32) || (__POWERPC__ && macintosh) +# if __MWERKS__ == 0x3000 +# define BOOST_COMPILER_VERSION 8.0 +# elif __MWERKS__ == 0x3001 +# define BOOST_COMPILER_VERSION 8.1 +# elif __MWERKS__ == 0x3002 +# define BOOST_COMPILER_VERSION 8.2 +# elif __MWERKS__ == 0x3003 +# define BOOST_COMPILER_VERSION 8.3 +# elif __MWERKS__ == 0x3200 +# define BOOST_COMPILER_VERSION 9.0 +# elif __MWERKS__ == 0x3201 +# define BOOST_COMPILER_VERSION 9.1 +# elif __MWERKS__ == 0x3202 +# define BOOST_COMPILER_VERSION 9.2 +# elif __MWERKS__ == 0x3204 +# define BOOST_COMPILER_VERSION 9.3 +# elif __MWERKS__ == 0x3205 +# define BOOST_COMPILER_VERSION 9.4 +# elif __MWERKS__ == 0x3206 +# define BOOST_COMPILER_VERSION 9.5 +# elif __MWERKS__ == 0x3207 +# define BOOST_COMPILER_VERSION 9.6 +# else +# define BOOST_COMPILER_VERSION __MWERKS__ +# endif +#else +# define BOOST_COMPILER_VERSION __MWERKS__ +#endif + +// +// C++0x features +// +// See boost\config\suffix.hpp for BOOST_NO_LONG_LONG +// +#if __MWERKS__ > 0x3206 && __option(rvalue_refs) +# define BOOST_HAS_RVALUE_REFS +#else +# define BOOST_NO_CXX11_RVALUE_REFERENCES +#endif +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_VARIADIC_MACROS +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +#define BOOST_COMPILER "Metrowerks CodeWarrior C++ version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION) + +// +// versions check: +// we don't support Metrowerks prior to version 5.3: +#if __MWERKS__ < 0x2301 +# error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version: +#if (__MWERKS__ > 0x3205) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + + + + + + + diff --git a/third-party/boost/boost/config/compiler/mpw.hpp b/third-party/boost/boost/config/compiler/mpw.hpp new file mode 100644 index 000000000..05c066efb --- /dev/null +++ b/third-party/boost/boost/config/compiler/mpw.hpp @@ -0,0 +1,137 @@ +// (C) Copyright John Maddock 2001 - 2002. +// (C) Copyright Aleksey Gurtovoy 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// MPW C++ compilers setup: + +# if defined(__SC__) +# define BOOST_COMPILER "MPW SCpp version " BOOST_STRINGIZE(__SC__) +# elif defined(__MRC__) +# define BOOST_COMPILER "MPW MrCpp version " BOOST_STRINGIZE(__MRC__) +# else +# error "Using MPW compiler configuration by mistake. Please update." +# endif + +// +// MPW 8.90: +// +#if (MPW_CPLUS <= 0x890) || !defined(BOOST_STRICT_CONFIG) +# define BOOST_NO_CV_SPECIALIZATIONS +# define BOOST_NO_DEPENDENT_NESTED_DERIVATIONS +# define BOOST_NO_DEPENDENT_TYPES_IN_TEMPLATE_VALUE_PARAMETERS +# define BOOST_NO_INCLASS_MEMBER_INITIALIZATION +# define BOOST_NO_INTRINSIC_WCHAR_T +# define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +# define BOOST_NO_USING_TEMPLATE + +# define BOOST_NO_CWCHAR +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + +# define BOOST_NO_STD_ALLOCATOR /* actually a bug with const reference overloading */ + +#endif + +// +// C++0x features +// +// See boost\config\suffix.hpp for BOOST_NO_LONG_LONG +// +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_VARIADIC_MACROS +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +// +// versions check: +// we don't support MPW prior to version 8.9: +#if MPW_CPLUS < 0x890 +# error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version is 0x890: +#if (MPW_CPLUS > 0x890) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + + diff --git a/third-party/boost/boost/config/compiler/nvcc.hpp b/third-party/boost/boost/config/compiler/nvcc.hpp new file mode 100644 index 000000000..ed035fcf7 --- /dev/null +++ b/third-party/boost/boost/config/compiler/nvcc.hpp @@ -0,0 +1,58 @@ +// (C) Copyright Eric Jourdanneau, Joel Falcou 2010 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// NVIDIA CUDA C++ compiler setup + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "NVIDIA CUDA C++ Compiler" +#endif + +#if defined(__CUDACC_VER_MAJOR__) && defined(__CUDACC_VER_MINOR__) && defined(__CUDACC_VER_BUILD__) +# define BOOST_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 1000000 + __CUDACC_VER_MINOR__ * 10000 + __CUDACC_VER_BUILD__) +#else +// We don't really know what the CUDA version is, but it's definitely before 7.5: +# define BOOST_CUDA_VERSION 7000000 +#endif + +// NVIDIA Specific support +// BOOST_GPU_ENABLED : Flag a function or a method as being enabled on the host and device +#define BOOST_GPU_ENABLED __host__ __device__ + +// A bug in version 7.0 of CUDA prevents use of variadic templates in some occasions +// https://svn.boost.org/trac/boost/ticket/11897 +// This is fixed in 7.5. As the following version macro was introduced in 7.5 an existance +// check is enough to detect versions < 7.5 +#if BOOST_CUDA_VERSION < 7050000 +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif +// The same bug is back again in 8.0: +#if (BOOST_CUDA_VERSION > 8000000) && (BOOST_CUDA_VERSION < 8010000) +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif +// CUDA (8.0) has no constexpr support in msvc mode: +#if defined(_MSC_VER) && (BOOST_CUDA_VERSION < 9000000) +# define BOOST_NO_CXX11_CONSTEXPR +#endif + +#ifdef __CUDACC__ +// +// When compiing .cu files, there's a bunch of stuff that doesn't work with msvc: +// +#if defined(_MSC_VER) +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +# define BOOST_NO_CXX11_UNICODE_LITERALS +#endif +// +// And this one effects the NVCC front end, +// See https://svn.boost.org/trac/boost/ticket/13049 +// +#if (BOOST_CUDA_VERSION >= 8000000) && (BOOST_CUDA_VERSION < 8010000) +# define BOOST_NO_CXX11_NOEXCEPT +#endif + +#endif + diff --git a/third-party/boost/boost/config/compiler/pathscale.hpp b/third-party/boost/boost/config/compiler/pathscale.hpp new file mode 100644 index 000000000..1318d275a --- /dev/null +++ b/third-party/boost/boost/config/compiler/pathscale.hpp @@ -0,0 +1,135 @@ +// (C) Copyright Bryce Lelbach 2011 + +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// PathScale EKOPath C++ Compiler + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "PathScale EKOPath C++ Compiler version " __PATHSCALE__ +#endif + +#if __PATHCC__ >= 6 +// PathCC is based on clang, and supports the __has_*() builtins used +// to detect features in clang.hpp. Since the clang toolset is much +// better maintained, it is more convenient to reuse its definitions. +# include "boost/config/compiler/clang.hpp" +#elif __PATHCC__ >= 4 +# define BOOST_MSVC6_MEMBER_TEMPLATES +# define BOOST_HAS_UNISTD_H +# define BOOST_HAS_STDINT_H +# define BOOST_HAS_SIGACTION +# define BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_THREADS +# define BOOST_HAS_PTHREADS +# define BOOST_HAS_PTHREAD_YIELD +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_PARTIAL_STD_ALLOCATOR +# define BOOST_HAS_NRVO +# define BOOST_HAS_NL_TYPES_H +# define BOOST_HAS_NANOSLEEP +# define BOOST_HAS_LONG_LONG +# define BOOST_HAS_LOG1P +# define BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_EXPM1 +# define BOOST_HAS_DIRENT_H +# define BOOST_HAS_CLOCK_GETTIME +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +# define BOOST_NO_CXX11_UNICODE_LITERALS +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +# define BOOST_NO_CXX11_STATIC_ASSERT +# define BOOST_NO_SFINAE_EXPR +# define BOOST_NO_CXX11_SFINAE_EXPR +# define BOOST_NO_CXX11_SCOPED_ENUMS +# define BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_NO_CXX11_RANGE_BASED_FOR +# define BOOST_NO_CXX11_RAW_LITERALS +# define BOOST_NO_CXX11_NULLPTR +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_NOEXCEPT +# define BOOST_NO_CXX11_LAMBDAS +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +# define BOOST_NO_CXX11_DECLTYPE +# define BOOST_NO_CXX11_DECLTYPE_N3276 +# define BOOST_NO_CXX11_CONSTEXPR +# define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +# define BOOST_NO_CXX11_CHAR32_T +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +# define BOOST_NO_CXX11_ALIGNAS +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +# define BOOST_NO_CXX11_INLINE_NAMESPACES +# define BOOST_NO_CXX11_REF_QUALIFIERS +# define BOOST_NO_CXX11_FINAL +# define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif +#endif diff --git a/third-party/boost/boost/config/compiler/pgi.hpp b/third-party/boost/boost/config/compiler/pgi.hpp new file mode 100644 index 000000000..4e909d8a1 --- /dev/null +++ b/third-party/boost/boost/config/compiler/pgi.hpp @@ -0,0 +1,23 @@ +// (C) Copyright Noel Belcourt 2007. +// Copyright 2017, NVIDIA CORPORATION. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// PGI C++ compiler setup: + +#define BOOST_COMPILER_VERSION __PGIC__##__PGIC_MINOR__ +#define BOOST_COMPILER "PGI compiler version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION) + +// PGI is mostly GNU compatible. So start with that. +#include + +// Now adjust for things that are different. + +// __float128 is a typedef, not a distinct type. +#undef BOOST_HAS_FLOAT128 + +// __int128 is not supported. +#undef BOOST_HAS_INT128 diff --git a/third-party/boost/boost/config/compiler/sgi_mipspro.hpp b/third-party/boost/boost/config/compiler/sgi_mipspro.hpp new file mode 100644 index 000000000..54433c997 --- /dev/null +++ b/third-party/boost/boost/config/compiler/sgi_mipspro.hpp @@ -0,0 +1,29 @@ +// (C) Copyright John Maddock 2001 - 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// SGI C++ compiler setup: + +#define BOOST_COMPILER "SGI Irix compiler version " BOOST_STRINGIZE(_COMPILER_VERSION) + +#include + +// +// Threading support: +// Turn this on unconditionally here, it will get turned off again later +// if no threading API is detected. +// +#define BOOST_HAS_THREADS +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP + +#undef BOOST_NO_SWPRINTF +#undef BOOST_DEDUCED_TYPENAME + +// +// version check: +// probably nothing to do here? + + diff --git a/third-party/boost/boost/config/compiler/sunpro_cc.hpp b/third-party/boost/boost/config/compiler/sunpro_cc.hpp new file mode 100644 index 000000000..41b7bcade --- /dev/null +++ b/third-party/boost/boost/config/compiler/sunpro_cc.hpp @@ -0,0 +1,213 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright Jens Maurer 2001 - 2003. +// (C) Copyright Peter Dimov 2002. +// (C) Copyright Aleksey Gurtovoy 2002 - 2003. +// (C) Copyright David Abrahams 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Sun C++ compiler setup: + +# if __SUNPRO_CC <= 0x500 +# define BOOST_NO_MEMBER_TEMPLATES +# define BOOST_NO_FUNCTION_TEMPLATE_ORDERING +# endif + +# if (__SUNPRO_CC <= 0x520) + // + // Sunpro 5.2 and earler: + // + // although sunpro 5.2 supports the syntax for + // inline initialization it often gets the value + // wrong, especially where the value is computed + // from other constants (J Maddock 6th May 2001) +# define BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + // Although sunpro 5.2 supports the syntax for + // partial specialization, it often seems to + // bind to the wrong specialization. Better + // to disable it until suppport becomes more stable + // (J Maddock 6th May 2001). +# define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +# endif + +# if (__SUNPRO_CC <= 0x530) + // Requesting debug info (-g) with Boost.Python results + // in an internal compiler error for "static const" + // initialized in-class. + // >> Assertion: (../links/dbg_cstabs.cc, line 611) + // while processing ../test.cpp at line 0. + // (Jens Maurer according to Gottfried Ganssauge 04 Mar 2002) +# define BOOST_NO_INCLASS_MEMBER_INITIALIZATION + + // SunPro 5.3 has better support for partial specialization, + // but breaks when compiling std::less > + // (Jens Maurer 4 Nov 2001). + + // std::less specialization fixed as reported by George + // Heintzelman; partial specialization re-enabled + // (Peter Dimov 17 Jan 2002) + +//# define BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION + + // integral constant expressions with 64 bit numbers fail +# define BOOST_NO_INTEGRAL_INT64_T +# endif + +# if (__SUNPRO_CC < 0x570) +# define BOOST_NO_TEMPLATE_TEMPLATES + // see http://lists.boost.org/MailArchives/boost/msg47184.php + // and http://lists.boost.org/MailArchives/boost/msg47220.php +# define BOOST_NO_INCLASS_MEMBER_INITIALIZATION +# define BOOST_NO_SFINAE +# define BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS +# endif +# if (__SUNPRO_CC <= 0x580) +# define BOOST_NO_IS_ABSTRACT +# endif + +# if (__SUNPRO_CC <= 0x5100) + // Sun 5.10 may not correctly value-initialize objects of + // some user defined types, as was reported in April 2010 + // (CR 6947016), and confirmed by Steve Clamage. + // (Niels Dekker, LKEB, May 2010). +# define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +# endif + +// +// Dynamic shared object (DSO) and dynamic-link library (DLL) support +// +#if __SUNPRO_CC > 0x500 +# define BOOST_SYMBOL_EXPORT __global +# define BOOST_SYMBOL_IMPORT __global +# define BOOST_SYMBOL_VISIBLE __global +#endif + +#if (__SUNPRO_CC < 0x5130) +// C++03 features in 12.4: +#define BOOST_NO_TWO_PHASE_NAME_LOOKUP +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_ADL_BARRIER +#define BOOST_NO_CXX11_VARIADIC_MACROS +#endif + +#if (__SUNPRO_CC < 0x5130) || (__cplusplus < 201100) +// C++11 only featuires in 12.4: +#define BOOST_NO_CXX11_AUTO_DECLARATIONS +#define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#define BOOST_NO_CXX11_CHAR16_T +#define BOOST_NO_CXX11_CHAR32_T +#define BOOST_NO_CXX11_CONSTEXPR +#define BOOST_NO_CXX11_DECLTYPE +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#define BOOST_NO_CXX11_EXTERN_TEMPLATE +#define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RVALUE_REFERENCES +#define BOOST_NO_CXX11_SCOPED_ENUMS +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_FINAL +#endif + +#if (__SUNPRO_CC < 0x5140) || (__cplusplus < 201103) +#define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +// +// C++0x features +// +# define BOOST_HAS_LONG_LONG + +#define BOOST_NO_CXX11_SFINAE_EXPR + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) || (__cplusplus < 201402L) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +// Turn on threading support for Solaris 12. +// Ticket #11972 +#if (__SUNPRO_CC >= 0x5140) && defined(__SunOS_5_12) && !defined(BOOST_HAS_THREADS) +# define BOOST_HAS_THREADS +#endif + +// +// Version +// + +#define BOOST_COMPILER "Sun compiler version " BOOST_STRINGIZE(__SUNPRO_CC) + +// +// versions check: +// we don't support sunpro prior to version 4: +#if __SUNPRO_CC < 0x400 +#error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version: +#if (__SUNPRO_CC > 0x5150) +# if defined(BOOST_ASSERT_CONFIG) +# error "Boost.Config is older than your compiler - please check for an updated Boost release." +# endif +#endif diff --git a/third-party/boost/boost/config/compiler/vacpp.hpp b/third-party/boost/boost/config/compiler/vacpp.hpp new file mode 100644 index 000000000..8e2644996 --- /dev/null +++ b/third-party/boost/boost/config/compiler/vacpp.hpp @@ -0,0 +1,183 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Toon Knapen 2001 - 2003. +// (C) Copyright Lie-Quan Lee 2001. +// (C) Copyright Markus Schoepflin 2002 - 2003. +// (C) Copyright Beman Dawes 2002 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Visual Age (IBM) C++ compiler setup: + +#if __IBMCPP__ <= 501 +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +# define BOOST_NO_MEMBER_FUNCTION_SPECIALIZATIONS +#endif + +#if (__IBMCPP__ <= 502) +// Actually the compiler supports inclass member initialization but it +// requires a definition for the class member and it doesn't recognize +// it as an integral constant expression when used as a template argument. +# define BOOST_NO_INCLASS_MEMBER_INITIALIZATION +# define BOOST_NO_INTEGRAL_INT64_T +# define BOOST_NO_MEMBER_TEMPLATE_KEYWORD +#endif + +#if (__IBMCPP__ <= 600) || !defined(BOOST_STRICT_CONFIG) +# define BOOST_NO_POINTER_TO_MEMBER_TEMPLATE_PARAMETERS +#endif + +#if (__IBMCPP__ <= 1110) +// XL C++ V11.1 and earlier versions may not always value-initialize +// a temporary object T(), when T is a non-POD aggregate class type. +// Michael Wong (IBM Canada Ltd) has confirmed this issue and gave it +// high priority. -- Niels Dekker (LKEB), May 2010. +# define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +#endif + +// +// On AIX thread support seems to be indicated by _THREAD_SAFE: +// +#ifdef _THREAD_SAFE +# define BOOST_HAS_THREADS +#endif + +#define BOOST_COMPILER "IBM Visual Age version " BOOST_STRINGIZE(__IBMCPP__) + +// +// versions check: +// we don't support Visual age prior to version 5: +#if __IBMCPP__ < 500 +#error "Compiler not supported or configured - please reconfigure" +#endif +// +// last known and checked version is 1210: +#if (__IBMCPP__ > 1210) +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + +// Some versions of the compiler have issues with default arguments on partial specializations +#if __IBMCPP__ <= 1010 +#define BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS +#endif + +// Type aliasing hint. Supported since XL C++ 13.1 +#if (__IBMCPP__ >= 1310) +# define BOOST_MAY_ALIAS __attribute__((__may_alias__)) +#endif + +// +// C++0x features +// +// See boost\config\suffix.hpp for BOOST_NO_LONG_LONG +// +#if ! __IBMCPP_AUTO_TYPEDEDUCTION +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#endif +#if ! __IBMCPP_UTF_LITERAL__ +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +#endif +#if ! __IBMCPP_CONSTEXPR +# define BOOST_NO_CXX11_CONSTEXPR +#endif +#if ! __IBMCPP_DECLTYPE +# define BOOST_NO_CXX11_DECLTYPE +#else +# define BOOST_HAS_DECLTYPE +#endif +#define BOOST_NO_CXX11_DECLTYPE_N3276 +#define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#define BOOST_NO_CXX11_DELETED_FUNCTIONS +#if ! __IBMCPP_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#endif +#if ! __IBMCPP_EXTERN_TEMPLATE +# define BOOST_NO_CXX11_EXTERN_TEMPLATE +#endif +#if ! __IBMCPP_VARIADIC_TEMPLATES +// not enabled separately at this time +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#if ! __IBMCPP_RVALUE_REFERENCES +# define BOOST_NO_CXX11_RVALUE_REFERENCES +#endif +#if ! __IBMCPP_SCOPED_ENUM +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#if ! __IBMCPP_STATIC_ASSERT +# define BOOST_NO_CXX11_STATIC_ASSERT +#endif +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_UNICODE_LITERALS +#if ! __IBMCPP_VARIADIC_TEMPLATES +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif +#if ! __C99_MACRO_WITH_VA_ARGS +# define BOOST_NO_CXX11_VARIADIC_MACROS +#endif +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#define BOOST_NO_CXX11_INLINE_NAMESPACES +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_THREAD_LOCAL + +// C++ 14: +#if !defined(__cpp_aggregate_nsdmi) || (__cpp_aggregate_nsdmi < 201304) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif +#if !defined(__cpp_binary_literals) || (__cpp_binary_literals < 201304) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif +#if !defined(__cpp_constexpr) || (__cpp_constexpr < 201304) +# define BOOST_NO_CXX14_CONSTEXPR +#endif +#if !defined(__cpp_decltype_auto) || (__cpp_decltype_auto < 201304) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif +#if (__cplusplus < 201304) // There's no SD6 check for this.... +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif +#if !defined(__cpp_generic_lambdas) || (__cpp_generic_lambdas < 201304) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif +#if !defined(__cpp_init_captures) || (__cpp_init_captures < 201304) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif +#if !defined(__cpp_return_type_deduction) || (__cpp_return_type_deduction < 201304) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif +#if !defined(__cpp_variable_templates) || (__cpp_variable_templates < 201304) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +// C++17 +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif +#if !defined(__cpp_inline_variables) || (__cpp_inline_variables < 201606) +# define BOOST_NO_CXX17_INLINE_VARIABLES +#endif +#if !defined(__cpp_fold_expressions) || (__cpp_fold_expressions < 201603) +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif diff --git a/third-party/boost/boost/config/compiler/visualc.hpp b/third-party/boost/boost/config/compiler/visualc.hpp new file mode 100644 index 000000000..29642473c --- /dev/null +++ b/third-party/boost/boost/config/compiler/visualc.hpp @@ -0,0 +1,359 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001 - 2002. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright Aleksey Gurtovoy 2002. +// (C) Copyright David Abrahams 2002 - 2003. +// (C) Copyright Beman Dawes 2002 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. +// +// Microsoft Visual C++ compiler setup: +// +// We need to be careful with the checks in this file, as contrary +// to popular belief there are versions with _MSC_VER with the final +// digit non-zero (mainly the MIPS cross compiler). +// +// So we either test _MSC_VER >= XXXX or else _MSC_VER < XXXX. +// No other comparisons (==, >, or <=) are safe. +// + +#define BOOST_MSVC _MSC_VER + +// +// Helper macro BOOST_MSVC_FULL_VER for use in Boost code: +// +#if _MSC_FULL_VER > 100000000 +# define BOOST_MSVC_FULL_VER _MSC_FULL_VER +#else +# define BOOST_MSVC_FULL_VER (_MSC_FULL_VER * 10) +#endif + +// Attempt to suppress VC6 warnings about the length of decorated names (obsolete): +#pragma warning( disable : 4503 ) // warning: decorated name length exceeded + +#define BOOST_HAS_PRAGMA_ONCE + +// +// versions check: +// we don't support Visual C++ prior to version 7.1: +#if _MSC_VER < 1310 +# error "Compiler not supported or configured - please reconfigure" +#endif + +#if _MSC_FULL_VER < 180020827 +# define BOOST_NO_FENV_H +#endif + +#if _MSC_VER < 1400 +// although a conforming signature for swprint exists in VC7.1 +// it appears not to actually work: +# define BOOST_NO_SWPRINTF +// Our extern template tests also fail for this compiler: +# define BOOST_NO_CXX11_EXTERN_TEMPLATE +// Variadic macros do not exist for VC7.1 and lower +# define BOOST_NO_CXX11_VARIADIC_MACROS +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#endif + +#if _MSC_VER < 1500 // 140X == VC++ 8.0 +# define BOOST_NO_MEMBER_TEMPLATE_FRIENDS +#endif + +#if _MSC_VER < 1600 // 150X == VC++ 9.0 + // A bug in VC9: +# define BOOST_NO_ADL_BARRIER +#endif + + +#ifndef _NATIVE_WCHAR_T_DEFINED +# define BOOST_NO_INTRINSIC_WCHAR_T +#endif + +// +// check for exception handling support: +#if !defined(_CPPUNWIND) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +// +// __int64 support: +// +#define BOOST_HAS_MS_INT64 +#if defined(_MSC_EXTENSIONS) || (_MSC_VER >= 1400) +# define BOOST_HAS_LONG_LONG +#else +# define BOOST_NO_LONG_LONG +#endif +#if (_MSC_VER >= 1400) && !defined(_DEBUG) +# define BOOST_HAS_NRVO +#endif +#if _MSC_VER >= 1600 // 160X == VC++ 10.0 +# define BOOST_HAS_PRAGMA_DETECT_MISMATCH +#endif +// +// disable Win32 API's if compiler extensions are +// turned off: +// +#if !defined(_MSC_EXTENSIONS) && !defined(BOOST_DISABLE_WIN32) +# define BOOST_DISABLE_WIN32 +#endif +#if !defined(_CPPRTTI) && !defined(BOOST_NO_RTTI) +# define BOOST_NO_RTTI +#endif + +// +// TR1 features: +// +#if (_MSC_VER >= 1700) && defined(_HAS_CXX17) && (_HAS_CXX17 > 0) +// # define BOOST_HAS_TR1_HASH // don't know if this is true yet. +// # define BOOST_HAS_TR1_TYPE_TRAITS // don't know if this is true yet. +# define BOOST_HAS_TR1_UNORDERED_MAP +# define BOOST_HAS_TR1_UNORDERED_SET +#endif + +// +// C++0x features +// +// See above for BOOST_NO_LONG_LONG + +// C++ features supported by VC++ 10 (aka 2010) +// +#if _MSC_VER < 1600 +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +# define BOOST_NO_CXX11_LAMBDAS +# define BOOST_NO_CXX11_RVALUE_REFERENCES +# define BOOST_NO_CXX11_STATIC_ASSERT +# define BOOST_NO_CXX11_NULLPTR +# define BOOST_NO_CXX11_DECLTYPE +#endif // _MSC_VER < 1600 + +#if _MSC_VER >= 1600 +# define BOOST_HAS_STDINT_H +#endif + +// C++11 features supported by VC++ 11 (aka 2012) +// +#if _MSC_VER < 1700 +# define BOOST_NO_CXX11_FINAL +# define BOOST_NO_CXX11_RANGE_BASED_FOR +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif // _MSC_VER < 1700 + +// C++11 features supported by VC++ 12 (aka 2013). +// +#if _MSC_FULL_VER < 180020827 +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +# define BOOST_NO_CXX11_RAW_LITERALS +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +# define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +# define BOOST_NO_CXX11_DECLTYPE_N3276 +#endif + +#if _MSC_FULL_VER >= 180020827 +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_LOG1P +#endif + +// C++11 features supported by VC++ 14 (aka 2015) +// +#if (_MSC_FULL_VER < 190023026) +# define BOOST_NO_CXX11_NOEXCEPT +# define BOOST_NO_CXX11_DEFAULTED_MOVES +# define BOOST_NO_CXX11_REF_QUALIFIERS +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +# define BOOST_NO_CXX11_ALIGNAS +# define BOOST_NO_CXX11_INLINE_NAMESPACES +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +# define BOOST_NO_CXX11_UNICODE_LITERALS +# define BOOST_NO_CXX14_DECLTYPE_AUTO +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +# define BOOST_NO_CXX14_BINARY_LITERALS +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif +// C++11 features supported by VC++ 14 update 3 (aka 2015) +// +#if (_MSC_FULL_VER < 190024210) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +# define BOOST_NO_SFINAE_EXPR +# define BOOST_NO_CXX11_CONSTEXPR +#endif + +// C++14 features supported by VC++ 14.1 (Visual Studio 2017) +// +#if (_MSC_VER < 1910) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif + +// C++17 features supported by VC++ 14.1 (Visual Studio 2017) Update 3 +// +#if (_MSC_VER < 1911) || (_MSVC_LANG < 201703) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +# define BOOST_NO_CXX17_IF_CONSTEXPR +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + +// MSVC including version 14 has not yet completely +// implemented value-initialization, as is reported: +// "VC++ does not value-initialize members of derived classes without +// user-declared constructor", reported in 2009 by Sylvester Hesp: +// https://connect.microsoft.com/VisualStudio/feedback/details/484295 +// "Presence of copy constructor breaks member class initialization", +// reported in 2009 by Alex Vakulenko: +// https://connect.microsoft.com/VisualStudio/feedback/details/499606 +// "Value-initialization in new-expression", reported in 2005 by +// Pavel Kuznetsov (MetaCommunications Engineering): +// https://connect.microsoft.com/VisualStudio/feedback/details/100744 +// Reported again by John Maddock in 2015 for VC14: +// https://connect.microsoft.com/VisualStudio/feedback/details/1582233/c-subobjects-still-not-value-initialized-correctly +// See also: http://www.boost.org/libs/utility/value_init.htm#compiler_issues +// (Niels Dekker, LKEB, May 2010) +// Still present in VC15.5, Dec 2017. +#define BOOST_NO_COMPLETE_VALUE_INITIALIZATION +// +// C++ 11: +// +// This is supported with /permissive- for 15.5 onwards, unfortunately we appear to have no way to tell +// if this is in effect or not, in any case nothing in Boost is currently using this, so we'll just go +// on defining it for now: +// +# define BOOST_NO_TWO_PHASE_NAME_LOOKUP + +#if (_MSC_VER < 1912) || (_MSVC_LANG < 201402) +// Supported from msvc-15.5 onwards: +#define BOOST_NO_CXX11_SFINAE_EXPR +#endif +#if (_MSC_VER < 1915) || (_MSVC_LANG < 201402) +// C++ 14: +// Still gives internal compiler error for msvc-15.5: +# define BOOST_NO_CXX14_CONSTEXPR +#endif +// C++ 17: +#if (_MSC_VER < 1912) || (_MSVC_LANG < 201703) +#define BOOST_NO_CXX17_INLINE_VARIABLES +#define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif + +// +// Things that don't work in clr mode: +// +#ifdef _M_CEE +#ifndef BOOST_NO_CXX11_THREAD_LOCAL +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif +#ifndef BOOST_NO_SFINAE_EXPR +# define BOOST_NO_SFINAE_EXPR +#endif +#ifndef BOOST_NO_CXX11_REF_QUALIFIERS +# define BOOST_NO_CXX11_REF_QUALIFIERS +#endif +#endif +#ifdef _M_CEE_PURE +#ifndef BOOST_NO_CXX11_CONSTEXPR +# define BOOST_NO_CXX11_CONSTEXPR +#endif +#endif + +// +// prefix and suffix headers: +// +#ifndef BOOST_ABI_PREFIX +# define BOOST_ABI_PREFIX "boost/config/abi/msvc_prefix.hpp" +#endif +#ifndef BOOST_ABI_SUFFIX +# define BOOST_ABI_SUFFIX "boost/config/abi/msvc_suffix.hpp" +#endif + +#ifndef BOOST_COMPILER +// TODO: +// these things are mostly bogus. 1200 means version 12.0 of the compiler. The +// artificial versions assigned to them only refer to the versions of some IDE +// these compilers have been shipped with, and even that is not all of it. Some +// were shipped with freely downloadable SDKs, others as crosscompilers in eVC. +// IOW, you can't use these 'versions' in any sensible way. Sorry. +# if defined(UNDER_CE) +# if _MSC_VER < 1400 + // Note: I'm not aware of any CE compiler with version 13xx +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown EVC++ compiler version - please run the configure tests and report the results" +# else +# pragma message("boost: Unknown EVC++ compiler version - please run the configure tests and report the results") +# endif +# elif _MSC_VER < 1500 +# define BOOST_COMPILER_VERSION evc8 +# elif _MSC_VER < 1600 +# define BOOST_COMPILER_VERSION evc9 +# elif _MSC_VER < 1700 +# define BOOST_COMPILER_VERSION evc10 +# elif _MSC_VER < 1800 +# define BOOST_COMPILER_VERSION evc11 +# elif _MSC_VER < 1900 +# define BOOST_COMPILER_VERSION evc12 +# elif _MSC_VER < 2000 +# define BOOST_COMPILER_VERSION evc14 +# else +# if defined(BOOST_ASSERT_CONFIG) +# error "boost: Unknown EVC++ compiler version - please run the configure tests and report the results" +# else +# pragma message("boost: Unknown EVC++ compiler version - please run the configure tests and report the results") +# endif +# endif +# else +# if _MSC_VER < 1200 + // Note: Versions up to 7.0 aren't supported. +# define BOOST_COMPILER_VERSION 5.0 +# elif _MSC_VER < 1300 +# define BOOST_COMPILER_VERSION 6.0 +# elif _MSC_VER < 1310 +# define BOOST_COMPILER_VERSION 7.0 +# elif _MSC_VER < 1400 +# define BOOST_COMPILER_VERSION 7.1 +# elif _MSC_VER < 1500 +# define BOOST_COMPILER_VERSION 8.0 +# elif _MSC_VER < 1600 +# define BOOST_COMPILER_VERSION 9.0 +# elif _MSC_VER < 1700 +# define BOOST_COMPILER_VERSION 10.0 +# elif _MSC_VER < 1800 +# define BOOST_COMPILER_VERSION 11.0 +# elif _MSC_VER < 1900 +# define BOOST_COMPILER_VERSION 12.0 +# elif _MSC_VER < 1910 +# define BOOST_COMPILER_VERSION 14.0 +# elif _MSC_VER < 1920 +# define BOOST_COMPILER_VERSION 14.1 +# else +# define BOOST_COMPILER_VERSION _MSC_VER +# endif +# endif + +# define BOOST_COMPILER "Microsoft Visual C++ version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION) +#endif + +#include + +// +// last known and checked version is 19.12.25830.2 (VC++ 2017.3): +#if (_MSC_VER > 1912) +# if defined(BOOST_ASSERT_CONFIG) +# error "Boost.Config is older than your current compiler version." +# elif !defined(BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE) + // + // Disabled as of March 2018 - the pace of VS releases is hard to keep up with + // and in any case, we have relatively few defect macros defined now. + // BOOST_PRAGMA_MESSAGE("Info: Boost.Config is older than your compiler version - probably nothing bad will happen - but you may wish to look for an updated Boost version. Define BOOST_CONFIG_SUPPRESS_OUTDATED_MESSAGE to suppress this message.") +# endif +#endif diff --git a/third-party/boost/boost/config/compiler/xlcpp.hpp b/third-party/boost/boost/config/compiler/xlcpp.hpp new file mode 100644 index 000000000..ee7aa1253 --- /dev/null +++ b/third-party/boost/boost/config/compiler/xlcpp.hpp @@ -0,0 +1,285 @@ +// (C) Copyright Douglas Gregor 2010 +// +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// compiler setup for IBM XL C/C++ for Linux (Little Endian) based on clang. + +#define BOOST_HAS_PRAGMA_ONCE + +// Detecting `-fms-extension` compiler flag assuming that _MSC_VER defined when that flag is used. +#if defined (_MSC_VER) && (__clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 4)) +# define BOOST_HAS_PRAGMA_DETECT_MISMATCH +#endif + +// When compiling with clang before __has_extension was defined, +// even if one writes 'defined(__has_extension) && __has_extension(xxx)', +// clang reports a compiler error. So the only workaround found is: + +#ifndef __has_extension +#define __has_extension __has_feature +#endif + +#ifndef __has_cpp_attribute +#define __has_cpp_attribute(x) 0 +#endif + +#if !__has_feature(cxx_exceptions) && !defined(BOOST_NO_EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +#if !__has_feature(cxx_rtti) && !defined(BOOST_NO_RTTI) +# define BOOST_NO_RTTI +#endif + +#if !__has_feature(cxx_rtti) && !defined(BOOST_NO_TYPEID) +# define BOOST_NO_TYPEID +#endif + +#if defined(__int64) && !defined(__GNUC__) +# define BOOST_HAS_MS_INT64 +#endif + +#define BOOST_HAS_NRVO + +// Branch prediction hints +#if defined(__has_builtin) +#if __has_builtin(__builtin_expect) +#define BOOST_LIKELY(x) __builtin_expect(x, 1) +#define BOOST_UNLIKELY(x) __builtin_expect(x, 0) +#endif +#endif + +// Clang supports "long long" in all compilation modes. +#define BOOST_HAS_LONG_LONG + +// +// Dynamic shared object (DSO) and dynamic-link library (DLL) support +// +#if !defined(_WIN32) && !defined(__WIN32__) && !defined(WIN32) +# define BOOST_SYMBOL_EXPORT __attribute__((__visibility__("default"))) +# define BOOST_SYMBOL_IMPORT +# define BOOST_SYMBOL_VISIBLE __attribute__((__visibility__("default"))) +#endif + +// +// The BOOST_FALLTHROUGH macro can be used to annotate implicit fall-through +// between switch labels. +// +#if __cplusplus >= 201103L && defined(__has_warning) +# if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough") +# define BOOST_FALLTHROUGH [[clang::fallthrough]] +# endif +#endif + +#if !__has_feature(cxx_auto_type) +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +#endif + +// +// Currently clang on Windows using VC++ RTL does not support C++11's char16_t or char32_t +// +#if defined(_MSC_VER) || !(defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L) +# define BOOST_NO_CXX11_CHAR16_T +# define BOOST_NO_CXX11_CHAR32_T +#endif + +#if !__has_feature(cxx_constexpr) +# define BOOST_NO_CXX11_CONSTEXPR +#endif + +#if !__has_feature(cxx_decltype) +# define BOOST_NO_CXX11_DECLTYPE +#endif + +#if !__has_feature(cxx_decltype_incomplete_return_types) +# define BOOST_NO_CXX11_DECLTYPE_N3276 +#endif + +#if !__has_feature(cxx_defaulted_functions) +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +#endif + +#if !__has_feature(cxx_deleted_functions) +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +#endif + +#if !__has_feature(cxx_explicit_conversions) +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#endif + +#if !__has_feature(cxx_default_function_template_args) +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif + +#if !__has_feature(cxx_generalized_initializers) +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#endif + +#if !__has_feature(cxx_lambdas) +# define BOOST_NO_CXX11_LAMBDAS +#endif + +#if !__has_feature(cxx_local_type_template_args) +# define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS +#endif + +#if !__has_feature(cxx_noexcept) +# define BOOST_NO_CXX11_NOEXCEPT +#endif + +#if !__has_feature(cxx_nullptr) +# define BOOST_NO_CXX11_NULLPTR +#endif + +#if !__has_feature(cxx_range_for) +# define BOOST_NO_CXX11_RANGE_BASED_FOR +#endif + +#if !__has_feature(cxx_raw_string_literals) +# define BOOST_NO_CXX11_RAW_LITERALS +#endif + +#if !__has_feature(cxx_reference_qualified_functions) +# define BOOST_NO_CXX11_REF_QUALIFIERS +#endif + +#if !__has_feature(cxx_generalized_initializers) +# define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#endif + +#if !__has_feature(cxx_rvalue_references) +# define BOOST_NO_CXX11_RVALUE_REFERENCES +#endif + +#if !__has_feature(cxx_strong_enums) +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +#if !__has_feature(cxx_static_assert) +# define BOOST_NO_CXX11_STATIC_ASSERT +#endif + +#if !__has_feature(cxx_alias_templates) +# define BOOST_NO_CXX11_TEMPLATE_ALIASES +#endif + +#if !__has_feature(cxx_unicode_literals) +# define BOOST_NO_CXX11_UNICODE_LITERALS +#endif + +#if !__has_feature(cxx_variadic_templates) +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +#endif + +#if !__has_feature(cxx_user_literals) +# define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#endif + +#if !__has_feature(cxx_alignas) +# define BOOST_NO_CXX11_ALIGNAS +#endif + +#if !__has_feature(cxx_trailing_return) +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#endif + +#if !__has_feature(cxx_inline_namespaces) +# define BOOST_NO_CXX11_INLINE_NAMESPACES +#endif + +#if !__has_feature(cxx_override_control) +# define BOOST_NO_CXX11_FINAL +#endif + +#if !(__has_feature(__cxx_binary_literals__) || __has_extension(__cxx_binary_literals__)) +# define BOOST_NO_CXX14_BINARY_LITERALS +#endif + +#if !__has_feature(__cxx_decltype_auto__) +# define BOOST_NO_CXX14_DECLTYPE_AUTO +#endif + +#if !__has_feature(__cxx_aggregate_nsdmi__) +# define BOOST_NO_CXX14_AGGREGATE_NSDMI +#endif + +#if !__has_feature(__cxx_init_captures__) +# define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#endif + +#if !__has_feature(__cxx_generic_lambdas__) +# define BOOST_NO_CXX14_GENERIC_LAMBDAS +#endif + +// clang < 3.5 has a defect with dependent type, like following. +// +// template +// constexpr typename enable_if >::type foo(T &) +// { } // error: no return statement in constexpr function +// +// This issue also affects C++11 mode, but C++11 constexpr requires return stmt. +// Therefore we don't care such case. +// +// Note that we can't check Clang version directly as the numbering system changes depending who's +// creating the Clang release (see https://github.com/boostorg/config/pull/39#issuecomment-59927873) +// so instead verify that we have a feature that was introduced at the same time as working C++14 +// constexpr (generic lambda's in this case): +// +#if !__has_feature(__cxx_generic_lambdas__) || !__has_feature(__cxx_relaxed_constexpr__) +# define BOOST_NO_CXX14_CONSTEXPR +#endif + +#if !__has_feature(__cxx_return_type_deduction__) +# define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#endif + +#if !__has_feature(__cxx_variable_templates__) +# define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#endif + +#if !defined(__cpp_structured_bindings) || (__cpp_structured_bindings < 201606) +# define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#endif + +#if !defined(__cpp_if_constexpr) || (__cpp_if_constexpr < 201606) +# define BOOST_NO_CXX17_IF_CONSTEXPR +#endif + +// Clang 3.9+ in c++1z +#if !__has_cpp_attribute(fallthrough) || __cplusplus < 201406L +# define BOOST_NO_CXX17_INLINE_VARIABLES +# define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#endif + +#if !__has_feature(cxx_thread_local) +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +#if __cplusplus < 201400 +// All versions with __cplusplus above this value seem to support this: +# define BOOST_NO_CXX14_DIGIT_SEPARATORS +#endif + + +// Unused attribute: +#if defined(__GNUC__) && (__GNUC__ >= 4) +# define BOOST_ATTRIBUTE_UNUSED __attribute__((unused)) +#endif + +// Type aliasing hint. +#if __has_attribute(__may_alias__) +# define BOOST_MAY_ALIAS __attribute__((__may_alias__)) +#endif + +#ifndef BOOST_COMPILER +# define BOOST_COMPILER "Clang version " __clang_version__ +#endif + +// Macro used to identify the Clang compiler. +#define BOOST_CLANG 1 + diff --git a/third-party/boost/boost/config/compiler/xlcpp_zos.hpp b/third-party/boost/boost/config/compiler/xlcpp_zos.hpp new file mode 100644 index 000000000..eb1bf2e99 --- /dev/null +++ b/third-party/boost/boost/config/compiler/xlcpp_zos.hpp @@ -0,0 +1,170 @@ +// Copyright (c) 2017 Dynatrace +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org for most recent version. + +// Compiler setup for IBM z/OS XL C/C++ compiler. + +// Oldest compiler version currently supported is 2.1 (V2R1) +#if !defined(__IBMCPP__) || !defined(__COMPILER_VER__) || __COMPILER_VER__ < 0x42010000 +# error "Compiler not supported or configured - please reconfigure" +#endif + +#if __COMPILER_VER__ > 0x42010000 +# if defined(BOOST_ASSERT_CONFIG) +# error "Unknown compiler version - please run the configure tests and report the results" +# endif +#endif + +#define BOOST_COMPILER "IBM z/OS XL C/C++ version " BOOST_STRINGIZE(__COMPILER_VER__) +#define BOOST_XLCPP_ZOS __COMPILER_VER__ + +// ------------------------------------- + +#include // For __UU, __C99, __TR1, ... + +#if !defined(__IBMCPP_DEFAULTED_AND_DELETED_FUNCTIONS) +# define BOOST_NO_CXX11_DELETED_FUNCTIONS +# define BOOST_NO_CXX11_DEFAULTED_FUNCTIONS +# define BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS +#endif + +// ------------------------------------- + +#if defined(__UU) || defined(__C99) || defined(__TR1) +# define BOOST_HAS_LOG1P +# define BOOST_HAS_EXPM1 +#endif + +#if defined(__C99) || defined(__TR1) +# define BOOST_HAS_STDINT_H +#else +# define BOOST_NO_FENV_H +#endif + +// ------------------------------------- + +#define BOOST_HAS_NRVO + +#if !defined(__RTTI_ALL__) +# define BOOST_NO_RTTI +#endif + +#if !defined(_CPPUNWIND) && !defined(__EXCEPTIONS) +# define BOOST_NO_EXCEPTIONS +#endif + +#if defined(_LONG_LONG) || defined(__IBMCPP_C99_LONG_LONG) || defined(__LL) +# define BOOST_HAS_LONG_LONG +#else +# define BOOST_NO_LONG_LONG +#endif + +#if defined(_LONG_LONG) || defined(__IBMCPP_C99_LONG_LONG) || defined(__LL) || defined(_LP64) +# define BOOST_HAS_MS_INT64 +#endif + +#define BOOST_NO_SFINAE_EXPR +#define BOOST_NO_CXX11_SFINAE_EXPR + +#if defined(__IBMCPP_VARIADIC_TEMPLATES) +# define BOOST_HAS_VARIADIC_TMPL +#else +# define BOOST_NO_CXX11_VARIADIC_TEMPLATES +# define BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif + +#if defined(__IBMCPP_STATIC_ASSERT) +# define BOOST_HAS_STATIC_ASSERT +#else +# define BOOST_NO_CXX11_STATIC_ASSERT +#endif + +#if defined(__IBMCPP_RVALUE_REFERENCES) +# define BOOST_HAS_RVALUE_REFS +#else +# define BOOST_NO_CXX11_RVALUE_REFERENCES +#endif + +#if !defined(__IBMCPP_SCOPED_ENUM) +# define BOOST_NO_CXX11_SCOPED_ENUMS +#endif + +#define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#define BOOST_NO_CXX11_TEMPLATE_ALIASES +#define BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS + +#if !defined(__IBMCPP_EXPLICIT_CONVERSION_OPERATORS) +# define BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS +#endif + +#if !defined(__IBMCPP_DECLTYPE) +# define BOOST_NO_CXX11_DECLTYPE +#else +# define BOOST_HAS_DECLTYPE +#endif +#define BOOST_NO_CXX11_DECLTYPE_N3276 + +#if !defined(__IBMCPP_INLINE_NAMESPACE) +# define BOOST_NO_CXX11_INLINE_NAMESPACES +#endif + +#if !defined(__IBMCPP_AUTO_TYPEDEDUCTION) +# define BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS +# define BOOST_NO_CXX11_AUTO_DECLARATIONS +# define BOOST_NO_CXX11_TRAILING_RESULT_TYPES +#endif + +#if !defined(__IBM_CHAR32_T__) +# define BOOST_NO_CXX11_CHAR32_T +#endif +#if !defined(__IBM_CHAR16_T__) +# define BOOST_NO_CXX11_CHAR16_T +#endif + +#if !defined(__IBMCPP_CONSTEXPR) +# define BOOST_NO_CXX11_CONSTEXPR +#endif + +#define BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX +#define BOOST_NO_CXX11_UNICODE_LITERALS +#define BOOST_NO_CXX11_RAW_LITERALS +#define BOOST_NO_CXX11_RANGE_BASED_FOR +#define BOOST_NO_CXX11_NULLPTR +#define BOOST_NO_CXX11_NOEXCEPT +#define BOOST_NO_CXX11_LAMBDAS +#define BOOST_NO_CXX11_USER_DEFINED_LITERALS +#define BOOST_NO_CXX11_THREAD_LOCAL +#define BOOST_NO_CXX11_REF_QUALIFIERS +#define BOOST_NO_CXX11_FINAL +#define BOOST_NO_CXX11_ALIGNAS +#define BOOST_NO_CXX14_VARIABLE_TEMPLATES +#define BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION +#define BOOST_NO_CXX14_AGGREGATE_NSDMI +#define BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES +#define BOOST_NO_CXX14_GENERIC_LAMBDAS +#define BOOST_NO_CXX14_DIGIT_SEPARATORS +#define BOOST_NO_CXX14_DECLTYPE_AUTO +#define BOOST_NO_CXX14_CONSTEXPR +#define BOOST_NO_CXX14_BINARY_LITERALS +#define BOOST_NO_CXX17_STRUCTURED_BINDINGS +#define BOOST_NO_CXX17_INLINE_VARIABLES +#define BOOST_NO_CXX17_FOLD_EXPRESSIONS +#define BOOST_NO_CXX17_IF_CONSTEXPR + +// ------------------------------------- + +#if defined(__IBM_ATTRIBUTES) +# define BOOST_FORCEINLINE inline __attribute__ ((__always_inline__)) +# define BOOST_NOINLINE __attribute__ ((__noinline__)) +# define BOOST_MAY_ALIAS __attribute__((__may_alias__)) +// No BOOST_ALIGNMENT - explicit alignment support is broken (V2R1). +#endif + +extern "builtin" long __builtin_expect(long, long); + +#define BOOST_LIKELY(x) __builtin_expect((x) && true, 1) +#define BOOST_UNLIKELY(x) __builtin_expect((x) && true, 0) diff --git a/third-party/boost/boost/config/detail/posix_features.hpp b/third-party/boost/boost/config/detail/posix_features.hpp new file mode 100644 index 000000000..d12954797 --- /dev/null +++ b/third-party/boost/boost/config/detail/posix_features.hpp @@ -0,0 +1,95 @@ +// (C) Copyright John Maddock 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +// See http://www.boost.org for most recent version. + +// All POSIX feature tests go in this file, +// Note that we test _POSIX_C_SOURCE and _XOPEN_SOURCE as well +// _POSIX_VERSION and _XOPEN_VERSION: on some systems POSIX API's +// may be present but none-functional unless _POSIX_C_SOURCE and +// _XOPEN_SOURCE have been defined to the right value (it's up +// to the user to do this *before* including any header, although +// in most cases the compiler will do this for you). + +# if defined(BOOST_HAS_UNISTD_H) +# include + + // XOpen has , but is this the correct version check? +# if defined(_XOPEN_VERSION) && (_XOPEN_VERSION >= 3) +# define BOOST_HAS_NL_TYPES_H +# endif + + // POSIX version 6 requires +# if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200100) +# define BOOST_HAS_STDINT_H +# endif + + // POSIX version 2 requires +# if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 199009L) +# define BOOST_HAS_DIRENT_H +# endif + + // POSIX version 3 requires to have sigaction: +# if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 199506L) +# define BOOST_HAS_SIGACTION +# endif + // POSIX defines _POSIX_THREADS > 0 for pthread support, + // however some platforms define _POSIX_THREADS without + // a value, hence the (_POSIX_THREADS+0 >= 0) check. + // Strictly speaking this may catch platforms with a + // non-functioning stub , but such occurrences should + // occur very rarely if at all. +# if defined(_POSIX_THREADS) && (_POSIX_THREADS+0 >= 0) && !defined(BOOST_HAS_WINTHREADS) && !defined(BOOST_HAS_MPTASKS) +# define BOOST_HAS_PTHREADS +# endif + + // BOOST_HAS_NANOSLEEP: + // This is predicated on _POSIX_TIMERS or _XOPEN_REALTIME: +# if (defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0 >= 0)) \ + || (defined(_XOPEN_REALTIME) && (_XOPEN_REALTIME+0 >= 0)) +# define BOOST_HAS_NANOSLEEP +# endif + + // BOOST_HAS_CLOCK_GETTIME: + // This is predicated on _POSIX_TIMERS (also on _XOPEN_REALTIME + // but at least one platform - linux - defines that flag without + // defining clock_gettime): +# if (defined(_POSIX_TIMERS) && (_POSIX_TIMERS+0 >= 0)) +# define BOOST_HAS_CLOCK_GETTIME +# endif + + // BOOST_HAS_SCHED_YIELD: + // This is predicated on _POSIX_PRIORITY_SCHEDULING or + // on _POSIX_THREAD_PRIORITY_SCHEDULING or on _XOPEN_REALTIME. +# if defined(_POSIX_PRIORITY_SCHEDULING) && (_POSIX_PRIORITY_SCHEDULING+0 > 0)\ + || (defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING+0 > 0))\ + || (defined(_XOPEN_REALTIME) && (_XOPEN_REALTIME+0 >= 0)) +# define BOOST_HAS_SCHED_YIELD +# endif + + // BOOST_HAS_GETTIMEOFDAY: + // BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE: + // These are predicated on _XOPEN_VERSION, and appears to be first released + // in issue 4, version 2 (_XOPEN_VERSION > 500). + // Likewise for the functions log1p and expm1. +# if defined(_XOPEN_VERSION) && (_XOPEN_VERSION+0 >= 500) +# define BOOST_HAS_GETTIMEOFDAY +# if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE+0 >= 500) +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# endif +# ifndef BOOST_HAS_LOG1P +# define BOOST_HAS_LOG1P +# endif +# ifndef BOOST_HAS_EXPM1 +# define BOOST_HAS_EXPM1 +# endif +# endif + +# endif + + + + diff --git a/third-party/boost/boost/config/detail/select_compiler_config.hpp b/third-party/boost/boost/config/detail/select_compiler_config.hpp new file mode 100644 index 000000000..8970dffb4 --- /dev/null +++ b/third-party/boost/boost/config/detail/select_compiler_config.hpp @@ -0,0 +1,157 @@ +// Boost compiler configuration selection header file + +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Martin Wille 2003. +// (C) Copyright Guillaume Melquiond 2003. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for most recent version. + +// locate which compiler we are using and define +// BOOST_COMPILER_CONFIG as needed: + +#if defined __CUDACC__ +// NVIDIA CUDA C++ compiler for GPU +# include "boost/config/compiler/nvcc.hpp" + +#endif + +#if defined(__GCCXML__) +// GCC-XML emulates other compilers, it has to appear first here! +# define BOOST_COMPILER_CONFIG "boost/config/compiler/gcc_xml.hpp" + +#elif defined(_CRAYC) +// EDG based Cray compiler: +# define BOOST_COMPILER_CONFIG "boost/config/compiler/cray.hpp" + +#elif defined __COMO__ +// Comeau C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/comeau.hpp" + +#elif defined(__PATHSCALE__) && (__PATHCC__ >= 4) +// PathScale EKOPath compiler (has to come before clang and gcc) +# define BOOST_COMPILER_CONFIG "boost/config/compiler/pathscale.hpp" + +#elif defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC) +// Intel +# define BOOST_COMPILER_CONFIG "boost/config/compiler/intel.hpp" + +#elif defined __clang__ && !defined(__ibmxl__) +// Clang C++ emulates GCC, so it has to appear early. +# define BOOST_COMPILER_CONFIG "boost/config/compiler/clang.hpp" + +#elif defined __DMC__ +// Digital Mars C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/digitalmars.hpp" + +#elif defined __DCC__ +// Wind River Diab C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/diab.hpp" + +#elif defined(__PGI) +// Portland Group Inc. +# define BOOST_COMPILER_CONFIG "boost/config/compiler/pgi.hpp" + +# elif defined(__GNUC__) && !defined(__ibmxl__) +// GNU C++: +# define BOOST_COMPILER_CONFIG "boost/config/compiler/gcc.hpp" + +#elif defined __KCC +// Kai C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/kai.hpp" + +#elif defined __sgi +// SGI MIPSpro C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/sgi_mipspro.hpp" + +#elif defined __DECCXX +// Compaq Tru64 Unix cxx +# define BOOST_COMPILER_CONFIG "boost/config/compiler/compaq_cxx.hpp" + +#elif defined __ghs +// Greenhills C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/greenhills.hpp" + +#elif defined __CODEGEARC__ +// CodeGear - must be checked for before Borland +# define BOOST_COMPILER_CONFIG "boost/config/compiler/codegear.hpp" + +#elif defined __BORLANDC__ +// Borland +# define BOOST_COMPILER_CONFIG "boost/config/compiler/borland.hpp" + +#elif defined __MWERKS__ +// Metrowerks CodeWarrior +# define BOOST_COMPILER_CONFIG "boost/config/compiler/metrowerks.hpp" + +#elif defined __SUNPRO_CC +// Sun Workshop Compiler C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/sunpro_cc.hpp" + +#elif defined __HP_aCC +// HP aCC +# define BOOST_COMPILER_CONFIG "boost/config/compiler/hp_acc.hpp" + +#elif defined(__MRC__) || defined(__SC__) +// MPW MrCpp or SCpp +# define BOOST_COMPILER_CONFIG "boost/config/compiler/mpw.hpp" + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) && defined(__MVS__) +// IBM z/OS XL C/C++ +# define BOOST_COMPILER_CONFIG "boost/config/compiler/xlcpp_zos.hpp" + +#elif defined(__ibmxl__) +// IBM XL C/C++ for Linux (Little Endian) +# define BOOST_COMPILER_CONFIG "boost/config/compiler/xlcpp.hpp" + +#elif defined(__IBMCPP__) +// IBM Visual Age or IBM XL C/C++ for Linux (Big Endian) +# define BOOST_COMPILER_CONFIG "boost/config/compiler/vacpp.hpp" + +#elif defined _MSC_VER +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for +// example) also #define _MSC_VER +# define BOOST_COMPILER_CONFIG "boost/config/compiler/visualc.hpp" + +#elif defined (BOOST_ASSERT_CONFIG) +// this must come last - generate an error if we don't +// recognise the compiler: +# error "Unknown compiler - please configure (http://www.boost.org/libs/config/config.htm#configuring) and report the results to the main boost mailing list (http://www.boost.org/more/mailing_lists.htm#main)" + +#endif + +#if 0 +// +// This section allows dependency scanners to find all the headers we *might* include: +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + diff --git a/third-party/boost/boost/config/detail/select_platform_config.hpp b/third-party/boost/boost/config/detail/select_platform_config.hpp new file mode 100644 index 000000000..b36eca57a --- /dev/null +++ b/third-party/boost/boost/config/detail/select_platform_config.hpp @@ -0,0 +1,142 @@ +// Boost compiler configuration selection header file + +// (C) Copyright John Maddock 2001 - 2002. +// (C) Copyright Jens Maurer 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// locate which platform we are on and define BOOST_PLATFORM_CONFIG as needed. +// Note that we define the headers to include using "header_name" not +// in order to prevent macro expansion within the header +// name (for example "linux" is a macro on linux systems). + +#if (defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__)) && !defined(_CRAYC) +// linux, also other platforms (Hurd etc) that use GLIBC, should these really have their own config headers though? +# define BOOST_PLATFORM_CONFIG "boost/config/platform/linux.hpp" + +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +// BSD: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/bsd.hpp" + +#elif defined(sun) || defined(__sun) +// solaris: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/solaris.hpp" + +#elif defined(__sgi) +// SGI Irix: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/irix.hpp" + +#elif defined(__hpux) +// hp unix: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/hpux.hpp" + +#elif defined(__CYGWIN__) +// cygwin is not win32: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/cygwin.hpp" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +// win32: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/win32.hpp" + +#elif defined(__HAIKU__) +// Haiku +# define BOOST_PLATFORM_CONFIG "boost/config/platform/haiku.hpp" + +#elif defined(__BEOS__) +// BeOS +# define BOOST_PLATFORM_CONFIG "boost/config/platform/beos.hpp" + +#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +// MacOS +# define BOOST_PLATFORM_CONFIG "boost/config/platform/macos.hpp" + +#elif defined(__TOS_MVS__) +// IBM z/OS +# define BOOST_PLATFORM_CONFIG "boost/config/platform/zos.hpp" + +#elif defined(__IBMCPP__) || defined(_AIX) +// IBM AIX +# define BOOST_PLATFORM_CONFIG "boost/config/platform/aix.hpp" + +#elif defined(__amigaos__) +// AmigaOS +# define BOOST_PLATFORM_CONFIG "boost/config/platform/amigaos.hpp" + +#elif defined(__QNXNTO__) +// QNX: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/qnxnto.hpp" + +#elif defined(__VXWORKS__) +// vxWorks: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/vxworks.hpp" + +#elif defined(__SYMBIAN32__) +// Symbian: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/symbian.hpp" + +#elif defined(_CRAYC) +// Cray: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/cray.hpp" + +#elif defined(__VMS) +// VMS: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/vms.hpp" + +#elif defined(__CloudABI__) +// Nuxi CloudABI: +# define BOOST_PLATFORM_CONFIG "boost/config/platform/cloudabi.hpp" +#else + +# if defined(unix) \ + || defined(__unix) \ + || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) + + // generic unix platform: + +# ifndef BOOST_HAS_UNISTD_H +# define BOOST_HAS_UNISTD_H +# endif + +# include + +# endif + +# if defined (BOOST_ASSERT_CONFIG) + // this must come last - generate an error if we don't + // recognise the platform: +# error "Unknown platform - please configure and report the results to boost.org" +# endif + +#endif + +#if 0 +// +// This section allows dependency scanners to find all the files we *might* include: +// +# include "boost/config/platform/linux.hpp" +# include "boost/config/platform/bsd.hpp" +# include "boost/config/platform/solaris.hpp" +# include "boost/config/platform/irix.hpp" +# include "boost/config/platform/hpux.hpp" +# include "boost/config/platform/cygwin.hpp" +# include "boost/config/platform/win32.hpp" +# include "boost/config/platform/beos.hpp" +# include "boost/config/platform/macos.hpp" +# include "boost/config/platform/zos.hpp" +# include "boost/config/platform/aix.hpp" +# include "boost/config/platform/amigaos.hpp" +# include "boost/config/platform/qnxnto.hpp" +# include "boost/config/platform/vxworks.hpp" +# include "boost/config/platform/symbian.hpp" +# include "boost/config/platform/cray.hpp" +# include "boost/config/platform/vms.hpp" +# include + + + +#endif + diff --git a/third-party/boost/boost/config/detail/select_stdlib_config.hpp b/third-party/boost/boost/config/detail/select_stdlib_config.hpp new file mode 100644 index 000000000..8db778c86 --- /dev/null +++ b/third-party/boost/boost/config/detail/select_stdlib_config.hpp @@ -0,0 +1,110 @@ +// Boost compiler configuration selection header file + +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +// See http://www.boost.org for most recent version. + +// locate which std lib we are using and define BOOST_STDLIB_CONFIG as needed: + +// First include to determine if some version of STLport is in use as the std lib +// (do not rely on this header being included since users can short-circuit this header +// if they know whose std lib they are using.) +#ifdef __cplusplus +# include +#else +# include +#endif + +#if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION) +// STLPort library; this _must_ come first, otherwise since +// STLport typically sits on top of some other library, we +// can end up detecting that first rather than STLport: +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/stlport.hpp" + +#else + +// If our std lib was not some version of STLport, and has not otherwise +// been detected, then include as it is about +// the smallest of the std lib headers that includes real C++ stuff. +// Some std libs do not include their C++-related macros in +// so this additional include makes sure we get those definitions. +// Note: do not rely on this header being included since users can short-circuit this +// #include if they know whose std lib they are using. +#if !defined(__LIBCOMO__) && !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER)\ + && !defined(_LIBCPP_VERSION) && !defined(__GLIBCPP__) && !defined(__GLIBCXX__)\ + && !defined(__STL_CONFIG_H) && !defined(__MSL_CPP__) && !defined(__IBMCPP__)\ + && !defined(MSIPL_COMPILE_H) && !defined(_YVALS) && !defined(_CPPLIB_VER) +#include +#endif + +#if defined(__LIBCOMO__) +// Comeau STL: +#define BOOST_STDLIB_CONFIG "boost/config/stdlib/libcomo.hpp" + +#elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER) +// Rogue Wave library: +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/roguewave.hpp" + +#elif defined(_LIBCPP_VERSION) +// libc++ +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/libcpp.hpp" + +#elif defined(__GLIBCPP__) || defined(__GLIBCXX__) +// GNU libstdc++ 3 +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/libstdcpp3.hpp" + +#elif defined(__STL_CONFIG_H) +// generic SGI STL +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/sgi.hpp" + +#elif defined(__MSL_CPP__) +// MSL standard lib: +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/msl.hpp" + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) && defined(__MVS__) +// IBM z/OS XL C/C++ +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/xlcpp_zos.hpp" + +#elif defined(__IBMCPP__) +// take the default VACPP std lib +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/vacpp.hpp" + +#elif defined(MSIPL_COMPILE_H) +// Modena C++ standard library +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/modena.hpp" + +#elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER) +// Dinkumware Library (this has to appear after any possible replacement libraries): +# define BOOST_STDLIB_CONFIG "boost/config/stdlib/dinkumware.hpp" + +#elif defined (BOOST_ASSERT_CONFIG) +// this must come last - generate an error if we don't +// recognise the library: +# error "Unknown standard library - please configure and report the results to boost.org" + +#endif + +#endif + +#if 0 +// +// This section allows dependency scanners to find all the files we *might* include: +// +# include "boost/config/stdlib/stlport.hpp" +# include "boost/config/stdlib/libcomo.hpp" +# include "boost/config/stdlib/roguewave.hpp" +# include "boost/config/stdlib/libcpp.hpp" +# include "boost/config/stdlib/libstdcpp3.hpp" +# include "boost/config/stdlib/sgi.hpp" +# include "boost/config/stdlib/msl.hpp" +# include "boost/config/stdlib/xlcpp_zos.hpp" +# include "boost/config/stdlib/vacpp.hpp" +# include "boost/config/stdlib/modena.hpp" +# include "boost/config/stdlib/dinkumware.hpp" +#endif + diff --git a/third-party/boost/boost/config/detail/suffix.hpp b/third-party/boost/boost/config/detail/suffix.hpp new file mode 100644 index 000000000..cee9647b6 --- /dev/null +++ b/third-party/boost/boost/config/detail/suffix.hpp @@ -0,0 +1,1049 @@ +// Boost config.hpp configuration header file ------------------------------// +// boostinspect:ndprecated_macros -- tell the inspect tool to ignore this file + +// Copyright (c) 2001-2003 John Maddock +// Copyright (c) 2001 Darin Adler +// Copyright (c) 2001 Peter Dimov +// Copyright (c) 2002 Bill Kempf +// Copyright (c) 2002 Jens Maurer +// Copyright (c) 2002-2003 David Abrahams +// Copyright (c) 2003 Gennaro Prota +// Copyright (c) 2003 Eric Friedman +// Copyright (c) 2010 Eric Jourdanneau, Joel Falcou +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org/ for most recent version. + +// Boost config.hpp policy and rationale documentation has been moved to +// http://www.boost.org/libs/config/ +// +// This file is intended to be stable, and relatively unchanging. +// It should contain boilerplate code only - no compiler specific +// code unless it is unavoidable - no changes unless unavoidable. + +#ifndef BOOST_CONFIG_SUFFIX_HPP +#define BOOST_CONFIG_SUFFIX_HPP + +#if defined(__GNUC__) && (__GNUC__ >= 4) +// +// Some GCC-4.x versions issue warnings even when __extension__ is used, +// so use this as a workaround: +// +#pragma GCC system_header +#endif + +// +// ensure that visibility macros are always defined, thus symplifying use +// +#ifndef BOOST_SYMBOL_EXPORT +# define BOOST_SYMBOL_EXPORT +#endif +#ifndef BOOST_SYMBOL_IMPORT +# define BOOST_SYMBOL_IMPORT +#endif +#ifndef BOOST_SYMBOL_VISIBLE +# define BOOST_SYMBOL_VISIBLE +#endif + +// +// look for long long by looking for the appropriate macros in . +// Note that we use limits.h rather than climits for maximal portability, +// remember that since these just declare a bunch of macros, there should be +// no namespace issues from this. +// +#if !defined(BOOST_HAS_LONG_LONG) && !defined(BOOST_NO_LONG_LONG) \ + && !defined(BOOST_MSVC) && !defined(__BORLANDC__) +# include +# if (defined(ULLONG_MAX) || defined(ULONG_LONG_MAX) || defined(ULONGLONG_MAX)) +# define BOOST_HAS_LONG_LONG +# else +# define BOOST_NO_LONG_LONG +# endif +#endif + +// GCC 3.x will clean up all of those nasty macro definitions that +// BOOST_NO_CTYPE_FUNCTIONS is intended to help work around, so undefine +// it under GCC 3.x. +#if defined(__GNUC__) && (__GNUC__ >= 3) && defined(BOOST_NO_CTYPE_FUNCTIONS) +# undef BOOST_NO_CTYPE_FUNCTIONS +#endif + +// +// Assume any extensions are in namespace std:: unless stated otherwise: +// +# ifndef BOOST_STD_EXTENSION_NAMESPACE +# define BOOST_STD_EXTENSION_NAMESPACE std +# endif + +// +// If cv-qualified specializations are not allowed, then neither are cv-void ones: +// +# if defined(BOOST_NO_CV_SPECIALIZATIONS) \ + && !defined(BOOST_NO_CV_VOID_SPECIALIZATIONS) +# define BOOST_NO_CV_VOID_SPECIALIZATIONS +# endif + +// +// If there is no numeric_limits template, then it can't have any compile time +// constants either! +// +# if defined(BOOST_NO_LIMITS) \ + && !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +# define BOOST_NO_LONG_LONG_NUMERIC_LIMITS +# endif + +// +// if there is no long long then there is no specialisation +// for numeric_limits either: +// +#if !defined(BOOST_HAS_LONG_LONG) && !defined(BOOST_NO_LONG_LONG_NUMERIC_LIMITS) +# define BOOST_NO_LONG_LONG_NUMERIC_LIMITS +#endif + +// +// if there is no __int64 then there is no specialisation +// for numeric_limits<__int64> either: +// +#if !defined(BOOST_HAS_MS_INT64) && !defined(BOOST_NO_MS_INT64_NUMERIC_LIMITS) +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +#endif + +// +// if member templates are supported then so is the +// VC6 subset of member templates: +// +# if !defined(BOOST_NO_MEMBER_TEMPLATES) \ + && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) +# define BOOST_MSVC6_MEMBER_TEMPLATES +# endif + +// +// Without partial specialization, can't test for partial specialisation bugs: +// +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) +# define BOOST_BCB_PARTIAL_SPECIALIZATION_BUG +# endif + +// +// Without partial specialization, we can't have array-type partial specialisations: +// +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !defined(BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS) +# define BOOST_NO_ARRAY_TYPE_SPECIALIZATIONS +# endif + +// +// Without partial specialization, std::iterator_traits can't work: +// +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !defined(BOOST_NO_STD_ITERATOR_TRAITS) +# define BOOST_NO_STD_ITERATOR_TRAITS +# endif + +// +// Without partial specialization, partial +// specialization with default args won't work either: +// +# if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \ + && !defined(BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS) +# define BOOST_NO_PARTIAL_SPECIALIZATION_IMPLICIT_DEFAULT_ARGS +# endif + +// +// Without member template support, we can't have template constructors +// in the standard library either: +// +# if defined(BOOST_NO_MEMBER_TEMPLATES) \ + && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) \ + && !defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +# endif + +// +// Without member template support, we can't have a conforming +// std::allocator template either: +// +# if defined(BOOST_NO_MEMBER_TEMPLATES) \ + && !defined(BOOST_MSVC6_MEMBER_TEMPLATES) \ + && !defined(BOOST_NO_STD_ALLOCATOR) +# define BOOST_NO_STD_ALLOCATOR +# endif + +// +// without ADL support then using declarations will break ADL as well: +// +#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) && !defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) +# define BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL +#endif + +// +// Without typeid support we have no dynamic RTTI either: +// +#if defined(BOOST_NO_TYPEID) && !defined(BOOST_NO_RTTI) +# define BOOST_NO_RTTI +#endif + +// +// If we have a standard allocator, then we have a partial one as well: +// +#if !defined(BOOST_NO_STD_ALLOCATOR) +# define BOOST_HAS_PARTIAL_STD_ALLOCATOR +#endif + +// +// We can't have a working std::use_facet if there is no std::locale: +// +# if defined(BOOST_NO_STD_LOCALE) && !defined(BOOST_NO_STD_USE_FACET) +# define BOOST_NO_STD_USE_FACET +# endif + +// +// We can't have a std::messages facet if there is no std::locale: +// +# if defined(BOOST_NO_STD_LOCALE) && !defined(BOOST_NO_STD_MESSAGES) +# define BOOST_NO_STD_MESSAGES +# endif + +// +// We can't have a working std::wstreambuf if there is no std::locale: +// +# if defined(BOOST_NO_STD_LOCALE) && !defined(BOOST_NO_STD_WSTREAMBUF) +# define BOOST_NO_STD_WSTREAMBUF +# endif + +// +// We can't have a if there is no : +// +# if defined(BOOST_NO_CWCHAR) && !defined(BOOST_NO_CWCTYPE) +# define BOOST_NO_CWCTYPE +# endif + +// +// We can't have a swprintf if there is no : +// +# if defined(BOOST_NO_CWCHAR) && !defined(BOOST_NO_SWPRINTF) +# define BOOST_NO_SWPRINTF +# endif + +// +// If Win32 support is turned off, then we must turn off +// threading support also, unless there is some other +// thread API enabled: +// +#if defined(BOOST_DISABLE_WIN32) && defined(_WIN32) \ + && !defined(BOOST_DISABLE_THREADS) && !defined(BOOST_HAS_PTHREADS) +# define BOOST_DISABLE_THREADS +#endif + +// +// Turn on threading support if the compiler thinks that it's in +// multithreaded mode. We put this here because there are only a +// limited number of macros that identify this (if there's any missing +// from here then add to the appropriate compiler section): +// +#if (defined(__MT__) || defined(_MT) || defined(_REENTRANT) \ + || defined(_PTHREADS) || defined(__APPLE__) || defined(__DragonFly__)) \ + && !defined(BOOST_HAS_THREADS) +# define BOOST_HAS_THREADS +#endif + +// +// Turn threading support off if BOOST_DISABLE_THREADS is defined: +// +#if defined(BOOST_DISABLE_THREADS) && defined(BOOST_HAS_THREADS) +# undef BOOST_HAS_THREADS +#endif + +// +// Turn threading support off if we don't recognise the threading API: +// +#if defined(BOOST_HAS_THREADS) && !defined(BOOST_HAS_PTHREADS)\ + && !defined(BOOST_HAS_WINTHREADS) && !defined(BOOST_HAS_BETHREADS)\ + && !defined(BOOST_HAS_MPTASKS) +# undef BOOST_HAS_THREADS +#endif + +// +// Turn threading detail macros off if we don't (want to) use threading +// +#ifndef BOOST_HAS_THREADS +# undef BOOST_HAS_PTHREADS +# undef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# undef BOOST_HAS_PTHREAD_YIELD +# undef BOOST_HAS_PTHREAD_DELAY_NP +# undef BOOST_HAS_WINTHREADS +# undef BOOST_HAS_BETHREADS +# undef BOOST_HAS_MPTASKS +#endif + +// +// If the compiler claims to be C99 conformant, then it had better +// have a : +// +# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) +# define BOOST_HAS_STDINT_H +# ifndef BOOST_HAS_LOG1P +# define BOOST_HAS_LOG1P +# endif +# ifndef BOOST_HAS_EXPM1 +# define BOOST_HAS_EXPM1 +# endif +# endif + +// +// Define BOOST_NO_SLIST and BOOST_NO_HASH if required. +// Note that this is for backwards compatibility only. +// +# if !defined(BOOST_HAS_SLIST) && !defined(BOOST_NO_SLIST) +# define BOOST_NO_SLIST +# endif + +# if !defined(BOOST_HAS_HASH) && !defined(BOOST_NO_HASH) +# define BOOST_NO_HASH +# endif + +// +// Set BOOST_SLIST_HEADER if not set already: +// +#if defined(BOOST_HAS_SLIST) && !defined(BOOST_SLIST_HEADER) +# define BOOST_SLIST_HEADER +#endif + +// +// Set BOOST_HASH_SET_HEADER if not set already: +// +#if defined(BOOST_HAS_HASH) && !defined(BOOST_HASH_SET_HEADER) +# define BOOST_HASH_SET_HEADER +#endif + +// +// Set BOOST_HASH_MAP_HEADER if not set already: +// +#if defined(BOOST_HAS_HASH) && !defined(BOOST_HASH_MAP_HEADER) +# define BOOST_HASH_MAP_HEADER +#endif + +// BOOST_HAS_ABI_HEADERS +// This macro gets set if we have headers that fix the ABI, +// and prevent ODR violations when linking to external libraries: +#if defined(BOOST_ABI_PREFIX) && defined(BOOST_ABI_SUFFIX) && !defined(BOOST_HAS_ABI_HEADERS) +# define BOOST_HAS_ABI_HEADERS +#endif + +#if defined(BOOST_HAS_ABI_HEADERS) && defined(BOOST_DISABLE_ABI_HEADERS) +# undef BOOST_HAS_ABI_HEADERS +#endif + +// BOOST_NO_STDC_NAMESPACE workaround --------------------------------------// +// Because std::size_t usage is so common, even in boost headers which do not +// otherwise use the C library, the workaround is included here so +// that ugly workaround code need not appear in many other boost headers. +// NOTE WELL: This is a workaround for non-conforming compilers; +// must still be #included in the usual places so that inclusion +// works as expected with standard conforming compilers. The resulting +// double inclusion of is harmless. + +# if defined(BOOST_NO_STDC_NAMESPACE) && defined(__cplusplus) +# include + namespace std { using ::ptrdiff_t; using ::size_t; } +# endif + +// Workaround for the unfortunate min/max macros defined by some platform headers + +#define BOOST_PREVENT_MACRO_SUBSTITUTION + +#ifndef BOOST_USING_STD_MIN +# define BOOST_USING_STD_MIN() using std::min +#endif + +#ifndef BOOST_USING_STD_MAX +# define BOOST_USING_STD_MAX() using std::max +#endif + +// BOOST_NO_STD_MIN_MAX workaround -----------------------------------------// + +# if defined(BOOST_NO_STD_MIN_MAX) && defined(__cplusplus) + +namespace std { + template + inline const _Tp& min BOOST_PREVENT_MACRO_SUBSTITUTION (const _Tp& __a, const _Tp& __b) { + return __b < __a ? __b : __a; + } + template + inline const _Tp& max BOOST_PREVENT_MACRO_SUBSTITUTION (const _Tp& __a, const _Tp& __b) { + return __a < __b ? __b : __a; + } +} + +# endif + +// BOOST_STATIC_CONSTANT workaround --------------------------------------- // +// On compilers which don't allow in-class initialization of static integral +// constant members, we must use enums as a workaround if we want the constants +// to be available at compile-time. This macro gives us a convenient way to +// declare such constants. + +# ifdef BOOST_NO_INCLASS_MEMBER_INITIALIZATION +# define BOOST_STATIC_CONSTANT(type, assignment) enum { assignment } +# else +# define BOOST_STATIC_CONSTANT(type, assignment) static const type assignment +# endif + +// BOOST_USE_FACET / HAS_FACET workaround ----------------------------------// +// When the standard library does not have a conforming std::use_facet there +// are various workarounds available, but they differ from library to library. +// The same problem occurs with has_facet. +// These macros provide a consistent way to access a locale's facets. +// Usage: +// replace +// std::use_facet(loc); +// with +// BOOST_USE_FACET(Type, loc); +// Note do not add a std:: prefix to the front of BOOST_USE_FACET! +// Use for BOOST_HAS_FACET is analogous. + +#if defined(BOOST_NO_STD_USE_FACET) +# ifdef BOOST_HAS_TWO_ARG_USE_FACET +# define BOOST_USE_FACET(Type, loc) std::use_facet(loc, static_cast(0)) +# define BOOST_HAS_FACET(Type, loc) std::has_facet(loc, static_cast(0)) +# elif defined(BOOST_HAS_MACRO_USE_FACET) +# define BOOST_USE_FACET(Type, loc) std::_USE(loc, Type) +# define BOOST_HAS_FACET(Type, loc) std::_HAS(loc, Type) +# elif defined(BOOST_HAS_STLP_USE_FACET) +# define BOOST_USE_FACET(Type, loc) (*std::_Use_facet(loc)) +# define BOOST_HAS_FACET(Type, loc) std::has_facet< Type >(loc) +# endif +#else +# define BOOST_USE_FACET(Type, loc) std::use_facet< Type >(loc) +# define BOOST_HAS_FACET(Type, loc) std::has_facet< Type >(loc) +#endif + +// BOOST_NESTED_TEMPLATE workaround ------------------------------------------// +// Member templates are supported by some compilers even though they can't use +// the A::template member syntax, as a workaround replace: +// +// typedef typename A::template rebind binder; +// +// with: +// +// typedef typename A::BOOST_NESTED_TEMPLATE rebind binder; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_KEYWORD +# define BOOST_NESTED_TEMPLATE template +#else +# define BOOST_NESTED_TEMPLATE +#endif + +// BOOST_UNREACHABLE_RETURN(x) workaround -------------------------------------// +// Normally evaluates to nothing, unless BOOST_NO_UNREACHABLE_RETURN_DETECTION +// is defined, in which case it evaluates to return x; Use when you have a return +// statement that can never be reached. + +#ifndef BOOST_UNREACHABLE_RETURN +# ifdef BOOST_NO_UNREACHABLE_RETURN_DETECTION +# define BOOST_UNREACHABLE_RETURN(x) return x; +# else +# define BOOST_UNREACHABLE_RETURN(x) +# endif +#endif + +// BOOST_DEDUCED_TYPENAME workaround ------------------------------------------// +// +// Some compilers don't support the use of `typename' for dependent +// types in deduced contexts, e.g. +// +// template void f(T, typename T::type); +// ^^^^^^^^ +// Replace these declarations with: +// +// template void f(T, BOOST_DEDUCED_TYPENAME T::type); + +#ifndef BOOST_NO_DEDUCED_TYPENAME +# define BOOST_DEDUCED_TYPENAME typename +#else +# define BOOST_DEDUCED_TYPENAME +#endif + +#ifndef BOOST_NO_TYPENAME_WITH_CTOR +# define BOOST_CTOR_TYPENAME typename +#else +# define BOOST_CTOR_TYPENAME +#endif + +// long long workaround ------------------------------------------// +// On gcc (and maybe other compilers?) long long is alway supported +// but it's use may generate either warnings (with -ansi), or errors +// (with -pedantic -ansi) unless it's use is prefixed by __extension__ +// +#if defined(BOOST_HAS_LONG_LONG) && defined(__cplusplus) +namespace boost{ +# ifdef __GNUC__ + __extension__ typedef long long long_long_type; + __extension__ typedef unsigned long long ulong_long_type; +# else + typedef long long long_long_type; + typedef unsigned long long ulong_long_type; +# endif +} +#endif +// same again for __int128: +#if defined(BOOST_HAS_INT128) && defined(__cplusplus) +namespace boost{ +# ifdef __GNUC__ + __extension__ typedef __int128 int128_type; + __extension__ typedef unsigned __int128 uint128_type; +# else + typedef __int128 int128_type; + typedef unsigned __int128 uint128_type; +# endif +} +#endif +// same again for __float128: +#if defined(BOOST_HAS_FLOAT128) && defined(__cplusplus) +namespace boost { +# ifdef __GNUC__ + __extension__ typedef __float128 float128_type; +# else + typedef __float128 float128_type; +# endif +} +#endif + +// BOOST_[APPEND_]EXPLICIT_TEMPLATE_[NON_]TYPE macros --------------------------// + +// These macros are obsolete. Port away and remove. + +# define BOOST_EXPLICIT_TEMPLATE_TYPE(t) +# define BOOST_EXPLICIT_TEMPLATE_TYPE_SPEC(t) +# define BOOST_EXPLICIT_TEMPLATE_NON_TYPE(t, v) +# define BOOST_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) + +# define BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(t) +# define BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(t) +# define BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(t, v) +# define BOOST_APPEND_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) + +// When BOOST_NO_STD_TYPEINFO is defined, we can just import +// the global definition into std namespace: +#if defined(BOOST_NO_STD_TYPEINFO) && defined(__cplusplus) +#include +namespace std{ using ::type_info; } +#endif + +// ---------------------------------------------------------------------------// + +// Helper macro BOOST_STRINGIZE: +// Helper macro BOOST_JOIN: + +#include + +// +// Set some default values for compiler/library/platform names. +// These are for debugging config setup only: +// +# ifndef BOOST_COMPILER +# define BOOST_COMPILER "Unknown ISO C++ Compiler" +# endif +# ifndef BOOST_STDLIB +# define BOOST_STDLIB "Unknown ISO standard library" +# endif +# ifndef BOOST_PLATFORM +# if defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) \ + || defined(_POSIX_SOURCE) +# define BOOST_PLATFORM "Generic Unix" +# else +# define BOOST_PLATFORM "Unknown" +# endif +# endif + +// +// Set some default values GPU support +// +# ifndef BOOST_GPU_ENABLED +# define BOOST_GPU_ENABLED +# endif + +// BOOST_RESTRICT ---------------------------------------------// +// Macro to use in place of 'restrict' keyword variants +#if !defined(BOOST_RESTRICT) +# if defined(_MSC_VER) +# define BOOST_RESTRICT __restrict +# if !defined(BOOST_NO_RESTRICT_REFERENCES) && (_MSC_FULL_VER < 190023026) +# define BOOST_NO_RESTRICT_REFERENCES +# endif +# elif defined(__GNUC__) && __GNUC__ > 3 + // Clang also defines __GNUC__ (as 4) +# define BOOST_RESTRICT __restrict__ +# else +# define BOOST_RESTRICT +# if !defined(BOOST_NO_RESTRICT_REFERENCES) +# define BOOST_NO_RESTRICT_REFERENCES +# endif +# endif +#endif + +// BOOST_MAY_ALIAS -----------------------------------------------// +// The macro expands to an attribute to mark a type that is allowed to alias other types. +// The macro is defined in the compiler-specific headers. +#if !defined(BOOST_MAY_ALIAS) +# define BOOST_NO_MAY_ALIAS +# define BOOST_MAY_ALIAS +#endif + +// BOOST_FORCEINLINE ---------------------------------------------// +// Macro to use in place of 'inline' to force a function to be inline +#if !defined(BOOST_FORCEINLINE) +# if defined(_MSC_VER) +# define BOOST_FORCEINLINE __forceinline +# elif defined(__GNUC__) && __GNUC__ > 3 + // Clang also defines __GNUC__ (as 4) +# define BOOST_FORCEINLINE inline __attribute__ ((__always_inline__)) +# else +# define BOOST_FORCEINLINE inline +# endif +#endif + +// BOOST_NOINLINE ---------------------------------------------// +// Macro to use in place of 'inline' to prevent a function to be inlined +#if !defined(BOOST_NOINLINE) +# if defined(_MSC_VER) +# define BOOST_NOINLINE __declspec(noinline) +# elif defined(__GNUC__) && __GNUC__ > 3 + // Clang also defines __GNUC__ (as 4) +# if defined(__CUDACC__) + // nvcc doesn't always parse __noinline__, + // see: https://svn.boost.org/trac/boost/ticket/9392 +# define BOOST_NOINLINE __attribute__ ((noinline)) +# else +# define BOOST_NOINLINE __attribute__ ((__noinline__)) +# endif +# else +# define BOOST_NOINLINE +# endif +#endif + +// BOOST_NORETURN ---------------------------------------------// +// Macro to use before a function declaration/definition to designate +// the function as not returning normally (i.e. with a return statement +// or by leaving the function scope, if the function return type is void). +#if !defined(BOOST_NORETURN) +# if defined(_MSC_VER) +# define BOOST_NORETURN __declspec(noreturn) +# elif defined(__GNUC__) +# define BOOST_NORETURN __attribute__ ((__noreturn__)) +# elif defined(__has_attribute) && defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x5130) +# if __has_attribute(noreturn) +# define BOOST_NORETURN [[noreturn]] +# endif +# elif defined(__has_cpp_attribute) +# if __has_cpp_attribute(noreturn) +# define BOOST_NORETURN [[noreturn]] +# endif +# endif +#endif + +#if !defined(BOOST_NORETURN) +# define BOOST_NO_NORETURN +# define BOOST_NORETURN +#endif + +// Branch prediction hints +// These macros are intended to wrap conditional expressions that yield true or false +// +// if (BOOST_LIKELY(var == 10)) +// { +// // the most probable code here +// } +// +#if !defined(BOOST_LIKELY) +# define BOOST_LIKELY(x) x +#endif +#if !defined(BOOST_UNLIKELY) +# define BOOST_UNLIKELY(x) x +#endif + +// Type and data alignment specification +// +#if !defined(BOOST_ALIGNMENT) +# if !defined(BOOST_NO_CXX11_ALIGNAS) +# define BOOST_ALIGNMENT(x) alignas(x) +# elif defined(_MSC_VER) +# define BOOST_ALIGNMENT(x) __declspec(align(x)) +# elif defined(__GNUC__) +# define BOOST_ALIGNMENT(x) __attribute__ ((__aligned__(x))) +# else +# define BOOST_NO_ALIGNMENT +# define BOOST_ALIGNMENT(x) +# endif +#endif + +// Lack of non-public defaulted functions is implied by the lack of any defaulted functions +#if !defined(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS) && defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) +# define BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS +#endif + +// Lack of defaulted moves is implied by the lack of either rvalue references or any defaulted functions +#if !defined(BOOST_NO_CXX11_DEFAULTED_MOVES) && (defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)) +# define BOOST_NO_CXX11_DEFAULTED_MOVES +#endif + +// Defaulted and deleted function declaration helpers +// These macros are intended to be inside a class definition. +// BOOST_DEFAULTED_FUNCTION accepts the function declaration and its +// body, which will be used if the compiler doesn't support defaulted functions. +// BOOST_DELETED_FUNCTION only accepts the function declaration. It +// will expand to a private function declaration, if the compiler doesn't support +// deleted functions. Because of this it is recommended to use BOOST_DELETED_FUNCTION +// in the end of the class definition. +// +// class my_class +// { +// public: +// // Default-constructible +// BOOST_DEFAULTED_FUNCTION(my_class(), {}) +// // Copying prohibited +// BOOST_DELETED_FUNCTION(my_class(my_class const&)) +// BOOST_DELETED_FUNCTION(my_class& operator= (my_class const&)) +// }; +// +#if !(defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || defined(BOOST_NO_CXX11_NON_PUBLIC_DEFAULTED_FUNCTIONS)) +# define BOOST_DEFAULTED_FUNCTION(fun, body) fun = default; +#else +# define BOOST_DEFAULTED_FUNCTION(fun, body) fun body +#endif + +#if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) +# define BOOST_DELETED_FUNCTION(fun) fun = delete; +#else +# define BOOST_DELETED_FUNCTION(fun) private: fun; +#endif + +// +// Set BOOST_NO_DECLTYPE_N3276 when BOOST_NO_DECLTYPE is defined +// +#if defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_DECLTYPE_N3276) +#define BOOST_NO_CXX11_DECLTYPE_N3276 BOOST_NO_CXX11_DECLTYPE +#endif + +// -------------------- Deprecated macros for 1.50 --------------------------- +// These will go away in a future release + +// Use BOOST_NO_CXX11_HDR_UNORDERED_SET or BOOST_NO_CXX11_HDR_UNORDERED_MAP +// instead of BOOST_NO_STD_UNORDERED +#if defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) || defined (BOOST_NO_CXX11_HDR_UNORDERED_SET) +# ifndef BOOST_NO_CXX11_STD_UNORDERED +# define BOOST_NO_CXX11_STD_UNORDERED +# endif +#endif + +// Use BOOST_NO_CXX11_HDR_INITIALIZER_LIST instead of BOOST_NO_INITIALIZER_LISTS +#if defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) && !defined(BOOST_NO_INITIALIZER_LISTS) +# define BOOST_NO_INITIALIZER_LISTS +#endif + +// Use BOOST_NO_CXX11_HDR_ARRAY instead of BOOST_NO_0X_HDR_ARRAY +#if defined(BOOST_NO_CXX11_HDR_ARRAY) && !defined(BOOST_NO_0X_HDR_ARRAY) +# define BOOST_NO_0X_HDR_ARRAY +#endif +// Use BOOST_NO_CXX11_HDR_CHRONO instead of BOOST_NO_0X_HDR_CHRONO +#if defined(BOOST_NO_CXX11_HDR_CHRONO) && !defined(BOOST_NO_0X_HDR_CHRONO) +# define BOOST_NO_0X_HDR_CHRONO +#endif +// Use BOOST_NO_CXX11_HDR_CODECVT instead of BOOST_NO_0X_HDR_CODECVT +#if defined(BOOST_NO_CXX11_HDR_CODECVT) && !defined(BOOST_NO_0X_HDR_CODECVT) +# define BOOST_NO_0X_HDR_CODECVT +#endif +// Use BOOST_NO_CXX11_HDR_CONDITION_VARIABLE instead of BOOST_NO_0X_HDR_CONDITION_VARIABLE +#if defined(BOOST_NO_CXX11_HDR_CONDITION_VARIABLE) && !defined(BOOST_NO_0X_HDR_CONDITION_VARIABLE) +# define BOOST_NO_0X_HDR_CONDITION_VARIABLE +#endif +// Use BOOST_NO_CXX11_HDR_FORWARD_LIST instead of BOOST_NO_0X_HDR_FORWARD_LIST +#if defined(BOOST_NO_CXX11_HDR_FORWARD_LIST) && !defined(BOOST_NO_0X_HDR_FORWARD_LIST) +# define BOOST_NO_0X_HDR_FORWARD_LIST +#endif +// Use BOOST_NO_CXX11_HDR_FUTURE instead of BOOST_NO_0X_HDR_FUTURE +#if defined(BOOST_NO_CXX11_HDR_FUTURE) && !defined(BOOST_NO_0X_HDR_FUTURE) +# define BOOST_NO_0X_HDR_FUTURE +#endif + +// Use BOOST_NO_CXX11_HDR_INITIALIZER_LIST +// instead of BOOST_NO_0X_HDR_INITIALIZER_LIST or BOOST_NO_INITIALIZER_LISTS +#ifdef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# ifndef BOOST_NO_0X_HDR_INITIALIZER_LIST +# define BOOST_NO_0X_HDR_INITIALIZER_LIST +# endif +# ifndef BOOST_NO_INITIALIZER_LISTS +# define BOOST_NO_INITIALIZER_LISTS +# endif +#endif + +// Use BOOST_NO_CXX11_HDR_MUTEX instead of BOOST_NO_0X_HDR_MUTEX +#if defined(BOOST_NO_CXX11_HDR_MUTEX) && !defined(BOOST_NO_0X_HDR_MUTEX) +# define BOOST_NO_0X_HDR_MUTEX +#endif +// Use BOOST_NO_CXX11_HDR_RANDOM instead of BOOST_NO_0X_HDR_RANDOM +#if defined(BOOST_NO_CXX11_HDR_RANDOM) && !defined(BOOST_NO_0X_HDR_RANDOM) +# define BOOST_NO_0X_HDR_RANDOM +#endif +// Use BOOST_NO_CXX11_HDR_RATIO instead of BOOST_NO_0X_HDR_RATIO +#if defined(BOOST_NO_CXX11_HDR_RATIO) && !defined(BOOST_NO_0X_HDR_RATIO) +# define BOOST_NO_0X_HDR_RATIO +#endif +// Use BOOST_NO_CXX11_HDR_REGEX instead of BOOST_NO_0X_HDR_REGEX +#if defined(BOOST_NO_CXX11_HDR_REGEX) && !defined(BOOST_NO_0X_HDR_REGEX) +# define BOOST_NO_0X_HDR_REGEX +#endif +// Use BOOST_NO_CXX11_HDR_SYSTEM_ERROR instead of BOOST_NO_0X_HDR_SYSTEM_ERROR +#if defined(BOOST_NO_CXX11_HDR_SYSTEM_ERROR) && !defined(BOOST_NO_0X_HDR_SYSTEM_ERROR) +# define BOOST_NO_0X_HDR_SYSTEM_ERROR +#endif +// Use BOOST_NO_CXX11_HDR_THREAD instead of BOOST_NO_0X_HDR_THREAD +#if defined(BOOST_NO_CXX11_HDR_THREAD) && !defined(BOOST_NO_0X_HDR_THREAD) +# define BOOST_NO_0X_HDR_THREAD +#endif +// Use BOOST_NO_CXX11_HDR_TUPLE instead of BOOST_NO_0X_HDR_TUPLE +#if defined(BOOST_NO_CXX11_HDR_TUPLE) && !defined(BOOST_NO_0X_HDR_TUPLE) +# define BOOST_NO_0X_HDR_TUPLE +#endif +// Use BOOST_NO_CXX11_HDR_TYPE_TRAITS instead of BOOST_NO_0X_HDR_TYPE_TRAITS +#if defined(BOOST_NO_CXX11_HDR_TYPE_TRAITS) && !defined(BOOST_NO_0X_HDR_TYPE_TRAITS) +# define BOOST_NO_0X_HDR_TYPE_TRAITS +#endif +// Use BOOST_NO_CXX11_HDR_TYPEINDEX instead of BOOST_NO_0X_HDR_TYPEINDEX +#if defined(BOOST_NO_CXX11_HDR_TYPEINDEX) && !defined(BOOST_NO_0X_HDR_TYPEINDEX) +# define BOOST_NO_0X_HDR_TYPEINDEX +#endif +// Use BOOST_NO_CXX11_HDR_UNORDERED_MAP instead of BOOST_NO_0X_HDR_UNORDERED_MAP +#if defined(BOOST_NO_CXX11_HDR_UNORDERED_MAP) && !defined(BOOST_NO_0X_HDR_UNORDERED_MAP) +# define BOOST_NO_0X_HDR_UNORDERED_MAP +#endif +// Use BOOST_NO_CXX11_HDR_UNORDERED_SET instead of BOOST_NO_0X_HDR_UNORDERED_SET +#if defined(BOOST_NO_CXX11_HDR_UNORDERED_SET) && !defined(BOOST_NO_0X_HDR_UNORDERED_SET) +# define BOOST_NO_0X_HDR_UNORDERED_SET +#endif + +// ------------------ End of deprecated macros for 1.50 --------------------------- + +// -------------------- Deprecated macros for 1.51 --------------------------- +// These will go away in a future release + +// Use BOOST_NO_CXX11_AUTO_DECLARATIONS instead of BOOST_NO_AUTO_DECLARATIONS +#if defined(BOOST_NO_CXX11_AUTO_DECLARATIONS) && !defined(BOOST_NO_AUTO_DECLARATIONS) +# define BOOST_NO_AUTO_DECLARATIONS +#endif +// Use BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS instead of BOOST_NO_AUTO_MULTIDECLARATIONS +#if defined(BOOST_NO_CXX11_AUTO_MULTIDECLARATIONS) && !defined(BOOST_NO_AUTO_MULTIDECLARATIONS) +# define BOOST_NO_AUTO_MULTIDECLARATIONS +#endif +// Use BOOST_NO_CXX11_CHAR16_T instead of BOOST_NO_CHAR16_T +#if defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CHAR16_T) +# define BOOST_NO_CHAR16_T +#endif +// Use BOOST_NO_CXX11_CHAR32_T instead of BOOST_NO_CHAR32_T +#if defined(BOOST_NO_CXX11_CHAR32_T) && !defined(BOOST_NO_CHAR32_T) +# define BOOST_NO_CHAR32_T +#endif +// Use BOOST_NO_CXX11_TEMPLATE_ALIASES instead of BOOST_NO_TEMPLATE_ALIASES +#if defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) && !defined(BOOST_NO_TEMPLATE_ALIASES) +# define BOOST_NO_TEMPLATE_ALIASES +#endif +// Use BOOST_NO_CXX11_CONSTEXPR instead of BOOST_NO_CONSTEXPR +#if defined(BOOST_NO_CXX11_CONSTEXPR) && !defined(BOOST_NO_CONSTEXPR) +# define BOOST_NO_CONSTEXPR +#endif +// Use BOOST_NO_CXX11_DECLTYPE_N3276 instead of BOOST_NO_DECLTYPE_N3276 +#if defined(BOOST_NO_CXX11_DECLTYPE_N3276) && !defined(BOOST_NO_DECLTYPE_N3276) +# define BOOST_NO_DECLTYPE_N3276 +#endif +// Use BOOST_NO_CXX11_DECLTYPE instead of BOOST_NO_DECLTYPE +#if defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_DECLTYPE) +# define BOOST_NO_DECLTYPE +#endif +// Use BOOST_NO_CXX11_DEFAULTED_FUNCTIONS instead of BOOST_NO_DEFAULTED_FUNCTIONS +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) && !defined(BOOST_NO_DEFAULTED_FUNCTIONS) +# define BOOST_NO_DEFAULTED_FUNCTIONS +#endif +// Use BOOST_NO_CXX11_DELETED_FUNCTIONS instead of BOOST_NO_DELETED_FUNCTIONS +#if defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) && !defined(BOOST_NO_DELETED_FUNCTIONS) +# define BOOST_NO_DELETED_FUNCTIONS +#endif +// Use BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS instead of BOOST_NO_EXPLICIT_CONVERSION_OPERATORS +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) && !defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS) +# define BOOST_NO_EXPLICIT_CONVERSION_OPERATORS +#endif +// Use BOOST_NO_CXX11_EXTERN_TEMPLATE instead of BOOST_NO_EXTERN_TEMPLATE +#if defined(BOOST_NO_CXX11_EXTERN_TEMPLATE) && !defined(BOOST_NO_EXTERN_TEMPLATE) +# define BOOST_NO_EXTERN_TEMPLATE +#endif +// Use BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS instead of BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS +#if defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) +# define BOOST_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS +#endif +// Use BOOST_NO_CXX11_LAMBDAS instead of BOOST_NO_LAMBDAS +#if defined(BOOST_NO_CXX11_LAMBDAS) && !defined(BOOST_NO_LAMBDAS) +# define BOOST_NO_LAMBDAS +#endif +// Use BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS instead of BOOST_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS +#if defined(BOOST_NO_CXX11_LOCAL_CLASS_TEMPLATE_PARAMETERS) && !defined(BOOST_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS) +# define BOOST_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS +#endif +// Use BOOST_NO_CXX11_NOEXCEPT instead of BOOST_NO_NOEXCEPT +#if defined(BOOST_NO_CXX11_NOEXCEPT) && !defined(BOOST_NO_NOEXCEPT) +# define BOOST_NO_NOEXCEPT +#endif +// Use BOOST_NO_CXX11_NULLPTR instead of BOOST_NO_NULLPTR +#if defined(BOOST_NO_CXX11_NULLPTR) && !defined(BOOST_NO_NULLPTR) +# define BOOST_NO_NULLPTR +#endif +// Use BOOST_NO_CXX11_RAW_LITERALS instead of BOOST_NO_RAW_LITERALS +#if defined(BOOST_NO_CXX11_RAW_LITERALS) && !defined(BOOST_NO_RAW_LITERALS) +# define BOOST_NO_RAW_LITERALS +#endif +// Use BOOST_NO_CXX11_RVALUE_REFERENCES instead of BOOST_NO_RVALUE_REFERENCES +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_RVALUE_REFERENCES) +# define BOOST_NO_RVALUE_REFERENCES +#endif +// Use BOOST_NO_CXX11_SCOPED_ENUMS instead of BOOST_NO_SCOPED_ENUMS +#if defined(BOOST_NO_CXX11_SCOPED_ENUMS) && !defined(BOOST_NO_SCOPED_ENUMS) +# define BOOST_NO_SCOPED_ENUMS +#endif +// Use BOOST_NO_CXX11_STATIC_ASSERT instead of BOOST_NO_STATIC_ASSERT +#if defined(BOOST_NO_CXX11_STATIC_ASSERT) && !defined(BOOST_NO_STATIC_ASSERT) +# define BOOST_NO_STATIC_ASSERT +#endif +// Use BOOST_NO_CXX11_STD_UNORDERED instead of BOOST_NO_STD_UNORDERED +#if defined(BOOST_NO_CXX11_STD_UNORDERED) && !defined(BOOST_NO_STD_UNORDERED) +# define BOOST_NO_STD_UNORDERED +#endif +// Use BOOST_NO_CXX11_UNICODE_LITERALS instead of BOOST_NO_UNICODE_LITERALS +#if defined(BOOST_NO_CXX11_UNICODE_LITERALS) && !defined(BOOST_NO_UNICODE_LITERALS) +# define BOOST_NO_UNICODE_LITERALS +#endif +// Use BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX instead of BOOST_NO_UNIFIED_INITIALIZATION_SYNTAX +#if defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) && !defined(BOOST_NO_UNIFIED_INITIALIZATION_SYNTAX) +# define BOOST_NO_UNIFIED_INITIALIZATION_SYNTAX +#endif +// Use BOOST_NO_CXX11_VARIADIC_TEMPLATES instead of BOOST_NO_VARIADIC_TEMPLATES +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_VARIADIC_TEMPLATES) +# define BOOST_NO_VARIADIC_TEMPLATES +#endif +// Use BOOST_NO_CXX11_VARIADIC_MACROS instead of BOOST_NO_VARIADIC_MACROS +#if defined(BOOST_NO_CXX11_VARIADIC_MACROS) && !defined(BOOST_NO_VARIADIC_MACROS) +# define BOOST_NO_VARIADIC_MACROS +#endif +// Use BOOST_NO_CXX11_NUMERIC_LIMITS instead of BOOST_NO_NUMERIC_LIMITS_LOWEST +#if defined(BOOST_NO_CXX11_NUMERIC_LIMITS) && !defined(BOOST_NO_NUMERIC_LIMITS_LOWEST) +# define BOOST_NO_NUMERIC_LIMITS_LOWEST +#endif +// ------------------ End of deprecated macros for 1.51 --------------------------- + + + +// +// Helper macros BOOST_NOEXCEPT, BOOST_NOEXCEPT_IF, BOOST_NOEXCEPT_EXPR +// These aid the transition to C++11 while still supporting C++03 compilers +// +#ifdef BOOST_NO_CXX11_NOEXCEPT +# define BOOST_NOEXCEPT +# define BOOST_NOEXCEPT_OR_NOTHROW throw() +# define BOOST_NOEXCEPT_IF(Predicate) +# define BOOST_NOEXCEPT_EXPR(Expression) false +#else +# define BOOST_NOEXCEPT noexcept +# define BOOST_NOEXCEPT_OR_NOTHROW noexcept +# define BOOST_NOEXCEPT_IF(Predicate) noexcept((Predicate)) +# define BOOST_NOEXCEPT_EXPR(Expression) noexcept((Expression)) +#endif +// +// Helper macro BOOST_FALLTHROUGH +// Fallback definition of BOOST_FALLTHROUGH macro used to mark intended +// fall-through between case labels in a switch statement. We use a definition +// that requires a semicolon after it to avoid at least one type of misuse even +// on unsupported compilers. +// +#ifndef BOOST_FALLTHROUGH +# define BOOST_FALLTHROUGH ((void)0) +#endif + +// +// constexpr workarounds +// +#if defined(BOOST_NO_CXX11_CONSTEXPR) +#define BOOST_CONSTEXPR +#define BOOST_CONSTEXPR_OR_CONST const +#else +#define BOOST_CONSTEXPR constexpr +#define BOOST_CONSTEXPR_OR_CONST constexpr +#endif +#if defined(BOOST_NO_CXX14_CONSTEXPR) +#define BOOST_CXX14_CONSTEXPR +#else +#define BOOST_CXX14_CONSTEXPR constexpr +#endif + +// +// Unused variable/typedef workarounds: +// +#ifndef BOOST_ATTRIBUTE_UNUSED +# define BOOST_ATTRIBUTE_UNUSED +#endif + +#define BOOST_STATIC_CONSTEXPR static BOOST_CONSTEXPR_OR_CONST + +// +// Set BOOST_HAS_STATIC_ASSERT when BOOST_NO_CXX11_STATIC_ASSERT is not defined +// +#if !defined(BOOST_NO_CXX11_STATIC_ASSERT) && !defined(BOOST_HAS_STATIC_ASSERT) +# define BOOST_HAS_STATIC_ASSERT +#endif + +// +// Set BOOST_HAS_RVALUE_REFS when BOOST_NO_CXX11_RVALUE_REFERENCES is not defined +// +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_HAS_RVALUE_REFS) +#define BOOST_HAS_RVALUE_REFS +#endif + +// +// Set BOOST_HAS_VARIADIC_TMPL when BOOST_NO_CXX11_VARIADIC_TEMPLATES is not defined +// +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_HAS_VARIADIC_TMPL) +#define BOOST_HAS_VARIADIC_TMPL +#endif +// +// Set BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS when +// BOOST_NO_CXX11_VARIADIC_TEMPLATES is set: +// +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS) +# define BOOST_NO_CXX11_FIXED_LENGTH_VARIADIC_TEMPLATE_EXPANSION_PACKS +#endif + +// This is a catch all case for obsolete compilers / std libs: +#if !defined(__has_include) +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#else +#if !__has_include() +# define BOOST_NO_CXX17_HDR_OPTIONAL +#endif +#if !__has_include() +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif +#endif + +// +// Finish off with checks for macros that are depricated / no longer supported, +// if any of these are set then it's very likely that much of Boost will no +// longer work. So stop with a #error for now, but give the user a chance +// to continue at their own risk if they really want to: +// +#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_CONFIG_ALLOW_DEPRECATED) +# error "You are using a compiler which lacks features which are now a minimum requirement in order to use Boost, define BOOST_CONFIG_ALLOW_DEPRECATED if you want to continue at your own risk!!!" +#endif + +#endif diff --git a/third-party/boost/boost/config/header_deprecated.hpp b/third-party/boost/boost/config/header_deprecated.hpp new file mode 100644 index 000000000..864554f2a --- /dev/null +++ b/third-party/boost/boost/config/header_deprecated.hpp @@ -0,0 +1,26 @@ +#ifndef BOOST_CONFIG_HEADER_DEPRECATED_HPP_INCLUDED +#define BOOST_CONFIG_HEADER_DEPRECATED_HPP_INCLUDED + +// Copyright 2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// BOOST_HEADER_DEPRECATED("") +// +// Expands to the equivalent of +// BOOST_PRAGMA_MESSAGE("This header is deprecated. Use instead.") +// +// Note that this header is C compatible. + +#include + +#if defined(BOOST_ALLOW_DEPRECATED_HEADERS) +# define BOOST_HEADER_DEPRECATED(a) +#else +# define BOOST_HEADER_DEPRECATED(a) BOOST_PRAGMA_MESSAGE("This header is deprecated. Use " a " instead.") +#endif + +#endif // BOOST_CONFIG_HEADER_DEPRECATED_HPP_INCLUDED diff --git a/third-party/boost/boost/config/helper_macros.hpp b/third-party/boost/boost/config/helper_macros.hpp new file mode 100644 index 000000000..3e79526df --- /dev/null +++ b/third-party/boost/boost/config/helper_macros.hpp @@ -0,0 +1,37 @@ +#ifndef BOOST_CONFIG_HELPER_MACROS_HPP_INCLUDED +#define BOOST_CONFIG_HELPER_MACROS_HPP_INCLUDED + +// Copyright 2001 John Maddock. +// Copyright 2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// BOOST_STRINGIZE(X) +// BOOST_JOIN(X, Y) +// +// Note that this header is C compatible. + +// +// Helper macro BOOST_STRINGIZE: +// Converts the parameter X to a string after macro replacement +// on X has been performed. +// +#define BOOST_STRINGIZE(X) BOOST_DO_STRINGIZE(X) +#define BOOST_DO_STRINGIZE(X) #X + +// +// Helper macro BOOST_JOIN: +// The following piece of macro magic joins the two +// arguments together, even when one of the arguments is +// itself a macro (see 16.3.1 in C++ standard). The key +// is that macro expansion of macro arguments does not +// occur in BOOST_DO_JOIN2 but does in BOOST_DO_JOIN. +// +#define BOOST_JOIN(X, Y) BOOST_DO_JOIN(X, Y) +#define BOOST_DO_JOIN(X, Y) BOOST_DO_JOIN2(X,Y) +#define BOOST_DO_JOIN2(X, Y) X##Y + +#endif // BOOST_CONFIG_HELPER_MACROS_HPP_INCLUDED diff --git a/third-party/boost/boost/config/no_tr1/cmath.hpp b/third-party/boost/boost/config/no_tr1/cmath.hpp new file mode 100644 index 000000000..d8268d842 --- /dev/null +++ b/third-party/boost/boost/config/no_tr1/cmath.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2008. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The aim of this header is just to include but to do +// so in a way that does not result in recursive inclusion of +// the Boost TR1 components if boost/tr1/tr1/cmath is in the +// include search path. We have to do this to avoid circular +// dependencies: +// + +#ifndef BOOST_CONFIG_CMATH +# define BOOST_CONFIG_CMATH + +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_CONFIG_NO_CMATH_RECURSION +# endif + +# include + +# ifdef BOOST_CONFIG_NO_CMATH_RECURSION +# undef BOOST_TR1_NO_RECURSION +# undef BOOST_CONFIG_NO_CMATH_RECURSION +# endif + +#endif diff --git a/third-party/boost/boost/config/no_tr1/complex.hpp b/third-party/boost/boost/config/no_tr1/complex.hpp new file mode 100644 index 000000000..ca200922b --- /dev/null +++ b/third-party/boost/boost/config/no_tr1/complex.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The aim of this header is just to include but to do +// so in a way that does not result in recursive inclusion of +// the Boost TR1 components if boost/tr1/tr1/complex is in the +// include search path. We have to do this to avoid circular +// dependencies: +// + +#ifndef BOOST_CONFIG_COMPLEX +# define BOOST_CONFIG_COMPLEX + +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_CONFIG_NO_COMPLEX_RECURSION +# endif + +# include + +# ifdef BOOST_CONFIG_NO_COMPLEX_RECURSION +# undef BOOST_TR1_NO_RECURSION +# undef BOOST_CONFIG_NO_COMPLEX_RECURSION +# endif + +#endif diff --git a/third-party/boost/boost/config/no_tr1/functional.hpp b/third-party/boost/boost/config/no_tr1/functional.hpp new file mode 100644 index 000000000..e395efc19 --- /dev/null +++ b/third-party/boost/boost/config/no_tr1/functional.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The aim of this header is just to include but to do +// so in a way that does not result in recursive inclusion of +// the Boost TR1 components if boost/tr1/tr1/functional is in the +// include search path. We have to do this to avoid circular +// dependencies: +// + +#ifndef BOOST_CONFIG_FUNCTIONAL +# define BOOST_CONFIG_FUNCTIONAL + +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_CONFIG_NO_FUNCTIONAL_RECURSION +# endif + +# include + +# ifdef BOOST_CONFIG_NO_FUNCTIONAL_RECURSION +# undef BOOST_TR1_NO_RECURSION +# undef BOOST_CONFIG_NO_FUNCTIONAL_RECURSION +# endif + +#endif diff --git a/third-party/boost/boost/config/no_tr1/memory.hpp b/third-party/boost/boost/config/no_tr1/memory.hpp new file mode 100644 index 000000000..2b5d20802 --- /dev/null +++ b/third-party/boost/boost/config/no_tr1/memory.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The aim of this header is just to include but to do +// so in a way that does not result in recursive inclusion of +// the Boost TR1 components if boost/tr1/tr1/memory is in the +// include search path. We have to do this to avoid circular +// dependencies: +// + +#ifndef BOOST_CONFIG_MEMORY +# define BOOST_CONFIG_MEMORY + +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_CONFIG_NO_MEMORY_RECURSION +# endif + +# include + +# ifdef BOOST_CONFIG_NO_MEMORY_RECURSION +# undef BOOST_TR1_NO_RECURSION +# undef BOOST_CONFIG_NO_MEMORY_RECURSION +# endif + +#endif diff --git a/third-party/boost/boost/config/no_tr1/utility.hpp b/third-party/boost/boost/config/no_tr1/utility.hpp new file mode 100644 index 000000000..dea8f115b --- /dev/null +++ b/third-party/boost/boost/config/no_tr1/utility.hpp @@ -0,0 +1,28 @@ +// (C) Copyright John Maddock 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// The aim of this header is just to include but to do +// so in a way that does not result in recursive inclusion of +// the Boost TR1 components if boost/tr1/tr1/utility is in the +// include search path. We have to do this to avoid circular +// dependencies: +// + +#ifndef BOOST_CONFIG_UTILITY +# define BOOST_CONFIG_UTILITY + +# ifndef BOOST_TR1_NO_RECURSION +# define BOOST_TR1_NO_RECURSION +# define BOOST_CONFIG_NO_UTILITY_RECURSION +# endif + +# include + +# ifdef BOOST_CONFIG_NO_UTILITY_RECURSION +# undef BOOST_TR1_NO_RECURSION +# undef BOOST_CONFIG_NO_UTILITY_RECURSION +# endif + +#endif diff --git a/third-party/boost/boost/config/platform/aix.hpp b/third-party/boost/boost/config/platform/aix.hpp new file mode 100644 index 000000000..a48e23206 --- /dev/null +++ b/third-party/boost/boost/config/platform/aix.hpp @@ -0,0 +1,33 @@ +// (C) Copyright John Maddock 2001 - 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// IBM/Aix specific config options: + +#define BOOST_PLATFORM "IBM Aix" + +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_NL_TYPES_H +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_CLOCK_GETTIME + +// This needs support in "boost/cstdint.hpp" exactly like FreeBSD. +// This platform has header named which includes all +// the things needed. +#define BOOST_HAS_STDINT_H + +// Threading API's: +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_PTHREAD_DELAY_NP +#define BOOST_HAS_SCHED_YIELD +//#define BOOST_HAS_PTHREAD_YIELD + +// boilerplate code: +#include + + + + diff --git a/third-party/boost/boost/config/platform/amigaos.hpp b/third-party/boost/boost/config/platform/amigaos.hpp new file mode 100644 index 000000000..34bcf4128 --- /dev/null +++ b/third-party/boost/boost/config/platform/amigaos.hpp @@ -0,0 +1,15 @@ +// (C) Copyright John Maddock 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +#define BOOST_PLATFORM "AmigaOS" + +#define BOOST_DISABLE_THREADS +#define BOOST_NO_CWCHAR +#define BOOST_NO_STD_WSTRING +#define BOOST_NO_INTRINSIC_WCHAR_T + + diff --git a/third-party/boost/boost/config/platform/beos.hpp b/third-party/boost/boost/config/platform/beos.hpp new file mode 100644 index 000000000..6158c1c20 --- /dev/null +++ b/third-party/boost/boost/config/platform/beos.hpp @@ -0,0 +1,26 @@ +// (C) Copyright John Maddock 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// BeOS specific config options: + +#define BOOST_PLATFORM "BeOS" + +#define BOOST_NO_CWCHAR +#define BOOST_NO_CWCTYPE +#define BOOST_HAS_UNISTD_H + +#define BOOST_HAS_BETHREADS + +#ifndef BOOST_DISABLE_THREADS +# define BOOST_HAS_THREADS +#endif + +// boilerplate code: +#include + + + diff --git a/third-party/boost/boost/config/platform/bsd.hpp b/third-party/boost/boost/config/platform/bsd.hpp new file mode 100644 index 000000000..79e74a080 --- /dev/null +++ b/third-party/boost/boost/config/platform/bsd.hpp @@ -0,0 +1,86 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Douglas Gregor 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// generic BSD config options: + +#if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) +#error "This platform is not BSD" +#endif + +#ifdef __FreeBSD__ +#define BOOST_PLATFORM "FreeBSD " BOOST_STRINGIZE(__FreeBSD__) +#elif defined(__NetBSD__) +#define BOOST_PLATFORM "NetBSD " BOOST_STRINGIZE(__NetBSD__) +#elif defined(__OpenBSD__) +#define BOOST_PLATFORM "OpenBSD " BOOST_STRINGIZE(__OpenBSD__) +#elif defined(__DragonFly__) +#define BOOST_PLATFORM "DragonFly " BOOST_STRINGIZE(__DragonFly__) +#endif + +// +// is this the correct version check? +// FreeBSD has but does not +// advertise the fact in : +// +#if (defined(__FreeBSD__) && (__FreeBSD__ >= 3)) || defined(__DragonFly__) +# define BOOST_HAS_NL_TYPES_H +#endif + +// +// FreeBSD 3.x has pthreads support, but defines _POSIX_THREADS in +// and not in +// +#if (defined(__FreeBSD__) && (__FreeBSD__ <= 3))\ + || defined(__OpenBSD__) || defined(__DragonFly__) +# define BOOST_HAS_PTHREADS +#endif + +// +// No wide character support in the BSD header files: +// +#if defined(__NetBSD__) +#define __NetBSD_GCC__ (__GNUC__ * 1000000 \ + + __GNUC_MINOR__ * 1000 \ + + __GNUC_PATCHLEVEL__) +// XXX - the following is required until c++config.h +// defines _GLIBCXX_HAVE_SWPRINTF and friends +// or the preprocessor conditionals are removed +// from the cwchar header. +#define _GLIBCXX_HAVE_SWPRINTF 1 +#endif + +#if !((defined(__FreeBSD__) && (__FreeBSD__ >= 5)) \ + || (defined(__NetBSD_GCC__) && (__NetBSD_GCC__ >= 2095003)) || defined(__DragonFly__)) +# define BOOST_NO_CWCHAR +#endif +// +// The BSD has macros only, no functions: +// +#if !defined(__OpenBSD__) || defined(__DragonFly__) +# define BOOST_NO_CTYPE_FUNCTIONS +#endif + +// +// thread API's not auto detected: +// +#define BOOST_HAS_SCHED_YIELD +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#define BOOST_HAS_SIGACTION + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include + + + + + + diff --git a/third-party/boost/boost/config/platform/cloudabi.hpp b/third-party/boost/boost/config/platform/cloudabi.hpp new file mode 100644 index 000000000..bed7b6318 --- /dev/null +++ b/third-party/boost/boost/config/platform/cloudabi.hpp @@ -0,0 +1,18 @@ +// Copyright Nuxi, https://nuxi.nl/ 2015. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_PLATFORM "CloudABI" + +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_UNISTD_H + +#define BOOST_HAS_CLOCK_GETTIME +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_LOG1P +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_SCHED_YIELD diff --git a/third-party/boost/boost/config/platform/cray.hpp b/third-party/boost/boost/config/platform/cray.hpp new file mode 100644 index 000000000..103e9c062 --- /dev/null +++ b/third-party/boost/boost/config/platform/cray.hpp @@ -0,0 +1,18 @@ +// (C) Copyright John Maddock 2011. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +// See http://www.boost.org for most recent version. + +// SGI Irix specific config options: + +#define BOOST_PLATFORM "Cray" + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include + + + diff --git a/third-party/boost/boost/config/platform/cygwin.hpp b/third-party/boost/boost/config/platform/cygwin.hpp new file mode 100644 index 000000000..d0052d8b4 --- /dev/null +++ b/third-party/boost/boost/config/platform/cygwin.hpp @@ -0,0 +1,71 @@ +// (C) Copyright John Maddock 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// cygwin specific config options: + +#define BOOST_PLATFORM "Cygwin" +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_LOG1P +#define BOOST_HAS_EXPM1 + +// +// Threading API: +// See if we have POSIX threads, if we do use them, otherwise +// revert to native Win threads. +#define BOOST_HAS_UNISTD_H +#include +#if defined(_POSIX_THREADS) && (_POSIX_THREADS+0 >= 0) && !defined(BOOST_HAS_WINTHREADS) +# define BOOST_HAS_PTHREADS +# define BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +//# define BOOST_HAS_SIGACTION +#else +# if !defined(BOOST_HAS_WINTHREADS) +# define BOOST_HAS_WINTHREADS +# endif +# define BOOST_HAS_FTIME +#endif + +// +// find out if we have a stdint.h, there should be a better way to do this: +// +#include +#ifdef _STDINT_H +#define BOOST_HAS_STDINT_H +#endif +#if __GNUC__ > 5 && !defined(BOOST_HAS_STDINT_H) +# define BOOST_HAS_STDINT_H +#endif + +#include +#if (CYGWIN_VERSION_API_MAJOR == 0 && CYGWIN_VERSION_API_MINOR < 231) +/// Cygwin has no fenv.h +#define BOOST_NO_FENV_H +#endif + +// Cygwin has it's own which breaks unless the correct compiler flags are used: +#ifndef BOOST_NO_CXX14_HDR_SHARED_MUTEX +#include +#if !(__XSI_VISIBLE >= 500 || __POSIX_VISIBLE >= 200112) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#endif + +// boilerplate code: +#include + +// +// Cygwin lies about XSI conformance, there is no nl_types.h: +// +#ifdef BOOST_HAS_NL_TYPES_H +# undef BOOST_HAS_NL_TYPES_H +#endif + + + + diff --git a/third-party/boost/boost/config/platform/haiku.hpp b/third-party/boost/boost/config/platform/haiku.hpp new file mode 100644 index 000000000..04244c567 --- /dev/null +++ b/third-party/boost/boost/config/platform/haiku.hpp @@ -0,0 +1,31 @@ +// (C) Copyright Jessica Hamilton 2014. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Haiku specific config options: + +#define BOOST_PLATFORM "Haiku" + +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_STDINT_H + +#ifndef BOOST_DISABLE_THREADS +# define BOOST_HAS_THREADS +#endif + +#define BOOST_NO_CXX11_HDR_TYPE_TRAITS +#define BOOST_NO_CXX11_ATOMIC_SMART_PTR +#define BOOST_NO_CXX11_STATIC_ASSERT +#define BOOST_NO_CXX11_VARIADIC_MACROS + +// +// thread API's not auto detected: +// +#define BOOST_HAS_SCHED_YIELD +#define BOOST_HAS_GETTIMEOFDAY + +// boilerplate code: +#include diff --git a/third-party/boost/boost/config/platform/hpux.hpp b/third-party/boost/boost/config/platform/hpux.hpp new file mode 100644 index 000000000..222622e7e --- /dev/null +++ b/third-party/boost/boost/config/platform/hpux.hpp @@ -0,0 +1,87 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2003. +// (C) Copyright David Abrahams 2002. +// (C) Copyright Toon Knapen 2003. +// (C) Copyright Boris Gubenko 2006 - 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// hpux specific config options: + +#define BOOST_PLATFORM "HP-UX" + +// In principle, HP-UX has a nice under the name +// However, it has the following problem: +// Use of UINT32_C(0) results in "0u l" for the preprocessed source +// (verifyable with gcc 2.95.3) +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__HP_aCC) +# define BOOST_HAS_STDINT_H +#endif + +#if !(defined(__HP_aCC) || !defined(_INCLUDE__STDC_A1_SOURCE)) +# define BOOST_NO_SWPRINTF +#endif +#if defined(__HP_aCC) && !defined(_INCLUDE__STDC_A1_SOURCE) +# define BOOST_NO_CWCTYPE +#endif + +#if defined(__GNUC__) +# if (__GNUC__ < 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ < 3)) + // GNU C on HP-UX does not support threads (checked up to gcc 3.3) +# define BOOST_DISABLE_THREADS +# elif !defined(BOOST_DISABLE_THREADS) + // threads supported from gcc-3.3 onwards: +# define BOOST_HAS_THREADS +# define BOOST_HAS_PTHREADS +# endif +#elif defined(__HP_aCC) && !defined(BOOST_DISABLE_THREADS) +# define BOOST_HAS_PTHREADS +#endif + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include + +// the following are always available: +#ifndef BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_GETTIMEOFDAY +#endif +#ifndef BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_SCHED_YIELD +#endif +#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#endif +#ifndef BOOST_HAS_NL_TYPES_H +# define BOOST_HAS_NL_TYPES_H +#endif +#ifndef BOOST_HAS_NANOSLEEP +# define BOOST_HAS_NANOSLEEP +#endif +#ifndef BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_GETTIMEOFDAY +#endif +#ifndef BOOST_HAS_DIRENT_H +# define BOOST_HAS_DIRENT_H +#endif +#ifndef BOOST_HAS_CLOCK_GETTIME +# define BOOST_HAS_CLOCK_GETTIME +#endif +#ifndef BOOST_HAS_SIGACTION +# define BOOST_HAS_SIGACTION +#endif +#ifndef BOOST_HAS_NRVO +# ifndef __parisc +# define BOOST_HAS_NRVO +# endif +#endif +#ifndef BOOST_HAS_LOG1P +# define BOOST_HAS_LOG1P +#endif +#ifndef BOOST_HAS_EXPM1 +# define BOOST_HAS_EXPM1 +#endif + diff --git a/third-party/boost/boost/config/platform/irix.hpp b/third-party/boost/boost/config/platform/irix.hpp new file mode 100644 index 000000000..0acb65155 --- /dev/null +++ b/third-party/boost/boost/config/platform/irix.hpp @@ -0,0 +1,31 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +// See http://www.boost.org for most recent version. + +// SGI Irix specific config options: + +#define BOOST_PLATFORM "SGI Irix" + +#define BOOST_NO_SWPRINTF +// +// these are not auto detected by POSIX feature tests: +// +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE + +#ifdef __GNUC__ + // GNU C on IRIX does not support threads (checked up to gcc 3.3) +# define BOOST_DISABLE_THREADS +#endif + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include + + + diff --git a/third-party/boost/boost/config/platform/linux.hpp b/third-party/boost/boost/config/platform/linux.hpp new file mode 100644 index 000000000..c4eef8f80 --- /dev/null +++ b/third-party/boost/boost/config/platform/linux.hpp @@ -0,0 +1,106 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// linux specific config options: + +#define BOOST_PLATFORM "linux" + +// make sure we have __GLIBC_PREREQ if available at all +#ifdef __cplusplus +#include +#else +#include +#endif + +// +// added to glibc 2.1.1 +// We can only test for 2.1 though: +// +#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))) + // defines int64_t unconditionally, but defines + // int64_t only if __GNUC__. Thus, assume a fully usable + // only when using GCC. Update 2017: this appears not to be the case for + // recent glibc releases, see bug report: https://svn.boost.org/trac/boost/ticket/13045 +# if defined(__GNUC__) || ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 5))) +# define BOOST_HAS_STDINT_H +# endif +#endif + +#if defined(__LIBCOMO__) + // + // como on linux doesn't have std:: c functions: + // NOTE: versions of libcomo prior to beta28 have octal version numbering, + // e.g. version 25 is 21 (dec) + // +# if __LIBCOMO_VERSION__ <= 20 +# define BOOST_NO_STDC_NAMESPACE +# endif + +# if __LIBCOMO_VERSION__ <= 21 +# define BOOST_NO_SWPRINTF +# endif + +#endif + +// +// If glibc is past version 2 then we definitely have +// gettimeofday, earlier versions may or may not have it: +// +#if defined(__GLIBC__) && (__GLIBC__ >= 2) +# define BOOST_HAS_GETTIMEOFDAY +#endif + +#ifdef __USE_POSIX199309 +# define BOOST_HAS_NANOSLEEP +#endif + +#if defined(__GLIBC__) && defined(__GLIBC_PREREQ) +// __GLIBC_PREREQ is available since 2.1.2 + + // swprintf is available since glibc 2.2.0 +# if !__GLIBC_PREREQ(2,2) || (!defined(__USE_ISOC99) && !defined(__USE_UNIX98)) +# define BOOST_NO_SWPRINTF +# endif +#else +# define BOOST_NO_SWPRINTF +#endif + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include +#if defined(__USE_GNU) && !defined(__ANDROID__) && !defined(ANDROID) +#define BOOST_HAS_PTHREAD_YIELD +#endif + +#ifndef __GNUC__ +// +// if the compiler is not gcc we still need to be able to parse +// the GNU system headers, some of which (mainly ) +// use GNU specific extensions: +// +# ifndef __extension__ +# define __extension__ +# endif +# ifndef __const__ +# define __const__ const +# endif +# ifndef __volatile__ +# define __volatile__ volatile +# endif +# ifndef __signed__ +# define __signed__ signed +# endif +# ifndef __typeof__ +# define __typeof__ typeof +# endif +# ifndef __inline__ +# define __inline__ inline +# endif +#endif + + diff --git a/third-party/boost/boost/config/platform/macos.hpp b/third-party/boost/boost/config/platform/macos.hpp new file mode 100644 index 000000000..ed7dc15f2 --- /dev/null +++ b/third-party/boost/boost/config/platform/macos.hpp @@ -0,0 +1,87 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001 - 2002. +// (C) Copyright Bill Kempf 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Mac OS specific config options: + +#define BOOST_PLATFORM "Mac OS" + +#if __MACH__ && !defined(_MSL_USING_MSL_C) + +// Using the Mac OS X system BSD-style C library. + +# ifndef BOOST_HAS_UNISTD_H +# define BOOST_HAS_UNISTD_H +# endif +// +// Begin by including our boilerplate code for POSIX +// feature detection, this is safe even when using +// the MSL as Metrowerks supply their own +// to replace the platform-native BSD one. G++ users +// should also always be able to do this on MaxOS X. +// +# include +# ifndef BOOST_HAS_STDINT_H +# define BOOST_HAS_STDINT_H +# endif + +// +// BSD runtime has pthreads, sigaction, sched_yield and gettimeofday, +// of these only pthreads are advertised in , so set the +// other options explicitly: +// +# define BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_SIGACTION + +# if (__GNUC__ < 3) && !defined( __APPLE_CC__) + +// GCC strange "ignore std" mode works better if you pretend everything +// is in the std namespace, for the most part. + +# define BOOST_NO_STDC_NAMESPACE +# endif + +# if (__GNUC__ >= 4) + +// Both gcc and intel require these. +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_NANOSLEEP + +# endif + +#else + +// Using the MSL C library. + +// We will eventually support threads in non-Carbon builds, but we do +// not support this yet. +# if ( defined(TARGET_API_MAC_CARBON) && TARGET_API_MAC_CARBON ) || ( defined(TARGET_CARBON) && TARGET_CARBON ) + +# if !defined(BOOST_HAS_PTHREADS) +// MPTasks support is deprecated/removed from Boost: +//# define BOOST_HAS_MPTASKS +# elif ( __dest_os == __mac_os_x ) +// We are doing a Carbon/Mach-O/MSL build which has pthreads, but only the +// gettimeofday and no posix. +# define BOOST_HAS_GETTIMEOFDAY +# endif + +#ifdef BOOST_HAS_PTHREADS +# define BOOST_HAS_THREADS +#endif + +// The remote call manager depends on this. +# define BOOST_BIND_ENABLE_PASCAL + +# endif + +#endif + + + diff --git a/third-party/boost/boost/config/platform/qnxnto.hpp b/third-party/boost/boost/config/platform/qnxnto.hpp new file mode 100644 index 000000000..d0298cb4e --- /dev/null +++ b/third-party/boost/boost/config/platform/qnxnto.hpp @@ -0,0 +1,31 @@ +// (C) Copyright Jim Douglas 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// QNX specific config options: + +#define BOOST_PLATFORM "QNX" + +#define BOOST_HAS_UNISTD_H +#include + +// QNX claims XOpen version 5 compatibility, but doesn't have an nl_types.h +// or log1p and expm1: +#undef BOOST_HAS_NL_TYPES_H +#undef BOOST_HAS_LOG1P +#undef BOOST_HAS_EXPM1 + +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE + +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_CLOCK_GETTIME +#define BOOST_HAS_NANOSLEEP + + + + + diff --git a/third-party/boost/boost/config/platform/solaris.hpp b/third-party/boost/boost/config/platform/solaris.hpp new file mode 100644 index 000000000..51ffe67f3 --- /dev/null +++ b/third-party/boost/boost/config/platform/solaris.hpp @@ -0,0 +1,31 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// sun specific config options: + +#define BOOST_PLATFORM "Sun Solaris" + +#define BOOST_HAS_GETTIMEOFDAY + +// boilerplate code: +#define BOOST_HAS_UNISTD_H +#include + +// +// pthreads don't actually work with gcc unless _PTHREADS is defined: +// +#if defined(__GNUC__) && defined(_POSIX_THREADS) && !defined(_PTHREADS) +# undef BOOST_HAS_PTHREADS +#endif + +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#define BOOST_HAS_LOG1P +#define BOOST_HAS_EXPM1 + + diff --git a/third-party/boost/boost/config/platform/symbian.hpp b/third-party/boost/boost/config/platform/symbian.hpp new file mode 100644 index 000000000..f814d00b5 --- /dev/null +++ b/third-party/boost/boost/config/platform/symbian.hpp @@ -0,0 +1,97 @@ +// (C) Copyright Yuriy Krasnoschek 2009. +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// symbian specific config options: + + +#define BOOST_PLATFORM "Symbian" +#define BOOST_SYMBIAN 1 + + +#if defined(__S60_3X__) +// Open C / C++ plugin was introdused in this SDK, earlier versions don't have CRT / STL +# define BOOST_S60_3rd_EDITION_FP2_OR_LATER_SDK +// make sure we have __GLIBC_PREREQ if available at all +#ifdef __cplusplus +#include +#else +#include +#endif// boilerplate code: +# define BOOST_HAS_UNISTD_H +# include +// S60 SDK defines _POSIX_VERSION as POSIX.1 +# ifndef BOOST_HAS_STDINT_H +# define BOOST_HAS_STDINT_H +# endif +# ifndef BOOST_HAS_GETTIMEOFDAY +# define BOOST_HAS_GETTIMEOFDAY +# endif +# ifndef BOOST_HAS_DIRENT_H +# define BOOST_HAS_DIRENT_H +# endif +# ifndef BOOST_HAS_SIGACTION +# define BOOST_HAS_SIGACTION +# endif +# ifndef BOOST_HAS_PTHREADS +# define BOOST_HAS_PTHREADS +# endif +# ifndef BOOST_HAS_NANOSLEEP +# define BOOST_HAS_NANOSLEEP +# endif +# ifndef BOOST_HAS_SCHED_YIELD +# define BOOST_HAS_SCHED_YIELD +# endif +# ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# endif +# ifndef BOOST_HAS_LOG1P +# define BOOST_HAS_LOG1P +# endif +# ifndef BOOST_HAS_EXPM1 +# define BOOST_HAS_EXPM1 +# endif +# ifndef BOOST_POSIX_API +# define BOOST_POSIX_API +# endif +// endianess support +# include +// Symbian SDK provides _BYTE_ORDER instead of __BYTE_ORDER +# ifndef __LITTLE_ENDIAN +# ifdef _LITTLE_ENDIAN +# define __LITTLE_ENDIAN _LITTLE_ENDIAN +# else +# define __LITTLE_ENDIAN 1234 +# endif +# endif +# ifndef __BIG_ENDIAN +# ifdef _BIG_ENDIAN +# define __BIG_ENDIAN _BIG_ENDIAN +# else +# define __BIG_ENDIAN 4321 +# endif +# endif +# ifndef __BYTE_ORDER +# define __BYTE_ORDER __LITTLE_ENDIAN // Symbian is LE +# endif +// Known limitations +# define BOOST_ASIO_DISABLE_SERIAL_PORT +# define BOOST_DATE_TIME_NO_LOCALE +# define BOOST_NO_STD_WSTRING +# define BOOST_EXCEPTION_DISABLE +# define BOOST_NO_EXCEPTIONS + +#else // TODO: More platform support e.g. UIQ +# error "Unsuppoted Symbian SDK" +#endif + +#if defined(__WINSCW__) && !defined(BOOST_DISABLE_WIN32) +# define BOOST_DISABLE_WIN32 // winscw defines WIN32 macro +#endif + + diff --git a/third-party/boost/boost/config/platform/vms.hpp b/third-party/boost/boost/config/platform/vms.hpp new file mode 100644 index 000000000..f70efcfb8 --- /dev/null +++ b/third-party/boost/boost/config/platform/vms.hpp @@ -0,0 +1,25 @@ +// (C) Copyright Artyom Beilis 2010. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_CONFIG_PLATFORM_VMS_HPP +#define BOOST_CONFIG_PLATFORM_VMS_HPP + +#define BOOST_PLATFORM "OpenVMS" + +#undef BOOST_HAS_STDINT_H +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_NL_TYPES_H +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_CLOCK_GETTIME +#define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +#define BOOST_HAS_LOG1P +#define BOOST_HAS_EXPM1 +#define BOOST_HAS_THREADS +#undef BOOST_HAS_SCHED_YIELD + +#endif diff --git a/third-party/boost/boost/config/platform/vxworks.hpp b/third-party/boost/boost/config/platform/vxworks.hpp new file mode 100644 index 000000000..a91e4ab43 --- /dev/null +++ b/third-party/boost/boost/config/platform/vxworks.hpp @@ -0,0 +1,433 @@ +// (C) Copyright Dustin Spicuzza 2009. +// Adapted to vxWorks 6.9 by Peter Brockamp 2012. +// Updated for VxWorks 7 by Brian Kuhl 2016 +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Old versions of vxWorks (namely everything below 6.x) are +// absolutely unable to use boost. Old STLs and compilers +// like (GCC 2.96) . Do not even think of getting this to work, +// a miserable failure will be guaranteed! +// +// Equally, this file has been tested for RTPs (Real Time Processes) +// only, not for DKMs (Downloadable Kernel Modules). These two types +// of executables differ largely in the available functionality of +// the C-library, STL, and so on. A DKM uses a C89 library with no +// wide character support and no guarantee of ANSI C. The same Dinkum +// STL library is used in both contexts. +// +// Similarly the Dinkum abridged STL that supports the loosely specified +// embedded C++ standard has not been tested and is unlikely to work +// on anything but the simplest library. +// ==================================================================== +// +// Additional Configuration +// ------------------------------------------------------------------- +// +// Because of the ordering of include files and other issues the following +// additional definitions worked better outside this file. +// +// When building the log library add the following to the b2 invocation +// define=BOOST_LOG_WITHOUT_IPC +// and +// -DBOOST_LOG_WITHOUT_DEFAULT_FACTORIES +// to your compile options. +// +// When building the test library add +// -DBOOST_TEST_LIMITED_SIGNAL_DETAILS +// to your compile options +// +// When building containers library add +// -DHAVE_MORECORE=0 +// to your c compile options so dlmalloc heap library is compiled +// without brk() calls +// +// ==================================================================== +// +// Some important information regarding the usage of POSIX semaphores: +// ------------------------------------------------------------------- +// +// VxWorks as a real time operating system handles threads somewhat +// different from what "normal" OSes do, regarding their scheduling! +// This could lead to a scenario called "priority inversion" when using +// semaphores, see http://en.wikipedia.org/wiki/Priority_inversion. +// +// Now, VxWorks POSIX-semaphores for DKM's default to the usage of +// priority inverting semaphores, which is fine. On the other hand, +// for RTP's it defaults to using non priority inverting semaphores, +// which could easily pose a serious problem for a real time process. +// +// To change the default properties for POSIX-semaphores in VxWorks 7 +// enable core > CORE_USER Menu > DEFAULT_PTHREAD_PRIO_INHERIT +// +// In VxWorks 6.x so as to integrate with boost. +// - Edit the file +// installDir/vxworks-6.x/target/usr/src/posix/pthreadLib.c +// - Around line 917 there should be the definition of the default +// mutex attributes: +// +// LOCAL pthread_mutexattr_t defaultMutexAttr = +// { +// PTHREAD_INITIALIZED_OBJ, PTHREAD_PRIO_NONE, 0, +// PTHREAD_MUTEX_DEFAULT +// }; +// +// Here, replace PTHREAD_PRIO_NONE by PTHREAD_PRIO_INHERIT. +// - Around line 1236 there should be a definition for the function +// pthread_mutexattr_init(). A couple of lines below you should +// find a block of code like this: +// +// pAttr->mutexAttrStatus = PTHREAD_INITIALIZED_OBJ; +// pAttr->mutexAttrProtocol = PTHREAD_PRIO_NONE; +// pAttr->mutexAttrPrioceiling = 0; +// pAttr->mutexAttrType = PTHREAD_MUTEX_DEFAULT; +// +// Here again, replace PTHREAD_PRIO_NONE by PTHREAD_PRIO_INHERIT. +// - Finally, rebuild your VSB. This will rebuild the libraries +// with the changed properties. That's it! Now, using boost should +// no longer cause any problems with task deadlocks! +// +// ==================================================================== + +// Block out all versions before vxWorks 6.x, as these don't work: +// Include header with the vxWorks version information and query them +#include +#if !defined(_WRS_VXWORKS_MAJOR) || (_WRS_VXWORKS_MAJOR < 6) +# error "The vxWorks version you're using is so badly outdated,\ + it doesn't work at all with boost, sorry, no chance!" +#endif + +// Handle versions above 5.X but below 6.9 +#if (_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR < 9) +// TODO: Starting from what version does vxWorks work with boost? +// We can't reasonably insert a #warning "" as a user hint here, +// as this will show up with every file including some boost header, +// badly bugging the user... So for the time being we just leave it. +#endif + +// vxWorks specific config options: +// -------------------------------- +#define BOOST_PLATFORM "vxWorks" + +// Special behaviour for DKMs: +#ifdef _WRS_KERNEL + // DKMs do not have the -header, + // but apparently they do have an intrinsic wchar_t meanwhile! +# define BOOST_NO_CWCHAR + + // Lots of wide-functions and -headers are unavailable for DKMs as well: +# define BOOST_NO_CWCTYPE +# define BOOST_NO_SWPRINTF +# define BOOST_NO_STD_WSTRING +# define BOOST_NO_STD_WSTREAMBUF +#endif + +// Generally available headers: +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_STDINT_H +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_SLIST + +// vxWorks does not have installed an iconv-library by default, +// so unfortunately no Unicode support from scratch is available! +// Thus, instead it is suggested to switch to ICU, as this seems +// to be the most complete and portable option... +#define BOOST_LOCALE_WITH_ICU + +// Generally available functionality: +#define BOOST_HAS_THREADS +#define BOOST_HAS_NANOSLEEP +#define BOOST_HAS_GETTIMEOFDAY +#define BOOST_HAS_CLOCK_GETTIME +#define BOOST_HAS_MACRO_USE_FACET + +// Generally available threading API's: +#define BOOST_HAS_PTHREADS +#define BOOST_HAS_SCHED_YIELD +#define BOOST_HAS_SIGACTION + +// Functionality available for RTPs only: +#ifdef __RTP__ +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_LOG1P +# define BOOST_HAS_EXPM1 +#endif + +// Functionality available for DKMs only: +#ifdef _WRS_KERNEL + // Luckily, at the moment there seems to be none! +#endif + +// These #defines allow detail/posix_features to work, since vxWorks doesn't +// #define them itself for DKMs (for RTPs on the contrary it does): +#ifdef _WRS_KERNEL +# ifndef _POSIX_TIMERS +# define _POSIX_TIMERS 1 +# endif +# ifndef _POSIX_THREADS +# define _POSIX_THREADS 1 +# endif +#endif + +#if (_WRS_VXWORKS_MAJOR < 7) +// vxWorks-around: #defines CLOCKS_PER_SEC as sysClkRateGet() but +// miserably fails to #include the required to make +// sysClkRateGet() available! So we manually include it here. +#ifdef __RTP__ +# include +# include +#endif + +// vxWorks-around: In the macros INT32_C(), UINT32_C(), INT64_C() and +// UINT64_C() are defined erroneously, yielding not a signed/ +// unsigned long/long long type, but a signed/unsigned int/long +// type. Eventually this leads to compile errors in ratio_fwd.hpp, +// when trying to define several constants which do not fit into a +// long type! We correct them here by redefining. + +#include + +// Some macro-magic to do the job +#define VX_JOIN(X, Y) VX_DO_JOIN(X, Y) +#define VX_DO_JOIN(X, Y) VX_DO_JOIN2(X, Y) +#define VX_DO_JOIN2(X, Y) X##Y + +// Correctly setup the macros +#undef INT32_C +#undef UINT32_C +#undef INT64_C +#undef UINT64_C +#define INT32_C(x) VX_JOIN(x, L) +#define UINT32_C(x) VX_JOIN(x, UL) +#define INT64_C(x) VX_JOIN(x, LL) +#define UINT64_C(x) VX_JOIN(x, ULL) + +// #include Libraries required for the following function adaption +#include +#endif // _WRS_VXWORKS_MAJOR < 7 + +#include +#include + +// Use C-linkage for the following helper functions +#ifdef __cplusplus +extern "C" { +#endif + +// vxWorks-around: The required functions getrlimit() and getrlimit() are missing. +// But we have the similar functions getprlimit() and setprlimit(), +// which may serve the purpose. +// Problem: The vxWorks-documentation regarding these functions +// doesn't deserve its name! It isn't documented what the first two +// parameters idtype and id mean, so we must fall back to an educated +// guess - null, argh... :-/ + +// TODO: getprlimit() and setprlimit() do exist for RTPs only, for whatever reason. +// Thus for DKMs there would have to be another implementation. +#if defined ( __RTP__) && (_WRS_VXWORKS_MAJOR < 7) + inline int getrlimit(int resource, struct rlimit *rlp){ + return getprlimit(0, 0, resource, rlp); + } + + inline int setrlimit(int resource, const struct rlimit *rlp){ + return setprlimit(0, 0, resource, const_cast(rlp)); + } +#endif + +// vxWorks has ftruncate() only, so we do simulate truncate(): +inline int truncate(const char *p, off_t l){ + int fd = open(p, O_WRONLY); + if (fd == -1){ + errno = EACCES; + return -1; + } + if (ftruncate(fd, l) == -1){ + close(fd); + errno = EACCES; + return -1; + } + return close(fd); +} + +#ifdef __GNUC__ +#define ___unused __attribute__((unused)) +#else +#define ___unused +#endif + +// Fake symlink handling by dummy functions: +inline int symlink(const char* path1 ___unused, const char* path2 ___unused){ + // vxWorks has no symlinks -> always return an error! + errno = EACCES; + return -1; +} + +inline ssize_t readlink(const char* path1 ___unused, char* path2 ___unused, size_t size ___unused){ + // vxWorks has no symlinks -> always return an error! + errno = EACCES; + return -1; +} + +#if (_WRS_VXWORKS_MAJOR < 7) + +inline int gettimeofday(struct timeval *tv, void * /*tzv*/) { + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + return 0; +} +#endif + +#ifdef __cplusplus +} // extern "C" +#endif + +/* + * moved to os/utils/unix/freind_h/times.h in VxWorks 7 + * to avoid conflict with MPL operator times + */ +#if (_WRS_VXWORKS_MAJOR < 7) +#ifdef __cplusplus + +// vxWorks provides neither struct tms nor function times()! +// We implement an empty dummy-function, simply setting the user +// and system time to the half of thew actual system ticks-value +// and the child user and system time to 0. +// Rather ugly but at least it suppresses compiler errors... +// Unfortunately, this of course *does* have an severe impact on +// dependant libraries, actually this is chrono only! Here it will +// not be possible to correctly use user and system times! But +// as vxWorks is lacking the ability to calculate user and system +// process times there seems to be no other possible solution. +struct tms{ + clock_t tms_utime; // User CPU time + clock_t tms_stime; // System CPU time + clock_t tms_cutime; // User CPU time of terminated child processes + clock_t tms_cstime; // System CPU time of terminated child processes +}; + + + inline clock_t times(struct tms *t){ + struct timespec ts; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); + clock_t ticks(static_cast(static_cast(ts.tv_sec) * CLOCKS_PER_SEC + + static_cast(ts.tv_nsec) * CLOCKS_PER_SEC / 1000000.0)); + t->tms_utime = ticks/2U; + t->tms_stime = ticks/2U; + t->tms_cutime = 0; // vxWorks is lacking the concept of a child process! + t->tms_cstime = 0; // -> Set the wait times for childs to 0 + return ticks; +} + + +namespace std { + using ::times; +} +#endif // __cplusplus +#endif // _WRS_VXWORKS_MAJOR < 7 + + +#ifdef __cplusplus +extern "C" void bzero (void *, size_t); // FD_ZERO uses bzero() but doesn't include strings.h + +// Put the selfmade functions into the std-namespace, just in case +namespace std { +# ifdef __RTP__ + using ::getrlimit; + using ::setrlimit; +# endif + using ::truncate; + using ::symlink; + using ::readlink; +#if (_WRS_VXWORKS_MAJOR < 7) + using ::gettimeofday; +#endif +} +#endif // __cplusplus + +// Some more macro-magic: +// vxWorks-around: Some functions are not present or broken in vxWorks +// but may be patched to life via helper macros... + +// Include signal.h which might contain a typo to be corrected here +#include +#if (_WRS_VXWORKS_MAJOR < 7) +#define getpagesize() sysconf(_SC_PAGESIZE) // getpagesize is deprecated anyway! +inline int lstat(p, b) { return stat(p, b); } // lstat() == stat(), as vxWorks has no symlinks! +#endif +#ifndef S_ISSOCK +# define S_ISSOCK(mode) ((mode & S_IFMT) == S_IFSOCK) // Is file a socket? +#endif +#ifndef FPE_FLTINV +# define FPE_FLTINV (FPE_FLTSUB+1) // vxWorks has no FPE_FLTINV, so define one as a dummy +#endif +#if !defined(BUS_ADRALN) && defined(BUS_ADRALNR) +# define BUS_ADRALN BUS_ADRALNR // Correct a supposed typo in vxWorks' +#endif +typedef int locale_t; // locale_t is a POSIX-extension, currently not present in vxWorks! + +// #include boilerplate code: +#include + +// vxWorks lies about XSI conformance, there is no nl_types.h: +#undef BOOST_HAS_NL_TYPES_H + +// vxWorks 7 adds C++11 support +// however it is optional, and does not match exactly the support determined +// by examining the Dinkum STL version and GCC version (or ICC and DCC) +#ifndef _WRS_CONFIG_LANG_LIB_CPLUS_CPLUS_USER_2011 +# define BOOST_NO_CXX11_ADDRESSOF // C11 addressof operator on memory location +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_NUMERIC_LIMITS // max_digits10 in test/../print_helper.hpp +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_STD_ALIGN + + +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST //serialization/test/test_list.cpp +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM //math/../test_data.hpp +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +#else +#ifndef BOOST_SYSTEM_NO_DEPRECATED +# define BOOST_SYSTEM_NO_DEPRECATED // workaround link error in spirit +#endif +#endif + + +// NONE is used in enums in lamda and other libraries +#undef NONE +// restrict is an iostreams class +#undef restrict + +// use fake poll() from Unix layer in ASIO to get full functionality +// most libraries will use select() but this define allows 'iostream' functionality +// which is based on poll() only +#if (_WRS_VXWORKS_MAJOR > 6) +# ifndef BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR +# define BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR +# endif +#else +# define BOOST_ASIO_DISABLE_SERIAL_PORT +#endif + + diff --git a/third-party/boost/boost/config/platform/win32.hpp b/third-party/boost/boost/config/platform/win32.hpp new file mode 100644 index 000000000..450158fba --- /dev/null +++ b/third-party/boost/boost/config/platform/win32.hpp @@ -0,0 +1,90 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Bill Kempf 2001. +// (C) Copyright Aleksey Gurtovoy 2003. +// (C) Copyright Rene Rivera 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Win32 specific config options: + +#define BOOST_PLATFORM "Win32" + +// Get the information about the MinGW runtime, i.e. __MINGW32_*VERSION. +#if defined(__MINGW32__) +# include <_mingw.h> +#endif + +#if defined(__GNUC__) && !defined(BOOST_NO_SWPRINTF) +# define BOOST_NO_SWPRINTF +#endif + +// Default defines for BOOST_SYMBOL_EXPORT and BOOST_SYMBOL_IMPORT +// If a compiler doesn't support __declspec(dllexport)/__declspec(dllimport), +// its boost/config/compiler/ file must define BOOST_SYMBOL_EXPORT and +// BOOST_SYMBOL_IMPORT +#ifndef BOOST_SYMBOL_EXPORT +# define BOOST_HAS_DECLSPEC +# define BOOST_SYMBOL_EXPORT __declspec(dllexport) +# define BOOST_SYMBOL_IMPORT __declspec(dllimport) +#endif + +#if defined(__MINGW32__) && ((__MINGW32_MAJOR_VERSION > 2) || ((__MINGW32_MAJOR_VERSION == 2) && (__MINGW32_MINOR_VERSION >= 0))) +# define BOOST_HAS_STDINT_H +# ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +# endif +# define BOOST_HAS_DIRENT_H +# define BOOST_HAS_UNISTD_H +#endif + +#if defined(__MINGW32__) && (__GNUC__ >= 4) +// Mingw has these functions but there are persistent problems +// with calls to these crashing, so disable for now: +//# define BOOST_HAS_EXPM1 +//# define BOOST_HAS_LOG1P +# define BOOST_HAS_GETTIMEOFDAY +#endif +// +// Win32 will normally be using native Win32 threads, +// but there is a pthread library avaliable as an option, +// we used to disable this when BOOST_DISABLE_WIN32 was +// defined but no longer - this should allow some +// files to be compiled in strict mode - while maintaining +// a consistent setting of BOOST_HAS_THREADS across +// all translation units (needed for shared_ptr etc). +// + +#ifndef BOOST_HAS_PTHREADS +# define BOOST_HAS_WINTHREADS +#endif + +// +// WinCE configuration: +// +#if defined(_WIN32_WCE) || defined(UNDER_CE) +# define BOOST_NO_ANSI_APIS +// Windows CE does not have a conforming signature for swprintf +# define BOOST_NO_SWPRINTF +#else +# define BOOST_HAS_GETSYSTEMTIMEASFILETIME +# define BOOST_HAS_THREADEX +# define BOOST_HAS_GETSYSTEMTIMEASFILETIME +#endif + +// +// Windows Runtime +// +#if defined(WINAPI_FAMILY) && \ + (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) +# define BOOST_NO_ANSI_APIS +#endif + +#ifndef BOOST_DISABLE_WIN32 +// WEK: Added +#define BOOST_HAS_FTIME +#define BOOST_WINDOWS 1 + +#endif diff --git a/third-party/boost/boost/config/platform/zos.hpp b/third-party/boost/boost/config/platform/zos.hpp new file mode 100644 index 000000000..fa77999ed --- /dev/null +++ b/third-party/boost/boost/config/platform/zos.hpp @@ -0,0 +1,32 @@ +// Copyright (c) 2017 Dynatrace +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org for most recent version. + +// Platform setup for IBM z/OS. + +#define BOOST_PLATFORM "IBM z/OS" + +#include // For __UU, __C99, __TR1, ... + +#if defined(__UU) +# define BOOST_HAS_GETTIMEOFDAY +#endif + +#if defined(_OPEN_THREADS) || defined(__SUSV3_THR) +# define BOOST_HAS_PTHREADS +# define BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE +# define BOOST_HAS_THREADS +#endif + +#if defined(__SUSV3) || defined(__SUSV3_THR) +# define BOOST_HAS_SCHED_YIELD +#endif + +#define BOOST_HAS_SIGACTION +#define BOOST_HAS_UNISTD_H +#define BOOST_HAS_DIRENT_H +#define BOOST_HAS_NL_TYPES_H diff --git a/third-party/boost/boost/config/pragma_message.hpp b/third-party/boost/boost/config/pragma_message.hpp new file mode 100644 index 000000000..b2c5ff2e8 --- /dev/null +++ b/third-party/boost/boost/config/pragma_message.hpp @@ -0,0 +1,31 @@ +#ifndef BOOST_CONFIG_PRAGMA_MESSAGE_HPP_INCLUDED +#define BOOST_CONFIG_PRAGMA_MESSAGE_HPP_INCLUDED + +// Copyright 2017 Peter Dimov. +// +// Distributed under the Boost Software License, Version 1.0. +// +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt +// +// BOOST_PRAGMA_MESSAGE("message") +// +// Expands to the equivalent of #pragma message("message") +// +// Note that this header is C compatible. + +#include + +#if defined(BOOST_DISABLE_PRAGMA_MESSAGE) +# define BOOST_PRAGMA_MESSAGE(x) +#elif defined(__INTEL_COMPILER) +# define BOOST_PRAGMA_MESSAGE(x) __pragma(message(__FILE__ "(" BOOST_STRINGIZE(__LINE__) "): note: " x)) +#elif defined(__GNUC__) +# define BOOST_PRAGMA_MESSAGE(x) _Pragma(BOOST_STRINGIZE(message(x))) +#elif defined(_MSC_VER) +# define BOOST_PRAGMA_MESSAGE(x) __pragma(message(__FILE__ "(" BOOST_STRINGIZE(__LINE__) "): note: " x)) +#else +# define BOOST_PRAGMA_MESSAGE(x) +#endif + +#endif // BOOST_CONFIG_PRAGMA_MESSAGE_HPP_INCLUDED diff --git a/third-party/boost/boost/config/requires_threads.hpp b/third-party/boost/boost/config/requires_threads.hpp new file mode 100644 index 000000000..cfaff2302 --- /dev/null +++ b/third-party/boost/boost/config/requires_threads.hpp @@ -0,0 +1,92 @@ +// (C) Copyright John Maddock 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_CONFIG_REQUIRES_THREADS_HPP +#define BOOST_CONFIG_REQUIRES_THREADS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_DISABLE_THREADS) + +// +// special case to handle versions of gcc which don't currently support threads: +// +#if defined(__GNUC__) && ((__GNUC__ < 3) || (__GNUC_MINOR__ <= 3) || !defined(BOOST_STRICT_CONFIG)) +// +// this is checked up to gcc 3.3: +// +#if defined(__sgi) || defined(__hpux) +# error "Multi-threaded programs are not supported by gcc on HPUX or Irix (last checked with gcc 3.3)" +#endif + +#endif + +# error "Threading support unavaliable: it has been explicitly disabled with BOOST_DISABLE_THREADS" + +#elif !defined(BOOST_HAS_THREADS) + +# if defined __COMO__ +// Comeau C++ +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -D_MT (Windows) or -D_REENTRANT (Unix)" + +#elif defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC) +// Intel +#ifdef _WIN32 +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: either /MT /MTd /MD or /MDd" +#else +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -openmp" +#endif + +# elif defined __GNUC__ +// GNU C++: +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)" + +#elif defined __sgi +// SGI MIPSpro C++ +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -D_SGI_MP_SOURCE" + +#elif defined __DECCXX +// Compaq Tru64 Unix cxx +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -pthread" + +#elif defined __BORLANDC__ +// Borland +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -tWM" + +#elif defined __MWERKS__ +// Metrowerks CodeWarrior +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: either -runtime sm, -runtime smd, -runtime dm, or -runtime dmd" + +#elif defined __SUNPRO_CC +// Sun Workshop Compiler C++ +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -mt" + +#elif defined __HP_aCC +// HP aCC +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: -mt" + +#elif defined(__IBMCPP__) +// IBM Visual Age +# error "Compiler threading support is not turned on. Please compile the code with the xlC_r compiler" + +#elif defined _MSC_VER +// Microsoft Visual C++ +// +// Must remain the last #elif since some other vendors (Metrowerks, for +// example) also #define _MSC_VER +# error "Compiler threading support is not turned on. Please set the correct command line options for threading: either /MT /MTd /MD or /MDd" + +#else + +# error "Compiler threading support is not turned on. Please consult your compiler's documentation for the appropriate options to use" + +#endif // compilers + +#endif // BOOST_HAS_THREADS + +#endif // BOOST_CONFIG_REQUIRES_THREADS_HPP diff --git a/third-party/boost/boost/config/stdlib/dinkumware.hpp b/third-party/boost/boost/config/stdlib/dinkumware.hpp new file mode 100644 index 000000000..e829f08e5 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/dinkumware.hpp @@ -0,0 +1,258 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright Peter Dimov 2001. +// (C) Copyright David Abrahams 2002. +// (C) Copyright Guillaume Melquiond 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Dinkumware standard library config: + +#if !defined(_YVALS) && !defined(_CPPLIB_VER) +#include +#if !defined(_YVALS) && !defined(_CPPLIB_VER) +#error This is not the Dinkumware lib! +#endif +#endif + + +#if defined(_CPPLIB_VER) && (_CPPLIB_VER >= 306) + // full dinkumware 3.06 and above + // fully conforming provided the compiler supports it: +# if !(defined(_GLOBAL_USING) && (_GLOBAL_USING+0 > 0)) && !defined(__BORLANDC__) && !defined(_STD) && !(defined(__ICC) && (__ICC >= 700)) // can be defined in yvals.h +# define BOOST_NO_STDC_NAMESPACE +# endif +# if !(defined(_HAS_MEMBER_TEMPLATES_REBIND) && (_HAS_MEMBER_TEMPLATES_REBIND+0 > 0)) && !(defined(_MSC_VER) && (_MSC_VER > 1300)) && defined(BOOST_MSVC) +# define BOOST_NO_STD_ALLOCATOR +# endif +# define BOOST_HAS_PARTIAL_STD_ALLOCATOR +# if defined(BOOST_MSVC) && (BOOST_MSVC < 1300) + // if this lib version is set up for vc6 then there is no std::use_facet: +# define BOOST_NO_STD_USE_FACET +# define BOOST_HAS_TWO_ARG_USE_FACET + // C lib functions aren't in namespace std either: +# define BOOST_NO_STDC_NAMESPACE + // and nor is +# define BOOST_NO_EXCEPTION_STD_NAMESPACE +# endif +// There's no numeric_limits support unless _LONGLONG is defined: +# if !defined(_LONGLONG) && (_CPPLIB_VER <= 310) +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +# endif +// 3.06 appears to have (non-sgi versions of) & , +// and no at all +#else +# define BOOST_MSVC_STD_ITERATOR 1 +# define BOOST_NO_STD_ITERATOR +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +# define BOOST_NO_STD_ALLOCATOR +# define BOOST_NO_STDC_NAMESPACE +# define BOOST_NO_STD_USE_FACET +# define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN +# define BOOST_HAS_MACRO_USE_FACET +# ifndef _CPPLIB_VER + // Updated Dinkum library defines this, and provides + // its own min and max definitions, as does MTA version. +# ifndef __MTA__ +# define BOOST_NO_STD_MIN_MAX +# endif +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +# endif +#endif + +// +// std extension namespace is stdext for vc7.1 and later, +// the same applies to other compilers that sit on top +// of vc7.1 (Intel and Comeau): +// +#if defined(_MSC_VER) && (_MSC_VER >= 1310) && !defined(__BORLANDC__) +# define BOOST_STD_EXTENSION_NAMESPACE stdext +#endif + + +#if (defined(_MSC_VER) && (_MSC_VER <= 1300) && !defined(__BORLANDC__)) || !defined(_CPPLIB_VER) || (_CPPLIB_VER < 306) + // if we're using a dinkum lib that's + // been configured for VC6/7 then there is + // no iterator traits (true even for icl) +# define BOOST_NO_STD_ITERATOR_TRAITS +#endif + +#if defined(__ICL) && (__ICL < 800) && defined(_CPPLIB_VER) && (_CPPLIB_VER <= 310) +// Intel C++ chokes over any non-trivial use of +// this may be an overly restrictive define, but regex fails without it: +# define BOOST_NO_STD_LOCALE +#endif + +// Fix for VC++ 8.0 on up ( I do not have a previous version to test ) +// or clang-cl. If exceptions are off you must manually include the +// header before including the header. Admittedly +// trying to use Boost libraries or the standard C++ libraries without +// exception support is not suggested but currently clang-cl ( v 3.4 ) +// does not support exceptions and must be compiled with exceptions off. +#if !_HAS_EXCEPTIONS && ((defined(BOOST_MSVC) && BOOST_MSVC >= 1400) || (defined(__clang__) && defined(_MSC_VER))) +#include +#endif +#include +#if ( (!_HAS_EXCEPTIONS && !defined(__ghs__)) || (defined(__ghs__) && !_HAS_NAMESPACE) ) && !defined(__TI_COMPILER_VERSION__) && !defined(__VISUALDSPVERSION__) \ + && !defined(__VXWORKS__) +# define BOOST_NO_STD_TYPEINFO +#endif + +// C++0x headers implemented in 520 (as shipped by Microsoft) +// +#if !defined(_CPPLIB_VER) || _CPPLIB_VER < 520 +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_SMART_PTR +#endif + +#if ((!defined(_HAS_TR1_IMPORTS) || (_HAS_TR1_IMPORTS+0 == 0)) && !defined(BOOST_NO_CXX11_HDR_TUPLE)) \ + && (!defined(_CPPLIB_VER) || _CPPLIB_VER < 610) +# define BOOST_NO_CXX11_HDR_TUPLE +#endif + +// C++0x headers implemented in 540 (as shipped by Microsoft) +// +#if !defined(_CPPLIB_VER) || _CPPLIB_VER < 540 +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +#endif + +// C++0x headers implemented in 610 (as shipped by Microsoft) +// +#if !defined(_CPPLIB_VER) || _CPPLIB_VER < 610 +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_ALLOCATOR +// 540 has std::align but it is not a conforming implementation +# define BOOST_NO_CXX11_STD_ALIGN +#endif + +// Before 650 std::pointer_traits has a broken rebind template +#if !defined(_CPPLIB_VER) || _CPPLIB_VER < 650 +# define BOOST_NO_CXX11_POINTER_TRAITS +#elif defined(BOOST_MSVC) && BOOST_MSVC < 1910 +# define BOOST_NO_CXX11_POINTER_TRAITS +#endif + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif (__cplusplus < 201402) && !defined(_MSC_VER) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#elif !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +#if !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) +# define BOOST_NO_CXX14_STD_EXCHANGE +#endif + +// C++17 features +#if !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) || !defined(BOOST_MSVC) || (BOOST_MSVC < 1910) || !defined(_HAS_CXX17) || (_HAS_CXX17 == 0) +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_ITERATOR_TRAITS +#endif +#if !defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) || !defined(_HAS_CXX17) || (_HAS_CXX17 == 0) || !defined(_MSVC_STL_UPDATE) || (_MSVC_STL_UPDATE < 201709) +# define BOOST_NO_CXX17_STD_INVOKE +#endif + +#if !(!defined(_CPPLIB_VER) || (_CPPLIB_VER < 650) || !defined(BOOST_MSVC) || (BOOST_MSVC < 1912) || !defined(_HAS_CXX17) || (_HAS_CXX17 == 0)) +// Deprecated std::iterator: +# define BOOST_NO_STD_ITERATOR +#endif + +#if defined(BOOST_INTEL) && (BOOST_INTEL <= 1400) +// Intel's compiler can't handle this header yet: +# define BOOST_NO_CXX11_HDR_ATOMIC +#endif + + +// 520..610 have std::addressof, but it doesn't support functions +// +#if !defined(_CPPLIB_VER) || _CPPLIB_VER < 650 +# define BOOST_NO_CXX11_ADDRESSOF +#endif + +// Bug specific to VC14, +// See https://connect.microsoft.com/VisualStudio/feedback/details/1348277/link-error-when-using-std-codecvt-utf8-utf16-char16-t +// and discussion here: http://blogs.msdn.com/b/vcblog/archive/2014/11/12/visual-studio-2015-preview-now-available.aspx?PageIndex=2 +#if defined(_CPPLIB_VER) && (_CPPLIB_VER == 650) +# define BOOST_NO_CXX11_HDR_CODECVT +#endif + +#if defined(_CPPLIB_VER) && (_CPPLIB_VER >= 650) +// If _HAS_AUTO_PTR_ETC is defined to 0, std::auto_ptr and std::random_shuffle are not available. +// See https://www.visualstudio.com/en-us/news/vs2015-vs.aspx#C++ +// and http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx +# if defined(_HAS_AUTO_PTR_ETC) && (_HAS_AUTO_PTR_ETC == 0) +# define BOOST_NO_AUTO_PTR +# define BOOST_NO_CXX98_RANDOM_SHUFFLE +# define BOOST_NO_CXX98_FUNCTION_BASE +# define BOOST_NO_CXX98_BINDERS +# endif +#endif + + +// +// Things not supported by the CLR: +#ifdef _M_CEE +#ifndef BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_MUTEX +#endif +#ifndef BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_HDR_ATOMIC +#endif +#ifndef BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_FUTURE +#endif +#ifndef BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +#endif +#ifndef BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_THREAD +#endif +#ifndef BOOST_NO_CXX14_HDR_SHARED_MUTEX +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#ifndef BOOST_NO_CXX14_STD_EXCHANGE +# define BOOST_NO_CXX14_STD_EXCHANGE +#endif +#ifndef BOOST_NO_FENV_H +# define BOOST_NO_FENV_H +#endif +#endif + +#ifdef _CPPLIB_VER +# define BOOST_DINKUMWARE_STDLIB _CPPLIB_VER +#else +# define BOOST_DINKUMWARE_STDLIB 1 +#endif + +#ifdef _CPPLIB_VER +# define BOOST_STDLIB "Dinkumware standard library version " BOOST_STRINGIZE(_CPPLIB_VER) +#else +# define BOOST_STDLIB "Dinkumware standard library version 1.x" +#endif diff --git a/third-party/boost/boost/config/stdlib/libcomo.hpp b/third-party/boost/boost/config/stdlib/libcomo.hpp new file mode 100644 index 000000000..75ac2bb76 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/libcomo.hpp @@ -0,0 +1,92 @@ +// (C) Copyright John Maddock 2002 - 2003. +// (C) Copyright Jens Maurer 2002 - 2003. +// (C) Copyright Beman Dawes 2002 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Comeau STL: + +#if !defined(__LIBCOMO__) +# include +# if !defined(__LIBCOMO__) +# error "This is not the Comeau STL!" +# endif +#endif + +// +// std::streambuf is non-standard +// NOTE: versions of libcomo prior to beta28 have octal version numbering, +// e.g. version 25 is 21 (dec) +#if __LIBCOMO_VERSION__ <= 22 +# define BOOST_NO_STD_WSTREAMBUF +#endif + +#if (__LIBCOMO_VERSION__ <= 31) && defined(_WIN32) +#define BOOST_NO_SWPRINTF +#endif + +#if __LIBCOMO_VERSION__ >= 31 +# define BOOST_HAS_HASH +# define BOOST_HAS_SLIST +#endif + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +// +// Intrinsic type_traits support. +// The SGI STL has it's own __type_traits class, which +// has intrinsic compiler support with SGI's compilers. +// Whatever map SGI style type traits to boost equivalents: +// +#define BOOST_HAS_SGI_TYPE_TRAITS + +#define BOOST_STDLIB "Comeau standard library " BOOST_STRINGIZE(__LIBCOMO_VERSION__) diff --git a/third-party/boost/boost/config/stdlib/libcpp.hpp b/third-party/boost/boost/config/stdlib/libcpp.hpp new file mode 100644 index 000000000..ffe2f2a0f --- /dev/null +++ b/third-party/boost/boost/config/stdlib/libcpp.hpp @@ -0,0 +1,143 @@ +// (C) Copyright Christopher Jefferson 2011. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// config for libc++ +// Might need more in here later. + +#if !defined(_LIBCPP_VERSION) +# include +# if !defined(_LIBCPP_VERSION) +# error "This is not libc++!" +# endif +#endif + +#define BOOST_STDLIB "libc++ version " BOOST_STRINGIZE(_LIBCPP_VERSION) + +#define BOOST_HAS_THREADS + +#ifdef _LIBCPP_HAS_NO_VARIADICS +# define BOOST_NO_CXX11_HDR_TUPLE +#endif + +// BOOST_NO_CXX11_ALLOCATOR should imply no support for the C++11 +// allocator model. The C++11 allocator model requires a conforming +// std::allocator_traits which is only possible with C++11 template +// aliases since members rebind_alloc and rebind_traits require it. +#if defined(_LIBCPP_HAS_NO_TEMPLATE_ALIASES) +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +#endif + +#if __cplusplus < 201103 +// +// These two appear to be somewhat useable in C++03 mode, there may be others... +// +//# define BOOST_NO_CXX11_HDR_ARRAY +//# define BOOST_NO_CXX11_HDR_FORWARD_LIST + +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_FUTURE +#elif _LIBCPP_VERSION < 3700 +// +// These appear to be unusable/incomplete so far: +// +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_FUTURE +#endif + + +#if _LIBCPP_VERSION < 3700 +// libc++ uses a non-standard messages_base +#define BOOST_NO_STD_MESSAGES +#endif + +// C++14 features +#if (_LIBCPP_VERSION < 3700) || (__cplusplus <= 201402L) +# define BOOST_NO_CXX14_STD_EXCHANGE +#endif + +// C++17 features +#if (_LIBCPP_VERSION < 4000) || (__cplusplus <= 201402L) +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif +#if (_LIBCPP_VERSION > 4000) && (__cplusplus > 201402L) && !defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) +# define BOOST_NO_AUTO_PTR +#endif +#if (_LIBCPP_VERSION > 4000) && (__cplusplus > 201402L) && !defined(_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE) +# define BOOST_NO_CXX98_RANDOM_SHUFFLE +#endif +#if (_LIBCPP_VERSION > 4000) && (__cplusplus > 201402L) && !defined(_LIBCPP_ENABLE_CXX17_REMOVED_BINDERS) +# define BOOST_NO_CXX98_BINDERS +#endif + +#define BOOST_NO_CXX17_ITERATOR_TRAITS +#define BOOST_NO_CXX17_STD_INVOKE // Invoke support is incomplete (no invoke_result) + +#if (_LIBCPP_VERSION <= 1101) && !defined(BOOST_NO_CXX11_THREAD_LOCAL) +// This is a bit of a sledgehammer, because really it's just libc++abi that has no +// support for thread_local, leading to linker errors such as +// "undefined reference to `__cxa_thread_atexit'". It is fixed in the +// most recent releases of libc++abi though... +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +#if defined(__linux__) && (_LIBCPP_VERSION < 6000) && !defined(BOOST_NO_CXX11_THREAD_LOCAL) +// After libc++-dev is installed on Trusty, clang++-libc++ almost works, +// except uses of `thread_local` fail with undefined reference to +// `__cxa_thread_atexit`. +// +// clang's libc++abi provides an implementation by deferring to the glibc +// implementation, which may or may not be available (it is not on Trusty). +// clang 4's libc++abi will provide an implementation if one is not in glibc +// though, so thread local support should work with clang 4 and above as long +// as libc++abi is linked in. +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus <= 201103 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) && (_LIBCPP_VERSION < 5000) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// --- end --- diff --git a/third-party/boost/boost/config/stdlib/libstdcpp3.hpp b/third-party/boost/boost/config/stdlib/libstdcpp3.hpp new file mode 100644 index 000000000..38209ddd4 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/libstdcpp3.hpp @@ -0,0 +1,349 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright Jens Maurer 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// config for libstdc++ v3 +// not much to go in here: + +#define BOOST_GNU_STDLIB 1 + +#ifdef __GLIBCXX__ +#define BOOST_STDLIB "GNU libstdc++ version " BOOST_STRINGIZE(__GLIBCXX__) +#else +#define BOOST_STDLIB "GNU libstdc++ version " BOOST_STRINGIZE(__GLIBCPP__) +#endif + +#if !defined(_GLIBCPP_USE_WCHAR_T) && !defined(_GLIBCXX_USE_WCHAR_T) +# define BOOST_NO_CWCHAR +# define BOOST_NO_CWCTYPE +# define BOOST_NO_STD_WSTRING +# define BOOST_NO_STD_WSTREAMBUF +#endif + +#if defined(__osf__) && !defined(_REENTRANT) \ + && ( defined(_GLIBCXX_HAVE_GTHR_DEFAULT) || defined(_GLIBCPP_HAVE_GTHR_DEFAULT) ) +// GCC 3 on Tru64 forces the definition of _REENTRANT when any std lib header +// file is included, therefore for consistency we define it here as well. +# define _REENTRANT +#endif + +#ifdef __GLIBCXX__ // gcc 3.4 and greater: +# if defined(_GLIBCXX_HAVE_GTHR_DEFAULT) \ + || defined(_GLIBCXX__PTHREADS) \ + || defined(_GLIBCXX_HAS_GTHREADS) \ + || defined(_WIN32) \ + || defined(_AIX) \ + || defined(__HAIKU__) + // + // If the std lib has thread support turned on, then turn it on in Boost + // as well. We do this because some gcc-3.4 std lib headers define _REENTANT + // while others do not... + // +# define BOOST_HAS_THREADS +# else +# define BOOST_DISABLE_THREADS +# endif +#elif defined(__GLIBCPP__) \ + && !defined(_GLIBCPP_HAVE_GTHR_DEFAULT) \ + && !defined(_GLIBCPP__PTHREADS) + // disable thread support if the std lib was built single threaded: +# define BOOST_DISABLE_THREADS +#endif + +#if (defined(linux) || defined(__linux) || defined(__linux__)) && defined(__arm__) && defined(_GLIBCPP_HAVE_GTHR_DEFAULT) +// linux on arm apparently doesn't define _REENTRANT +// so just turn on threading support whenever the std lib is thread safe: +# define BOOST_HAS_THREADS +#endif + +#if !defined(_GLIBCPP_USE_LONG_LONG) \ + && !defined(_GLIBCXX_USE_LONG_LONG)\ + && defined(BOOST_HAS_LONG_LONG) +// May have been set by compiler/*.hpp, but "long long" without library +// support is useless. +# undef BOOST_HAS_LONG_LONG +#endif + +// Apple doesn't seem to reliably defined a *unix* macro +#if !defined(CYGWIN) && ( defined(__unix__) \ + || defined(__unix) \ + || defined(unix) \ + || defined(__APPLE__) \ + || defined(__APPLE) \ + || defined(APPLE)) +# include +#endif + +#ifndef __VXWORKS__ // VxWorks uses Dinkum, not GNU STL with GCC +#if defined(__GLIBCXX__) || (defined(__GLIBCPP__) && __GLIBCPP__>=20020514) // GCC >= 3.1.0 +# define BOOST_STD_EXTENSION_NAMESPACE __gnu_cxx +# define BOOST_HAS_SLIST +# define BOOST_HAS_HASH +# define BOOST_SLIST_HEADER +# if !defined(__GNUC__) || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 3) +# define BOOST_HASH_SET_HEADER +# define BOOST_HASH_MAP_HEADER +# else +# define BOOST_HASH_SET_HEADER +# define BOOST_HASH_MAP_HEADER +# endif +#endif +#endif + +// +// Decide whether we have C++11 support turned on: +// +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103) +# define BOOST_LIBSTDCXX11 +#endif + +// +// Decide which version of libstdc++ we have, normally +// libstdc++ C++0x support is detected via __GNUC__, __GNUC_MINOR__, and possibly +// __GNUC_PATCHLEVEL__ at the suggestion of Jonathan Wakely, one of the libstdc++ +// developers. He also commented: +// +// "I'm not sure how useful __GLIBCXX__ is for your purposes, for instance in +// GCC 4.2.4 it is set to 20080519 but in GCC 4.3.0 it is set to 20080305. +// Although 4.3.0 was released earlier than 4.2.4, it has better C++0x support +// than any release in the 4.2 series." +// +// Another resource for understanding libstdc++ features is: +// http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#manual.intro.status.standard.200x +// +// However, using the GCC version number fails when the compiler is clang since this +// only ever claims to emulate GCC-4.2, see https://svn.boost.org/trac/boost/ticket/7473 +// for a long discussion on this issue. What we can do though is use clang's __has_include +// to detect the presence of a C++11 header that was introduced with a specific GCC release. +// We still have to be careful though as many such headers were buggy and/or incomplete when +// first introduced, so we only check for headers that were fully featured from day 1, and then +// use that to infer the underlying GCC version: +// +#ifdef __clang__ + +#if __has_include() +# define BOOST_LIBSTDCXX_VERSION 60100 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 50100 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40900 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40800 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40700 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40600 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40500 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40400 +#elif __has_include() +# define BOOST_LIBSTDCXX_VERSION 40300 +#endif + +#if (BOOST_LIBSTDCXX_VERSION < 50100) +// libstdc++ does not define this function as it's deprecated in C++11, but clang still looks for it, +// defining it here is a terrible cludge, but should get things working: +extern "C" char *gets (char *__s); +#endif +// +// clang is unable to parse some GCC headers, add those workarounds here: +// +#if BOOST_LIBSTDCXX_VERSION < 50000 +# define BOOST_NO_CXX11_HDR_REGEX +#endif +// +// GCC 4.7.x has no __cxa_thread_atexit which +// thread_local objects require for cleanup: +// +#if BOOST_LIBSTDCXX_VERSION < 40800 +# define BOOST_NO_CXX11_THREAD_LOCAL +#endif +// +// Early clang versions can handle , not exactly sure which versions +// but certainly up to clang-3.8 and gcc-4.6: +// +#if (__clang_major__ < 5) +# if BOOST_LIBSTDCXX_VERSION < 40800 +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_CHRONO +# endif +#endif + +// +// GCC 4.8 and 9 add working versions of and respectively. +// However, we have no test for these as the headers were present but broken +// in early GCC versions. +// +#endif + +#if defined(__SUNPRO_CC) && (__SUNPRO_CC >= 0x5130) && (__cplusplus >= 201103L) +// +// Oracle Solaris compiler uses it's own verison of libstdc++ but doesn't +// set __GNUC__ +// +#if __SUNPRO_CC >= 0x5140 +#define BOOST_LIBSTDCXX_VERSION 50100 +#else +#define BOOST_LIBSTDCXX_VERSION 40800 +#endif +#endif + +#if !defined(BOOST_LIBSTDCXX_VERSION) +# define BOOST_LIBSTDCXX_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) +#endif + +// std::auto_ptr isn't provided with _GLIBCXX_DEPRECATED=0 (GCC 4.5 and earlier) +// or _GLIBCXX_USE_DEPRECATED=0 (GCC 4.6 and later). +#if defined(BOOST_LIBSTDCXX11) +# if BOOST_LIBSTDCXX_VERSION < 40600 +# if !_GLIBCXX_DEPRECATED +# define BOOST_NO_AUTO_PTR +# endif +# elif !_GLIBCXX_USE_DEPRECATED +# define BOOST_NO_AUTO_PTR +# endif +#endif + +// C++0x headers in GCC 4.3.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40300) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +#endif + +// C++0x headers in GCC 4.4.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40400) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_SMART_PTR +#else +# define BOOST_HAS_TR1_COMPLEX_INVERSE_TRIG +# define BOOST_HAS_TR1_COMPLEX_OVERLOADS +#endif + +// C++0x features in GCC 4.5.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40500) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_RANDOM +#endif + +// C++0x features in GCC 4.6.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40600) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_ADDRESSOF +# define BOOST_NO_CXX17_ITERATOR_TRAITS +#endif + +// C++0x features in GCC 4.7.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40700) || !defined(BOOST_LIBSTDCXX11) +// Note that although existed prior to 4.7, "steady_clock" is spelled "monotonic_clock" +// so 4.7.0 is the first truly conforming one. +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +#endif +// C++0x features in GCC 4.8.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40800) || !defined(BOOST_LIBSTDCXX11) +// Note that although existed prior to gcc 4.8 it was largely unimplemented for many types: +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_HDR_THREAD +#endif +// C++0x features in GCC 4.9.0 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 40900) || !defined(BOOST_LIBSTDCXX11) +// Although is present and compilable against, the actual implementation is not functional +// even for the simplest patterns such as "\d" or "[0-9]". This is the case at least in gcc up to 4.8, inclusively. +# define BOOST_NO_CXX11_HDR_REGEX +#endif +#if (BOOST_LIBSTDCXX_VERSION < 40900) || (__cplusplus <= 201103) +# define BOOST_NO_CXX14_STD_EXCHANGE +#endif + +#if defined(__clang_major__) && ((__clang_major__ < 3) || ((__clang_major__ == 3) && (__clang_minor__ < 7))) +// As of clang-3.6, libstdc++ header throws up errors with clang: +# define BOOST_NO_CXX11_HDR_ATOMIC +#endif +// +// C++0x features in GCC 5.1 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 50100) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_STD_ALIGN +#endif + +// +// C++17 features in GCC 7.1 and later +// +#if (BOOST_LIBSTDCXX_VERSION < 70100) || (__cplusplus <= 201402L) +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_HDR_OPTIONAL +# define BOOST_NO_CXX17_HDR_STRING_VIEW +#endif + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus <= 201103 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#elif __cplusplus < 201402 || (BOOST_LIBSTDCXX_VERSION < 40900) || !defined(BOOST_LIBSTDCXX11) +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// +// Headers not present on Solaris with the Oracle compiler: +#if defined(__SUNPRO_CC) && (__SUNPRO_CC < 0x5140) +#define BOOST_NO_CXX11_HDR_FUTURE +#define BOOST_NO_CXX11_HDR_FORWARD_LIST +#define BOOST_NO_CXX11_HDR_ATOMIC +// shared_ptr is present, but is not convertible to bool +// which causes all kinds of problems especially in Boost.Thread +// but probably elsewhere as well. +#define BOOST_NO_CXX11_SMART_PTR +#endif + +#if (!defined(_GLIBCXX_HAS_GTHREADS) || !defined(_GLIBCXX_USE_C99_STDINT_TR1)) + // Headers not always available: +# ifndef BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# endif +# ifndef BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_MUTEX +# endif +# ifndef BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_THREAD +# endif +# ifndef BOOST_NO_CXX14_HDR_SHARED_MUTEX +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +# endif +#endif + +#if (!defined(_GTHREAD_USE_MUTEX_TIMEDLOCK) || (_GTHREAD_USE_MUTEX_TIMEDLOCK == 0)) && !defined(BOOST_NO_CXX11_HDR_MUTEX) +// Timed mutexes are not always available: +# define BOOST_NO_CXX11_HDR_MUTEX +#endif + +// --- end --- diff --git a/third-party/boost/boost/config/stdlib/modena.hpp b/third-party/boost/boost/config/stdlib/modena.hpp new file mode 100644 index 000000000..81919e018 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/modena.hpp @@ -0,0 +1,78 @@ +// (C) Copyright Jens Maurer 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Modena C++ standard library (comes with KAI C++) + +#if !defined(MSIPL_COMPILE_H) +# include +# if !defined(__MSIPL_COMPILE_H) +# error "This is not the Modena C++ library!" +# endif +#endif + +#ifndef MSIPL_NL_TYPES +#define BOOST_NO_STD_MESSAGES +#endif + +#ifndef MSIPL_WCHART +#define BOOST_NO_STD_WSTRING +#endif + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +#define BOOST_STDLIB "Modena C++ standard library" + + + + + diff --git a/third-party/boost/boost/config/stdlib/msl.hpp b/third-party/boost/boost/config/stdlib/msl.hpp new file mode 100644 index 000000000..0e2e2afee --- /dev/null +++ b/third-party/boost/boost/config/stdlib/msl.hpp @@ -0,0 +1,97 @@ +// (C) Copyright John Maddock 2001. +// (C) Copyright Darin Adler 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Metrowerks standard library: + +#ifndef __MSL_CPP__ +# include +# ifndef __MSL_CPP__ +# error This is not the MSL standard library! +# endif +#endif + +#if __MSL_CPP__ >= 0x6000 // Pro 6 +# define BOOST_HAS_HASH +# define BOOST_STD_EXTENSION_NAMESPACE Metrowerks +#endif +#define BOOST_HAS_SLIST + +#if __MSL_CPP__ < 0x6209 +# define BOOST_NO_STD_MESSAGES +#endif + +// check C lib version for +#include + +#if defined(__MSL__) && (__MSL__ >= 0x5000) +# define BOOST_HAS_STDINT_H +# if !defined(__PALMOS_TRAPS__) +# define BOOST_HAS_UNISTD_H +# endif + // boilerplate code: +# include +#endif + +#if defined(_MWMT) || _MSL_THREADSAFE +# define BOOST_HAS_THREADS +#endif + +#ifdef _MSL_NO_EXPLICIT_FUNC_TEMPLATE_ARG +# define BOOST_NO_STD_USE_FACET +# define BOOST_HAS_TWO_ARG_USE_FACET +#endif + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +#define BOOST_STDLIB "Metrowerks Standard Library version " BOOST_STRINGIZE(__MSL_CPP__) diff --git a/third-party/boost/boost/config/stdlib/roguewave.hpp b/third-party/boost/boost/config/stdlib/roguewave.hpp new file mode 100644 index 000000000..df6021551 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/roguewave.hpp @@ -0,0 +1,207 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Jens Maurer 2001. +// (C) Copyright David Abrahams 2003. +// (C) Copyright Boris Gubenko 2007. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// Rogue Wave std lib: + +#define BOOST_RW_STDLIB 1 + +#if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) +# include +# if !defined(__STD_RWCOMPILER_H__) && !defined(_RWSTD_VER) +# error This is not the Rogue Wave standard library +# endif +#endif +// +// figure out a consistent version number: +// +#ifndef _RWSTD_VER +# define BOOST_RWSTD_VER 0x010000 +#elif _RWSTD_VER < 0x010000 +# define BOOST_RWSTD_VER (_RWSTD_VER << 8) +#else +# define BOOST_RWSTD_VER _RWSTD_VER +#endif + +#ifndef _RWSTD_VER +# define BOOST_STDLIB "Rogue Wave standard library version (Unknown version)" +#elif _RWSTD_VER < 0x04010200 + # define BOOST_STDLIB "Rogue Wave standard library version " BOOST_STRINGIZE(_RWSTD_VER) +#else +# ifdef _RWSTD_VER_STR +# define BOOST_STDLIB "Apache STDCXX standard library version " _RWSTD_VER_STR +# else +# define BOOST_STDLIB "Apache STDCXX standard library version " BOOST_STRINGIZE(_RWSTD_VER) +# endif +#endif + +// +// Prior to version 2.2.0 the primary template for std::numeric_limits +// does not have compile time constants, even though specializations of that +// template do: +// +#if BOOST_RWSTD_VER < 0x020200 +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +#endif + +// Sun CC 5.5 patch 113817-07 adds long long specialization, but does not change the +// library version number (http://sunsolve6.sun.com/search/document.do?assetkey=1-21-113817): +#if BOOST_RWSTD_VER <= 0x020101 && (!defined(__SUNPRO_CC) || (__SUNPRO_CC < 0x550)) +# define BOOST_NO_LONG_LONG_NUMERIC_LIMITS +# endif + +// +// Borland version of numeric_limits lacks __int64 specialisation: +// +#ifdef __BORLANDC__ +# define BOOST_NO_MS_INT64_NUMERIC_LIMITS +#endif + +// +// No std::iterator if it can't figure out default template args: +// +#if defined(_RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || defined(RWSTD_NO_SIMPLE_DEFAULT_TEMPLATES) || (BOOST_RWSTD_VER < 0x020000) +# define BOOST_NO_STD_ITERATOR +#endif + +// +// No iterator traits without partial specialization: +// +#if defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) || defined(RWSTD_NO_CLASS_PARTIAL_SPEC) +# define BOOST_NO_STD_ITERATOR_TRAITS +#endif + +// +// Prior to version 2.0, std::auto_ptr was buggy, and there were no +// new-style iostreams, and no conformant std::allocator: +// +#if (BOOST_RWSTD_VER < 0x020000) +# define BOOST_NO_AUTO_PTR +# define BOOST_NO_STRINGSTREAM +# define BOOST_NO_STD_ALLOCATOR +# define BOOST_NO_STD_LOCALE +#endif + +// +// No template iterator constructors without member template support: +// +#if defined(RWSTD_NO_MEMBER_TEMPLATES) || defined(_RWSTD_NO_MEMBER_TEMPLATES) +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +#endif + +// +// RW defines _RWSTD_ALLOCATOR if the allocator is conformant and in use +// (the or _HPACC_ part is a hack - the library seems to define _RWSTD_ALLOCATOR +// on HP aCC systems even though the allocator is in fact broken): +// +#if !defined(_RWSTD_ALLOCATOR) || (defined(__HP_aCC) && __HP_aCC <= 33100) +# define BOOST_NO_STD_ALLOCATOR +#endif + +// +// If we have a std::locale, we still may not have std::use_facet: +// +#if defined(_RWSTD_NO_TEMPLATE_ON_RETURN_TYPE) && !defined(BOOST_NO_STD_LOCALE) +# define BOOST_NO_STD_USE_FACET +# define BOOST_HAS_TWO_ARG_USE_FACET +#endif + +// +// There's no std::distance prior to version 2, or without +// partial specialization support: +// +#if (BOOST_RWSTD_VER < 0x020000) || defined(_RWSTD_NO_CLASS_PARTIAL_SPEC) + #define BOOST_NO_STD_DISTANCE +#endif + +// +// Some versions of the rogue wave library don't have assignable +// OutputIterators: +// +#if BOOST_RWSTD_VER < 0x020100 +# define BOOST_NO_STD_OUTPUT_ITERATOR_ASSIGN +#endif + +// +// Disable BOOST_HAS_LONG_LONG when the library has no support for it. +// +#if !defined(_RWSTD_LONG_LONG) && defined(BOOST_HAS_LONG_LONG) +# undef BOOST_HAS_LONG_LONG +#endif + +// +// check that on HP-UX, the proper RW library is used +// +#if defined(__HP_aCC) && !defined(_HP_NAMESPACE_STD) +# error "Boost requires Standard RW library. Please compile and link with -AA" +#endif + +// +// Define macros specific to RW V2.2 on HP-UX +// +#if defined(__HP_aCC) && (BOOST_RWSTD_VER == 0x02020100) +# ifndef __HP_TC1_MAKE_PAIR +# define __HP_TC1_MAKE_PAIR +# endif +# ifndef _HP_INSTANTIATE_STD2_VL +# define _HP_INSTANTIATE_STD2_VL +# endif +#endif + +#if _RWSTD_VER < 0x05000000 +# define BOOST_NO_CXX11_HDR_ARRAY +#endif +// type_traits header is incomplete: +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +// +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS diff --git a/third-party/boost/boost/config/stdlib/sgi.hpp b/third-party/boost/boost/config/stdlib/sgi.hpp new file mode 100644 index 000000000..0c8ab2e4c --- /dev/null +++ b/third-party/boost/boost/config/stdlib/sgi.hpp @@ -0,0 +1,167 @@ +// (C) Copyright John Maddock 2001 - 2003. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Jens Maurer 2001 - 2003. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// generic SGI STL: + +#if !defined(__STL_CONFIG_H) +# include +# if !defined(__STL_CONFIG_H) +# error "This is not the SGI STL!" +# endif +#endif + +// +// No std::iterator traits without partial specialisation: +// +#if !defined(__STL_CLASS_PARTIAL_SPECIALIZATION) +# define BOOST_NO_STD_ITERATOR_TRAITS +#endif + +// +// No std::stringstream with gcc < 3 +// +#if defined(__GNUC__) && (__GNUC__ < 3) && \ + ((__GNUC_MINOR__ < 95) || (__GNUC_MINOR__ == 96)) && \ + !defined(__STL_USE_NEW_IOSTREAMS) || \ + defined(__APPLE_CC__) + // Note that we only set this for GNU C++ prior to 2.95 since the + // latest patches for that release do contain a minimal + // If you are running a 2.95 release prior to 2.95.3 then this will need + // setting, but there is no way to detect that automatically (other + // than by running the configure script). + // Also, the unofficial GNU C++ 2.96 included in RedHat 7.1 doesn't + // have . +# define BOOST_NO_STRINGSTREAM +#endif + +// Apple doesn't seem to reliably defined a *unix* macro +#if !defined(CYGWIN) && ( defined(__unix__) \ + || defined(__unix) \ + || defined(unix) \ + || defined(__APPLE__) \ + || defined(__APPLE) \ + || defined(APPLE)) +# include +#endif + + +// +// Assume no std::locale without own iostreams (this may be an +// incorrect assumption in some cases): +// +#if !defined(__SGI_STL_OWN_IOSTREAMS) && !defined(__STL_USE_NEW_IOSTREAMS) +# define BOOST_NO_STD_LOCALE +#endif + +// +// Original native SGI streams have non-standard std::messages facet: +// +#if defined(__sgi) && (_COMPILER_VERSION <= 650) && !defined(__SGI_STL_OWN_IOSTREAMS) +# define BOOST_NO_STD_LOCALE +#endif + +// +// SGI's new iostreams have missing "const" in messages<>::open +// +#if defined(__sgi) && (_COMPILER_VERSION <= 740) && defined(__STL_USE_NEW_IOSTREAMS) +# define BOOST_NO_STD_MESSAGES +#endif + +// +// No template iterator constructors, or std::allocator +// without member templates: +// +#if !defined(__STL_MEMBER_TEMPLATES) +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +# define BOOST_NO_STD_ALLOCATOR +#endif + +// +// We always have SGI style hash_set, hash_map, and slist: +// +#define BOOST_HAS_HASH +#define BOOST_HAS_SLIST + +// +// If this is GNU libstdc++2, then no and no std::wstring: +// +#if (defined(__GNUC__) && (__GNUC__ < 3)) +# include +# if defined(__BASTRING__) +# define BOOST_NO_LIMITS +// Note: will provide compile-time constants +# undef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +# define BOOST_NO_STD_WSTRING +# endif +#endif + +// +// There is no standard iterator unless we have namespace support: +// +#if !defined(__STL_USE_NAMESPACES) +# define BOOST_NO_STD_ITERATOR +#endif + +// +// Intrinsic type_traits support. +// The SGI STL has it's own __type_traits class, which +// has intrinsic compiler support with SGI's compilers. +// Whatever map SGI style type traits to boost equivalents: +// +#define BOOST_HAS_SGI_TYPE_TRAITS + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +#define BOOST_STDLIB "SGI standard library" diff --git a/third-party/boost/boost/config/stdlib/stlport.hpp b/third-party/boost/boost/config/stdlib/stlport.hpp new file mode 100644 index 000000000..2e304e2b9 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/stlport.hpp @@ -0,0 +1,257 @@ +// (C) Copyright John Maddock 2001 - 2002. +// (C) Copyright Darin Adler 2001. +// (C) Copyright Jens Maurer 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +// STLPort standard library config: + +#if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) +# include +# if !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION) +# error "This is not STLPort!" +# endif +#endif + +// Apple doesn't seem to reliably defined a *unix* macro +#if !defined(CYGWIN) && ( defined(__unix__) \ + || defined(__unix) \ + || defined(unix) \ + || defined(__APPLE__) \ + || defined(__APPLE) \ + || defined(APPLE)) +# include +#endif + +// +// __STL_STATIC_CONST_INIT_BUG implies BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +// for versions prior to 4.1(beta) +// +#if (defined(__STL_STATIC_CONST_INIT_BUG) || defined(_STLP_STATIC_CONST_INIT_BUG)) && (__SGI_STL_PORT <= 0x400) +# define BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +#endif + +// +// If STLport thinks that there is no partial specialisation, then there is no +// std::iterator traits: +// +#if !(defined(_STLP_CLASS_PARTIAL_SPECIALIZATION) || defined(__STL_CLASS_PARTIAL_SPECIALIZATION)) +# define BOOST_NO_STD_ITERATOR_TRAITS +#endif + +// +// No new style iostreams on GCC without STLport's iostreams enabled: +// +#if (defined(__GNUC__) && (__GNUC__ < 3)) && !(defined(__SGI_STL_OWN_IOSTREAMS) || defined(_STLP_OWN_IOSTREAMS)) +# define BOOST_NO_STRINGSTREAM +#endif + +// +// No new iostreams implies no std::locale, and no std::stringstream: +// +#if defined(__STL_NO_IOSTREAMS) || defined(__STL_NO_NEW_IOSTREAMS) || defined(_STLP_NO_IOSTREAMS) || defined(_STLP_NO_NEW_IOSTREAMS) +# define BOOST_NO_STD_LOCALE +# define BOOST_NO_STRINGSTREAM +#endif + +// +// If the streams are not native, and we have a "using ::x" compiler bug +// then the io stream facets are not available in namespace std:: +// +#ifdef _STLPORT_VERSION +# if !(_STLPORT_VERSION >= 0x500) && !defined(_STLP_OWN_IOSTREAMS) && defined(_STLP_USE_NAMESPACES) && defined(BOOST_NO_USING_TEMPLATE) && !defined(__BORLANDC__) +# define BOOST_NO_STD_LOCALE +# endif +#else +# if !defined(__SGI_STL_OWN_IOSTREAMS) && defined(__STL_USE_NAMESPACES) && defined(BOOST_NO_USING_TEMPLATE) && !defined(__BORLANDC__) +# define BOOST_NO_STD_LOCALE +# endif +#endif + +#if defined(_STLPORT_VERSION) && (_STLPORT_VERSION >= 0x520) +# define BOOST_HAS_TR1_UNORDERED_SET +# define BOOST_HAS_TR1_UNORDERED_MAP +#endif +// +// Without member template support enabled, their are no template +// iterate constructors, and no std::allocator: +// +#if !(defined(__STL_MEMBER_TEMPLATES) || defined(_STLP_MEMBER_TEMPLATES)) +# define BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS +# define BOOST_NO_STD_ALLOCATOR +#endif +// +// however we always have at least a partial allocator: +// +#define BOOST_HAS_PARTIAL_STD_ALLOCATOR + +#if !defined(_STLP_MEMBER_TEMPLATE_CLASSES) || defined(_STLP_DONT_SUPPORT_REBIND_MEMBER_TEMPLATE) +# define BOOST_NO_STD_ALLOCATOR +#endif + +#if defined(_STLP_NO_MEMBER_TEMPLATE_KEYWORD) && defined(BOOST_MSVC) && (BOOST_MSVC <= 1300) +# define BOOST_NO_STD_ALLOCATOR +#endif + +// +// If STLport thinks there is no wchar_t at all, then we have to disable +// the support for the relevant specilazations of std:: templates. +// +#if !defined(_STLP_HAS_WCHAR_T) && !defined(_STLP_WCHAR_T_IS_USHORT) +# ifndef BOOST_NO_STD_WSTRING +# define BOOST_NO_STD_WSTRING +# endif +# ifndef BOOST_NO_STD_WSTREAMBUF +# define BOOST_NO_STD_WSTREAMBUF +# endif +#endif + +// +// We always have SGI style hash_set, hash_map, and slist: +// +#ifndef _STLP_NO_EXTENSIONS +#define BOOST_HAS_HASH +#define BOOST_HAS_SLIST +#endif + +// +// STLport does a good job of importing names into namespace std::, +// but doesn't always get them all, define BOOST_NO_STDC_NAMESPACE, since our +// workaround does not conflict with STLports: +// +// +// Harold Howe says: +// Borland switched to STLport in BCB6. Defining BOOST_NO_STDC_NAMESPACE with +// BCB6 does cause problems. If we detect C++ Builder, then don't define +// BOOST_NO_STDC_NAMESPACE +// +#if !defined(__BORLANDC__) && !defined(__DMC__) +// +// If STLport is using it's own namespace, and the real names are in +// the global namespace, then we duplicate STLport's using declarations +// (by defining BOOST_NO_STDC_NAMESPACE), we do this because STLport doesn't +// necessarily import all the names we need into namespace std:: +// +# if (defined(__STL_IMPORT_VENDOR_CSTD) \ + || defined(__STL_USE_OWN_NAMESPACE) \ + || defined(_STLP_IMPORT_VENDOR_CSTD) \ + || defined(_STLP_USE_OWN_NAMESPACE)) \ + && (defined(__STL_VENDOR_GLOBAL_CSTD) || defined (_STLP_VENDOR_GLOBAL_CSTD)) +# define BOOST_NO_STDC_NAMESPACE +# define BOOST_NO_EXCEPTION_STD_NAMESPACE +# endif +#elif defined(__BORLANDC__) && __BORLANDC__ < 0x560 +// STLport doesn't import std::abs correctly: +#include +namespace std { using ::abs; } +// and strcmp/strcpy don't get imported either ('cos they are macros) +#include +#ifdef strcpy +# undef strcpy +#endif +#ifdef strcmp +# undef strcmp +#endif +#ifdef _STLP_VENDOR_CSTD +namespace std{ using _STLP_VENDOR_CSTD::strcmp; using _STLP_VENDOR_CSTD::strcpy; } +#endif +#endif + +// +// std::use_facet may be non-standard, uses a class instead: +// +#if defined(__STL_NO_EXPLICIT_FUNCTION_TMPL_ARGS) || defined(_STLP_NO_EXPLICIT_FUNCTION_TMPL_ARGS) +# define BOOST_NO_STD_USE_FACET +# define BOOST_HAS_STLP_USE_FACET +#endif + +// +// If STLport thinks there are no wide functions, etc. is not working; but +// only if BOOST_NO_STDC_NAMESPACE is not defined (if it is then we do the import +// into std:: ourselves). +// +#if defined(_STLP_NO_NATIVE_WIDE_FUNCTIONS) && !defined(BOOST_NO_STDC_NAMESPACE) +# define BOOST_NO_CWCHAR +# define BOOST_NO_CWCTYPE +#endif + +// +// If STLport for some reason was configured so that it thinks that wchar_t +// is not an intrinsic type, then we have to disable the support for it as +// well (we would be missing required specializations otherwise). +// +#if !defined( _STLP_HAS_WCHAR_T) || defined(_STLP_WCHAR_T_IS_USHORT) +# undef BOOST_NO_INTRINSIC_WCHAR_T +# define BOOST_NO_INTRINSIC_WCHAR_T +#endif + +// +// Borland ships a version of STLport with C++ Builder 6 that lacks +// hashtables and the like: +// +#if defined(__BORLANDC__) && (__BORLANDC__ == 0x560) +# undef BOOST_HAS_HASH +#endif + +// +// gcc-2.95.3/STLPort does not like the using declarations we use to get ADL with std::min/max +// +#if defined(__GNUC__) && (__GNUC__ < 3) +# include // for std::min and std::max +# define BOOST_USING_STD_MIN() ((void)0) +# define BOOST_USING_STD_MAX() ((void)0) +namespace boost { using std::min; using std::max; } +#endif + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +#define BOOST_STDLIB "STLPort standard library version " BOOST_STRINGIZE(__SGI_STL_PORT) diff --git a/third-party/boost/boost/config/stdlib/vacpp.hpp b/third-party/boost/boost/config/stdlib/vacpp.hpp new file mode 100644 index 000000000..c4e1fb184 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/vacpp.hpp @@ -0,0 +1,73 @@ +// (C) Copyright John Maddock 2001 - 2002. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See http://www.boost.org for most recent version. + +#if __IBMCPP__ <= 501 +# define BOOST_NO_STD_ALLOCATOR +#endif + +#define BOOST_HAS_MACRO_USE_FACET +#define BOOST_NO_STD_MESSAGES + +// Apple doesn't seem to reliably defined a *unix* macro +#if !defined(CYGWIN) && ( defined(__unix__) \ + || defined(__unix) \ + || defined(unix) \ + || defined(__APPLE__) \ + || defined(__APPLE) \ + || defined(APPLE)) +# include +#endif + +// C++0x headers not yet implemented +// +# define BOOST_NO_CXX11_HDR_ARRAY +# define BOOST_NO_CXX11_HDR_CHRONO +# define BOOST_NO_CXX11_HDR_CODECVT +# define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +# define BOOST_NO_CXX11_HDR_FORWARD_LIST +# define BOOST_NO_CXX11_HDR_FUTURE +# define BOOST_NO_CXX11_HDR_INITIALIZER_LIST +# define BOOST_NO_CXX11_HDR_MUTEX +# define BOOST_NO_CXX11_HDR_RANDOM +# define BOOST_NO_CXX11_HDR_RATIO +# define BOOST_NO_CXX11_HDR_REGEX +# define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +# define BOOST_NO_CXX11_HDR_THREAD +# define BOOST_NO_CXX11_HDR_TUPLE +# define BOOST_NO_CXX11_HDR_TYPE_TRAITS +# define BOOST_NO_CXX11_HDR_TYPEINDEX +# define BOOST_NO_CXX11_HDR_UNORDERED_MAP +# define BOOST_NO_CXX11_HDR_UNORDERED_SET +# define BOOST_NO_CXX11_NUMERIC_LIMITS +# define BOOST_NO_CXX11_ALLOCATOR +# define BOOST_NO_CXX11_POINTER_TRAITS +# define BOOST_NO_CXX11_ATOMIC_SMART_PTR +# define BOOST_NO_CXX11_SMART_PTR +# define BOOST_NO_CXX11_HDR_FUNCTIONAL +# define BOOST_NO_CXX11_HDR_ATOMIC +# define BOOST_NO_CXX11_STD_ALIGN +# define BOOST_NO_CXX11_ADDRESSOF + +#if defined(__has_include) +#if !__has_include() +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#elif __cplusplus < 201402 +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif +#else +# define BOOST_NO_CXX14_HDR_SHARED_MUTEX +#endif + +// C++14 features +# define BOOST_NO_CXX14_STD_EXCHANGE + +// C++17 features +# define BOOST_NO_CXX17_STD_APPLY +# define BOOST_NO_CXX17_STD_INVOKE +# define BOOST_NO_CXX17_ITERATOR_TRAITS + +#define BOOST_STDLIB "Visual Age default standard library" diff --git a/third-party/boost/boost/config/stdlib/xlcpp_zos.hpp b/third-party/boost/boost/config/stdlib/xlcpp_zos.hpp new file mode 100644 index 000000000..4d5beb185 --- /dev/null +++ b/third-party/boost/boost/config/stdlib/xlcpp_zos.hpp @@ -0,0 +1,60 @@ +// Copyright (c) 2017 Dynatrace +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt + +// See http://www.boost.org for most recent version. + +// Standard library setup for IBM z/OS XL C/C++ compiler. + +// Oldest library version currently supported is 2.1 (V2R1) +#if __TARGET_LIB__ < 0x42010000 +# error "Library version not supported or configured - please reconfigure" +#endif + +#if __TARGET_LIB__ > 0x42010000 +# if defined(BOOST_ASSERT_CONFIG) +# error "Unknown library version - please run the configure tests and report the results" +# endif +#endif + +#define BOOST_STDLIB "IBM z/OS XL C/C++ standard library" + +#define BOOST_HAS_MACRO_USE_FACET + +#define BOOST_NO_CXX11_HDR_TYPE_TRAITS +#define BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +#define BOOST_NO_CXX11_ADDRESSOF +#define BOOST_NO_CXX11_SMART_PTR +#define BOOST_NO_CXX11_ATOMIC_SMART_PTR +#define BOOST_NO_CXX11_NUMERIC_LIMITS +#define BOOST_NO_CXX11_ALLOCATOR +#define BOOST_NO_CXX11_POINTER_TRAITS +#define BOOST_NO_CXX11_HDR_FUNCTIONAL +#define BOOST_NO_CXX11_HDR_UNORDERED_SET +#define BOOST_NO_CXX11_HDR_UNORDERED_MAP +#define BOOST_NO_CXX11_HDR_TYPEINDEX +#define BOOST_NO_CXX11_HDR_TUPLE +#define BOOST_NO_CXX11_HDR_THREAD +#define BOOST_NO_CXX11_HDR_SYSTEM_ERROR +#define BOOST_NO_CXX11_HDR_REGEX +#define BOOST_NO_CXX11_HDR_RATIO +#define BOOST_NO_CXX11_HDR_RANDOM +#define BOOST_NO_CXX11_HDR_MUTEX +#define BOOST_NO_CXX11_HDR_FUTURE +#define BOOST_NO_CXX11_HDR_FORWARD_LIST +#define BOOST_NO_CXX11_HDR_CONDITION_VARIABLE +#define BOOST_NO_CXX11_HDR_CODECVT +#define BOOST_NO_CXX11_HDR_CHRONO +#define BOOST_NO_CXX11_HDR_ATOMIC +#define BOOST_NO_CXX11_HDR_ARRAY +#define BOOST_NO_CXX11_STD_ALIGN + +#define BOOST_NO_CXX14_STD_EXCHANGE +#define BOOST_NO_CXX14_HDR_SHARED_MUTEX + +#define BOOST_NO_CXX17_STD_INVOKE +#define BOOST_NO_CXX17_STD_APPLY +#define BOOST_NO_CXX17_ITERATOR_TRAITS diff --git a/third-party/boost/boost/config/user.hpp b/third-party/boost/boost/config/user.hpp new file mode 100644 index 000000000..28e7476af --- /dev/null +++ b/third-party/boost/boost/config/user.hpp @@ -0,0 +1,133 @@ +// boost/config/user.hpp ---------------------------------------------------// + +// (C) Copyright John Maddock 2001. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Do not check in modified versions of this file, +// This file may be customized by the end user, but not by boost. + +// +// Use this file to define a site and compiler specific +// configuration policy: +// + +// define this to locate a compiler config file: +// #define BOOST_COMPILER_CONFIG + +// define this to locate a stdlib config file: +// #define BOOST_STDLIB_CONFIG + +// define this to locate a platform config file: +// #define BOOST_PLATFORM_CONFIG + +// define this to disable compiler config, +// use if your compiler config has nothing to set: +// #define BOOST_NO_COMPILER_CONFIG + +// define this to disable stdlib config, +// use if your stdlib config has nothing to set: +// #define BOOST_NO_STDLIB_CONFIG + +// define this to disable platform config, +// use if your platform config has nothing to set: +// #define BOOST_NO_PLATFORM_CONFIG + +// define this to disable all config options, +// excluding the user config. Use if your +// setup is fully ISO compliant, and has no +// useful extensions, or for autoconf generated +// setups: +// #define BOOST_NO_CONFIG + +// define this to make the config "optimistic" +// about unknown compiler versions. Normally +// unknown compiler versions are assumed to have +// all the defects of the last known version, however +// setting this flag, causes the config to assume +// that unknown compiler versions are fully conformant +// with the standard: +// #define BOOST_STRICT_CONFIG + +// define this to cause the config to halt compilation +// with an #error if it encounters anything unknown -- +// either an unknown compiler version or an unknown +// compiler/platform/library: +// #define BOOST_ASSERT_CONFIG + + +// define if you want to disable threading support, even +// when available: +// #define BOOST_DISABLE_THREADS + +// define when you want to disable Win32 specific features +// even when available: +// #define BOOST_DISABLE_WIN32 + +// BOOST_DISABLE_ABI_HEADERS: Stops boost headers from including any +// prefix/suffix headers that normally control things like struct +// packing and alignment. +// #define BOOST_DISABLE_ABI_HEADERS + +// BOOST_ABI_PREFIX: A prefix header to include in place of whatever +// boost.config would normally select, any replacement should set up +// struct packing and alignment options as required. +// #define BOOST_ABI_PREFIX my-header-name + +// BOOST_ABI_SUFFIX: A suffix header to include in place of whatever +// boost.config would normally select, any replacement should undo +// the effects of the prefix header. +// #define BOOST_ABI_SUFFIX my-header-name + +// BOOST_ALL_DYN_LINK: Forces all libraries that have separate source, +// to be linked as dll's rather than static libraries on Microsoft Windows +// (this macro is used to turn on __declspec(dllimport) modifiers, so that +// the compiler knows which symbols to look for in a dll rather than in a +// static library). Note that there may be some libraries that can only +// be linked in one way (statically or dynamically), in these cases this +// macro has no effect. +// #define BOOST_ALL_DYN_LINK + +// BOOST_WHATEVER_DYN_LINK: Forces library "whatever" to be linked as a dll +// rather than a static library on Microsoft Windows: replace the WHATEVER +// part of the macro name with the name of the library that you want to +// dynamically link to, for example use BOOST_DATE_TIME_DYN_LINK or +// BOOST_REGEX_DYN_LINK etc (this macro is used to turn on __declspec(dllimport) +// modifiers, so that the compiler knows which symbols to look for in a dll +// rather than in a static library). +// Note that there may be some libraries that can only +// be linked in one way (statically or dynamically), +// in these cases this macro is unsupported. +// #define BOOST_WHATEVER_DYN_LINK + +// BOOST_ALL_NO_LIB: Tells the config system not to automatically select +// which libraries to link against. +// Normally if a compiler supports #pragma lib, then the correct library +// build variant will be automatically selected and linked against, +// simply by the act of including one of that library's headers. +// This macro turns that feature off. +// #define BOOST_ALL_NO_LIB + +// BOOST_WHATEVER_NO_LIB: Tells the config system not to automatically +// select which library to link against for library "whatever", +// replace WHATEVER in the macro name with the name of the library; +// for example BOOST_DATE_TIME_NO_LIB or BOOST_REGEX_NO_LIB. +// Normally if a compiler supports #pragma lib, then the correct library +// build variant will be automatically selected and linked against, simply +// by the act of including one of that library's headers. This macro turns +// that feature off. +// #define BOOST_WHATEVER_NO_LIB + +// BOOST_LIB_BUILDID: Set to the same value as the value passed to Boost.Build's +// --buildid command line option. For example if you built using: +// +// bjam address-model=64 --buildid=amd64 +// +// then compile your code with: +// +// -DBOOST_LIB_BUILDID = amd64 +// +// to ensure the correct libraries are selected at link time. +// #define BOOST_LIB_BUILDID amd64 + diff --git a/third-party/boost/boost/config/warning_disable.hpp b/third-party/boost/boost/config/warning_disable.hpp new file mode 100644 index 000000000..fea8e829f --- /dev/null +++ b/third-party/boost/boost/config/warning_disable.hpp @@ -0,0 +1,47 @@ +// Copyright John Maddock 2008 +// Use, modification, and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// This file exists to turn off some overly-pedantic warning emitted +// by certain compilers. You should include this header only in: +// +// * A test case, before any other headers, or, +// * A library source file before any other headers. +// +// IT SHOULD NOT BE INCLUDED BY ANY BOOST HEADER. +// +// YOU SHOULD NOT INCLUDE IT IF YOU CAN REASONABLY FIX THE WARNING. +// +// The only warnings disabled here are those that are: +// +// * Quite unreasonably pedantic. +// * Generally only emitted by a single compiler. +// * Can't easily be fixed: for example if the vendors own std lib +// code emits these warnings! +// +// Note that THIS HEADER MUST NOT INCLUDE ANY OTHER HEADERS: +// not even std library ones! Doing so may turn the warning +// off too late to be of any use. For example the VC++ C4996 +// warning can be emitted from if that header is included +// before or by this one :-( +// + +#ifndef BOOST_CONFIG_WARNING_DISABLE_HPP +#define BOOST_CONFIG_WARNING_DISABLE_HPP + +#if defined(_MSC_VER) && (_MSC_VER >= 1400) + // Error 'function': was declared deprecated + // http://msdn2.microsoft.com/en-us/library/ttcz0bys(VS.80).aspx + // This error is emitted when you use some perfectly conforming + // std lib functions in a perfectly correct way, and also by + // some of Microsoft's own std lib code ! +# pragma warning(disable:4996) +#endif +#if defined(__INTEL_COMPILER) || defined(__ICL) + // As above: gives warning when a "deprecated" + // std library function is encountered. +# pragma warning(disable:1786) +#endif + +#endif // BOOST_CONFIG_WARNING_DISABLE_HPP diff --git a/third-party/boost/boost/config/workaround.hpp b/third-party/boost/boost/config/workaround.hpp new file mode 100644 index 000000000..fca8f3ab7 --- /dev/null +++ b/third-party/boost/boost/config/workaround.hpp @@ -0,0 +1,279 @@ +// Copyright David Abrahams 2002. +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_CONFIG_WORKAROUND_HPP +#define BOOST_CONFIG_WORKAROUND_HPP + +// Compiler/library version workaround macro +// +// Usage: +// +// #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) +// // workaround for eVC4 and VC6 +// ... // workaround code here +// #endif +// +// When BOOST_STRICT_CONFIG is defined, expands to 0. Otherwise, the +// first argument must be undefined or expand to a numeric +// value. The above expands to: +// +// (BOOST_MSVC) != 0 && (BOOST_MSVC) < 1300 +// +// When used for workarounds that apply to the latest known version +// and all earlier versions of a compiler, the following convention +// should be observed: +// +// #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1301)) +// +// The version number in this case corresponds to the last version in +// which the workaround was known to have been required. When +// BOOST_DETECT_OUTDATED_WORKAROUNDS is not the defined, the macro +// BOOST_TESTED_AT(x) expands to "!= 0", which effectively activates +// the workaround for any version of the compiler. When +// BOOST_DETECT_OUTDATED_WORKAROUNDS is defined, a compiler warning or +// error will be issued if the compiler version exceeds the argument +// to BOOST_TESTED_AT(). This can be used to locate workarounds which +// may be obsoleted by newer versions. + +#ifndef BOOST_STRICT_CONFIG + +#include + +#ifndef __BORLANDC__ +#define __BORLANDC___WORKAROUND_GUARD 1 +#else +#define __BORLANDC___WORKAROUND_GUARD 0 +#endif +#ifndef __CODEGEARC__ +#define __CODEGEARC___WORKAROUND_GUARD 1 +#else +#define __CODEGEARC___WORKAROUND_GUARD 0 +#endif +#ifndef _MSC_VER +#define _MSC_VER_WORKAROUND_GUARD 1 +#else +#define _MSC_VER_WORKAROUND_GUARD 0 +#endif +#ifndef _MSC_FULL_VER +#define _MSC_FULL_VER_WORKAROUND_GUARD 1 +#else +#define _MSC_FULL_VER_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_MSVC +#define BOOST_MSVC_WORKAROUND_GUARD 1 +#else +#define BOOST_MSVC_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_MSVC_FULL_VER +#define BOOST_MSVC_FULL_VER_WORKAROUND_GUARD 1 +#else +#define BOOST_MSVC_FULL_VER_WORKAROUND_GUARD 0 +#endif +#ifndef __GNUC__ +#define __GNUC___WORKAROUND_GUARD 1 +#else +#define __GNUC___WORKAROUND_GUARD 0 +#endif +#ifndef __GNUC_MINOR__ +#define __GNUC_MINOR___WORKAROUND_GUARD 1 +#else +#define __GNUC_MINOR___WORKAROUND_GUARD 0 +#endif +#ifndef __GNUC_PATCHLEVEL__ +#define __GNUC_PATCHLEVEL___WORKAROUND_GUARD 1 +#else +#define __GNUC_PATCHLEVEL___WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_GCC +#define BOOST_GCC_WORKAROUND_GUARD 1 +#define BOOST_GCC_VERSION_WORKAROUND_GUARD 1 +#else +#define BOOST_GCC_WORKAROUND_GUARD 0 +#define BOOST_GCC_VERSION_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_XLCPP_ZOS +#define BOOST_XLCPP_ZOS_WORKAROUND_GUARD 1 +#else +#define BOOST_XLCPP_ZOS_WORKAROUND_GUARD 0 +#endif +#ifndef __IBMCPP__ +#define __IBMCPP___WORKAROUND_GUARD 1 +#else +#define __IBMCPP___WORKAROUND_GUARD 0 +#endif +#ifndef __SUNPRO_CC +#define __SUNPRO_CC_WORKAROUND_GUARD 1 +#else +#define __SUNPRO_CC_WORKAROUND_GUARD 0 +#endif +#ifndef __DECCXX_VER +#define __DECCXX_VER_WORKAROUND_GUARD 1 +#else +#define __DECCXX_VER_WORKAROUND_GUARD 0 +#endif +#ifndef __MWERKS__ +#define __MWERKS___WORKAROUND_GUARD 1 +#else +#define __MWERKS___WORKAROUND_GUARD 0 +#endif +#ifndef __EDG__ +#define __EDG___WORKAROUND_GUARD 1 +#else +#define __EDG___WORKAROUND_GUARD 0 +#endif +#ifndef __EDG_VERSION__ +#define __EDG_VERSION___WORKAROUND_GUARD 1 +#else +#define __EDG_VERSION___WORKAROUND_GUARD 0 +#endif +#ifndef __HP_aCC +#define __HP_aCC_WORKAROUND_GUARD 1 +#else +#define __HP_aCC_WORKAROUND_GUARD 0 +#endif +#ifndef __hpxstd98 +#define __hpxstd98_WORKAROUND_GUARD 1 +#else +#define __hpxstd98_WORKAROUND_GUARD 0 +#endif +#ifndef _CRAYC +#define _CRAYC_WORKAROUND_GUARD 1 +#else +#define _CRAYC_WORKAROUND_GUARD 0 +#endif +#ifndef __DMC__ +#define __DMC___WORKAROUND_GUARD 1 +#else +#define __DMC___WORKAROUND_GUARD 0 +#endif +#ifndef MPW_CPLUS +#define MPW_CPLUS_WORKAROUND_GUARD 1 +#else +#define MPW_CPLUS_WORKAROUND_GUARD 0 +#endif +#ifndef __COMO__ +#define __COMO___WORKAROUND_GUARD 1 +#else +#define __COMO___WORKAROUND_GUARD 0 +#endif +#ifndef __COMO_VERSION__ +#define __COMO_VERSION___WORKAROUND_GUARD 1 +#else +#define __COMO_VERSION___WORKAROUND_GUARD 0 +#endif +#ifndef __INTEL_COMPILER +#define __INTEL_COMPILER_WORKAROUND_GUARD 1 +#else +#define __INTEL_COMPILER_WORKAROUND_GUARD 0 +#endif +#ifndef __ICL +#define __ICL_WORKAROUND_GUARD 1 +#else +#define __ICL_WORKAROUND_GUARD 0 +#endif +#ifndef _COMPILER_VERSION +#define _COMPILER_VERSION_WORKAROUND_GUARD 1 +#else +#define _COMPILER_VERSION_WORKAROUND_GUARD 0 +#endif + +#ifndef _RWSTD_VER +#define _RWSTD_VER_WORKAROUND_GUARD 1 +#else +#define _RWSTD_VER_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_RWSTD_VER +#define BOOST_RWSTD_VER_WORKAROUND_GUARD 1 +#else +#define BOOST_RWSTD_VER_WORKAROUND_GUARD 0 +#endif +#ifndef __GLIBCPP__ +#define __GLIBCPP___WORKAROUND_GUARD 1 +#else +#define __GLIBCPP___WORKAROUND_GUARD 0 +#endif +#ifndef _GLIBCXX_USE_C99_FP_MACROS_DYNAMIC +#define _GLIBCXX_USE_C99_FP_MACROS_DYNAMIC_WORKAROUND_GUARD 1 +#else +#define _GLIBCXX_USE_C99_FP_MACROS_DYNAMIC_WORKAROUND_GUARD 0 +#endif +#ifndef __SGI_STL_PORT +#define __SGI_STL_PORT_WORKAROUND_GUARD 1 +#else +#define __SGI_STL_PORT_WORKAROUND_GUARD 0 +#endif +#ifndef _STLPORT_VERSION +#define _STLPORT_VERSION_WORKAROUND_GUARD 1 +#else +#define _STLPORT_VERSION_WORKAROUND_GUARD 0 +#endif +#ifndef __LIBCOMO_VERSION__ +#define __LIBCOMO_VERSION___WORKAROUND_GUARD 1 +#else +#define __LIBCOMO_VERSION___WORKAROUND_GUARD 0 +#endif +#ifndef _CPPLIB_VER +#define _CPPLIB_VER_WORKAROUND_GUARD 1 +#else +#define _CPPLIB_VER_WORKAROUND_GUARD 0 +#endif + +#ifndef BOOST_INTEL_CXX_VERSION +#define BOOST_INTEL_CXX_VERSION_WORKAROUND_GUARD 1 +#else +#define BOOST_INTEL_CXX_VERSION_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_INTEL_WIN +#define BOOST_INTEL_WIN_WORKAROUND_GUARD 1 +#else +#define BOOST_INTEL_WIN_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_DINKUMWARE_STDLIB +#define BOOST_DINKUMWARE_STDLIB_WORKAROUND_GUARD 1 +#else +#define BOOST_DINKUMWARE_STDLIB_WORKAROUND_GUARD 0 +#endif +#ifndef BOOST_INTEL +#define BOOST_INTEL_WORKAROUND_GUARD 1 +#else +#define BOOST_INTEL_WORKAROUND_GUARD 0 +#endif +// Always define to zero, if it's used it'll be defined my MPL: +#define BOOST_MPL_CFG_GCC_WORKAROUND_GUARD 0 + +#define BOOST_WORKAROUND(symbol, test) \ + ((symbol ## _WORKAROUND_GUARD + 0 == 0) && \ + (symbol != 0) && (1 % (( (symbol test) ) + 1))) +// ^ ^ ^ ^ +// The extra level of parenthesis nesting above, along with the +// BOOST_OPEN_PAREN indirection below, is required to satisfy the +// broken preprocessor in MWCW 8.3 and earlier. +// +// The basic mechanism works as follows: +// (symbol test) + 1 => if (symbol test) then 2 else 1 +// 1 % ((symbol test) + 1) => if (symbol test) then 1 else 0 +// +// The complication with % is for cooperation with BOOST_TESTED_AT(). +// When "test" is BOOST_TESTED_AT(x) and +// BOOST_DETECT_OUTDATED_WORKAROUNDS is #defined, +// +// symbol test => if (symbol <= x) then 1 else -1 +// (symbol test) + 1 => if (symbol <= x) then 2 else 0 +// 1 % ((symbol test) + 1) => if (symbol <= x) then 1 else divide-by-zero +// + +#ifdef BOOST_DETECT_OUTDATED_WORKAROUNDS +# define BOOST_OPEN_PAREN ( +# define BOOST_TESTED_AT(value) > value) ?(-1): BOOST_OPEN_PAREN 1 +#else +# define BOOST_TESTED_AT(value) != ((value)-(value)) +#endif + +#else + +#define BOOST_WORKAROUND(symbol, test) 0 + +#endif + +#endif // BOOST_CONFIG_WORKAROUND_HPP diff --git a/third-party/boost/boost/container/adaptive_pool.hpp b/third-party/boost/boost/container/adaptive_pool.hpp new file mode 100644 index 000000000..d1d77bcad --- /dev/null +++ b/third-party/boost/boost/container/adaptive_pool.hpp @@ -0,0 +1,609 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ADAPTIVE_POOL_HPP +#define BOOST_CONTAINER_ADAPTIVE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +namespace boost { +namespace container { + +//!An STL node allocator that uses a modified DLMalloc as memory +//!source. +//! +//!This node allocator shares a segregated storage between all instances +//!of adaptive_pool with equal sizeof(T). +//! +//!NodesPerBlock is the number of nodes allocated at once when the allocator +//!needs runs out of nodes. MaxFreeBlocks is the maximum number of totally free blocks +//!that the adaptive node pool will hold. The rest of the totally free blocks will be +//!deallocated to the memory manager. +//! +//!OverheadPercent is the (approximated) maximum size overhead (1-20%) of the allocator: +//!(memory usable for nodes / total memory allocated from the memory allocator) +template < class T + , std::size_t NodesPerBlock BOOST_CONTAINER_DOCONLY(= ADP_nodes_per_block) + , std::size_t MaxFreeBlocks BOOST_CONTAINER_DOCONLY(= ADP_max_free_blocks) + , std::size_t OverheadPercent BOOST_CONTAINER_DOCONLY(= ADP_overhead_percent) + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I unsigned Version) + > +class adaptive_pool +{ + //!If Version is 1, the allocator is a STL conforming allocator. If Version is 2, + //!the allocator offers advanced expand in place and burst allocation capabilities. + public: + typedef unsigned int allocation_type; + typedef adaptive_pool + self_t; + + static const std::size_t nodes_per_block = NodesPerBlock; + static const std::size_t max_free_blocks = MaxFreeBlocks; + static const std::size_t overhead_percent = OverheadPercent; + static const std::size_t real_nodes_per_block = NodesPerBlock; + + BOOST_CONTAINER_DOCIGN(BOOST_STATIC_ASSERT((Version <=2))); + + public: + //------- + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef typename ::boost::container:: + dtl::unvoid_ref::type reference; + typedef typename ::boost::container:: + dtl::unvoid_ref::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::container::dtl:: + version_type version; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::dtl:: + basic_multiallocation_chain multiallocation_chain_void; + typedef boost::container::dtl:: + transform_multiallocation_chain + multiallocation_chain; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //!Obtains adaptive_pool from + //!adaptive_pool + template + struct rebind + { + typedef adaptive_pool + < T2 + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version) + > other; + }; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + //!Not assignable from related adaptive_pool + template + adaptive_pool& operator= + (const adaptive_pool&); + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + //!Default constructor + adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Copy constructor from other adaptive_pool. + adaptive_pool(const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Copy constructor from related adaptive_pool. + template + adaptive_pool + (const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Destructor + ~adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return size_type(-1)/sizeof(T); } + + //!Allocate memory for an array of count elements. + //!Throws std::bad_alloc if there is no enough memory + pointer allocate(size_type count, const void * = 0) + { + if(BOOST_UNLIKELY(count > this->max_size())) + boost::container::throw_bad_alloc(); + + if(Version == 1 && count == 1){ + typedef typename dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + return pointer(static_cast(singleton_t::instance().allocate_node())); + } + else{ + return static_cast(dlmalloc_malloc(count*sizeof(T))); + } + } + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW + { + (void)count; + if(Version == 1 && count == 1){ + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + singleton_t::instance().deallocate_node(ptr); + } + else{ + dlmalloc_free(ptr); + } + } + + pointer allocation_command(allocation_type command, + size_type limit_size, + size_type &prefer_in_recvd_out_size, + pointer &reuse) + { + pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); + if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION))) + boost::container::throw_bad_alloc(); + return ret; + } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW + { return dlmalloc_size(p); } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws bad_alloc if there is no enough memory + pointer allocate_one() + { + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + return (pointer)singleton_t::instance().allocate_node(); + } + + //!Allocates many elements of size == 1. + //!Elements must be individually deallocated with deallocate_one() + void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) + { + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + singleton_t::instance().allocate_nodes(num_elements, static_cast(chain)); + //typename shared_pool_t::multiallocation_chain ch; + //singleton_t::instance().allocate_nodes(num_elements, ch); + //chain.incorporate_after + //(chain.before_begin(), (T*)&*ch.begin(), (T*)&*ch.last(), ch.size()); + } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW + { + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + singleton_t::instance().deallocate_node(p); + } + + void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + { + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + //typename shared_pool_t::multiallocation_chain ch(&*chain.begin(), &*chain.last(), chain.size()); + //singleton_t::instance().deallocate_nodes(ch); + singleton_t::instance().deallocate_nodes(chain); + } + + //!Allocates many elements of size elem_size. + //!Elements must be individually deallocated with deallocate() + void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 ));/* + dlmalloc_memchain ch; + BOOST_CONTAINER_MEMCHAIN_INIT(&ch); + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + boost::container::throw_bad_alloc(); + } + chain.incorporate_after(chain.before_begin() + ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) + ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) + ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes + (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + boost::container::throw_bad_alloc(); + } + } + + //!Allocates n_elements elements, each one of size elem_sizes[i] + //!Elements must be individually deallocated with deallocate() + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 ));/* + dlmalloc_memchain ch; + BOOST_CONTAINER_MEMCHAIN_INIT(&ch); + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch))){ + boost::container::throw_bad_alloc(); + } + chain.incorporate_after(chain.before_begin() + ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) + ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) + ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) );*/ + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays + (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + boost::container::throw_bad_alloc(); + } + } + + void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + {/* + dlmalloc_memchain ch; + void *beg(&*chain.begin()), *last(&*chain.last()); + size_t size(chain.size()); + BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); + dlmalloc_multidealloc(&ch);*/ + dlmalloc_multidealloc(reinterpret_cast(&chain)); + } + + //!Deallocates all free blocks of the pool + static void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW + { + typedef dtl::shared_adaptive_node_pool + shared_pool_t; + typedef dtl::singleton_default singleton_t; + singleton_t::instance().deallocate_free_blocks(); + } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(adaptive_pool &, adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!An allocator always compares to true, as memory allocated with one + //!instance can be deallocated by another instance + friend bool operator==(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return true; } + + //!An allocator always compares to false, as memory allocated with one + //!instance can be deallocated by another instance + friend bool operator!=(const adaptive_pool &, const adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return false; } + + private: + pointer priv_allocation_command + (allocation_type command, std::size_t limit_size + ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr) + { + std::size_t const preferred_size = prefer_in_recvd_out_size; + dlmalloc_command_ret_t ret = {0 , 0}; + if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){ + return pointer(); + } + std::size_t l_size = limit_size*sizeof(T); + std::size_t p_size = preferred_size*sizeof(T); + std::size_t r_size; + { + void* reuse_ptr_void = reuse_ptr; + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; + } + prefer_in_recvd_out_size = r_size/sizeof(T); + return (pointer)ret.first; + } +}; + + + + + + + + + + + + + + + + + + + + +template < class T + , std::size_t NodesPerBlock = ADP_nodes_per_block + , std::size_t MaxFreeBlocks = ADP_max_free_blocks + , std::size_t OverheadPercent = ADP_overhead_percent + , unsigned Version = 2 + > +class private_adaptive_pool +{ + //!If Version is 1, the allocator is a STL conforming allocator. If Version is 2, + //!the allocator offers advanced expand in place and burst allocation capabilities. + public: + typedef unsigned int allocation_type; + typedef private_adaptive_pool + self_t; + + static const std::size_t nodes_per_block = NodesPerBlock; + static const std::size_t max_free_blocks = MaxFreeBlocks; + static const std::size_t overhead_percent = OverheadPercent; + static const std::size_t real_nodes_per_block = NodesPerBlock; + + BOOST_CONTAINER_DOCIGN(BOOST_STATIC_ASSERT((Version <=2))); + + typedef dtl::private_adaptive_node_pool + pool_t; + pool_t m_pool; + + public: + //------- + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef typename ::boost::container:: + dtl::unvoid_ref::type reference; + typedef typename ::boost::container:: + dtl::unvoid_ref::type const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::container::dtl:: + version_type version; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::dtl:: + basic_multiallocation_chain multiallocation_chain_void; + typedef boost::container::dtl:: + transform_multiallocation_chain + multiallocation_chain; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //!Obtains private_adaptive_pool from + //!private_adaptive_pool + template + struct rebind + { + typedef private_adaptive_pool + < T2 + , NodesPerBlock + , MaxFreeBlocks + , OverheadPercent + BOOST_CONTAINER_DOCIGN(BOOST_MOVE_I Version) + > other; + }; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + //!Not assignable from related private_adaptive_pool + template + private_adaptive_pool& operator= + (const private_adaptive_pool&); + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + //!Default constructor + private_adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Copy constructor from other private_adaptive_pool. + private_adaptive_pool(const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Copy constructor from related private_adaptive_pool. + template + private_adaptive_pool + (const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Destructor + ~private_adaptive_pool() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Returns the number of elements that could be allocated. + //!Never throws + size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return size_type(-1)/sizeof(T); } + + //!Allocate memory for an array of count elements. + //!Throws std::bad_alloc if there is no enough memory + pointer allocate(size_type count, const void * = 0) + { + if(BOOST_UNLIKELY(count > this->max_size())) + boost::container::throw_bad_alloc(); + + if(Version == 1 && count == 1){ + return pointer(static_cast(m_pool.allocate_node())); + } + else{ + return static_cast(dlmalloc_malloc(count*sizeof(T))); + } + } + + //!Deallocate allocated memory. + //!Never throws + void deallocate(const pointer &ptr, size_type count) BOOST_NOEXCEPT_OR_NOTHROW + { + (void)count; + if(Version == 1 && count == 1){ + m_pool.deallocate_node(ptr); + } + else{ + dlmalloc_free(ptr); + } + } + + pointer allocation_command(allocation_type command, + size_type limit_size, + size_type &prefer_in_recvd_out_size, + pointer &reuse) + { + pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); + if(BOOST_UNLIKELY(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION))) + boost::container::throw_bad_alloc(); + return ret; + } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW + { return dlmalloc_size(p); } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws bad_alloc if there is no enough memory + pointer allocate_one() + { + return (pointer)m_pool.allocate_node(); + } + + //!Allocates many elements of size == 1. + //!Elements must be individually deallocated with deallocate_one() + void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) + { + m_pool.allocate_nodes(num_elements, static_cast(chain)); + } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one(). Never throws + void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW + { + m_pool.deallocate_node(p); + } + + void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + { + m_pool.deallocate_nodes(chain); + } + + //!Allocates many elements of size elem_size. + //!Elements must be individually deallocated with deallocate() + void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + if(BOOST_UNLIKELY(!dlmalloc_multialloc_nodes + (n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + boost::container::throw_bad_alloc(); + } + } + + //!Allocates n_elements elements, each one of size elem_sizes[i] + //!Elements must be individually deallocated with deallocate() + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + if(BOOST_UNLIKELY(!dlmalloc_multialloc_arrays + (n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain)))){ + boost::container::throw_bad_alloc(); + } + } + + void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + { + dlmalloc_multidealloc(reinterpret_cast(&chain)); + } + + //!Deallocates all free blocks of the pool + void deallocate_free_blocks() BOOST_NOEXCEPT_OR_NOTHROW + { + m_pool.deallocate_free_blocks(); + } + + //!Swaps allocators. Does not throw. If each allocator is placed in a + //!different memory segment, the result is undefined. + friend void swap(private_adaptive_pool &, private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!An allocator always compares to true, as memory allocated with one + //!instance can be deallocated by another instance + friend bool operator==(const private_adaptive_pool &, const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return true; } + + //!An allocator always compares to false, as memory allocated with one + //!instance can be deallocated by another instance + friend bool operator!=(const private_adaptive_pool &, const private_adaptive_pool &) BOOST_NOEXCEPT_OR_NOTHROW + { return false; } + + private: + pointer priv_allocation_command + (allocation_type command, std::size_t limit_size + ,size_type &prefer_in_recvd_out_size, pointer &reuse_ptr) + { + std::size_t const preferred_size = prefer_in_recvd_out_size; + dlmalloc_command_ret_t ret = {0 , 0}; + if(BOOST_UNLIKELY(limit_size > this->max_size() || preferred_size > this->max_size())){ + return pointer(); + } + std::size_t l_size = limit_size*sizeof(T); + std::size_t p_size = preferred_size*sizeof(T); + std::size_t r_size; + { + void* reuse_ptr_void = reuse_ptr; + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; + } + prefer_in_recvd_out_size = r_size/sizeof(T); + return (pointer)ret.first; + } +}; + +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_ADAPTIVE_POOL_HPP diff --git a/third-party/boost/boost/container/allocator.hpp b/third-party/boost/boost/container/allocator.hpp new file mode 100644 index 000000000..aef620ce5 --- /dev/null +++ b/third-party/boost/boost/container/allocator.hpp @@ -0,0 +1,369 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ALLOCATOR_HPP +#define BOOST_CONTAINER_ALLOCATOR_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//!\file + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +class allocator +{ + typedef allocator self_t; + public: + typedef void value_type; + typedef void * pointer; + typedef const void* const_pointer; + typedef int & reference; + typedef const int & const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef boost::container::dtl:: + version_type version; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::dtl:: + basic_multiallocation_chain multiallocation_chain; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //!Obtains an allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef allocator< T2 + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + , Version, AllocationDisableMask + #endif + > other; + }; + + //!Default constructor + //!Never throws + allocator() + {} + + //!Constructor from other allocator. + //!Never throws + allocator(const allocator &) + {} + + //!Constructor from related allocator. + //!Never throws + template + allocator(const allocator &) + {} +}; + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! This class is an extended STL-compatible that offers advanced allocation mechanism +//!(in-place expansion, shrinking, burst-allocation...) +//! +//! This allocator is a wrapper around a modified DLmalloc. +//! If Version is 1, the allocator is a STL conforming allocator. If Version is 2, +//! the allocator offers advanced expand in place and burst allocation capabilities. +//! +//! AllocationDisableMask works only if Version is 2 and it can be an inclusive OR +//! of allocation types the user wants to disable. +template< class T + , unsigned Version BOOST_CONTAINER_DOCONLY(=2) + , unsigned int AllocationDisableMask BOOST_CONTAINER_DOCONLY(=0)> +class allocator +{ + typedef unsigned int allocation_type; + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + + //Self type + typedef allocator self_t; + + //Not assignable from related allocator + template + allocator& operator=(const allocator&); + + static const unsigned int ForbiddenMask = + BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BWD | BOOST_CONTAINER_EXPAND_FWD ; + + //The mask can't disable all the allocation types + BOOST_STATIC_ASSERT(( (AllocationDisableMask & ForbiddenMask) != ForbiddenMask )); + + //The mask is only valid for version 2 allocators + BOOST_STATIC_ASSERT(( Version != 1 || (AllocationDisableMask == 0) )); + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + typedef T value_type; + typedef T * pointer; + typedef const T * const_pointer; + typedef T & reference; + typedef const T & const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + typedef boost::container::dtl:: + version_type version; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef boost::container::dtl:: + basic_multiallocation_chain void_multiallocation_chain; + + typedef boost::container::dtl:: + transform_multiallocation_chain + multiallocation_chain; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + //!Obtains an allocator that allocates + //!objects of type T2 + template + struct rebind + { + typedef allocator other; + }; + + //!Default constructor + //!Never throws + allocator() BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Constructor from other allocator. + //!Never throws + allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Constructor from related allocator. + //!Never throws + template + allocator(const allocator &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!Allocates memory for an array of count elements. + //!Throws std::bad_alloc if there is no enough memory + //!If Version is 2, this allocated memory can only be deallocated + //!with deallocate() or (for Version == 2) deallocate_many() + pointer allocate(size_type count, const void * hint= 0) + { + (void)hint; + if(count > this->max_size()) + boost::container::throw_bad_alloc(); + void *ret = dlmalloc_malloc(count*sizeof(T)); + if(!ret) + boost::container::throw_bad_alloc(); + return static_cast(ret); + } + + //!Deallocates previously allocated memory. + //!Never throws + BOOST_CONTAINER_FORCEINLINE void deallocate(pointer ptr, size_type) BOOST_NOEXCEPT_OR_NOTHROW + { dlmalloc_free(ptr); } + + //!Returns the maximum number of elements that could be allocated. + //!Never throws + BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return size_type(-1)/sizeof(T); } + + //!Swaps two allocators, does nothing + //!because this allocator is stateless + BOOST_CONTAINER_FORCEINLINE friend void swap(self_t &, self_t &) BOOST_NOEXCEPT_OR_NOTHROW + {} + + //!An allocator always compares to true, as memory allocated with one + //!instance can be deallocated by another instance + friend bool operator==(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW + { return true; } + + //!An allocator always compares to false, as memory allocated with one + //!instance can be deallocated by another instance + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const allocator &, const allocator &) BOOST_NOEXCEPT_OR_NOTHROW + { return false; } + + //!An advanced function that offers in-place expansion shrink to fit and new allocation + //!capabilities. Memory allocated with this function can only be deallocated with deallocate() + //!or deallocate_many(). + //!This function is available only with Version == 2 + pointer allocation_command(allocation_type command, + size_type limit_size, + size_type &prefer_in_recvd_out_size, + pointer &reuse) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + const allocation_type mask(AllocationDisableMask); + command &= ~mask; + pointer ret = this->priv_allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); + if(!ret && !(command & BOOST_CONTAINER_NOTHROW_ALLOCATION)) + boost::container::throw_bad_alloc(); + return ret; + } + + //!Returns maximum the number of objects the previously allocated memory + //!pointed by p can hold. + //!Memory must not have been allocated with + //!allocate_one or allocate_individual. + //!This function is available only with Version == 2 + size_type size(pointer p) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_STATIC_ASSERT(( Version > 1 )); + return dlmalloc_size(p); + } + + //!Allocates just one object. Memory allocated with this function + //!must be deallocated only with deallocate_one(). + //!Throws bad_alloc if there is no enough memory + //!This function is available only with Version == 2 + BOOST_CONTAINER_FORCEINLINE pointer allocate_one() + { + BOOST_STATIC_ASSERT(( Version > 1 )); + return this->allocate(1); + } + + //!Allocates many elements of size == 1. + //!Elements must be individually deallocated with deallocate_one() + //!This function is available only with Version == 2 + BOOST_CONTAINER_FORCEINLINE void allocate_individual(std::size_t num_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + this->allocate_many(1, num_elements, chain); + } + + //!Deallocates memory previously allocated with allocate_one(). + //!You should never use deallocate_one to deallocate memory allocated + //!with other functions different from allocate_one() or allocate_individual. + //Never throws + void deallocate_one(pointer p) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_STATIC_ASSERT(( Version > 1 )); + return this->deallocate(p, 1); + } + + //!Deallocates memory allocated with allocate_one() or allocate_individual(). + //!This function is available only with Version == 2 + BOOST_CONTAINER_FORCEINLINE void deallocate_individual(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_STATIC_ASSERT(( Version > 1 )); + return this->deallocate_many(chain); + } + + //!Allocates many elements of size elem_size. + //!Elements must be individually deallocated with deallocate() + //!This function is available only with Version == 2 + void allocate_many(size_type elem_size, std::size_t n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + dlmalloc_memchain ch; + BOOST_CONTAINER_MEMCHAIN_INIT(&ch); + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + boost::container::throw_bad_alloc(); + } + chain.incorporate_after(chain.before_begin() + ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) + ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) + ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); +/* + if(!dlmalloc_multialloc_nodes(n_elements, elem_size*sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + boost::container::throw_bad_alloc(); + }*/ + } + + //!Allocates n_elements elements, each one of size elem_sizes[i] + //!Elements must be individually deallocated with deallocate() + //!This function is available only with Version == 2 + void allocate_many(const size_type *elem_sizes, size_type n_elements, multiallocation_chain &chain) + { + BOOST_STATIC_ASSERT(( Version > 1 )); + dlmalloc_memchain ch; + BOOST_CONTAINER_MEMCHAIN_INIT(&ch); + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, &ch)){ + boost::container::throw_bad_alloc(); + } + chain.incorporate_after(chain.before_begin() + ,(T*)BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(&ch) + ,(T*)BOOST_CONTAINER_MEMCHAIN_LASTMEM(&ch) + ,BOOST_CONTAINER_MEMCHAIN_SIZE(&ch) ); + /* + if(!dlmalloc_multialloc_arrays(n_elements, elem_sizes, sizeof(T), DL_MULTIALLOC_DEFAULT_CONTIGUOUS, reinterpret_cast(&chain))){ + boost::container::throw_bad_alloc(); + }*/ + } + + //!Deallocates several elements allocated by + //!allocate_many(), allocate(), or allocation_command(). + //!This function is available only with Version == 2 + void deallocate_many(multiallocation_chain &chain) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_STATIC_ASSERT(( Version > 1 )); + dlmalloc_memchain ch; + void *beg(&*chain.begin()), *last(&*chain.last()); + size_t size(chain.size()); + BOOST_CONTAINER_MEMCHAIN_INIT_FROM(&ch, beg, last, size); + dlmalloc_multidealloc(&ch); + //dlmalloc_multidealloc(reinterpret_cast(&chain)); + } + + private: + + pointer priv_allocation_command + (allocation_type command, std::size_t limit_size + ,size_type &prefer_in_recvd_out_size + ,pointer &reuse_ptr) + { + std::size_t const preferred_size = prefer_in_recvd_out_size; + dlmalloc_command_ret_t ret = {0 , 0}; + if((limit_size > this->max_size()) | (preferred_size > this->max_size())){ + return pointer(); + } + std::size_t l_size = limit_size*sizeof(T); + std::size_t p_size = preferred_size*sizeof(T); + std::size_t r_size; + { + void* reuse_ptr_void = reuse_ptr; + ret = dlmalloc_allocation_command(command, sizeof(T), l_size, p_size, &r_size, reuse_ptr_void); + reuse_ptr = ret.second ? static_cast(reuse_ptr_void) : 0; + } + prefer_in_recvd_out_size = r_size/sizeof(T); + return (pointer)ret.first; + } +}; + +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_ALLOCATOR_HPP + diff --git a/third-party/boost/boost/container/allocator_traits.hpp b/third-party/boost/boost/container/allocator_traits.hpp new file mode 100644 index 000000000..8cfb0378b --- /dev/null +++ b/third-party/boost/boost/container/allocator_traits.hpp @@ -0,0 +1,493 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Pablo Halpern 2009. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP +#define BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// container +#include +#include +#include //is_empty +#include +#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP +#include +#endif +// intrusive +#include +#include +// move +#include +// move/detail +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +// other boost +#include + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME allocate +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 2 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 2 +#include + +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME destroy +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 1 +#include + +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME construct +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_BEG namespace boost { namespace container { namespace dtl { +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_NS_END }}} +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MIN 1 +#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 9 +#include + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +class small_vector_allocator; + +namespace allocator_traits_detail { + +BOOST_INTRUSIVE_HAS_STATIC_MEMBER_FUNC_SIGNATURE(has_max_size, max_size) +BOOST_INTRUSIVE_HAS_STATIC_MEMBER_FUNC_SIGNATURE(has_select_on_container_copy_construction, select_on_container_copy_construction) + +} //namespace allocator_traits_detail { + +namespace dtl { + +//workaround needed for C++03 compilers with no construct() +//supporting rvalue references +template +struct is_std_allocator +{ static const bool value = false; }; + +template +struct is_std_allocator< std::allocator > +{ static const bool value = true; }; + +template +struct is_std_allocator< small_vector_allocator > > +{ static const bool value = true; }; + +template +struct is_not_std_allocator +{ static const bool value = !is_std_allocator::value; }; + +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(pointer) +BOOST_INTRUSIVE_INSTANTIATE_EVAL_DEFAULT_TYPE_TMPLT(const_pointer) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(reference) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(const_reference) +BOOST_INTRUSIVE_INSTANTIATE_EVAL_DEFAULT_TYPE_TMPLT(void_pointer) +BOOST_INTRUSIVE_INSTANTIATE_EVAL_DEFAULT_TYPE_TMPLT(const_void_pointer) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(size_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(propagate_on_container_swap) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_always_equal) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(difference_type) +BOOST_INTRUSIVE_INSTANTIATE_DEFAULT_TYPE_TMPLT(is_partially_propagable) + +} //namespace dtl { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! The class template allocator_traits supplies a uniform interface to all allocator types. +//! This class is a C++03-compatible implementation of std::allocator_traits +template +struct allocator_traits +{ + //allocator_type + typedef Allocator allocator_type; + //value_type + typedef typename allocator_type::value_type value_type; + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Allocator::pointer if such a type exists; otherwise, value_type* + //! + typedef unspecified pointer; + //! Allocator::const_pointer if such a type exists ; otherwise, pointer_traits::rebind::rebind. + //! + typedef see_documentation void_pointer; + //! Allocator::const_void_pointer if such a type exists ; otherwise, pointer_traits::rebind::difference_type. + //! + typedef see_documentation difference_type; + //! Allocator::size_type if such a type exists ; otherwise, make_unsigned::type + //! + typedef see_documentation size_type; + //! Allocator::propagate_on_container_copy_assignment if such a type exists, otherwise a type + //! with an internal constant static boolean member value == false. + typedef see_documentation propagate_on_container_copy_assignment; + //! Allocator::propagate_on_container_move_assignment if such a type exists, otherwise a type + //! with an internal constant static boolean member value == false. + typedef see_documentation propagate_on_container_move_assignment; + //! Allocator::propagate_on_container_swap if such a type exists, otherwise a type + //! with an internal constant static boolean member value == false. + typedef see_documentation propagate_on_container_swap; + //! Allocator::is_always_equal if such a type exists, otherwise a type + //! with an internal constant static boolean member value == is_empty::value + typedef see_documentation is_always_equal; + //! Allocator::is_partially_propagable if such a type exists, otherwise a type + //! with an internal constant static boolean member value == false + //! Note: Non-standard extension used to implement `small_vector_allocator`. + typedef see_documentation is_partially_propagable; + //! Defines an allocator: Allocator::rebind::other if such a type exists; otherwise, Allocator + //! if Allocator is a class template instantiation of the form Allocator, where Args is zero or + //! more type arguments ; otherwise, the instantiation of rebind_alloc is ill-formed. + //! + //! In C++03 compilers rebind_alloc is a struct derived from an allocator + //! deduced by previously detailed rules. + template using rebind_alloc = see_documentation; + + //! In C++03 compilers rebind_traits is a struct derived from + //! allocator_traits, where OtherAlloc is + //! the allocator deduced by rules explained in rebind_alloc. + template using rebind_traits = allocator_traits >; + + //! Non-standard extension: Portable allocator rebind for C++03 and C++11 compilers. + //! type is an allocator related to Allocator deduced deduced by rules explained in rebind_alloc. + template + struct portable_rebind_alloc + { typedef see_documentation type; }; + #else + //pointer + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + pointer, value_type*) + pointer; + //const_pointer + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::dtl::, Allocator, + const_pointer, typename boost::intrusive::pointer_traits::template + rebind_pointer) + const_pointer; + //reference + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + reference, typename dtl::unvoid_ref::type) + reference; + //const_reference + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + const_reference, typename dtl::unvoid_ref::type) + const_reference; + //void_pointer + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::dtl::, Allocator, + void_pointer, typename boost::intrusive::pointer_traits::template + rebind_pointer) + void_pointer; + //const_void_pointer + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_EVAL_DEFAULT(boost::container::dtl::, Allocator, + const_void_pointer, typename boost::intrusive::pointer_traits::template + rebind_pointer) + const_void_pointer; + //difference_type + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + difference_type, std::ptrdiff_t) + difference_type; + //size_type + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + size_type, std::size_t) + size_type; + //propagate_on_container_copy_assignment + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + propagate_on_container_copy_assignment, dtl::false_type) + propagate_on_container_copy_assignment; + //propagate_on_container_move_assignment + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + propagate_on_container_move_assignment, dtl::false_type) + propagate_on_container_move_assignment; + //propagate_on_container_swap + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + propagate_on_container_swap, dtl::false_type) + propagate_on_container_swap; + //is_always_equal + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + is_always_equal, dtl::is_empty) + is_always_equal; + //is_partially_propagable + typedef BOOST_INTRUSIVE_OBTAIN_TYPE_WITH_DEFAULT(boost::container::dtl::, Allocator, + is_partially_propagable, dtl::false_type) + is_partially_propagable; + + //rebind_alloc & rebind_traits + #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + //C++11 + template using rebind_alloc = typename boost::intrusive::pointer_rebind::type; + template using rebind_traits = allocator_traits< rebind_alloc >; + #else // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + //Some workaround for C++03 or C++11 compilers with no template aliases + template + struct rebind_alloc : boost::intrusive::pointer_rebind::type + { + typedef typename boost::intrusive::pointer_rebind::type Base; + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + rebind_alloc(BOOST_FWD_REF(Args)... args) : Base(boost::forward(args)...) {} + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_REBIND_ALLOC(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ + explicit rebind_alloc(BOOST_MOVE_UREF##N) : Base(BOOST_MOVE_FWD##N){}\ + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ALLOCATOR_TRAITS_REBIND_ALLOC) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_REBIND_ALLOC + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + }; + + template + struct rebind_traits + : allocator_traits::type> + {}; + #endif // #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + + //portable_rebind_alloc + template + struct portable_rebind_alloc + { typedef typename boost::intrusive::pointer_rebind::type type; }; + #endif //BOOST_CONTAINER_DOXYGEN_INVOKED + + //! Returns: a.allocate(n) + //! + BOOST_CONTAINER_FORCEINLINE static pointer allocate(Allocator &a, size_type n) + { return a.allocate(n); } + + //! Returns: a.deallocate(p, n) + //! + //! Throws: Nothing + BOOST_CONTAINER_FORCEINLINE static void deallocate(Allocator &a, pointer p, size_type n) + { a.deallocate(p, n); } + + //! Effects: calls a.allocate(n, p) if that call is well-formed; + //! otherwise, invokes a.allocate(n) + BOOST_CONTAINER_FORCEINLINE static pointer allocate(Allocator &a, size_type n, const_void_pointer p) + { + const bool value = boost::container::dtl:: + has_member_function_callable_with_allocate + ::value; + dtl::bool_ flag; + return allocator_traits::priv_allocate(flag, a, n, p); + } + + //! Effects: calls a.destroy(p) if that call is well-formed; + //! otherwise, invokes p->~T(). + template + BOOST_CONTAINER_FORCEINLINE static void destroy(Allocator &a, T*p) BOOST_NOEXCEPT_OR_NOTHROW + { + typedef T* destroy_pointer; + const bool value = boost::container::dtl:: + has_member_function_callable_with_destroy + ::value; + dtl::bool_ flag; + allocator_traits::priv_destroy(flag, a, p); + } + + //! Returns: a.max_size() if that expression is well-formed; otherwise, + //! numeric_limits::max(). + BOOST_CONTAINER_FORCEINLINE static size_type max_size(const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW + { + const bool value = allocator_traits_detail::has_max_size::value; + dtl::bool_ flag; + return allocator_traits::priv_max_size(flag, a); + } + + //! Returns: a.select_on_container_copy_construction() if that expression is well-formed; + //! otherwise, a. + BOOST_CONTAINER_FORCEINLINE static BOOST_CONTAINER_DOC1ST(Allocator, + typename dtl::if_c + < allocator_traits_detail::has_select_on_container_copy_construction::value + BOOST_MOVE_I Allocator BOOST_MOVE_I const Allocator & >::type) + select_on_container_copy_construction(const Allocator &a) + { + const bool value = allocator_traits_detail::has_select_on_container_copy_construction + ::value; + dtl::bool_ flag; + return allocator_traits::priv_select_on_container_copy_construction(flag, a); + } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: calls a.construct(p, std::forward(args)...) if that call is well-formed; + //! otherwise, invokes `placement new` (static_cast(p)) T(std::forward(args)...) + template + BOOST_CONTAINER_FORCEINLINE static void construct(Allocator & a, T* p, BOOST_FWD_REF(Args)... args) + { + static const bool value = ::boost::move_detail::and_ + < dtl::is_not_std_allocator + , boost::container::dtl::has_member_function_callable_with_construct + < Allocator, T*, Args... > + >::value; + dtl::bool_ flag; + allocator_traits::priv_construct(flag, a, p, ::boost::forward(args)...); + } + #endif + + //! Returns: a.storage_is_unpropagable(p) if is_partially_propagable::value is true; otherwise, + //! false. + BOOST_CONTAINER_FORCEINLINE static bool storage_is_unpropagable(const Allocator &a, pointer p) BOOST_NOEXCEPT_OR_NOTHROW + { + dtl::bool_ flag; + return allocator_traits::priv_storage_is_unpropagable(flag, a, p); + } + + //! Returns: true if is_always_equal::value == true, otherwise, + //! a == b. + BOOST_CONTAINER_FORCEINLINE static bool equal(const Allocator &a, const Allocator &b) BOOST_NOEXCEPT_OR_NOTHROW + { + dtl::bool_ flag; + return allocator_traits::priv_equal(flag, a, b); + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + private: + BOOST_CONTAINER_FORCEINLINE static pointer priv_allocate(dtl::true_type, Allocator &a, size_type n, const_void_pointer p) + { return a.allocate(n, p); } + + BOOST_CONTAINER_FORCEINLINE static pointer priv_allocate(dtl::false_type, Allocator &a, size_type n, const_void_pointer) + { return a.allocate(n); } + + template + BOOST_CONTAINER_FORCEINLINE static void priv_destroy(dtl::true_type, Allocator &a, T* p) BOOST_NOEXCEPT_OR_NOTHROW + { a.destroy(p); } + + template + BOOST_CONTAINER_FORCEINLINE static void priv_destroy(dtl::false_type, Allocator &, T* p) BOOST_NOEXCEPT_OR_NOTHROW + { p->~T(); (void)p; } + + BOOST_CONTAINER_FORCEINLINE static size_type priv_max_size(dtl::true_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW + { return a.max_size(); } + + BOOST_CONTAINER_FORCEINLINE static size_type priv_max_size(dtl::false_type, const Allocator &) BOOST_NOEXCEPT_OR_NOTHROW + { return size_type(-1)/sizeof(value_type); } + + BOOST_CONTAINER_FORCEINLINE static Allocator priv_select_on_container_copy_construction(dtl::true_type, const Allocator &a) + { return a.select_on_container_copy_construction(); } + + BOOST_CONTAINER_FORCEINLINE static const Allocator &priv_select_on_container_copy_construction(dtl::false_type, const Allocator &a) BOOST_NOEXCEPT_OR_NOTHROW + { return a; } + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + BOOST_CONTAINER_FORCEINLINE static void priv_construct(dtl::true_type, Allocator &a, T *p, BOOST_FWD_REF(Args) ...args) + { a.construct( p, ::boost::forward(args)...); } + + template + BOOST_CONTAINER_FORCEINLINE static void priv_construct(dtl::false_type, Allocator &, T *p, BOOST_FWD_REF(Args) ...args) + { ::new((void*)p, boost_container_new_t()) T(::boost::forward(args)...); } + #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + public: + + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL(N) \ + template\ + BOOST_CONTAINER_FORCEINLINE static void construct(Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + static const bool value = ::boost::move_detail::and_ \ + < dtl::is_not_std_allocator \ + , boost::container::dtl::has_member_function_callable_with_construct \ + < Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_FWD_T##N > \ + >::value; \ + dtl::bool_ flag;\ + (priv_construct)(flag, a, p BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + }\ + // + BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_CONSTRUCT_IMPL + + private: + ///////////////////////////////// + // priv_construct + ///////////////////////////////// + #define BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL(N) \ + template\ + BOOST_CONTAINER_FORCEINLINE static void priv_construct(dtl::true_type, Allocator &a, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { a.construct( p BOOST_MOVE_I##N BOOST_MOVE_FWD##N ); }\ + \ + template\ + BOOST_CONTAINER_FORCEINLINE static void priv_construct(dtl::false_type, Allocator &, T *p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + { ::new((void*)p, boost_container_new_t()) T(BOOST_MOVE_FWD##N); }\ + // + BOOST_MOVE_ITERATE_0TO8(BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL) + #undef BOOST_CONTAINER_ALLOCATOR_TRAITS_PRIV_CONSTRUCT_IMPL + + #endif // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template + BOOST_CONTAINER_FORCEINLINE static void priv_construct(dtl::false_type, Allocator &, T *p, const ::boost::container::default_init_t&) + { ::new((void*)p, boost_container_new_t()) T; } + + BOOST_CONTAINER_FORCEINLINE static bool priv_storage_is_unpropagable(dtl::true_type, const Allocator &a, pointer p) + { return a.storage_is_unpropagable(p); } + + BOOST_CONTAINER_FORCEINLINE static bool priv_storage_is_unpropagable(dtl::false_type, const Allocator &, pointer) + { return false; } + + BOOST_CONTAINER_FORCEINLINE static bool priv_equal(dtl::true_type, const Allocator &, const Allocator &) + { return true; } + + BOOST_CONTAINER_FORCEINLINE static bool priv_equal(dtl::false_type, const Allocator &a, const Allocator &b) + { return a == b; } + + #endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) +}; + +#if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +template +struct real_allocator +{ + typedef AllocatorOrVoid type; +}; + +template +struct real_allocator +{ + typedef new_allocator type; +}; + +#endif //#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + +} //namespace container { +} //namespace boost { + +#include + +#endif // ! defined(BOOST_CONTAINER_ALLOCATOR_ALLOCATOR_TRAITS_HPP) diff --git a/third-party/boost/boost/container/container_fwd.hpp b/third-party/boost/boost/container/container_fwd.hpp new file mode 100644 index 000000000..b7591cd25 --- /dev/null +++ b/third-party/boost/boost/container/container_fwd.hpp @@ -0,0 +1,290 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP +#define BOOST_CONTAINER_CONTAINER_FWD_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//! \file +//! This header file forward declares the following containers: +//! - boost::container::vector +//! - boost::container::stable_vector +//! - boost::container::static_vector +//! - boost::container::small_vector +//! - boost::container::slist +//! - boost::container::list +//! - boost::container::set +//! - boost::container::multiset +//! - boost::container::map +//! - boost::container::multimap +//! - boost::container::flat_set +//! - boost::container::flat_multiset +//! - boost::container::flat_map +//! - boost::container::flat_multimap +//! - boost::container::basic_string +//! - boost::container::string +//! - boost::container::wstring +//! +//! Forward declares the following allocators: +//! - boost::container::allocator +//! - boost::container::node_allocator +//! - boost::container::adaptive_pool +//! +//! Forward declares the following polymorphic resource classes: +//! - boost::container::pmr::memory_resource +//! - boost::container::pmr::polymorphic_allocator +//! - boost::container::pmr::monotonic_buffer_resource +//! - boost::container::pmr::pool_options +//! - boost::container::pmr::unsynchronized_pool_resource +//! - boost::container::pmr::synchronized_pool_resource +//! +//! And finally it defines the following types + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//Std forward declarations +#ifndef BOOST_CONTAINER_DETAIL_STD_FWD_HPP + #include +#endif + +namespace boost{ +namespace intrusive{ +namespace detail{ + //Create namespace to avoid compilation errors +}}} + +namespace boost{ namespace container{ namespace dtl{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +namespace boost{ namespace container{ namespace pmr{ + namespace bi = boost::intrusive; + namespace bid = boost::intrusive::detail; +}}} + +#include + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +////////////////////////////////////////////////////////////////////////////// +// Containers +////////////////////////////////////////////////////////////////////////////// + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +template +struct pair; + +template +class new_allocator; + +template +class vector; + +template +class stable_vector; + +template +class static_vector; + +template < class T, std::size_t N + , class Allocator = void > +class small_vector; + +template +class deque; + +template +class list; + +template +class slist; + +template + ,class Allocator = void + ,class Options = void> +class set; + +template + ,class Allocator = void + ,class Options = void > +class multiset; + +template + ,class Allocator = void + ,class Options = void > +class map; + +template + ,class Allocator = void + ,class Options = void > +class multimap; + +template + ,class Allocator = void > +class flat_set; + +template + ,class Allocator = void > +class flat_multiset; + +template + ,class Allocator = void > +class flat_map; + +template + ,class Allocator = void > +class flat_multimap; + +template + ,class Allocator = void > +class basic_string; + +typedef basic_string string; +typedef basic_string wstring; + +static const std::size_t ADP_nodes_per_block = 256u; +static const std::size_t ADP_max_free_blocks = 2u; +static const std::size_t ADP_overhead_percent = 1u; +static const std::size_t ADP_only_alignment = 0u; + +template < class T + , std::size_t NodesPerBlock = ADP_nodes_per_block + , std::size_t MaxFreeBlocks = ADP_max_free_blocks + , std::size_t OverheadPercent = ADP_overhead_percent + , unsigned Version = 2 + > +class adaptive_pool; + +template < class T + , unsigned Version = 2 + , unsigned int AllocationDisableMask = 0> +class allocator; + +static const std::size_t NodeAlloc_nodes_per_block = 256u; + +template + < class T + , std::size_t NodesPerBlock = NodeAlloc_nodes_per_block + , std::size_t Version = 2> +class node_allocator; + +namespace pmr { + +class memory_resource; + +template +class polymorphic_allocator; + +class monotonic_buffer_resource; + +struct pool_options; + +template +class resource_adaptor_imp; + +class unsynchronized_pool_resource; + +class synchronized_pool_resource; + +} //namespace pmr { + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the input range is +//! guaranteed to be ordered +struct ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered +static const ordered_range_t ordered_range = ordered_range_t(); + +//! Type used to tag that the input range is +//! guaranteed to be ordered and unique +struct ordered_unique_range_t + : public ordered_range_t +{}; + +//! Value used to tag that the input range is +//! guaranteed to be ordered and unique +static const ordered_unique_range_t ordered_unique_range = ordered_unique_range_t(); + +//! Type used to tag that the inserted values +//! should be default initialized +struct default_init_t +{}; + +//! Value used to tag that the inserted values +//! should be default initialized +static const default_init_t default_init = default_init_t(); +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +//! Type used to tag that the inserted values +//! should be value initialized +struct value_init_t +{}; + +//! Value used to tag that the inserted values +//! should be value initialized +static const value_init_t value_init = value_init_t(); + +namespace container_detail_really_deep_namespace { + +//Otherwise, gcc issues a warning of previously defined +//anonymous_instance and unique_instance +struct dummy +{ + dummy() + { + (void)ordered_range; + (void)ordered_unique_range; + (void)default_init; + } +}; + +} //detail_really_deep_namespace { + + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +}} //namespace boost { namespace container { + +#endif //#ifndef BOOST_CONTAINER_CONTAINER_FWD_HPP diff --git a/third-party/boost/boost/container/deque.hpp b/third-party/boost/boost/container/deque.hpp new file mode 100644 index 000000000..1fa3e5d5d --- /dev/null +++ b/third-party/boost/boost/container/deque.hpp @@ -0,0 +1,2283 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DEQUE_HPP +#define BOOST_CONTAINER_DEQUE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +// container +#include +#include +#include //new_allocator +#include +// container/detail +#include +#include //algo_equal(), algo_lexicographical_compare +#include +#include +#include +#include +#include +#include +#include +#include +#include +// move +#include +#include +#include +#include +// move/detail +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +#include +// other +#include +#include +// std +#include + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) +#include +#endif + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +template +class deque; + +template +struct deque_value_traits +{ + typedef T value_type; + static const bool trivial_dctr = dtl::is_trivially_destructible::value; + static const bool trivial_dctr_after_move = ::boost::has_trivial_destructor_after_move::value; +}; + +// Note: this function is simply a kludge to work around several compilers' +// bugs in handling constant expressions. +template +struct deque_buf_size +{ + static const std::size_t min_size = 512u; + static const std::size_t sizeof_t = sizeof(T); + static const std::size_t value = sizeof_t < min_size ? (min_size/sizeof_t) : std::size_t(1); +}; + +namespace dtl { + +// Class invariants: +// For any nonsingular iterator i: +// i.node is the address of an element in the map array. The +// contents of i.node is a pointer to the beginning of a node. +// i.first == //(i.node) +// i.last == i.first + node_size +// i.cur is a pointer in the range [i.first, i.last). NOTE: +// the implication of this is that i.cur is always a dereferenceable +// pointer, even if i is a past-the-end iterator. +// Start and Finish are always nonsingular iterators. NOTE: this means +// that an empty deque must have one node, and that a deque +// with N elements, where N is the buffer size, must have two nodes. +// For every node other than start.node and finish.node, every element +// in the node is an initialized object. If start.node == finish.node, +// then [start.cur, finish.cur) are initialized objects, and +// the elements outside that range are uninitialized storage. Otherwise, +// [start.cur, start.last) and [finish.first, finish.cur) are initialized +// objects, and [start.first, start.cur) and [finish.cur, finish.last) +// are uninitialized storage. +// [map, map + map_size) is a valid, non-empty range. +// [start.node, finish.node] is a valid range contained within +// [map, map + map_size). +// A pointer in the range [map, map + map_size) points to an allocated node +// if and only if the pointer is in the range [start.node, finish.node]. +template +class deque_iterator +{ + public: + typedef std::random_access_iterator_tag iterator_category; + typedef typename boost::intrusive::pointer_traits::element_type value_type; + typedef typename boost::intrusive::pointer_traits::difference_type difference_type; + typedef typename if_c + < IsConst + , typename boost::intrusive::pointer_traits::template + rebind_pointer::type + , Pointer + >::type pointer; + typedef typename if_c + < IsConst + , const value_type& + , value_type& + >::type reference; + + class nat; + typedef typename dtl::if_c< IsConst + , deque_iterator + , nat>::type nonconst_iterator; + + BOOST_CONTAINER_FORCEINLINE static std::size_t s_buffer_size() + { return deque_buf_size::value; } + + typedef Pointer val_alloc_ptr; + typedef typename boost::intrusive::pointer_traits:: + template rebind_pointer::type index_pointer; + + Pointer m_cur; + Pointer m_first; + Pointer m_last; + index_pointer m_node; + + public: + + BOOST_CONTAINER_FORCEINLINE Pointer get_cur() const { return m_cur; } + BOOST_CONTAINER_FORCEINLINE Pointer get_first() const { return m_first; } + BOOST_CONTAINER_FORCEINLINE Pointer get_last() const { return m_last; } + BOOST_CONTAINER_FORCEINLINE index_pointer get_node() const { return m_node; } + + BOOST_CONTAINER_FORCEINLINE deque_iterator(val_alloc_ptr x, index_pointer y) BOOST_NOEXCEPT_OR_NOTHROW + : m_cur(x), m_first(*y), m_last(*y + s_buffer_size()), m_node(y) + {} + + BOOST_CONTAINER_FORCEINLINE deque_iterator() BOOST_NOEXCEPT_OR_NOTHROW + : m_cur(), m_first(), m_last(), m_node() //Value initialization to achieve "null iterators" (N3644) + {} + + BOOST_CONTAINER_FORCEINLINE deque_iterator(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW + : m_cur(x.get_cur()), m_first(x.get_first()), m_last(x.get_last()), m_node(x.get_node()) + {} + + BOOST_CONTAINER_FORCEINLINE deque_iterator(const nonconst_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW + : m_cur(x.get_cur()), m_first(x.get_first()), m_last(x.get_last()), m_node(x.get_node()) + {} + + deque_iterator(Pointer cur, Pointer first, Pointer last, index_pointer node) BOOST_NOEXCEPT_OR_NOTHROW + : m_cur(cur), m_first(first), m_last(last), m_node(node) + {} + + BOOST_CONTAINER_FORCEINLINE deque_iterator& operator=(const deque_iterator& x) BOOST_NOEXCEPT_OR_NOTHROW + { m_cur = x.get_cur(); m_first = x.get_first(); m_last = x.get_last(); m_node = x.get_node(); return *this; } + + BOOST_CONTAINER_FORCEINLINE deque_iterator unconst() const BOOST_NOEXCEPT_OR_NOTHROW + { + return deque_iterator(this->get_cur(), this->get_first(), this->get_last(), this->get_node()); + } + + BOOST_CONTAINER_FORCEINLINE reference operator*() const BOOST_NOEXCEPT_OR_NOTHROW + { return *this->m_cur; } + + BOOST_CONTAINER_FORCEINLINE pointer operator->() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->m_cur; } + + difference_type operator-(const deque_iterator& x) const BOOST_NOEXCEPT_OR_NOTHROW + { + if(!this->m_cur && !x.m_cur){ + return 0; + } + return difference_type(this->s_buffer_size()) * (this->m_node - x.m_node - 1) + + (this->m_cur - this->m_first) + (x.m_last - x.m_cur); + } + + deque_iterator& operator++() BOOST_NOEXCEPT_OR_NOTHROW + { + ++this->m_cur; + if (this->m_cur == this->m_last) { + this->priv_set_node(this->m_node + 1); + this->m_cur = this->m_first; + } + return *this; + } + + BOOST_CONTAINER_FORCEINLINE deque_iterator operator++(int) BOOST_NOEXCEPT_OR_NOTHROW + { + deque_iterator tmp(*this); + ++*this; + return tmp; + } + + deque_iterator& operator--() BOOST_NOEXCEPT_OR_NOTHROW + { + if (this->m_cur == this->m_first) { + this->priv_set_node(this->m_node - 1); + this->m_cur = this->m_last; + } + --this->m_cur; + return *this; + } + + BOOST_CONTAINER_FORCEINLINE deque_iterator operator--(int) BOOST_NOEXCEPT_OR_NOTHROW + { + deque_iterator tmp(*this); + --*this; + return tmp; + } + + deque_iterator& operator+=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + difference_type offset = n + (this->m_cur - this->m_first); + if (offset >= 0 && offset < difference_type(this->s_buffer_size())) + this->m_cur += n; + else { + difference_type node_offset = + offset > 0 ? offset / difference_type(this->s_buffer_size()) + : -difference_type((-offset - 1) / this->s_buffer_size()) - 1; + this->priv_set_node(this->m_node + node_offset); + this->m_cur = this->m_first + + (offset - node_offset * difference_type(this->s_buffer_size())); + } + return *this; + } + + BOOST_CONTAINER_FORCEINLINE deque_iterator operator+(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { deque_iterator tmp(*this); return tmp += n; } + + BOOST_CONTAINER_FORCEINLINE deque_iterator& operator-=(difference_type n) BOOST_NOEXCEPT_OR_NOTHROW + { return *this += -n; } + + BOOST_CONTAINER_FORCEINLINE deque_iterator operator-(difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { deque_iterator tmp(*this); return tmp -= n; } + + BOOST_CONTAINER_FORCEINLINE reference operator[](difference_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { return *(*this + n); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return l.m_cur == r.m_cur; } + + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return l.m_cur != r.m_cur; } + + BOOST_CONTAINER_FORCEINLINE friend bool operator<(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return (l.m_node == r.m_node) ? (l.m_cur < r.m_cur) : (l.m_node < r.m_node); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return r < l; } + + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return !(r < l); } + + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const deque_iterator& l, const deque_iterator& r) BOOST_NOEXCEPT_OR_NOTHROW + { return !(l < r); } + + BOOST_CONTAINER_FORCEINLINE void priv_set_node(index_pointer new_node) BOOST_NOEXCEPT_OR_NOTHROW + { + this->m_node = new_node; + this->m_first = *new_node; + this->m_last = this->m_first + this->s_buffer_size(); + } + + BOOST_CONTAINER_FORCEINLINE friend deque_iterator operator+(difference_type n, deque_iterator x) BOOST_NOEXCEPT_OR_NOTHROW + { return x += n; } +}; + +} //namespace dtl { + +// Deque base class. It has two purposes. First, its constructor +// and destructor allocate (but don't initialize) storage. This makes +// exception safety easier. +template +class deque_base +{ + BOOST_COPYABLE_AND_MOVABLE(deque_base) + public: + typedef allocator_traits val_alloc_traits_type; + typedef typename val_alloc_traits_type::value_type val_alloc_val; + typedef typename val_alloc_traits_type::pointer val_alloc_ptr; + typedef typename val_alloc_traits_type::const_pointer val_alloc_cptr; + typedef typename val_alloc_traits_type::reference val_alloc_ref; + typedef typename val_alloc_traits_type::const_reference val_alloc_cref; + typedef typename val_alloc_traits_type::difference_type val_alloc_diff; + typedef typename val_alloc_traits_type::size_type val_alloc_size; + typedef typename val_alloc_traits_type::template + portable_rebind_alloc::type ptr_alloc_t; + typedef allocator_traits ptr_alloc_traits_type; + typedef typename ptr_alloc_traits_type::value_type ptr_alloc_val; + typedef typename ptr_alloc_traits_type::pointer ptr_alloc_ptr; + typedef typename ptr_alloc_traits_type::const_pointer ptr_alloc_cptr; + typedef typename ptr_alloc_traits_type::reference ptr_alloc_ref; + typedef typename ptr_alloc_traits_type::const_reference ptr_alloc_cref; + typedef Allocator allocator_type; + typedef allocator_type stored_allocator_type; + typedef val_alloc_size size_type; + + protected: + + typedef deque_value_traits traits_t; + typedef ptr_alloc_t map_allocator_type; + + BOOST_CONTAINER_FORCEINLINE static size_type s_buffer_size() BOOST_NOEXCEPT_OR_NOTHROW + { return deque_buf_size::value; } + + BOOST_CONTAINER_FORCEINLINE val_alloc_ptr priv_allocate_node() + { return this->alloc().allocate(s_buffer_size()); } + + BOOST_CONTAINER_FORCEINLINE void priv_deallocate_node(val_alloc_ptr p) BOOST_NOEXCEPT_OR_NOTHROW + { this->alloc().deallocate(p, s_buffer_size()); } + + BOOST_CONTAINER_FORCEINLINE ptr_alloc_ptr priv_allocate_map(size_type n) + { return this->ptr_alloc().allocate(n); } + + BOOST_CONTAINER_FORCEINLINE void priv_deallocate_map(ptr_alloc_ptr p, size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { this->ptr_alloc().deallocate(p, n); } + + typedef dtl::deque_iterator iterator; + typedef dtl::deque_iterator const_iterator; + + BOOST_CONTAINER_FORCEINLINE deque_base(size_type num_elements, const allocator_type& a) + : members_(a) + { this->priv_initialize_map(num_elements); } + + BOOST_CONTAINER_FORCEINLINE explicit deque_base(const allocator_type& a) + : members_(a) + {} + + BOOST_CONTAINER_FORCEINLINE deque_base() + : members_() + {} + + BOOST_CONTAINER_FORCEINLINE explicit deque_base(BOOST_RV_REF(deque_base) x) + : members_( boost::move(x.ptr_alloc()) + , boost::move(x.alloc()) ) + {} + + ~deque_base() + { + if (this->members_.m_map) { + this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + } + } + + private: + deque_base(const deque_base&); + + protected: + + void swap_members(deque_base &x) BOOST_NOEXCEPT_OR_NOTHROW + { + ::boost::adl_move_swap(this->members_.m_start, x.members_.m_start); + ::boost::adl_move_swap(this->members_.m_finish, x.members_.m_finish); + ::boost::adl_move_swap(this->members_.m_map, x.members_.m_map); + ::boost::adl_move_swap(this->members_.m_map_size, x.members_.m_map_size); + } + + void priv_initialize_map(size_type num_elements) + { +// if(num_elements){ + size_type num_nodes = num_elements / s_buffer_size() + 1; + + this->members_.m_map_size = dtl::max_value((size_type) InitialMapSize, num_nodes + 2); + this->members_.m_map = this->priv_allocate_map(this->members_.m_map_size); + + ptr_alloc_ptr nstart = this->members_.m_map + (this->members_.m_map_size - num_nodes) / 2; + ptr_alloc_ptr nfinish = nstart + num_nodes; + + BOOST_TRY { + this->priv_create_nodes(nstart, nfinish); + } + BOOST_CATCH(...){ + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = 0; + this->members_.m_map_size = 0; + BOOST_RETHROW + } + BOOST_CATCH_END + + this->members_.m_start.priv_set_node(nstart); + this->members_.m_finish.priv_set_node(nfinish - 1); + this->members_.m_start.m_cur = this->members_.m_start.m_first; + this->members_.m_finish.m_cur = this->members_.m_finish.m_first + + num_elements % s_buffer_size(); +// } + } + + void priv_create_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) + { + ptr_alloc_ptr cur = nstart; + BOOST_TRY { + for (; cur < nfinish; ++cur) + *cur = this->priv_allocate_node(); + } + BOOST_CATCH(...){ + this->priv_destroy_nodes(nstart, cur); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + void priv_destroy_nodes(ptr_alloc_ptr nstart, ptr_alloc_ptr nfinish) BOOST_NOEXCEPT_OR_NOTHROW + { + for (ptr_alloc_ptr n = nstart; n < nfinish; ++n) + this->priv_deallocate_node(*n); + } + + void priv_clear_map() BOOST_NOEXCEPT_OR_NOTHROW + { + if (this->members_.m_map) { + this->priv_destroy_nodes(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + this->members_.m_map = 0; + this->members_.m_map_size = 0; + this->members_.m_start = iterator(); + this->members_.m_finish = this->members_.m_start; + } + } + + enum { InitialMapSize = 8 }; + + protected: + struct members_holder + : public ptr_alloc_t + , public allocator_type + { + members_holder() + : map_allocator_type(), allocator_type() + , m_map(0), m_map_size(0) + , m_start(), m_finish(m_start) + {} + + explicit members_holder(const allocator_type &a) + : map_allocator_type(a), allocator_type(a) + , m_map(0), m_map_size(0) + , m_start(), m_finish(m_start) + {} + + template + members_holder(BOOST_FWD_REF(PtrAllocConvertible) pa, BOOST_FWD_REF(ValAllocConvertible) va) + : map_allocator_type(boost::forward(pa)) + , allocator_type (boost::forward(va)) + , m_map(0), m_map_size(0) + , m_start(), m_finish(m_start) + {} + + ptr_alloc_ptr m_map; + val_alloc_size m_map_size; + iterator m_start; + iterator m_finish; + } members_; + + BOOST_CONTAINER_FORCEINLINE ptr_alloc_t &ptr_alloc() BOOST_NOEXCEPT_OR_NOTHROW + { return members_; } + + BOOST_CONTAINER_FORCEINLINE const ptr_alloc_t &ptr_alloc() const BOOST_NOEXCEPT_OR_NOTHROW + { return members_; } + + BOOST_CONTAINER_FORCEINLINE allocator_type &alloc() BOOST_NOEXCEPT_OR_NOTHROW + { return members_; } + + BOOST_CONTAINER_FORCEINLINE const allocator_type &alloc() const BOOST_NOEXCEPT_OR_NOTHROW + { return members_; } +}; +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#ifdef BOOST_CONTAINER_DOXYGEN_INVOKED +//! A double-ended queue is a sequence that supports random access to elements, constant time insertion +//! and removal of elements at the end of the sequence, and linear time insertion and removal of elements in the middle. +//! +//! \tparam T The type of object that is stored in the deque +//! \tparam Allocator The allocator used for all internal memory management +template > +#else +template +#endif +class deque : protected deque_base::type> +{ + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + typedef deque_base::type> Base; + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + typedef typename real_allocator::type ValAllocator; + + public: + + ////////////////////////////////////////////// + // + // types + // + ////////////////////////////////////////////// + + typedef T value_type; + typedef ValAllocator allocator_type; + typedef typename ::boost::container::allocator_traits::pointer pointer; + typedef typename ::boost::container::allocator_traits::const_pointer const_pointer; + typedef typename ::boost::container::allocator_traits::reference reference; + typedef typename ::boost::container::allocator_traits::const_reference const_reference; + typedef typename ::boost::container::allocator_traits::size_type size_type; + typedef typename ::boost::container::allocator_traits::difference_type difference_type; + typedef BOOST_CONTAINER_IMPDEF(allocator_type) stored_allocator_type; + typedef BOOST_CONTAINER_IMPDEF(typename Base::iterator) iterator; + typedef BOOST_CONTAINER_IMPDEF(typename Base::const_iterator) const_iterator; + typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) reverse_iterator; + typedef BOOST_CONTAINER_IMPDEF(boost::container::reverse_iterator) const_reverse_iterator; + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + private: // Internal typedefs + BOOST_COPYABLE_AND_MOVABLE(deque) + typedef typename Base::ptr_alloc_ptr index_pointer; + BOOST_CONTAINER_FORCEINLINE static size_type s_buffer_size() + { return Base::s_buffer_size(); } + typedef allocator_traits allocator_traits_type; + + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + + public: + ////////////////////////////////////////////// + // + // construct/copy/destroy + // + ////////////////////////////////////////////// + + //! Effects: Default constructors a deque. + //! + //! Throws: If allocator_type's default constructor throws. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE deque() BOOST_NOEXCEPT_IF(dtl::is_nothrow_default_constructible::value) + : Base() + {} + + //! Effects: Constructs a deque taking the allocator as parameter. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE explicit deque(const allocator_type& a) BOOST_NOEXCEPT_OR_NOTHROW + : Base(a) + {} + + //! Effects: Constructs a deque + //! and inserts n value initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's value initialization throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE explicit deque(size_type n) + : Base(n, allocator_type()) + { + dtl::insert_value_initialized_n_proxy proxy; + proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + //deque_base will deallocate in case of exception... + } + + //! Effects: Constructs a deque + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's default initialization or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE deque(size_type n, default_init_t) + : Base(n, allocator_type()) + { + dtl::insert_default_initialized_n_proxy proxy; + proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + //deque_base will deallocate in case of exception... + } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts n value initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's value initialization throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE explicit deque(size_type n, const allocator_type &a) + : Base(n, a) + { + dtl::insert_value_initialized_n_proxy proxy; + proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + //deque_base will deallocate in case of exception... + } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts n default initialized values. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's default initialization or copy constructor throws. + //! + //! Complexity: Linear to n. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE deque(size_type n, default_init_t, const allocator_type &a) + : Base(n, a) + { + dtl::insert_default_initialized_n_proxy proxy; + proxy.uninitialized_copy_n_and_update(this->alloc(), this->begin(), n); + //deque_base will deallocate in case of exception... + } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE deque(size_type n, const value_type& value) + : Base(n, allocator_type()) + { this->priv_fill_initialize(value); } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts n copies of value. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE deque(size_type n, const value_type& value, const allocator_type& a) + : Base(n, a) + { this->priv_fill_initialize(value); } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the deque. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + BOOST_CONTAINER_FORCEINLINE deque(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_convertible + ::type * = 0 + #endif + ) + : Base(allocator_type()) + { + this->priv_range_initialize(first, last); + } + + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts a copy of the range [first, last) in the deque. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced InIt throws. + //! + //! Complexity: Linear to the range [first, last). + template + BOOST_CONTAINER_FORCEINLINE deque(InIt first, InIt last, const allocator_type& a + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_convertible + ::type * = 0 + #endif + ) + : Base(a) + { + this->priv_range_initialize(first, last); + } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Effects: Constructs a deque that will use a copy of allocator a + //! and inserts a copy of the range [il.begin(), il.end()) in the deque. + //! + //! Throws: If allocator_type's default constructor + //! throws or T's constructor taking a dereferenced std::initializer_list iterator throws. + //! + //! Complexity: Linear to the range [il.begin(), il.end()). + BOOST_CONTAINER_FORCEINLINE deque(std::initializer_list il, const allocator_type& a = allocator_type()) + : Base(a) + { + this->priv_range_initialize(il.begin(), il.end()); + } +#endif + + //! Effects: Copy constructs a deque. + //! + //! Postcondition: x == *this. + //! + //! Complexity: Linear to the elements x contains. + BOOST_CONTAINER_FORCEINLINE deque(const deque& x) + : Base(allocator_traits_type::select_on_container_copy_construction(x.alloc())) + { + if(x.size()){ + this->priv_initialize_map(x.size()); + boost::container::uninitialized_copy_alloc + (this->alloc(), x.begin(), x.end(), this->members_.m_start); + } + } + + //! Effects: Move constructor. Moves x's resources to *this. + //! + //! Throws: If allocator_type's copy constructor throws. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE deque(BOOST_RV_REF(deque) x) BOOST_NOEXCEPT_OR_NOTHROW + : Base(BOOST_MOVE_BASE(Base, x)) + { this->swap_members(x); } + + //! Effects: Copy constructs a vector using the specified allocator. + //! + //! Postcondition: x == *this. + //! + //! Throws: If allocation + //! throws or T's copy constructor throws. + //! + //! Complexity: Linear to the elements x contains. + deque(const deque& x, const allocator_type &a) + : Base(a) + { + if(x.size()){ + this->priv_initialize_map(x.size()); + boost::container::uninitialized_copy_alloc + (this->alloc(), x.begin(), x.end(), this->members_.m_start); + } + } + + //! Effects: Move constructor using the specified allocator. + //! Moves x's resources to *this if a == allocator_type(). + //! Otherwise copies values from x to *this. + //! + //! Throws: If allocation or T's copy constructor throws. + //! + //! Complexity: Constant if a == x.get_allocator(), linear otherwise. + deque(BOOST_RV_REF(deque) x, const allocator_type &a) + : Base(a) + { + if(x.alloc() == a){ + this->swap_members(x); + } + else{ + if(x.size()){ + this->priv_initialize_map(x.size()); + boost::container::uninitialized_copy_alloc + ( this->alloc(), boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end()), this->members_.m_start); + } + } + } + + //! Effects: Destroys the deque. All stored values are destroyed + //! and used memory is deallocated. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements. + BOOST_CONTAINER_FORCEINLINE ~deque() BOOST_NOEXCEPT_OR_NOTHROW + { + this->priv_destroy_range(this->members_.m_start, this->members_.m_finish); + } + + //! Effects: Makes *this contain the same elements as x. + //! + //! Postcondition: this->size() == x.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in x. + deque& operator= (BOOST_COPY_ASSIGN_REF(deque) x) + { + if (&x != this){ + allocator_type &this_alloc = this->alloc(); + const allocator_type &x_alloc = x.alloc(); + dtl::bool_ flag; + if(flag && this_alloc != x_alloc){ + this->clear(); + this->shrink_to_fit(); + } + dtl::assign_alloc(this->alloc(), x.alloc(), flag); + dtl::assign_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + this->assign(x.cbegin(), x.cend()); + } + return *this; + } + + //! Effects: Move assignment. All x's values are transferred to *this. + //! + //! Throws: If allocator_traits_type::propagate_on_container_move_assignment + //! is false and (allocation throws or value_type's move constructor throws) + //! + //! Complexity: Constant if allocator_traits_type:: + //! propagate_on_container_move_assignment is true or + //! this->get>allocator() == x.get_allocator(). Linear otherwise. + deque& operator= (BOOST_RV_REF(deque) x) + BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_move_assignment::value + || allocator_traits_type::is_always_equal::value) + { + BOOST_ASSERT(this != &x); + allocator_type &this_alloc = this->alloc(); + allocator_type &x_alloc = x.alloc(); + const bool propagate_alloc = allocator_traits_type:: + propagate_on_container_move_assignment::value; + dtl::bool_ flag; + const bool allocators_equal = this_alloc == x_alloc; (void)allocators_equal; + //Resources can be transferred if both allocators are + //going to be equal after this function (either propagated or already equal) + if(propagate_alloc || allocators_equal){ + //Destroy objects but retain memory in case x reuses it in the future + this->clear(); + //Move allocator if needed + dtl::move_alloc(this_alloc, x_alloc, flag); + dtl::move_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + //Nothrow swap + this->swap_members(x); + } + //Else do a one by one move + else{ + this->assign( boost::make_move_iterator(x.begin()) + , boost::make_move_iterator(x.end())); + } + return *this; + } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Effects: Makes *this contain the same elements as il. + //! + //! Postcondition: this->size() == il.size(). *this contains a copy + //! of each of x's elements. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to the number of elements in il. + BOOST_CONTAINER_FORCEINLINE deque& operator=(std::initializer_list il) + { + this->assign(il.begin(), il.end()); + return *this; + } +#endif + + //! Effects: Assigns the n copies of val to *this. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE void assign(size_type n, const T& val) + { + typedef constant_iterator c_it; + this->assign(c_it(val, n), c_it()); + } + + //! Effects: Assigns the the range [first, last) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing InIt throws. + //! + //! Complexity: Linear to n. + template + void assign(InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_or + < void + , dtl::is_convertible + , dtl::is_not_input_iterator + >::type * = 0 + #endif + ) + { + iterator cur = this->begin(); + for ( ; first != last && cur != end(); ++cur, ++first){ + *cur = *first; + } + if (first == last){ + this->erase(cur, this->cend()); + } + else{ + this->insert(this->cend(), first, last); + } + } + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + void assign(FwdIt first, FwdIt last + , typename dtl::disable_if_or + < void + , dtl::is_convertible + , dtl::is_input_iterator + >::type * = 0 + ) + { + const size_type len = boost::container::iterator_distance(first, last); + if (len > size()) { + FwdIt mid = first; + boost::container::iterator_advance(mid, this->size()); + boost::container::copy(first, mid, begin()); + this->insert(this->cend(), mid, last); + } + else{ + this->erase(boost::container::copy(first, last, this->begin()), cend()); + } + } + #endif + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Effects: Assigns the the range [il.begin(), il.end()) to *this. + //! + //! Throws: If memory allocation throws or + //! T's constructor from dereferencing std::initializer_list iterator throws. + //! + //! Complexity: Linear to il.size(). + BOOST_CONTAINER_FORCEINLINE void assign(std::initializer_list il) + { this->assign(il.begin(), il.end()); } +#endif + + //! Effects: Returns a copy of the internal allocator. + //! + //! Throws: If allocator's copy constructor throws. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return Base::alloc(); } + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const BOOST_NOEXCEPT_OR_NOTHROW + { return Base::alloc(); } + + ////////////////////////////////////////////// + // + // iterators + // + ////////////////////////////////////////////// + + //! Effects: Returns a reference to the internal allocator. + //! + //! Throws: Nothing + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension. + BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() BOOST_NOEXCEPT_OR_NOTHROW + { return Base::alloc(); } + + //! Effects: Returns an iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE iterator begin() BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_start; } + + //! Effects: Returns a const_iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_iterator begin() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_start; } + + //! Effects: Returns an iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE iterator end() BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_finish; } + + //! Effects: Returns a const_iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_iterator end() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_finish; } + + //! Effects: Returns a reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reverse_iterator rbegin() BOOST_NOEXCEPT_OR_NOTHROW + { return reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return const_reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reverse_iterator rend() BOOST_NOEXCEPT_OR_NOTHROW + { return reverse_iterator(this->members_.m_start); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator rend() const BOOST_NOEXCEPT_OR_NOTHROW + { return const_reverse_iterator(this->members_.m_start); } + + //! Effects: Returns a const_iterator to the first element contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_start; } + + //! Effects: Returns a const_iterator to the end of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_iterator cend() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_finish; } + + //! Effects: Returns a const_reverse_iterator pointing to the beginning + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crbegin() const BOOST_NOEXCEPT_OR_NOTHROW + { return const_reverse_iterator(this->members_.m_finish); } + + //! Effects: Returns a const_reverse_iterator pointing to the end + //! of the reversed deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reverse_iterator crend() const BOOST_NOEXCEPT_OR_NOTHROW + { return const_reverse_iterator(this->members_.m_start); } + + ////////////////////////////////////////////// + // + // capacity + // + ////////////////////////////////////////////// + + //! Effects: Returns true if the deque contains no elements. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE bool empty() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_finish == this->members_.m_start; } + + //! Effects: Returns the number of the elements contained in the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE size_type size() const BOOST_NOEXCEPT_OR_NOTHROW + { return this->members_.m_finish - this->members_.m_start; } + + //! Effects: Returns the largest possible size of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW + { return allocator_traits_type::max_size(this->alloc()); } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are value initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size) + { + const size_type len = size(); + if (new_size < len) + this->priv_erase_last_n(len - new_size); + else{ + const size_type n = new_size - this->size(); + dtl::insert_value_initialized_n_proxy proxy; + priv_insert_back_aux_impl(n, proxy); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are default initialized. + //! + //! Throws: If memory allocation throws, or T's constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + //! + //! Note: Non-standard extension + void resize(size_type new_size, default_init_t) + { + const size_type len = size(); + if (new_size < len) + this->priv_erase_last_n(len - new_size); + else{ + const size_type n = new_size - this->size(); + dtl::insert_default_initialized_n_proxy proxy; + priv_insert_back_aux_impl(n, proxy); + } + } + + //! Effects: Inserts or erases elements at the end such that + //! the size becomes n. New elements are copy constructed from x. + //! + //! Throws: If memory allocation throws, or T's copy constructor throws. + //! + //! Complexity: Linear to the difference between size() and new_size. + void resize(size_type new_size, const value_type& x) + { + const size_type len = size(); + if (new_size < len) + this->erase(this->members_.m_start + new_size, this->members_.m_finish); + else + this->insert(this->members_.m_finish, new_size - len, x); + } + + //! Effects: Tries to deallocate the excess of memory created + //! with previous allocations. The size of the deque is unchanged + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Constant. + void shrink_to_fit() + { + //This deque implementation already + //deallocates excess nodes when erasing + //so there is nothing to do except for + //empty deque + if(this->empty()){ + this->priv_clear_map(); + } + } + + ////////////////////////////////////////////// + // + // element access + // + ////////////////////////////////////////////// + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the first + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reference front() BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + return *this->members_.m_start; + } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the first element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reference front() const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + return *this->members_.m_start; + } + + //! Requires: !empty() + //! + //! Effects: Returns a reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reference back() BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + return *(end()-1); + } + + //! Requires: !empty() + //! + //! Effects: Returns a const reference to the last + //! element of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reference back() const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + return *(cend()-1); + } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reference operator[](size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(this->size() > n); + return this->members_.m_start[difference_type(n)]; + } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reference operator[](size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(this->size() > n); + return this->members_.m_start[difference_type(n)]; + } + + //! Requires: size() >= n. + //! + //! Effects: Returns an iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE iterator nth(size_type n) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(this->size() >= n); + return iterator(this->begin()+n); + } + + //! Requires: size() >= n. + //! + //! Effects: Returns a const_iterator to the nth element + //! from the beginning of the container. Returns end() + //! if n == size(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE const_iterator nth(size_type n) const BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(this->size() >= n); + return const_iterator(this->cbegin()+n); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE size_type index_of(iterator p) BOOST_NOEXCEPT_OR_NOTHROW + { + //Range checked priv_index_of + return this->priv_index_of(p); + } + + //! Requires: begin() <= p <= end(). + //! + //! Effects: Returns the index of the element pointed by p + //! and size() if p == end(). + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + //! + //! Note: Non-standard extension + BOOST_CONTAINER_FORCEINLINE size_type index_of(const_iterator p) const BOOST_NOEXCEPT_OR_NOTHROW + { + //Range checked priv_index_of + return this->priv_index_of(p); + } + + //! Requires: size() > n. + //! + //! Effects: Returns a reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE reference at(size_type n) + { + this->priv_throw_if_out_of_range(n); + return (*this)[n]; + } + + //! Requires: size() > n. + //! + //! Effects: Returns a const reference to the nth element + //! from the beginning of the container. + //! + //! Throws: std::range_error if n >= size() + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE const_reference at(size_type n) const + { + this->priv_throw_if_out_of_range(n); + return (*this)[n]; + } + + ////////////////////////////////////////////// + // + // modifiers + // + ////////////////////////////////////////////// + + #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the beginning of the deque. + //! + //! Returns: A reference to the created object. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time + template + reference emplace_front(BOOST_FWD_REF(Args)... args) + { + if(this->priv_push_front_simple_available()){ + reference r = *this->priv_push_front_simple_pos(); + allocator_traits_type::construct + ( this->alloc() + , this->priv_push_front_simple_pos() + , boost::forward(args)...); + this->priv_push_front_simple_commit(); + return r; + } + else{ + typedef dtl::insert_nonmovable_emplace_proxy type; + return *this->priv_insert_front_aux_impl(1, type(boost::forward(args)...)); + } + } + + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... in the end of the deque. + //! + //! Returns: A reference to the created object. + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: Amortized constant time + template + reference emplace_back(BOOST_FWD_REF(Args)... args) + { + if(this->priv_push_back_simple_available()){ + reference r = *this->priv_push_back_simple_pos(); + allocator_traits_type::construct + ( this->alloc() + , this->priv_push_back_simple_pos() + , boost::forward(args)...); + this->priv_push_back_simple_commit(); + return r; + } + else{ + typedef dtl::insert_nonmovable_emplace_proxy type; + return *this->priv_insert_back_aux_impl(1, type(boost::forward(args)...)); + } + } + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Inserts an object of type T constructed with + //! std::forward(args)... before p + //! + //! Throws: If memory allocation throws or the in-place constructor throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + template + iterator emplace(const_iterator p, BOOST_FWD_REF(Args)... args) + { + BOOST_ASSERT(this->priv_in_range_or_end(p)); + if(p == this->cbegin()){ + this->emplace_front(boost::forward(args)...); + return this->begin(); + } + else if(p == this->cend()){ + this->emplace_back(boost::forward(args)...); + return (this->end()-1); + } + else{ + typedef dtl::insert_emplace_proxy type; + return this->priv_insert_aux_impl(p, 1, type(boost::forward(args)...)); + } + } + + #else //!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #define BOOST_CONTAINER_DEQUE_EMPLACE_CODE(N) \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ + reference emplace_front(BOOST_MOVE_UREF##N)\ + {\ + if(priv_push_front_simple_available()){\ + reference r = *this->priv_push_front_simple_pos();\ + allocator_traits_type::construct\ + ( this->alloc(), this->priv_push_front_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + priv_push_front_simple_commit();\ + return r;\ + }\ + else{\ + typedef dtl::insert_nonmovable_emplace_proxy##N\ + type;\ + return *priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ + reference emplace_back(BOOST_MOVE_UREF##N)\ + {\ + if(priv_push_back_simple_available()){\ + reference r = *this->priv_push_back_simple_pos();\ + allocator_traits_type::construct\ + ( this->alloc(), this->priv_push_back_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ + priv_push_back_simple_commit();\ + return r;\ + }\ + else{\ + typedef dtl::insert_nonmovable_emplace_proxy##N\ + type;\ + return *priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\ + }\ + }\ + \ + BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ + iterator emplace(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ + {\ + BOOST_ASSERT(this->priv_in_range_or_end(p));\ + if(p == this->cbegin()){\ + this->emplace_front(BOOST_MOVE_FWD##N);\ + return this->begin();\ + }\ + else if(p == cend()){\ + this->emplace_back(BOOST_MOVE_FWD##N);\ + return (--this->end());\ + }\ + else{\ + typedef dtl::insert_emplace_proxy_arg##N\ + type;\ + return this->priv_insert_aux_impl(p, 1, type(BOOST_MOVE_FWD##N));\ + }\ + } + // + BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_DEQUE_EMPLACE_CODE) + #undef BOOST_CONTAINER_DEQUE_EMPLACE_CODE + + #endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the front of the deque. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_front(const T &x); + + //! Effects: Constructs a new element in the front of the deque + //! and moves the resources of x to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_front(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_front, T, void, priv_push_front) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + //! Effects: Inserts a copy of x at the end of the deque. + //! + //! Throws: If memory allocation throws or + //! T's copy constructor throws. + //! + //! Complexity: Amortized constant time. + void push_back(const T &x); + + //! Effects: Constructs a new element in the end of the deque + //! and moves the resources of x to this new element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: Amortized constant time. + void push_back(T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back) + #endif + + #if defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a copy of x before p. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws or x's copy constructor throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator p, const T &x); + + //! Requires: p must be a valid iterator of *this. + //! + //! Effects: Insert a new element before p with x's resources. + //! + //! Returns: an iterator to the inserted element. + //! + //! Throws: If memory allocation throws. + //! + //! Complexity: If p is end(), amortized constant time + //! Linear time otherwise. + iterator insert(const_iterator p, T &&x); + #else + BOOST_MOVE_CONVERSION_AWARE_CATCH_1ARG(insert, T, iterator, priv_insert, const_iterator, const_iterator) + #endif + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert n copies of x before pos. + //! + //! Returns: an iterator to the first inserted element or pos if n is 0. + //! + //! Throws: If memory allocation throws or T's copy constructor throws. + //! + //! Complexity: Linear to n. + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, size_type n, const value_type& x) + { + //Range check of p is done by insert() + typedef constant_iterator c_it; + return this->insert(pos, c_it(x, n), c_it()); + } + + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [first, last) range before pos. + //! + //! Returns: an iterator to the first inserted element or pos if first == last. + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced InIt throws or T's copy constructor throws. + //! + //! Complexity: Linear to distance [first, last). + template + iterator insert(const_iterator pos, InIt first, InIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_or + < void + , dtl::is_convertible + , dtl::is_not_input_iterator + >::type * = 0 + #endif + ) + { + BOOST_ASSERT(this->priv_in_range_or_end(pos)); + size_type n = 0; + iterator it(pos.unconst()); + for(;first != last; ++first, ++n){ + it = this->emplace(it, *first); + ++it; + } + it -= n; + return it; + } + +#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST) + //! Requires: pos must be a valid iterator of *this. + //! + //! Effects: Insert a copy of the [il.begin(), il.end()) range before pos. + //! + //! Returns: an iterator to the first inserted element or pos if il.begin() == il.end(). + //! + //! Throws: If memory allocation throws, T's constructor from a + //! dereferenced std::initializer_list throws or T's copy constructor throws. + //! + //! Complexity: Linear to distance [il.begin(), il.end()). + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator pos, std::initializer_list il) + { + //Range check os pos is done in insert() + return insert(pos, il.begin(), il.end()); + } +#endif + + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + template + BOOST_CONTAINER_FORCEINLINE iterator insert(const_iterator p, FwdIt first, FwdIt last + #if !defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + , typename dtl::disable_if_or + < void + , dtl::is_convertible + , dtl::is_input_iterator + >::type * = 0 + #endif + ) + { + BOOST_ASSERT(this->priv_in_range_or_end(p)); + dtl::insert_range_proxy proxy(first); + return priv_insert_aux_impl(p, boost::container::iterator_distance(first, last), proxy); + } + #endif + + //! Effects: Removes the first element from the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_front() BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + if (this->members_.m_start.m_cur != this->members_.m_start.m_last - 1) { + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) + ); + ++this->members_.m_start.m_cur; + } + else + this->priv_pop_front_aux(); + } + + //! Effects: Removes the last element from the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant time. + void pop_back() BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(!this->empty()); + if (this->members_.m_finish.m_cur != this->members_.m_finish.m_first) { + --this->members_.m_finish.m_cur; + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) + ); + } + else + this->priv_pop_back_aux(); + } + + //! Effects: Erases the element at p. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the elements between pos and the + //! last element (if pos is near the end) or the first element + //! if(pos is near the beginning). + //! Constant if pos is the first or the last element. + iterator erase(const_iterator pos) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(this->priv_in_range(pos)); + iterator next = pos.unconst(); + ++next; + size_type index = pos - this->members_.m_start; + if (index < (this->size()/2)) { + boost::container::move_backward(this->begin(), pos.unconst(), next); + pop_front(); + } + else { + boost::container::move(next, this->end(), pos.unconst()); + pop_back(); + } + return this->members_.m_start + index; + } + + //! Effects: Erases the elements pointed by [first, last). + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the distance between first and + //! last plus the elements between pos and the + //! last element (if pos is near the end) or the first element + //! if(pos is near the beginning). + iterator erase(const_iterator first, const_iterator last) BOOST_NOEXCEPT_OR_NOTHROW + { + BOOST_ASSERT(first == last || + (first < last && this->priv_in_range(first) && this->priv_in_range_or_end(last))); + if (first == this->members_.m_start && last == this->members_.m_finish) { + this->clear(); + return this->members_.m_finish; + } + else { + const size_type n = static_cast(last - first); + const size_type elems_before = static_cast(first - this->members_.m_start); + if (elems_before < (this->size() - n) - elems_before) { + boost::container::move_backward(begin(), first.unconst(), last.unconst()); + iterator new_start = this->members_.m_start + n; + this->priv_destroy_range(this->members_.m_start, new_start); + this->priv_destroy_nodes(this->members_.m_start.m_node, new_start.m_node); + this->members_.m_start = new_start; + } + else { + boost::container::move(last.unconst(), end(), first.unconst()); + iterator new_finish = this->members_.m_finish - n; + this->priv_destroy_range(new_finish, this->members_.m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); + this->members_.m_finish = new_finish; + } + return this->members_.m_start + elems_before; + } + } + + //! Effects: Swaps the contents of *this and x. + //! + //! Throws: Nothing. + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE void swap(deque &x) + BOOST_NOEXCEPT_IF(allocator_traits_type::propagate_on_container_swap::value + || allocator_traits_type::is_always_equal::value) + { + this->swap_members(x); + dtl::bool_ flag; + dtl::swap_alloc(this->alloc(), x.alloc(), flag); + dtl::swap_alloc(this->ptr_alloc(), x.ptr_alloc(), flag); + } + + //! Effects: Erases all the elements of the deque. + //! + //! Throws: Nothing. + //! + //! Complexity: Linear to the number of elements in the deque. + void clear() BOOST_NOEXCEPT_OR_NOTHROW + { + for (index_pointer node = this->members_.m_start.m_node + 1; + node < this->members_.m_finish.m_node; + ++node) { + this->priv_destroy_range(*node, *node + this->s_buffer_size()); + this->priv_deallocate_node(*node); + } + + if (this->members_.m_start.m_node != this->members_.m_finish.m_node) { + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_start.m_last); + this->priv_destroy_range(this->members_.m_finish.m_first, this->members_.m_finish.m_cur); + this->priv_deallocate_node(this->members_.m_finish.m_first); + } + else + this->priv_destroy_range(this->members_.m_start.m_cur, this->members_.m_finish.m_cur); + + this->members_.m_finish = this->members_.m_start; + } + + //! Effects: Returns true if x and y are equal + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator==(const deque& x, const deque& y) + { return x.size() == y.size() && ::boost::container::algo_equal(x.begin(), x.end(), y.begin()); } + + //! Effects: Returns true if x and y are unequal + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator!=(const deque& x, const deque& y) + { return !(x == y); } + + //! Effects: Returns true if x is less than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator<(const deque& x, const deque& y) + { return ::boost::container::algo_lexicographical_compare(x.begin(), x.end(), y.begin(), y.end()); } + + //! Effects: Returns true if x is greater than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator>(const deque& x, const deque& y) + { return y < x; } + + //! Effects: Returns true if x is equal or less than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator<=(const deque& x, const deque& y) + { return !(y < x); } + + //! Effects: Returns true if x is equal or greater than y + //! + //! Complexity: Linear to the number of elements in the container. + BOOST_CONTAINER_FORCEINLINE friend bool operator>=(const deque& x, const deque& y) + { return !(x < y); } + + //! Effects: x.swap(y) + //! + //! Complexity: Constant. + BOOST_CONTAINER_FORCEINLINE friend void swap(deque& x, deque& y) + { x.swap(y); } + + #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + private: + + BOOST_CONTAINER_FORCEINLINE size_type priv_index_of(const_iterator p) const + { + BOOST_ASSERT(this->cbegin() <= p); + BOOST_ASSERT(p <= this->cend()); + return static_cast(p - this->cbegin()); + } + + void priv_erase_last_n(size_type n) + { + if(n == this->size()) { + this->clear(); + } + else { + iterator new_finish = this->members_.m_finish - n; + this->priv_destroy_range(new_finish, this->members_.m_finish); + this->priv_destroy_nodes(new_finish.m_node + 1, this->members_.m_finish.m_node + 1); + this->members_.m_finish = new_finish; + } + } + + void priv_throw_if_out_of_range(size_type n) const + { + if (n >= this->size()) + throw_out_of_range("deque::at out of range"); + } + + BOOST_CONTAINER_FORCEINLINE bool priv_in_range(const_iterator pos) const + { + return (this->begin() <= pos) && (pos < this->end()); + } + + BOOST_CONTAINER_FORCEINLINE bool priv_in_range_or_end(const_iterator pos) const + { + return (this->begin() <= pos) && (pos <= this->end()); + } + + template + iterator priv_insert(const_iterator p, BOOST_FWD_REF(U) x) + { + BOOST_ASSERT(this->priv_in_range_or_end(p)); + if (p == cbegin()){ + this->push_front(::boost::forward(x)); + return begin(); + } + else if (p == cend()){ + this->push_back(::boost::forward(x)); + return --end(); + } + else { + return priv_insert_aux_impl + ( p, (size_type)1 + , dtl::get_insert_value_proxy(::boost::forward(x))); + } + } + + template + void priv_push_front(BOOST_FWD_REF(U) x) + { + if(this->priv_push_front_simple_available()){ + allocator_traits_type::construct + ( this->alloc(), this->priv_push_front_simple_pos(), ::boost::forward(x)); + this->priv_push_front_simple_commit(); + } + else{ + priv_insert_aux_impl + ( this->cbegin(), (size_type)1 + , dtl::get_insert_value_proxy(::boost::forward(x))); + } + } + + template + void priv_push_back(BOOST_FWD_REF(U) x) + { + if(this->priv_push_back_simple_available()){ + allocator_traits_type::construct + ( this->alloc(), this->priv_push_back_simple_pos(), ::boost::forward(x)); + this->priv_push_back_simple_commit(); + } + else{ + priv_insert_aux_impl + ( this->cend(), (size_type)1 + , dtl::get_insert_value_proxy(::boost::forward(x))); + } + } + + BOOST_CONTAINER_FORCEINLINE bool priv_push_back_simple_available() const + { + return this->members_.m_map && + (this->members_.m_finish.m_cur != (this->members_.m_finish.m_last - 1)); + } + + BOOST_CONTAINER_FORCEINLINE T *priv_push_back_simple_pos() const + { + return boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur); + } + + BOOST_CONTAINER_FORCEINLINE void priv_push_back_simple_commit() + { + ++this->members_.m_finish.m_cur; + } + + BOOST_CONTAINER_FORCEINLINE bool priv_push_front_simple_available() const + { + return this->members_.m_map && + (this->members_.m_start.m_cur != this->members_.m_start.m_first); + } + + BOOST_CONTAINER_FORCEINLINE T *priv_push_front_simple_pos() const + { return boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) - 1; } + + BOOST_CONTAINER_FORCEINLINE void priv_push_front_simple_commit() + { --this->members_.m_start.m_cur; } + + void priv_destroy_range(iterator p, iterator p2) + { + if(!Base::traits_t::trivial_dctr){ + for(;p != p2; ++p){ + allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); + } + } + } + + void priv_destroy_range(pointer p, pointer p2) + { + if(!Base::traits_t::trivial_dctr){ + for(;p != p2; ++p){ + allocator_traits_type::destroy(this->alloc(), boost::movelib::iterator_to_raw_pointer(p)); + } + } + } + + template + iterator priv_insert_aux_impl(const_iterator p, size_type n, InsertProxy proxy) + { + iterator pos(p.unconst()); + const size_type pos_n = p - this->cbegin(); + if(!this->members_.m_map){ + this->priv_initialize_map(0); + pos = this->begin(); + } + + const size_type elemsbefore = static_cast(pos - this->members_.m_start); + const size_type length = this->size(); + if (elemsbefore < length / 2) { + const iterator new_start = this->priv_reserve_elements_at_front(n); + const iterator old_start = this->members_.m_start; + if(!elemsbefore){ + proxy.uninitialized_copy_n_and_update(this->alloc(), new_start, n); + this->members_.m_start = new_start; + } + else{ + pos = this->members_.m_start + elemsbefore; + if (elemsbefore >= n) { + const iterator start_n = this->members_.m_start + n; + ::boost::container::uninitialized_move_alloc + (this->alloc(), this->members_.m_start, start_n, new_start); + this->members_.m_start = new_start; + boost::container::move(start_n, pos, old_start); + proxy.copy_n_and_update(this->alloc(), pos - n, n); + } + else { + const size_type mid_count = n - elemsbefore; + const iterator mid_start = old_start - mid_count; + proxy.uninitialized_copy_n_and_update(this->alloc(), mid_start, mid_count); + this->members_.m_start = mid_start; + ::boost::container::uninitialized_move_alloc + (this->alloc(), old_start, pos, new_start); + this->members_.m_start = new_start; + proxy.copy_n_and_update(this->alloc(), old_start, elemsbefore); + } + } + } + else { + const iterator new_finish = this->priv_reserve_elements_at_back(n); + const iterator old_finish = this->members_.m_finish; + const size_type elemsafter = length - elemsbefore; + if(!elemsafter){ + proxy.uninitialized_copy_n_and_update(this->alloc(), old_finish, n); + this->members_.m_finish = new_finish; + } + else{ + pos = old_finish - elemsafter; + if (elemsafter >= n) { + iterator finish_n = old_finish - difference_type(n); + ::boost::container::uninitialized_move_alloc + (this->alloc(), finish_n, old_finish, old_finish); + this->members_.m_finish = new_finish; + boost::container::move_backward(pos, finish_n, old_finish); + proxy.copy_n_and_update(this->alloc(), pos, n); + } + else { + const size_type raw_gap = n - elemsafter; + ::boost::container::uninitialized_move_alloc + (this->alloc(), pos, old_finish, old_finish + raw_gap); + BOOST_TRY{ + proxy.copy_n_and_update(this->alloc(), pos, elemsafter); + proxy.uninitialized_copy_n_and_update(this->alloc(), old_finish, raw_gap); + } + BOOST_CATCH(...){ + this->priv_destroy_range(old_finish, old_finish + elemsafter); + BOOST_RETHROW + } + BOOST_CATCH_END + this->members_.m_finish = new_finish; + } + } + } + return this->begin() + pos_n; + } + + template + iterator priv_insert_back_aux_impl(size_type n, InsertProxy proxy) + { + if(!this->members_.m_map){ + this->priv_initialize_map(0); + } + + iterator new_finish = this->priv_reserve_elements_at_back(n); + iterator old_finish = this->members_.m_finish; + proxy.uninitialized_copy_n_and_update(this->alloc(), old_finish, n); + this->members_.m_finish = new_finish; + return iterator(this->members_.m_finish - n); + } + + template + iterator priv_insert_front_aux_impl(size_type n, InsertProxy proxy) + { + if(!this->members_.m_map){ + this->priv_initialize_map(0); + } + + iterator new_start = this->priv_reserve_elements_at_front(n); + proxy.uninitialized_copy_n_and_update(this->alloc(), new_start, n); + this->members_.m_start = new_start; + return new_start; + } + + BOOST_CONTAINER_FORCEINLINE iterator priv_fill_insert(const_iterator pos, size_type n, const value_type& x) + { + typedef constant_iterator c_it; + return this->insert(pos, c_it(x, n), c_it()); + } + + // Precondition: this->members_.m_start and this->members_.m_finish have already been initialized, + // but none of the deque's elements have yet been constructed. + void priv_fill_initialize(const value_type& value) + { + index_pointer cur = this->members_.m_start.m_node; + BOOST_TRY { + for ( ; cur < this->members_.m_finish.m_node; ++cur){ + boost::container::uninitialized_fill_alloc + (this->alloc(), *cur, *cur + this->s_buffer_size(), value); + } + boost::container::uninitialized_fill_alloc + (this->alloc(), this->members_.m_finish.m_first, this->members_.m_finish.m_cur, value); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur, cur)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(InIt first, InIt last, typename iterator_enable_if_tag::type* =0) + { + this->priv_initialize_map(0); + BOOST_TRY { + for ( ; first != last; ++first) + this->emplace_back(*first); + } + BOOST_CATCH(...){ + this->clear(); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + template + void priv_range_initialize(FwdIt first, FwdIt last, typename iterator_disable_if_tag::type* =0) + { + size_type n = 0; + n = boost::container::iterator_distance(first, last); + this->priv_initialize_map(n); + + index_pointer cur_node = this->members_.m_start.m_node; + BOOST_TRY { + for (; cur_node < this->members_.m_finish.m_node; ++cur_node) { + FwdIt mid = first; + boost::container::iterator_advance(mid, this->s_buffer_size()); + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, mid, *cur_node); + first = mid; + } + ::boost::container::uninitialized_copy_alloc(this->alloc(), first, last, this->members_.m_finish.m_first); + } + BOOST_CATCH(...){ + this->priv_destroy_range(this->members_.m_start, iterator(*cur_node, cur_node)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + + // Called only if this->members_.m_finish.m_cur == this->members_.m_finish.m_first. + void priv_pop_back_aux() BOOST_NOEXCEPT_OR_NOTHROW + { + this->priv_deallocate_node(this->members_.m_finish.m_first); + this->members_.m_finish.priv_set_node(this->members_.m_finish.m_node - 1); + this->members_.m_finish.m_cur = this->members_.m_finish.m_last - 1; + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->members_.m_finish.m_cur) + ); + } + + // Called only if this->members_.m_start.m_cur == this->members_.m_start.m_last - 1. Note that + // if the deque has at least one element (a precondition for this member + // function), and if this->members_.m_start.m_cur == this->members_.m_start.m_last, then the deque + // must have at least two nodes. + void priv_pop_front_aux() BOOST_NOEXCEPT_OR_NOTHROW + { + allocator_traits_type::destroy + ( this->alloc() + , boost::movelib::to_raw_pointer(this->members_.m_start.m_cur) + ); + this->priv_deallocate_node(this->members_.m_start.m_first); + this->members_.m_start.priv_set_node(this->members_.m_start.m_node + 1); + this->members_.m_start.m_cur = this->members_.m_start.m_first; + } + + iterator priv_reserve_elements_at_front(size_type n) + { + size_type vacancies = this->members_.m_start.m_cur - this->members_.m_start.m_first; + if (n > vacancies){ + size_type new_elems = n-vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1) / + this->s_buffer_size(); + size_type s = (size_type)(this->members_.m_start.m_node - this->members_.m_map); + if (new_nodes > s){ + this->priv_reallocate_map(new_nodes, true); + } + size_type i = 1; + BOOST_TRY { + for (; i <= new_nodes; ++i) + *(this->members_.m_start.m_node - i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_start.m_node - j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_start - difference_type(n); + } + + iterator priv_reserve_elements_at_back(size_type n) + { + size_type vacancies = (this->members_.m_finish.m_last - this->members_.m_finish.m_cur) - 1; + if (n > vacancies){ + size_type new_elems = n - vacancies; + size_type new_nodes = (new_elems + this->s_buffer_size() - 1)/s_buffer_size(); + size_type s = (size_type)(this->members_.m_map_size - (this->members_.m_finish.m_node - this->members_.m_map)); + if (new_nodes + 1 > s){ + this->priv_reallocate_map(new_nodes, false); + } + size_type i = 1; + BOOST_TRY { + for (; i <= new_nodes; ++i) + *(this->members_.m_finish.m_node + i) = this->priv_allocate_node(); + } + BOOST_CATCH(...) { + for (size_type j = 1; j < i; ++j) + this->priv_deallocate_node(*(this->members_.m_finish.m_node + j)); + BOOST_RETHROW + } + BOOST_CATCH_END + } + return this->members_.m_finish + difference_type(n); + } + + void priv_reallocate_map(size_type nodes_to_add, bool add_at_front) + { + size_type old_num_nodes = this->members_.m_finish.m_node - this->members_.m_start.m_node + 1; + size_type new_num_nodes = old_num_nodes + nodes_to_add; + + index_pointer new_nstart; + if (this->members_.m_map_size > 2 * new_num_nodes) { + new_nstart = this->members_.m_map + (this->members_.m_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + if (new_nstart < this->members_.m_start.m_node) + boost::container::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + else + boost::container::move_backward + (this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart + old_num_nodes); + } + else { + size_type new_map_size = + this->members_.m_map_size + dtl::max_value(this->members_.m_map_size, nodes_to_add) + 2; + + index_pointer new_map = this->priv_allocate_map(new_map_size); + new_nstart = new_map + (new_map_size - new_num_nodes) / 2 + + (add_at_front ? nodes_to_add : 0); + boost::container::move(this->members_.m_start.m_node, this->members_.m_finish.m_node + 1, new_nstart); + this->priv_deallocate_map(this->members_.m_map, this->members_.m_map_size); + + this->members_.m_map = new_map; + this->members_.m_map_size = new_map_size; + } + + this->members_.m_start.priv_set_node(new_nstart); + this->members_.m_finish.priv_set_node(new_nstart + old_num_nodes - 1); + } + #endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +}; + +#ifndef BOOST_CONTAINER_NO_CXX17_CTAD +template +deque(InputIterator, InputIterator) -> deque::value_type>; +template +deque(InputIterator, InputIterator, Allocator const&) -> deque::value_type, Allocator>; +#endif + +}} + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +namespace boost { + +//!has_trivial_destructor_after_move<> == true_type +//!specialization for optimizations +template +struct has_trivial_destructor_after_move > +{ + typedef typename ::boost::container::allocator_traits::pointer pointer; + static const bool value = ::boost::has_trivial_destructor_after_move::value && + ::boost::has_trivial_destructor_after_move::value; +}; + +} + +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED + +#include + +#endif // #ifndef BOOST_CONTAINER_DEQUE_HPP diff --git a/third-party/boost/boost/container/detail/adaptive_node_pool.hpp b/third-party/boost/boost/container/detail/adaptive_node_pool.hpp new file mode 100644 index 000000000..d14e865d8 --- /dev/null +++ b/third-party/boost/boost/container/detail/adaptive_node_pool.hpp @@ -0,0 +1,169 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP +#define BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace boost { +namespace container { +namespace dtl { + +//!Pooled memory allocator using an smart adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time. +template< std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , std::size_t OverheadPercent + > +class private_adaptive_node_pool + : public private_adaptive_node_pool_impl_ct + < fake_segment_manager + , MaxFreeBlocks + , NodeSize + , NodesPerBlock + , OverheadPercent + , unsigned(OverheadPercent == 0)*::boost::container::adaptive_pool_flag::align_only + | ::boost::container::adaptive_pool_flag::size_ordered + | ::boost::container::adaptive_pool_flag::address_ordered + > +{ + typedef private_adaptive_node_pool_impl_ct + < fake_segment_manager + , MaxFreeBlocks + , NodeSize + , NodesPerBlock + , OverheadPercent + , unsigned(OverheadPercent == 0)*::boost::container::adaptive_pool_flag::align_only + | ::boost::container::adaptive_pool_flag::size_ordered + | ::boost::container::adaptive_pool_flag::address_ordered + > base_t; + + //Non-copyable + private_adaptive_node_pool(const private_adaptive_node_pool &); + private_adaptive_node_pool &operator=(const private_adaptive_node_pool &); + + public: + static const std::size_t nodes_per_block = NodesPerBlock; + + //!Constructor. Never throws + private_adaptive_node_pool() + : base_t(0) + {} +}; + +//!Pooled memory allocator using adaptive pool. Includes +//!a reference count but the class does not delete itself, this is +//!responsibility of user classes. Node size (NodeSize) and the number of +//!nodes allocated per block (NodesPerBlock) are known at compile time +template< std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t MaxFreeBlocks + , std::size_t OverheadPercent + > +class shared_adaptive_node_pool + : public private_adaptive_node_pool + +{ + private: + typedef private_adaptive_node_pool + private_node_allocator_t; + public: + typedef typename private_node_allocator_t::multiallocation_chain multiallocation_chain; + + //!Constructor. Never throws + shared_adaptive_node_pool() + : private_node_allocator_t(){} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~shared_adaptive_node_pool() + {} + + //!Allocates array of count elements. Can throw std::bad_alloc + void *allocate_node() + { + //----------------------- + scoped_lock guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_node(); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *ptr) + { + //----------------------- + scoped_lock guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_node(ptr); + } + + //!Allocates a singly linked list of n nodes ending in null pointer. + //!can throw std::bad_alloc + void allocate_nodes(const std::size_t n, multiallocation_chain &chain) + { + //----------------------- + scoped_lock guard(mutex_); + //----------------------- + return private_node_allocator_t::allocate_nodes(n, chain); + } + + void deallocate_nodes(multiallocation_chain &chain) + { + //----------------------- + scoped_lock guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_nodes(chain); + } + + //!Deallocates all the free blocks of memory. Never throws + void deallocate_free_blocks() + { + //----------------------- + scoped_lock guard(mutex_); + //----------------------- + private_node_allocator_t::deallocate_free_blocks(); + } + + private: + default_mutex mutex_; +}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_HPP diff --git a/third-party/boost/boost/container/detail/adaptive_node_pool_impl.hpp b/third-party/boost/boost/container/detail/adaptive_node_pool_impl.hpp new file mode 100644 index 000000000..b2070921d --- /dev/null +++ b/third-party/boost/boost/container/detail/adaptive_node_pool_impl.hpp @@ -0,0 +1,1259 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP +#define BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// container +#include +#include +// container/detail +#include +#include +#include +#include +#include +#include +#include +// intrusive +#include +#include +#include +#include +// other +#include +#include +#include + +namespace boost { +namespace container { + +namespace adaptive_pool_flag { + +static const unsigned int none = 0u; +static const unsigned int align_only = 1u << 0u; +static const unsigned int size_ordered = 1u << 1u; +static const unsigned int address_ordered = 1u << 2u; + +} //namespace adaptive_pool_flag{ + +namespace dtl { + +template +struct hdr_offset_holder_t +{ + hdr_offset_holder_t(size_type offset = 0) + : hdr_offset(offset) + {} + size_type hdr_offset; +}; + +template +struct less_func; + +template +struct less_func +{ + static bool less(SizeType, SizeType, const void *, const void *) + { return true; } +}; + +template +struct less_func +{ + static bool less(SizeType ls, SizeType rs, const void *, const void *) + { return ls < rs; } +}; + +template +struct less_func +{ + static bool less(SizeType, SizeType, const void *la, const void *ra) + { return la < ra; } +}; + +template +struct less_func +{ + static bool less(SizeType ls, SizeType rs, const void *la, const void *ra) + { return (ls < rs) || ((ls == rs) && (la < ra)); } +}; + +template +struct block_container_traits +{ + typedef typename bi::make_set_base_hook + < bi::void_pointer + , bi::optimize_size + , bi::link_mode >::type hook_t; + + template + struct container + { + typedef typename bi::make_multiset + , bi::size_type >::type type; + }; + + template + static void reinsert_was_used(Container &container, typename Container::reference v, bool) + { + typedef typename Container::const_iterator const_block_iterator; + typedef typename Container::iterator block_iterator; + typedef typename Container::value_compare value_compare; + + const block_iterator this_block(Container::s_iterator_to(v)); + const const_block_iterator cendit(container.cend()); + block_iterator next_block(this_block); + + if(++next_block != cendit && value_compare()(*next_block, v)){ + const_block_iterator next2_block(next_block); + //Test if v should be swapped with next (optimization) + if(++next2_block == cendit || !value_compare()(*next2_block, v)){ + v.swap_nodes(*next_block); + BOOST_ASSERT(++next_block == this_block); + } + else{ + container.erase(this_block); + container.insert(v); + } + } + } + + template + static void insert_was_empty(Container &container, typename Container::value_type &v, bool) + { + container.insert(v); + } + + template + static void erase_first(Container &container) + { + container.erase(container.cbegin()); + } + + template + static void erase_last(Container &container) + { + container.erase(--container.cend()); + } +}; + +template +struct block_container_traits +{ + typedef typename bi::make_list_base_hook + < bi::void_pointer + , bi::link_mode >::type hook_t; + + template + struct container + { + typedef typename bi::make_list + , bi::size_type, bi::constant_time_size >::type type; + }; + + template + static void reinsert_was_used(Container &container, typename Container::value_type &v, bool is_full) + { + if(is_full){ + container.erase(Container::s_iterator_to(v)); + container.push_back(v); + } + } + + template + static void insert_was_empty(Container &container, typename Container::value_type &v, bool is_full) + { + if(is_full){ + container.push_back(v); + } + else{ + container.push_front(v); + } + } + + template + static void erase_first(Container &container) + { + container.pop_front(); + } + + template + static void erase_last(Container &container) + { + container.pop_back(); + } +}; + +///////////////////////////// +// +// adaptive_pool_types +// +///////////////////////////// +template +struct adaptive_pool_types +{ + typedef VoidPointer void_pointer; + static const unsigned ordered = (Flags & (adaptive_pool_flag::size_ordered | adaptive_pool_flag::address_ordered)); + typedef block_container_traits block_container_traits_t; + typedef typename block_container_traits_t::hook_t hook_t; + typedef hdr_offset_holder_t hdr_offset_holder; + static const unsigned int order_flags = Flags & (adaptive_pool_flag::size_ordered | adaptive_pool_flag::address_ordered); + typedef MultiallocationChain free_nodes_t; + + struct block_info_t + : public hdr_offset_holder, + public hook_t + { + //An intrusive list of free node from this block + free_nodes_t free_nodes; + friend bool operator <(const block_info_t &l, const block_info_t &r) + { + return less_func:: + less(l.free_nodes.size(), r.free_nodes.size(), &l , &r); + } + + friend bool operator ==(const block_info_t &l, const block_info_t &r) + { return &l == &r; } + }; + typedef typename block_container_traits_t:: template container::type block_container_t; +}; + + +///////////////////////////////////////////// +// +// candidate_power_of_2_ct +// +///////////////////////////////////////////// +template< std::size_t alignment + , std::size_t real_node_size + , std::size_t payload_per_allocation + , std::size_t min_elements_per_block + , std::size_t hdr_size + , std::size_t hdr_offset_size + , std::size_t overhead_percent> +struct candidate_power_of_2_ct_helper +{ + static const std::size_t hdr_subblock_elements_alone = (alignment - hdr_size - payload_per_allocation)/real_node_size; + static const std::size_t hdr_subblock_elements_first = (alignment - hdr_size - payload_per_allocation)/real_node_size; + static const std::size_t elements_per_b_subblock_mid = (alignment - hdr_offset_size)/real_node_size; + static const std::size_t elements_per_b_subblock_end = (alignment - hdr_offset_size - payload_per_allocation)/real_node_size; + static const std::size_t num_b_subblock = + hdr_subblock_elements_alone >= min_elements_per_block + ? 0 + : ( ((hdr_subblock_elements_first + elements_per_b_subblock_end) >= min_elements_per_block) + ? 1 + : 2 + (min_elements_per_block - hdr_subblock_elements_first - elements_per_b_subblock_end - 1)/elements_per_b_subblock_mid + ) + ; + + static const std::size_t num_b_subblock_mid = (num_b_subblock > 1) ? (num_b_subblock - 1) : 0; + + static const std::size_t total_nodes = (num_b_subblock == 0) + ? hdr_subblock_elements_alone + : ( (num_b_subblock == 1) + ? (hdr_subblock_elements_first + elements_per_b_subblock_end) + : (hdr_subblock_elements_first + num_b_subblock_mid*elements_per_b_subblock_mid + elements_per_b_subblock_end) + ) + ; + static const std::size_t total_data = total_nodes*real_node_size; + static const std::size_t total_size = alignment*(num_b_subblock+1); + static const bool overhead_satisfied = (total_size - total_data)*100/total_size < overhead_percent; +}; + +template< std::size_t initial_alignment + , std::size_t real_node_size + , std::size_t payload_per_allocation + , std::size_t min_elements_per_block + , std::size_t hdr_size + , std::size_t hdr_offset_size + , std::size_t overhead_percent + , bool Loop = true> +struct candidate_power_of_2_ct +{ + typedef candidate_power_of_2_ct_helper + < initial_alignment + , real_node_size + , payload_per_allocation + , min_elements_per_block + , hdr_size + , hdr_offset_size + , overhead_percent> helper_t; + + static const std::size_t candidate_power_of_2 = initial_alignment << std::size_t(!helper_t::overhead_satisfied); + + typedef typename candidate_power_of_2_ct + < candidate_power_of_2 + , real_node_size + , payload_per_allocation + , min_elements_per_block + , hdr_size + , hdr_offset_size + , overhead_percent + , !helper_t::overhead_satisfied + >::type type; + + static const std::size_t alignment = type::alignment; + static const std::size_t num_subblocks = type::num_subblocks; + static const std::size_t real_num_node = type::real_num_node; +}; + +template< std::size_t initial_alignment + , std::size_t real_node_size + , std::size_t payload_per_allocation + , std::size_t min_elements_per_block + , std::size_t hdr_size + , std::size_t hdr_offset_size + , std::size_t overhead_percent + > +struct candidate_power_of_2_ct + < initial_alignment + , real_node_size + , payload_per_allocation + , min_elements_per_block + , hdr_size + , hdr_offset_size + , overhead_percent + , false> +{ + typedef candidate_power_of_2_ct + < initial_alignment + , real_node_size + , payload_per_allocation + , min_elements_per_block + , hdr_size + , hdr_offset_size + , overhead_percent + , false> type; + + typedef candidate_power_of_2_ct_helper + < initial_alignment + , real_node_size + , payload_per_allocation + , min_elements_per_block + , hdr_size + , hdr_offset_size + , overhead_percent> helper_t; + + static const std::size_t alignment = initial_alignment; + static const std::size_t num_subblocks = helper_t::num_b_subblock+1; + static const std::size_t real_num_node = helper_t::total_nodes; +}; + +///////////////////////////////////////////// +// +// candidate_power_of_2_rt +// +///////////////////////////////////////////// +inline void candidate_power_of_2_rt ( std::size_t initial_alignment + , std::size_t real_node_size + , std::size_t payload_per_allocation + , std::size_t min_elements_per_block + , std::size_t hdr_size + , std::size_t hdr_offset_size + , std::size_t overhead_percent + , std::size_t &alignment + , std::size_t &num_subblocks + , std::size_t &real_num_node) +{ + bool overhead_satisfied = false; + std::size_t num_b_subblock = 0; + std::size_t total_nodes = 0; + + while(!overhead_satisfied) + { + std::size_t hdr_subblock_elements_alone = (initial_alignment - hdr_size - payload_per_allocation)/real_node_size; + std::size_t hdr_subblock_elements_first = (initial_alignment - hdr_size - payload_per_allocation)/real_node_size; + std::size_t elements_per_b_subblock_mid = (initial_alignment - hdr_offset_size)/real_node_size; + std::size_t elements_per_b_subblock_end = (initial_alignment - hdr_offset_size - payload_per_allocation)/real_node_size; + + num_b_subblock = + hdr_subblock_elements_alone >= min_elements_per_block + ? 0 + : ( ((hdr_subblock_elements_first + elements_per_b_subblock_end) >= min_elements_per_block) + ? 1 + : 2 + (min_elements_per_block - hdr_subblock_elements_first - elements_per_b_subblock_end - 1)/elements_per_b_subblock_mid + ) + ; + + std::size_t num_b_subblock_mid = (num_b_subblock > 1) ? (num_b_subblock - 1) : 0; + + total_nodes = (num_b_subblock == 0) + ? hdr_subblock_elements_alone + : ( (num_b_subblock == 1) + ? (hdr_subblock_elements_first + elements_per_b_subblock_end) + : (hdr_subblock_elements_first + num_b_subblock_mid*elements_per_b_subblock_mid + elements_per_b_subblock_end) + ) + ; + std::size_t total_data = total_nodes*real_node_size; + std::size_t total_size = initial_alignment*(num_b_subblock+1); + overhead_satisfied = (total_size - total_data)*100/total_size < overhead_percent; + initial_alignment = initial_alignment << std::size_t(!overhead_satisfied); + } + alignment = initial_alignment; + num_subblocks = num_b_subblock+1; + real_num_node = total_nodes; +} + +///////////////////////////////////////////// +// +// private_adaptive_node_pool_impl_common +// +///////////////////////////////////////////// +template< class SegmentManagerBase, unsigned int Flags> +class private_adaptive_node_pool_impl_common +{ + public: + //!Segment manager typedef + typedef SegmentManagerBase segment_manager_base_type; + typedef typename SegmentManagerBase::multiallocation_chain multiallocation_chain; + typedef typename SegmentManagerBase::size_type size_type; + //Flags + //align_only + static const bool AlignOnly = (Flags & adaptive_pool_flag::align_only) != 0; + typedef bool_ IsAlignOnly; + typedef true_ AlignOnlyTrue; + typedef false_ AlignOnlyFalse; + + typedef typename SegmentManagerBase::void_pointer void_pointer; + static const typename SegmentManagerBase:: + size_type PayloadPerAllocation = SegmentManagerBase::PayloadPerAllocation; + + typedef typename boost::intrusive::pointer_traits + ::template rebind_pointer::type segment_mngr_base_ptr_t; + + protected: + typedef adaptive_pool_types + adaptive_pool_types_t; + typedef typename adaptive_pool_types_t::free_nodes_t free_nodes_t; + typedef typename adaptive_pool_types_t::block_info_t block_info_t; + typedef typename adaptive_pool_types_t::block_container_t block_container_t; + typedef typename adaptive_pool_types_t::block_container_traits_t block_container_traits_t; + typedef typename block_container_t::iterator block_iterator; + typedef typename block_container_t::const_iterator const_block_iterator; + typedef typename adaptive_pool_types_t::hdr_offset_holder hdr_offset_holder; + typedef private_adaptive_node_pool_impl_common this_type; + + static const size_type MaxAlign = alignment_of::value; + static const size_type HdrSize = ((sizeof(block_info_t)-1)/MaxAlign+1)*MaxAlign; + static const size_type HdrOffsetSize = ((sizeof(hdr_offset_holder)-1)/MaxAlign+1)*MaxAlign; + + segment_mngr_base_ptr_t mp_segment_mngr_base; //Segment manager + block_container_t m_block_container; //Intrusive block list + size_type m_totally_free_blocks; //Free blocks + + class block_destroyer; + friend class block_destroyer; + + class block_destroyer + { + public: + block_destroyer(const this_type *impl, multiallocation_chain &chain, const size_type num_subblocks, const size_type real_block_alignment, const size_type real_num_node) + : mp_impl(impl), m_chain(chain), m_num_subblocks(num_subblocks), m_real_block_alignment(real_block_alignment), m_real_num_node(real_num_node) + {} + + void operator()(typename block_container_t::pointer to_deallocate) + { return this->do_destroy(to_deallocate, IsAlignOnly()); } + + private: + void do_destroy(typename block_container_t::pointer to_deallocate, AlignOnlyTrue) + { + BOOST_ASSERT(to_deallocate->free_nodes.size() == m_real_num_node); + m_chain.push_back(to_deallocate); + } + + void do_destroy(typename block_container_t::pointer to_deallocate, AlignOnlyFalse) + { + BOOST_ASSERT(to_deallocate->free_nodes.size() == m_real_num_node); + BOOST_ASSERT(0 == to_deallocate->hdr_offset); + hdr_offset_holder *hdr_off_holder = + mp_impl->priv_first_subblock_from_block(boost::movelib::to_raw_pointer(to_deallocate), m_num_subblocks, m_real_block_alignment); + m_chain.push_back(hdr_off_holder); + } + + const this_type *mp_impl; + multiallocation_chain &m_chain; + const size_type m_num_subblocks; + const size_type m_real_block_alignment; + const size_type m_real_num_node; + }; + + //This macro will activate invariant checking. Slow, but helpful for debugging the code. + //#define BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS + void priv_invariants(const size_type real_num_node, const size_type num_subblocks, const size_type real_block_alignment) const + { + (void)real_num_node; (void)num_subblocks; (void)real_block_alignment; + #ifdef BOOST_CONTAINER_ADAPTIVE_NODE_POOL_CHECK_INVARIANTS + //Check that the total totally free blocks are correct + BOOST_ASSERT(m_block_container.size() >= m_totally_free_blocks); + + const const_block_iterator itend(m_block_container.cend()); + const const_block_iterator itbeg(m_block_container.cbegin()); + + { //Try to do checks in a single iteration + const_block_iterator it(itbeg); + size_type total_free_nodes = 0; + size_type total_free_blocks = 0u; + for(; it != itend; ++it){ + if(it != itbeg){ + //Check order invariant + const_block_iterator prev(it); + --prev; + BOOST_ASSERT(!(m_block_container.key_comp()(*it, *prev))); + (void)prev; (void)it; + } + + //free_nodes invariant + const size_type free_nodes = it->free_nodes.size(); + BOOST_ASSERT(free_nodes <= real_num_node); + BOOST_ASSERT(free_nodes != 0); + + //Acummulate total_free_nodes and total_free_blocks + total_free_nodes += free_nodes; + total_free_blocks += it->free_nodes.size() == real_num_node; + + if (!AlignOnly) { + //Check that header offsets are correct + hdr_offset_holder *hdr_off_holder = this->priv_first_subblock_from_block(const_cast(&*it), num_subblocks, real_block_alignment); + for (size_type i = 0, max = num_subblocks; i < max; ++i) { + const size_type offset = reinterpret_cast(const_cast(&*it)) - reinterpret_cast(hdr_off_holder); + (void)offset; + BOOST_ASSERT(hdr_off_holder->hdr_offset == offset); + BOOST_ASSERT(0 == (reinterpret_cast(hdr_off_holder) & (real_block_alignment - 1))); + BOOST_ASSERT(0 == (hdr_off_holder->hdr_offset & (real_block_alignment - 1))); + hdr_off_holder = reinterpret_cast(reinterpret_cast(hdr_off_holder) + real_block_alignment); + } + } + } + BOOST_ASSERT(total_free_blocks == m_totally_free_blocks); + BOOST_ASSERT(total_free_nodes >= m_totally_free_blocks*real_num_node); + } + #endif + } + + void priv_deallocate_free_blocks( const size_type max_free_blocks, const size_type real_num_node + , const size_type num_subblocks, const size_type real_block_alignment) + { //Trampoline function to ease inlining + if(m_totally_free_blocks > max_free_blocks){ + this->priv_deallocate_free_blocks_impl(max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + } + } + + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block, const size_type num_subblocks, const size_type real_block_alignment) const + { return this->priv_first_subblock_from_block(block, num_subblocks, real_block_alignment, IsAlignOnly()); } + + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block, const size_type num_subblocks, const size_type real_block_alignment, AlignOnlyFalse) const + { + hdr_offset_holder *const hdr_off_holder = reinterpret_cast + (reinterpret_cast(block) - (num_subblocks-1)*real_block_alignment); + BOOST_ASSERT(hdr_off_holder->hdr_offset == size_type(reinterpret_cast(block) - reinterpret_cast(hdr_off_holder))); + BOOST_ASSERT(0 == ((std::size_t)hdr_off_holder & (real_block_alignment - 1))); + BOOST_ASSERT(0 == (hdr_off_holder->hdr_offset & (real_block_alignment - 1))); + return hdr_off_holder; + } + + hdr_offset_holder *priv_first_subblock_from_block(block_info_t *block, const size_type num_subblocks, const size_type real_block_alignment, AlignOnlyTrue) const + { + (void)num_subblocks; (void)real_block_alignment; + return reinterpret_cast(block); + } + + void priv_deallocate_free_blocks_impl( const size_type max_free_blocks, const size_type real_num_node + , const size_type num_subblocks, const size_type real_block_alignment) + { + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + //Now check if we've reached the free nodes limit + //and check if we have free blocks. If so, deallocate as much + //as we can to stay below the limit + multiallocation_chain chain; + { + if(Flags & adaptive_pool_flag::size_ordered){ + const_block_iterator it = m_block_container.cend(); + --it; + size_type totally_free_blocks = m_totally_free_blocks; + + for( ; totally_free_blocks > max_free_blocks; --totally_free_blocks){ + BOOST_ASSERT(it->free_nodes.size() == real_num_node); + void *addr = priv_first_subblock_from_block(const_cast(&*it), num_subblocks, real_block_alignment); + --it; + block_container_traits_t::erase_last(m_block_container); + chain.push_front(void_pointer(addr)); + } + } + else{ + const_block_iterator it = m_block_container.cend(); + size_type totally_free_blocks = m_totally_free_blocks; + + while(totally_free_blocks > max_free_blocks){ + --it; + if(it->free_nodes.size() == real_num_node){ + void *addr = priv_first_subblock_from_block(const_cast(&*it), num_subblocks, real_block_alignment); + it = m_block_container.erase(it); + chain.push_front(void_pointer(addr)); + --totally_free_blocks; + } + } + } + BOOST_ASSERT((m_totally_free_blocks - max_free_blocks) == chain.size()); + m_totally_free_blocks = max_free_blocks; + } + this->mp_segment_mngr_base->deallocate_many(chain); + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + } + + void priv_fill_chain_remaining_to_block + ( multiallocation_chain &chain, size_type target_elem_in_chain, block_info_t &c_info + , char *mem_address, size_type max_node_in_mem + , const size_type real_node_size) + { + BOOST_ASSERT(chain.size() <= target_elem_in_chain); + + //First add all possible nodes to the chain + const size_type left = target_elem_in_chain - chain.size(); + const size_type add_to_chain = (max_node_in_mem < left) ? max_node_in_mem : left; + char *free_mem_address = static_cast(boost::movelib::to_raw_pointer + (chain.incorporate_after(chain.last(), void_pointer(mem_address), real_node_size, add_to_chain))); + //Now store remaining nodes in the free list + if(const size_type free = max_node_in_mem - add_to_chain){ + free_nodes_t & free_nodes = c_info.free_nodes; + free_nodes.incorporate_after(free_nodes.last(), void_pointer(free_mem_address), real_node_size, free); + } + } + + //!Allocates a several blocks of nodes. Can throw + void priv_append_from_new_blocks( size_type min_elements, multiallocation_chain &chain + , const size_type max_free_blocks + , const size_type real_block_alignment, const size_type real_node_size + , const size_type real_num_node, const size_type num_subblocks + , AlignOnlyTrue) + { + (void)num_subblocks; + BOOST_ASSERT(m_block_container.empty()); + BOOST_ASSERT(min_elements > 0); + const size_type n = (min_elements - 1)/real_num_node + 1; + const size_type real_block_size = real_block_alignment - PayloadPerAllocation; + const size_type target_elem_in_chain = chain.size() + min_elements; + for(size_type i = 0; i != n; ++i){ + //We allocate a new NodeBlock and put it the last + //element of the tree + char *mem_address = static_cast + (mp_segment_mngr_base->allocate_aligned(real_block_size, real_block_alignment)); + if(!mem_address){ + //In case of error, free memory deallocating all nodes (the new ones allocated + //in this function plus previously stored nodes in chain). + this->priv_deallocate_nodes(chain, max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + throw_bad_alloc(); + } + block_info_t &c_info = *new(mem_address)block_info_t(); + mem_address += HdrSize; + this->priv_fill_chain_remaining_to_block(chain, target_elem_in_chain, c_info, mem_address, real_num_node, real_node_size); + const size_type free_nodes = c_info.free_nodes.size(); + if(free_nodes){ + const bool is_full = free_nodes == real_num_node; + BOOST_ASSERT(free_nodes < real_num_node); + m_totally_free_blocks += static_cast(is_full); + block_container_traits_t::insert_was_empty(m_block_container, c_info, is_full); + } + } + } + + void priv_append_from_new_blocks( size_type min_elements, multiallocation_chain &chain + , const size_type max_free_blocks + , const size_type real_block_alignment, const size_type real_node_size + , const size_type real_num_node, const size_type num_subblocks + , AlignOnlyFalse) + { + BOOST_ASSERT(m_block_container.empty()); + BOOST_ASSERT(min_elements > 0); + const size_type n = (min_elements - 1)/real_num_node + 1; + const size_type real_block_size = real_block_alignment*num_subblocks - PayloadPerAllocation; + const size_type elements_per_subblock_mid = (real_block_alignment - HdrOffsetSize)/real_node_size; + const size_type elements_per_subblock_end = (real_block_alignment - HdrOffsetSize - PayloadPerAllocation) / real_node_size; + const size_type hdr_subblock_elements = (real_block_alignment - HdrSize - PayloadPerAllocation)/real_node_size; + const size_type target_elem_in_chain = chain.size() + min_elements; + + for(size_type i = 0; i != n; ++i){ + //We allocate a new NodeBlock and put it the last + //element of the tree + char *mem_address = static_cast + (mp_segment_mngr_base->allocate_aligned(real_block_size, real_block_alignment)); + if(!mem_address){ + //In case of error, free memory deallocating all nodes (the new ones allocated + //in this function plus previously stored nodes in chain). + this->priv_deallocate_nodes(chain, max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + throw_bad_alloc(); + } + //First initialize header information on the last subblock + char *hdr_addr = mem_address + real_block_alignment*(num_subblocks-1); + block_info_t &c_info = *new(hdr_addr)block_info_t(); + //Some structural checks + BOOST_ASSERT(static_cast(&static_cast(c_info).hdr_offset) == + static_cast(&c_info)); (void)c_info; + for( size_type subblock = 0, maxsubblock = num_subblocks - 1 + ; subblock < maxsubblock + ; ++subblock, mem_address += real_block_alignment){ + //Initialize header offset mark + new(mem_address) hdr_offset_holder(size_type(hdr_addr - mem_address)); + const size_type elements_per_subblock = (subblock != (maxsubblock - 1)) ? elements_per_subblock_mid : elements_per_subblock_end; + this->priv_fill_chain_remaining_to_block + (chain, target_elem_in_chain, c_info, mem_address + HdrOffsetSize, elements_per_subblock, real_node_size); + } + this->priv_fill_chain_remaining_to_block + (chain, target_elem_in_chain, c_info, hdr_addr + HdrSize, hdr_subblock_elements, real_node_size); + m_totally_free_blocks += static_cast(c_info.free_nodes.size() == real_num_node); + if (c_info.free_nodes.size()) + m_block_container.push_front(c_info); + } + } + + //!Allocates array of count elements. Can throw + void *priv_allocate_node( const size_type max_free_blocks, const size_type real_block_alignment, const size_type real_node_size + , const size_type real_num_node, const size_type num_subblocks) + { + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + //If there are no free nodes we allocate a new block + if(!m_block_container.empty()){ + //We take the first free node the multiset can't be empty + free_nodes_t &free_nodes = m_block_container.begin()->free_nodes; + BOOST_ASSERT(!free_nodes.empty()); + const size_type free_nodes_count = free_nodes.size(); + void *first_node = boost::movelib::to_raw_pointer(free_nodes.pop_front()); + if(free_nodes.empty()){ + block_container_traits_t::erase_first(m_block_container); + } + m_totally_free_blocks -= static_cast(free_nodes_count == real_num_node); + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + return first_node; + } + else{ + multiallocation_chain chain; + this->priv_append_from_new_blocks + (1, chain, max_free_blocks, real_block_alignment, real_node_size, real_num_node, num_subblocks, IsAlignOnly()); + void *node = boost::movelib::to_raw_pointer(chain.pop_front()); + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + return node; + } + } + + void priv_allocate_nodes( const size_type n, multiallocation_chain &chain + , const size_type max_free_blocks, const size_type real_block_alignment, const size_type real_node_size + , const size_type real_num_node, const size_type num_subblocks) + { + size_type i = 0; + BOOST_TRY{ + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + while(i != n){ + //If there are no free nodes we allocate all needed blocks + if (m_block_container.empty()){ + this->priv_append_from_new_blocks + (n - i, chain, max_free_blocks, real_block_alignment, real_node_size, real_num_node, num_subblocks, IsAlignOnly()); + BOOST_ASSERT(m_block_container.empty() || (++m_block_container.cbegin() == m_block_container.cend())); + BOOST_ASSERT(chain.size() == n); + break; + } + free_nodes_t &free_nodes = m_block_container.begin()->free_nodes; + const size_type free_nodes_count_before = free_nodes.size(); + m_totally_free_blocks -= static_cast(free_nodes_count_before == real_num_node); + const size_type num_left = n-i; + const size_type num_elems = (num_left < free_nodes_count_before) ? num_left : free_nodes_count_before; + typedef typename free_nodes_t::iterator free_nodes_iterator; + + if(num_left < free_nodes_count_before){ + const free_nodes_iterator it_bbeg(free_nodes.before_begin()); + free_nodes_iterator it_bend(it_bbeg); + for(size_type j = 0; j != num_elems; ++j){ + ++it_bend; + } + free_nodes_iterator it_end = it_bend; ++it_end; + free_nodes_iterator it_beg = it_bbeg; ++it_beg; + free_nodes.erase_after(it_bbeg, it_end, num_elems); + chain.incorporate_after(chain.last(), &*it_beg, &*it_bend, num_elems); + //chain.splice_after(chain.last(), free_nodes, it_bbeg, it_bend, num_elems); + BOOST_ASSERT(!free_nodes.empty()); + } + else{ + const free_nodes_iterator it_beg(free_nodes.begin()), it_bend(free_nodes.last()); + free_nodes.clear(); + chain.incorporate_after(chain.last(), &*it_beg, &*it_bend, num_elems); + block_container_traits_t::erase_first(m_block_container); + } + i += num_elems; + } + } + BOOST_CATCH(...){ + this->priv_deallocate_nodes(chain, max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + BOOST_RETHROW + } + BOOST_CATCH_END + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + } + + //!Deallocates an array pointed by ptr. Never throws + void priv_deallocate_node( void *pElem + , const size_type max_free_blocks, const size_type real_num_node + , const size_type num_subblocks, const size_type real_block_alignment) + { + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + block_info_t &block_info = *this->priv_block_from_node(pElem, real_block_alignment); + const size_type prev_free_nodes = block_info.free_nodes.size(); + BOOST_ASSERT(block_info.free_nodes.size() < real_num_node); + + //We put the node at the beginning of the free node list + block_info.free_nodes.push_back(void_pointer(pElem)); + + //The loop reinserts all blocks except the last one + this->priv_reinsert_block(block_info, prev_free_nodes == 0, real_num_node); + this->priv_deallocate_free_blocks(max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + } + + void priv_deallocate_nodes( multiallocation_chain &nodes + , const size_type max_free_blocks, const size_type real_num_node + , const size_type num_subblocks, const size_type real_block_alignment) + { + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + //To take advantage of node locality, wait until two + //nodes belong to different blocks. Only then reinsert + //the block of the first node in the block tree. + //Cache of the previous block + block_info_t *prev_block_info = 0; + + //If block was empty before this call, it's not already + //inserted in the block tree. + bool prev_block_was_empty = false; + typedef typename free_nodes_t::iterator free_nodes_iterator; + { + const free_nodes_iterator itbb(nodes.before_begin()), ite(nodes.end()); + free_nodes_iterator itf(nodes.begin()), itbf(itbb); + size_type splice_node_count = size_type(-1); + while(itf != ite){ + void *pElem = boost::movelib::to_raw_pointer(boost::movelib::iterator_to_raw_pointer(itf)); + block_info_t &block_info = *this->priv_block_from_node(pElem, real_block_alignment); + BOOST_ASSERT(block_info.free_nodes.size() < real_num_node); + ++splice_node_count; + + //If block change is detected calculate the cached block position in the tree + if(&block_info != prev_block_info){ + if(prev_block_info){ //Make sure we skip the initial "dummy" cache + free_nodes_iterator it(itbb); ++it; + nodes.erase_after(itbb, itf, splice_node_count); + prev_block_info->free_nodes.incorporate_after(prev_block_info->free_nodes.last(), &*it, &*itbf, splice_node_count); + this->priv_reinsert_block(*prev_block_info, prev_block_was_empty, real_num_node); + splice_node_count = 0; + } + //Update cache with new data + prev_block_was_empty = block_info.free_nodes.empty(); + prev_block_info = &block_info; + } + itbf = itf; + ++itf; + } + } + if(prev_block_info){ + //The loop reinserts all blocks except the last one + const free_nodes_iterator itfirst(nodes.begin()), itlast(nodes.last()); + const size_type splice_node_count = nodes.size(); + nodes.clear(); + prev_block_info->free_nodes.incorporate_after(prev_block_info->free_nodes.last(), &*itfirst, &*itlast, splice_node_count); + this->priv_reinsert_block(*prev_block_info, prev_block_was_empty, real_num_node); + this->priv_deallocate_free_blocks(max_free_blocks, real_num_node, num_subblocks, real_block_alignment); + } + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + } + + void priv_reinsert_block(block_info_t &prev_block_info, const bool prev_block_was_empty, const size_type real_num_node) + { + //Cache the free nodes from the block + const size_type this_block_free_nodes = prev_block_info.free_nodes.size(); + const bool is_full = this_block_free_nodes == real_num_node; + + //Update free block count + m_totally_free_blocks += static_cast(is_full); + if(prev_block_was_empty){ + block_container_traits_t::insert_was_empty(m_block_container, prev_block_info, is_full); + } + else{ + block_container_traits_t::reinsert_was_used(m_block_container, prev_block_info, is_full); + } + } + + block_info_t *priv_block_from_node(void *node, const size_type real_block_alignment, AlignOnlyFalse) const + { + hdr_offset_holder *hdr_off_holder = + reinterpret_cast((std::size_t)node & size_type(~(real_block_alignment - 1))); + BOOST_ASSERT(0 == ((std::size_t)hdr_off_holder & (real_block_alignment - 1))); + BOOST_ASSERT(0 == (hdr_off_holder->hdr_offset & (real_block_alignment - 1))); + block_info_t *block = reinterpret_cast + (reinterpret_cast(hdr_off_holder) + hdr_off_holder->hdr_offset); + BOOST_ASSERT(block->hdr_offset == 0); + return block; + } + + block_info_t *priv_block_from_node(void *node, const size_type real_block_alignment, AlignOnlyTrue) const + { + return (block_info_t *)((std::size_t)node & std::size_t(~(real_block_alignment - 1))); + } + + block_info_t *priv_block_from_node(void *node, const size_type real_block_alignment) const + { return this->priv_block_from_node(node, real_block_alignment, IsAlignOnly()); } + + //!Deallocates all used memory. Never throws + void priv_clear(const size_type num_subblocks, const size_type real_block_alignment, const size_type real_num_node) + { + #ifndef NDEBUG + block_iterator it = m_block_container.begin(); + block_iterator itend = m_block_container.end(); + size_type n_free_nodes = 0; + for(; it != itend; ++it){ + //Check for memory leak + BOOST_ASSERT(it->free_nodes.size() == real_num_node); + ++n_free_nodes; + } + BOOST_ASSERT(n_free_nodes == m_totally_free_blocks); + #endif + //Check for memory leaks + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + multiallocation_chain chain; + m_block_container.clear_and_dispose(block_destroyer(this, chain, num_subblocks, real_block_alignment, real_num_node)); + this->mp_segment_mngr_base->deallocate_many(chain); + m_totally_free_blocks = 0; + this->priv_invariants(real_num_node, num_subblocks, real_block_alignment); + } + + public: + private_adaptive_node_pool_impl_common(segment_manager_base_type *segment_mngr_base) + //General purpose allocator + : mp_segment_mngr_base(segment_mngr_base) + , m_block_container() + , m_totally_free_blocks(0) + {} + + size_type num_free_nodes() + { + typedef typename block_container_t::const_iterator citerator; + size_type count = 0; + citerator it (m_block_container.begin()), itend(m_block_container.end()); + for(; it != itend; ++it){ + count += it->free_nodes.size(); + } + return count; + } + + void swap(private_adaptive_node_pool_impl_common &other) + { + std::swap(mp_segment_mngr_base, other.mp_segment_mngr_base); + std::swap(m_totally_free_blocks, other.m_totally_free_blocks); + m_block_container.swap(other.m_block_container); + } + + //!Returns the segment manager. Never throws + segment_manager_base_type* get_segment_manager_base()const + { return boost::movelib::to_raw_pointer(mp_segment_mngr_base); } +}; + +template< class SizeType + , std::size_t HdrSize + , std::size_t PayloadPerAllocation + , std::size_t RealNodeSize + , std::size_t NodesPerBlock + , std::size_t HdrOffsetSize + , std::size_t OverheadPercent + , bool AlignOnly> +struct calculate_alignment_ct +{ + static const std::size_t alignment = upper_power_of_2_ct::value; + static const std::size_t num_subblocks = 0; + static const std::size_t real_num_node = (alignment - PayloadPerAllocation - HdrSize)/RealNodeSize; +}; + +template< class SizeType + , std::size_t HdrSize + , std::size_t PayloadPerAllocation + , std::size_t RealNodeSize + , std::size_t NodesPerBlock + , std::size_t HdrOffsetSize + , std::size_t OverheadPercent> +struct calculate_alignment_ct + < SizeType + , HdrSize + , PayloadPerAllocation + , RealNodeSize + , NodesPerBlock + , HdrOffsetSize + , OverheadPercent + , false> +{ + typedef typename candidate_power_of_2_ct + < upper_power_of_2_ct::value + , RealNodeSize + , PayloadPerAllocation + , NodesPerBlock + , HdrSize + , HdrOffsetSize + , OverheadPercent + >::type type; + + static const std::size_t alignment = type::alignment; + static const std::size_t num_subblocks = type::num_subblocks; + static const std::size_t real_num_node = type::real_num_node; +}; + + +///////////////////////////////////////////// +// +// private_adaptive_node_pool_impl_ct +// +///////////////////////////////////////////// +template< class SegmentManagerBase + , std::size_t MaxFreeBlocks + , std::size_t NodeSize + , std::size_t NodesPerBlock + , std::size_t OverheadPercent + , unsigned int Flags> +class private_adaptive_node_pool_impl_ct + : public private_adaptive_node_pool_impl_common +{ + typedef private_adaptive_node_pool_impl_common base_t; + + //Non-copyable + private_adaptive_node_pool_impl_ct(); + private_adaptive_node_pool_impl_ct(const private_adaptive_node_pool_impl_ct &); + private_adaptive_node_pool_impl_ct &operator=(const private_adaptive_node_pool_impl_ct &); + + public: + typedef typename base_t::void_pointer void_pointer; + typedef typename base_t::size_type size_type; + typedef typename base_t::multiallocation_chain multiallocation_chain; + typedef typename base_t::segment_manager_base_type segment_manager_base_type; + + static const typename base_t::size_type PayloadPerAllocation = base_t::PayloadPerAllocation; + + //align_only + static const bool AlignOnly = base_t::AlignOnly; + + private: + static const size_type MaxAlign = base_t::MaxAlign; + static const size_type HdrSize = base_t::HdrSize; + static const size_type HdrOffsetSize = base_t::HdrOffsetSize; + + static const size_type RealNodeSize = lcm_ct::value>::value; + + typedef calculate_alignment_ct + < size_type, HdrSize, PayloadPerAllocation + , RealNodeSize, NodesPerBlock, HdrOffsetSize, OverheadPercent, AlignOnly> data_t; + + //Round the size to a power of two value. + //This is the total memory size (including payload) that we want to + //allocate from the general-purpose allocator + static const size_type NumSubBlocks = data_t::num_subblocks; + static const size_type RealNumNode = data_t::real_num_node; + static const size_type RealBlockAlignment = data_t::alignment; + + public: + + //!Constructor from a segment manager. Never throws + private_adaptive_node_pool_impl_ct(typename base_t::segment_manager_base_type *segment_mngr_base) + //General purpose allocator + : base_t(segment_mngr_base) + {} + + //!Destructor. Deallocates all allocated blocks. Never throws + ~private_adaptive_node_pool_impl_ct() + { this->priv_clear(NumSubBlocks, data_t::alignment, RealNumNode); } + + size_type get_real_num_node() const + { return RealNumNode; } + + //!Allocates array of count elements. Can throw + void *allocate_node() + { + return this->priv_allocate_node + (MaxFreeBlocks, data_t::alignment, RealNodeSize, RealNumNode, NumSubBlocks); + } + + //!Allocates n nodes. + //!Can throw + void allocate_nodes(const size_type n, multiallocation_chain &chain) + { + this->priv_allocate_nodes + (n, chain, MaxFreeBlocks, data_t::alignment, RealNodeSize, RealNumNode, NumSubBlocks); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *pElem) + { + this->priv_deallocate_node(pElem, MaxFreeBlocks, RealNumNode, NumSubBlocks, RealBlockAlignment); + } + + //!Deallocates a linked list of nodes. Never throws + void deallocate_nodes(multiallocation_chain &nodes) + { + this->priv_deallocate_nodes(nodes, MaxFreeBlocks, RealNumNode, NumSubBlocks, data_t::alignment); + } + + void deallocate_free_blocks() + { this->priv_deallocate_free_blocks(0, RealNumNode, NumSubBlocks, data_t::alignment); } + + //Deprecated, use deallocate_free_blocks + void deallocate_free_chunks() + { this->priv_deallocate_free_blocks(0, RealNumNode, NumSubBlocks, data_t::alignment); } +}; + +///////////////////////////////////////////// +// +// private_adaptive_node_pool_impl_rt +// +///////////////////////////////////////////// +template +struct private_adaptive_node_pool_impl_rt_data +{ + typedef SizeType size_type; + + private_adaptive_node_pool_impl_rt_data(size_type max_free_blocks, size_type real_node_size) + : m_max_free_blocks(max_free_blocks), m_real_node_size(real_node_size) + , m_real_block_alignment(), m_num_subblocks(), m_real_num_node() + {} + + const size_type m_max_free_blocks; + const size_type m_real_node_size; + //Round the size to a power of two value. + //This is the total memory size (including payload) that we want to + //allocate from the general-purpose allocator + size_type m_real_block_alignment; + size_type m_num_subblocks; + //This is the real number of nodes per block + size_type m_real_num_node; +}; + + +template +class private_adaptive_node_pool_impl_rt + : private private_adaptive_node_pool_impl_rt_data + , public private_adaptive_node_pool_impl_common +{ + typedef private_adaptive_node_pool_impl_common impl_t; + typedef private_adaptive_node_pool_impl_rt_data data_t; + + //Non-copyable + private_adaptive_node_pool_impl_rt(); + private_adaptive_node_pool_impl_rt(const private_adaptive_node_pool_impl_rt &); + private_adaptive_node_pool_impl_rt &operator=(const private_adaptive_node_pool_impl_rt &); + + protected: + + typedef typename impl_t::void_pointer void_pointer; + typedef typename impl_t::size_type size_type; + typedef typename impl_t::multiallocation_chain multiallocation_chain; + + static const typename impl_t::size_type PayloadPerAllocation = impl_t::PayloadPerAllocation; + + //Flags + //align_only + static const bool AlignOnly = impl_t::AlignOnly; + + static const size_type HdrSize = impl_t::HdrSize; + static const size_type HdrOffsetSize = impl_t::HdrOffsetSize; + + public: + + //!Segment manager typedef + typedef SegmentManagerBase segment_manager_base_type; + + //!Constructor from a segment manager. Never throws + private_adaptive_node_pool_impl_rt + ( segment_manager_base_type *segment_mngr_base + , size_type node_size + , size_type nodes_per_block + , size_type max_free_blocks + , unsigned char overhead_percent + ) + : data_t(max_free_blocks, lcm(node_size, size_type(alignment_of::value))) + , impl_t(segment_mngr_base) + { + if(AlignOnly){ + this->m_real_block_alignment = upper_power_of_2(HdrSize + this->m_real_node_size*nodes_per_block); + this->m_real_num_node = (this->m_real_block_alignment - PayloadPerAllocation - HdrSize)/this->m_real_node_size; + } + else{ + candidate_power_of_2_rt ( upper_power_of_2(HdrSize + PayloadPerAllocation + this->m_real_node_size) + , this->m_real_node_size + , PayloadPerAllocation + , nodes_per_block + , HdrSize + , HdrOffsetSize + , overhead_percent + , this->m_real_block_alignment + , this->m_num_subblocks + , this->m_real_num_node); + } + } + + //!Destructor. Deallocates all allocated blocks. Never throws + ~private_adaptive_node_pool_impl_rt() + { this->priv_clear(this->m_num_subblocks, this->m_real_block_alignment, this->m_real_num_node); } + + size_type get_real_num_node() const + { return this->m_real_num_node; } + + //!Allocates array of count elements. Can throw + void *allocate_node() + { + return this->priv_allocate_node + (this->m_max_free_blocks, this->m_real_block_alignment, this->m_real_node_size, this->m_real_num_node, this->m_num_subblocks); + } + + //!Allocates n nodes. + //!Can throw + void allocate_nodes(const size_type n, multiallocation_chain &chain) + { + + this->priv_allocate_nodes + (n, chain, this->m_max_free_blocks, this->m_real_block_alignment, this->m_real_node_size, this->m_real_num_node, this->m_num_subblocks); + } + + //!Deallocates an array pointed by ptr. Never throws + void deallocate_node(void *pElem) + { + this->priv_deallocate_node(pElem, this->m_max_free_blocks, this->m_real_num_node, this->m_num_subblocks, this->m_real_block_alignment); + } + + //!Deallocates a linked list of nodes. Never throws + void deallocate_nodes(multiallocation_chain &nodes) + { + this->priv_deallocate_nodes(nodes, this->m_max_free_blocks, this->m_real_num_node, this->m_num_subblocks, this->m_real_block_alignment); + } + + void deallocate_free_blocks() + { this->priv_deallocate_free_blocks(0, this->m_real_num_node, this->m_num_subblocks, this->m_real_block_alignment); } + + //Deprecated, use deallocate_free_blocks + void deallocate_free_chunks() + { this->priv_deallocate_free_blocks(0, this->m_real_num_node, this->m_num_subblocks, this->m_real_block_alignment); } +}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#include + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ADAPTIVE_NODE_POOL_IMPL_HPP diff --git a/third-party/boost/boost/container/detail/addressof.hpp b/third-party/boost/boost/container/detail/addressof.hpp new file mode 100644 index 000000000..b3b8a4dd6 --- /dev/null +++ b/third-party/boost/boost/container/detail/addressof.hpp @@ -0,0 +1,41 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_ADDRESSOF_HPP +#define BOOST_CONTAINER_DETAIL_ADDRESSOF_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +namespace boost { +namespace container { +namespace dtl { + +template +BOOST_CONTAINER_FORCEINLINE T* addressof(T& obj) +{ + return static_cast( + static_cast( + const_cast( + &reinterpret_cast(obj) + ))); +} + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ADDRESSOF_HPP diff --git a/third-party/boost/boost/container/detail/advanced_insert_int.hpp b/third-party/boost/boost/container/detail/advanced_insert_int.hpp new file mode 100644 index 000000000..17ceb013f --- /dev/null +++ b/third-party/boost/boost/container/detail/advanced_insert_int.hpp @@ -0,0 +1,495 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2008-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP +#define BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +// container +#include +// container/detail +#include +#include +#include +#include +#include +#include +#include +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#include +#endif +// move +#include +// other +#include +#include + +namespace boost { namespace container { namespace dtl { + +template +struct move_insert_range_proxy +{ + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + explicit move_insert_range_proxy(FwdIt first) + : first_(first) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + { + this->first_ = ::boost::container::uninitialized_move_alloc_n_source + (a, this->first_, n, p); + } + + void copy_n_and_update(Allocator &, Iterator p, size_type n) + { + this->first_ = ::boost::container::move_n_source(this->first_, n, p); + } + + FwdIt first_; +}; + + +template +struct insert_range_proxy +{ + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + explicit insert_range_proxy(FwdIt first) + : first_(first) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + { + this->first_ = ::boost::container::uninitialized_copy_alloc_n_source(a, this->first_, n, p); + } + + void copy_n_and_update(Allocator &, Iterator p, size_type n) + { + this->first_ = ::boost::container::copy_n_source(this->first_, n, p); + } + + FwdIt first_; +}; + + +template +struct insert_n_copies_proxy +{ + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + explicit insert_n_copies_proxy(const value_type &v) + : v_(v) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { boost::container::uninitialized_fill_alloc_n(a, v_, n, p); } + + void copy_n_and_update(Allocator &, Iterator p, size_type n) const + { + for (; 0 < n; --n, ++p){ + *p = v_; + } + } + + const value_type &v_; +}; + +template +struct insert_value_initialized_n_proxy +{ + typedef ::boost::container::allocator_traits alloc_traits; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { boost::container::uninitialized_value_init_alloc_n(a, n, p); } + + void copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { + for (; 0 < n; --n, ++p){ + typename aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); + alloc_traits::construct(a, vp); + value_destructor on_exit(a, *vp); (void)on_exit; + *p = ::boost::move(*vp); + } + } +}; + +template +struct insert_default_initialized_n_proxy +{ + typedef ::boost::container::allocator_traits alloc_traits; + typedef typename allocator_traits::size_type size_type; + typedef typename allocator_traits::value_type value_type; + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { boost::container::uninitialized_default_init_alloc_n(a, n, p); } + + void copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { + if(!is_pod::value){ + for (; 0 < n; --n, ++p){ + typename aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); + alloc_traits::construct(a, vp, default_init); + value_destructor on_exit(a, *vp); (void)on_exit; + *p = ::boost::move(*vp); + } + } + } +}; + +template +struct insert_copy_proxy +{ + typedef boost::container::allocator_traits alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; + + explicit insert_copy_proxy(const value_type &v) + : v_(v) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), v_); + } + + void copy_n_and_update(Allocator &, Iterator p, size_type n) const + { + BOOST_ASSERT(n == 1); (void)n; + *p = v_; + } + + const value_type &v_; +}; + + +template +struct insert_move_proxy +{ + typedef boost::container::allocator_traits alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; + + explicit insert_move_proxy(value_type &v) + : v_(v) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) const + { + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::move(v_) ); + } + + void copy_n_and_update(Allocator &, Iterator p, size_type n) const + { + BOOST_ASSERT(n == 1); (void)n; + *p = ::boost::move(v_); + } + + value_type &v_; +}; + +template +insert_move_proxy get_insert_value_proxy(BOOST_RV_REF(typename boost::container::iterator_traits::value_type) v) +{ + return insert_move_proxy(v); +} + +template +insert_copy_proxy get_insert_value_proxy(const typename boost::container::iterator_traits::value_type &v) +{ + return insert_copy_proxy(v); +} + +}}} //namespace boost { namespace container { namespace dtl { + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include +#include + +namespace boost { +namespace container { +namespace dtl { + +template +struct insert_nonmovable_emplace_proxy +{ + typedef boost::container::allocator_traits alloc_traits; + typedef typename alloc_traits::size_type size_type; + typedef typename alloc_traits::value_type value_type; + + typedef typename build_number_seq::type index_tuple_t; + + explicit insert_nonmovable_emplace_proxy(BOOST_FWD_REF(Args)... args) + : args_(args...) + {} + + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n) + { this->priv_uninitialized_copy_some_and_update(a, index_tuple_t(), p, n); } + + private: + template + void priv_uninitialized_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) + { + BOOST_ASSERT(n == 1); (void)n; + alloc_traits::construct( a, boost::movelib::iterator_to_raw_pointer(p), ::boost::forward(get(this->args_))... ); + } + + protected: + tuple args_; +}; + +template +struct insert_emplace_proxy + : public insert_nonmovable_emplace_proxy +{ + typedef insert_nonmovable_emplace_proxy base_t; + typedef boost::container::allocator_traits alloc_traits; + typedef typename base_t::value_type value_type; + typedef typename base_t::size_type size_type; + typedef typename base_t::index_tuple_t index_tuple_t; + + explicit insert_emplace_proxy(BOOST_FWD_REF(Args)... args) + : base_t(::boost::forward(args)...) + {} + + void copy_n_and_update(Allocator &a, Iterator p, size_type n) + { this->priv_copy_some_and_update(a, index_tuple_t(), p, n); } + + private: + + template + void priv_copy_some_and_update(Allocator &a, const index_tuple&, Iterator p, size_type n) + { + BOOST_ASSERT(n ==1); (void)n; + typename aligned_storage::value>::type v; + value_type *vp = reinterpret_cast(v.data); + alloc_traits::construct(a, vp, + ::boost::forward(get(this->args_))...); + BOOST_TRY{ + *p = ::boost::move(*vp); + } + BOOST_CATCH(...){ + alloc_traits::destroy(a, vp); + BOOST_RETHROW + } + BOOST_CATCH_END + alloc_traits::destroy(a, vp); + } +}; + +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template +struct insert_emplace_proxy::value_type> + : public insert_move_proxy +{ + explicit insert_emplace_proxy(typename boost::container::allocator_traits::value_type &&v) + : insert_move_proxy(v) + {} +}; + +//We use "add_const" here as adding "const" only confuses MSVC12(and maybe later) provoking +//compiler error C2752 ("more than one partial specialization matches"). +//Any problem is solvable with an extra layer of indirection? ;-) +template +struct insert_emplace_proxy::value_type>::type + > + : public insert_copy_proxy +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +template +struct insert_emplace_proxy::value_type &> + : public insert_copy_proxy +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +template +struct insert_emplace_proxy::value_type>::type & + > + : public insert_copy_proxy +{ + explicit insert_emplace_proxy(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +}}} //namespace boost { namespace container { namespace dtl { + +#else // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include + +namespace boost { +namespace container { +namespace dtl { + +#define BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE(N) \ +template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ +struct insert_nonmovable_emplace_proxy##N\ +{\ + typedef boost::container::allocator_traits alloc_traits;\ + typedef typename alloc_traits::size_type size_type;\ + typedef typename alloc_traits::value_type value_type;\ + \ + explicit insert_nonmovable_emplace_proxy##N(BOOST_MOVE_UREF##N)\ + BOOST_MOVE_COLON##N BOOST_MOVE_FWD_INIT##N {}\ + \ + void uninitialized_copy_n_and_update(Allocator &a, Iterator p, size_type n)\ + {\ + BOOST_ASSERT(n == 1); (void)n;\ + alloc_traits::construct(a, boost::movelib::iterator_to_raw_pointer(p) BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ + }\ + \ + void copy_n_and_update(Allocator &, Iterator, size_type)\ + { BOOST_ASSERT(false); }\ + \ + protected:\ + BOOST_MOVE_MREF##N\ +};\ +\ +template< class Allocator, class Iterator BOOST_MOVE_I##N BOOST_MOVE_CLASS##N >\ +struct insert_emplace_proxy_arg##N\ + : insert_nonmovable_emplace_proxy##N< Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N >\ +{\ + typedef insert_nonmovable_emplace_proxy##N\ + < Allocator, Iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N > base_t;\ + typedef typename base_t::value_type value_type;\ + typedef typename base_t::size_type size_type;\ + typedef boost::container::allocator_traits alloc_traits;\ + \ + explicit insert_emplace_proxy_arg##N(BOOST_MOVE_UREF##N)\ + : base_t(BOOST_MOVE_FWD##N){}\ + \ + void copy_n_and_update(Allocator &a, Iterator p, size_type n)\ + {\ + BOOST_ASSERT(n == 1); (void)n;\ + typename aligned_storage::value>::type v;\ + BOOST_ASSERT((((size_type)(&v)) % alignment_of::value) == 0);\ + value_type *vp = reinterpret_cast(v.data);\ + alloc_traits::construct(a, vp BOOST_MOVE_I##N BOOST_MOVE_MFWD##N);\ + BOOST_TRY{\ + *p = ::boost::move(*vp);\ + }\ + BOOST_CATCH(...){\ + alloc_traits::destroy(a, vp);\ + BOOST_RETHROW\ + }\ + BOOST_CATCH_END\ + alloc_traits::destroy(a, vp);\ + }\ +};\ +// +BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE) +#undef BOOST_CONTAINER_ADVANCED_INSERT_INT_CODE + +#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template +struct insert_emplace_proxy_arg1::value_type> > + : public insert_move_proxy +{ + explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &v) + : insert_move_proxy(v) + {} +}; + +template +struct insert_emplace_proxy_arg1::value_type> + : public insert_copy_proxy +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +#else //e.g. MSVC10 & MSVC11 + +//Specializations to avoid an unneeded temporary when emplacing from a single argument o type value_type +template +struct insert_emplace_proxy_arg1::value_type> + : public insert_move_proxy +{ + explicit insert_emplace_proxy_arg1(typename boost::container::allocator_traits::value_type &&v) + : insert_move_proxy(v) + {} +}; + +//We use "add_const" here as adding "const" only confuses MSVC10&11 provoking +//compiler error C2752 ("more than one partial specialization matches"). +//Any problem is solvable with an extra layer of indirection? ;-) +template +struct insert_emplace_proxy_arg1::value_type>::type + > + : public insert_copy_proxy +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +template +struct insert_emplace_proxy_arg1::value_type &> + : public insert_copy_proxy +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +template +struct insert_emplace_proxy_arg1::value_type>::type & + > + : public insert_copy_proxy +{ + explicit insert_emplace_proxy_arg1(const typename boost::container::allocator_traits::value_type &v) + : insert_copy_proxy(v) + {} +}; + +#endif + +}}} //namespace boost { namespace container { namespace dtl { + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +#include + +#endif //#ifndef BOOST_CONTAINER_ADVANCED_INSERT_INT_HPP diff --git a/third-party/boost/boost/container/detail/algorithm.hpp b/third-party/boost/boost/container/detail/algorithm.hpp new file mode 100644 index 000000000..11844220e --- /dev/null +++ b/third-party/boost/boost/container/detail/algorithm.hpp @@ -0,0 +1,157 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ALGORITHM_HPP +#define BOOST_CONTAINER_DETAIL_ALGORITHM_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +namespace boost { +namespace container { + +using boost::intrusive::algo_equal; +using boost::intrusive::algo_lexicographical_compare; + +template +class binder1st +{ + public: + typedef typename Func::second_argument_type argument_type; + typedef typename Func::result_type result_type; + + binder1st(const Func& func, const typename Func::first_argument_type& arg) + : op(func), value(arg) + {} + + result_type operator()(const argument_type& arg) const + { return op(value, arg); } + + result_type operator()(argument_type& arg) const + { return op(value, arg); } + + private: + Func op; + typename Func::first_argument_type value; +}; + +template +inline binder1st bind1st(const Func& func, const T& arg) +{ return boost::container::binder1st(func, arg); } + +template +class binder2nd +{ + public: + typedef typename Func::first_argument_type argument_type; + typedef typename Func::result_type result_type; + + binder2nd(const Func& func, const typename Func::second_argument_type& arg) + : op(func), value(arg) + {} + + result_type operator()(const argument_type& arg) const + { return op(arg, value); } + + result_type operator()(argument_type& arg) const + { return op(arg, value); } + + private: + Func op; + typename Func::second_argument_type value; +}; + +template +inline binder2nd bind2nd(const Func& func, const T& arg) +{ + return (boost::container::binder2nd(func, arg)); +} + +template +class unary_negate +{ + public: + typedef typename Func::argument_type argument_type; + typedef typename Func::result_type result_type; + + explicit unary_negate(const Func& func) + : m_func(func) + {} + + bool operator()(const typename Func::argument_type& arg) const + { return !m_func(arg); } + + private: + Func m_func; +}; + +template inline +unary_negate not1(const Func& func) +{ + return boost::container::unary_negate(func); +} + +template +InputIt find_if(InputIt first, InputIt last, UnaryPredicate p) +{ + for (; first != last; ++first) { + if (p(*first)) { + return first; + } + } + return last; +} + +template +InputIt find_first_of(InputIt first1, InputIt last1, ForwardIt first2, ForwardIt last2, BinaryPredicate p) +{ + for (; first1 != last1; ++first1) { + for (ForwardIt it = first2; it != last2; ++it) { + if (p(*first1, *it)) { + return first1; + } + } + } + return last1; +} + +template +ForwardIt1 search(ForwardIt1 first1, ForwardIt1 last1, + ForwardIt2 first2, ForwardIt2 last2, BinaryPredicate p) +{ + for (; ; ++first1) { + ForwardIt1 it = first1; + for (ForwardIt2 it2 = first2; ; ++it, ++it2) { + if (it2 == last2) { + return first1; + } + if (it == last1) { + return last1; + } + if (!p(*it, *it2)) { + break; + } + } + } +} + +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ALGORITHM_HPP diff --git a/third-party/boost/boost/container/detail/alloc_helpers.hpp b/third-party/boost/boost/container/detail/alloc_helpers.hpp new file mode 100644 index 000000000..57c59e46c --- /dev/null +++ b/third-party/boost/boost/container/detail/alloc_helpers.hpp @@ -0,0 +1,60 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_ALLOC_TRAITS_HPP +#define BOOST_CONTAINER_DETAIL_ALLOC_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +// move +#include +#include + +namespace boost { +namespace container { +namespace dtl { + +template +inline void swap_alloc(AllocatorType &, AllocatorType &, dtl::false_type) + BOOST_NOEXCEPT_OR_NOTHROW +{} + +template +inline void swap_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) +{ boost::adl_move_swap(l, r); } + +template +inline void assign_alloc(AllocatorType &, const AllocatorType &, dtl::false_type) + BOOST_NOEXCEPT_OR_NOTHROW +{} + +template +inline void assign_alloc(AllocatorType &l, const AllocatorType &r, dtl::true_type) +{ l = r; } + +template +inline void move_alloc(AllocatorType &, AllocatorType &, dtl::false_type) + BOOST_NOEXCEPT_OR_NOTHROW +{} + +template +inline void move_alloc(AllocatorType &l, AllocatorType &r, dtl::true_type) +{ l = ::boost::move(r); } + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_ALLOC_TRAITS_HPP diff --git a/third-party/boost/boost/container/detail/alloc_lib.h b/third-party/boost/boost/container/detail/alloc_lib.h new file mode 100644 index 000000000..950ff722a --- /dev/null +++ b/third-party/boost/boost/container/detail/alloc_lib.h @@ -0,0 +1,314 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_ALLOC_LIB_EXT_H +#define BOOST_CONTAINER_ALLOC_LIB_EXT_H + +#include + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable : 4127) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*!An forward iterator to traverse the elements of a memory chain container.*/ +typedef struct multialloc_node_impl +{ + struct multialloc_node_impl *next_node_ptr; +} boost_cont_memchain_node; + + +/*!An forward iterator to traverse the elements of a memory chain container.*/ +typedef struct multialloc_it_impl +{ + boost_cont_memchain_node *node_ptr; +} boost_cont_memchain_it; + +/*!Memory chain: A container holding memory portions allocated by boost_cont_multialloc_nodes + and boost_cont_multialloc_arrays functions.*/ +typedef struct boost_cont_memchain_impl +{ + size_t num_mem; + boost_cont_memchain_node root_node; + boost_cont_memchain_node *last_node_ptr; +} boost_cont_memchain; + +/*!Advances the iterator one position so that it points to the next element in the memory chain*/ +#define BOOST_CONTAINER_MEMIT_NEXT(IT) (IT.node_ptr = IT.node_ptr->next_node_ptr) + +/*!Returns the address of the memory chain currently pointed by the iterator*/ +#define BOOST_CONTAINER_MEMIT_ADDR(IT) ((void*)IT.node_ptr) + +/*!Initializer for an iterator pointing to the position before the first element*/ +#define BOOST_CONTAINER_MEMCHAIN_BEFORE_BEGIN_IT(PMEMCHAIN) { &((PMEMCHAIN)->root_node) } + +/*!Initializer for an iterator pointing to the first element*/ +#define BOOST_CONTAINER_MEMCHAIN_BEGIN_IT(PMEMCHAIN) {(PMEMCHAIN)->root_node.next_node_ptr } + +/*!Initializer for an iterator pointing to the last element*/ +#define BOOST_CONTAINER_MEMCHAIN_LAST_IT(PMEMCHAIN) {(PMEMCHAIN)->last_node_ptr } + +/*!Initializer for an iterator pointing to one past the last element (end iterator)*/ +#define BOOST_CONTAINER_MEMCHAIN_END_IT(PMEMCHAIN) {(boost_cont_memchain_node *)0 } + +/*!True if IT is the end iterator, false otherwise*/ +#define BOOST_CONTAINER_MEMCHAIN_IS_END_IT(PMEMCHAIN, IT) (!(IT).node_ptr) + +/*!The address of the first memory portion hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_FIRSTMEM(PMEMCHAIN)((void*)((PMEMCHAIN)->root_node.next_node_ptr)) + +/*!The address of the last memory portion hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_LASTMEM(PMEMCHAIN) ((void*)((PMEMCHAIN)->last_node_ptr)) + +/*!The number of memory portions hold by the memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_SIZE(PMEMCHAIN) ((PMEMCHAIN)->num_mem) + +/*!Initializes the memory chain from the first memory portion, the last memory + portion and number of portions obtained from another memory chain*/ +#define BOOST_CONTAINER_MEMCHAIN_INIT_FROM(PMEMCHAIN, FIRST, LAST, NUM)\ + (PMEMCHAIN)->last_node_ptr = (boost_cont_memchain_node *)(LAST), \ + (PMEMCHAIN)->root_node.next_node_ptr = (boost_cont_memchain_node *)(FIRST), \ + (PMEMCHAIN)->num_mem = (NUM);\ +/**/ + +/*!Default initializes a memory chain. Postconditions: begin iterator is end iterator, + the number of portions is zero.*/ +#define BOOST_CONTAINER_MEMCHAIN_INIT(PMEMCHAIN)\ + ((PMEMCHAIN)->root_node.next_node_ptr = 0, (PMEMCHAIN)->last_node_ptr = &((PMEMCHAIN)->root_node), (PMEMCHAIN)->num_mem = 0)\ +/**/ + +/*!True if the memory chain is empty (holds no memory portions*/ +#define BOOST_CONTAINER_MEMCHAIN_EMPTY(PMEMCHAIN)\ + ((PMEMCHAIN)->num_mem == 0)\ +/**/ + +/*!Inserts a new memory portions in the front of the chain*/ +#define BOOST_CONTAINER_MEMCHAIN_PUSH_BACK(PMEMCHAIN, MEM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____tmp_mem____ = (boost_cont_memchain_node *)(MEM);\ + ____chain____->last_node_ptr->next_node_ptr = ____tmp_mem____;\ + ____tmp_mem____->next_node_ptr = 0;\ + ____chain____->last_node_ptr = ____tmp_mem____;\ + ++____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Inserts a new memory portions in the back of the chain*/ +#define BOOST_CONTAINER_MEMCHAIN_PUSH_FRONT(PMEMCHAIN, MEM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____tmp_mem____ = (boost_cont_memchain_node *)(MEM);\ + boost_cont_memchain *____root____ = &((PMEMCHAIN)->root_node);\ + if(!____chain____->root_node.next_node_ptr){\ + ____chain____->last_node_ptr = ____tmp_mem____;\ + }\ + boost_cont_memchain_node *____old_first____ = ____root____->next_node_ptr;\ + ____tmp_mem____->next_node_ptr = ____old_first____;\ + ____root____->next_node_ptr = ____tmp_mem____;\ + ++____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Erases the memory portion after the portion pointed by BEFORE_IT from the memory chain*/ +/*!Precondition: BEFORE_IT must be a valid iterator of the memory chain and it can't be the end iterator*/ +#define BOOST_CONTAINER_MEMCHAIN_ERASE_AFTER(PMEMCHAIN, BEFORE_IT)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____prev_node____ = (BEFORE_IT).node_ptr;\ + boost_cont_memchain_node *____erase_node____ = ____prev_node____->next_node_ptr;\ + if(____chain____->last_node_ptr == ____erase_node____){\ + ____chain____->last_node_ptr = &____chain____->root_node;\ + }\ + ____prev_node____->next_node_ptr = ____erase_node____->next_node_ptr;\ + --____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Erases the first portion from the memory chain. + Precondition: the memory chain must not be empty*/ +#define BOOST_CONTAINER_MEMCHAIN_POP_FRONT(PMEMCHAIN)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____prev_node____ = &____chain____->root_node;\ + boost_cont_memchain_node *____erase_node____ = ____prev_node____->next_node_ptr;\ + if(____chain____->last_node_ptr == ____erase_node____){\ + ____chain____->last_node_ptr = &____chain____->root_node;\ + }\ + ____prev_node____->next_node_ptr = ____erase_node____->next_node_ptr;\ + --____chain____->num_mem;\ + }while(0)\ +/**/ + +/*!Joins two memory chains inserting the portions of the second chain at the back of the first chain*/ +/* +#define BOOST_CONTAINER_MEMCHAIN_SPLICE_BACK(PMEMCHAIN, PMEMCHAIN2)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain *____chain2____ = (PMEMCHAIN2);\ + if(!____chain2____->root_node.next_node_ptr){\ + break;\ + }\ + else if(!____chain____->first_mem){\ + ____chain____->first_mem = ____chain2____->first_mem;\ + ____chain____->last_node_ptr = ____chain2____->last_node_ptr;\ + ____chain____->num_mem = ____chain2____->num_mem;\ + BOOST_CONTAINER_MEMCHAIN_INIT(*____chain2____);\ + }\ + else{\ + ____chain____->last_node_ptr->next_node_ptr = ____chain2____->first_mem;\ + ____chain____->last_node_ptr = ____chain2____->last_node_ptr;\ + ____chain____->num_mem += ____chain2____->num_mem;\ + }\ + }while(0)\*/ +/**/ + +/*!Joins two memory chains inserting the portions of the second chain at the back of the first chain*/ +#define BOOST_CONTAINER_MEMCHAIN_INCORPORATE_AFTER(PMEMCHAIN, BEFORE_IT, FIRST, BEFORELAST, NUM)\ + do{\ + boost_cont_memchain *____chain____ = (PMEMCHAIN);\ + boost_cont_memchain_node *____pnode____ = (BEFORE_IT).node_ptr;\ + boost_cont_memchain_node *____next____ = ____pnode____->next_node_ptr;\ + boost_cont_memchain_node *____first____ = (boost_cont_memchain_node *)(FIRST);\ + boost_cont_memchain_node *____blast____ = (boost_cont_memchain_node *)(BEFORELAST);\ + size_t ____num____ = (NUM);\ + if(!____num____){\ + break;\ + }\ + if(____pnode____ == ____chain____->last_node_ptr){\ + ____chain____->last_node_ptr = ____blast____;\ + }\ + ____pnode____->next_node_ptr = ____first____;\ + ____blast____->next_node_ptr = ____next____;\ + ____chain____->num_mem += ____num____;\ + }while(0)\ +/**/ + +/*!Indicates the all elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays + must be contiguous.*/ +#define DL_MULTIALLOC_ALL_CONTIGUOUS ((size_t)(-1)) + +/*!Indicates the number of contiguous elements allocated by boost_cont_multialloc_nodes or boost_cont_multialloc_arrays + should be selected by those functions.*/ +#define DL_MULTIALLOC_DEFAULT_CONTIGUOUS ((size_t)(0)) + +typedef struct boost_cont_malloc_stats_impl +{ + size_t max_system_bytes; + size_t system_bytes; + size_t in_use_bytes; +} boost_cont_malloc_stats_t; + +typedef unsigned int allocation_type; + +enum +{ + // constants for allocation commands + BOOST_CONTAINER_ALLOCATE_NEW = 0X01, + BOOST_CONTAINER_EXPAND_FWD = 0X02, + BOOST_CONTAINER_EXPAND_BWD = 0X04, + BOOST_CONTAINER_SHRINK_IN_PLACE = 0X08, + BOOST_CONTAINER_NOTHROW_ALLOCATION = 0X10, +// BOOST_CONTAINER_ZERO_MEMORY = 0X20, + BOOST_CONTAINER_TRY_SHRINK_IN_PLACE = 0X40, + BOOST_CONTAINER_EXPAND_BOTH = BOOST_CONTAINER_EXPAND_FWD | BOOST_CONTAINER_EXPAND_BWD, + BOOST_CONTAINER_EXPAND_OR_NEW = BOOST_CONTAINER_ALLOCATE_NEW | BOOST_CONTAINER_EXPAND_BOTH +}; + +//#define BOOST_CONTAINERDLMALLOC__FOOTERS +#ifndef BOOST_CONTAINERDLMALLOC__FOOTERS +enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t) }; +#else +enum { BOOST_CONTAINER_ALLOCATION_PAYLOAD = sizeof(size_t)*2 }; +#endif + +typedef struct boost_cont_command_ret_impl +{ + void *first; + int second; +}boost_cont_command_ret_t; + +size_t boost_cont_size(const void *p); + +void* boost_cont_malloc(size_t bytes); + +void boost_cont_free(void* mem); + +void* boost_cont_memalign(size_t bytes, size_t alignment); + +int boost_cont_multialloc_nodes + (size_t n_elements, size_t elem_size, size_t contiguous_elements, boost_cont_memchain *pchain); + +int boost_cont_multialloc_arrays + (size_t n_elements, const size_t *sizes, size_t sizeof_element, size_t contiguous_elements, boost_cont_memchain *pchain); + +void boost_cont_multidealloc(boost_cont_memchain *pchain); + +size_t boost_cont_footprint(); + +size_t boost_cont_allocated_memory(); + +size_t boost_cont_chunksize(const void *p); + +int boost_cont_all_deallocated(); + +boost_cont_malloc_stats_t boost_cont_malloc_stats(); + +size_t boost_cont_in_use_memory(); + +int boost_cont_trim(size_t pad); + +int boost_cont_mallopt(int parameter_number, int parameter_value); + +int boost_cont_grow + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received); + +int boost_cont_shrink + (void* oldmem, size_t minbytes, size_t maxbytes, size_t *received, int do_commit); + +void* boost_cont_alloc + (size_t minbytes, size_t preferred_bytes, size_t *received_bytes); + +int boost_cont_malloc_check(); + +boost_cont_command_ret_t boost_cont_allocation_command + ( allocation_type command + , size_t sizeof_object + , size_t limit_objects + , size_t preferred_objects + , size_t *received_objects + , void *reuse_ptr + ); + +void *boost_cont_sync_create(); + +void boost_cont_sync_destroy(void *sync); + +int boost_cont_sync_lock(void *sync); + +void boost_cont_sync_unlock(void *sync); + +int boost_cont_global_sync_lock(); + +void boost_cont_global_sync_unlock(); + +#ifdef __cplusplus +} //extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning (pop) +#endif + + +#endif //#define BOOST_CONTAINERDLMALLOC__EXT_H diff --git a/third-party/boost/boost/container/detail/allocation_type.hpp b/third-party/boost/boost/container/detail/allocation_type.hpp new file mode 100644 index 000000000..1e8aa6731 --- /dev/null +++ b/third-party/boost/boost/container/detail/allocation_type.hpp @@ -0,0 +1,58 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_ALLOCATION_TYPE_HPP +#define BOOST_CONTAINER_ALLOCATION_TYPE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +namespace boost { +namespace container { + +#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +enum allocation_type_v +{ + // constants for allocation commands + allocate_new_v = 0x01, + expand_fwd_v = 0x02, + expand_bwd_v = 0x04, +// expand_both = expand_fwd | expand_bwd, +// expand_or_new = allocate_new | expand_both, + shrink_in_place_v = 0x08, + nothrow_allocation_v = 0x10, + zero_memory_v = 0x20, + try_shrink_in_place_v = 0x40 +}; + +typedef unsigned int allocation_type; +#endif //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED +static const allocation_type allocate_new = (allocation_type)allocate_new_v; +static const allocation_type expand_fwd = (allocation_type)expand_fwd_v; +static const allocation_type expand_bwd = (allocation_type)expand_bwd_v; +static const allocation_type shrink_in_place = (allocation_type)shrink_in_place_v; +static const allocation_type try_shrink_in_place= (allocation_type)try_shrink_in_place_v; +static const allocation_type nothrow_allocation = (allocation_type)nothrow_allocation_v; +static const allocation_type zero_memory = (allocation_type)zero_memory_v; + +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_ALLOCATION_TYPE_HPP diff --git a/third-party/boost/boost/container/detail/allocator_version_traits.hpp b/third-party/boost/boost/container/detail/allocator_version_traits.hpp new file mode 100644 index 000000000..d037e0e39 --- /dev/null +++ b/third-party/boost/boost/container/detail/allocator_version_traits.hpp @@ -0,0 +1,163 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP +#define BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include + +#include //allocator_traits +#include +#include //multiallocation_chain +#include //version_type +#include //allocation_type +#include //integral_constant +#include //pointer_traits +#include //BOOST_TRY + +namespace boost { +namespace container { +namespace dtl { + +template::value> +struct allocator_version_traits +{ + typedef ::boost::container::dtl::integral_constant + alloc_version; + + typedef typename Allocator::multiallocation_chain multiallocation_chain; + + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate_one(); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate_one(p); } + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { return a.allocate_individual(n, m); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { a.deallocate_individual(holder); } + + static pointer allocation_command(Allocator &a, allocation_type command, + size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse) + { return a.allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse); } +}; + +template +struct allocator_version_traits +{ + typedef ::boost::container::dtl::integral_constant + alloc_version; + + typedef typename boost::container::allocator_traits::pointer pointer; + typedef typename boost::container::allocator_traits::size_type size_type; + typedef typename boost::container::allocator_traits::value_type value_type; + + typedef typename boost::intrusive::pointer_traits:: + template rebind_pointer::type void_ptr; + typedef dtl::basic_multiallocation_chain + multialloc_cached_counted; + typedef boost::container::dtl:: + transform_multiallocation_chain + < multialloc_cached_counted, value_type> multiallocation_chain; + + //Node allocation interface + static pointer allocate_one(Allocator &a) + { return a.allocate(1); } + + static void deallocate_one(Allocator &a, const pointer &p) + { a.deallocate(p, 1); } + + static void deallocate_individual(Allocator &a, multiallocation_chain &holder) + { + size_type n = holder.size(); + typename multiallocation_chain::iterator it = holder.begin(); + while(n){ + --n; + pointer p = boost::intrusive::pointer_traits::pointer_to(*it); + ++it; + a.deallocate(p, 1); + } + } + + struct allocate_individual_rollback + { + allocate_individual_rollback(Allocator &a, multiallocation_chain &chain) + : mr_a(a), mp_chain(&chain) + {} + + ~allocate_individual_rollback() + { + if(mp_chain) + allocator_version_traits::deallocate_individual(mr_a, *mp_chain); + } + + void release() + { + mp_chain = 0; + } + + Allocator &mr_a; + multiallocation_chain * mp_chain; + }; + + static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m) + { + allocate_individual_rollback rollback(a, m); + while(n--){ + m.push_front(a.allocate(1)); + } + rollback.release(); + } + + static pointer allocation_command(Allocator &a, allocation_type command, + size_type, size_type &prefer_in_recvd_out_size, pointer &reuse) + { + pointer ret = pointer(); + if(BOOST_UNLIKELY(!(command & allocate_new) && !(command & nothrow_allocation))){ + throw_logic_error("version 1 allocator without allocate_new flag"); + } + else{ + BOOST_TRY{ + ret = a.allocate(prefer_in_recvd_out_size); + } + BOOST_CATCH(...){ + if(!(command & nothrow_allocation)){ + BOOST_RETHROW + } + } + BOOST_CATCH_END + reuse = pointer(); + } + return ret; + } +}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#include + +#endif // ! defined(BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP) diff --git a/third-party/boost/boost/container/detail/auto_link.hpp b/third-party/boost/boost/container/detail/auto_link.hpp new file mode 100644 index 000000000..264b1ba11 --- /dev/null +++ b/third-party/boost/boost/container/detail/auto_link.hpp @@ -0,0 +1,51 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2007-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED +#define BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +//Define BOOST_CONTAINER_DYNAMIC_LINKING which is independent from BOOST_*_NO_LIB +//and is needed is some tests that need to disable some checks (like operator new replacements) +//that don't work across DLL boundaries +#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_CONTAINER_DYN_LINK) +# define BOOST_CONTAINER_DYNAMIC_LINKING +#endif + +// +// Automatically link to the correct build variant where possible. +// +#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_CONTAINER_NO_LIB) && !defined(BOOST_CONTAINER_SOURCE) +// +// Set the name of our library, this will get undef'ed by auto_link.hpp +// once it's done with it: +// +#define BOOST_LIB_NAME boost_container + +// +// If we're importing code from a dll, then tell auto_link.hpp about it: +// +#if defined(BOOST_CONTAINER_DYNAMIC_LINKING) +# define BOOST_DYN_LINK +#endif + +// +// And include the header that does the work: +// +#include +#endif // auto-linking disabled + +#endif //#ifndef BOOST_CONTAINER_DETAIL_AUTO_LINK_HPP_INCLUDED diff --git a/third-party/boost/boost/container/detail/block_list.hpp b/third-party/boost/boost/container/detail/block_list.hpp new file mode 100644 index 000000000..0ed0e2279 --- /dev/null +++ b/third-party/boost/boost/container/detail/block_list.hpp @@ -0,0 +1,140 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_BLOCK_LIST_HEADER +#define BOOST_CONTAINER_DETAIL_BLOCK_LIST_HEADER + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +struct list_node +{ + list_node *next; + list_node *previous; +}; + +struct list_node_traits +{ + typedef list_node node; + typedef list_node* node_ptr; + typedef const list_node* const_node_ptr; + + static node_ptr get_next(const_node_ptr n) + { return n->next; } + + static node_ptr get_previous(const_node_ptr n) + { return n->previous; } + + static void set_next(const node_ptr & n, const node_ptr & next) + { n->next = next; } + + static void set_previous(const node_ptr & n, const node_ptr & previous) + { n->previous = previous; } +}; + +struct block_list_header + : public list_node +{ + std::size_t size; +}; + +typedef bi::circular_list_algorithms list_algo; + + +template +class block_list_base +{ + list_node m_list; + + static const std::size_t MaxAlignMinus1 = memory_resource::max_align-1u; + + public: + + static const std::size_t header_size = std::size_t(sizeof(DerivedFromBlockListHeader) + MaxAlignMinus1) & std::size_t(~MaxAlignMinus1); + + explicit block_list_base() + { list_algo::init_header(&m_list); } + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_list_base(const block_list_base&) = delete; + block_list_base operator=(const block_list_base&) = delete; + #else + private: + block_list_base (const block_list_base&); + block_list_base operator=(const block_list_base&); + public: + #endif + + ~block_list_base() + {} + + void *allocate(std::size_t size, memory_resource &mr) + { + if((size_t(-1) - header_size) < size) + throw_bad_alloc(); + void *p = mr.allocate(size+header_size); + block_list_header &mb = *::new((void*)p, boost_container_new_t()) DerivedFromBlockListHeader; + mb.size = size+header_size; + list_algo::link_after(&m_list, &mb); + return (char *)p + header_size; + } + + void deallocate(void *p, memory_resource &mr) BOOST_NOEXCEPT + { + DerivedFromBlockListHeader *pheader = static_cast + (static_cast((char*)p - header_size)); + list_algo::unlink(pheader); + const std::size_t size = pheader->size; + static_cast(pheader)->~DerivedFromBlockListHeader(); + mr.deallocate(pheader, size, memory_resource::max_align); + } + + void release(memory_resource &mr) BOOST_NOEXCEPT + { + list_node *n = list_algo::node_traits::get_next(&m_list); + while(n != &m_list){ + DerivedFromBlockListHeader &d = static_cast(*n); + n = list_algo::node_traits::get_next(n); + std::size_t size = d.size; + d.~DerivedFromBlockListHeader(); + mr.deallocate(reinterpret_cast(&d), size, memory_resource::max_align); + } + list_algo::init_header(&m_list); + } +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_DETAIL_BLOCK_LIST_HEADER diff --git a/third-party/boost/boost/container/detail/block_slist.hpp b/third-party/boost/boost/container/detail/block_slist.hpp new file mode 100644 index 000000000..890e72588 --- /dev/null +++ b/third-party/boost/boost/container/detail/block_slist.hpp @@ -0,0 +1,158 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2015-2015. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_BLOCK_SLIST_HEADER +#define BOOST_CONTAINER_DETAIL_BLOCK_SLIST_HEADER + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace boost { +namespace container { +namespace pmr { + +struct slist_node +{ + slist_node *next; +}; + +struct slist_node_traits +{ + typedef slist_node node; + typedef slist_node* node_ptr; + typedef const slist_node* const_node_ptr; + + static node_ptr get_next(const_node_ptr n) + { return n->next; } + + static void set_next(const node_ptr & n, const node_ptr & next) + { n->next = next; } +}; + +struct block_slist_header + : public slist_node +{ + std::size_t size; +}; + +typedef bi::linear_slist_algorithms slist_algo; + +template +class block_slist_base +{ + slist_node m_slist; + + static const std::size_t MaxAlignMinus1 = memory_resource::max_align-1u; + + public: + + static const std::size_t header_size = std::size_t(sizeof(DerivedFromBlockSlistHeader) + MaxAlignMinus1) & std::size_t(~MaxAlignMinus1); + + explicit block_slist_base() + { slist_algo::init_header(&m_slist); } + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_slist_base(const block_slist_base&) = delete; + block_slist_base operator=(const block_slist_base&) = delete; + #else + private: + block_slist_base (const block_slist_base&); + block_slist_base operator=(const block_slist_base&); + public: + #endif + + ~block_slist_base() + {} + + void *allocate(std::size_t size, memory_resource &mr) + { + if((size_t(-1) - header_size) < size) + throw_bad_alloc(); + void *p = mr.allocate(size+header_size); + block_slist_header &mb = *::new((void*)p, boost_container_new_t()) DerivedFromBlockSlistHeader; + mb.size = size+header_size; + slist_algo::link_after(&m_slist, &mb); + return (char *)p + header_size; + } + + void release(memory_resource &mr) BOOST_NOEXCEPT + { + slist_node *n = slist_algo::node_traits::get_next(&m_slist); + while(n){ + DerivedFromBlockSlistHeader &d = static_cast(*n); + n = slist_algo::node_traits::get_next(n); + std::size_t size = d.block_slist_header::size; + d.~DerivedFromBlockSlistHeader(); + mr.deallocate(reinterpret_cast(&d), size, memory_resource::max_align); + } + slist_algo::init_header(&m_slist); + } +}; + +class block_slist + : public block_slist_base<> +{ + memory_resource &m_upstream_rsrc; + + public: + + explicit block_slist(memory_resource &upstream_rsrc) + : block_slist_base<>(), m_upstream_rsrc(upstream_rsrc) + {} + + #if !defined(BOOST_NO_CXX11_DELETED_FUNCTIONS) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED) + block_slist(const block_slist&) = delete; + block_slist operator=(const block_slist&) = delete; + #else + private: + block_slist (const block_slist&); + block_slist operator=(const block_slist&); + public: + #endif + + ~block_slist() + { this->release(); } + + void *allocate(std::size_t size) + { return this->block_slist_base<>::allocate(size, m_upstream_rsrc); } + + void release() BOOST_NOEXCEPT + { return this->block_slist_base<>::release(m_upstream_rsrc); } + + memory_resource& upstream_resource() const BOOST_NOEXCEPT + { return m_upstream_rsrc; } +}; + +} //namespace pmr { +} //namespace container { +} //namespace boost { + +#include + +#endif //BOOST_CONTAINER_DETAIL_BLOCK_SLIST_HEADER diff --git a/third-party/boost/boost/container/detail/compare_functors.hpp b/third-party/boost/boost/container/detail/compare_functors.hpp new file mode 100644 index 000000000..21f222bfa --- /dev/null +++ b/third-party/boost/boost/container/detail/compare_functors.hpp @@ -0,0 +1,130 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_COMPARE_FUNCTORS_HPP +#define BOOST_CONTAINER_DETAIL_COMPARE_FUNCTORS_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + +namespace boost { +namespace container { + +template +class equal_to_value +{ + typedef ValueType value_type; + const value_type &t_; + + public: + explicit equal_to_value(const value_type &t) + : t_(t) + {} + + bool operator()(const value_type &t)const + { return t_ == t; } +}; + +template +struct value_to_node_compare + : Pred +{ + typedef Pred predicate_type; + typedef Node node_type; + + value_to_node_compare() + : Pred() + {} + + explicit value_to_node_compare(Pred pred) + : Pred(pred) + {} + + Ret operator()(const Node &a, const Node &b) const + { return static_cast(*this)(a.get_data(), b.get_data()); } + + Ret operator()(const Node &a) const + { return static_cast(*this)(a.get_data()); } + + Ret operator()(const Node &a, const Node &b) + { return static_cast(*this)(a.get_data(), b.get_data()); } + + Ret operator()(const Node &a) + { return static_cast(*this)(a.get_data()); } + + predicate_type & predicate() { return static_cast(*this); } + const predicate_type & predicate() const { return static_cast(*this); } +}; + +template +struct key_node_pred + : public boost::intrusive::detail::ebo_functor_holder +{ + BOOST_CONTAINER_FORCEINLINE explicit key_node_pred(const KeyPred &comp) + : base_t(comp) + {} + + typedef boost::intrusive::detail::ebo_functor_holder base_t; + typedef KeyPred key_predicate; + typedef KeyOfValue key_of_value; + typedef typename KeyOfValue::type key_type; + + + BOOST_CONTAINER_FORCEINLINE static const key_type &key_from(const Node &n) + { + return key_of_value()(n.get_data()); + } + + template + BOOST_CONTAINER_FORCEINLINE static const T & + key_from(const T &t) + { return t; } + + BOOST_CONTAINER_FORCEINLINE const key_predicate &key_pred() const + { return static_cast(*this); } + + BOOST_CONTAINER_FORCEINLINE key_predicate &key_pred() + { return static_cast(*this); } + + BOOST_CONTAINER_FORCEINLINE Ret operator()(const key_type &key) const + { return this->key_pred()(key); } + + template + BOOST_CONTAINER_FORCEINLINE Ret operator()(const U &nonkey) const + { return this->key_pred()(this->key_from(nonkey)); } + + BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const key_type &key2) const + { return this->key_pred()(key1, key2); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const key_type &key1, const U &nonkey2) const + { return this->key_pred()(key1, this->key_from(nonkey2)); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const key_type &key2) const + { return this->key_pred()(this->key_from(nonkey1), key2); } + + template + BOOST_CONTAINER_FORCEINLINE bool operator()(const U &nonkey1, const V &nonkey2) const + { return this->key_pred()(this->key_from(nonkey1), this->key_from(nonkey2)); } +}; + + +} //namespace container { +} //namespace boost { + +#endif //BOOST_CONTAINER_DETAIL_COMPARE_FUNCTORS_HPP diff --git a/third-party/boost/boost/container/detail/config_begin.hpp b/third-party/boost/boost/container/detail/config_begin.hpp new file mode 100644 index 000000000..4df9e35d8 --- /dev/null +++ b/third-party/boost/boost/container/detail/config_begin.hpp @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED +#define BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED +#ifndef BOOST_CONFIG_HPP +#include +#endif + +#endif //BOOST_CONTAINER_CONTAINER_DETAIL_CONFIG_INCLUDED + +#ifdef BOOST_MSVC + #pragma warning (push) + #pragma warning (disable : 4127) // conditional expression is constant + #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned + #pragma warning (disable : 4197) // top-level volatile in cast is ignored + #pragma warning (disable : 4244) // possible loss of data + #pragma warning (disable : 4251) // "identifier" : class "type" needs to have dll-interface to be used by clients of class "type2" + #pragma warning (disable : 4267) // conversion from "X" to "Y", possible loss of data + #pragma warning (disable : 4275) // non DLL-interface classkey "identifier" used as base for DLL-interface classkey "identifier" + #pragma warning (disable : 4284) // odd return type for operator-> + #pragma warning (disable : 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) + #pragma warning (disable : 4324) // structure was padded due to __declspec(align( + #pragma warning (disable : 4345) // behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized + #pragma warning (disable : 4355) // "this" : used in base member initializer list + #pragma warning (disable : 4503) // "identifier" : decorated name length exceeded, name was truncated + #pragma warning (disable : 4510) // default constructor could not be generated + #pragma warning (disable : 4511) // copy constructor could not be generated + #pragma warning (disable : 4512) // assignment operator could not be generated + #pragma warning (disable : 4514) // unreferenced inline removed + #pragma warning (disable : 4521) // Disable "multiple copy constructors specified" + #pragma warning (disable : 4522) // "class" : multiple assignment operators specified + #pragma warning (disable : 4541) // 'typeid' used on polymorphic type '' with /GR-; unpredictable behavior may result + #pragma warning (disable : 4584) // X is already a base-class of Y + #pragma warning (disable : 4610) // struct can never be instantiated - user defined constructor required + #pragma warning (disable : 4671) // the copy constructor is inaccessible + #pragma warning (disable : 4673) // throwing '' the following types will not be considered at the catch site + #pragma warning (disable : 4675) // "method" should be declared "static" and have exactly one parameter + #pragma warning (disable : 4702) // unreachable code + #pragma warning (disable : 4706) // assignment within conditional expression + #pragma warning (disable : 4710) // function not inlined + #pragma warning (disable : 4714) // "function": marked as __forceinline not inlined + #pragma warning (disable : 4711) // function selected for automatic inline expansion + #pragma warning (disable : 4786) // identifier truncated in debug info + #pragma warning (disable : 4996) // "function": was declared deprecated + +#endif //BOOST_MSVC diff --git a/third-party/boost/boost/container/detail/config_end.hpp b/third-party/boost/boost/container/detail/config_end.hpp new file mode 100644 index 000000000..f93c8f6f7 --- /dev/null +++ b/third-party/boost/boost/container/detail/config_end.hpp @@ -0,0 +1,13 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2005-2013. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#if defined BOOST_MSVC + #pragma warning (pop) +#endif + diff --git a/third-party/boost/boost/container/detail/construct_in_place.hpp b/third-party/boost/boost/container/detail/construct_in_place.hpp new file mode 100644 index 000000000..b131f06a8 --- /dev/null +++ b/third-party/boost/boost/container/detail/construct_in_place.hpp @@ -0,0 +1,96 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2014-2014. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_CONTAINER_DETAIL_CONSTRUCT_IN_PLACE_HPP +#define BOOST_CONTAINER_DETAIL_CONSTRUCT_IN_PLACE_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace container { + +//In place construction + +template +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T* dest, InpIt source) +{ boost::container::allocator_traits::construct(a, dest, *source); } + +template +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, value_init_construct_iterator) +{ + boost::container::allocator_traits::construct(a, dest); +} + +template +class default_init_construct_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, default_init_construct_iterator) +{ + boost::container::allocator_traits::construct(a, dest, default_init); +} + +template +class emplace_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void construct_in_place(Allocator &a, T *dest, emplace_iterator ei) +{ + ei.construct_in_place(a, dest); +} + +//Assignment + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, InpIt source) +{ *dest = *source; } + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, value_init_construct_iterator) +{ + dtl::value_init val; + *dest = boost::move(val.get()); +} + +template +class default_init_construct_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, default_init_construct_iterator) +{ + U u; + *dest = boost::move(u); +} + +template +class emplace_iterator; + +template +BOOST_CONTAINER_FORCEINLINE void assign_in_place(DstIt dest, emplace_iterator ei) +{ + ei.assign_in_place(dest); +} + +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_CONSTRUCT_IN_PLACE_HPP diff --git a/third-party/boost/boost/container/detail/container_or_allocator_rebind.hpp b/third-party/boost/boost/container/detail/container_or_allocator_rebind.hpp new file mode 100644 index 000000000..1525e41d9 --- /dev/null +++ b/third-party/boost/boost/container/detail/container_or_allocator_rebind.hpp @@ -0,0 +1,53 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP +#define BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include +#include +#include + +namespace boost { +namespace container { +namespace dtl { + +template::value> +struct container_or_allocator_rebind_impl + : container_rebind +{}; + +template +struct container_or_allocator_rebind_impl + : allocator_traits::template portable_rebind_alloc +{}; + +template +struct container_or_allocator_rebind_impl + : real_allocator +{}; + +template +struct container_or_allocator_rebind + : container_or_allocator_rebind_impl +{}; + +} //namespace dtl { +} //namespace container { +} //namespace boost { + +#endif //#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_OR_ALLOCATOR_REBIND_HPP diff --git a/third-party/boost/boost/container/detail/container_rebind.hpp b/third-party/boost/boost/container/detail/container_rebind.hpp new file mode 100644 index 000000000..0ebb4789e --- /dev/null +++ b/third-party/boost/boost/container/detail/container_rebind.hpp @@ -0,0 +1,258 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Ion Gaztanaga 2017-2017. Distributed under the Boost +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/container for documentation. +// +////////////////////////////////////////////////////////////////////////////// +#ifndef BOOST_CONTAINER_DETAIL_CONTAINER_REBIND_HPP +#define BOOST_CONTAINER_DETAIL_CONTAINER_REBIND_HPP + +#ifndef BOOST_CONFIG_HPP +# include +#endif + +#if defined(BOOST_HAS_PRAGMA_ONCE) +# pragma once +#endif + +#include + + +namespace boost { +namespace container { +namespace dtl { + + template + struct container_rebind; + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + + template