Nestable.h (2173B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef ds_Nestable_h 8 #define ds_Nestable_h 9 10 #include "mozilla/Assertions.h" 11 12 namespace js { 13 14 // A base class for nestable structures. 15 // 16 // This subclasses of this class must follow a LIFO destruction order, The 17 // easiest way to ensure that is adding MOZ_STACK_CLASS to the subclasses. 18 // This class doesn't have the MOZ_STACK_CLASS annotation in order to allow 19 // specific cases where the subclasses can be allocated on heap for reduced 20 // stack usage and other implementation specific reasons, but even in such 21 // cases the subclasses must follow a LIFO destruction order. 22 template <typename Concrete> 23 class Nestable { 24 Concrete** stack_; 25 Concrete* enclosing_; 26 27 protected: 28 explicit Nestable(Concrete** stack) : stack_(stack), enclosing_(*stack) { 29 *stack_ = static_cast<Concrete*>(this); 30 } 31 32 // These method are protected. Some derived classes, such as ParseContext, 33 // do not expose the ability to walk the stack. 34 Concrete* enclosing() const { return enclosing_; } 35 36 template <typename Predicate /* (Concrete*) -> bool */> 37 static Concrete* findNearest(Concrete* it, Predicate predicate) { 38 while (it && !predicate(it)) { 39 it = it->enclosing(); 40 } 41 return it; 42 } 43 44 template <typename T> 45 static T* findNearest(Concrete* it) { 46 while (it && !it->template is<T>()) { 47 it = it->enclosing(); 48 } 49 return it ? &it->template as<T>() : nullptr; 50 } 51 52 template <typename T, typename Predicate /* (T*) -> bool */> 53 static T* findNearest(Concrete* it, Predicate predicate) { 54 while (it && (!it->template is<T>() || !predicate(&it->template as<T>()))) { 55 it = it->enclosing(); 56 } 57 return it ? &it->template as<T>() : nullptr; 58 } 59 60 public: 61 ~Nestable() { 62 MOZ_ASSERT(*stack_ == static_cast<Concrete*>(this)); 63 *stack_ = enclosing_; 64 } 65 }; 66 67 } // namespace js 68 69 #endif /* ds_Nestable_h */