How to fill a stl::map by iterating to maximum value? - c++

I have an std::map, and I use the following method for filling up to the maximum value of the supplied data type. In this case, if K is int then the maximum value is 2,147,483,647. I want my map to have 2,147,483,647 keys with the same value.
The below loop is very inefficient. Is there any method to reduce the time consumption?
for (auto i = keyBegin; i!=numeric_limits<K>::max(); i++) {
m_map[i] = val;
}

The problem with the code above is that you're inserting 2 billion numbers, all at the end of the map. But operator[] has no idea that you'll be inserting a new item there!
std::map::insert(hint_before, value) is what you need. You've got a perfect hint - all values will be inserted directly before m_map.end()

To supplement the existing answers, this is really not a good use of std::map.
Maps are designed for quick lookup in a collection of keys & values, where the keys are "sparse". They're generally implemented as trees, requiring lots of dynamic allocation, tree rebalancing, and the sacrifice of cache locality. This is worth it for the general map use case.
But your keys are far from sparse! You literally have a value for every possible number in the key's type's range. This is what arrays are for.
Use an array and you will benefit from cache, you will benefit from constant-time lookups, and you will not need any dynamic allocation inside the container. You will of course need to dynamically allocate the container itself because it is huge, so, you're looking for std::vector.
And that's only if you really need to precalculate all these values. If you don't necessarily need them all multiple times, consider generating them on-demand instead. Because, regardless how much RAM a contemporary PC can provide you, this feels a bit like an abuse of the technology.

To supplement MSalters's answer, that suggests to use map::insert(hint, {key, value}) construct, I suggest to use a non-default allocator. A specialized allocater can further speed up the insertion twofold. Consider the following trivial allocator:
template <class T>
class chunk_allocator
{
private:
struct node
{
union
{
node *next;
char element[sizeof(T)];
};
};
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using is_always_equal = std::false_type;
using propagate_on_container_move_assignment = std::true_type;
T*allocate(std::size_t n)
{
if (n > 1)
return reinterpret_cast<T*>(::operator new(sizeof(T) * n));
if (!m_free_head) populate();
node * head = m_free_head;
m_free_head = head->next;
using node_ptr = node*;
head->next.~node_ptr();
return reinterpret_cast<T*>(&head->element);
}
void deallocate(T* p, std::size_t n) {
if (!p)
return;
if (n > 1) {
::operator delete((void*)p);
return;
}
node * new_head = new ((void*)p) node;
new_head->next = m_free_head;
m_free_head = new_head->next;
}
private:
static constexpr unsigned NODES_IN_CHUNK = 1000;
void populate()
{
if (m_free_head) return;
m_chunks.emplace_back();
for (node & entry : m_chunks.back()) {
entry.next = m_free_head;
m_free_head = &entry;
}
}
std::list<std::array<node, NODES_IN_CHUNK>> m_chunks;
node * m_free_head = nullptr;
};
template< class T1, class T2 >
bool operator==( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
return (void*)&a == (void*)&b;
}
template< class T1, class T2 >
bool operator!=( const chunk_allocator<T1>& a, const chunk_allocator<T2>& b )
{
return !(a == b);
}
And its use:
std::map<int, int, std::less<int>,
chunk_allocator<std::pair<const int, int >>> m_map;
Working 100,000,000 elements takes (on windows with cygwin):
std::allocator: Insertion: 7.987, destruction: 7.238
chunk_allocator: Insertion: 2.745, destruction: 1.357
On Linux the differences are not that big, but still 2x improvements are possible.
Bonus points - the chunk_allocator takes less memory, since it does not use operator new for individual map nodes. Each call to operator new has to maintain memory management bookkeeping, which chunk_allocator does not have to.

Related

Create a vector of pairs, where the second element of a pair points to the next pair in the vector

