Files
Upsilon/apps/code/accordion.cpp
Léa Saviot 07c6acada4 [escher/code] Move Accordion from escher/ to apps/code/.
Change-Id: Id90ef9791f8c18bcdce497b8e20f060314f7b58b
2017-11-17 14:05:23 +01:00

229 lines
6.1 KiB
C++

#include "accordion.h"
#include <assert.h>
#include <string.h>
Accordion::Accordion(char * buffer, int bufferSize) :
m_historySize(bufferSize),
m_history(buffer),
m_numberOfBuffers(0),
m_startOfLastEditedBuffer(0)
{
for (int i = 0; i < m_historySize; i ++) {
m_history[i] = k_freeSpaceMarker;
}
}
int Accordion::numberOfBuffers() {
return m_numberOfBuffers;
}
const char * Accordion::bufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
int startOfBuffer = startOfBufferAtIndex(index);
return &m_history[startOfBuffer];
}
char * Accordion::editableBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
moveFreeSpaceAtEndOfBufferAtIndex(index);
int startOfBuffer = startOfBufferAtIndex(index);
return &m_history[startOfBuffer];
}
int Accordion::sizeOfEditableBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
moveFreeSpaceAtEndOfBufferAtIndex(index);
int length = 0;
for (int i = startOfBufferAtIndex(index); i < m_historySize-1; i++) {
if (m_history[i] == k_freeSpaceMarker && m_history[i+1] != k_freeSpaceMarker) {
break;
}
length++;
// We do not count one Free Space Marker, in order to always have at a
// Free Space of sizeat least one.
}
return length;
}
bool Accordion::appendBuffer(const char * buffer) {
cleanFreeSpace();
moveFreeSpaceAtEndOfHistory();
int len = strlen(buffer);
if (len + 1 > freeSpaceSize() - 1) { // We keep at keast one Free char.
return false;
}
m_startOfLastEditedBuffer = startOfFreeSpace();
memcpy(&m_history[m_startOfLastEditedBuffer], buffer, len+1);
m_numberOfBuffers++;
return true;
}
bool Accordion::replaceBufferAtIndex(int index, const char * buffer) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
int len = strlen(buffer);
if (len < sizeOfEditableBufferAtIndex(index)) {
int startOfOldBuffer = startOfBufferAtIndex(index);
memcpy(&m_history[startOfOldBuffer], buffer, len+1);
m_startOfLastEditedBuffer = startOfOldBuffer;
return true;
}
return false;
}
void Accordion::deleteBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
moveFreeSpaceAtEndOfBufferAtIndex(index);
int i = startOfBufferAtIndex(index);
while (i < m_historySize && m_history[i] != k_freeSpaceMarker) {
m_history[i] = k_freeSpaceMarker;
i++;
}
m_numberOfBuffers--;
}
void Accordion::deleteLastBuffer() {
cleanFreeSpace();
if (m_numberOfBuffers > 0) {
deleteBufferAtIndex(m_numberOfBuffers-1);
}
}
void Accordion::deleteAll() {
cleanFreeSpace();
for (int i = 0; i < m_historySize; i++){
m_history[i] = k_freeSpaceMarker;
}
m_numberOfBuffers = 0;
}
int Accordion::freeSpaceSize() {
cleanFreeSpace();
int sizeOfFreeSpace = 0;
int freeSpaceStart = startOfFreeSpace();
for (int i = freeSpaceStart; i < m_historySize; i++) {
if (m_history[i] == k_freeSpaceMarker) {
sizeOfFreeSpace++;
} else {
return sizeOfFreeSpace;
}
}
return sizeOfFreeSpace;
}
int Accordion::startOfBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
int bufferCount = 0;
int startOfBuffer = 0;
while (m_history[startOfBuffer] == k_freeSpaceMarker && startOfBuffer < m_historySize) {
startOfBuffer++;
}
for (int i = startOfBuffer; i < m_historySize; i++) {
if (bufferCount == index) {
while (m_history[i] == k_freeSpaceMarker && i < m_historySize) {
i++;
}
return i;
}
if (m_history[i] == 0) {
bufferCount++;
}
}
assert(false);
return 0;
}
int Accordion::endOfBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
int startOfBuffer = startOfBufferAtIndex(index);
for (int i = startOfBuffer; i < m_historySize; i++) {
if (m_history[i] == 0) {
return i;
}
}
assert(false);
return 0;
}
int Accordion::startOfFreeSpace() {
cleanFreeSpace();
for (int i = 0; i < m_historySize; i++) {
if (m_history[i] == k_freeSpaceMarker) {
return i;
}
}
assert(false);
return 0;
}
void Accordion::cleanFreeSpace() {
if (m_history[m_startOfLastEditedBuffer] == k_freeSpaceMarker) {
return;
}
int indexOfCharToChangeIntoFreeSpaceMarker = m_startOfLastEditedBuffer
+ strlen(&m_history[m_startOfLastEditedBuffer]) + 1;
while (m_history[indexOfCharToChangeIntoFreeSpaceMarker] != k_freeSpaceMarker
&& indexOfCharToChangeIntoFreeSpaceMarker < m_historySize)
{
m_history[indexOfCharToChangeIntoFreeSpaceMarker] = k_freeSpaceMarker;
indexOfCharToChangeIntoFreeSpaceMarker ++;
}
}
void Accordion::moveFreeSpaceAtPosition(int i) {
assert(i >= 0 && i <= m_historySize);
cleanFreeSpace();
int freeSpaceStart = startOfFreeSpace();
if (freeSpaceStart != i){
// First, move the chars that would be overriden by the free space.
// The indexes depend on the relative positions of the free space and the
// new destination.
int sizeFreeSpace = freeSpaceSize();
int len, src, dst, newFreeSpaceStart;
if (freeSpaceStart > i) {
len = freeSpaceStart - i;
src = i;
dst = i + sizeFreeSpace;
newFreeSpaceStart = i;
} else {
src = freeSpaceStart + sizeFreeSpace;
len = i - src;
dst = freeSpaceStart;
newFreeSpaceStart = i-sizeFreeSpace;
}
memmove(&m_history[dst], &m_history[src], len);
// Then move the free space.
for (int j = newFreeSpaceStart ; j < newFreeSpaceStart+sizeFreeSpace; j++) {
m_history[j] = k_freeSpaceMarker;
}
}
m_startOfLastEditedBuffer = i-1;
while (m_startOfLastEditedBuffer > 0 && m_history[m_startOfLastEditedBuffer-1] != 0 ) {
m_startOfLastEditedBuffer--;
}
}
void Accordion::moveFreeSpaceAtEndOfBufferAtIndex(int index) {
assert(index >= 0 && index < numberOfBuffers());
cleanFreeSpace();
int endOfBuffer = endOfBufferAtIndex(index);
moveFreeSpaceAtPosition(endOfBuffer+1);
}
void Accordion::moveFreeSpaceAtEndOfHistory() {
cleanFreeSpace();
if (m_numberOfBuffers > 0) {
moveFreeSpaceAtEndOfBufferAtIndex(m_numberOfBuffers-1);
}
}