--- a/src/data_buffer.cc Sun Jan 19 20:39:30 2014 +0200 +++ b/src/data_buffer.cc Sun Jan 26 23:18:48 2014 +0200 @@ -30,46 +30,46 @@ // ============================================================================ // -void data_buffer::merge (data_buffer* other) +data_buffer::data_buffer (int size) +{ + set_writepos (get_buffer()); + set_buffer (new byte[size]); + set_allocated_size (size); +} + +// ============================================================================ +// +data_buffer::~data_buffer() +{ + assert (count_marks() == 0 && count_refs() == 0); + delete get_buffer(); +} + +// ============================================================================ +// +void data_buffer::merge_and_destroy (data_buffer* other) { if (!other) return; - int oldsize = writesize; - - for (int x = 0; x < other->writesize; x++) - write (* (other->buffer + x)); - - // Merge its marks and references - int u = 0; - - for (u = 0; u < MAX_MARKS; u++) - { - if (other->marks[u]) - { - // Merge the mark and offset its position. - if (marks[u]) - error ("DataBuffer: duplicate mark %d!\n"); + int oldsize = get_write_size(); + copy_buffer (other); - marks[u] = other->marks[u]; - marks[u]->pos += oldsize; - - // The original mark becomes null so that the deconstructor - // will not delete it prematurely. (should it delete any - // marks in the first place since there is no such thing - // as at temporary mark?) - other->marks[u] = null; - } - - if (other->refs[u]) - { - // Same for references - // TODO: add a g_NextRef system like here, akin to marks! - int r = add_reference (other->refs[u]->num, false); - refs[r]->pos = other->refs[u]->pos + oldsize; - } + // Assimilate in its marks and references + for (byte_mark* mark : other->get_marks()) + { + mark->pos += oldsize; + push_to_marks (mark); } + for (mark_reference* ref : other->get_refs()) + { + ref->pos += oldsize; + push_to_refs (ref); + } + + clear_marks(); + clear_refs(); delete other; } @@ -78,182 +78,166 @@ data_buffer* data_buffer::clone() { data_buffer* other = new data_buffer; - - for (int x = 0; x < writesize; x++) - other->write (* (buffer + x)); - + other->copy_buffer (this); return other; } // ============================================================================ // -int data_buffer::add_mark (string name) +void data_buffer::copy_buffer (const data_buffer* buf) { - // Find a free slot for the mark - int u = g_NextMark++; - - if (marks[u]) - error ("DataBuffer: attempted to re-create mark %u!\n", u); - - 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->pos = writesize; - marks[u] = m; - return u; + check_space (buf->get_write_size()); + memcpy (m_writepos, buf->get_buffer(), buf->get_write_size()); + m_writepos += buf->get_write_size(); } // ============================================================================ // -int data_buffer::add_reference (int marknum, bool placeholder) +byte_mark* data_buffer::add_mark (string name) { - int u; - - for (u = 0; u < MAX_MARKS; u++) - if (!refs[u]) - break; - - // TODO: get rid of this - if (u == MAX_MARKS) - error ("mark reference quota exceeded, all goto-statements, if-structs and loops add refs\n"); - - ScriptMarkReference* r = new ScriptMarkReference; - r->num = marknum; - r->pos = writesize; - refs[u] = r; - - // Write a dummy placeholder for the reference - if (placeholder) - write (0xBEEFCAFE); - - return u; + byte_mark* mark = new byte_mark; + mark->name = name; + mark->pos = get_write_size(); + push_to_marks (mark); + return mark; } // ============================================================================ // -void data_buffer::delete_mark (int marknum) +mark_reference* data_buffer::add_reference (byte_mark* mark, bool write_placeholder) { - if (!marks[marknum]) - return; - - // Delete the mark - delete marks[marknum]; - marks[marknum] = null; + mark_reference* ref = new mark_reference; + ref->target = mark; + ref->pos = get_write_size(); + push_to_refs (ref); - // Delete its references - for (int u = 0; u < MAX_MARKS; u++) - { - if (refs[u]->num == marknum) - { - delete refs[u]; - refs[u] = null; - } - } + // Write a dummy placeholder for the reference + if (write_placeholder) + write_dword (0xBEEFCAFE); + + return ref; } // ============================================================================ // -void data_buffer::move_mark (int i) +void data_buffer::adjust_mark (byte_mark* mark) { - if (!marks[i]) - return; - - marks[i]->pos = writesize; -} - -// ============================================================================ -// -void data_buffer::offset_mark (int mark, int offset) -{ - if (!marks[mark]) - return; - - marks[mark]->pos += offset; + mark->pos = get_write_size(); } // ============================================================================ // -int data_buffer::count_marks() +void data_buffer::offset_mark (byte_mark* mark, int offset) { - int count = 0; - - for (int u = 0; u < MAX_MARKS; u++) - count += !!marks[u]; - - return count; + mark->pos += offset; } // ============================================================================ // -int data_buffer::count_references() +void data_buffer::write_float (float a) { - int count = 0; + // TODO: Find a way to store the number without decimal loss. + write_dword (dh_push_number); + write_dword (abs (a)); - for (int u = 0; u < MAX_MARKS; u++) - count += !!refs[u]; - - return count; + if (a < 0) + write_dword (dh_unary_minus); } // ============================================================================ // -void data_buffer::write_float (string floatstring) +void data_buffer::write_string_index (const string& a) { - // TODO: Casting float to word causes the decimal to be lost. - // Find a way to store the number without such loss. - float val = atof (floatstring); - write (dh_push_number); - write (static_cast<word> (abs (val))); - - if (val < 0) - write (dh_unary_minus); -} - -// ============================================================================ -// -void data_buffer::write_string (string a) -{ - write (dh_push_string_index); - write (get_string_table_index (a)); + write_dword (dh_push_string_index); + write_dword (get_string_table_index (a)); } // ============================================================================ // void data_buffer::dump() { - for (int x = 0; x < writesize; x++) - printf ("%d. [%d]\n", x, * (buffer + x)); + for (int i = 0; i < get_write_size(); ++i) + printf ("%d. [%d]\n", i, get_buffer()[i]); } // ============================================================================ // -data_buffer::~data_buffer() +void data_buffer::check_space (int bytes) { - delete buffer; + int writesize = get_write_size(); + + if (writesize + bytes < get_allocated_size()) + return; + + // We don't have enough space in the buffer to write + // the stuff - thus resize. First, store the old + // buffer temporarily: + char* copy = new char[get_allocated_size()]; + memcpy (copy, get_buffer(), get_allocated_size()); - // Delete any marks and references - for (int i = 0; i < MAX_MARKS; i++) - { - delete marks[i]; - delete refs[i]; - } + // Remake the buffer with the new size. Have enough space + // for the stuff we're going to write, as well as a bit + // of leeway so we don't have to resize immediately again. + size_t newsize = get_allocated_size() + bytes + 512; + + delete get_buffer(); + set_buffer (new byte[newsize]); + set_allocated_size (newsize); + + // Now, copy the stuff back. + memcpy (m_buffer, copy, get_allocated_size()); + set_writepos (get_buffer() + writesize); + delete copy; +} + +// ============================================================================= +// +void data_buffer::write_byte (int8_t data) +{ + check_space (1); + *m_writepos++ = data; } -// ============================================================================ +// ============================================================================= // -data_buffer::data_buffer (int size) +void data_buffer::write_word (int16_t data) { - writesize = 0; + check_space (2); + + for (int i = 0; i < 2; ++i) + *m_writepos++ = (data >> (i * 8)) & 0xFF; +} + +// ============================================================================= +// +void data_buffer::write_dword (int32_t data) +{ + check_space (4); + + for (int i = 0; i < 4; ++i) + *m_writepos++ = (data >> (i * 8)) & 0xFF; +} - buffer = new unsigned char[size]; - allocsize = size; +// ============================================================================= +// +void data_buffer::write_string (const string& a) +{ + check_space (a.length() + 1); + + for (char c : a) + write_byte (c); + + write_byte ('\0'); +} - // Clear the marks table out - for (int u = 0; u < MAX_MARKS; u++) - { - marks[u] = null; - refs[u] = null; - } -} + +// ============================================================================= +// +byte_mark* data_buffer::find_mark_by_name (const string& target) +{ + for (byte_mark* mark : get_marks()) + if (mark->name == target) + return mark; + + return null; +} \ No newline at end of file