databuffer.h

changeset 37
c349dca807f9
parent 36
a8838b5f1213
child 38
e4bbd540663b
--- a/databuffer.h	Sun Jul 29 04:02:07 2012 +0300
+++ b/databuffer.h	Sun Jul 29 16:55:32 2012 +0300
@@ -44,6 +44,8 @@
 #include <string.h>
 #include "common.h"
 
+#define MAX_MARKS 256
+
 // ============================================================================
 // DataBuffer: A dynamic data buffer.
 class DataBuffer {
@@ -57,18 +59,44 @@
 	// Written size of the buffer
 	unsigned int writesize;
 	
+	// Marks and references
+	ScriptMark* marks[MAX_MARKS];
+	ScriptMarkReference* refs[MAX_MARKS];
+	
+	// ====================================================================
 	// METHODS
+	
+	// ====================================================================
+	// Constructor
 	DataBuffer (unsigned int size=128) {
 		writesize = 0;
 		
 		buffer = new unsigned char[size];
 		allocsize = size;
+		
+		// Clear the marks table out
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			marks[u] = NULL;
+			refs[u] = NULL;
+		}
 	}
 	
+	// ====================================================================
 	~DataBuffer () {
 		delete buffer;
+		
+		// Delete any marks and references
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			if (marks[u])
+				delete marks[u];
+			
+			if (refs[u])
+				delete refs[u];
+		}
 	}
 	
+	// ====================================================================
+	// Write stuff to the buffer
 	template<class T> void Write(T stuff) {
 		if (sizeof (char) != 1) {
 			error ("DataBuffer: sizeof(char) must be 1!\n");
@@ -99,39 +127,100 @@
 		for (unsigned int x = 0; x < sizeof (T); x++) {
 			if (writesize >= allocsize)
 				error ("DataBuffer: written size exceeds allocated size!\n");
-			buffer[writesize] = CharByte<T> (stuff, x);
+			buffer[writesize] = GetByteIndex<T> (stuff, x);
 			writesize++;
 		}
 	}
 	
+	// ====================================================================
 	// Merge another data buffer into this one.
 	void Merge (DataBuffer* other) {
 		if (!other)
-				return;
+			return;
 		
 		for (unsigned int x = 0; x < other->writesize; x++) {
 			unsigned char c = *(other->buffer+x);
 			Write<unsigned char> (c);
 		}
 		
+		// Merge its marks and references
+		unsigned int u = 0;
+		for (u = 0; u < MAX_MARKS; u++) {
+			if (other->marks[u]) {
+				// Add the mark and offset its position.
+				unsigned int u = AddMark (other->marks[u]->type, other->marks[u]->name);
+				marks[u]->pos += other->writesize;
+			}
+			
+			if (other->refs[u]) {
+				// Same for references
+				unsigned int r = AddMarkReference (other->refs[u]->num);
+				refs[r]->pos += other->writesize;
+			}
+		}
+		
 		delete other;
 	}
 	
-private:
-	template <class T> unsigned char CharByte (T a, unsigned int b) {
-		if (b >= sizeof (T))
-			error ("CharByte: tried to get byte %u out of a %u-byte %s\n",
-				b, sizeof (T), typeid (T).name());
+	// ====================================================================
+	// Adds a mark to the buffer. A mark is a reference to a particular
+	// position in the bytecode. The actual permanent position cannot
+	// be predicted in any way or form, thus these things will be used
+	// to "mark" a position like that for future use.
+	unsigned int AddMark (int type, str name) {
+		// Find a free slot for the mark
+		unsigned int u;
+		for (u = 0; u < MAX_MARKS; u++)
+			if (!marks[u])
+				break;
+		
+		if (u >= MAX_MARKS)
+			error ("mark quota exceeded, all labels, if-structs and loops add marks\n");
+		
+		ScriptMark* m = new ScriptMark;
+		m->name = name;
+		m->type = type;
+		m->pos = writesize;
+		marks[u] = m;
+		return u;
+	}
+	
+	unsigned int AddMarkReference (unsigned int marknum) {
+		unsigned int u;
+		for (u = 0; u < MAX_MARKS; u++)
+			if (!refs[u])
+				break;
 		
-		unsigned long p1 = pow<unsigned long> (256, b);
-		unsigned long p2 = pow<unsigned long> (256, b+1);
-		unsigned long r = (a % p2) / p1;
+		if (u == MAX_MARKS)
+			error ("mark reference quota exceeded, all goto-statements, if-structs and loops add refs\n");
+		
+		// NOTE: Do not check if the mark actually exists here since a
+		// reference may come in the code earlier than the actual mark
+		// and the new mark number can be predicted.
+		ScriptMarkReference* r = new ScriptMarkReference;
+		r->num = marknum;
+		r->pos = writesize;
+		refs[u] = r;
 		
-		if (r > 256)
-			error ("DataBuffer::CharByte: result %lu too big!", r);
+		return u;
+	}
+	
+	// Delete a mark and all references to it.
+	void DeleteMark (unsigned int marknum) {
+		if (!marks[marknum])
+			return;
 		
-		unsigned char ur = static_cast<unsigned char> (r);
-		return ur;
+		// Delete the mark
+		delete marks[marknum];
+		marks[marknum] = NULL;
+		
+		// Delete its references
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			if (refs[u]->num == marknum) {
+				delete refs[u];
+				refs[u] = NULL;
+			}
+		}
 	}
 };
 

mercurial