// Copyright (C) 2018 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FIXED_ARGV_H_ #define FIXED_ARGV_H_ #include <array> #include <tuple> #include <utility> #include <vector> #include <assert.h> #include <string.h> class FixedArgvAccess; class FixedArgv { friend FixedArgvAccess; private: std::vector<const char *> argv_; public: FixedArgv(int argc, const char **argv) : argv_(argv, argv + argc) {} int GetArgc() const { return argv_.size(); } const char *const *GetArgv() const { return argv_.data(); } void Resize(int argc) { assert(argc <= argv_.size()); argv_.resize(argc); } template <typename... T> const char *GetLastArg(T&& ...options) const { std::array<const char *, sizeof...(options)> opts{ std::forward<T&&>(options)...}; for (std::vector<const char *>::const_reverse_iterator it = argv_.rbegin(), end = argv_.rend(); it != end; ++it) { for (const char *opt : opts) { if (::strcmp(*it, opt) == 0) { return opt; } } } return nullptr; } template <typename... T> bool IsLastArgEqualFirstOption(const char *expected, T&& ...others) const { const char *last = GetLastArg(expected, others...); // Since GetLastArg() returns the address in {expected, others...}, pointer // comparison is sufficient. return last == expected; } template<typename... T> void PushForwardArgs(T&& ...arguments) { std::array<const char *, sizeof...(arguments)> args{ std::forward<T&&>(arguments)...}; if (!GetLastArg("--")) { argv_.push_back("--"); } argv_.insert(argv_.end(), args.begin(), args.end()); } }; class FixedArgvAccess { private: FixedArgv &fixed_argv_; public: int argc_; const char **argv_; public: explicit FixedArgvAccess(FixedArgv &fixed_argv) : fixed_argv_(fixed_argv), argc_(fixed_argv.GetArgc()), argv_(fixed_argv.argv_.data()) { } ~FixedArgvAccess() { fixed_argv_.Resize(argc_); } private: FixedArgvAccess(const FixedArgvAccess &) = delete; FixedArgvAccess& operator=(const FixedArgvAccess &rhs) = delete; }; class FixedArgvRegistry { public: typedef void (Function)(FixedArgv &); private: static FixedArgvRegistry *head_; Function *func_; FixedArgvRegistry *next_; public: FixedArgvRegistry(Function *func) : func_(func), next_(head_) { head_ = this; } static void Apply(FixedArgv &fixed_argv) { for (FixedArgvRegistry *ptr = head_; ptr; ptr = ptr->next_) { ptr->func_(fixed_argv); } } }; #endif // FIXED_ARGV_H_