converted marks.js to sparse list...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2014-01-16 06:36:59 +04:00
parent a76753eaa5
commit 6fe9276cee
4 changed files with 83 additions and 62 deletions

View File

@ -110,6 +110,22 @@ Roadmap
[_] 31% Gen 3 current todo [_] 31% Gen 3 current todo
[_] 62% High priority [_] 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... [_] BUG: sorting breaks when at or near the end of a ribbon...
| |
| Race condition... | Race condition...

View File

@ -35,6 +35,7 @@ function getAllData(){
// //
// XXX should this set the .current to anything but null or the first elem??? // XXX should this set the .current to anything but null or the first elem???
function makeCroppedData(gids, keep_ribbons, keep_unloaded_gids){ function makeCroppedData(gids, keep_ribbons, keep_unloaded_gids){
gids = fastSortGIDsByOrder(gids)
var res = { var res = {
varsion: DATA_VERSION, varsion: DATA_VERSION,
current: null, current: null,

View File

@ -23,6 +23,7 @@
// MARKED - marks data // MARKED - marks data
// BOOKMARKS - bookmarks data // BOOKMARKS - bookmarks data
// BOOKMARKS_DATA - bookmarks metadata // BOOKMARKS_DATA - bookmarks metadata
// TAGS - tag data
// //
// //
// Changes: // 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... // This is a cheating fast sort...
// //
// By cheating we might use more memory -- this is both not in-place // 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 // On the down side, this has some memory overhead -- ~ N - n * ref
// //
function fastSortGIDsByOrder(gids, data){ function fastSortGIDsByOrder(gids, data){
data = data == null ? DATA : data return compactSparceList(makeSparceGIDList(gids, 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
})
} }
@ -794,7 +812,7 @@ function getAllGids(data){
// NOTE: this will return an unsorted list of gids... // NOTE: this will return an unsorted list of gids...
// NOTE: this will sort the result unless either no_sort is true or gids // NOTE: this will sort the result unless either no_sort is true or gids
// is not given... // is not given...
function getLoadedGIDs(gids, data, no_sort){ function getLoadedGIDs(gids, data){
data = data == null ? DATA : data data = data == null ? DATA : data
var res = [] var res = []
data.ribbons.forEach(function(r){ data.ribbons.forEach(function(r){
@ -802,12 +820,9 @@ function getLoadedGIDs(gids, data, no_sort){
}) })
if(gids != null){ if(gids != null){
return gids.filter(function(e){ 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 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: if gid is present in the searched ribbon this will return it.
// NOTE: this uses it's own predicate... // NOTE: this uses it's own predicate...
//
// XXX make this undefined tolerant -- sparse list compatibility...
function getGIDBefore(gid, ribbon, data, search){ function getGIDBefore(gid, ribbon, data, search){
gid = gid == null ? getImageGID() : gid gid = gid == null ? getImageGID() : gid
data = data == null ? DATA : data 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. // NOTE: if no_reload_viewer is true, then no re-rendering is triggered.
function updateRibbonOrder(no_reload_viewer){ function updateRibbonOrder(no_reload_viewer){
for(var i=0; i < DATA.ribbons.length; i++){ for(var i=0; i < DATA.ribbons.length; i++){
//DATA.ribbons[i].sort(imageOrderCmp)
DATA.ribbons[i] = fastSortGIDsByOrder(DATA.ribbons[i]) DATA.ribbons[i] = fastSortGIDsByOrder(DATA.ribbons[i])
} }
if(!no_reload_viewer){ if(!no_reload_viewer){

View File

@ -101,6 +101,8 @@ function makeMarkedLister(get_marked){
// - number - ribbon index // - number - ribbon index
// - list - list of gids used as source // - list - list of gids used as source
// - null - same as all // - null - same as all
//
// XXX with sparce lists this is trivial: get all the null indexes...
function makeUnmarkedLister(get_marked, get_cache){ function makeUnmarkedLister(get_marked, get_cache){
return function(mode){ return function(mode){
var marked = get_marked() var marked = get_marked()
@ -138,9 +140,10 @@ var getUnmarked = makeUnmarkedLister(
function(){ return _UNMARKED_CACHE }) function(){ return _UNMARKED_CACHE })
// XXX make this undefined tolerant -- sparse list compatibility...
var getMarkedGIDBefore = makeGIDBeforeGetterFromList( var getMarkedGIDBefore = makeGIDBeforeGetterFromList(
function(){ function(){
return MARKED return compactSparceList(MARKED)
}) })
@ -347,12 +350,12 @@ var toggleMark = makeMarkToggler(
// add marked image to list... // add marked image to list...
if(action == 'on'){ if(action == 'on'){
if(MARKED.indexOf(gid) == -1){ if(MARKED.indexOf(gid) == -1){
insertGIDToPosition(gid, MARKED) MARKED[DATA.order.indexOf(gid)] = gid
} }
// remove marked image from list... // remove marked image from list...
} else { } else {
MARKED.splice(MARKED.indexOf(gid), 1) delete MARKED[MARKED.indexOf(gid)]
} }
marksUpdated() marksUpdated()
@ -360,7 +363,7 @@ var toggleMark = makeMarkToggler(
function toggleAllMarks(action, mode){ function setAllMarks(action, mode){
action = action == null ? toggleMark('?') : action action = action == null ? toggleMark('?') : action
mode = mode == null ? 'ribbon' : mode mode = mode == null ? 'ribbon' : mode
@ -369,8 +372,7 @@ function toggleAllMarks(action, mode){
if(action == 'on'){ if(action == 'on'){
var _update = function(e){ var _update = function(e){
if(MARKED.indexOf(e) < 0){ if(MARKED.indexOf(e) < 0){
//insertGIDToPosition(e, MARKED) MARKED[DATA.order.indexOf(e)] = e
MARKED.push(e)
updated.push(e) updated.push(e)
} }
} }
@ -378,7 +380,7 @@ function toggleAllMarks(action, mode){
var _update = function(e){ var _update = function(e){
var i = MARKED.indexOf(e) var i = MARKED.indexOf(e)
if(i >= 0){ if(i >= 0){
MARKED.splice(i, 1) delete MARKED[i]
updated.push(e) updated.push(e)
} }
} }
@ -395,8 +397,6 @@ function toggleAllMarks(action, mode){
res.forEach(_update) res.forEach(_update)
MARKED = fastSortGIDsByOrder(MARKED)
updateImages(updated) updateImages(updated)
$('.viewer').trigger('togglingMarks', [updated, action]) $('.viewer').trigger('togglingMarks', [updated, action])
@ -411,7 +411,7 @@ function toggleAllMarks(action, mode){
// - 'all' // - 'all'
function removeImageMarks(mode){ function removeImageMarks(mode){
mode = mode == null ? 'ribbon' : mode mode = mode == null ? 'ribbon' : mode
var res = toggleAllMarks('off', mode) var res = setAllMarks('off', mode)
$('.viewer').trigger('removingMarks', [res, mode]) $('.viewer').trigger('removingMarks', [res, mode])
return res return res
} }
@ -419,7 +419,7 @@ function removeImageMarks(mode){
function markAll(mode){ function markAll(mode){
mode = mode == null ? 'ribbon' : mode mode = mode == null ? 'ribbon' : mode
var res = toggleAllMarks('on', mode) var res = setAllMarks('on', mode)
$('.viewer').trigger('addingMarks', [res, mode]) $('.viewer').trigger('addingMarks', [res, mode])
return res return res
} }
@ -435,14 +435,12 @@ function invertImageMarks(){
var i = MARKED.indexOf(e) var i = MARKED.indexOf(e)
if(i == -1){ if(i == -1){
on.push(e) on.push(e)
MARKED.push(e) MARKED[DATA.order.indexOf(e)] = e
//insertGIDToPosition(e, MARKED)
} else { } else {
off.push(e) off.push(e)
MARKED.splice(i, 1) delete MARKED[i]
} }
}) })
MARKED = fastSortGIDsByOrder(MARKED)
updateImages(ribbon) updateImages(ribbon)
$('.viewer') $('.viewer')
@ -477,10 +475,9 @@ function toggleMarkBlock(image){
} }
// do the toggle... // do the toggle...
if(state){ if(state){
//insertGIDToPosition(e, MARKED) MARKED[DATA.order.indexOf(e)] = e
MARKED.push(e)
} else { } else {
MARKED.splice(MARKED.indexOf(e), 1) delete MARKED[MARKED.indexOf(e)]
} }
updated.push(e) updated.push(e)
} }
@ -494,8 +491,6 @@ function toggleMarkBlock(image){
var right = ribbon.slice(i+1) var right = ribbon.slice(i+1)
$.each(right, _convert) $.each(right, _convert)
MARKED = fastSortGIDsByOrder(MARKED)
updateImages(updated) updateImages(updated)
$('.viewer') $('.viewer')
@ -593,10 +588,10 @@ function shiftMarkedImagesRight(){
// of makeNextFromListAction(..) for more info) // of makeNextFromListAction(..) for more info)
var nextMark = makeNextFromListAction( var nextMark = makeNextFromListAction(
getMarkedGIDBefore, getMarkedGIDBefore,
function(){ return MARKED }) function(){ return compactSparceList(MARKED) })
var prevMark = makePrevFromListAction( var prevMark = makePrevFromListAction(
getMarkedGIDBefore, getMarkedGIDBefore,
function(){ return MARKED }) function(){ return compactSparceList(MARKED) })
var nextUnmarked = makeNextFromListAction( var nextUnmarked = makeNextFromListAction(
@ -697,23 +692,7 @@ var loadFileMarks = makeFileLoader(
MARKED_FILE_PATTERN, MARKED_FILE_PATTERN,
[], [],
function(data){ function(data){
// set the MARKED... MARKED = makeSparceGIDList(data)
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)
}
}, },
'marksLoaded') 'marksLoaded')
@ -723,7 +702,7 @@ var saveFileMarks = makeFileSaver(
'Marks', 'Marks',
MARKED_FILE_DEFAULT, MARKED_FILE_DEFAULT,
function(){ function(){
return MARKED return compactSparceList(MARKED)
}) })
@ -768,11 +747,20 @@ function setupMarks(viewer){
}) })
}) })
.on('sortedImages', function(){ .on('sortedImages', function(){
MARKED = fastSortGIDsByOrder(MARKED) MARKED = makeSparceGIDList(MARKED)
marksUpdated() marksUpdated()
}) })
.on('horizontalShiftedImage', function(evt, gid, direction){ .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() marksUpdated()
} }
}) })