[code] Avoid dynamic allocation and useless string copy by keeping the

importation status flag in the areaBuffer
This commit is contained in:
Émilie Feral
2018-09-11 16:21:35 +02:00
parent db3cd16128
commit 79740e72b0
9 changed files with 25 additions and 45 deletions

View File

@@ -57,9 +57,10 @@ void App::Snapshot::setOpt(const char * name, char * value) {
}
*separator = 0;
const char * scriptName = value;
const char * scriptContent = separator+1;
const char * scriptContent = separator;
Code::ScriptTemplate script(scriptName, scriptContent);
m_scriptStore.addScriptFromTemplate(&script);
m_scriptStore.scriptNamed(scriptName).toggleImportationStatus(); // set Importation Status to 1
return;
}
if (strcmp(name, "lock-on-console") == 0) {

View File

@@ -11,33 +11,26 @@ namespace Code {
EditorController::EditorController(MenuController * menuController) :
ViewController(nullptr),
m_editorView(this),
m_areaBuffer(nullptr),
m_script(Ion::Storage::Record()),
m_menuController(menuController)
{
m_editorView.setTextAreaDelegate(this);
}
EditorController::~EditorController() {
delete m_areaBuffer;
m_areaBuffer = nullptr;
}
void EditorController::setScript(Script script) {
m_script = script;
const char * scriptBody = m_script.readContent();
size_t scriptBodySize = strlen(scriptBody)+1;
size_t availableScriptSize = scriptBodySize + Ion::Storage::sharedStorage()->availableSize();
assert(m_areaBuffer == nullptr);
m_areaBuffer = new char[availableScriptSize];
strlcpy(m_areaBuffer, scriptBody, scriptBodySize);
m_editorView.setText(m_areaBuffer, availableScriptSize);
Script::Data scriptData = m_script.value();
size_t availableScriptSize = scriptData.size + Ion::Storage::sharedStorage()->availableSize();
assert(sizeof(m_areaBuffer) >= availableScriptSize);
strlcpy(m_areaBuffer, (const char *)scriptData.buffer, scriptData.size);
m_editorView.setText(m_areaBuffer+1, availableScriptSize-1); // 1 char is taken by the importation status flag
}
// TODO: this should be done in textAreaDidFinishEditing maybe??
bool EditorController::handleEvent(Ion::Events::Event event) {
if (event == Ion::Events::OK || event == Ion::Events::Back || event == Ion::Events::Home) {
Script::ErrorStatus err = m_script.writeContent(m_areaBuffer, strlen(m_areaBuffer)+1);
size_t sizeOfValue = strlen(m_areaBuffer+1)+1+1; // size of scriptContent + size of importation status
Script::ErrorStatus err = m_script.setValue({.buffer=m_areaBuffer, .size=sizeOfValue});
if (err == Script::ErrorStatus::NotEnoughSpaceAvailable || err == Script::ErrorStatus::RecordDoesNotExist) {
assert(false); // This should not happen as we set the text area according to the available space in the Kallax
} else {
@@ -59,8 +52,6 @@ void EditorController::viewWillAppear() {
void EditorController::viewDidDisappear() {
m_menuController->scriptContentEditionDidFinish();
delete[] m_areaBuffer;
m_areaBuffer = nullptr;
m_editorView.unloadSyntaxHighlighter();
}

View File

@@ -13,7 +13,6 @@ class ScriptParameterController;
class EditorController : public ViewController, public TextAreaDelegate {
public:
EditorController(MenuController * menuController);
~EditorController();
void setScript(Script script);
/* ViewController */
@@ -32,7 +31,10 @@ private:
static constexpr int k_indentationSpacesNumber = 2;
StackViewController * stackController();
EditorView m_editorView;
char * m_areaBuffer;
/* m_areaBuffer first character is dedicated to the importation status.
* Thereby, we avoid wasteful copy while adding the Script to the storage
* (in order to add the importation status char before the areaBuffer). */
char m_areaBuffer[Ion::Storage::k_storageSize]; // this could be slightly optimize
Script m_script;
MenuController * m_menuController;
};

View File

@@ -25,14 +25,4 @@ const char * Script::readContent() const {
return (const char *)d.buffer+k_importationStatusSize;
}
Ion::Storage::Record::ErrorStatus Script::writeContent(const char * data, size_t size) {
// TODO: could we avoid this useless allocation?
char * buffer = new char[size+k_importationStatusSize];
strlcpy(buffer+1, data, size);
buffer[0] = importationStatus() ? 1 : 0;
ErrorStatus e = setValue({.buffer= buffer, .size = size+k_importationStatusSize});
delete[] buffer;
return e;
}
}

View File

@@ -16,7 +16,6 @@ public:
void toggleImportationStatus();
const char * readContent() const;
ErrorStatus writeContent(const char * data, size_t size);
constexpr static size_t k_importationStatusSize = 1;
};

View File

@@ -120,13 +120,9 @@ const char * ScriptStore::contentOfScript(const char * name) {
}
Script::ErrorStatus ScriptStore::addScriptFromTemplate(const ScriptTemplate * scriptTemplate) {
size_t scriptSize = strlen(scriptTemplate->content())+1;
char * body = new char[scriptSize+Script::k_importationStatusSize];
body[0] = 1;
strlcpy(body+Script::k_importationStatusSize, scriptTemplate->content(), scriptSize);
Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecord(scriptTemplate->name(), body, scriptSize+Script::k_importationStatusSize);
size_t valueSize = strlen(scriptTemplate->content())+1+1;// scriptcontent size + 1 char for the importation status
Script::ErrorStatus err = Ion::Storage::sharedStorage()->createRecord(scriptTemplate->name(), scriptTemplate->value(), valueSize);
assert(err != Script::ErrorStatus::NonCompliantName);
delete[] body;
return err;
}

View File

@@ -2,16 +2,16 @@
namespace Code {
constexpr ScriptTemplate emptyScriptTemplate(".py", R"(from math import *
constexpr ScriptTemplate emptyScriptTemplate(".py", "\x01" R"(from math import *
)");
constexpr ScriptTemplate factorialScriptTemplate("factorial.py", R"(def factorial(n):
constexpr ScriptTemplate factorialScriptTemplate("factorial.py", "\x01" R"(def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1))");
constexpr ScriptTemplate fibonacciScriptTemplate("fibonacci.py", R"(def fibo(n):
constexpr ScriptTemplate fibonacciScriptTemplate("fibonacci.py", "\x01" R"(def fibo(n):
a=0
b=1
for i in range(1,n+1):
@@ -27,7 +27,7 @@ def fibo2(n):
return 1
return fibo2(n-1)+fibo2(n-2))");
constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", R"(# This script draws a Mandelbrot fractal set
constexpr ScriptTemplate mandelbrotScriptTemplate("mandelbrot.py", "\x01" R"(# This script draws a Mandelbrot fractal set
# N_iteration: degree of precision
import kandinsky
def mandelbrot(N_iteration):
@@ -47,7 +47,7 @@ def mandelbrot(N_iteration):
# Draw a pixel colored in 'col' at position (x,y)
kandinsky.set_pixel(x,y,col))");
constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", R"(from math import *
constexpr ScriptTemplate polynomialScriptTemplate("polynomial.py", "\x01" R"(from math import *
# roots(a,b,c) computes the solutions of the equation a*x**2+b*x+c=0
def roots(a,b,c):
delta = b*b-4*a*c

View File

@@ -5,17 +5,18 @@ namespace Code {
class ScriptTemplate {
public:
constexpr ScriptTemplate(const char * name, const char * content) : m_name(name), m_content(content) {}
constexpr ScriptTemplate(const char * name, const char * value) : m_name(name), m_value(value) {}
static const ScriptTemplate * Empty();
static const ScriptTemplate * Factorial();
static const ScriptTemplate * Fibonacci();
static const ScriptTemplate * Mandelbrot();
static const ScriptTemplate * Polynomial();
const char * name() const { return m_name; }
const char * content() const { return m_content; }
const char * content() const { return m_value+1; }
const char * value() const { return m_value; }
private:
const char * m_name;
const char * m_content;
const char * m_value; // hold the 'importation status' flag concatenate with the script content
};
}

View File

@@ -63,9 +63,9 @@ public:
Record recordWithExtensionAtIndex(const char * extension, int index);
Record recordNamed(const char * name);
typedef uint16_t record_size_t;
constexpr static size_t k_storageSize = 4096;
private:
constexpr static uint32_t Magic = 0xEE0BDDBA;
constexpr static size_t k_storageSize = 4096;
constexpr static size_t k_maxRecordSize = (1 << sizeof(record_size_t)*8);
/* Getters/Setters on recordID */