mirror of
https://github.com/jerryscript-project/jerryscript.git
synced 2025-12-15 16:29:21 +00:00
Add utf-8 processing routines. Change ecma_char_t from char/uint16_t to uint16_t. Apply all utf-8 processing routines. Change char to jerry_api_char in API functions' declarations. JerryScript-DCO-1.0-Signed-off-by: Andrey Shitov a.shitov@samsung.com
385 lines
9.6 KiB
C++
385 lines
9.6 KiB
C++
/* Copyright 2015 Samsung Electronics Co., Ltd.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef RCS_RECORDSET_H
|
|
#define RCS_RECORDSET_H
|
|
|
|
#include <string.h>
|
|
|
|
#include "jrt.h"
|
|
#include "jrt-bit-fields.h"
|
|
#include "mem-allocator.h"
|
|
#include "rcs-chunked-list.h"
|
|
|
|
/** \addtogroup recordset Recordset
|
|
* @{
|
|
*
|
|
* Non-contiguous container abstraction with iterator.
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* Logarithm of a dynamic storage unit alignment
|
|
*/
|
|
#define RCS_DYN_STORAGE_ALIGNMENT_LOG (2u)
|
|
|
|
/**
|
|
* Dynamic storage unit alignment
|
|
*/
|
|
#define RCS_DYN_STORAGE_ALIGNMENT (1ull << RCS_DYN_STORAGE_ALIGNMENT_LOG)
|
|
|
|
/**
|
|
* Unit of length
|
|
*
|
|
* See also:
|
|
* rcs_dyn_storage_length_t
|
|
*/
|
|
#define RCS_DYN_STORAGE_LENGTH_UNIT (4u)
|
|
|
|
/**
|
|
* Dynamic storage
|
|
*
|
|
* Note:
|
|
* Static C++ constructors / desctructors are supposed to be not supported.
|
|
* So, initialization / destruction is implemented through init / finalize
|
|
* static functions.
|
|
*/
|
|
class rcs_recordset_t
|
|
{
|
|
public:
|
|
/* Constructor */
|
|
void init (void)
|
|
{
|
|
_chunk_list.init ();
|
|
|
|
JERRY_ASSERT (_chunk_list.get_data_space_size () % RCS_DYN_STORAGE_LENGTH_UNIT == 0);
|
|
} /* init */
|
|
|
|
/* Destructor */
|
|
void finalize (void)
|
|
{
|
|
_chunk_list.free ();
|
|
} /* finalize */
|
|
|
|
/* Free memory occupied by the dynamic storage */
|
|
void cleanup (void)
|
|
{
|
|
_chunk_list.cleanup ();
|
|
} /* cleanup */
|
|
|
|
/**
|
|
* Record type
|
|
*/
|
|
class record_t
|
|
{
|
|
public:
|
|
typedef uint8_t type_t;
|
|
|
|
type_t get_type (void) const;
|
|
void set_type (type_t type);
|
|
|
|
/**
|
|
* Dynamic storage-specific extended compressed pointer
|
|
*
|
|
* Note:
|
|
* the pointer can represent addresses aligned by RCS_DYN_STORAGE_ALIGNMENT,
|
|
* while mem_cpointer_t can only represent addressed aligned by MEM_ALIGNMENT.
|
|
*/
|
|
struct cpointer_t
|
|
{
|
|
static const uint32_t bit_field_width = MEM_CP_WIDTH + MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_ALIGNMENT_LOG;
|
|
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
mem_cpointer_t base_cp : MEM_CP_WIDTH; /**< pointer to base of addressed area */
|
|
#if MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_ALIGNMENT_LOG
|
|
uint16_t ext : (MEM_ALIGNMENT_LOG - RCS_DYN_STORAGE_ALIGNMENT_LOG); /**< extension of the basic
|
|
* compressed pointer
|
|
* used for more detailed
|
|
* addressing */
|
|
#endif /* MEM_ALIGNMENT_LOG > RCS_DYN_STORAGE_ALIGNMENT_LOG */
|
|
} value;
|
|
uint16_t packed_value;
|
|
};
|
|
|
|
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:
|
|
/**
|
|
* Offset of 'type' field, in bits
|
|
*/
|
|
static const uint32_t _type_field_pos = 0u;
|
|
|
|
/**
|
|
* Width of 'type' field, in bits
|
|
*/
|
|
static const uint32_t _type_field_width = 4u;
|
|
|
|
protected:
|
|
void check_this (void) const;
|
|
|
|
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;
|
|
void set_pointer (uint32_t field_pos, uint32_t field_width, record_t* pointer_p);
|
|
|
|
/**
|
|
* Offset of a derived record's fields, in bits
|
|
*/
|
|
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;
|
|
|
|
/**
|
|
* Type identifier for free record
|
|
*/
|
|
static const record_t::type_t _free_record_type_id = 0;
|
|
|
|
/**
|
|
* Chunked list used for memory allocation
|
|
*/
|
|
rcs_chunked_list_t _chunk_list;
|
|
|
|
void alloc_record_in_place (record_t* place_p,
|
|
size_t free_size,
|
|
record_t* next_record_p);
|
|
|
|
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
|
|
*/
|
|
static const record_t::type_t _first_type_id = _free_record_type_id + 1;
|
|
|
|
/**
|
|
* Allocate new record of specified type
|
|
*
|
|
* @return pointer to the new record
|
|
*/
|
|
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 */
|
|
SizeArgs ... size_args) /**< arguments of T::size */
|
|
{
|
|
JERRY_ASSERT (type >= _first_type_id);
|
|
|
|
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));
|
|
|
|
rec_p->set_type (type);
|
|
rec_p->set_size (size);
|
|
rec_p->set_prev (prev_rec_p);
|
|
|
|
assert_state_is_correct ();
|
|
|
|
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);
|
|
|
|
virtual record_t *get_prev (record_t *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);
|
|
|
|
void assert_state_is_correct (void);
|
|
}; /* rcs_recordset_t */
|
|
|
|
/**
|
|
* Record type
|
|
*/
|
|
typedef rcs_recordset_t::record_t rcs_record_t;
|
|
|
|
/**
|
|
* Recordset-specific compressed pointer type
|
|
*/
|
|
typedef rcs_record_t::cpointer_t rcs_cpointer_t;
|
|
|
|
/**
|
|
* Record iterator
|
|
*/
|
|
class rcs_record_iterator_t
|
|
{
|
|
public:
|
|
/**
|
|
* 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:
|
|
/**
|
|
* 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 */
|
|
{
|
|
if (size)
|
|
{
|
|
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 */
|
|
|
|
/**
|
|
* Free record layout description
|
|
*/
|
|
class rcs_free_record_t : public rcs_record_t
|
|
{
|
|
public:
|
|
size_t get_size (void) const;
|
|
void set_size (size_t size);
|
|
|
|
rcs_record_t* get_prev (void) const;
|
|
void set_prev (rcs_record_t* prev_rec_p);
|
|
private:
|
|
/**
|
|
* Offset of 'length' field, in bits
|
|
*/
|
|
static const uint32_t _length_field_pos = _fields_offset_begin;
|
|
|
|
/**
|
|
* Width of 'length' field, in bits
|
|
*/
|
|
static const uint32_t _length_field_width = 12u;
|
|
|
|
/**
|
|
* Offset of 'previous record' field, in bits
|
|
*/
|
|
static const uint32_t _prev_field_pos = _length_field_pos + _length_field_width;
|
|
|
|
/**
|
|
* Width of 'previous record' field, in bits
|
|
*/
|
|
static const uint32_t _prev_field_width = rcs_cpointer_t::bit_field_width;
|
|
};
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
#endif /* RCS_RECORDSET_H */
|