cfad47cfa3/tads3/vmbytarr.h
Commiter: Nikos Chantziaras
Author: Nikos Chantziaras
Revision: cfad47cfa3
File Size: 14.9 KB
(June 01, 2009 20:54 UTC) Almost 3 years ago
Initial commit.
/*
* Copyright (c) 2001, 2002 Michael J. Roberts. All Rights Reserved.
*
* Please see the accompanying license file, LICENSE.TXT, for information
* on using and copying this software.
*/
/*
Name
vmbytarr.h - T3 ByteArray metaclass
Function
Notes
Modified
06/05/01 MJRoberts - Creation
*/
#ifndef VMBYTARR_H
#define VMBYTARR_H
#include <stdlib.h>
#include "os.h"
#include "vmtype.h"
#include "vmobj.h"
#include "vmglob.h"
/* ------------------------------------------------------------------------ */
/*
* A ByteArray is simply an array of byte values. This class provides a
* simple, fast mechanism to store blocks of binary data, so it is not a
* subclass of Array and is not a Collection.
*
* The image file data for a byte array is simple:
*
* UINT4 number of bytes
*. BYTE bytes[1..number_of_bytes]
*
* Internally, we store the array data in chunks of 32k each. Our
* extension is a first-level page table, pointing to the chunks:
*
* UINT4 number of elements
*. unsigned char **page0
*. unsigned char **page1
*. ...
*
* Each pageN pointer points to a second-level page table, which consists
* of (up to) 8192 pointers to the actual pages. Since a page is 32k, and
* we can store 8k pointers per second-level table, each second-level
* table is capable of referencing 256MB. By design, we can store up to
* 4GB, so we need at most 16 second-level tables.
*
* The extension is allocated according to the actual number of
* second-level tables we require for the element count. Each
* second-level page is allocated to 8192*sizeof(char *), except the last
* second-level page, which is allocated to N*sizeof(char *) where N is
* the number of elements required in the last second-level table. Each
* page is allocated to 32K bytes, except the last, which is allocated to
* the actual size needed.
*
* To access an element at index i, we calculate s1 (the page table
* selector) as i/(32k*8k) == i/256M; s2 (the page selector within the
* selected page table) as (i%256M)/32k; and s3 (the byte selector within
* the page) as i%32k. The byte is then accessed as
*
* page[s1][s2][s3]
*/
class CVmObjByteArray: public CVmObject
{
friend class CVmMetaclassByteArray;
friend class bytearray_undo_rec;
public:
/* metaclass registration object */
static class CVmMetaclass *metaclass_reg_;
class CVmMetaclass *get_metaclass_reg() const { return metaclass_reg_; }
/* am I of the given metaclass? */
virtual int is_of_metaclass(class CVmMetaclass *meta) const
{
/* try my own metaclass and my base class */
return (meta == metaclass_reg_
|| CVmObject::is_of_metaclass(meta));
}
/* create dynamically using stack arguments */
static vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr,
uint argc);
/*
* call a static property - we don't have any of our own, so simply
* "inherit" the base class handling
*/
static int call_stat_prop(VMG_ vm_val_t *result,
const uchar **pc_ptr, uint *argc,
vm_prop_id_t prop)
{
/* explicitly inherit our superclass handling */
return CVmObject::call_stat_prop(vmg_ result, pc_ptr, argc, prop);
}
/* reserve constant data */
virtual void reserve_const_data(VMG_ class CVmConstMapper *mapper,
vm_obj_id_t self)
{
/*
* we reference no other objects and cannot ourselves be converted
* to constant data, so there's nothing to do here
*/
}
/* convert to constant data */
virtual void convert_to_const_data(VMG_ class CVmConstMapper *mapper,
vm_obj_id_t self)
{
/*
* we reference no data and cannot be converted to constant data,
* so there's nothing to do
*/
}
/* create an array with no initial contents */
static vm_obj_id_t create(VMG_ int in_root_set);
/* create an array with a given number of elements */
static vm_obj_id_t create(VMG_ int in_root_set,
unsigned long element_count);
/*
* determine if an object is a byte array - it is if the object's
* virtual metaclass registration index matches the class's static
* index
*/
static int is_byte_array(VMG_ vm_obj_id_t obj)
{ return vm_objp(vmg_ obj)->is_of_metaclass(metaclass_reg_); }
/* notify of deletion */
void notify_delete(VMG_ int in_root_set);
/* set a property */
void set_prop(VMG_ class CVmUndo *undo,
vm_obj_id_t self, vm_prop_id_t prop, const vm_val_t *val);
/* get a property */
int get_prop(VMG_ vm_prop_id_t prop, vm_val_t *val,
vm_obj_id_t self, vm_obj_id_t *source_obj, uint *argc);
/* undo operations */
void notify_new_savept() { }
void apply_undo(VMG_ struct CVmUndoRecord *rec);
void discard_undo(VMG_ struct CVmUndoRecord *);
/* our data are just bytes - we reference nothing */
void mark_undo_ref(VMG_ struct CVmUndoRecord *) { }
void remove_stale_undo_weak_ref(VMG_ struct CVmUndoRecord *) { }
void mark_refs(VMG_ uint /*state*/) { }
void remove_stale_weak_refs(VMG0_) { }
/* load from an image file */
void load_from_image(VMG_ vm_obj_id_t self, const char *ptr, size_t siz);
/* rebuild for image file */
virtual ulong rebuild_image(VMG_ char *buf, ulong buflen);
/* reload from the image file */
void reload_from_image(VMG_ vm_obj_id_t self,
const char *ptr, size_t siz);
/* save to a file */
void save_to_file(VMG_ class CVmFile *fp);
/* restore from a file */
void restore_from_file(VMG_ vm_obj_id_t self,
class CVmFile *fp, class CVmObjFixup *fixup);
/* index the array */
void index_val(VMG_ vm_val_t *result, vm_obj_id_t self,
const vm_val_t *index_val);
/* set an indexed element of the array */
void set_index_val(VMG_ vm_val_t *new_container, vm_obj_id_t self,
const vm_val_t *index_val, const vm_val_t *new_val);
/*
* Check a value for equality. We will match another byte array with
* the same number of elements and the same value for each element.
*/
int equals(VMG_ vm_obj_id_t self, const vm_val_t *val, int depth) const;
/* calculate a hash value for the array */
uint calc_hash(VMG_ vm_obj_id_t self, int depth) const;
/*
* assume that we've been changed since loading, if we came from the
* image file
*/
int is_changed_since_load() const { return TRUE; }
/* get the number of elements in the array */
unsigned long get_element_count() const
{ return t3rp4u(get_ext_ptr()); }
/*
* construction: copy (without undo) bytes from a buffer into the byte
* array
*/
void cons_copy_from_buf(const unsigned char *buf,
unsigned long idx, size_t cnt)
{
/* copy the bytes into our array */
copy_from_buf(buf, idx, cnt);
}
/*
* Write the specified region of the array to a file. Returns zero on
* success, non-zero on failure.
*/
int write_to_file(osfildef *fp, unsigned long start_idx,
unsigned long len) const;
/*
* Read bytes from a file into a region of the array, replacing
* existing bytes in the array; saves undo for the change. Returns
* the number of bytes actually read from the file, which will be less
* than the number of bytes requested if we reach the end of the file
* before satisfying the request.
*/
unsigned long read_from_file(osfildef *fp, unsigned long start_idx,
unsigned long len);
/*
* write to a 'data' mode file - returns zero on success, non-zero on
* failure
*/
int write_to_data_file(osfildef *fp);
/*
* read from a 'data' mode file, creating a new ByteArray object to
* hold the bytes from the file
*/
static int read_from_data_file(VMG_ vm_val_t *retval, osfildef *fp);
protected:
/* load image data */
virtual void load_image_data(VMG_ const char *ptr, size_t siz);
/* create a list with no initial contents */
CVmObjByteArray() { ext_ = 0; }
/*
* create a list with a given number of elements, for construction
* of the list element-by-element
*/
CVmObjByteArray(VMG_ unsigned long byte_count);
/* get a pointer to my extension */
const char *get_ext_ptr() const { return ext_; }
/*
* get my extension data pointer for construction purposes - this is
* a writable pointer, so that a caller can fill our data buffer
* during construction
*/
char *cons_get_ext_ptr() const { return ext_; }
/* allocate space for the array, given the number of elements */
void alloc_array(VMG_ unsigned long element_count);
/* property evaluator - undefined function */
int getp_undef(VMG_ vm_obj_id_t, vm_val_t *, uint *) { return FALSE; }
/* property evaluator - length */
int getp_length(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - subarray */
int getp_subarray(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - copy from another byte array */
int getp_copy_from(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - fill with a value */
int getp_fill_val(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - convert to string */
int getp_to_string(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - read integer */
int getp_read_int(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/* property evaluator - write integer */
int getp_write_int(VMG_ vm_obj_id_t self, vm_val_t *val, uint *argc);
/*
* Given a 1-based index, get a pointer to the byte at the index, and
* the number of contiguous bytes available starting with that byte.
* The available byte count doesn't take into account a short last
* page, but simply returns the maximum number of bytes that would be
* available on the page if it were allocated to full size; the caller
* is responsible for ensuring that there is no reading or writing
* past the end of the array.
*/
unsigned char *get_ele_ptr(unsigned long idx, size_t *bytes_avail) const
{
size_t s1;
size_t s2;
size_t s3;
/* convert to a zero-based index */
--idx;
/*
* calculate the page table index - since each page holds 32k
* bytes and each page table points to 8k pages, divide by 32k*8k
* == 2^15*2^13 == 2^28
*/
s1 = idx >> 28;
/*
* calculate the page index within the page table - each page
* holds 32k, so calculate the excess from the page table selector
* (i.e, idx % 32k*8k) and then divide by 32k == 2^15
*/
s2 = (idx & 0x0FFFFFFF) >> 15;
/*
* calculate the page offset - this is simply the excess from the
* page index
*/
s3 = idx & 0x7FFF;
/*
* Each page holds 32k, so the number of contiguous bytes starting
* at this byte is 32k less the index.
*/
*bytes_avail = (32*1024) - s3;
/*
* dereference the extension to get the page table, deference the
* page table to get the page, and index the page by the offset
*/
return get_page_table_ptr(s1)[s2] + s3;
}
/*
* Given a page table selector, return a pointer to the selected page
* table.
*/
unsigned char **get_page_table_ptr(size_t s) const
{
return get_page_table_array()[s];
}
/*
* Get a pointer to the page table array
*/
unsigned char ***get_page_table_array() const
{
/* the page table array starts after the element count */
return (unsigned char ***)(ext_ + 4);
}
/* fill the given (1-based index) range with the given byte value */
void fill_with(unsigned char val, unsigned long start_idx,
unsigned long cnt);
/* copy bytes from another byte array into this one */
void copy_from(unsigned long dst_idx,
CVmObjByteArray *src_arr,
unsigned long src_start_idx, unsigned long cnt);
/* move bytes within this array */
void move_bytes(unsigned long dst_idx, unsigned long src_idx,
unsigned long cnt);
/* copy bytes into a buffer */
void copy_to_buf(unsigned char *buf, unsigned long idx, size_t cnt) const;
/* copy bytes from a buffer into the array */
void copy_from_buf(const unsigned char *buf,
unsigned long idx, size_t cnt);
/* map to a string */
size_t map_to_string(unsigned long idx, unsigned long len,
class CVmObjString *str, size_t str_len,
class CCharmapToUni *mapper);
/* save undo for a change to a range of the array */
void save_undo(VMG_ vm_obj_id_t self, unsigned long start_idx,
unsigned long cnt);
/* set the number of bytes in the array */
void set_element_count(unsigned long cnt)
{ oswp4(cons_get_ext_ptr(), cnt); }
/* property evaluation function table */
static int (CVmObjByteArray::*func_table_[])(
VMG_ vm_obj_id_t self, vm_val_t *retval, uint *argc);
};
/* ------------------------------------------------------------------------ */
/*
* Registration table object
*/
class CVmMetaclassByteArray: public CVmMetaclass
{
public:
/* get the global name */
const char *get_meta_name() const { return "bytearray/030001"; }
/* create from image file */
void create_for_image_load(VMG_ vm_obj_id_t id)
{
new (vmg_ id) CVmObjByteArray();
G_obj_table->set_obj_gc_characteristics(id, FALSE, FALSE);
}
/* create from restoring from saved state */
void create_for_restore(VMG_ vm_obj_id_t id)
{
new (vmg_ id) CVmObjByteArray();
G_obj_table->set_obj_gc_characteristics(id, FALSE, FALSE);
}
/* create dynamically using stack arguments */
vm_obj_id_t create_from_stack(VMG_ const uchar **pc_ptr, uint argc)
{ return CVmObjByteArray::create_from_stack(vmg_ pc_ptr, argc); }
/* call a static property */
int call_stat_prop(VMG_ vm_val_t *result,
const uchar **pc_ptr, uint *argc,
vm_prop_id_t prop)
{
return CVmObjByteArray::
call_stat_prop(vmg_ result, pc_ptr, argc, prop);
}
};
#endif /* VMBYTARR_H */
/*
* Register the class
*/
VM_REGISTER_METACLASS(CVmObjByteArray) |