Ejemplo n.º 1
0
static value_t listify_chunk( zone_t zone, value_t chunk )
{
	value_t out = &list_empty;
	while (chunk_can_shrink( chunk )) {
		out = METHOD_1( out, sym_append, chunk_head( chunk ) );
		chunk = chunk_pop( zone, chunk );
	}
	out = METHOD_1( out, sym_append, chunk_head( chunk ) );
	return out;
}
Ejemplo n.º 2
0
static value_t List_push( PREFUNC, value_t listObj, value_t value )
{
	ARGCHECK_2( listObj, value );
	value_t head_chunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
	value_t cold_storage = listObj->slots[LIST_COLD_STORAGE_SLOT];
	value_t tail_chunk = listObj->slots[LIST_TAIL_CHUNK_SLOT];

	// If our head chunk has space remaining, push this value onto it. If the
	// chunk is full, we will push it onto the cold storage list and create a
	// new, one-element chunk for the new value, which becomes our head chunk.
	// This way the cold storage is a list of chunks, not a list of values.
	if (!chunk_can_grow( head_chunk )) {
		// Pushing a chunk onto cold storage is a potentially O(log n)
		// operation, as is popping a chunk. Therefore instead of pushing the
		// whole chunk, we will push only the last three elements. Our new
		// head chunk will include the new value and the previous head. This
		// way, an inexpensive pop always follows an expensive push, and vice
		// versa, which is how we get amortized O(1) performance.
		value_t pushable = chunk_pop( zone, head_chunk );
		cold_storage = METHOD_1( cold_storage, sym_push, pushable );
		head_chunk = chunk_alloc_1( zone, chunk_head( head_chunk ) );
	}
	// Push the new value onto our head chunk, which may or may not have been
	// freshly created for the purpose.
	head_chunk = chunk_push( zone, head_chunk, value );

	return alloc_list( zone, head_chunk, cold_storage, tail_chunk );
}
Ejemplo n.º 3
0
static value_t List_head( PREFUNC, value_t listObj )
{
	ARGCHECK_1( listObj );
	// Head is always element zero of our left chunk, which must never be
	// empty - if we were going to have an empty chunk we would have to demote
	// ourselves to a single-element list.
	value_t chunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
	return chunk_head( chunk );
}
Ejemplo n.º 4
0
static value_t List_pop( PREFUNC, value_t listObj )
{
	ARGCHECK_1( listObj );
	value_t head_chunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
	value_t cold_storage = listObj->slots[LIST_COLD_STORAGE_SLOT];
	value_t tail_chunk = listObj->slots[LIST_TAIL_CHUNK_SLOT];

	// Remove the head element from this list. If our head chunk is not minimal,
	// we can just pop the value from the head chunk and continue on. Otherwise,
	// popping the value from the head chunk will empty it, and then we must
	// pull a new chunk from our cold storage. If the cold storage is empty, we
	// will try to cannibalize an element from the tail chunk. But if the tail
	// chunk is minimal, that means we have only one element left, which means
	// we should drop back down to single-element list mode.
	if (chunk_can_shrink( head_chunk )) {
		head_chunk = chunk_pop( zone, head_chunk );
	}
	else {
		// We need a new head chunk. If cold storage is not empty, get a chunk
		// from cold storage and call it our new head.
		value_t empty_val = METHOD_0( cold_storage, sym_is_empty );
		if (!BoolFromBoolean( zone, empty_val )) {
			// The cold storage is not empty. yay, get a chunk from it.
			head_chunk = METHOD_0( cold_storage, sym_head );
			cold_storage = METHOD_0( cold_storage, sym_pop );
		}
		else if (chunk_can_shrink( tail_chunk )) {
			// Cold storage is empty, but there are still items left on our
			// tail. We'll poach one item from the tail and put it on our head.
			head_chunk = chunk_alloc_1( zone, chunk_head( tail_chunk ) );
			tail_chunk = chunk_pop( zone, tail_chunk );
		}
		else {
			// Cold storage is empty and the tail chunk is already minimal.
			// This means we have only one value left, which means we should
			// drop back to single-item mode.
			return AllocSingleItemList( zone, chunk_head( tail_chunk ) );
		}
	}

	return alloc_list( zone, head_chunk, cold_storage, tail_chunk );
}
Ejemplo n.º 5
0
        static int32_t header(AsyncState* pState, int32_t n)
        {
            asyncReadFrom* pThis = (asyncReadFrom*)pState;

            if (pThis->m_strLine.length() > 0) {
                if (!qstricmp(pThis->m_strLine.c_str(), "content-length:", 15)) {
                    pThis->m_contentLength = atoi(pThis->m_strLine.c_str() + 15);

                    if ((pThis->m_contentLength < 0)
                        || (pThis->m_pThis->m_maxBodySize >= 0
                               && pThis->m_contentLength > pThis->m_pThis->m_maxBodySize * 1024 * 1024))
                        return CHECK_ERROR(Runtime::setError("HttpMessage: body is too huge."));
                } else if (!qstricmp(pThis->m_strLine.c_str(),
                               "transfer-encoding:", 18)) {
                    _parser p(pThis->m_strLine.c_str() + 18,
                        (int32_t)pThis->m_strLine.length() - 18);

                    p.skipSpace();
                    if (qstricmp(p.now(), "chunked"))
                        return CHECK_ERROR(Runtime::setError("HttpMessage: unknown transfer-encoding."));

                    pThis->m_bChunked = true;
                } else {
                    result_t hr = pThis->m_pThis->addHeader(pThis->m_strLine);
                    if (hr < 0)
                        return hr;

                    pThis->m_headCount++;
                    if (pThis->m_headCount > pThis->m_pThis->m_maxHeadersCount)
                        return CHECK_ERROR(Runtime::setError("HttpMessage: too many headers."));
                }

                return pThis->m_stm->readLine(HTTP_MAX_LINE, pThis->m_strLine,
                    pThis);
            }

            if (pThis->m_bChunked) {
                if (pThis->m_contentLength)
                    return CHECK_ERROR(CALL_E_INVALID_DATA);

                pThis->m_pThis->get_body(pThis->m_body);
                return chunk_head(pState, n);
            }

            if (pThis->m_contentLength > 0) {
                pThis->m_pThis->get_body(pThis->m_body);

                pThis->set(body);
                return pThis->m_stm->copyTo(pThis->m_body,
                    pThis->m_contentLength, pThis->m_copySize, pThis);
            }

            return pThis->done();
        }
