static QSE_INLINE __utf8_t* get_utf8_slot (qse_wchar_t uc) { #if (QSE_SIZEOF_WCHAR_T == QSE_SIZEOF_MCHAR_T) /* no utf8 support */ return QSE_NULL; /* invalid character */ #else __utf8_t* cur, * end; QSE_ASSERT (QSE_SIZEOF(qse_mchar_t) == 1); QSE_ASSERT (QSE_SIZEOF(qse_wchar_t) >= 2); end = utf8_table + QSE_COUNTOF(utf8_table); cur = utf8_table; while (cur < end) { if (uc >= cur->lower && uc <= cur->upper) return cur; cur++; } return QSE_NULL; /* invalid character */ #endif }
static qse_rex_node_t* pseudo_group (comp_t* c, qse_rex_node_t* atom) { qse_rex_node_t* g, *ge, * b; QSE_ASSERT (atom->occ.min <= 0); g = newgroupnode (c); if (g == QSE_NULL) return QSE_NULL; ge = newgroupendnode (c, g); if (ge == QSE_NULL) return QSE_NULL; b = newbranchnode (c, atom, ge); if (b == QSE_NULL) return QSE_NULL; atom->occ.min = 1; atom->next = ge; QSE_ASSERT (atom->occ.max >= atom->occ.min); g->occ.max = 1; g->occ.min = 1; g->u.g.end = ge; g->u.g.head = b; g->u.g.pseudo = 1; ge->u.ge.pseudo = 1; return g; }
RedBlackTreeNode(const T& value, Color color, SelfType* up, SelfType* left, SelfType* right): value (value), color (color), up (up), left (left), right (right) { QSE_ASSERT (up != this); QSE_ASSERT (left != this); QSE_ASSERT (right != this); }
void clear (bool clear_mpool = false) { while (this->root->notNil()) this->remove_node (this->root); QSE_ASSERT (this->root = this->nil); QSE_ASSERT (this->node_count == 0); if (clear_mpool) this->mp.dispose (); }
qse_size_t qse_mb8towc ( const qse_mchar_t* utf8, qse_size_t size, qse_wchar_t* wc) { QSE_ASSERT (utf8 != QSE_NULL); QSE_ASSERT (size > 0); *wc = *(const qse_uint8_t*)utf8; return 1; }
/// The inject() function inserts a \a datum if no existing datum /// is found to be equal using the comparator. The \a mode argument /// determines what action to take when an equal datum is found. /// - -1: failure /// - 0: do nothing /// - 1: overwrite the existing datum /// /// if \a injected is not #QSE_NULL, it is set to true when \a datum /// has been inserted newly and false when an equal datum has been /// found. /// /// The function returns the poniter to the node inserted or /// affected. It return #QSE_NULL if mode is set to -1 and a duplicate /// item has been found. Node* inject (const T& datum, int mode, bool* injected = QSE_NULL) { Node* x_cur = this->root; Node* x_par = this->nil; while (x_cur->notNil()) { int n = this->comparator (datum, x_cur->value); if (n == 0) { if (injected) *injected = false; if (mode <= -1) return QSE_NULL; // return failure if (mode >= 1) x_cur->value = datum; return x_cur; } x_par = x_cur; if (n > 0) x_cur = x_cur->right; else /* if (n < 0) */ x_cur = x_cur->left; } Node* x_new = new(&this->mp) Node (datum, Node::RED, this->nil, this->nil, this->nil); if (x_par->isNil()) { QSE_ASSERT (this->root->isNil()); this->root = x_new; } else { int n = this->comparator (datum, x_par->value); if (n > 0) { QSE_ASSERT (x_par->right->isNil()); x_par->right = x_new; } else { QSE_ASSERT (x_par->left->isNil()); x_par->left = x_new; } x_new->up = x_par; this->rebalance_for_injection (x_new); } this->root->color = Node::BLACK; this->node_count++; if (injected) *injected = true; // indicate that a new node has been injected return x_new; }
int qse_rex_exec ( qse_rex_t* rex, const qse_cstr_t* str, const qse_cstr_t* substr, qse_cstr_t* matstr) { exec_t e; int n = 0; if (rex->code == QSE_NULL) { rex->errnum = QSE_REX_ENOCOMP; return -1; } QSE_MEMSET (&e, 0, QSE_SIZEOF(e)); e.rex = rex; e.str.ptr = str->ptr; e.str.end = str->ptr + str->len; e.sub.ptr = substr->ptr; e.sub.end = substr->ptr + substr->len; if (init_exec_dds (&e, rex->mmgr) <= -1) return -1; while (e.sub.ptr <= e.sub.end) { n = exec (&e); if (n <= -1) { n = -1; break; } if (n >= 1) { QSE_ASSERT (e.nmatches > 0); QSE_ASSERT (e.matchend != QSE_NULL); if (matstr) { matstr->ptr = e.sub.ptr; matstr->len = e.matchend - e.sub.ptr; } break; } e.sub.ptr++; } fini_exec_dds (&e); return n; }
void qse_subtime (const qse_ntime_t* x, const qse_ntime_t* y, qse_ntime_t* z) { QSE_ASSERT (x->nsec >= 0 && x->nsec < QSE_NSECS_PER_SEC); QSE_ASSERT (y->nsec >= 0 && y->nsec < QSE_NSECS_PER_SEC); z->sec = x->sec - y->sec; z->nsec = x->nsec - y->nsec; if (z->nsec < 0) { z->sec = z->sec - 1; z->nsec = z->nsec + QSE_NSECS_PER_SEC; } }
void qse_addtime (const qse_ntime_t* x, const qse_ntime_t* y, qse_ntime_t* z) { QSE_ASSERT (x->nsec >= 0 && x->nsec < QSE_NSECS_PER_SEC); QSE_ASSERT (y->nsec >= 0 && y->nsec < QSE_NSECS_PER_SEC); z->sec = x->sec + y->sec; z->nsec = x->nsec + y->nsec; if (z->nsec >= QSE_NSECS_PER_SEC) { z->sec = z->sec + 1; z->nsec = z->nsec - QSE_NSECS_PER_SEC; } }
static group_t* dupgroupstackmembers (exec_t* e, group_t* g) { group_t* yg, * xg = QSE_NULL; QSE_ASSERT (g != QSE_NULL); if (g->next != QSE_NULL) { /* TODO: make it non recursive or * implement stack overflow protection */ xg = dupgroupstackmembers (e, g->next); if (xg == QSE_NULL) return QSE_NULL; } yg = (group_t*) QSE_MMGR_ALLOC (e->rex->mmgr, QSE_SIZEOF(*yg)); if (yg == QSE_NULL) { if (xg != QSE_NULL) freegroupstack (xg, e->rex->mmgr); e->rex->errnum = QSE_REX_ENOMEM; return QSE_NULL; } QSE_MEMCPY (yg, g, QSE_SIZEOF(*yg)); yg->next = xg; return yg; }
/* duplidate a group stack excluding the top data element */ static group_t* dupgroupstackpop (exec_t* e, group_t* gs) { group_t* dupg, * head; QSE_ASSERT (gs != QSE_NULL); QSE_ASSERTX (gs->node == QSE_NULL, "The head of a group stack must point to QSE_NULL for management purpose."); QSE_ASSERTX (gs->next != QSE_NULL && gs->next->next != QSE_NULL, "dupgroupstackpop() needs at least two data elements"); dupg = dupgroupstackmembers (e, gs->next->next); if (dupg == QSE_NULL) return QSE_NULL; head = (group_t*) QSE_MMGR_ALLOC (e->rex->mmgr, QSE_SIZEOF(*head)); if (head == QSE_NULL) { if (dupg != QSE_NULL) freegroupstackmembers (dupg, e->rex->mmgr); e->rex->errnum = QSE_REX_ENOMEM; return QSE_NULL; } head->node = QSE_NULL; head->occ = 0; head->next = dupg; return head; }
int operator() (const T& v1, const T& v2) const { if (v1 > v2) return 1; if (v1 < v2) return -1; QSE_ASSERT (v1 == v2); return 0; }
static qse_rex_node_t* newnode (comp_t* c, qse_rex_node_id_t id) { qse_rex_node_t* node; /* TODO: performance optimization. * preallocate a large chunk of memory and allocate a node * from the chunk. increase the chunk if it has been used up. */ node = (qse_rex_node_t*) QSE_MMGR_ALLOC (c->rex->mmgr, QSE_SIZEOF(qse_rex_node_t)); if (node == QSE_NULL) { c->rex->errnum = QSE_REX_ENOMEM; return QSE_NULL; } QSE_MEMSET (node, 0, QSE_SIZEOF(*node)); node->id = id; if (c->start != QSE_NULL) { QSE_ASSERT (c->start->id == QSE_REX_NODE_START); node->link = c->start->u.s.link; c->start->u.s.link = node; } return node; }
static void freegroupstack (group_t* gs, qse_mmgr_t* mmgr) { QSE_ASSERT (gs != QSE_NULL); QSE_ASSERTX (gs->node == QSE_NULL, "The head of a group stack must point to QSE_NULL for management purpose."); freegroupstackmembers (gs, mmgr); }
int qse_tio_attachin ( qse_tio_t* tio, qse_tio_io_impl_t input, qse_mchar_t* bufptr, qse_size_t bufcapa) { qse_mchar_t* xbufptr; if (input == QSE_NULL || bufcapa < QSE_TIO_MININBUFCAPA) { tio->errnum = QSE_TIO_EINVAL; return -1; } if (qse_tio_detachin(tio) <= -1) return -1; QSE_ASSERT (tio->in.fun == QSE_NULL); xbufptr = bufptr; if (xbufptr == QSE_NULL) { xbufptr = QSE_MMGR_ALLOC ( tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa); if (xbufptr == QSE_NULL) { tio->errnum = QSE_TIO_ENOMEM; return -1; } } tio->errnum = QSE_TIO_ENOERR; if (input (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1) { if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER; if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr); return -1; } /* if i defined tio->io[2] instead of tio->in and tio-out, * i would be able to shorten code amount. but fields to initialize * are not symmetric between input and output. * so it's just a bit clumsy that i repeat almost the same code * in qse_tio_attachout(). */ tio->in.fun = input; tio->in.buf.ptr = xbufptr; tio->in.buf.capa = bufcapa; tio->status &= ~(STATUS_INPUT_ILLSEQ | STATUS_INPUT_EOF); tio->inbuf_cur = 0; tio->inbuf_len = 0; if (xbufptr != bufptr) tio->status |= STATUS_INPUT_DYNBUF; return 0; }
void __move_to_next_node () { QSE_ASSERT (this->current != QSE_NULL); while (this->current->notNil()) { if (this->previous == this->current->getUpNode()) { /* the previous node is the parent of the current node. * it indicates that we're going down to the getChild(l) */ if ((this->current->*this->get_left)()->notNil()) { /* go to the left child */ this->previous = this->current; this->current = (this->current->*this->get_left)(); } else { this->pending_action = 1; break; } } else if (this->previous == (this->current->*this->get_left)()) { /* the left child has been already traversed */ this->pending_action = 2; break; } else { /* both the left child and the right child have been traversed */ QSE_ASSERT (this->previous == (this->current->*this->get_right)()); /* just move up to the parent */ this->previous = this->current; this->current = this->current->getUpNode(); } } }
int qse_rex_init (qse_rex_t* rex, qse_mmgr_t* mmgr, qse_rex_node_t* code) { QSE_MEMSET (rex, 0, QSE_SIZEOF(*rex)); rex->mmgr = mmgr; QSE_ASSERT (code == QSE_NULL || code->id == QSE_REX_NODE_START); /* note that passing a compiled expression to qse_rex_open() * is to delegate it to this rex object. when this rex object * is closed, the code delegated is destroyed. */ rex->code = code; return 0; }
static int addsimplecand ( exec_t* e, group_t* group, qse_rex_node_t* node, qse_size_t occ, const qse_char_t* mptr) { cand_t cand; QSE_ASSERT ( node->id == QSE_REX_NODE_NOP || node->id == QSE_REX_NODE_BOL || node->id == QSE_REX_NODE_EOL || node->id == QSE_REX_NODE_ANY || node->id == QSE_REX_NODE_CHAR || node->id == QSE_REX_NODE_CSET ); cand.node = node; cand.occ = occ; cand.group = group; cand.mptr = mptr; if (qse_lda_search ( &e->cand.set[e->cand.pending], 0, &cand, 1) != QSE_LDA_NIL) { /* exclude any existing entries in the array. * see comp_cand() for the equality test used. * note this linear search may be a performance bottle neck * if the arrary grows large. not so sure if it should be * switched to a different data structure such as a hash table. * the problem is that most practical regular expressions * won't have many candidates for a particular match point. * so i'm a bit skeptical about data struct switching. */ return 0; } if (qse_lda_insert ( &e->cand.set[e->cand.pending], QSE_LDA_SIZE(&e->cand.set[e->cand.pending]), &cand, 1) == QSE_LDA_NIL) { e->rex->errnum = QSE_REX_ENOMEM; return -1; } /* the reference must be decremented by the freeer */ refupgroupstack (group); return 0; }
void rebalance_for_injection (Node* node) { while (node != this->root) { Node* tmp, * tmp2, * x_par, * x_grand_par; bool leftwise; x_par = node->up; if (x_par->color == Node::BLACK) break; QSE_ASSERT (x_par->up->notNil()); x_grand_par = x_par->up; if (x_par == x_grand_par->left) { tmp = x_grand_par->right; tmp2 = x_par->right; leftwise = true; } else { tmp = x_grand_par->left; tmp2 = x_par->left; leftwise = false; } if (tmp->color == Node::RED) { x_par->color = Node::BLACK; tmp->color = Node::BLACK; x_grand_par->color = Node::RED; node = x_grand_par; } else { if (node == tmp2) { node = x_par; this->rotate (node, leftwise); x_par = node->up; x_grand_par = x_par->up; } x_par->color = Node::BLACK; x_grand_par->color = Node::RED; this->rotate (x_grand_par, !leftwise); } } }
static int matchtre ( qse_awk_t* awk, qse_tre_t* tre, int opt, const qse_cstr_t* str, qse_cstr_t* mat, qse_cstr_t submat[9], qse_awk_errnum_t* errnum) { int n; /*qse_tre_match_t match[10] = { { 0, 0 }, };*/ qse_tre_match_t match[10]; QSE_MEMSET (match, 0, QSE_SIZEOF(match)); n = qse_tre_execx(tre, str->ptr, str->len, match, QSE_COUNTOF(match), opt); if (n <= -1) { if (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMATCH) return 0; #if 0 /* TODO: */ *errnum = (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMEM)? QSE_AWK_ENOMEM: QSE_AWK_EREXMA; SETERR0 (sed, errnum, loc); #endif *errnum = (QSE_TRE_ERRNUM(tre) == QSE_TRE_ENOMEM)? QSE_AWK_ENOMEM: QSE_AWK_EREXMA; return -1; } QSE_ASSERT (match[0].rm_so != -1); if (mat) { mat->ptr = &str->ptr[match[0].rm_so]; mat->len = match[0].rm_eo - match[0].rm_so; } if (submat) { int i; /* you must intialize submat before you pass into this * function because it can abort filling */ for (i = 1; i < QSE_COUNTOF(match); i++) { if (match[i].rm_so != -1) { submat[i-1].ptr = &str->ptr[match[i].rm_so]; submat[i-1].len = match[i].rm_eo - match[i].rm_so; } } } return 1; }
void qse_xli_seterror ( qse_xli_t* xli, qse_xli_errnum_t errnum, const qse_cstr_t* errarg, const qse_xli_loc_t* errloc) { const qse_char_t* errfmt; xli->errnum = errnum; errfmt = qse_xli_geterrstr(xli)(xli,xli->errnum); QSE_ASSERT (errfmt != QSE_NULL); qse_strxfncpy (xli->errmsg, QSE_COUNTOF(xli->errmsg), errfmt, errarg); if (errloc != QSE_NULL) xli->errloc = *errloc; else QSE_MEMSET (&xli->errloc, 0, QSE_SIZEOF(xli->errloc)); }
static void adjust (rbt_t* rbt, pair_t* pair) { while (pair != rbt->root) { pair_t* tmp, * tmp2, * x_par; int leftwise; x_par = pair->parent; if (x_par->color == QSE_RBT_BLACK) break; QSE_ASSERT (x_par->parent != QSE_NULL); if (x_par == x_par->parent->child[LEFT]) { tmp = x_par->parent->child[RIGHT]; tmp2 = x_par->child[RIGHT]; leftwise = 1; } else { tmp = x_par->parent->child[LEFT]; tmp2 = x_par->child[LEFT]; leftwise = 0; } if (tmp->color == QSE_RBT_RED) { x_par->color = QSE_RBT_BLACK; tmp->color = QSE_RBT_BLACK; x_par->parent->color = QSE_RBT_RED; pair = x_par->parent; } else { if (pair == tmp2) { pair = x_par; rotate (rbt, pair, leftwise); x_par = pair->parent; } x_par->color = QSE_RBT_BLACK; x_par->parent->color = QSE_RBT_RED; rotate (rbt, x_par->parent, !leftwise); } } }
static void freeallnodes (qse_rex_node_t* start) { qse_rex_node_t* x, * y; qse_mmgr_t* mmgr; QSE_ASSERT (start->id == QSE_REX_NODE_START); mmgr = start->u.s.mmgr; x = start->u.s.link; while (x != QSE_NULL) { y = x; x = x->link; freenode (y, mmgr); } QSE_MMGR_FREE (mmgr, start); }
static group_t* groupstackpop (exec_t* e, group_t* gs) { group_t* top; QSE_ASSERT (gs != QSE_NULL); QSE_ASSERTX (gs->node == QSE_NULL, "The head of a group stack must point to QSE_NULL for management purpose."); QSE_ASSERTX (gs->next != QSE_NULL && gs->next->next != QSE_NULL, "groupstackpop() needs at least two data elements"); top = gs->next; gs->next = top->next; QSE_MMGR_FREE (e->rex->mmgr, top); return gs; }
int qse_tio_attachout ( qse_tio_t* tio, qse_tio_io_impl_t output, qse_mchar_t* bufptr, qse_size_t bufcapa) { qse_mchar_t* xbufptr; if (output == QSE_NULL || bufcapa < QSE_TIO_MINOUTBUFCAPA) { tio->errnum = QSE_TIO_EINVAL; return -1; } if (qse_tio_detachout(tio) == -1) return -1; QSE_ASSERT (tio->out.fun == QSE_NULL); xbufptr = bufptr; if (xbufptr == QSE_NULL) { xbufptr = QSE_MMGR_ALLOC ( tio->mmgr, QSE_SIZEOF(qse_mchar_t) * bufcapa); if (xbufptr == QSE_NULL) { tio->errnum = QSE_TIO_ENOMEM; return -1; } } tio->errnum = QSE_TIO_ENOERR; if (output (tio, QSE_TIO_OPEN, QSE_NULL, 0) <= -1) { if (tio->errnum == QSE_TIO_ENOERR) tio->errnum = QSE_TIO_EOTHER; if (xbufptr != bufptr) QSE_MMGR_FREE (tio->mmgr, xbufptr); return -1; } tio->out.fun = output; tio->out.buf.ptr = xbufptr; tio->out.buf.capa = bufcapa; tio->outbuf_len = 0; if (xbufptr != bufptr) tio->status |= STATUS_OUTPUT_DYNBUF; return 0; }
COptional & operator = (COptional const & other) { QSE_ASSERT( !(this == &other) ); // don't copy over self! if (m_bValid) { // first, have to destroy our original. m_bValid = false; // for exception safety if destroy() throws. // (big trouble if destroy() throws, though) destroy(); } if (other.m_bValid) { construct( *other ); m_bValid = true; // order vital. } return *this; }
RedBlackTreeIterator (Node* root, Mode mode): pending_action (0), current (root) { QSE_ASSERT (root != QSE_NULL); this->previous = root->getUpNode(); if (mode == DESCENDING) { this->get_left = &Node::getRightNode; this->get_right = &Node::getLeftNode; } else { this->get_left = &Node::getLeftNode; this->get_right = &Node::getRightNode; } this->__move_to_next_node (); }
static group_t* dupgroupstack (exec_t* e, group_t* gs) { group_t* head; QSE_ASSERT (gs != QSE_NULL); QSE_ASSERTX (gs->node == QSE_NULL, "The head of a group stack must point to QSE_NULL for management purpose."); head = dupgroupstackmembers (e, gs); if (head == QSE_NULL) return QSE_NULL; QSE_ASSERTX ( head->node == QSE_NULL && head->node == gs->node && head->occ == gs->occ, "The duplicated stack head must not be corrupted" ); /* reset the reference count of a duplicated stack */ head->occ = 0; return head; }
static int charset (comp_t* com, qse_rex_node_t* node) { QSE_ASSERT (node->id == QSE_REX_NODE_CSET); QSE_ASSERT (node->u.cset.negated == 0); QSE_ASSERT (node->u.cset.member == QSE_NULL); if (IS_SPE(com,QSE_T('^'))) { /* negate an expression */ node->u.cset.negated = 1; if (getc_noesc(com) <= -1) return -1; } /* initialize the member array */ node->u.cset.member = qse_str_open (com->rex->mmgr, 0, 64); if (node->u.cset.member == QSE_NULL) { com->rex->errnum = QSE_REX_ENOMEM; return -1; } /* if ] is the first character or the second character following ^, * it is treated literally */ do { int x1, x2; qse_char_t c1, c2; x1 = com->c.escaped; c1 = com->c.value; if (c1 == QSE_CHAR_EOF) { com->rex->errnum = QSE_REX_EPREEND; return -1; } if (getc_esc(com) <= -1) return -1; x2 = com->c.escaped; c2 = com->c.value; if (!x1 && c1 == QSE_T('[') && !x2 && c2 == QSE_T(':')) { int n; qse_char_t tmp[2]; /* begins with [: * don't read in the next character as charclass() * matches a class name differently from other routines. * if (getc_noesc(com) <= -1) return -1; */ if ((n = charclass(com)) <= -1) return -1; QSE_ASSERT (n < QSE_TYPE_MAX(qse_char_t)); tmp[0] = QSE_REX_CSET_CLASS; tmp[1] = n; ADD_CSET_CODE (com, node, tmp, QSE_COUNTOF(tmp)); } else if (!x2 && c2 == QSE_T('-')) { if (getc_esc(com) <= -1) return -1; if (IS_SPE(com, QSE_T(']'))) { qse_char_t tmp[4]; /* '-' is the last character in the set. * treat it literally */ tmp[0] = QSE_REX_CSET_CHAR; tmp[1] = c1; tmp[2] = QSE_REX_CSET_CHAR; tmp[3] = c2; ADD_CSET_CODE (com, node, tmp, QSE_COUNTOF(tmp)); break; } if (c1 > com->c.value) { /* range end must be >= range start */ com->rex->errnum = QSE_REX_ECRANGE; return -1; } else if (c1 == com->c.value) { /* if two chars in the range are the same, * treat it as a single character */ qse_char_t tmp[2]; tmp[0] = QSE_REX_CSET_CHAR; tmp[1] = c1; ADD_CSET_CODE (com, node, tmp, QSE_COUNTOF(tmp)); } else { qse_char_t tmp[3]; tmp[0] = QSE_REX_CSET_RANGE; tmp[1] = c1; tmp[2] = com->c.value; ADD_CSET_CODE (com, node, tmp, QSE_COUNTOF(tmp)); } if (getc_esc(com) <= -1) return -1; } else { qse_char_t tmp[2]; tmp[0] = QSE_REX_CSET_CHAR; tmp[1] = c1; ADD_CSET_CODE (com, node, tmp, QSE_COUNTOF(tmp)); } } while (!IS_SPE(com,QSE_T(']'))); if (getc_esc(com) <= -1) return -1; return 0; }
static void refdowngroupstack_incand (qse_lda_t* lda, void* dptr, qse_size_t dlen) { QSE_ASSERT (dlen == 1); refdowngroupstack (((cand_t*)dptr)->group, lda->mmgr); }