opm-common
ThreadSafeMapBuilder.hpp
1 /*
2  This file is part of the Open Porous Media project (OPM).
3 
4  Copyright 2025 SINTEF Digital
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
23 #ifndef OPM_THREAD_SAFE_MAP_BUILDER_HPP
24 #define OPM_THREAD_SAFE_MAP_BUILDER_HPP
25 
26 #include <algorithm>
27 #include <cassert>
28 #include <cstddef>
29 #include <list>
30 #include <map>
31 #include <numeric>
32 #include <vector>
33 
34 #if _OPENMP
35 #include <omp.h>
36 #endif
37 
38 namespace Opm {
39 
53 
56  Emplace, // Use first inserted value encountered
57  Insert_Or_Assign // Use last inserted value encountered (last thread wins)
58 };
59 
60 template<class Map>
62 {
64  template<class T>
65  struct is_ordered
66  {
67  constexpr static bool value = false;
68  };
69 
70  template<class Key, class T, class Compare, class Allocator>
71  struct is_ordered<std::map<Key,T,Compare,Allocator>>
72  {
73  constexpr static bool value = true;
74  };
75 
76 public:
77  using Key = typename Map::key_type;
78  using Value = typename Map::mapped_type;
79 
81  ThreadSafeMapBuilder(Map& map, const int num_threads,
82  const MapBuilderInsertionMode mode)
83  : map_(map), num_threads_(num_threads), mode_(mode)
84  {
85  if (num_threads_ > 1) {
86  thread_values_.resize(num_threads_);
87  }
88  }
89 
92  {
93  finalize();
94  }
95 
97  template<class M>
98  void insert_or_assign(const Key& key, M&& value)
99  {
100  assert(mode_ == MapBuilderInsertionMode::Insert_Or_Assign);
101 #if _OPENMP
102  if (num_threads_ > 1) {
103  thread_values_[omp_get_thread_num()].
104  emplace_back(key, std::forward<M>(value));
105  } else
106 #endif // _OPENMP
107  {
108  map_.insert_or_assign(key, std::forward<M>(value));
109  }
110  }
111 
113  template<class... Args>
114  void emplace(Args&&... args)
115  {
116  assert(mode_ == MapBuilderInsertionMode::Emplace);
117 #if _OPENMP
118  if (num_threads_ > 1) {
119  thread_values_[omp_get_thread_num()].
120  emplace_back(std::forward<Args>(args)...);
121  } else
122 #endif // _OPENMP
123  {
124  map_.emplace(std::forward<Args>(args)...);
125  }
126  }
127 
129  void finalize()
130  {
131  if (num_threads_ > 1 && !thread_values_.empty()) {
132  if constexpr (!is_ordered<Map>::value) {
133  const std::size_t size =
134  std::accumulate(thread_values_.begin(),
135  thread_values_.end(), std::size_t(0),
136  [](std::size_t s, const auto& v) { return s + v.size(); });
137  map_.reserve(size);
138  }
139  for (int i = 0; i < num_threads_; ++i) {
140  for (const auto& it : thread_values_[i]) {
141  if (mode_== MapBuilderInsertionMode::Insert_Or_Assign) {
142  map_.insert_or_assign(std::move(it.first), std::move(it.second));
143  } else {
144  map_.emplace(std::move(it.first), std::move(it.second));
145  }
146  }
147  }
148  }
149  thread_values_.clear();
150  }
151 
152 private:
153  std::vector<std::list<std::pair<Key,Value>>> thread_values_;
154  Map& map_;
155  int num_threads_;
157 };
158 
159 }
160 
161 #endif // OPM_THREAD_SAFE_MAP_BUILDER_HPP
MapBuilderInsertionMode
Utility class for adding multi-threading to loops that are building maps.
Definition: ThreadSafeMapBuilder.hpp:55
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
~ThreadSafeMapBuilder()
The destructor (optionally) assembles the final map.
Definition: ThreadSafeMapBuilder.hpp:91
void insert_or_assign(const Key &key, M &&value)
Insert a value into the map.
Definition: ThreadSafeMapBuilder.hpp:98
void finalize()
Assembles the final map.
Definition: ThreadSafeMapBuilder.hpp:129
void emplace(Args &&... args)
Insert a value into the map.
Definition: ThreadSafeMapBuilder.hpp:114
ThreadSafeMapBuilder(Map &map, const int num_threads, const MapBuilderInsertionMode mode)
Constructor for a given map and number of threads.
Definition: ThreadSafeMapBuilder.hpp:81
Definition: ThreadSafeMapBuilder.hpp:61