| //===--- DiverseList.h - List of variably-sized objects ---------*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines a data structure for representing a list of |
| // variably-sized objects. It is a requirement that the object type |
| // be trivially movable, meaning that it has a trivial move |
| // constructor and a trivial destructor. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SWIFT_BASIC_DIVERSELIST_H |
| #define SWIFT_BASIC_DIVERSELIST_H |
| |
| #include "swift/Basic/Malloc.h" |
| #include <cassert> |
| #include <cstring> |
| #include <utility> |
| |
| namespace swift { |
| |
| template <class T> class DiverseListImpl; |
| |
| /// DiverseList - A list of heterogeneously-typed objects. |
| /// |
| /// \tparam T - A common base class of the objects in the list; must |
| /// provide an allocated_size() const method. |
| /// \tparam InlineCapacity - the amount of inline storage to provide, in bytes. |
| template <class T, unsigned InlineCapacity> |
| class DiverseList : public DiverseListImpl<T> { |
| char InlineStorage[InlineCapacity]; |
| |
| public: |
| DiverseList() : DiverseListImpl<T>(InlineStorage + InlineCapacity) {} |
| DiverseList(const DiverseList &other) |
| : DiverseListImpl<T>(other, InlineStorage + InlineCapacity) {} |
| DiverseList(const DiverseListImpl<T> &other) |
| : DiverseListImpl<T>(other, InlineStorage + InlineCapacity) {} |
| DiverseList(DiverseList<T, InlineCapacity> &&other) |
| : DiverseListImpl<T>(std::move(other), InlineStorage + InlineCapacity) {} |
| DiverseList(DiverseListImpl<T> &&other) |
| : DiverseListImpl<T>(std::move(other), InlineStorage + InlineCapacity) {} |
| }; |
| |
| /// A base class for DiverseListImpl. |
| class DiverseListBase { |
| public: |
| /// The first element in the list and the beginning of the allocation. |
| char *Begin; |
| |
| /// A pointer past the last element in the list. |
| char *End; |
| |
| /// A pointer past the end of the allocation. |
| char *EndOfAllocation; |
| |
| bool isAllocatedInline() const { |
| return (Begin == reinterpret_cast<const char *>(this + 1)); |
| } |
| |
| void checkValid() const { |
| assert(Begin <= End); |
| assert(End <= EndOfAllocation); |
| } |
| |
| void initialize(char *endOfAllocation) { |
| EndOfAllocation = endOfAllocation; |
| Begin = End = reinterpret_cast<char*>(this + 1); |
| } |
| void copyFrom(const DiverseListBase &other) { |
| // Ensure that we're large enough to store all the data. |
| std::size_t size = static_cast<std::size_t>(other.End - other.Begin); |
| char *newStorage = addNewStorage(size); |
| std::memcpy(newStorage, other.Begin, size); |
| } |
| char *addNewStorage(std::size_t needed) { |
| checkValid(); |
| if (std::size_t(EndOfAllocation - End) >= needed) { |
| char *newStorage = End; |
| End += needed; |
| return newStorage; |
| } |
| return addNewStorageSlow(needed); |
| } |
| char *addNewStorageSlow(std::size_t needed); |
| |
| /// A stable iterator is the equivalent of an index into the list. |
| /// It's an iterator that stays stable across modification of the |
| /// list. |
| class stable_iterator { |
| std::size_t Offset; |
| friend class DiverseListBase; |
| template <class T> friend class DiverseListImpl; |
| stable_iterator(std::size_t offset) : Offset(offset) {} |
| public: |
| stable_iterator() = default; |
| friend bool operator==(stable_iterator a, stable_iterator b) { |
| return a.Offset == b.Offset; |
| } |
| friend bool operator!=(stable_iterator a, stable_iterator b) { |
| return !operator==(a, b); |
| } |
| }; |
| stable_iterator stable_begin() const { |
| return stable_iterator(0); |
| } |
| stable_iterator stable_end() { |
| return stable_iterator(std::size_t(End - Begin)); |
| } |
| |
| protected: |
| ~DiverseListBase() { |
| checkValid(); |
| if (!isAllocatedInline()) |
| delete[] Begin; |
| } |
| }; |
| |
| /// An "abstract" base class for DiverseList<T> which does not |
| /// explicitly set the preferred inline capacity. Most of the |
| /// implementation is in this class. |
| template <class T> class DiverseListImpl : private DiverseListBase { |
| DiverseListImpl(const DiverseListImpl<T> &other) = delete; |
| DiverseListImpl(DiverseListImpl<T> &&other) = delete; |
| |
| protected: |
| DiverseListImpl(char *endOfAllocation) { |
| initialize(endOfAllocation); |
| } |
| |
| DiverseListImpl(const DiverseListImpl<T> &other, char *endOfAllocation) { |
| initialize(endOfAllocation); |
| copyFrom(other); |
| } |
| DiverseListImpl(DiverseListImpl<T> &&other, char *endOfAllocation) { |
| // If the other is allocated inline, just initialize and copy. |
| if (other.isAllocatedInline()) { |
| initialize(endOfAllocation); |
| copyFrom(other); |
| return; |
| } |
| |
| // Otherwise, steal its allocations. |
| Begin = other.Begin; |
| End = other.End; |
| EndOfAllocation = other.EndOfAllocation; |
| other.Begin = other.End = other.EndOfAllocation = (char*) (&other + 1); |
| assert(other.isAllocatedInline()); |
| } |
| |
| public: |
| /// Query whether the stack is empty. |
| bool empty() const { |
| checkValid(); |
| return Begin == End; |
| } |
| |
| /// Return a reference to the first element in the list. |
| T &front() { |
| assert(!empty()); |
| return *reinterpret_cast<T*>(Begin); |
| } |
| |
| /// Return a reference to the first element in the list. |
| const T &front() const { |
| assert(!empty()); |
| return *reinterpret_cast<const T*>(Begin); |
| } |
| |
| class const_iterator; |
| class iterator { |
| char *Ptr; |
| friend class DiverseListImpl; |
| friend class const_iterator; |
| iterator(char *ptr) : Ptr(ptr) {} |
| |
| public: |
| iterator() = default; |
| |
| T &operator*() const { return *reinterpret_cast<T*>(Ptr); } |
| T *operator->() const { return reinterpret_cast<T*>(Ptr); } |
| iterator &operator++() { |
| Ptr += (*this)->allocated_size(); |
| return *this; |
| } |
| iterator operator++(int _) { |
| auto copy = *this; |
| operator++(); |
| return copy; |
| } |
| |
| /// advancePast - Like operator++, but asserting that the current |
| /// object has a known type. |
| template <class U> void advancePast() { |
| assert((*this)->allocated_size() == sizeof(U)); |
| Ptr += sizeof(U); |
| } |
| |
| friend bool operator==(iterator a, iterator b) { return a.Ptr == b.Ptr; } |
| friend bool operator!=(iterator a, iterator b) { return !operator==(a, b); } |
| }; |
| iterator begin() { checkValid(); return iterator(Begin); } |
| iterator end() { checkValid(); return iterator(End); } |
| iterator find(stable_iterator it) { |
| checkValid(); |
| assert(it.Offset <= End - Begin); |
| return iterator(Begin + it.Offset); |
| } |
| stable_iterator stabilize(iterator it) const { |
| checkValid(); |
| assert(Begin <= it.Ptr && it.Ptr <= End); |
| return stable_iterator(it.Ptr - Begin); |
| } |
| |
| class const_iterator { |
| const char *Ptr; |
| friend class DiverseListImpl; |
| const_iterator(const char *ptr) : Ptr(ptr) {} |
| public: |
| const_iterator() = default; |
| const_iterator(iterator it) : Ptr(it.Ptr) {} |
| |
| const T &operator*() const { return *reinterpret_cast<const T*>(Ptr); } |
| const T *operator->() const { return reinterpret_cast<const T*>(Ptr); } |
| const_iterator &operator++() { |
| Ptr += (*this)->allocated_size(); |
| return *this; |
| } |
| const_iterator operator++(int _) { |
| auto copy = *this; |
| operator++(); |
| return copy; |
| } |
| |
| /// advancePast - Like operator++, but asserting that the current |
| /// object has a known type. |
| template <class U> void advancePast() { |
| assert((*this)->allocated_size() == sizeof(U)); |
| Ptr += sizeof(U); |
| } |
| |
| friend bool operator==(const_iterator a, const_iterator b) { |
| return a.Ptr == b.Ptr; |
| } |
| friend bool operator!=(const_iterator a, const_iterator b) { |
| return !operator==(a, b); |
| } |
| }; |
| const_iterator begin() const { checkValid(); return const_iterator(Begin); } |
| const_iterator end() const { checkValid(); return const_iterator(End); } |
| const_iterator find(stable_iterator it) const { |
| checkValid(); |
| assert(it.Offset <= End - Begin); |
| return const_iterator(Begin + it.Offset); |
| } |
| stable_iterator stabilize(const_iterator it) const { |
| checkValid(); |
| assert(Begin <= it.Ptr && it.Ptr <= End); |
| return stable_iterator(it.Ptr - Begin); |
| } |
| |
| /// Add a new object onto the end of the list. |
| template <class U, class... A> U &add(A && ...args) { |
| char *storage = addNewStorage(sizeof(U)); |
| U &newObject = *::new (storage) U(::std::forward<A>(args)...); |
| return newObject; |
| } |
| |
| /// Add a new object onto the end of the list with some extra storage. |
| template <class U, class... A> U &addWithExtra(size_t extra, A && ...args) { |
| char *storage = addNewStorage(sizeof(U) + extra); |
| U &newObject = *::new (storage) U(::std::forward<A>(args)...); |
| return newObject; |
| } |
| }; |
| |
| } // end namespace swift |
| |
| #endif // SWIFT_BASIC_DIVERSELIST_H |