I need to create a vector or similar list of pairs, where the first element of a pair is of class T, and the second element is a pointer to the next pair.
Illustration
template<class T>
std::vector<std::pair<T, T*>> createPointingVector(std::vector<T> vec) {
std::vector<std::pair<T, T*>> new_vec;
for (int i=0; i<vec.size(); i++){
new_vec.push_back(std::make_pair(vec[i], &(vec[i - 1])));
}
return new_vec;
}
I understand that std::vector<std::pair<T, T*>> is incorrect because the second element of the pair is not supposed to be of type *T but rather a recursive *std::pair<T, *std::pair<T, *std::pair<T, ...>>>.
Is it possible to fix my code or what are the other ways to achieve my goal, if any?
I strongly recommend rethinking using a bare vector.
My reason for that is that you need to guarantee that that the memory of the vector is never reallocated. Note that you also should in any case make sure that your vector is made sure to allocate all required memory from the start, either by initializing with empty elements or by using std::vector::reserve.
Otherwise, if you have a pointer already set and then change the capacity of the vector, the pointer becomes invalid, a good setup if you want undefined behaviour.
Therefore I strongly advise you to use a wrapper class around your vector, which makes sure no capacity change is ever called.
Now, if you do that, the thing is, why do you use actual pointers?
Consider using data of type std::vector<std::pair<T, size_t> >, with the second entry actually storing the position within the vector, rather than an actual pointer:
template<class T>
class PointingVector
{
public:
PointingVector(const std::vector<T>& vec);
private:
std::vector<std::pair<T, size_t> > data;
};
template<class T>
PointingVector<T>::PointingVector(const std::vector<T>& vec)
{
for (int i=0; i<vec.size()-1; i++)
{
data.push_back(std::make_pair(vec[i], i+1));
}
data.push_back(std::make_pair(vec.back(), 0)); // assuming that the last points to the first
}
After that, make sure that every additional method you add leaves the pointing consistent. Like should you write something similar to erase, make sure that all pairs are updated accordingly.
And the analogy to dereferencing is trivial:
template<class T>
std::pair<T, size_t>& PointingVector<T>::get(size_t index)
{
return data[index];
}
The important thing about my solution is that you can exclude possible bugs in regard to dangling pointers. Those are really bad, especially since they might not cause an error in test executions, given the nature of undefined behaviour. Worst thing in my solution is that the indices are wrong after calling a method that has a bug.
And if you want to introduce anything that changes the capacity of the vector, no problem, no need to redo any pointers. Just make sure the indices are changed accordingly. If you did this with pointers, your first step would probably be to create a list of indices anyway, so why not work with one directly.
Plus, as this solution has no (visible) pointers at all, you don't need to do any memory management.
Another solution: Ditch std::pair and define your own type:
template<class T>
struct Node
{
T data;
Node* next; // or a smart pointer type
Node(const T& data, Node* next) : data(data), next(next) {}
};
Then build up your vector like this:
template<class T>
std::vector<Node<T>*> createPointingVector(const std::vector<T>& vec)
{
std::vector<Node<T>*> new_vec;
for (int i=0; i<vec.size(); i++)
{
new_vec.push_back(new Node<T>(vec[i], nullptr));
}
for (int i=0; i<vec.size()-1; i++)
{
new_vec[i]->next = new_vec[i+1];
}
new_vec[vec.size()-1]->next = new_vec[0];
return new_vec;
}
Note that without smart pointers, you need to do memory management. I'd consider making next a weak_ptr<Node>, and have the vector be over shared_ptr<Node>. That way, the memory is automatically deallocated as soon as the vector gets deleted (assuming you have no other pointers active).
What you ask is doable, but according to the illustration found linked within your answer, the pointers should point one-up circularly inside the input vector, and not one-down, as is in your code example. What I mean is:
new_vec[0] = {vec[0], &vec[1]}
new_vec[1] = {vec[1], &vec[2]}
...
new_vec[N-1] = {vec[N-1], &vec[0]}
above, N = vec.size().
I attach a minimum working example:
#include <iostream>
#include <vector>
#include <utility> // std::pair, std::make_pair
template<class T>
std::vector<std::pair<T, T*> > createPointingVector(std::vector<T>& vec) { // important: make the parameter a reference
std::vector<std::pair<T, T*> > new_vec;
int vec_size = vec.size();
for (int i = 0; i < vec_size-1; i++)
new_vec.push_back( std::make_pair( vec[i], &(vec[i + 1]) ) ); // pointers assigned according to linked picture
new_vec.push_back( std::make_pair( vec[vec_size-1], &vec[0] ) );
return new_vec;
}
int main()
{
std::vector<int> input = {1,2,3,4};
std::vector<std::pair<int,int*> > sol = createPointingVector(input);
for (auto i : sol)
std::cout << i.first << " -> " << *(i.second) << std::endl;
return 0;
}

