diff --git a/ui/TODO.otl b/ui/TODO.otl index c4b5f9dd..3095fa0e 100755 --- a/ui/TODO.otl +++ b/ui/TODO.otl @@ -110,6 +110,22 @@ Roadmap [_] 31% Gen 3 current todo [_] 62% High priority + [_] Might be a good idea to use sparse arrays for things like marks... + | eliminate: + | - need for keeping things sorted all the time + | - speed-up access -- everything has the same index + | - speed-up modification -- just mirror all the operations + | - searching in more than one place + | + | introduce: + | - memory overhead - each array is always N elements + | - conversion on import, export and crop + | need to clear / insert all the nulls + | + | candidates: + | - marks + | - bookmarks + | - tags [_] BUG: sorting breaks when at or near the end of a ribbon... | | Race condition... diff --git a/ui/crop.js b/ui/crop.js index b22ced54..4ce31a6d 100755 --- a/ui/crop.js +++ b/ui/crop.js @@ -35,6 +35,7 @@ function getAllData(){ // // XXX should this set the .current to anything but null or the first elem??? function makeCroppedData(gids, keep_ribbons, keep_unloaded_gids){ + gids = fastSortGIDsByOrder(gids) var res = { varsion: DATA_VERSION, current: null, diff --git a/ui/data.js b/ui/data.js index f6006320..d9302451 100755 --- a/ui/data.js +++ b/ui/data.js @@ -23,6 +23,7 @@ // MARKED - marks data // BOOKMARKS - bookmarks data // BOOKMARKS_DATA - bookmarks metadata +// TAGS - tag data // // // Changes: @@ -574,6 +575,36 @@ function binSearch(target, lst, check, return_position, get){ } +// Make a sparse gid list... +// +// NOTE: the resulting list will always be sorted... +// NOTE: this will skip all elements not in order +function makeSparceGIDList(gids, data){ + data = data == null ? DATA : data + var order = data.order + var res = [] + + gids.forEach(function(e){ + var i = order.indexOf(e) + if(i < 0){ + return + } + res[i] = e + }) + + return res +} + + +// Remove all the undefined's form a sparse list... +// +function compactSparceList(lst){ + return lst.filter(function(e){ + return e !== undefined + }) +} + + // This is a cheating fast sort... // // By cheating we might use more memory -- this is both not in-place @@ -605,20 +636,7 @@ function binSearch(target, lst, check, return_position, get){ // On the down side, this has some memory overhead -- ~ N - n * ref // function fastSortGIDsByOrder(gids, data){ - data = data == null ? DATA : data - - var order = data.order - var res = [] - - // insert the gids to their order positions... - gids.forEach(function(gid){ - res[order.indexOf(gid)] = gid - }) - - // clear out the nulls... - return res.filter(function(e){ - return e != null - }) + return compactSparceList(makeSparceGIDList(gids, data)) } @@ -794,7 +812,7 @@ function getAllGids(data){ // NOTE: this will return an unsorted list of gids... // NOTE: this will sort the result unless either no_sort is true or gids // is not given... -function getLoadedGIDs(gids, data, no_sort){ +function getLoadedGIDs(gids, data){ data = data == null ? DATA : data var res = [] data.ribbons.forEach(function(r){ @@ -802,12 +820,9 @@ function getLoadedGIDs(gids, data, no_sort){ }) if(gids != null){ return gids.filter(function(e){ - return res.indexOf(e) >= 0 + return e == null ? false : (res.indexOf(e) >= 0) }) } - if(!no_sort){ - res = fastSortGIDsByOrder(res) - } return res } @@ -857,6 +872,8 @@ function insertGIDToPosition(gid, list, data){ // // NOTE: if gid is present in the searched ribbon this will return it. // NOTE: this uses it's own predicate... +// +// XXX make this undefined tolerant -- sparse list compatibility... function getGIDBefore(gid, ribbon, data, search){ gid = gid == null ? getImageGID() : gid data = data == null ? DATA : data @@ -2360,7 +2377,6 @@ function showImage(gid){ // NOTE: if no_reload_viewer is true, then no re-rendering is triggered. function updateRibbonOrder(no_reload_viewer){ for(var i=0; i < DATA.ribbons.length; i++){ - //DATA.ribbons[i].sort(imageOrderCmp) DATA.ribbons[i] = fastSortGIDsByOrder(DATA.ribbons[i]) } if(!no_reload_viewer){ diff --git a/ui/marks.js b/ui/marks.js index 1d8fe57f..18dcdcba 100755 --- a/ui/marks.js +++ b/ui/marks.js @@ -101,6 +101,8 @@ function makeMarkedLister(get_marked){ // - number - ribbon index // - list - list of gids used as source // - null - same as all +// +// XXX with sparce lists this is trivial: get all the null indexes... function makeUnmarkedLister(get_marked, get_cache){ return function(mode){ var marked = get_marked() @@ -138,9 +140,10 @@ var getUnmarked = makeUnmarkedLister( function(){ return _UNMARKED_CACHE }) +// XXX make this undefined tolerant -- sparse list compatibility... var getMarkedGIDBefore = makeGIDBeforeGetterFromList( function(){ - return MARKED + return compactSparceList(MARKED) }) @@ -347,12 +350,12 @@ var toggleMark = makeMarkToggler( // add marked image to list... if(action == 'on'){ if(MARKED.indexOf(gid) == -1){ - insertGIDToPosition(gid, MARKED) + MARKED[DATA.order.indexOf(gid)] = gid } // remove marked image from list... } else { - MARKED.splice(MARKED.indexOf(gid), 1) + delete MARKED[MARKED.indexOf(gid)] } marksUpdated() @@ -360,7 +363,7 @@ var toggleMark = makeMarkToggler( -function toggleAllMarks(action, mode){ +function setAllMarks(action, mode){ action = action == null ? toggleMark('?') : action mode = mode == null ? 'ribbon' : mode @@ -369,8 +372,7 @@ function toggleAllMarks(action, mode){ if(action == 'on'){ var _update = function(e){ if(MARKED.indexOf(e) < 0){ - //insertGIDToPosition(e, MARKED) - MARKED.push(e) + MARKED[DATA.order.indexOf(e)] = e updated.push(e) } } @@ -378,7 +380,7 @@ function toggleAllMarks(action, mode){ var _update = function(e){ var i = MARKED.indexOf(e) if(i >= 0){ - MARKED.splice(i, 1) + delete MARKED[i] updated.push(e) } } @@ -395,8 +397,6 @@ function toggleAllMarks(action, mode){ res.forEach(_update) - MARKED = fastSortGIDsByOrder(MARKED) - updateImages(updated) $('.viewer').trigger('togglingMarks', [updated, action]) @@ -411,7 +411,7 @@ function toggleAllMarks(action, mode){ // - 'all' function removeImageMarks(mode){ mode = mode == null ? 'ribbon' : mode - var res = toggleAllMarks('off', mode) + var res = setAllMarks('off', mode) $('.viewer').trigger('removingMarks', [res, mode]) return res } @@ -419,7 +419,7 @@ function removeImageMarks(mode){ function markAll(mode){ mode = mode == null ? 'ribbon' : mode - var res = toggleAllMarks('on', mode) + var res = setAllMarks('on', mode) $('.viewer').trigger('addingMarks', [res, mode]) return res } @@ -435,14 +435,12 @@ function invertImageMarks(){ var i = MARKED.indexOf(e) if(i == -1){ on.push(e) - MARKED.push(e) - //insertGIDToPosition(e, MARKED) + MARKED[DATA.order.indexOf(e)] = e } else { off.push(e) - MARKED.splice(i, 1) + delete MARKED[i] } }) - MARKED = fastSortGIDsByOrder(MARKED) updateImages(ribbon) $('.viewer') @@ -477,10 +475,9 @@ function toggleMarkBlock(image){ } // do the toggle... if(state){ - //insertGIDToPosition(e, MARKED) - MARKED.push(e) + MARKED[DATA.order.indexOf(e)] = e } else { - MARKED.splice(MARKED.indexOf(e), 1) + delete MARKED[MARKED.indexOf(e)] } updated.push(e) } @@ -494,8 +491,6 @@ function toggleMarkBlock(image){ var right = ribbon.slice(i+1) $.each(right, _convert) - MARKED = fastSortGIDsByOrder(MARKED) - updateImages(updated) $('.viewer') @@ -593,10 +588,10 @@ function shiftMarkedImagesRight(){ // of makeNextFromListAction(..) for more info) var nextMark = makeNextFromListAction( getMarkedGIDBefore, - function(){ return MARKED }) + function(){ return compactSparceList(MARKED) }) var prevMark = makePrevFromListAction( getMarkedGIDBefore, - function(){ return MARKED }) + function(){ return compactSparceList(MARKED) }) var nextUnmarked = makeNextFromListAction( @@ -697,23 +692,7 @@ var loadFileMarks = makeFileLoader( MARKED_FILE_PATTERN, [], function(data){ - // set the MARKED... - MARKED = data - - // for version below 2.1, sort MARKED and update to 2.1... - if(DATA.version == '2.0'){ - setTimeout(function(){ - var t0 = Date.now() - MARKED = fastSortGIDsByOrder(MARKED) - var t1 = Date.now() - marksUpdated() - - DATA.version = DATA_VERSION - dataUpdated() - - console.warn('Marks: sort: done ('+( t1 - t0 )+'ms) -- re-save the data.') - }, 0) - } + MARKED = makeSparceGIDList(data) }, 'marksLoaded') @@ -723,7 +702,7 @@ var saveFileMarks = makeFileSaver( 'Marks', MARKED_FILE_DEFAULT, function(){ - return MARKED + return compactSparceList(MARKED) }) @@ -768,11 +747,20 @@ function setupMarks(viewer){ }) }) .on('sortedImages', function(){ - MARKED = fastSortGIDsByOrder(MARKED) + MARKED = makeSparceGIDList(MARKED) marksUpdated() }) .on('horizontalShiftedImage', function(evt, gid, direction){ - if(shiftGIDToOrderInList(gid, direction, MARKED)){ + var n = DATA.order.indexOf(gid) + var o = MARKED.indexOf(gid) + + // move the marked gid... + MARKED.splice(o, 1) + MARKED.splice(n, 0, gid) + + // test if there are any marked images between n and o... + var shift = compactSparceList(MARKED.slice(Math.min(n, o)+1, Math.max(n, o))) + if(shift.length > 0){ marksUpdated() } })