| 
 | 1 | +// Copyright (c) 2024 Roberto Raggi <[email protected]>  | 
 | 2 | +//  | 
 | 3 | +// Permission is hereby granted, free of charge, to any person obtaining a copy  | 
 | 4 | +// of this software and associated documentation files (the "Software"), to deal  | 
 | 5 | +// in the Software without restriction, including without limitation the rights  | 
 | 6 | +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  | 
 | 7 | +// copies of the Software, and to permit persons to whom the Software is  | 
 | 8 | +// furnished to do so, subject to the following conditions:  | 
 | 9 | +//  | 
 | 10 | +// The above copyright notice and this permission notice shall be included in  | 
 | 11 | +// all copies or substantial portions of the Software.  | 
 | 12 | +//  | 
 | 13 | +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  | 
 | 14 | +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  | 
 | 15 | +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  | 
 | 16 | +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  | 
 | 17 | +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  | 
 | 18 | +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  | 
 | 19 | +// SOFTWARE.  | 
 | 20 | + | 
 | 21 | +#pragma once  | 
 | 22 | + | 
 | 23 | +#include <cxx/symbols.h>  | 
 | 24 | + | 
 | 25 | +#include <ranges>  | 
 | 26 | +#include <stack>  | 
 | 27 | + | 
 | 28 | +namespace cxx {  | 
 | 29 | + | 
 | 30 | +class BaseClassesView {  | 
 | 31 | + public:  | 
 | 32 | +  explicit BaseClassesView(ClassSymbol* classSymbol)  | 
 | 33 | +      : state_(std::make_shared<State>()) {  | 
 | 34 | +    if (classSymbol) {  | 
 | 35 | +      for (auto base : classSymbol->baseClasses() | std::views::reverse) {  | 
 | 36 | +        state_->stack.push(base);  | 
 | 37 | +      }  | 
 | 38 | +    }  | 
 | 39 | +  }  | 
 | 40 | + | 
 | 41 | +  ~BaseClassesView() = default;  | 
 | 42 | + | 
 | 43 | +  auto begin() { return Generator{this}; }  | 
 | 44 | +  auto end() { return std::default_sentinel; }  | 
 | 45 | + | 
 | 46 | + private:  | 
 | 47 | +  class Generator {  | 
 | 48 | +   public:  | 
 | 49 | +    using value_type = BaseClassSymbol*;  | 
 | 50 | +    using difference_type = std::ptrdiff_t;  | 
 | 51 | + | 
 | 52 | +    explicit Generator(BaseClassesView* view) : view_{view} {}  | 
 | 53 | + | 
 | 54 | +    auto operator*() const -> BaseClassSymbol* {  | 
 | 55 | +      auto state = view_->state_;  | 
 | 56 | +      if (state->stack.empty()) return nullptr;  | 
 | 57 | +      return state->stack.top();  | 
 | 58 | +    }  | 
 | 59 | + | 
 | 60 | +    auto operator++() -> Generator& {  | 
 | 61 | +      auto state = view_->state_;  | 
 | 62 | +      auto base = state->stack.top();  | 
 | 63 | +      state->stack.pop();  | 
 | 64 | + | 
 | 65 | +      if (auto classSymbol = symbol_cast<ClassSymbol>(base->symbol())) {  | 
 | 66 | +        if (!state->visited.insert(classSymbol).second) {  | 
 | 67 | +          return *this;  | 
 | 68 | +        }  | 
 | 69 | + | 
 | 70 | +        for (auto base : classSymbol->baseClasses() | std::views::reverse) {  | 
 | 71 | +          state->stack.push(base);  | 
 | 72 | +        }  | 
 | 73 | +      }  | 
 | 74 | + | 
 | 75 | +      return *this;  | 
 | 76 | +    }  | 
 | 77 | + | 
 | 78 | +    auto operator++(int) -> Generator {  | 
 | 79 | +      auto tmp = *this;  | 
 | 80 | +      ++*this;  | 
 | 81 | +      return tmp;  | 
 | 82 | +    }  | 
 | 83 | + | 
 | 84 | +    auto operator==(const std::default_sentinel_t&) const -> bool {  | 
 | 85 | +      auto state = view_->state_;  | 
 | 86 | +      return state->stack.empty();  | 
 | 87 | +    }  | 
 | 88 | + | 
 | 89 | +   private:  | 
 | 90 | +    BaseClassesView* view_ = nullptr;  | 
 | 91 | +  };  | 
 | 92 | + | 
 | 93 | + private:  | 
 | 94 | +  struct State {  | 
 | 95 | +    std::unordered_set<ClassSymbol*> visited;  | 
 | 96 | +    std::stack<BaseClassSymbol*> stack;  | 
 | 97 | +  };  | 
 | 98 | + | 
 | 99 | +  std::shared_ptr<State> state_ = std::make_shared<State>();  | 
 | 100 | +};  | 
 | 101 | + | 
 | 102 | +namespace views {  | 
 | 103 | + | 
 | 104 | +inline auto base_classes(ClassSymbol* classSymbol) -> BaseClassesView {  | 
 | 105 | +  return BaseClassesView{classSymbol};  | 
 | 106 | +}  | 
 | 107 | + | 
 | 108 | +}  // namespace views  | 
 | 109 | + | 
 | 110 | +}  // namespace cxx  | 
0 commit comments