diff --git a/library/include/MiscUtils.h b/library/include/MiscUtils.h index 8959a766b..05be881ee 100644 --- a/library/include/MiscUtils.h +++ b/library/include/MiscUtils.h @@ -66,36 +66,116 @@ void print_bits ( T val, DFHack::Console& out ) out.print(strs.str().c_str()); } -//FIXME: Error 8 error C4519: default template arguments are only allowed on a class template -template -CT *binsearch_in_vector(std::vector &vec, FT CT::*field, AT value) +/* + * Binary search in vectors. + */ + +template +int binsearch_index(const std::vector &vec, FT key, bool exact = true) +{ + // Returns the index of the value >= the key + int min = -1, max = (int)vec.size(); + const FT *p = vec.data(); + for (;;) + { + int mid = (min + max)>>1; + if (mid == min) + return exact ? -1 : max; + FT midv = p[mid]; + if (midv == key) + return mid; + else if (midv < key) + min = mid; + else + max = mid; + } +} + +template +int binsearch_index(const std::vector &vec, FT CT::*field, FT key, bool exact = true) { + // Returns the index of the value >= the key int min = -1, max = (int)vec.size(); - CT **p = vec.data(); - FT key = (FT)value; + CT *const *p = vec.data(); for (;;) { int mid = (min + max)>>1; if (mid == min) - { - return NULL; - } + return exact ? -1 : max; FT midv = p[mid]->*field; if (midv == key) - { - return p[mid]; - } + return mid; else if (midv < key) - { min = mid; - } else - { max = mid; - } } } +template +inline int binsearch_index(const std::vector &vec, typename CT::key_field_type key, bool exact = true) +{ + return CT::binsearch_index(vec, key, exact); +} + +template +inline int binsearch_index(const std::vector &vec, typename CT::key_pointer_type key, bool exact = true) +{ + return CT::binsearch_index(vec, key, exact); +} + +template +inline bool vector_contains(const std::vector &vec, KT key) +{ + return binsearch_index(vec, key) >= 0; +} + +template +inline bool vector_contains(const std::vector &vec, FT CT::*field, FT key) +{ + return binsearch_index(vec, field, key) >= 0; +} + +template +unsigned insert_into_vector(std::vector &vec, FT key, bool *inserted = NULL) +{ + unsigned pos = (unsigned)binsearch_index(vec, key, false); + bool to_ins = (pos >= vec.size() || vec[pos] != key); + if (inserted) *inserted = to_ins; + if (to_ins) + vec.insert(vec.begin()+pos,key); + return pos; +} + +template +unsigned insert_into_vector(std::vector &vec, FT CT::*field, CT *obj, bool *inserted = NULL) +{ + unsigned pos = (unsigned)binsearch_index(vec, field, obj->*field, false); + bool to_ins = (pos >= vec.size() || vec[pos] != obj); + if (inserted) *inserted = to_ins; + if (to_ins) + vec.insert(vec.begin()+pos,obj); + return pos; +} + +template +CT *binsearch_in_vector(const std::vector &vec, KT value) +{ + int idx = binsearch_index(vec, value); + return idx < 0 ? NULL : vec[idx]; +} + +template +CT *binsearch_in_vector(const std::vector &vec, FT CT::*field, FT value) +{ + int idx = binsearch_index(vec, field, value); + return idx < 0 ? NULL : vec[idx]; +} + +/* + * MISC + */ + /** * Returns the amount of milliseconds elapsed since the UNIX epoch. * Works on both windows and linux. diff --git a/library/xml b/library/xml index 7b89e5958..c99be2349 160000 --- a/library/xml +++ b/library/xml @@ -1 +1 @@ -Subproject commit 7b89e595811ed81b012a805131aa10a89d451e76 +Subproject commit c99be2349fef32db026af7541676e2e4f24e4636