Home | History | Annotate | Download | only in src
      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:
     37   FixedArgv(int argc, const char **argv) : argv_(argv, argv + argc) {}
     38 
     39   int GetArgc() const {
     40     return argv_.size();
     41   }
     42 
     43   const char *const *GetArgv() const {
     44     return argv_.data();
     45   }
     46 
     47   void Resize(int argc) {
     48     assert(argc <= argv_.size());
     49     argv_.resize(argc);
     50   }
     51 
     52   template <typename... T>
     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>
     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>
     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:
     96   explicit FixedArgvAccess(FixedArgv &fixed_argv)
     97       : fixed_argv_(fixed_argv), argc_(fixed_argv.GetArgc()),
     98         argv_(fixed_argv.argv_.data()) {
     99   }
    100 
    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:
    122   FixedArgvRegistry(Function *func) : func_(func), next_(head_) {
    123     head_ = this;
    124   }
    125 
    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