Does constant time access imply contiguous memory at some point?

As the title says, I was wondering if constant-time/O(1) access to a container does imply that memory is necessarily contiguous at some point.
When I say contiguous I mean if pointers can be compared with relational operators at some point without invoking undefined behavior.
Take eg std::deque: it does not guarantee that all its elements are stored contiguously (i.e in the same memory array), but is it correct to say that as std::deque satisfy the requirements of a Random Access Iterator, memory will be contiguous at some point independently of the implementation?
I am new to C++ so in case what I said above does not make sense: suppose I was going to implement random access iterators in C. Can
typedef struct random_access_iterator {
void *pointer; /*pointer to element */
void *block; /* pointer to the memory array
* so in case of comparing iterators
* where pointer does not point to addresses in the same array
* it can be used to comparisons instead*/
/* implement other stuff */
} RandomIter;
be used to generically express a similar mechanism to that of C++ random access iterators (considering that even if pointer do not, block will always
point to addresses in the same memory array in iterators of the same container)?
EDIT: just to clarify, constant-time here is used to denote constant-time random access
No. Consider a fixed-size linked list like the following:
struct DumbCounterexample
{
struct node
{
std::vector<int> items;
std::unique_ptr<node> next;
};
std::unique_ptr<node> first;
size_t size;
static constexpr size_t NODE_COUNT = 10;
DumbCounterexample()
: first{new node},
size{0}
{
node* to_fill = first.get();
for (size_t i = 0; i < NODE_COUNT - 1; ++i) {
to_fill->next.reset(new node);
to_fill = to_fill->next.get();
}
}
int& operator[](size_t i)
{
size_t node_num = i % NODE_COUNT;
size_t item_num = i / NODE_COUNT;
node* target_node = first.get();
for (size_t n = 0; n < node_num; ++n) {
target_node = target_node->next.get();
}
return target_node->items[item_num];
}
void push_back(int i)
{
size_t node_num = size % NODE_COUNT;
node* target_node = first.get();
for (size_t n = 0; n < node_num; ++n) {
target_node = target_node->next.get();
}
target_node->items.push_back(i);
++size;
}
};
Lookup time is constant. It does not depend on the number of elements stored in the container (only the constant NODE_COUNT).
Now, this is a strange data structure, and I can't think of any legitimate reason to use it, but it does serve as a counterexample to the claim that there need be a single contiguous block of memory that would be shared by all iterators to elements in the container (i.e. the block pointer in your example random_access_iterator struct).

C++ design issue with unordered_set and iterators

I have the following snippet
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
const size_t INF(numeric_limits<size_t>::max());
class nodehasher;
class node{
public:
int x,y;
unordered_set<node, nodehasher>::iterator neighbs[6]; //Issue Here
node(){}
node(int x_, int y_):x(x_),y(y_){}
void set(int x_, int y_){x = x_,y = y_;}
bool operator == (const node &n)const{
return x == n.x && y == n.y;
}
};
class nodehasher{
std::size_t operator()(node const& n) const{
std::size_t seed = 0;
hash_combine(seed, n.x);
hash_combine(seed, n.y);
return seed;
}
};
I seem to be having issues declaring the iterators pointing to class node inside node itself.
This causes a huge number of too verbose errors.
Now i realize i could make my neighbs array, an array of pointers to node,
but i want to avoid pointers for obvious reasons
A typical simplified way i use this would be:
unordered_set<node, nodehasher> nodes;
void typical_use(node dest){
auto src_node = node(0,0);
int neighbcount = 0;
auto iter = dest.insert(node).first;
src_node.neighbs[neighb_count] = iter;
}
I could obviously convert it into pointers and do:
src_node.neighbs[neighb_count] = &(*iter);
But Is there no way to avoid pointers for what i want to do?
EDIT:
As many of the comments and answers have pointed out both pointers and iterators to the container elements get invalidated after a rehash
so it is a bad idea storing them.
I was thinking if the following way works instead of an unordered_set of node i will use an unordered_set of pointer to nodes, something like this
unordered_set<shared_ptr<node> > nodes;
Also, if i know that the number of nodes is always going to be less than 500, i could forgo this whole hash table idea and use an array and each time i will have to search the array to check if the node is already there.
Can you please point out which approach is better?
Standard containers require complete types for values. node isn't complete type at the point where you use it to instantiate unordered_set<node, nodehasher>.
You could use Boost.Container, because they allow incomplete types, but I don't see hashed containers there (so you'd have to use set).
You should be careful with storing iterators, though, because, at least for unordered_ containers from the standard library, they may be invalidated upon
rehashing. References (and pointers) are not invalidated.

