Implement recordset iterators
JerryScript-DCO-1.0-Signed-off-by: Evgeny Gavrin e.gavrin@samsung.com JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
This commit is contained in:
@@ -37,6 +37,14 @@
|
||||
class rcs_chunked_list_t
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor of chunked list
|
||||
*/
|
||||
rcs_chunked_list_t ()
|
||||
{
|
||||
head_p = tail_p = NULL;
|
||||
} /* rcs_chunked_list_t */
|
||||
|
||||
/**
|
||||
* List node
|
||||
*/
|
||||
@@ -52,27 +60,27 @@ public:
|
||||
node_t *get_first (void) const;
|
||||
node_t *get_last (void) const;
|
||||
|
||||
node_t *get_prev (node_t *node_p) const;
|
||||
node_t *get_prev (node_t *) const;
|
||||
node_t *get_next (node_t *node_p) const;
|
||||
|
||||
node_t *append_new (void);
|
||||
node_t *insert_new (node_t *after_p);
|
||||
node_t *insert_new (node_t *);
|
||||
|
||||
void remove (node_t *node_p);
|
||||
void remove (node_t *);
|
||||
|
||||
node_t *get_node_from_pointer (void *ptr) const;
|
||||
uint8_t* get_data_space (node_t *node_p) const;
|
||||
node_t *get_node_from_pointer (void *) const;
|
||||
uint8_t* get_data_space (node_t *) const;
|
||||
|
||||
static size_t get_data_space_size (void);
|
||||
|
||||
private:
|
||||
void set_prev (node_t *node_p, node_t *prev_node_p);
|
||||
void set_next (node_t *node_p, node_t *next_node_p);
|
||||
void set_prev (node_t *, node_t *);
|
||||
void set_next (node_t *, node_t *);
|
||||
|
||||
static size_t get_node_size (void);
|
||||
|
||||
void assert_list_is_correct (void) const;
|
||||
void assert_node_is_correct (const node_t *node_p) const;
|
||||
void assert_node_is_correct (const node_t *) const;
|
||||
|
||||
node_t* head_p; /**< head node of list */
|
||||
node_t* tail_p; /**< tail node of list */
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include "rcs-chunked-list.h"
|
||||
#include "rcs-recordset.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
|
||||
/** \addtogroup recordset Recordset
|
||||
* @{
|
||||
@@ -91,7 +90,6 @@ rcs_recordset_t::record_t::cpointer_t::decompress (rcs_cpointer_t compressed_poi
|
||||
* compressed pointer */
|
||||
{
|
||||
uint8_t* base_pointer;
|
||||
|
||||
if (compressed_pointer.value.base_cp == MEM_CP_NULL)
|
||||
{
|
||||
base_pointer = NULL;
|
||||
@@ -106,6 +104,19 @@ rcs_recordset_t::record_t::cpointer_t::decompress (rcs_cpointer_t compressed_poi
|
||||
return (rcs_recordset_t::record_t*) (base_pointer + diff);
|
||||
} /* rcs_recordset_t::record_t::cpointer_t::decompress */
|
||||
|
||||
/**
|
||||
* Create NULL compressed pointer
|
||||
*
|
||||
* @return NULL compressed pointer
|
||||
*/
|
||||
rcs_cpointer_t
|
||||
rcs_recordset_t::record_t::cpointer_t::null_cp ()
|
||||
{
|
||||
rcs_cpointer_t cp;
|
||||
cp.packed_value = MEM_CP_NULL;
|
||||
return cp;
|
||||
} /* rcs_recordset_t::record_t::cpointer_t::null_cp */
|
||||
|
||||
/**
|
||||
* Assert that 'this' value points to correct record
|
||||
*/
|
||||
@@ -612,6 +623,7 @@ rcs_recordset_t::assert_state_is_correct (void)
|
||||
rec_p != NULL;
|
||||
last_record_p = rec_p, rec_p = next_rec_p)
|
||||
{
|
||||
JERRY_ASSERT (get_record_size (rec_p) > 0);
|
||||
record_size_sum += get_record_size (rec_p);
|
||||
|
||||
rcs_chunked_list_t::node_t *node_p = _chunk_list.get_node_from_pointer (rec_p);
|
||||
@@ -649,6 +661,110 @@ rcs_recordset_t::assert_state_is_correct (void)
|
||||
#endif /* !JERRY_NDEBUG */
|
||||
} /* rcs_recordset_t::assert_state_is_correct */
|
||||
|
||||
/**
|
||||
* Perform general access to the record
|
||||
*
|
||||
* Warning: This function is implemented in assumption that `size` is not more than `2 * node_data_space_size`.
|
||||
*/
|
||||
void
|
||||
rcs_record_iterator_t::access (access_t access_type, /**< type of access: read, write or skip */
|
||||
void *data, /**< in/out data to read or write */
|
||||
size_t size) /**< size of the data in bytes */
|
||||
{
|
||||
const size_t node_data_space_size = _recordset_p->_chunk_list.get_data_space_size ();
|
||||
JERRY_ASSERT (2 * node_data_space_size >= size);
|
||||
const size_t record_size = _recordset_p->get_record_size (_record_start_p);
|
||||
|
||||
JERRY_ASSERT (!finished ());
|
||||
|
||||
rcs_chunked_list_t::node_t *current_node_p = _recordset_p->_chunk_list.get_node_from_pointer (_current_pos_p);
|
||||
uint8_t *current_node_data_space_p = _recordset_p->_chunk_list.get_data_space (current_node_p);
|
||||
size_t left_in_node = node_data_space_size - (size_t)(_current_pos_p - current_node_data_space_p);
|
||||
|
||||
JERRY_ASSERT (_current_offset + size <= record_size);
|
||||
|
||||
/*
|
||||
* Read the data and increase the current position pointer.
|
||||
*/
|
||||
if (left_in_node >= size)
|
||||
{
|
||||
/* all data is placed inside single node */
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy (data, _current_pos_p, size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (_current_pos_p, data, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == ACCESS_SKIP);
|
||||
|
||||
if (left_in_node > size)
|
||||
{
|
||||
_current_pos_p += size;
|
||||
}
|
||||
else if (_current_offset + size < record_size)
|
||||
{
|
||||
current_node_p = _recordset_p->_chunk_list.get_next (current_node_p);
|
||||
JERRY_ASSERT (current_node_p);
|
||||
_current_pos_p = _recordset_p->_chunk_list.get_data_space (current_node_p);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (_current_offset + size == record_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* data is distributed between two nodes */
|
||||
size_t first_chunk_size = node_data_space_size - (size_t) (_current_pos_p - current_node_data_space_p);
|
||||
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy (data, _current_pos_p, first_chunk_size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (_current_pos_p, data, first_chunk_size);
|
||||
}
|
||||
|
||||
rcs_chunked_list_t::node_t *next_node_p = _recordset_p->_chunk_list.get_next (current_node_p);
|
||||
JERRY_ASSERT (next_node_p != NULL);
|
||||
uint8_t *next_node_data_space_p = _recordset_p->_chunk_list.get_data_space (next_node_p);
|
||||
|
||||
if (access_type == ACCESS_READ)
|
||||
{
|
||||
memcpy ((uint8_t *)data + first_chunk_size, next_node_data_space_p, size - first_chunk_size);
|
||||
}
|
||||
else if (access_type == ACCESS_WRITE)
|
||||
{
|
||||
memcpy (next_node_data_space_p, (uint8_t *)data + first_chunk_size, size - first_chunk_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
JERRY_ASSERT (access_type == ACCESS_SKIP);
|
||||
|
||||
_current_pos_p = next_node_data_space_p + size - first_chunk_size;
|
||||
}
|
||||
}
|
||||
|
||||
/* check if we reached the end */
|
||||
if (access_type == ACCESS_SKIP)
|
||||
{
|
||||
_current_offset += size;
|
||||
JERRY_ASSERT (_current_offset <= record_size);
|
||||
|
||||
if (_current_offset == record_size)
|
||||
{
|
||||
_current_pos_p = NULL;
|
||||
_current_offset = 0;
|
||||
}
|
||||
}
|
||||
} /* rcs_record_iterator_t::access */
|
||||
|
||||
/**
|
||||
* Get size of the free record
|
||||
*/
|
||||
|
||||
+117
-17
@@ -16,6 +16,8 @@
|
||||
#ifndef RCS_RECORDSET_H
|
||||
#define RCS_RECORDSET_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jrt.h"
|
||||
#include "jrt-bit-fields.h"
|
||||
#include "mem-allocator.h"
|
||||
@@ -109,8 +111,12 @@ public:
|
||||
uint16_t packed_value;
|
||||
};
|
||||
|
||||
static cpointer_t compress (record_t* pointer_p);
|
||||
static record_t* decompress (cpointer_t pointer_cp);
|
||||
static cpointer_t compress (record_t *pointer_p);
|
||||
static record_t *decompress (cpointer_t pointer_cp);
|
||||
|
||||
static cpointer_t null_cp ();
|
||||
|
||||
static const int conval = 3;
|
||||
};
|
||||
|
||||
private:
|
||||
@@ -130,7 +136,7 @@ public:
|
||||
uint32_t get_field (uint32_t field_pos, uint32_t field_width) const;
|
||||
void set_field (uint32_t field_pos, uint32_t field_width, size_t value);
|
||||
|
||||
record_t* get_pointer (uint32_t field_pos, uint32_t field_width) const;
|
||||
record_t *get_pointer (uint32_t field_pos, uint32_t field_width) const;
|
||||
void set_pointer (uint32_t field_pos, uint32_t field_width, record_t* pointer_p);
|
||||
|
||||
/**
|
||||
@@ -139,6 +145,9 @@ public:
|
||||
static const uint32_t _fields_offset_begin = _type_field_pos + _type_field_width;
|
||||
};
|
||||
|
||||
record_t *get_first (void);
|
||||
record_t *get_next (record_t *rec_p);
|
||||
|
||||
private:
|
||||
friend class rcs_record_iterator_t;
|
||||
|
||||
@@ -158,6 +167,7 @@ private:
|
||||
|
||||
void init_free_record (record_t *free_rec_p, size_t size, record_t *prev_rec_p);
|
||||
bool is_record_free (record_t *record_p);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* First type identifier that can be used for storage-specific record types
|
||||
@@ -172,7 +182,7 @@ protected:
|
||||
template<
|
||||
typename T, /**< type of record structure */
|
||||
typename ... SizeArgs> /**< type of arguments of T::size */
|
||||
T* alloc_record (record_t::type_t type, /**< record's type identifier */
|
||||
T *alloc_record (record_t::type_t type, /**< record's type identifier */
|
||||
SizeArgs ... size_args) /**< arguments of T::size */
|
||||
{
|
||||
JERRY_ASSERT (type >= _first_type_id);
|
||||
@@ -180,7 +190,7 @@ protected:
|
||||
size_t size = T::size (size_args...);
|
||||
|
||||
record_t *prev_rec_p;
|
||||
T* rec_p = static_cast<T*> (alloc_space_for_record (size, &prev_rec_p));
|
||||
T *rec_p = static_cast<T*> (alloc_space_for_record (size, &prev_rec_p));
|
||||
|
||||
rec_p->set_type (type);
|
||||
rec_p->set_size (size);
|
||||
@@ -191,16 +201,14 @@ protected:
|
||||
return rec_p;
|
||||
} /* alloc_record */
|
||||
|
||||
record_t* alloc_space_for_record (size_t bytes, record_t** out_prev_rec_p);
|
||||
void free_record (record_t* record_p);
|
||||
record_t *alloc_space_for_record (size_t bytes, record_t **out_prev_rec_p);
|
||||
void free_record (record_t *record_p);
|
||||
|
||||
record_t* get_first (void);
|
||||
virtual record_t *get_prev (record_t *rec_p);
|
||||
|
||||
virtual record_t* get_prev (record_t* rec_p);
|
||||
record_t* get_next (record_t* rec_p);
|
||||
virtual void set_prev (record_t* rec_p, record_t *prev_rec_p);
|
||||
virtual void set_prev (record_t *rec_p, record_t *prev_rec_p);
|
||||
|
||||
virtual size_t get_record_size (record_t* rec_p);
|
||||
virtual size_t get_record_size (record_t *rec_p);
|
||||
|
||||
void assert_state_is_correct (void);
|
||||
}; /* rcs_recordset_t */
|
||||
@@ -221,17 +229,109 @@ typedef rcs_record_t::cpointer_t rcs_cpointer_t;
|
||||
class rcs_record_iterator_t
|
||||
{
|
||||
public:
|
||||
rcs_record_iterator_t (rcs_record_t* rec_p);
|
||||
rcs_record_iterator_t (rcs_cpointer_t rec_ext_cp);
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */
|
||||
rcs_record_t *rec_p) /**< record which should belong to the recordset */
|
||||
{
|
||||
_record_start_p = rec_p;
|
||||
_recordset_p = rcs_p;
|
||||
|
||||
reset ();
|
||||
} /* rcs_record_iterator_t */
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
rcs_record_iterator_t (rcs_recordset_t *rcs_p, /**< recordset */
|
||||
rcs_cpointer_t rec_ext_cp) /**< compressed pointer to the record */
|
||||
{
|
||||
_record_start_p = rcs_cpointer_t::decompress (rec_ext_cp);
|
||||
_recordset_p = rcs_p;
|
||||
|
||||
reset ();
|
||||
} /* rcs_record_iterator_t */
|
||||
|
||||
protected:
|
||||
template<typename T> T read (void);
|
||||
template<typename T> void write (T value);
|
||||
/**
|
||||
* Types of access
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
ACCESS_WRITE, /**< If access_type == ACCESS_WRITE,
|
||||
* write 'size' bytes from 'data' buffer to the record. */
|
||||
ACCESS_READ, /**< If access_type == ACCESS_READ,
|
||||
* read 'size' bytes from the record and write to the 'data' buffer. */
|
||||
ACCESS_SKIP /**< If access_type == ACCESS_SKIP,
|
||||
* increment current position so that 'size' bytes would be skipped. */
|
||||
} access_t;
|
||||
|
||||
void access (access_t access_type, void *data, size_t size);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Read value of type T from the record.
|
||||
* After reading iterator doesn't change its position.
|
||||
*
|
||||
* @return read value
|
||||
*/
|
||||
template<typename T> T read (void)
|
||||
{
|
||||
T data;
|
||||
access (ACCESS_READ, &data, sizeof (T));
|
||||
return data;
|
||||
} /* read */
|
||||
|
||||
/**
|
||||
* Write value of type T to the record.
|
||||
* After writing iterator doesn't change its position.
|
||||
*/
|
||||
template<typename T> void write (T value) /**< value to write */
|
||||
{
|
||||
access (ACCESS_WRITE, &value, sizeof (T));
|
||||
} /* write */
|
||||
|
||||
/**
|
||||
* Increment current position to skip T value in the record.
|
||||
*/
|
||||
template<typename T> void skip ()
|
||||
{
|
||||
access (ACCESS_SKIP, NULL, sizeof (T));
|
||||
} /* skip */
|
||||
|
||||
/**
|
||||
* Increment current position to skip 'size' bytes.
|
||||
*/
|
||||
void skip (size_t size) /**< number of bytes to skip */
|
||||
{
|
||||
access (ACCESS_SKIP, NULL, size);
|
||||
} /* skip */
|
||||
|
||||
/**
|
||||
* Check if the end of the record was reached.
|
||||
*
|
||||
* @return true if the whole record was iterated
|
||||
* false otherwise
|
||||
*/
|
||||
bool finished ()
|
||||
{
|
||||
return _current_pos_p == NULL;
|
||||
} /* finished */
|
||||
|
||||
/**
|
||||
* Reset the iterator, so that it points to the beginning of the record
|
||||
*/
|
||||
void reset ()
|
||||
{
|
||||
_current_pos_p = (uint8_t *)_record_start_p;
|
||||
_current_offset = 0;
|
||||
} /* reset */
|
||||
|
||||
private:
|
||||
rcs_record_t* _record_start_p; /**< start of current record */
|
||||
uint8_t* _current_pos_p; /**< pointer to current offset in current record */
|
||||
|
||||
size_t _current_offset; /**< current offset */
|
||||
rcs_recordset_t *_recordset_p; /**< recordset containing the record */
|
||||
}; /* rcs_record_iterator_t */
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ extern "C"
|
||||
// Maximum number of elements in a type-one record
|
||||
#define test_max_type_one_record_elements 64
|
||||
|
||||
// Element size in a type-one record
|
||||
#define test_element_size_type_one_record (sizeof (uint16_t))
|
||||
|
||||
class test_rcs_record_type_one_t : public rcs_record_t
|
||||
{
|
||||
public:
|
||||
@@ -80,7 +83,7 @@ private:
|
||||
static const uint32_t prev_field_width = rcs_cpointer_t::bit_field_width;
|
||||
|
||||
static const size_t header_size = 2 * RCS_DYN_STORAGE_LENGTH_UNIT;
|
||||
static const size_t element_size = sizeof (uint16_t);
|
||||
static const size_t element_size = test_element_size_type_one_record;
|
||||
};
|
||||
|
||||
class test_rcs_record_type_two_t : public rcs_record_t
|
||||
@@ -232,6 +235,7 @@ main (int __attr_unused___ argc,
|
||||
{
|
||||
test_rcs_record_type_one_t *type_one_records[test_sub_iters];
|
||||
uint32_t type_one_record_element_counts[test_sub_iters];
|
||||
uint16_t type_one_record_elements[test_sub_iters][test_max_type_one_record_elements];
|
||||
int type_one_records_number = 0;
|
||||
|
||||
test_rcs_record_type_two_t *type_two_records[test_sub_iters];
|
||||
@@ -249,6 +253,27 @@ main (int __attr_unused___ argc,
|
||||
|
||||
JERRY_ASSERT (type_one_records[type_one_records_number] != NULL);
|
||||
|
||||
rcs_record_iterator_t it (&storage, type_one_records[type_one_records_number]);
|
||||
it.skip<uint32_t> (); // skip header
|
||||
it.skip<uint32_t> (); // skip header
|
||||
for (uint32_t i = 0; i < type_one_record_element_counts[type_one_records_number]; it.skip<uint16_t>(), i++)
|
||||
{
|
||||
uint16_t val = (uint16_t)rand ();
|
||||
type_one_record_elements[type_one_records_number][i] = val;
|
||||
it.write (val);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (type_one_records[type_one_records_number] != NULL);
|
||||
|
||||
it.reset ();
|
||||
it.skip<uint32_t> (); // skip header
|
||||
it.skip<uint32_t> (); // skip header
|
||||
for (uint32_t i = 0; i < type_one_record_element_counts[type_one_records_number]; it.skip<uint16_t>(), i++)
|
||||
{
|
||||
uint16_t val = type_one_record_elements[type_one_records_number][i];
|
||||
JERRY_ASSERT (val == it.read<uint16_t> ());
|
||||
}
|
||||
|
||||
type_one_records_number++;
|
||||
}
|
||||
else
|
||||
@@ -265,6 +290,26 @@ main (int __attr_unused___ argc,
|
||||
|
||||
while (type_one_records_number + type_two_records_number != 0)
|
||||
{
|
||||
// Read test
|
||||
for (int index_to_free = 0; index_to_free < type_one_records_number; index_to_free++)
|
||||
{
|
||||
JERRY_ASSERT (type_one_records_number > 0);
|
||||
|
||||
JERRY_ASSERT (index_to_free >= 0 && index_to_free < type_one_records_number);
|
||||
|
||||
rcs_record_iterator_t it (&storage, type_one_records[index_to_free]);
|
||||
it.skip<uint32_t> (); // skip header
|
||||
it.skip<uint32_t> (); // skip header
|
||||
for (uint32_t i = 0; i < type_one_record_element_counts[index_to_free]; it.skip<uint16_t>(), i++)
|
||||
{
|
||||
uint16_t val = type_one_record_elements[index_to_free][i];
|
||||
JERRY_ASSERT (it.read <uint16_t> () == val);
|
||||
}
|
||||
|
||||
JERRY_ASSERT (JERRY_ALIGNUP (type_one_record_element_counts[index_to_free]*2 + 8, RCS_DYN_STORAGE_ALIGNMENT) ==
|
||||
type_one_records[index_to_free]->get_size ());
|
||||
}
|
||||
|
||||
bool free_type_one;
|
||||
|
||||
if (type_one_records_number == 0)
|
||||
@@ -291,6 +336,16 @@ main (int __attr_unused___ argc,
|
||||
|
||||
JERRY_ASSERT (index_to_free >= 0 && index_to_free < type_one_records_number);
|
||||
|
||||
rcs_record_iterator_t it (&storage, type_one_records[index_to_free]);
|
||||
it.skip<uint32_t> (); // skip header
|
||||
it.skip<uint32_t> (); // skip header
|
||||
for (uint32_t i = 0; i < type_one_record_element_counts[index_to_free]; it.skip<uint16_t>(), i++)
|
||||
{
|
||||
uint16_t val = type_one_record_elements[index_to_free][i];
|
||||
JERRY_ASSERT (it.read <uint16_t> () == val);
|
||||
}
|
||||
|
||||
// free the record
|
||||
storage.free_record_type_one (type_one_records[index_to_free]);
|
||||
|
||||
type_one_records_number--;
|
||||
@@ -298,6 +353,8 @@ main (int __attr_unused___ argc,
|
||||
{
|
||||
type_one_records[index_to_free] = type_one_records[index_to_free + 1];
|
||||
type_one_record_element_counts[index_to_free] = type_one_record_element_counts[index_to_free + 1];
|
||||
memcpy (type_one_record_elements[index_to_free], type_one_record_elements[index_to_free + 1],
|
||||
test_max_type_one_record_elements * test_element_size_type_one_record);
|
||||
|
||||
index_to_free++;
|
||||
}
|
||||
@@ -328,3 +385,9 @@ main (int __attr_unused___ argc,
|
||||
|
||||
return 0;
|
||||
} /* main */
|
||||
|
||||
template test_rcs_record_type_one_t *
|
||||
rcs_recordset_t::alloc_record<test_rcs_record_type_one_t> (rcs_record_t::type_t, uint32_t);
|
||||
|
||||
template test_rcs_record_type_two_t *
|
||||
rcs_recordset_t::alloc_record<test_rcs_record_type_two_t> (rcs_record_t::type_t);
|
||||
|
||||
Reference in New Issue
Block a user