base/list/m_list.c
/* Function for operations relating to values:
 *   - count
 *   - remove
 *   - replace
 */
Function for operations relating to values:
- count
- remove
- replace
Function for operations relating to values : - count - remove - replace
static size_t M_list_match_op_val_int(M_list_t *d, const void *val, const void *new_val, M_list_match_type_t type, M_list_match_op_t match_op)
{
	void                 *ptr = NULL;
	size_t                idx;
	size_t                start;
	size_t                end;
	size_t                i;
	size_t                cnt = 0;
	M_list_insert_type_t  insert_type;
	if (d == NULL || val == NULL || d->elements == 0 || (!(type & M_LIST_MATCH_PTR) && d->equality == NULL) ||
		(match_op == M_LIST_MATCH_OP_REPLACE &&
			(new_val == NULL || (type & M_LIST_MATCH_PTR && val == new_val) ||
			(!(type & M_LIST_MATCH_PTR) && d->equality(&val, &new_val, d->thunk) == 0))))
	{
		return 0;
	}
	if (match_op == M_LIST_MATCH_OP_REPLACE && 
		(d->flags & (M_LIST_SET_VAL|M_LIST_SET_PTR) &&
			M_list_index_of(d, new_val, (d->flags&M_LIST_SET_PTR)?M_LIST_MATCH_PTR:M_LIST_MATCH_VAL, NULL)))
	{
		match_op = M_LIST_MATCH_OP_REMOVE;
	}
	if ((d->flags & M_LIST_SORTED) && !d->multi_insert) {
		if (!M_list_index_of(d, val, type, &idx)) {
			return 0;
		}
		start = idx;
		end   = idx;
		cnt   = 1;
		if ((type & M_LIST_MATCH_ALL) || match_op == M_LIST_MATCH_OP_COUNT) {
			for (i=idx+1; i<d->elements; i++) {
				if (d->equality(&val, &d->start[i], d->thunk) != 0) {
					break;
				}
				if (type & M_LIST_MATCH_PTR) {
					if (val == d->start[i]) {
						if (match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE) {
							M_list_remove_at(d, i);
							i--;
						}
						cnt++;
					}
				} else {
					end = i;
				}
			}
			for (i=idx; i-->0; ) {
				if (d->equality(&val, &d->start[i], d->thunk) != 0) {
					break;
				}
				if (type & M_LIST_MATCH_PTR) {
					if (val == d->start[i]) {
						if (match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE) {
							M_list_remove_at(d, i);
						}
						cnt++;
					}
				} else {
					start = i;
				}
			}
		}
		if (!(type & M_LIST_MATCH_PTR)) {
			cnt += end-start;
		}
		if (match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE) {
			M_list_remove_range(d, start, end);
		}
		if (match_op == M_LIST_MATCH_OP_REPLACE) {
			ptr         = d->duplicate_insert(new_val);
			insert_type = M_LIST_INSERT_INITIAL|M_LIST_INSERT_NODUP|M_LIST_INSERT_NOSETCHECK;
			idx         = M_list_convert_idx_insert(d, M_list_insert_idx(d, ptr));
			for (i=0; i<cnt; i++) {
				if (i > 0) {
					ptr         = d->duplicate_copy(ptr);
					insert_type = M_LIST_INSERT_NODUP|M_LIST_INSERT_NOSETCHECK;
					idx++;
				}
				if (!M_list_insert_at_int(d, ptr, idx, insert_type)) {
					d->value_free(ptr);
					break;
				}
			}
		}
		return cnt;
	}
	for (i=d->elements; i-->0; ) {
		if ((!(type & M_LIST_MATCH_PTR) && d->equality(&val, &d->start[i], d->thunk) == 0) || (type & M_LIST_MATCH_PTR && val == d->start[i])) {
			if (match_op == M_LIST_MATCH_OP_REPLACE) {
				if (cnt == 0) {
					ptr = d->duplicate_insert(new_val);
				} else {
					ptr = d->duplicate_copy(ptr);
				}
				d->value_free(d->start[i]);
				d->start[i] = ptr;
			} else if (match_op == M_LIST_MATCH_OP_REMOVE) {
				M_list_remove_at(d, i);
			}
			cnt++;
		}
		if (cnt == 1 && !(type & M_LIST_MATCH_ALL) && match_op != M_LIST_MATCH_OP_COUNT) {
			break;
		}
	}
	return cnt;
}
static size_t M_list_match_op_val_int ( M_list_t * d , const void * val , const void * new_val , M_list_match_type_t type , M_list_match_op_t match_op ) { void * ptr = NULL ; size_t idx ; size_t start ; size_t end ; size_t i ; size_t cnt = 0 ; M_list_insert_type_t insert_type ; if ( d == NULL || val == NULL || d -> elements == 0 || ( ! ( type & M_LIST_MATCH_PTR ) && d -> equality == NULL ) || ( match_op == M_LIST_MATCH_OP_REPLACE && ( new_val == NULL || ( type & M_LIST_MATCH_PTR && val == new_val ) || ( ! ( type & M_LIST_MATCH_PTR ) && d -> equality ( & val , & new_val , d -> thunk ) == 0 ) ) ) ) { return 0 ; } if ( match_op == M_LIST_MATCH_OP_REPLACE && ( d -> flags & ( M_LIST_SET_VAL | M_LIST_SET_PTR ) && M_list_index_of ( d , new_val , ( d -> flags & M_LIST_SET_PTR ) ? M_LIST_MATCH_PTR : M_LIST_MATCH_VAL , NULL ) ) ) { match_op = M_LIST_MATCH_OP_REMOVE ; } if ( ( d -> flags & M_LIST_SORTED ) && ! d -> multi_insert ) { if ( ! M_list_index_of ( d , val , type , & idx ) ) { return 0 ; } start = idx ; end = idx ; cnt = 1 ; if ( ( type & M_LIST_MATCH_ALL ) || match_op == M_LIST_MATCH_OP_COUNT ) { for ( i = idx + 1 ; i < d -> elements ; i ++ ) { if ( d -> equality ( & val , & d -> start [ i ] , d -> thunk ) != 0 ) { break ; } if ( type & M_LIST_MATCH_PTR ) { if ( val == d -> start [ i ] ) { if ( match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE ) { M_list_remove_at ( d , i ) ; i -- ; } cnt ++ ; } } else { end = i ; } } for ( i = idx ; i -- > 0 ; ) { if ( d -> equality ( & val , & d -> start [ i ] , d -> thunk ) != 0 ) { break ; } if ( type & M_LIST_MATCH_PTR ) { if ( val == d -> start [ i ] ) { if ( match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE ) { M_list_remove_at ( d , i ) ; } cnt ++ ; } } else { start = i ; } } } if ( ! ( type & M_LIST_MATCH_PTR ) ) { cnt += end - start ; } if ( match_op == M_LIST_MATCH_OP_REMOVE || match_op == M_LIST_MATCH_OP_REPLACE ) { M_list_remove_range ( d , start , end ) ; } if ( match_op == M_LIST_MATCH_OP_REPLACE ) { ptr = d -> duplicate_insert ( new_val ) ; insert_type = M_LIST_INSERT_INITIAL | M_LIST_INSERT_NODUP | M_LIST_INSERT_NOSETCHECK ; idx = M_list_convert_idx_insert ( d , M_list_insert_idx ( d , ptr ) ) ; for ( i = 0 ; i < cnt ; i ++ ) { if ( i > 0 ) { ptr = d -> duplicate_copy ( ptr ) ; insert_type = M_LIST_INSERT_NODUP | M_LIST_INSERT_NOSETCHECK ; idx ++ ; } if ( ! M_list_insert_at_int ( d , ptr , idx , insert_type ) ) { d -> value_free ( ptr ) ; break ; } } } return cnt ; } for ( i = d -> elements ; i -- > 0 ; ) { if ( ( ! ( type & M_LIST_MATCH_PTR ) && d -> equality ( & val , & d -> start [ i ] , d -> thunk ) == 0 ) || ( type & M_LIST_MATCH_PTR && val == d -> start [ i ] ) ) { if ( match_op == M_LIST_MATCH_OP_REPLACE ) { if ( cnt == 0 ) { ptr = d -> duplicate_insert ( new_val ) ; } else { ptr = d -> duplicate_copy ( ptr ) ; } d -> value_free ( d -> start [ i ] ) ; d -> start [ i ] = ptr ; } else if ( match_op == M_LIST_MATCH_OP_REMOVE ) { M_list_remove_at ( d , i ) ; } cnt ++ ; } if ( cnt == 1 && ! ( type & M_LIST_MATCH_ALL ) && match_op != M_LIST_MATCH_OP_COUNT ) { break ; } } return cnt ; }
Function for operations relating to values:
   - count
   - remove
   - replace
