neptools

Modding tools to Neptunia games
git clone https://git.neptards.moe/neptards/neptools.git
Log | Files | Refs | Submodules | README | LICENSE

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"