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