//////////////////////////////////////////////////////////////////////////////// /// DISCLAIMER /// /// Copyright 2019 ArangoDB GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is ArangoDB GmbH, Cologne, Germany /// /// @author Tobias Gödderz //////////////////////////////////////////////////////////////////////////////// #ifndef ARANGOD_CLUSTER_PATHCOMPONENT_H #define ARANGOD_CLUSTER_PATHCOMPONENT_H #include #include #include #include #include #include namespace arangodb { namespace cluster { namespace paths { class Path { public: // Call for each component on the path, starting with the topmost component, // excluding Root. virtual void forEach(std::function const&) const = 0; // Fold the path. template T fold(std::function const& callback, T init) const { forEach([&callback, &init](const char* component) { init = callback(init); }); return std::move(init); } std::ostream& toStream(std::ostream& stream) const { forEach([&stream](const char* component) { stream << "/" << component; }); return stream; } std::vector vec() const { std::vector res; forEach([&res](const char* component) { res.emplace_back(std::string{component}); }); return res; } std::string str() const { auto stream = std::stringstream{}; toStream(stream); return stream.str(); } virtual ~Path() = default; }; template class StaticComponent : public std::enable_shared_from_this /* (sic) */, public Path { public: using ParentType = P; using BaseType = StaticComponent; StaticComponent() = delete; void forEach(std::function const& callback) const final { parent().forEach(callback); callback(child().component()); } // Only the parent type P may instantiate a component, so make this protected // and P a friend. MSVC ignores the friend declaration, though. #if defined(_WIN32) || defined(_WIN64) public: #else protected: friend P; #endif explicit constexpr StaticComponent(std::shared_ptr

parent) noexcept : _parent(std::move(parent)) {} // shared ptr constructor static std::shared_ptr make_shared(std::shared_ptr

parent) { struct ConstructibleT : public T { public: explicit ConstructibleT(std::shared_ptr

parent) noexcept : T(std::move(parent)) {} }; return std::make_shared(std::move(parent)); } private: // Accessor to our subclass T const& child() const { return static_cast(*this); } // Accessor to our parent. Could be made public, but should then probably return the shared_ptr. P const& parent() const noexcept { return *_parent; } std::shared_ptr

const _parent; }; template class DynamicComponent : public std::enable_shared_from_this /* (sic) */, public Path { public: using ParentType = P; using BaseType = DynamicComponent; DynamicComponent() = delete; void forEach(std::function const& callback) const final { parent().forEach(callback); callback(child().component()); } // Only the parent type P may instantiate a component, so make this protected // and P a friend. MSVC ignores the friend declaration, though. #if defined(_WIN32) || defined(_WIN64) public: #else protected: friend P; #endif explicit constexpr DynamicComponent(std::shared_ptr

parent, V value) noexcept : _parent(std::move(parent)), _value(std::move(value)) { static_assert(noexcept(V(std::move(value))), "Move constructor of V is expected to be noexcept"); } // shared ptr constructor static std::shared_ptr make_shared(std::shared_ptr

parent, V value) { struct ConstructibleT : public T { public: explicit ConstructibleT(std::shared_ptr

parent, V value) noexcept : T(std::move(parent), std::move(value)) {} }; return std::make_shared(std::move(parent), std::move(value)); } V const& value() const noexcept { return _value; } private: // Accessor to our subclass T const& child() const { return static_cast(*this); } // Accessor to our parent. Could be made public, but should then probably return the shared_ptr. P const& parent() const noexcept { return *_parent; } std::shared_ptr

const _parent; V const _value; }; inline std::ostream& operator<<(std::ostream& stream, Path const& path) { return path.toStream(stream); } } // namespace paths } // namespace cluster } // namespace arangodb #endif // ARANGOD_CLUSTER_PATHCOMPONENT_H