Здравствуйте, Sinix, Вы писали:
S>1.
S>Для *Bound нужно написать примеры использования, лучше всего оформлять их в виде тестов.
S>Почему это важно:
S>В дотнете API стараются оформлять так, чтобы его можно было использовать без чтения документации. Любой другой вариант резко уменьшает число пользователей, отсылки к STL тут не помогут, т.к. у подавляющего большинства дотнетчиков опыта работы с c++ — мизер.
ОК. Примеры добавлю в тесты.
S>* BinarySearchLower/BinarySearchUpper? Практически идеал, т.к. ещё и показывает, что нам нужно отсортировать список перед использованием.
Хороший вариант, ИМХО.
S>2.
S>Если мы решаем не трогать имена методов, то у нас такая ситуация: вперемешку с обычными бери-и-пользуйся методами лежат методы, которые надо изучать перед тем, как использовать. Как минимум из-за необходимости сортировать данные и неочевидной пары up-to.
S>Решить легко: вытаскиваем все *Bound-методы в отдельный тип, скажем, в BinarySearchExtenstions — вуаля.
Тоже вариант.
S>3.
S>Мне отчаянно не нравится пара up-to. Её или переименовать в startIndex+endIndex и сделать endIndex < count, или поменять на традиционный дотнетовский startIndex + count.
S>Чтобы принять решение надо бы написать реальный пример использования с этими параметрами и посмотреть, что будет лучше. Возьмёшься? Я могу придумать только такие, где вариант с startIndex + count выигрывает.
Вот тебе пример реального использования:
//(1)
var vBegin = verticals.LowerBound(horizontal.Begin, (x, v) => Comparer<double>.Default.Compare(x.Key, v));
if (vBegin == verticalsCount)
{
continue;
}
//(2)
var vEnd = verticals.UpperBound(horizontal.End, vBegin, verticalsCount, (x, v) => Comparer<double>.Default.Compare(x.Key, v));
//(3)
for (var vIndex = vBegin; vIndex < vEnd; ++vIndex)
В приниципе, можно тут передавать count вместо endIndex, но, тогда придется перед (2) добавить вычисления нужного count (тогда как endIndex мы и так уже знаем). Плюс, в самой реализации делать обратное преобразование.
Хотя, тут пример не самый удачный, ибо взят еще с той версии, когда не было перегрузки, принимающей только start без end'а.
С другой стороны, в нем видно, что может понадобиться сравнивать результат с endIndex (как в (1)), соответственно, если передавать count, то в итоге получится, что нужно работать с двумя сущностями (и count и endIndex), а не с одной (endIndex).
В общем, КМК, вариант с endIndex более консистентен.
Впрочем, если у нас будут удобные диапазоны, то можно сделать 2 варианта:
1) с start и count;
2) с диапазоном
S>4.
S>Возвращаемое значение.
S>Или оставляем как есть, или, если значение не найдено, возвращаем bitwise complement к индексу, как это делает BinarySearch. Второй вариант явно не подходит для UpperBound, там по определению не может быть "не найдено". Оставляем как есть?
Тут я бы предпочел не менять. Ибо результаты lower/upper, как правило, далее используется в последующих вызовах lower/upper (как в (2)) или цикле (как в (3)). И проверки на дополнения и их снятие тут будут выглядеть лишними.
S>5.
S>Тип параметра. В идеале, надо бы сделать IReadOnlyList, но там столько возни, что я бы отложил до лучших времён.
S>Пример возни см в DictionaryExtensions.GetValueOrDefault. По три перегрузки на каждый метод — нафиг-нафиг.
Угу, кто-то (rameel, вроде) это уже предлагал. Идея хорошая, но с перегрузками будет морока.
S>P.S.
S>С DisjointSets давай разберёмся после того, как добьём Lower/UpperBound()
ОК.