item.hpp (6569B)
1 #ifndef UUID_294A7F35_D9EC_4A07_961F_A74307C4FA29 2 #define UUID_294A7F35_D9EC_4A07_961F_A74307C4FA29 3 #pragma once 4 5 #include "item_base.hpp" 6 #include "../dumpable.hpp" 7 8 #include <libshit/check.hpp> 9 #include <libshit/shared_ptr.hpp> 10 #include <libshit/container/parent_list.hpp> 11 #include <libshit/lua/user_type_fwd.hpp> 12 13 #include <iosfwd> 14 #include <vector> 15 #include <map> 16 #include <boost/intrusive/set.hpp> 17 18 namespace Neptools 19 { 20 21 class ItemWithChildren; 22 struct ItemListTraits; 23 24 LIBSHIT_GEN_EXCEPTION_TYPE(InvalidItemState, std::logic_error); 25 26 class Item 27 : public Libshit::RefCounted, public Dumpable, 28 public Libshit::ParentListBaseHook<> 29 { 30 LIBSHIT_LUA_CLASS; 31 protected: 32 struct Key {}; 33 public: 34 // do not change Context& to Weak/Shared ptr 35 // otherwise Context's constructor will try to construct a WeakPtr before 36 // RefCounted's constructor is finished, making an off-by-one error and 37 // freeing the context twice 38 explicit Item( 39 Key, Context& ctx, FilePosition position = 0) noexcept 40 : position{position}, context{&ctx} {} 41 Item(const Item&) = delete; 42 void operator=(const Item&) = delete; 43 virtual ~Item(); 44 45 Libshit::RefCountedPtr<Context> GetContextMaybe() noexcept 46 { return context.lock(); } 47 Libshit::NotNull<Libshit::RefCountedPtr<Context>> GetContext() 48 { return Libshit::NotNull<Libshit::RefCountedPtr<Context>>{context}; } 49 LIBSHIT_NOLUA Context& GetUnsafeContext() noexcept 50 { return *context.unsafe_get(); } 51 ItemWithChildren* GetParent() noexcept; 52 53 LIBSHIT_NOLUA Libshit::RefCountedPtr<const Context> 54 GetContextMaybe() const noexcept 55 { return context.lock(); } 56 LIBSHIT_NOLUA Libshit::NotNull<Libshit::RefCountedPtr<const Context>> 57 GetContext() const 58 { return Libshit::NotNull<Libshit::RefCountedPtr<const Context>>{context}; } 59 LIBSHIT_NOLUA const Context& GetUnsafeContext() const noexcept 60 { return *context.unsafe_get(); } 61 LIBSHIT_NOLUA const ItemWithChildren* GetParent() const noexcept; 62 LIBSHIT_NOLUA auto Iterator() const noexcept; 63 LIBSHIT_NOLUA auto Iterator() noexcept; 64 65 FilePosition GetPosition() const noexcept { return position; } 66 67 template <typename Checker = Libshit::Check::Assert> 68 void Replace(const Libshit::NotNull<Libshit::RefCountedPtr<Item>>& nitem) 69 { 70 LIBSHIT_CHECK(InvalidItemState, GetParent(), "no parent"); 71 if constexpr (!Checker::IS_NOP) 72 { 73 auto nsize = nitem->GetSize(); 74 for (auto& l : labels) 75 LIBSHIT_CHECK(InvalidItemState, l.GetPtr().offset <= nsize, 76 "would invalidate labels"); 77 } 78 LIBSHIT_CHECK(InvalidItemState, nitem->labels.empty(), 79 "new item has labels"); 80 Replace_(nitem); 81 } 82 83 // properties needed: none (might help if ordered) 84 // update Slice if no longer ordered 85 using LabelsContainer = boost::intrusive::multiset< 86 Label, 87 boost::intrusive::base_hook<LabelOffsetHook>, 88 boost::intrusive::constant_time_size<false>, 89 boost::intrusive::key_of_value<LabelOffsetKeyOfValue>>; 90 LIBSHIT_LUAGEN(wrap: "TableRetWrap") 91 const LabelsContainer& GetLabels() const { return labels; } 92 93 void Dispose() noexcept override; 94 95 protected: 96 void UpdatePosition(FilePosition npos); 97 98 void Inspect_(std::ostream& os, unsigned indent) const override = 0; 99 100 using SlicePair = std::pair<Libshit::NotNull< 101 Libshit::RefCountedPtr<Item>>, FilePosition>; 102 using SliceSeq = std::vector<SlicePair>; 103 void Slice(SliceSeq seq); 104 105 FilePosition position; 106 107 private: 108 Libshit::WeakRefCountedPtr<Context> context; 109 110 LabelsContainer labels; 111 112 void Replace_(const Libshit::NotNull<Libshit::RefCountedPtr<Item>>& nitem); 113 virtual void Removed(); 114 115 friend class Context; 116 friend struct ItemListTraits; 117 friend class ItemWithChildren; 118 template <typename, typename> friend struct Libshit::Lua::TypeRegisterTraits; 119 }; 120 static_assert( 121 std::is_same_v<Libshit::SmartPtr<Item>, Libshit::RefCountedPtr<Item>>); 122 123 std::ostream& operator<<(std::ostream& os, const Item& item); 124 inline FilePosition ToFilePos(ItemPointer ptr) noexcept 125 { return ptr.item->GetPosition() + ptr.offset; } 126 127 using ItemList = Libshit::ParentList<Item, ItemListTraits>; 128 struct ItemListTraits 129 { 130 static void add(ItemList&, Item& item) noexcept 131 { item.AddRef(); } 132 static void remove(ItemList&, Item& item) noexcept 133 { item.Removed(); item.RemoveRef(); } 134 }; 135 136 inline auto Item::Iterator() const noexcept 137 { return ItemList::s_iterator_to(*this); } 138 inline auto Item::Iterator() noexcept 139 { return ItemList::s_iterator_to(*this); } 140 141 class ItemWithChildren : public Item, private ItemList 142 { 143 LIBSHIT_LUA_CLASS; 144 public: 145 using Item::Item; 146 147 LIBSHIT_LUAGEN(wrap: "OwnedSharedPtrWrap") 148 ItemList& GetChildren() noexcept { return *this; } 149 LIBSHIT_NOLUA const ItemList& GetChildren() const noexcept { return *this; } 150 151 FilePosition GetSize() const override; 152 void Fixup() override { Fixup_(0); } 153 154 LIBSHIT_NOLUA void MoveNextToChild(size_t size) noexcept; 155 156 void Dispose() noexcept override; 157 158 protected: 159 void Dump_(Sink& sink) const override; 160 void InspectChildren(std::ostream& sink, unsigned indent) const; 161 void Fixup_(FilePosition offset); 162 163 private: 164 void Removed() override; 165 166 friend struct ::Neptools::ItemListTraits; 167 friend class Item; 168 } LIBSHIT_LUAGEN(post_register: %q( 169 LIBSHIT_LUA_RUNBC(bld, builder, 1); 170 bld.SetField("build"); 171 )); 172 173 inline ItemWithChildren* Item::GetParent() noexcept 174 { return static_cast<ItemWithChildren*>(ItemList::opt_get_parent(*this)); } 175 inline const ItemWithChildren* Item::GetParent() const noexcept 176 { return static_cast<const ItemWithChildren*>(ItemList::opt_get_parent(*this)); } 177 178 } 179 180 #if LIBSHIT_WITH_LUA 181 template <typename T> 182 struct Libshit::Lua::SmartObjectMaker< 183 T, std::enable_if_t< 184 std::is_base_of_v<Neptools::Item, T> && 185 !std::is_base_of_v<Neptools::Context, T>>> 186 { 187 template <typename Key, typename Ctx, typename... Args> 188 static decltype(auto) Make(std::remove_pointer_t<Ctx>& ctx, Args&&... args) 189 { return ctx.template Create<T>(std::forward<Args>(args)...); } 190 }; 191 192 template<> struct Libshit::Lua::TypeTraits<Neptools::Item::Key> 193 { 194 // HACK 195 // Dummy function, needed by LuaGetRef to get above maker to work when 196 // using binding generator. It's undefined on purpose. 197 template <bool> static void Get(Lua::StateRef, bool, int); 198 }; 199 #endif 200 201 #endif