Function for operations relating to values : - count - remove - replace
/* If we're replacing in a SET and the replace value already exists in the list we can't add it so we'll turn
 	 * the replace into a remove */ /* Sorted.
 	 *
	 * Logic for Remove:
	 *   - Use index_of to find a matching element. This works with both values and pointer match types.
	 *   - If index_of doesn't find a match then the value doesn't exist in the list and we're done.
	 *   - index_of gives us 1 match. However, it does not guarantee where it is. Meaning if there are
	 *     three matching elements index_of could give us any of them.
	 *   - Being sorted we're guaranteed that all of the matching values are adjacent. So we can determine
	 *     a range to remove for all values when matching values only
	 *   - However, we're not guaranteed that matching pointers are adjacent. So we cannot determine
	 *     a range to remove for all values when matching pointers.
	 *   - Look at elements before and after until we hit an element that doesn't match the value.
	 *   - When matching values we'll track the first and last element we found in the list and remove the range.
	 *   - When matching pointers we'll remove them as we encounter them.
	 *
	 * Logic for Replace:
	 *   - Follow Remove logic.
	 *   - Since the elements are sorted replacing doesn't necessarily mean the new value will be in the same
	 *     place as the old.
	 *   - We know how many elements we've removed so we'll add that may to the list.
	 */ /* We're using index_of here as a convience. It will ensure we either have a match or not. */ /* Even if we're matching pointers the idx will be correct due to using index_of. */ /* Look for matches after. */ /* look for matches before. */ /* Add the matched range of elements to the count when matching values. */ /* Remove the values. This will remove the range of values when not matching pointers. When matching
 		 * pointers we've already removed the matches as we found them because they may not have been adjacent. */ /* If we're replacing add the new value the number of times val was removed. */ /* Same value and sorted so the inserted values should all be together. */ /* Copy the already-inserted value rather than calling duplicate_insert()
					 * again as duplicate_insert() may just be a direct pointer cast */ /* Put the value after the last one that was inserted. This ensures if we're inserting
 					 * at the end we continue to do so and prevent M_mem_moves. */ /* Not sorted. */ /* Copy the already-inserted value rather than calling duplicate_insert()
					 * again as duplicate_insert() may just be a direct pointer cast */ /* Stop after the first removal/replacement if not dealing with all and not counting. */