are there center-allocation deque or vector in STL implementations?

I was reading about deques vs vectors, and came across its wikipedia entry, which says one of the three possible implementations of deque using dynamic arrays is:
Allocating deque contents from the center of the underlying array, and
resizing the underlying array when either end is reached. This
approach may require more frequent resizings and waste more space,
particularly when elements are only inserted at one end.
I was wondering if there are any STL (or STL-style) implementations that actually use this center-allocation strategy?
I am asking because this strategy looks rather appealing as it involves only one underlying array, and thus removes the memory dis-contiguity issue, which is probably the only major issue deque has when compared to vector. If I understand it right, this could well be a replacement for std::vector that allows O(1) pop_front (amortized) or a replacement for deque with memory-contiguity guarantees. I assume that this is at the cost of doubling the buffering space of a std::vector, which is not a major concern for my use cases.
Also, is it true that insertion/deletion in the middle of such a container would take half the time of std::vector on average?
UPDATE:
As #Lightness Races in Orbit pointed out, such a implementation will not be used under current standards because no one can benefit from the upsides per contract with STL and everyone will suffer from the downsides. A further question I have regarding the downsides is this:
Is it possible to implement a new vector or deque like container (say bivector) such that in addition to the functionality/operators of std::vector,
1) provides (amortized) constant time push_front() and pop_front() operations and
2) guarantees memory contiguity but not iterator validity after growing sizes?
I imagine with one array behind the scene, a lot of the indirection/performance issues on deque would go away.
No Standard Library (not "STL") implementation is going to bother with this, because it has the downsides you mention, and the upsides are not part of the requirement for std::deque.
Those requirements are carefully constructed, right from algorithmic complexity for various operations, through to iterator invalidation rules. There is no benefit in implementing a container in such a way that nobody can rely on that implementation's upsides.
Could the C++ committee introduce a new container in a future standard with a different name and with different constraints, which vendors could implement as you describe? Yes, they could.
Your problem is you lack that container. Start with something like this:
template<typename T>
class bi_vec {
std::unique_ptr<char[]> raw;
std::size_t first = 0;
std::size_t last = 0;
std::size_t capacity = 0;
char* raw_get( std::size_t index ) {
return &raw[index*sizeof(T)];
}
char const* raw_get( std::size_t index ) const {
return &raw[index*sizeof(T)];
}
T& get( std::size_t index ) {
return *reinterpret_cast<T*>(raw_get(index));
}
T const& get( std::size_t index ) const {
return *reinterpret_cast<T const *>(raw_get(index));
}
char* raw_before() {
if (first < 1)
grow();
--first;
return raw_get(first);
}
char* raw_after() {
if (last+1 >= capacity)
grow();
++last;
return raw_get(last-1);
}
void grow() {
std::vector new_capacity = (capacity+1)*2;
std::size_t new_first = (new_capacity - (last-first)) / 2;
std::size_t new_last = new_capacity - new_first;
std::unique_ptr<char[]> new_buff( new char[new_capacity*sizeof(T)] );
T* b = &get(0);
T* e = &get(last-first);
std::move( b, e, reinterpret_cast<T*>( &new_buff[new_first*sizeof(T)] ) );
std::swap( buff, raw );
std::swap( new_capacity, capacity );
std::swap( new_first, first );
std::swap( new_last, last );
for (T* it = b; it != e; ++it) {
it->~T();
}
}
public:
T& operator[]( std::size_t index ) { return get(index); }
T const& operator[]( std::size_t index ) const { return get(index); }
template<class... Us>
void emplace_back( Us&&...us ) {
char* a = raw_after();
new (a) T( std::forward<Us>(us) );
}
template<class... Us>
void emplace_front( Us&&...us ) {
char* a = raw_before();
new (a) T( std::forward<Us>(us) );
}
~bi_vec() {
for( std::size_t i = 0; i != last-first; ++i ) {
get(i).~T();
}
}
};
and add iterators (I'd be tempted to use boost iterator helpers, or raw pointers to start) and whatever interfaces you need. Note that the above needs work to ensure it remains exception safe.

performance of find in an unordered_map

I know this is probably a stupid question, but I wanted to make sure and I couldn't readily find this information.
What is the performance characteristic of find() in an unordered map? Is it as fast/nearly as fast as a normal lookup?
I.e.
std::string defaultrow = sprite.attribute("defaultrow").value();
auto rclassIt = Rows::NameRowMap.find(defaultrow);
if (rclassIt != Rows::NameRowMap.end())
defRow = rclassIt->second;
vs.
std::string defaultrow = sprite.attribute("defaultrow").value();
defRow = Rows::NameRowMap[defaultrow];
where Rows::NameRowMap is a unordered map mapping a string index to an int.
In my case, I don't know for certain if the key will exist before hand, so the first solution seemed safer to me, but if I can guarantee existence, is the second case faster (ignoring the extra checks I'm doing)? and if so, why? If it matters, I'm using the 1.46 boost implementation
find and operator[] on an unordered container are O(1) average, O(n) worst-case -- it depends on the quality of your hash function.
It's pretty possible that operator[] uses find and insert internally. For example, IIRC that's the case with Miscrosoft's std::map implementation.
EDIT:
What I was trying to say is that operator[] is not magical, it still has to do a lookup first. From what I see in Boost 1.46.0 both find and said operator use find_iterator internally.
Usually it's better to use find for lookups, because your code will be more reusable and robust (e.g. you will never insert something accidentally), especially in some kind of generic code.
They have the same amortized complexity of O(1), but the operator also creates a new element when the value is not found. If the value is found, performance difference should be minor. My boost is a little old - version 1.41, but hopefully it does not matter. Here is the code:
// find
//
// strong exception safety, no side effects
template <class H, class P, class A, class G, class K>
BOOST_DEDUCED_TYPENAME hash_table<H, P, A, G, K>::iterator_base
hash_table<H, P, A, G, K>::find(key_type const& k) const
{
if(!this->size_) return this->end();
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
node_ptr it = find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(it))
return iterator_base(bucket, it);
else
return this->end();
}
// if hash function throws, basic exception safety
// strong otherwise
template <class H, class P, class A, class K>
BOOST_DEDUCED_TYPENAME hash_unique_table<H, P, A, K>::value_type&
hash_unique_table<H, P, A, K>::operator[](key_type const& k)
{
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
std::size_t hash_value = this->hash_function()(k);
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
if(!this->buckets_) {
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
return *this->emplace_empty_impl_with_node(a, 1);
}
node_ptr pos = this->find_iterator(bucket, k);
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
return node::get_value(pos);
}
else {
// Side effects only in this block.
// Create the node before rehashing in case it throws an
// exception (need strong safety in such a case).
node_constructor a(*this);
a.construct_pair(k, (mapped_type*) 0);
// reserve has basic exception safety if the hash function
// throws, strong otherwise.
if(this->reserve_for_insert(this->size_ + 1))
bucket = this->bucket_ptr_from_hash(hash_value);
// Nothing after this point can throw.
return node::get_value(add_node(a, bucket));
}
}