summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/unordered/test/helpers/invariants.hpp
blob: a555da60cb3ae2419a2fb50cd0d25e63c188f9a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2006-2009 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// This header contains metafunctions/functions to get the equivalent
// associative container for an unordered container, and compare the contents.

#if !defined(BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER)
#define BOOST_UNORDERED_TEST_HELPERS_INVARIANT_HEADER

#include "./helpers.hpp"
#include "./metafunctions.hpp"
#include <cmath>
#include <set>

#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
#pragma warning(disable : 4267) // conversion from 'size_t' to 'unsigned int',
                                // possible loss of data
#endif

namespace test {
  template <class X> void check_equivalent_keys(X const& x1)
  {
    typename X::key_equal eq = x1.key_eq();
    typedef typename X::key_type key_type;
    std::set<key_type, std::less<key_type> > found_;

    typename X::const_iterator it = x1.begin(), end = x1.end();
    typename X::size_type size = 0;
    while (it != end) {
      // First test that the current key has not occurred before, required
      // to test either that keys are unique or that equivalent keys are
      // adjacent. (6.3.1/6)
      key_type key = get_key<X>(*it);
      if (!found_.insert(key).second)
        BOOST_ERROR("Elements with equivalent keys aren't adjacent.");

      // Iterate over equivalent keys, counting them.
      unsigned int count = 0;
      do {
        ++it;
        ++count;
        ++size;
      } while (it != end && eq(get_key<X>(*it), key));

      // If the container has unique keys, test that there's only one.
      // Since the previous test makes sure that all equivalent keys are
      // adjacent, this is all the equivalent keys - so the test is
      // sufficient. (6.3.1/6 again).
      if (test::has_unique_keys<X>::value && count != 1)
        BOOST_ERROR("Non-unique key.");

      if (x1.count(key) != count) {
        BOOST_ERROR("Incorrect output of count.");
        std::cerr << x1.count(key) << "," << count << "\n";
      }

      // Check that the keys are in the correct bucket and are
      // adjacent in the bucket.
      typename X::size_type bucket = x1.bucket(key);
      typename X::const_local_iterator lit = x1.begin(bucket),
                                       lend = x1.end(bucket);

      unsigned int count_checked = 0;
      for (; lit != lend && !eq(get_key<X>(*lit), key); ++lit) {
        ++count_checked;
      }

      if (lit == lend) {
        BOOST_ERROR("Unable to find element with a local_iterator");
        std::cerr << "Checked: " << count_checked << " elements" << std::endl;
      } else {
        unsigned int count2 = 0;
        for (; lit != lend && eq(get_key<X>(*lit), key); ++lit)
          ++count2;
        if (count != count2)
          BOOST_ERROR("Element count doesn't match local_iterator.");
        for (; lit != lend; ++lit) {
          if (eq(get_key<X>(*lit), key)) {
            BOOST_ERROR("Non-adjacent element with equivalent key "
                        "in bucket.");
            break;
          }
        }
      }
    };

    // Check that size matches up.

    if (x1.size() != size) {
      BOOST_ERROR("x1.size() doesn't match actual size.");
      std::cout << x1.size() << "/" << size << std::endl;
    }

    // Check the load factor.

    float load_factor = size == 0 ? 0
                                  : static_cast<float>(size) /
                                      static_cast<float>(x1.bucket_count());
    using namespace std;
    if (fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
      BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");

    // Check that size in the buckets matches up.

    typename X::size_type bucket_size = 0;

    for (typename X::size_type i = 0; i < x1.bucket_count(); ++i) {
      for (typename X::const_local_iterator begin2 = x1.begin(i),
                                            end2 = x1.end(i);
           begin2 != end2; ++begin2) {
        ++bucket_size;
      }
    }

    if (x1.size() != bucket_size) {
      BOOST_ERROR("x1.size() doesn't match bucket size.");
      std::cout << x1.size() << "/" << bucket_size << std::endl;
    }
  }
}

#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

#endif