diff --git a/aegisub/src/auto4_lua.h b/aegisub/src/auto4_lua.h index 6fc7e6b74..2b4caeba7 100644 --- a/aegisub/src/auto4_lua.h +++ b/aegisub/src/auto4_lua.h @@ -55,7 +55,7 @@ namespace Automation4 { struct PendingCommit { wxString mesage; int modification_type; - std::list lines; + std::vector lines; }; /// Pointer to file being modified @@ -70,6 +70,8 @@ namespace Automation4 { bool can_set_undo; /// throws an error if modification is disallowed void CheckAllowModify(); + /// throws an error if the line index is out of bounds + void CheckBounds(int idx); /// How ass file been modified by the script since the last commit int modification_type; @@ -79,19 +81,12 @@ namespace Automation4 { int references; /// Set of subtitle lines being modified; initially a shallow copy of ass->Line - std::list lines; + std::vector lines; /// Commits to apply once processing completes successfully std::deque pending_commits; /// Lines to delete once processing complete successfully std::deque lines_to_delete; - /// Cursor for last access into file - std::list::iterator last_entry_ptr; - /// Index for last access into file - int last_entry_id; - /// Move last_entry_ptr to 1-based index n - void SeekCursorTo(int n); - int ObjectIndexRead(lua_State *L); void ObjectIndexWrite(lua_State *L); int ObjectGetLen(lua_State *L); diff --git a/aegisub/src/auto4_lua_assfile.cpp b/aegisub/src/auto4_lua_assfile.cpp index cbf34bb2a..7ddacc04e 100644 --- a/aegisub/src/auto4_lua_assfile.cpp +++ b/aegisub/src/auto4_lua_assfile.cpp @@ -183,6 +183,12 @@ namespace Automation4 { luaL_error(L, "Attempt to modify subtitles in read-only feature context."); } + void LuaAssFile::CheckBounds(int idx) + { + if (idx <= 0 || idx > (int)lines.size()) + luaL_error(L, "Requested out-of-range line from subtitle file: %d", idx); + } + void LuaAssFile::AssEntryToLua(lua_State *L, AssEntry *e) { lua_newtable(L); @@ -371,35 +377,17 @@ namespace Automation4 { } } - void LuaAssFile::SeekCursorTo(int n) - { - if (n <= 0 || n > (int)lines.size()) - luaL_error(L, "Requested out-of-range line from subtitle file: %d", n); - - if (n < last_entry_id - n) { - // fastest to search from start - last_entry_ptr = lines.begin(); - last_entry_id = 1; - } - else if ((int)lines.size() - last_entry_id < abs(last_entry_id - n)) { - // fastest to search from end - last_entry_ptr = lines.end(); - last_entry_id = lines.size() + 1; - } - // otherwise fastest to search from cursor - - advance(last_entry_ptr, n - last_entry_id); - last_entry_id = n; - } - int LuaAssFile::ObjectIndexRead(lua_State *L) { switch (lua_type(L, 2)) { case LUA_TNUMBER: + { // read an indexed AssEntry - SeekCursorTo(lua_tointeger(L, 2)); - AssEntryToLua(L, *last_entry_ptr); + int idx = lua_tointeger(L, 2); + CheckBounds(idx); + AssEntryToLua(L, lines[idx - 1]); return 1; + } case LUA_TSTRING: { @@ -466,9 +454,9 @@ namespace Automation4 { // insert AssEntry *e = LuaToAssEntry(L); modification_type |= modification_mask(e); - SeekCursorTo(n); - lines_to_delete.push_back(*last_entry_ptr); - *last_entry_ptr = e; + CheckBounds(n); + lines_to_delete.push_back(lines[n - 1]); + lines[n - 1] = e; } else { // delete @@ -497,40 +485,43 @@ namespace Automation4 { while (itemcount > 0) { int n = luaL_checkint(L, itemcount); luaL_argcheck(L, n > 0 && n <= (int)lines.size(), itemcount, "Out of range line index"); - ids.push_back(n); + ids.push_back(n - 1); --itemcount; } - // sort the item id's so we can delete from last to first to preserve original numbering sort(ids.begin(), ids.end()); - // now delete the id's backwards - SeekCursorTo(ids.back()); - for (size_t i = ids.size(); i > 0; --i) { - while (last_entry_id > ids[i - 1]) { - --last_entry_ptr; - --last_entry_id; + size_t id_idx = 0, out = 0; + for (size_t i = 0; i < lines.size(); ++i) { + if (id_idx < ids.size() && ids[id_idx] == i) { + modification_type |= modification_mask(lines[i]); + lines_to_delete.push_back(lines[i]); + ++id_idx; + } + else { + lines[out++] = lines[i]; } - modification_type |= modification_mask(*last_entry_ptr); - lines_to_delete.push_back(*last_entry_ptr); - lines.erase(last_entry_ptr++); } + + lines.erase(lines.begin() + out, lines.end()); } void LuaAssFile::ObjectDeleteRange(lua_State *L) { CheckAllowModify(); - int a = std::max(luaL_checkinteger(L, 1), 1); - int b = std::min(luaL_checkinteger(L, 2), lines.size()); + size_t a = std::max(luaL_checkinteger(L, 1), 1) - 1; + size_t b = std::min(luaL_checkinteger(L, 2), lines.size()); - SeekCursorTo(a); + if (a >= b) return; - while (a++ <= b) { - modification_type |= modification_mask(*last_entry_ptr); - lines_to_delete.push_back(*last_entry_ptr); - lines.erase(last_entry_ptr++); + for (; b < lines.size(); ++a, ++b) { + modification_type |= modification_mask(lines[a]); + lines_to_delete.push_back(lines[a]); + lines[a] = lines[b]; } + + lines.erase(lines.begin() + a, lines.end()); } void LuaAssFile::ObjectAppend(lua_State *L) @@ -539,18 +530,13 @@ namespace Automation4 { int n = lua_gettop(L); - if (last_entry_ptr != lines.begin()) { - --last_entry_ptr; - --last_entry_id; - } - for (int i = 1; i <= n; i++) { lua_pushvalue(L, i); AssEntry *e = LuaToAssEntry(L); modification_type |= modification_mask(e); // Find the appropriate place to put it - std::list::iterator it = lines.end(); + std::vector::iterator it = lines.end(); if (!lines.empty()) { do { --it; @@ -574,11 +560,6 @@ namespace Automation4 { lines.insert(it, e); } } - - // If last_entry_ptr is end, the file was empty but no longer is, so - // last_entry_id is wrong - if (last_entry_ptr == lines.end()) - last_entry_id = lines.size() + 1; } void LuaAssFile::ObjectInsert(lua_State *L) @@ -597,18 +578,16 @@ namespace Automation4 { return; } - SeekCursorTo(before); - int n = lua_gettop(L); + std::vector new_entries(n - 1, (AssEntry *)0); for (int i = 2; i <= n; i++) { lua_pushvalue(L, i); AssEntry *e = LuaToAssEntry(L); modification_type |= modification_mask(e); - lines.insert(last_entry_ptr, e); + new_entries[i - 2] = e; lua_pop(L, 1); } - - last_entry_id += n - 1; + lines.insert(lines.begin() + before - 1, new_entries.begin(), new_entries.end()); } void LuaAssFile::ObjectGarbageCollect(lua_State *L) @@ -680,13 +659,16 @@ namespace Automation4 { { // Apply any pending commits for (std::deque::iterator it = pending_commits.begin(); it != pending_commits.end(); ++it) { - swap(ass->Line, it->lines); + ass->Line.clear(); + ass->Line.insert(ass->Line.end(), it->lines.begin(), it->lines.end()); ass->Commit(it->mesage, it->modification_type); } // Commit any changes after the last undo point was set - if (modification_type) - swap(ass->Line, lines); + if (modification_type) { + ass->Line.clear(); + ass->Line.insert(ass->Line.end(), lines.begin(), lines.end()); + } if (modification_type && can_set_undo && !undo_description.empty()) ass->Commit(undo_description, modification_type); @@ -709,9 +691,7 @@ namespace Automation4 { , can_set_undo(can_set_undo) , modification_type(0) , references(2) - , lines(ass->Line) - , last_entry_ptr(lines.begin()) - , last_entry_id(1) + , lines(ass->Line.begin(), ass->Line.end()) { // prepare userdata object *static_cast(lua_newuserdata(L, sizeof(LuaAssFile*))) = this;