sams
Version:
Some Awsome Memory Scheduler.
298 lines (261 loc) • 8.44 kB
JavaScript
var cocktail = require('cocktail');
//Add Logger annotation.
var Logger = require('../annotations/Logger');
cocktail.use(Logger);
//Using Behavior class.
var Behavior = require('./Behavior');
var Page = require('./Page');
/*
* Adding this trait lets the constructor accept an object as parameter.
* Automaticaly, it will map the properties of the object with
* the properties defined as instance variables.
*/
//var Configurable = require('cocktail-trait-configurable');
/*
**********************************************************************
* This Memory defines Equals and Clone method. *
* This Memory allows to have the same element twice. *
**********************************************************************
*/
cocktail.mix({
//Define this file as a single class module exportable.
'@exports' : module,
'@as' : 'class',
//'@traits' : [Configurable],
//Set the logger and signature of this class.
'@logger' : [console, "Memory:"],
/*
* Instance variables of the class.
* Since we want them to be private, we'll define them in the constructor.
*/
// '@properties': {
// array: undefined,
// size: 0,
// used: 0
// },
/*
* Creates a memory with 'size' ammount of frames.
* The proper initialization of the properties must be here.
*/
constructor: function(size) {
this._size = size;
this._array = [];
this._used = 0;
this.log("Created with " + size + " frames.");
},
/*
* Return whether the memory is full or not.
*/
isFull: function() {
/*
if (this._used === this._size) {
return true;
}
return false;
*/
return this.getFreeFrame() === -1;
},
/*
* Short circuit search for a free frame.
* Returns the index of a free frame if there is one.
* Otherwise return -1.
*/
getFreeFrame: function() {
//NOTE: changed the way finished proceses are handled.
// now, they are completly erased from the algorithm's view.
// Now it's memory's responsibility to check for finished proceses.
// //Ensure there is space before searching for it.
// if(this.isFull()) {
// return -1;
// }
//Move all initializations out of the loop.
var i = 0;
var array = this._array;
var length = this._size;
for (; i < length; i++) {
if (array[i] === undefined || Page.empty().equals(array[i])) {
return i;
}
}
return -1;
},
/*
* Look for the frame that contains the element.
* If the element isn't found, return -1.
* This method is identical to Queue.js indexOf.
*/
getFrameOf: function(element) {
//Move all asignations out of the loop.
var i = 0;
var array = this._array;
var length = array.length;
//Ask for the supported comparing method of the element.
var areEquals = Behavior.ComparingMethod(element);
for(; i< length; i++) {
if(areEquals(element, array[i])) {
return i;
}
}
return -1
},
/*
* Returns whether an element is already in the Memory.
*/
contains: function(element) {
if(this.getFrameOf(element) === -1) {
return false;
}
return true;
},
/*
* Returns a reference to the frame in the position of the Memory.
* If the request ask for a frame out of bounds, return undefined.
*
* BEWARE THAT THIS METHOD DOESN'T DIFFERENCE BETWEEN ACCESSING TO
* AN OUT OF BOUND POSITION OR ACCESING TO AN UNDEFINED FRAME.
*
* **Should it return a copy(C++ const.)?**
*/
at: function(position) {
//Check if the position is out of the array.
if(position < 0 || position >= this._size) {
this.log("Access to the position " + position + " out of bounds. Access denied.");
return undefined;
}
return this._array[position];
},
/*
* Add an element to a certain position of the Memory.
* If the position is out of bounds, return false.
* Return true when the operation is completed succesfully.
*/
atPut: function(position, element) {
//Check if the position is out of the array.
if(position < 0 || position >= this._size) {
this.log("Access to the position " + position + " out of bounds. Access denied.");
return false;
}
//Check if the element is not defined or is empty
if(!element || (typeof element === 'object' && !Object.keys(element).length)) {
this.log("Element should be not undefined or empty");
return false;
}
//Check if the position was free and add 1 to the used acumulator.
//Log all replaced elements.
if(this.at(position) === undefined) {
this._used = this._used + 1;
} else {
this.log(this.at(position).toString() + " at frame[" + position + "] being replaced.");
}
//Finally add the element to the Memory and log it.
this._array[position] = element;
this.log(element.toString() + " added to the frame[" + position + "].");
return true;
},
/*
* Determines the comparing method used in the Memory objects.
* This is a deep equivalency comparission.
*/
equals: function(obj) {
//For performance improvement, check if they hold the same reference.
if (!obj) {
return false;
}
if(this === obj) {
return true;
}
/*
* Check that the objects are the same class,
* were instantiated with the same params and
* if the internal state of the objects at this given time is "similar".
*/
if(this.constructor !== obj.constructor || this._size !== obj._size || this._used !== obj._used) {
return false;
}
//Then it's time for a deep check.
//Move all asignations out of the loop.
var i = 0;
var myArray = this._array;
var herArray = obj._array;
var length = myArray.length;
/*
* Don't use a forEach loop beacuse it skips undefined values.
* We want to check for those too.
* Also we want to stop in
*/
for(; i < length; i++) {
var myElement = myArray[i];
var herElement = herArray[i];
/*
* If self holds a reference to obj and
* at the same time obj holds a reference to self,
* That would cause an infinite loop so we skip it.
*/
if(myElement !== obj || herElement !== this) {
/*
* Use Behavior to ask for the comparing method of myElement.
* Then call the function with myElement and herElement.
*/
if(!Behavior.ComparingMethod(myElement)(myElement, herElement)) {
return false;
}
}
}
//After iterating all the elements we know for sure that the objects are equivalents.
return true;
},
/*
* Generate a new object equivalent to this one.
* Tries to do a deep clone.
*/
clone: function() {
this.log("---Start of Clonation.---");
//Using Memory class.
var Memory = require('./Memory');
var aux = new Memory(this._size);
var myArray = this._array;
myArray.forEach(function(element, index) {
//Check that the Memory holds a reference to itself.
//Then add a reference to the new object.
if(element == this) {
aux.atPut(index, aux);
} else {
/*
* Use Behavior to ask for the cloning method of element.
* Then call the function with element and assign it to the new Memory.
*/
aux.atPut(index, Behavior.CloningMethod(element)(element));
}
}, this);
this.log("---End of Clonation.---\n");
return aux;
},
forEach: function(exec, that) {
var myArray = this._array;
if ( typeof exec !== 'function')
throw new Error('First param must be a function')
var context = {
memory: this,
caller: that
};
if(that) {
myArray.forEach(function(element, index) {
//Use the contex passed by the caller in the execution of the function.
exec.call(context.caller, element, index, context.memory);
}, context);
} else {
//If no contex was especified use a simple forEach.
myArray.forEach(function(element, index) {
exec(element, index, context.memory);
}, context);
}
},
clearFinished: function() {
for (var i = 0; i < this._size; i++) {
var page = this._array[i];
if (page === undefined || page.isFinished()) {
this.atPut(i, Page.empty());
}
}
}
});