/** @brief Sorts a dynar according to their color assuming elements can have only three colors. * Since there are only three colors, it is linear and much faster than a classical sort. * See for example http://en.wikipedia.org/wiki/Dutch_national_flag_problem * * \param dynar the dynar to sort * \param color the color function of type (int (compar_fn*) (void*) (void*)). The return value of color is assumed to * be 0, 1, or 2. * * At the end of the call, elements with color 0 are at the beginning of the dynar, elements with color 2 are at the * end and elements with color 1 are in the middle. * * Remark: if the elements stored in the dynar are structures, the color function has to retrieve the field to sort * first. */ XBT_PUBLIC(void) xbt_dynar_three_way_partition(xbt_dynar_t const dynar, int_f_pvoid_t color) { unsigned long int i; unsigned long int p = -1; unsigned long int q = dynar->used; const unsigned long elmsize = dynar->elmsize; void *tmp = xbt_malloc(elmsize); void *elm; for (i = 0; i < q;) { void *elmi = _xbt_dynar_elm(dynar, i); int colori = color(elmi); if (colori == 1) { ++i; } else { if (colori == 0) { elm = _xbt_dynar_elm(dynar, ++p); ++i; } else { /* colori == 2 */ elm = _xbt_dynar_elm(dynar, --q); } if (elm != elmi) { memcpy(tmp, elm, elmsize); memcpy(elm, elmi, elmsize); memcpy(elmi, tmp, elmsize); } } } xbt_free(tmp); }
/** @brief Remove a slice of the dynar, sliding the rest of the values to the left * * This function removes an n-sized slice that starts at element idx. It is equivalent to xbt_dynar_remove_at with a * NULL object argument if n equals to 1. * * Each of the removed elements is freed using the free_f function passed at dynar creation. */ void xbt_dynar_remove_n_at(xbt_dynar_t const dynar, const unsigned int n, const int idx) { unsigned long nb_shift; unsigned long offset; unsigned long cur; if (!n) return; _sanity_check_dynar(dynar); _check_inbound_idx(dynar, idx); _check_inbound_idx(dynar, idx + n - 1); if (dynar->free_f) { for (cur = idx; cur < idx + n; cur++) { dynar->free_f(_xbt_dynar_elm(dynar, cur)); } } nb_shift = dynar->used - n - idx; if (nb_shift) { offset = nb_shift * dynar->elmsize; memmove(_xbt_dynar_elm(dynar, idx), _xbt_dynar_elm(dynar, idx + n), offset); } dynar->used -= n; }
/** @brief Remove the Nth dynar's element, sliding the previous values to the left * * Get the Nth element of a dynar, removing it from the dynar and moving * all subsequent values to one position left in the dynar. * * If the object argument of this function is a non-null pointer, the removed * element is copied to this address. If not, the element is freed using the * free_f function passed at dynar creation. */ void xbt_dynar_remove_at(xbt_dynar_t const dynar, const int idx, void *const object) { unsigned long nb_shift; unsigned long offset; _sanity_check_dynar(dynar); _check_inbound_idx(dynar, idx); if (object) { _xbt_dynar_get_elm(object, dynar, idx); } else if (dynar->free_f) { dynar->free_f(_xbt_dynar_elm(dynar, idx)); } nb_shift = dynar->used - 1 - idx; if (nb_shift) { offset = nb_shift * dynar->elmsize; memmove(_xbt_dynar_elm(dynar, idx), _xbt_dynar_elm(dynar, idx + 1), offset); } dynar->used--; }
/** @brief Make room for a new element, and return a pointer to it * * You can then use regular affectation to set its value instead of relying on the slow memcpy. This is what * xbt_dynar_insert_at_as() does. */ void *xbt_dynar_insert_at_ptr(xbt_dynar_t const dynar, const int idx) { void *res; unsigned long old_used; unsigned long new_used; long nb_shift; _sanity_check_dynar(dynar); _sanity_check_idx(idx); old_used = dynar->used; new_used = old_used + 1; _xbt_dynar_expand(dynar, new_used); nb_shift = old_used - idx; if (nb_shift>0) { memmove(_xbt_dynar_elm(dynar, idx + 1), _xbt_dynar_elm(dynar, idx), nb_shift * dynar->elmsize); } dynar->used = new_used; res = _xbt_dynar_elm(dynar, idx); return res; }
inline void *xbt_dynar_set_at_ptr(const xbt_dynar_t dynar, const unsigned long idx) { _sanity_check_dynar(dynar); if (idx >= dynar->used) { _xbt_dynar_expand(dynar, idx + 1); if (idx > dynar->used) { memset(_xbt_dynar_elm(dynar, dynar->used), 0, (idx - dynar->used) * dynar->elmsize); } dynar->used = idx + 1; } return _xbt_dynar_elm(dynar, idx); }
/** @brief Mark the last dynar's element as unused and return a pointer to it. * * You can then use regular affectation to set its value instead of relying on the slow memcpy. This is what * xbt_dynar_pop_as() does. */ inline void *xbt_dynar_pop_ptr(xbt_dynar_t const dynar) { _check_populated_dynar(dynar); XBT_CDEBUG(xbt_dyn, "Pop %p", (void *) dynar); dynar->used--; return _xbt_dynar_elm(dynar, dynar->used); }
/** @brief Merge dynar d2 into d1 * * \param d1 dynar to keep * \param d2 dynar to merge into d1. This dynar is free at end. */ void xbt_dynar_merge(xbt_dynar_t *d1, xbt_dynar_t *d2) { if((*d1)->elmsize != (*d2)->elmsize) xbt_die("Element size must are not equal"); const unsigned long elmsize = (*d1)->elmsize; void *ptr = _xbt_dynar_elm((*d2), 0); _xbt_dynar_resize(*d1, (*d1)->size + (*d2)->size); void *elm = _xbt_dynar_elm((*d1), (*d1)->used); memcpy(elm, ptr, ((*d2)->size)*elmsize); (*d1)->used += (*d2)->used; (*d2)->used = 0; xbt_dynar_free(d2); }
/** @brief Retrieve a pointer to the Nth element of a dynar. * * \param dynar information dealer * \param idx index of the slot we want to retrieve * \return the \a idx-th element of \a dynar. * * \warning The returned value is the actual content of the dynar. * Make a copy before fooling with it. */ inline void *xbt_dynar_get_ptr(const xbt_dynar_t dynar, const unsigned long idx) { void *res; _sanity_check_dynar(dynar); _check_inbound_idx(dynar, idx); res = _xbt_dynar_elm(dynar, idx); return res; }
static XBT_INLINE void _xbt_dynar_get_elm(void *const dst, const xbt_dynar_t dynar, const unsigned long idx) { void *const elm = _xbt_dynar_elm(dynar, idx); memcpy(dst, elm, dynar->elmsize); }
static XBT_INLINE void _xbt_dynar_put_elm(const xbt_dynar_t dynar, const unsigned long idx, const void *const src) { void *const elm = _xbt_dynar_elm(dynar, idx); const unsigned long elmsize = dynar->elmsize; memcpy(elm, src, elmsize); }
/** @brief Returns the position of the element in the dynar (or -1 if not found) * * Beware that if your dynar contains pointed values (such as strings) instead of scalar, this function is probably not * what you want. Check the documentation of xbt_dynar_search() for more info. * * Note that usually, the dynar indices are unsigned integers. If you have more than 2 million elements in your dynar, * this very function will not work (but the other will). */ signed int xbt_dynar_search_or_negative(xbt_dynar_t const dynar, void *const elem) { unsigned long it; for (it = 0; it < dynar->used; it++) if (!memcmp(_xbt_dynar_elm(dynar, it), elem, dynar->elmsize)) { return it; } return -1; }
/** @brief Returns a boolean indicating whether the element is part of the dynar * * Beware that if your dynar contains pointed values (such as strings) instead of scalar, this function is probably not * what you want. Check the documentation of xbt_dynar_search() for more info. */ int xbt_dynar_member(xbt_dynar_t const dynar, void* const elem) { unsigned long it; for (it = 0; it < dynar->used; it++) if (not memcmp(_xbt_dynar_elm(dynar, it), elem, dynar->elmsize)) { return 1; } return 0; }
/** @brief Returns the position of the element in the dynar * * Beware that if your dynar contains pointed values (such as strings) instead of scalar, this function compares the * pointer value, not what's pointed. The only solution to search for a pointed value is then to write the foreach loop * yourself: * \code * signed int position = -1; * xbt_dynar_foreach(dynar, iter, elem) { * if (!memcmp(elem, searched_element, sizeof(*elem))) { * position = iter; * break; * } * } * \endcode * * Raises not_found_error if not found. If you have less than 2 millions elements, you probably want to use * #xbt_dynar_search_or_negative() instead, so that you don't have to TRY/CATCH on element not found. */ unsigned int xbt_dynar_search(xbt_dynar_t const dynar, void *const elem) { unsigned long it; for (it = 0; it < dynar->used; it++) if (!memcmp(_xbt_dynar_elm(dynar, it), elem, dynar->elmsize)) { return it; } THROWF(not_found_error, 0, "Element %p not part of dynar %p", elem, dynar); return -1; // Won't happen, just to please eclipse }
/** @brief Set the Nth element of a dynar (expanded if needed). Previous value is freed * * \param dynar * \param idx * \param object * * Set the Nth element of a dynar, expanding the dynar if needed, AND DO free the previous value at this position. If * you don't want to free the previous content, use xbt_dynar_set(). */ void xbt_dynar_replace(xbt_dynar_t dynar, const unsigned long idx, const void *const object) { _sanity_check_dynar(dynar); if (idx < dynar->used && dynar->free_f) { void *const old_object = _xbt_dynar_elm(dynar, idx); dynar->free_f(old_object); } xbt_dynar_set(dynar, idx, object); }