Ejemplo n.º 6
0
static value_t List_concatenate(
		PREFUNC, value_t listObj, value_t otherList )
{
	ARGCHECK_2( listObj, otherList );
	// If the list to be concatenated is also a multi-item list, we will do an
	// efficient concatenation by taking advantage of our knowledge of its
	// internal structure. Otherwise, we will hope it is a sequence and append
	// each of its items.
	if (otherList->function == (function_t)List_function) {
		value_t ourHeadChunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
		value_t ourColdStorage = listObj->slots[LIST_COLD_STORAGE_SLOT];
		value_t ourTailChunk = listObj->slots[LIST_TAIL_CHUNK_SLOT];
		value_t otherHeadChunk = otherList->slots[LIST_HEAD_CHUNK_SLOT];
		value_t otherColdStorage = otherList->slots[LIST_COLD_STORAGE_SLOT];
		value_t otherTailChunk = otherList->slots[LIST_TAIL_CHUNK_SLOT];
		// We need to put these chunks into cold storage somehow. There are
		// enough possibilities that it would be tedious to do it all with if-
		// statements. Instead, we have this matrix, which will map each of the
		// sixteen possible combinations down to one of six actions. The
		// horizontal axis represents the size of the other list's head chunk;
		// the vertical axis represents the size of our list's tail chunk.
		int actions[4][4] = {
			{0, 1, 2, 2},
			{0, 4, 4, 2},
			{3, 4, 4, 5},
			{3, 3, 5, 5}};
		int x_size = chunk_item_count(otherHeadChunk);
		int y_size = chunk_item_count(ourTailChunk);
		switch(actions[y_size][x_size]) {
			case 0: {
				// Append other chunk's head to our chunk. Append our chunk to
				// our cold storage; let the other chunk drop.
				value_t item = chunk_head( otherHeadChunk );
				ourTailChunk = chunk_append( zone, ourTailChunk, item );
				ourColdStorage = 
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
			} break;
			case 1: {
				// Push our chunk's tail onto the other chunk. Push the other
				// chunk onto its cold storage, then let ours drop.
				value_t item = chunk_tail( zone, ourTailChunk );
				otherHeadChunk = chunk_push( zone, otherHeadChunk, item );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 2: {
				// Append other chunk's head to our chunk. Append our chunk to
				// our cold storage and push the other chunk onto its.
				value_t item = chunk_head( otherHeadChunk );
				otherHeadChunk = chunk_pop( zone, otherHeadChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
				ourTailChunk = chunk_append( zone, ourTailChunk, item );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
			} break;
			case 3: {
				// Push our chunk's tail onto the other chunk. Put each chunk
				// into its own cold storage.
				value_t item = chunk_tail( zone, ourTailChunk );
				ourTailChunk = chunk_chop( zone, ourTailChunk );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
				otherHeadChunk = chunk_push( zone, otherHeadChunk, item );
				otherColdStorage = 
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 4: {
				// Put each chunk into its own cold storage.
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 5: {
				// Split one item off of each chunk to create a new middle
				// chunk. Put each original chunk onto its own list, then add
				// the middle chunk to our cold storage.
				value_t item = chunk_tail( zone, ourTailChunk );
				ourTailChunk = chunk_chop( zone, ourTailChunk );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );

				value_t midChunk = chunk_alloc_1( zone, item );
				item = chunk_head( otherHeadChunk );
				otherHeadChunk = chunk_pop( zone, otherHeadChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );

				midChunk = chunk_append( zone, midChunk, item );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, midChunk );
			} break;
		}
		// Having dealt with the active chunks, we now have a head chunk for
		// the whole list, a tail chunk for the whole list, and two cold
		// storage lists. We will recursively concatenate the cold storage
		// lists, then assemble our output list from these pieces.
		value_t combined_storage =
			METHOD_1( ourColdStorage, sym_concatenate, otherColdStorage );
		listObj = alloc_list(
				zone, ourHeadChunk, combined_storage, otherTailChunk );
	}
	else {
		value_t iter = METHOD_0( otherList, sym_iterate );
		if (IsAnException( iter )) return iter;
		while (BoolFromBoolean( zone, METHOD_0( iter, sym_is_valid ) )) {
			value_t val = METHOD_0( iter, sym_current );
			listObj = METHOD_1( listObj, sym_append, val );
			iter = METHOD_0( iter, sym_next );
		}
	}
	return listObj;
}