From 7bd058600b682781abb3fd93bfaf516e7d8d7b23 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Remko=20Tron=C3=A7on?= <git@el-tramo.be>
Date: Mon, 23 Apr 2012 18:11:21 +0200
Subject: Another fix for SRV selection.


diff --git a/3rdParty/Boost/update.sh b/3rdParty/Boost/update.sh
index 9b28f2d..09eb7cb 100755
--- a/3rdParty/Boost/update.sh
+++ b/3rdParty/Boost/update.sh
@@ -28,8 +28,8 @@ fi
 	optional.hpp \
 	program_options.hpp \
 	random/mersenne_twister.hpp \
-	random/uniform_real.hpp \
 	random/variate_generator.hpp \
+	random/uniform_int.hpp \
 	regex.hpp \
 	shared_ptr.hpp \
 	smart_ptr/make_shared.hpp \
diff --git a/Swiften/Base/BoostRandomGenerator.cpp b/Swiften/Base/BoostRandomGenerator.cpp
index b8c50d0..62c3055 100644
--- a/Swiften/Base/BoostRandomGenerator.cpp
+++ b/Swiften/Base/BoostRandomGenerator.cpp
@@ -7,21 +7,14 @@
 #include <Swiften/Base/BoostRandomGenerator.h>
 
 #include <numeric>
