1 // Copyright (C) 2018 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef FIXED_ARGV_H_ 16 #define FIXED_ARGV_H_ 17 18 #include <array> 19 #include <tuple> 20 #include <utility> 21 #include <vector> 22 23 #include <assert.h> 24 #include <string.h> 25 26 27 class FixedArgvAccess; 28 29 30 class FixedArgv { 31 friend FixedArgvAccess; 32 33 private: 34 std::vector<const char *> argv_; 35 36 public: FixedArgv(int argc,const char ** argv)37 FixedArgv(int argc, const char **argv) : argv_(argv, argv + argc) {} 38 GetArgc()39 int GetArgc() const { 40 return argv_.size(); 41 } 42 GetArgv()43 const char *const *GetArgv() const { 44 return argv_.data(); 45 } 46 Resize(int argc)47 void Resize(int argc) { 48 assert(argc <= argv_.size()); 49 argv_.resize(argc); 50 } 51 52 template <typename... T> GetLastArg(T &&...options)53 const char *GetLastArg(T&& ...options) const { 54 std::array<const char *, sizeof...(options)> opts{ 55 std::forward<T&&>(options)...}; 56 for (std::vector<const char *>::const_reverse_iterator it = argv_.rbegin(), 57 end = argv_.rend(); it != end; ++it) { 58 for (const char *opt : opts) { 59 if (::strcmp(*it, opt) == 0) { 60 return opt; 61 } 62 } 63 } 64 return nullptr; 65 } 66 67 template <typename... T> IsLastArgEqualFirstOption(const char * expected,T &&...others)68 bool IsLastArgEqualFirstOption(const char *expected, T&& ...others) const { 69 const char *last = GetLastArg(expected, others...); 70 // Since GetLastArg() returns the address in {expected, others...}, pointer 71 // comparison is sufficient. 72 return last == expected; 73 } 74 75 template<typename... T> PushForwardArgs(T &&...arguments)76 void PushForwardArgs(T&& ...arguments) { 77 std::array<const char *, sizeof...(arguments)> args{ 78 std::forward<T&&>(arguments)...}; 79 if (!GetLastArg("--")) { 80 argv_.push_back("--"); 81 } 82 argv_.insert(argv_.end(), args.begin(), args.end()); 83 } 84 }; 85 86 87 class FixedArgvAccess { 88 private: 89 FixedArgv &fixed_argv_; 90 91 public: 92 int argc_; 93 const char **argv_; 94 95 public: FixedArgvAccess(FixedArgv & fixed_argv)96 explicit FixedArgvAccess(FixedArgv &fixed_argv) 97 : fixed_argv_(fixed_argv), argc_(fixed_argv.GetArgc()), 98 argv_(fixed_argv.argv_.data()) { 99 } 100 ~FixedArgvAccess()101 ~FixedArgvAccess() { 102 fixed_argv_.Resize(argc_); 103 } 104 105 private: 106 FixedArgvAccess(const FixedArgvAccess &) = delete; 107 FixedArgvAccess& operator=(const FixedArgvAccess &rhs) = delete; 108 }; 109 110 111 class FixedArgvRegistry { 112 public: 113 typedef void (Function)(FixedArgv &); 114 115 private: 116 static FixedArgvRegistry *head_; 117 118 Function *func_; 119 FixedArgvRegistry *next_; 120 121 public: FixedArgvRegistry(Function * func)122 FixedArgvRegistry(Function *func) : func_(func), next_(head_) { 123 head_ = this; 124 } 125 Apply(FixedArgv & fixed_argv)126 static void Apply(FixedArgv &fixed_argv) { 127 for (FixedArgvRegistry *ptr = head_; ptr; ptr = ptr->next_) { 128 ptr->func_(fixed_argv); 129 } 130 } 131 }; 132 133 134 #endif // FIXED_ARGV_H_ 135