item.cpp (5207B)
1 #include "item.hpp" 2 #include "context.hpp" 3 #include "raw_item.hpp" 4 #include "../utils.hpp" 5 6 #include <libshit/string_utils.hpp> 7 8 #include <algorithm> 9 #include <iostream> 10 11 #if LIBSHIT_WITH_LUA && !defined(LIBSHIT_BINDING_GENERATOR) 12 # include "format/builder.lua.h" 13 #endif 14 15 #define LIBSHIT_LOG_NAME "item" 16 #include <libshit/logger_helper.hpp> 17 18 namespace Neptools 19 { 20 21 Item::~Item() 22 { 23 Item::Dispose(); 24 } 25 26 void Item::Inspect_(std::ostream& os, unsigned indent) const 27 { 28 for (const auto& it : GetLabels()) 29 { 30 os << "label(" << Libshit::Quoted(it.GetName()); 31 if (it.GetPtr().offset != 0) 32 os << ", " << it.GetPtr().offset; 33 os << ")\n"; 34 } 35 Indent(os, indent); 36 } 37 38 void Item::UpdatePosition(FilePosition npos) 39 { 40 position = npos; 41 Fixup(); 42 } 43 44 void Item::Replace_(const Libshit::NotNull<Libshit::SmartPtr<Item>>& nitem) 45 { 46 auto ctx = GetContext(); 47 // move labels 48 nitem->labels.swap(labels); // intrusive move op= does this... (but undocumented) 49 for (auto& l : nitem->labels) 50 l.ptr.item = nitem.get(); 51 52 // update pointermap 53 nitem->position = position; 54 auto it = ctx->pmap.find(position); 55 if (it != ctx->pmap.end() && it->second == this) 56 it->second = nitem.get(); 57 58 auto& list = GetParent()->GetChildren(); 59 auto self = Iterator(); 60 61 list.insert(self, *nitem); 62 list.erase(self); 63 } 64 65 void Item::Removed() 66 { 67 auto ctx = GetContextMaybe(); 68 if (!ctx) return; 69 auto it = ctx->pmap.find(position); 70 if (it != ctx->pmap.end() && it->second == this) 71 ctx->pmap.erase(it); 72 } 73 74 void Item::Slice(SliceSeq seq) 75 { 76 LIBSHIT_ASSERT(std::is_sorted(seq.begin(), seq.end(), 77 [](const auto& a, const auto& b) { return a.second < b.second; })); 78 79 Libshit::SmartPtr<Item> do_not_delete_this_until_returning{this}; 80 81 LabelsContainer lbls{std::move(labels)}; 82 auto ctx = GetContext(); 83 auto& pmap = ctx->pmap; 84 auto empty = pmap.empty(); 85 86 auto& list = GetParent()->GetChildren(); 87 auto it = Iterator(); 88 it = list.erase(it); 89 90 FilePosition offset = 0; 91 auto base_pos = position; 92 93 auto label = lbls.unlink_leftmost_without_rebalance(); 94 FilePosition last_offset = 0; 95 for (auto& el : seq) 96 { 97 LIBSHIT_ASSERT(el.first->labels.empty()); 98 while (label && (label->ptr.offset < el.second || 99 (label->ptr.offset == el.second && 100 label->ptr.offset == last_offset))) 101 { 102 label->ptr.item = el.first.get(); 103 label->ptr.offset -= offset; 104 el.first->labels.insert(*label); 105 106 label = lbls.unlink_leftmost_without_rebalance(); 107 } 108 last_offset = el.second; 109 110 // move in place 111 el.first->position = base_pos + offset; 112 list.insert(it, *el.first); 113 114 // add to pmap if needed 115 if (!empty) 116 // may throw! but only used during parsing, and an exception there 117 // is fatal, so it's not really a problem 118 pmap.emplace(el.first->position, &*el.first); 119 120 offset = el.second; 121 } 122 LIBSHIT_ASSERT(label == nullptr); 123 } 124 125 void Item::Dispose() noexcept 126 { 127 LIBSHIT_ASSERT(labels.empty() && !GetParent()); 128 if (auto ctx = GetContextMaybe()) 129 { 130 auto it = ctx->pmap.find(position); 131 if (it != ctx->pmap.end() && it->second == this) 132 { 133 WARN << "Item " << this << " unlinked from pmap in Dispose" << std::endl; 134 ctx->pmap.erase(it); 135 } 136 } 137 138 context.reset(); 139 } 140 141 std::ostream& operator<<(std::ostream& os, const Item& item) 142 { 143 item.Inspect(os); 144 return os; 145 } 146 147 void ItemWithChildren::Dump_(Sink& sink) const 148 { 149 for (auto& c : GetChildren()) 150 c.Dump(sink); 151 } 152 153 void ItemWithChildren::InspectChildren(std::ostream& os, unsigned indent) const 154 { 155 if (GetChildren().empty()) return; 156 157 os << ":build(function()\n"; 158 for (auto& c : GetChildren()) 159 { 160 c.Inspect_(os, indent+1); 161 os << '\n'; 162 } 163 Indent(os, indent) << "end)"; 164 } 165 166 167 FilePosition ItemWithChildren::GetSize() const 168 { 169 FilePosition ret = 0; 170 for (auto& c : GetChildren()) 171 ret += c.GetSize(); 172 return ret; 173 } 174 175 void ItemWithChildren::Fixup_(FilePosition offset) 176 { 177 FilePosition pos = position + offset; 178 for (auto& c : GetChildren()) 179 { 180 c.UpdatePosition(pos); 181 pos += c.GetSize(); 182 } 183 } 184 185 void ItemWithChildren::MoveNextToChild(size_t size) noexcept 186 { 187 auto& list = GetParent()->GetChildren(); 188 // make sure we have a ref when erasing... 189 Libshit::SmartPtr<Item> nchild = &Libshit::asserted_cast<RawItem&>( 190 *++Iterator()).Split(0, size); 191 list.erase(nchild->Iterator()); 192 GetChildren().push_back(*nchild); 193 } 194 195 void ItemWithChildren::Dispose() noexcept 196 { 197 GetChildren().clear(); 198 Item::Dispose(); 199 } 200 201 void ItemWithChildren::Removed() 202 { 203 Item::Removed(); 204 for (auto& ch : GetChildren()) ch.Removed(); 205 } 206 207 } 208 209 #include <libshit/container/parent_list.lua.hpp> 210 #include <libshit/lua/table_ret_wrap.hpp> 211 #include <libshit/lua/owned_shared_ptr_wrap.hpp> 212 LIBSHIT_PARENT_LIST_LUAGEN( 213 item, false, Neptools::Item, Neptools::ItemListTraits); 214 #include "item.binding.hpp"