mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 16:57:31 +01:00
[code] Cleaned Script and ScriptStore classes, created accordion.h
A Script object now contains its AutoImport marker, its name and its content. The ScripStore methods have better names and the optimization is cleaner. Change-Id: I1b21af2d23f1c9a34f984309512b0c01b2f1c320
This commit is contained in:
@@ -7,355 +7,138 @@ namespace Code {
|
||||
constexpr char ScriptStore::k_defaultScriptName[];
|
||||
|
||||
ScriptStore::ScriptStore() :
|
||||
m_numberOfScripts(0),
|
||||
m_lastEditedStringPosition(0)
|
||||
m_accordion(m_scriptData, k_scriptDataSize)
|
||||
{
|
||||
for (int i = 0; i<k_historySize; i ++) {
|
||||
m_history[i] = FreeSpaceMarker;
|
||||
}
|
||||
}
|
||||
|
||||
Script ScriptStore::editableScript(int i) {
|
||||
assert(i >= 0 && i < numberOfScripts());
|
||||
cleanAndMoveFreeSpaceAfterScriptContent(i);
|
||||
int beginningOfScriptContent = indexOfScriptContent(i);
|
||||
const Script ScriptStore::scriptAtIndex(int index, EditableZone zone) {
|
||||
assert(index >= 0 && index < numberOfScripts());
|
||||
size_t nameBufferSize = 0;
|
||||
size_t contentBufferSize = 0;
|
||||
int accordionIndex;
|
||||
|
||||
// Compute the size of the script, including the free space of m_history
|
||||
int sizeOfEditableScript = 0;
|
||||
for (int j=beginningOfScriptContent; j<k_historySize-1; j++) {
|
||||
if (m_history[j] == FreeSpaceMarker && m_history[j+1] != FreeSpaceMarker) {
|
||||
// Move the Free Space at the end of the correct string.
|
||||
switch (zone) {
|
||||
case EditableZone::None:
|
||||
break;
|
||||
case EditableZone::Name:
|
||||
accordionIndex = accordionIndexOfNameOfScriptAtIndex(index);
|
||||
nameBufferSize = m_accordion.sizeOfEditableBufferAtIndex(accordionIndex);
|
||||
break;
|
||||
case EditableZone::Content:
|
||||
accordionIndex = accordionIndexOfContentOfScriptAtIndex(index);
|
||||
contentBufferSize = m_accordion.sizeOfEditableBufferAtIndex(accordionIndex);
|
||||
break;
|
||||
}
|
||||
sizeOfEditableScript++;
|
||||
}
|
||||
return Script(&m_history[beginningOfScriptContent], sizeOfEditableScript);
|
||||
|
||||
// Compute the positions and lengths of the Script Marker, Name and Content.
|
||||
const char * marker = m_accordion.bufferAtIndex(accordionIndexOfMarkersOfScriptAtIndex(index));
|
||||
const char * name = m_accordion.bufferAtIndex(accordionIndexOfNameOfScriptAtIndex(index));
|
||||
if (nameBufferSize == 0) {
|
||||
nameBufferSize = strlen(name);
|
||||
}
|
||||
const char * content = m_accordion.bufferAtIndex(accordionIndexOfContentOfScriptAtIndex(index));
|
||||
if (contentBufferSize == 0) {
|
||||
contentBufferSize = strlen(content);
|
||||
}
|
||||
return Script(marker, name, nameBufferSize, content, contentBufferSize);
|
||||
}
|
||||
|
||||
Script ScriptStore::script(int i) {
|
||||
assert(i >= 0 && i < numberOfScripts());
|
||||
cleanFreeSpace();
|
||||
int beginningOfScriptContent = indexOfScriptContent(i);
|
||||
return Script(&m_history[beginningOfScriptContent], strlen(&m_history[beginningOfScriptContent]) + 1);
|
||||
}
|
||||
|
||||
Script ScriptStore::script(const char * name) {
|
||||
cleanFreeSpace();
|
||||
for (int i=0; i<numberOfScripts(); i++) {
|
||||
const char * nameScripti = nameOfScript(i);
|
||||
if (strcmp(nameScripti, name) == 0) {
|
||||
return script(i);
|
||||
const Script ScriptStore::scriptNamed(const char * name) {
|
||||
for (int i = 0; i < numberOfScripts(); i++) {
|
||||
int accordionIndex = accordionIndexOfNameOfScriptAtIndex(i);
|
||||
const char * currentScriptName = m_accordion.bufferAtIndex(accordionIndex);
|
||||
if (strcmp(currentScriptName, name) == 0) {
|
||||
return scriptAtIndex(i);
|
||||
}
|
||||
}
|
||||
return Script();
|
||||
}
|
||||
|
||||
char * ScriptStore::nameOfScript(int i) {
|
||||
cleanFreeSpace();
|
||||
return &m_history[indexOfScriptName(i)];
|
||||
int ScriptStore::numberOfScripts() {
|
||||
return (m_accordion.numberOfBuffers())/Script::NumberOfStringsPerScript;
|
||||
}
|
||||
|
||||
char * ScriptStore::editableNameOfScript(int i) {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
cleanAndMoveFreeSpaceAfterScriptName(i);
|
||||
return &m_history[indexOfScriptName(i)];
|
||||
}
|
||||
|
||||
int ScriptStore::sizeOfEditableNameOfScript(int i) {
|
||||
// Compute the size of the name of the script, including the free space of m_history
|
||||
int sizeOfEditableNameScript = 0;
|
||||
for (int j=indexOfScriptName(i); j<k_historySize-1; j++) {
|
||||
if (m_history[j] == FreeSpaceMarker && m_history[j+1] != FreeSpaceMarker) {
|
||||
bool ScriptStore::addNewScript(DefaultScript defaultScript) {
|
||||
const char autoImportationString[2] = {Script::DefaultAutoImportationMarker, 0};
|
||||
if (!m_accordion.appendBuffer(autoImportationString)) {
|
||||
return false;
|
||||
}
|
||||
const char * name = nullptr;
|
||||
switch (defaultScript) {
|
||||
case DefaultScript::Empty:
|
||||
name = k_defaultScriptName;
|
||||
break;
|
||||
case DefaultScript::Mandelbrot:
|
||||
name = "mandelbrot.py";
|
||||
break;
|
||||
case DefaultScript::Factorial:
|
||||
name = "factorial.py";
|
||||
break;
|
||||
}
|
||||
sizeOfEditableNameScript++;
|
||||
}
|
||||
return sizeOfEditableNameScript;
|
||||
}
|
||||
|
||||
int ScriptStore::numberOfScripts() const {
|
||||
return m_numberOfScripts;
|
||||
}
|
||||
|
||||
bool ScriptStore::addNewScript() {
|
||||
int sizeFreeSpace = sizeOfFreeSpace();
|
||||
if (sizeFreeSpace < 4) {
|
||||
if (!m_accordion.appendBuffer(name)) {
|
||||
// Delete the Auto Importation Marker
|
||||
m_accordion.deleteLastBuffer();
|
||||
return false;
|
||||
}
|
||||
cleanAndMoveFreeSpaceAfterScriptContent(numberOfScripts()-1);
|
||||
int beginningNewScript = indexOfFirstFreeSpaceMarker();
|
||||
m_history[beginningNewScript] = AutoImportationMarker;
|
||||
if (copyName(beginningNewScript + 1)) {
|
||||
if (copyEmptyScriptOnFreeSpace()) {
|
||||
m_numberOfScripts++;
|
||||
m_lastEditedStringPosition = indexOfScriptContent(numberOfScripts()-1);
|
||||
return true;
|
||||
}
|
||||
bool didCopy = false;
|
||||
switch (defaultScript) {
|
||||
case DefaultScript::Empty:
|
||||
didCopy = copyEmptyScriptOnFreeSpace();
|
||||
break;
|
||||
case DefaultScript::Mandelbrot:
|
||||
didCopy = copyMandelbrotScriptOnFreeSpace();
|
||||
break;
|
||||
case DefaultScript::Factorial:
|
||||
didCopy = copyFactorialScriptOnFreeSpace();
|
||||
break;
|
||||
}
|
||||
for (int i = beginningNewScript; i<k_historySize; i++) {
|
||||
m_history[i] = FreeSpaceMarker;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptStore::addFactorialScript() {
|
||||
int sizeFreeSpace = sizeOfFreeSpace();
|
||||
if (sizeFreeSpace < 4) {
|
||||
return false;
|
||||
}
|
||||
cleanAndMoveFreeSpaceAfterScriptContent(numberOfScripts()-1);
|
||||
int beginningNewScript = indexOfFirstFreeSpaceMarker();
|
||||
m_history[beginningNewScript] = AutoImportationMarker;
|
||||
if (copyName(beginningNewScript + 1, "factorial.py")) {
|
||||
if (copyFactorialScriptOnFreeSpace()) {
|
||||
m_numberOfScripts++;
|
||||
m_lastEditedStringPosition = indexOfScriptContent(numberOfScripts()-1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i = beginningNewScript; i<k_historySize; i++) {
|
||||
m_history[i] = FreeSpaceMarker;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptStore::addMandelbrotScript() {
|
||||
int sizeFreeSpace = sizeOfFreeSpace();
|
||||
if (sizeFreeSpace < 5) {
|
||||
return false;
|
||||
}
|
||||
cleanAndMoveFreeSpaceAfterScriptContent(numberOfScripts()-1);
|
||||
int beginningNewScript = indexOfFirstFreeSpaceMarker();
|
||||
m_history[beginningNewScript] = AutoImportationMarker;
|
||||
if (copyName(beginningNewScript + 1, "mandelbrot.py")) {
|
||||
if (copyMandelbrotScriptOnFreeSpace()) {
|
||||
m_numberOfScripts++;
|
||||
m_lastEditedStringPosition = indexOfScriptContent(numberOfScripts()-1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (int i = beginningNewScript; i<k_historySize; i++) {
|
||||
m_history[i] = FreeSpaceMarker;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptStore::renameScript(int i, const char * newName) {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
cleanAndMoveFreeSpaceAfterScriptName(i);
|
||||
if (strlen(newName) <= sizeOfEditableNameOfScript(i)) {
|
||||
copyName(indexOfScriptName(i), newName);
|
||||
if (didCopy) {
|
||||
return true;
|
||||
}
|
||||
// Delete the Auto Importation Marker and the Name Of the Script
|
||||
m_accordion.deleteLastBuffer();
|
||||
m_accordion.deleteLastBuffer();
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptStore::deleteScript(int i) {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
cleanAndMoveFreeSpaceAfterScriptContent(i);
|
||||
int indexOfCharToDelete = indexOfScript(i);
|
||||
while (m_history[indexOfCharToDelete] != FreeSpaceMarker && indexOfCharToDelete < k_historySize) {
|
||||
m_history[indexOfCharToDelete] = FreeSpaceMarker;
|
||||
indexOfCharToDelete++;
|
||||
}
|
||||
m_numberOfScripts--;
|
||||
bool ScriptStore::renameScriptAtIndex(int index, const char * newName) {
|
||||
assert (index >= 0 && index < numberOfScripts());
|
||||
int accordionIndex = accordionIndexOfNameOfScriptAtIndex(index);
|
||||
return m_accordion.replaceBufferAtIndex(accordionIndex, newName);
|
||||
}
|
||||
|
||||
void ScriptStore::deleteAll() {
|
||||
for (int i = 0; i<k_historySize; i++){
|
||||
m_history[i] = FreeSpaceMarker;
|
||||
}
|
||||
m_numberOfScripts = 0;
|
||||
void ScriptStore::deleteScriptAtIndex(int index) {
|
||||
assert (index >= 0 && index < numberOfScripts());
|
||||
int accordionIndex = accordionIndexOfContentOfScriptAtIndex(index);
|
||||
// We delete in reverse order because we want the indexes to stay true.
|
||||
m_accordion.deleteBufferAtIndex(accordionIndex);
|
||||
m_accordion.deleteBufferAtIndex(accordionIndex-1);
|
||||
m_accordion.deleteBufferAtIndex(accordionIndex-2);
|
||||
}
|
||||
|
||||
void ScriptStore::deleteAllScripts() {
|
||||
m_accordion.deleteAll();
|
||||
}
|
||||
|
||||
const char * ScriptStore::contentOfScript(const char * name) {
|
||||
int filenameIndex = indexBeginningFilename(name);
|
||||
const char * filename = &name[filenameIndex];
|
||||
return script(filename).readOnlyContent();
|
||||
Script script = scriptNamed(name);
|
||||
if (script.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
return script.content();
|
||||
}
|
||||
|
||||
bool ScriptStore::copyName(int position, const char * name) {
|
||||
if (name) {
|
||||
int len = strlen(name);
|
||||
if (len > sizeOfFreeSpace() - 1) { // We keep at keast one free char.
|
||||
return false;
|
||||
}
|
||||
memcpy(&m_history[position], name, len+1);
|
||||
return true;
|
||||
} else {
|
||||
int len = strlen(k_defaultScriptName);
|
||||
if (len > sizeOfFreeSpace() - 1) { // We keep at keast one free char.
|
||||
return false;
|
||||
}
|
||||
memcpy(&m_history[position], k_defaultScriptName, len+1);
|
||||
return true;
|
||||
|
||||
}
|
||||
int ScriptStore::accordionIndexOfMarkersOfScriptAtIndex(int index) const {
|
||||
return index * Script::NumberOfStringsPerScript;
|
||||
}
|
||||
|
||||
int ScriptStore::indexOfScript(int i) const {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
int currentScriptNumber = 0;
|
||||
int beginningOfScript = 0;
|
||||
while (m_history[beginningOfScript] == FreeSpaceMarker && beginningOfScript < k_historySize) {
|
||||
beginningOfScript++;
|
||||
}
|
||||
if (i == 0) {
|
||||
return beginningOfScript;
|
||||
}
|
||||
bool goingThroughName = true;
|
||||
for (int j=beginningOfScript; j<k_historySize; j++) {
|
||||
if (m_history[j] == 0) {
|
||||
if (goingThroughName) {
|
||||
goingThroughName = false;
|
||||
} else {
|
||||
goingThroughName = true;
|
||||
currentScriptNumber++;
|
||||
if (currentScriptNumber == i) {
|
||||
j++;
|
||||
while (m_history[j] == FreeSpaceMarker && j < beginningOfScript) {
|
||||
j++;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return 0;
|
||||
int ScriptStore::accordionIndexOfNameOfScriptAtIndex(int index) const {
|
||||
return index * Script::NumberOfStringsPerScript + 1;
|
||||
}
|
||||
|
||||
int ScriptStore::indexOfScriptName(int i) const {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
return indexOfScript(i)+1;
|
||||
}
|
||||
|
||||
|
||||
int ScriptStore::indexOfScriptContent(int i) const {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
int indexOfScriptContent = indexOfScriptName(i);
|
||||
while (m_history[indexOfScriptContent] != 0 && indexOfScriptContent<k_historySize) {
|
||||
indexOfScriptContent++;
|
||||
}
|
||||
indexOfScriptContent++;
|
||||
return indexOfScriptContent;
|
||||
}
|
||||
|
||||
int ScriptStore::lastIndexOfScript(int i) const {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
int indexOfPrgm = indexOfScriptContent(i);
|
||||
int lastIndexOfScript = indexOfPrgm + strlen(&m_history[indexOfPrgm]);
|
||||
return lastIndexOfScript;
|
||||
}
|
||||
|
||||
int ScriptStore::indexOfFirstFreeSpaceMarker() const {
|
||||
for (int i=0; i<k_historySize; i++) {
|
||||
if (m_history[i] == FreeSpaceMarker) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScriptStore::sizeOfFreeSpace() const {
|
||||
int sizeOfFreeSpace = 0;
|
||||
for (int i=0; i<k_historySize; i++) {
|
||||
if (m_history[i] == FreeSpaceMarker) {
|
||||
sizeOfFreeSpace++;
|
||||
} else {
|
||||
if (sizeOfFreeSpace > 0) {
|
||||
return sizeOfFreeSpace;
|
||||
}
|
||||
}
|
||||
}
|
||||
return sizeOfFreeSpace;
|
||||
}
|
||||
|
||||
void ScriptStore::cleanFreeSpace() {
|
||||
if (m_history[m_lastEditedStringPosition] == FreeSpaceMarker
|
||||
|| m_history[m_lastEditedStringPosition] == AutoImportationMarker
|
||||
|| m_history[m_lastEditedStringPosition] == NoAutoImportationMarker)
|
||||
{
|
||||
return;
|
||||
}
|
||||
int indexOfCharToChangeIntoFreeSpaceMarker = m_lastEditedStringPosition
|
||||
+ strlen (&m_history[m_lastEditedStringPosition]) + 1;
|
||||
while (m_history[indexOfCharToChangeIntoFreeSpaceMarker] != FreeSpaceMarker
|
||||
&& indexOfCharToChangeIntoFreeSpaceMarker<k_historySize)
|
||||
{
|
||||
m_history[indexOfCharToChangeIntoFreeSpaceMarker] = FreeSpaceMarker;
|
||||
indexOfCharToChangeIntoFreeSpaceMarker ++;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptStore::moveFreeSpaceAfterScriptContent(int i) {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
int indexOfFreeSpace = indexOfFirstFreeSpaceMarker();
|
||||
int newFreeSpacePosition = lastIndexOfScript(i) + 1;
|
||||
if (indexOfFreeSpace < newFreeSpacePosition) {
|
||||
newFreeSpacePosition -= sizeOfFreeSpace();
|
||||
}
|
||||
moveFreeSpaceAtPosition(newFreeSpacePosition);
|
||||
}
|
||||
|
||||
void ScriptStore::moveFreeSpaceAfterScriptName(int i) {
|
||||
assert (i >= 0 && i < numberOfScripts());
|
||||
int newFreeSpacePosition = indexOfScriptName(i);
|
||||
while (m_history[newFreeSpacePosition] != 0 && newFreeSpacePosition < k_historySize) {
|
||||
newFreeSpacePosition++;
|
||||
}
|
||||
newFreeSpacePosition++;
|
||||
moveFreeSpaceAtPosition(newFreeSpacePosition);
|
||||
}
|
||||
|
||||
void ScriptStore::moveFreeSpaceAtPosition(int i) {
|
||||
assert (i >= 0 && i < k_historySize);
|
||||
int indexOfFreeSpace = indexOfFirstFreeSpaceMarker();
|
||||
if (indexOfFreeSpace != i){
|
||||
|
||||
// First, move the chars that would be overriden by the free space.
|
||||
int freeSpaceSize = sizeOfFreeSpace();
|
||||
int len, src, dst;
|
||||
// The indexes depend on the relative positions of the free space and the
|
||||
// new destination.
|
||||
if (indexOfFreeSpace > i) {
|
||||
len = indexOfFreeSpace - i;
|
||||
src = i;
|
||||
dst = i + freeSpaceSize;
|
||||
} else {
|
||||
src = indexOfFreeSpace + freeSpaceSize;
|
||||
len = i + freeSpaceSize - src;
|
||||
dst = indexOfFreeSpace;
|
||||
}
|
||||
memmove(&m_history[dst], &m_history[src], len);
|
||||
|
||||
// Then move the free space.
|
||||
for (int j = i ; j<i+freeSpaceSize; j++) {
|
||||
m_history[j] = FreeSpaceMarker;
|
||||
}
|
||||
}
|
||||
|
||||
m_lastEditedStringPosition = i-1;
|
||||
while (m_lastEditedStringPosition > 0
|
||||
&& m_history[m_lastEditedStringPosition-1] != 0
|
||||
&& m_history[m_lastEditedStringPosition-1] != AutoImportationMarker
|
||||
&& m_history[m_lastEditedStringPosition-1] != NoAutoImportationMarker)
|
||||
{
|
||||
m_lastEditedStringPosition--;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptStore::cleanAndMoveFreeSpaceAfterScriptContent(int i) {
|
||||
if (i >= 0 && i<numberOfScripts()){
|
||||
cleanFreeSpace();
|
||||
moveFreeSpaceAfterScriptContent(i);
|
||||
}
|
||||
}
|
||||
void ScriptStore::cleanAndMoveFreeSpaceAfterScriptName(int i) {
|
||||
if (i >= 0 && i<numberOfScripts()){
|
||||
cleanFreeSpace();
|
||||
moveFreeSpaceAfterScriptName(i);
|
||||
}
|
||||
int ScriptStore::accordionIndexOfContentOfScriptAtIndex(int index) const {
|
||||
return index * Script::NumberOfStringsPerScript + 2;
|
||||
}
|
||||
|
||||
bool ScriptStore::copyMandelbrotScriptOnFreeSpace() {
|
||||
@@ -383,47 +166,21 @@ for x in range(320):
|
||||
# Draw a pixel colored in 'col' at position (x,y)
|
||||
kandinsky.set_pixel(x,y,col))";
|
||||
|
||||
int len = strlen(script);
|
||||
if (len + 1 > sizeOfFreeSpace() - 1) { // We keep at keast one free char.
|
||||
return false;
|
||||
}
|
||||
memcpy(&m_history[indexOfFirstFreeSpaceMarker()], script, len+1);
|
||||
return true;
|
||||
return m_accordion.appendBuffer(script);
|
||||
}
|
||||
|
||||
bool ScriptStore::copyFactorialScriptOnFreeSpace() {
|
||||
const char script[] = R"(def factorial(n):
|
||||
if n == 0:
|
||||
return 1
|
||||
else:
|
||||
return n * factorial(n-1)
|
||||
)";
|
||||
return n * factorial(n-1))";
|
||||
|
||||
int len = strlen(script);
|
||||
if (len + 1 > sizeOfFreeSpace() - 1) { // We keep at keast one free char.
|
||||
return false;
|
||||
}
|
||||
memcpy(&m_history[indexOfFirstFreeSpaceMarker()], script, len+1);
|
||||
return true;
|
||||
return m_accordion.appendBuffer(script);
|
||||
}
|
||||
|
||||
bool ScriptStore::copyEmptyScriptOnFreeSpace() {
|
||||
const char script[] = "\0";
|
||||
|
||||
int len = 1;
|
||||
if (len > sizeOfFreeSpace() - 1) { // We keep at keast one free char.
|
||||
return false;
|
||||
}
|
||||
memcpy(&m_history[indexOfFirstFreeSpaceMarker()], script, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
int ScriptStore::indexBeginningFilename(const char * path) {
|
||||
int beginningFilename = strlen(path)-1;
|
||||
while (beginningFilename > 0 && path[beginningFilename - 1] != '\\') {
|
||||
beginningFilename--;
|
||||
}
|
||||
return beginningFilename;
|
||||
return m_accordion.appendBuffer(script);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user