neptools

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

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