-#include <boost/random/uniform_real.hpp>
+#include <boost/random/uniform_int.hpp>
 #include <boost/random/variate_generator.hpp>
 
 namespace Swift {
 
-int BoostRandomGenerator::generateWeighedRandomNumber(std::vector<double>::const_iterator probabilities_begin, std::vector<double>::const_iterator probabilities_end) {
-	// Only works starting boost 1.47
-	//boost::random::discrete_distribution<> distribution(weights.begin(), weights.end());
-	//return distribution(generator);
-
-	std::vector<double> cumulative;
-	std::partial_sum(probabilities_begin, probabilities_end, std::back_inserter(cumulative));
-	boost::uniform_real<> dist(0, cumulative.back());
-	boost::variate_generator<boost::mt19937&, boost::uniform_real<> > die(generator, dist);
-	return std::lower_bound(cumulative.begin(), cumulative.end(), die()) - cumulative.begin();
+int BoostRandomGenerator::generateRandomInteger(int maximum) {
+	boost::uniform_int<> distribution(0, maximum);
+	return distribution(generator);
 }
 
 }
diff --git a/Swiften/Base/BoostRandomGenerator.h b/Swiften/Base/BoostRandomGenerator.h
index ffc7a72..6d65b0b 100644
--- a/Swiften/Base/BoostRandomGenerator.h
+++ b/Swiften/Base/BoostRandomGenerator.h
@@ -13,7 +13,7 @@
 namespace Swift {
 	class BoostRandomGenerator : public RandomGenerator{
 		public:
-			int generateWeighedRandomNumber(std::vector<double>::const_iterator probabilities_begin, std::vector<double>::const_iterator probabilities_end);
+			int generateRandomInteger(int max);
 
 		private:
 			boost::mt19937 generator;
diff --git a/Swiften/Base/RandomGenerator.h b/Swiften/Base/RandomGenerator.h
index a998e0d..4a3550d 100644
--- a/Swiften/Base/RandomGenerator.h
+++ b/Swiften/Base/RandomGenerator.h
@@ -13,6 +13,6 @@ namespace Swift {
 		public:
 			virtual ~RandomGenerator();
 
-			virtual int generateWeighedRandomNumber(std::vector<double>::const_iterator probabilities_begin, std::vector<double>::const_iterator probabilities_end) = 0;
+			virtual int generateRandomInteger(int max) = 0;
 	};
 }
diff --git a/Swiften/Network/DomainNameServiceQuery.cpp b/Swiften/Network/DomainNameServiceQuery.cpp
index f7ffecc..da1e1ab 100644
--- a/Swiften/Network/DomainNameServiceQuery.cpp
+++ b/Swiften/Network/DomainNameServiceQuery.cpp
@@ -8,6 +8,8 @@
 
 #include <numeric>
 #include <cassert>
+#include <functional>
+#include <iterator>
 
 #include <Swiften/Base/RandomGenerator.h>
 #include <boost/numeric/conversion/cast.hpp>
@@ -21,19 +23,12 @@ namespace {
 		}
 	};
 
-	struct WeightAccumulator {
-			int operator()(int accumulator, const DomainNameServiceQuery::Result& result) {
-				return accumulator + result.weight;
-			}
-	};
+	struct GetWeight {
+			GetWeight() {}
 
-	struct WeightToProbability {
-			WeightToProbability(int total) : total(total) {}
-
-			double operator()(const DomainNameServiceQuery::Result& result) {
-				return result.weight / boost::numeric_cast<double>(total);
+			int operator()(const DomainNameServiceQuery::Result& result) {
+				return result.weight + 1 /* easy hack to account for '0' weights getting at least some weight */;
 			}
-			int total;
 	};
 }
 
@@ -50,15 +45,15 @@ void DomainNameServiceQuery::sortResults(std::vector<DomainNameServiceQuery::Res
 	while (i != queries.end()) {
 		std::vector<DomainNameServiceQuery::Result>::iterator next = std::upper_bound(i, queries.end(), *i, comparator);
 		if (std::distance(i, next) > 1) {
-			int weightSum = std::accumulate(i, next, 0, WeightAccumulator());
-			std::vector<double> probabilities;
-			std::transform(i, next, std::back_inserter(probabilities), WeightToProbability(weightSum > 0 ? weightSum : 1));
-
-			// Shuffling the result array and the probabilities in parallel
-			for (size_t j = 0; j < probabilities.size(); ++j) {
-				int selectedIndex = generator.generateWeighedRandomNumber(probabilities.begin() + j, probabilities.end());
+			std::vector<int> weights;
+			std::transform(i, next, std::back_inserter(weights), GetWeight());
+			for (size_t j = 0; j < weights.size() - 1; ++j) {
+				std::vector<int> cumulativeWeights;
+				std::partial_sum(weights.begin() + j, weights.end(), std::back_inserter(cumulativeWeights));
+				int randomNumber = generator.generateRandomInteger(cumulativeWeights.back());
+				int selectedIndex = std::lower_bound(cumulativeWeights.begin(), cumulativeWeights.end(), randomNumber) - cumulativeWeights.begin();
 				std::swap(i[j], i[j + selectedIndex]);
-				std::swap(probabilities.begin()[j], probabilities.begin()[j + selectedIndex]);
+				std::swap(weights.begin()[j], weights.begin()[j + selectedIndex]);
 			}
 		}
 		i = next;
diff --git a/Swiften/Network/UnitTest/DomainNameServiceQueryTest.cpp b/Swiften/Network/UnitTest/DomainNameServiceQueryTest.cpp
index aefd815..53b9413 100644
--- a/Swiften/Network/UnitTest/DomainNameServiceQueryTest.cpp
+++ b/Swiften/Network/UnitTest/DomainNameServiceQueryTest.cpp
@@ -16,14 +16,14 @@ using namespace Swift;
 
 namespace {
 	struct RandomGenerator1 : public RandomGenerator {
-		virtual int generateWeighedRandomNumber(std::vector<double>::const_iterator, std::vector<double>::const_iterator) {
+		virtual int generateRandomInteger(int) {
 			return 0;
 		}
 	};
 
 	struct RandomGenerator2 : public RandomGenerator {
-		virtual int generateWeighedRandomNumber(std::vector<double>::const_iterator probabilities_begin, std::vector<double>::const_iterator probabilities_end) {
-			return std::max_element(probabilities_begin, probabilities_end) - probabilities_begin;
+		virtual int generateRandomInteger(int i) {
+			return i;
 		}
 	};
 }
@@ -70,9 +70,9 @@ class DomainNameServiceQueryTest : public CppUnit::TestFixture {
 
 			CPPUNIT_ASSERT_EQUAL(std::string("server5.com"), results[0].hostname);
 			CPPUNIT_ASSERT_EQUAL(std::string("server7.com"), results[1].hostname);
-			CPPUNIT_ASSERT_EQUAL(std::string("server4.com"), results[2].hostname);
-			CPPUNIT_ASSERT_EQUAL(std::string("server6.com"), results[3].hostname);
-			CPPUNIT_ASSERT_EQUAL(std::string("server2.com"), results[4].hostname);
+			CPPUNIT_ASSERT_EQUAL(std::string("server2.com"), results[2].hostname);
+			CPPUNIT_ASSERT_EQUAL(std::string("server4.com"), results[3].hostname);
+			CPPUNIT_ASSERT_EQUAL(std::string("server6.com"), results[4].hostname);
 			CPPUNIT_ASSERT_EQUAL(std::string("server1.com"), results[5].hostname);
 			CPPUNIT_ASSERT_EQUAL(std::string("server3.com"), results[6].hostname);
 		}
-- 
cgit v0.10.2-6-g49f6