2019-08-31 04:07:25 +05:00
|
|
|
const GAP = 2 ** 14;
|
|
|
|
const MIN_GAP = 0.125;
|
2019-10-10 02:51:54 +05:00
|
|
|
const MAX_POSITION = 2 ** 50;
|
2019-08-31 04:07:25 +05:00
|
|
|
|
|
|
|
const findBeginnings = positions => {
|
|
|
|
positions.unshift(0);
|
|
|
|
|
|
|
|
let prevPosition = positions.pop();
|
|
|
|
const beginnings = [prevPosition];
|
|
|
|
|
|
|
|
_.forEachRight(positions, position => {
|
|
|
|
if (prevPosition - MIN_GAP >= position) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
prevPosition = position;
|
|
|
|
beginnings.unshift(prevPosition);
|
|
|
|
});
|
|
|
|
|
|
|
|
return beginnings;
|
|
|
|
};
|
|
|
|
|
|
|
|
const getRepositionsMap = positions => {
|
|
|
|
const repositionsMap = {};
|
|
|
|
|
|
|
|
if (positions.length <= 1) {
|
|
|
|
if (!_.isUndefined(positions[0]) && positions[0] > MAX_POSITION) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return repositionsMap;
|
|
|
|
}
|
|
|
|
|
|
|
|
let prevPosition = positions.shift();
|
|
|
|
|
|
|
|
for (let i = 0; i < positions.length; i++) {
|
|
|
|
const position = positions[i];
|
|
|
|
const nextPosition = positions[i + 1];
|
|
|
|
|
|
|
|
if (prevPosition + MIN_GAP <= position) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
!_.isUndefined(nextPosition) &&
|
|
|
|
prevPosition + MIN_GAP * 2 <= nextPosition
|
|
|
|
) {
|
|
|
|
(repositionsMap[position] || (repositionsMap[position] = [])).push(
|
|
|
|
prevPosition + (nextPosition - prevPosition) / 2
|
|
|
|
);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
prevPosition += GAP;
|
|
|
|
|
|
|
|
if (prevPosition > MAX_POSITION) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
(repositionsMap[position] || (repositionsMap[position] = [])).push(
|
|
|
|
prevPosition
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return repositionsMap;
|
|
|
|
};
|
|
|
|
|
|
|
|
const getFullRepositionsMap = positions => {
|
|
|
|
const repositionsMap = {};
|
|
|
|
|
|
|
|
_.forEach(positions, (position, index) => {
|
|
|
|
(repositionsMap[position] || (repositionsMap[position] = [])).push(
|
|
|
|
GAP * (index + 1)
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
return repositionsMap;
|
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
sync: true,
|
|
|
|
|
|
|
|
inputs: {
|
|
|
|
position: {
|
|
|
|
type: 'number',
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
records: {
|
|
|
|
type: 'ref',
|
|
|
|
required: true
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
fn: function(inputs, exits) {
|
|
|
|
const lowers = [];
|
|
|
|
const uppers = [];
|
|
|
|
|
|
|
|
inputs.records.forEach(({ position }) => {
|
|
|
|
(position <= inputs.position ? lowers : uppers).push(position);
|
|
|
|
});
|
|
|
|
|
|
|
|
const beginnings = findBeginnings([...lowers, inputs.position]);
|
|
|
|
|
|
|
|
const repositionsMap =
|
|
|
|
getRepositionsMap([...beginnings, ...uppers]) ||
|
|
|
|
getFullRepositionsMap([...lowers, inputs.position, ...uppers]);
|
|
|
|
|
|
|
|
let position = repositionsMap[inputs.position]
|
|
|
|
? repositionsMap[inputs.position].pop()
|
|
|
|
: inputs.position;
|
|
|
|
|
|
|
|
const repositions = [];
|
|
|
|
|
|
|
|
_.forEachRight(inputs.records, ({ id, position }) => {
|
|
|
|
if (_.isEmpty(repositionsMap[position])) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
repositions.unshift({
|
|
|
|
id,
|
|
|
|
position: repositionsMap[position].pop()
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return exits.success({
|
|
|
|
position,
|
|
|
|
repositions
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|