<commit_before>
namespace collections
{
    shared_state::shared_state()
        : registry(nullptr)
        , aqueue(nullptr)
    {
        registry = new object_registry();
        aqueue = new autorelease_queue(*registry);
    }

    shared_state::~shared_state() {

        delete registry;
        delete aqueue;
    }
    
    void shared_state::u_clearState() {

        /*  Not good, but working solution.

        purpose: free allocated memory
        problem: regular delete call won't help as delete call will access memory of possible deleted object

        solution: isolate objects by nullifying cross-references, then delete objects

        all we need is just free all allocated memory but this will require track stl memory blocks
        */

        aqueue->u_nullify();

        for (auto& obj : registry->u_container()) {
            obj->u_nullifyObjects();
        }
        for (auto& obj : registry->u_container()) {
            delete obj;
        }

        registry->u_clear();
        aqueue->u_clear();
        
        if (delegate) {
            delegate->u_cleanup();
        }
    }
    
    void shared_state::clearState() {
        
        aqueue->stop();
        
        {
            u_clearState();
        }
        
        aqueue->start();
    }

    object_base * shared_state::getObject(Handle hdl) {
        return registry->getObject(hdl);
    }

    object_stack_ref shared_state::getObjectRef(Handle hdl) {
        return registry->getObjectRef(hdl);
    }

    object_base * shared_state::u_getObject(Handle hdl) {
        return registry->u_getObject(hdl);
    }

    size_t shared_state::aqueueSize() {
        return aqueue->count();
    }

    void shared_state::read_from_string(const std::string & data, int version) {
        namespace io = boost::iostreams;
        io::stream<io::array_source> stream( io::array_source(data.c_str(), data.size()) );
        read_from_stream(stream, version);
    }

    void shared_state::read_from_stream(std::istream & stream, int version) {

        stream.flags(stream.flags() | std::ios::binary);

        aqueue->stop();
        {
            // i have assumed that Skyrim devs are not idiots to run scripts in process of save game loading
            //write_lock g(_mutex);

            u_clearState();

            if (stream.peek() != std::istream::traits_type::eof()) {
                boost::archive::binary_iarchive archive(stream);

                if (kJSerializationCurrentVersion < version) {
                    _FATALERROR("plugin can not be compatible with future save version %u. plugin save vesrion is %u", version, kJSerializationCurrentVersion);
                    assert(false);
                }

                try {
                    archive >> *registry;
                    archive >> *aqueue;

                    if (delegate) {
                        delegate->u_loadAdditional(archive);
                    }
                }
                catch (const std::exception& exc) {
                    _FATALERROR("caught exception (%s) during archive load - '%s'. forcing application to crash",
                        typeid(exc).name(), exc.what());
                    //u_clearState();

                    // force whole app to crash
                    assert(false);
                }
                catch (...) {
                    _FATALERROR("caught unknown (non std::*) exception. forcing application to crash");
                    // force whole app to crash
                    assert(false);
                }
            }

            u_applyUpdates(version);
            // deadlock possible
            u_postLoadMaintenance(version);

            _DMESSAGE("%lu objects total", registry->u_container().size());
            _DMESSAGE("%lu objects in aqueue", aqueue->u_count());
        }
        aqueue->start();
    }

    std::string shared_state::write_to_string() {
        std::ostringstream stream;
        write_to_stream(stream);
        return stream.str();
    }

    void shared_state::write_to_stream(std::ostream& stream) {

        stream.flags(stream.flags() | std::ios::binary);

        boost::archive::binary_oarchive arch(stream);

        aqueue->stop();
        {
            // i have assumed that Skyrim devs are not idiots to run scripts in process of saving
            // but didn't dare to disable all that locks

            // do not lock as test shows that skyrim waits for completion of any native function running.
            // this _probably_ means that there is no any thread inside my code during save
            //read_lock g(_mutex);
            //all_objects_lock l(*registry);

            arch << *registry;
            arch << *aqueue;

            if (delegate) {
                delegate->u_saveAdditional(arch);
            }
            _DMESSAGE("%lu objects total", registry->u_container().size());
            _DMESSAGE("%lu objects in aqueue", aqueue->u_count());
        }
        aqueue->start();
    }

    //////////////////////////////////////////////////////////////////////////

    void shared_state::u_applyUpdates(int saveVersion) {

    }

    void shared_state::u_postLoadMaintenance(int saveVersion)
    {
        for (auto& obj : registry->u_container()) {
            obj->set_context(*this);
            obj->u_onLoaded();
        }
    }

}
<commit_msg>assign context to all objects first, then do the rest<commit_after>
namespace collections
{
    shared_state::shared_state()
        : registry(nullptr)
        , aqueue(nullptr)
    {
        registry = new object_registry();
        aqueue = new autorelease_queue(*registry);
    }

    shared_state::~shared_state() {

        delete registry;
        delete aqueue;
    }
    
    void shared_state::u_clearState() {

        /*  Not good, but working solution.

        purpose: free allocated memory
        problem: regular delete call won't help as delete call will access memory of possible deleted object

        solution: isolate objects by nullifying cross-references, then delete objects

        all we need is just free all allocated memory but this will require track stl memory blocks
        */

        aqueue->u_nullify();

        for (auto& obj : registry->u_container()) {
            obj->u_nullifyObjects();
        }
        for (auto& obj : registry->u_container()) {
            delete obj;
        }

        registry->u_clear();
        aqueue->u_clear();
        
        if (delegate) {
            delegate->u_cleanup();
        }
    }
    
    void shared_state::clearState() {
        
        aqueue->stop();
        
        {
            u_clearState();
        }
        
        aqueue->start();
    }

    object_base * shared_state::getObject(Handle hdl) {
        return registry->getObject(hdl);
    }

    object_stack_ref shared_state::getObjectRef(Handle hdl) {
        return registry->getObjectRef(hdl);
    }

    object_base * shared_state::u_getObject(Handle hdl) {
        return registry->u_getObject(hdl);
    }

    size_t shared_state::aqueueSize() {
        return aqueue->count();
    }

    void shared_state::read_from_string(const std::string & data, int version) {
        namespace io = boost::iostreams;
        io::stream<io::array_source> stream( io::array_source(data.c_str(), data.size()) );
        read_from_stream(stream, version);
    }

    void shared_state::read_from_stream(std::istream & stream, int version) {

        stream.flags(stream.flags() | std::ios::binary);

        aqueue->stop();
        {
            // i have assumed that Skyrim devs are not idiots to run scripts in process of save game loading
            //write_lock g(_mutex);

            u_clearState();

            if (stream.peek() != std::istream::traits_type::eof()) {
                boost::archive::binary_iarchive archive(stream);

                if (kJSerializationCurrentVersion < version) {
                    _FATALERROR("plugin can not be compatible with future save version %u. plugin save vesrion is %u", version, kJSerializationCurrentVersion);
                    assert(false);
                }

                try {
                    archive >> *registry;
                    archive >> *aqueue;

                    if (delegate) {
                        delegate->u_loadAdditional(archive);
                    }
                }
                catch (const std::exception& exc) {
                    _FATALERROR("caught exception (%s) during archive load - '%s'. forcing application to crash",
                        typeid(exc).name(), exc.what());
                    //u_clearState();

                    // force whole app to crash
                    assert(false);
                }
                catch (...) {
                    _FATALERROR("caught unknown (non std::*) exception. forcing application to crash");
                    // force whole app to crash
                    assert(false);
                }
            }

            u_applyUpdates(version);
            // deadlock possible
            u_postLoadMaintenance(version);

            _DMESSAGE("%lu objects total", registry->u_container().size());
            _DMESSAGE("%lu objects in aqueue", aqueue->u_count());
        }
        aqueue->start();
    }

    std::string shared_state::write_to_string() {
        std::ostringstream stream;
        write_to_stream(stream);
        return stream.str();
    }

    void shared_state::write_to_stream(std::ostream& stream) {

        stream.flags(stream.flags() | std::ios::binary);

        boost::archive::binary_oarchive arch(stream);

        aqueue->stop();
        {
            // i have assumed that Skyrim devs are not idiots to run scripts in process of saving
            // but didn't dare to disable all that locks

            // do not lock as test shows that skyrim waits for completion of any native function running.
            // this _probably_ means that there is no any thread inside my code during save
            //read_lock g(_mutex);
            //all_objects_lock l(*registry);

            arch << *registry;
            arch << *aqueue;

            if (delegate) {
                delegate->u_saveAdditional(arch);
            }
            _DMESSAGE("%lu objects total", registry->u_container().size());
            _DMESSAGE("%lu objects in aqueue", aqueue->u_count());
        }
        aqueue->start();
    }

    //////////////////////////////////////////////////////////////////////////

    void shared_state::u_applyUpdates(int saveVersion) {

    }

    void shared_state::u_postLoadMaintenance(int saveVersion)
    {
        for (auto& obj : registry->u_container()) {
            obj->set_context(*this);
        }

        for (auto& obj : registry->u_container()) {
            obj->u_onLoaded();
        }
    }

}

{'fraction_non_alphanumeric': 0.11837862736066329, 'fraction_numerical': 0.0, 'mean_word_length': 1.7146786696674168, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 66, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2340618', 'n_tokens_mistral': 2886, 'n_tokens_neox': 2752, 'n_words': 703}