BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslh_filesystem.h
Go to the documentation of this file.
1/// @file bslh_filesystem.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslh_filesystem.h -*-C++-*-
8#ifndef INCLUDED_BSLH_FILESYSTEM
9#define INCLUDED_BSLH_FILESYSTEM
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bslh_filesystem bslh_filesystem
15/// @brief Provide `hash` for `std::filesystem::path`.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bslh
19/// @{
20/// @addtogroup bslh_filesystem
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bslh_filesystem-purpose"> Purpose</a>
25/// * <a href="#bslh_filesystem-classes"> Classes </a>
26/// * <a href="#bslh_filesystem-description"> Description </a>
27/// * <a href="#bslh_filesystem-usage"> Usage </a>
28/// * <a href="#bslh_filesystem-example-1-creating-and-using-a-hash-cross-reference"> Example 1: Creating and Using a Hash Cross Reference </a>
29///
30/// # Purpose {#bslh_filesystem-purpose}
31/// Provide `hash` for `std::filesystem::path`.
32///
33/// # Classes {#bslh_filesystem-classes}
34///
35///
36/// @see bslh_hash
37///
38/// # Description {#bslh_filesystem-description}
39/// Provides a `hash` specialization for `std::filesystem::path`,
40/// delegating to `std::filesystem::path::hash_value` for the implementation
41/// since it is already available and conforming.
42///
43/// ## Usage {#bslh_filesystem-usage}
44///
45///
46/// This section illustrates intended usage of this component.
47///
48/// ### Example 1: Creating and Using a Hash Cross Reference {#bslh_filesystem-example-1-creating-and-using-a-hash-cross-reference}
49///
50///
51/// Suppose we already have an array of unique values of type `TYPE`, for which
52/// `operator==` is defined, and we want to be able to quickly look up whether
53/// an element is in the array, without exhaustively applying `operator==` to
54/// all the elements in sequence. The array itself is guaranteed not to change
55/// for the duration of our interest in it.
56///
57/// The problem is much simpler than building a general-purpose hash table,
58/// because we know how many elements our cross reference will contain in
59/// advance, so we will never have to dynamically grow the number of `buckets`.
60/// We do not need to copy the values into our own area, so we don't have to
61/// create storage for them, or require that a copy constructor or destructor be
62/// available. We only require that they have a transitive, symmetric
63/// equivalence operation `bool operator==` and that a hash function be
64/// provided.
65///
66/// We will need a hash function -- the hash function is a function that will
67/// take as input an object of the type stored in our array, and yield a
68/// `size_t` value that will be very randomized. Ideally, the slightest change
69/// in the value of the `TYPE` object will result in a large change in the value
70/// returned by the hash function. In a good hash function, typically half the
71/// bits of the return value will change for a 1-bit change in the hashed value.
72/// We then use the result of the hash function to index into our array of
73/// `buckets`. Each `bucket` is simply a pointer to a value in our original
74/// array of `TYPE` objects. We will resolve hash collisions in our array
75/// through `linear probing`, where we will search consecutive buckets following
76/// the bucket where the collision occurred, testing occupied buckets for
77/// equality with the value we are searching on, and concluding that the value
78/// is not in the table if we encounter an empty bucket before we encounter one
79/// referring to an equal element.
80///
81/// An important quality of the hash function is that if two values are
82/// equivalent, they must yield the same hash value.
83///
84/// First, we define our `HashCrossReference` template class, with the two type
85/// parameters `TYPE` (the type being referenced') and `HASHER`, which defaults
86/// to `bslh::Hash<TYPE>`. This component provides the specialization of
87/// `bslh::Hash` for `std::filesystem::path`:
88/// @code
89/// /// This table leverages a hash table to provide a fast lookup of an
90/// /// external, non-owned, array of values of configurable type.
91/// ///
92/// /// The only requirement for `TYPE` is that it have a transitive,
93/// /// symmetric `operator==` function. There is no requirement that it
94/// /// have any kind of creator defined.
95/// ///
96/// /// The `HASHER` template parameter type must be a functor with a
97/// /// function of the following signature:
98/// /// ```
99/// /// size_t operator()(const TYPE) const; or
100/// /// size_t operator()(const TYPE&) const; or
101/// /// ```
102/// /// and `HASHER` must have a publicly available default constructor and
103/// /// destructor.
104/// template <class TYPE, class HASHER = bslh::Hash<TYPE> >
105/// class HashCrossReference {
106/// // DATA
107/// const TYPE *d_values; // Array of values table is to
108/// // cross-reference. Held, not
109/// // owned.
110/// size_t d_numValues; // Length of `d_values`.
111/// const TYPE **d_bucketArray; // Contains ptrs into
112/// // `d_values`
113/// size_t d_bucketArrayMask; // Will always be `2^N - 1`.
114/// HASHER d_hasher;
115/// bool d_valid; // Object was properly
116/// // initialized.
117/// bslma::Allocator *d_allocator_p; // held, not owned
118///
119/// private:
120/// // PRIVATE ACCESSORS
121///
122/// /// Look up the specified `value`, having hash value `hashValue`,
123/// /// and return its index in `d_bucketArray`. If not found, return
124/// /// the vacant entry in `d_bucketArray` where it should be inserted.
125/// /// Return `true` if `value is found and `false` otherwise.
126/// bool lookup(size_t *idx,
127/// const TYPE& value,
128/// size_t hashValue) const
129/// {
130/// const TYPE *ptr;
131/// for (*idx = hashValue & d_bucketArrayMask;
132/// (ptr = d_bucketArray[*idx]);
133/// *idx = (*idx + 1) & d_bucketArrayMask) {
134/// if (value == *ptr) {
135/// return true; // RETURN
136/// }
137/// }
138/// // value was not found in table
139///
140/// return false;
141/// }
142///
143/// public:
144/// // CREATORS
145///
146/// /// Create a hash cross reference referring to the array of value.
147/// HashCrossReference(const TYPE *valuesArray,
148/// size_t numValues,
149/// bslma::Allocator *allocator = 0)
150/// : d_values(valuesArray)
151/// , d_numValues(numValues)
152/// , d_hasher()
153/// , d_valid(true)
154/// , d_allocator_p(bslma::Default::allocator(allocator))
155/// {
156/// size_t bucketArrayLength = 4;
157/// while (bucketArrayLength < numValues * 4) {
158/// bucketArrayLength *= 2;
159/// BSLS_ASSERT_OPT(bucketArrayLength);
160/// }
161/// d_bucketArrayMask = bucketArrayLength - 1;
162/// d_bucketArray = (const TYPE **) d_allocator_p->allocate(
163/// bucketArrayLength * sizeof(TYPE **));
164/// memset(d_bucketArray, 0, bucketArrayLength * sizeof(TYPE *));
165///
166/// for (unsigned i = 0; i < numValues; ++i) {
167/// const TYPE& value = d_values[i];
168/// size_t idx;
169/// if (lookup(&idx, value, d_hasher(value))) {
170/// // Duplicate value. Fail.
171///
172/// printf("Error: entries %u and %u have the same value\n",
173/// i, (unsigned) (d_bucketArray[idx] - d_values));
174/// d_valid = false;
175///
176/// // don't return, continue reporting other redundant
177/// // entries.
178/// }
179/// else {
180/// d_bucketArray[idx] = &d_values[i];
181/// }
182/// }
183/// }
184///
185/// /// Free up memory used by this cross-reference.
186/// ~HashCrossReference()
187/// {
188/// d_allocator_p->deallocate(d_bucketArray);
189/// }
190///
191/// // ACCESSORS
192///
193/// /// Return 1 if the specified `value` is found in the cross
194/// /// reference and 0 otherwise.
195/// int count(const TYPE& value) const
196/// {
197/// BSLS_ASSERT_OPT(d_valid);
198///
199/// size_t idx;
200/// return lookup(&idx, value, d_hasher(value));
201/// }
202///
203/// /// Return `true` if this cross reference was successfully
204/// /// constructed and `false` otherwise.
205/// bool isValid() const
206/// {
207/// return d_valid;
208/// }
209/// };
210/// @endcode
211/// Then, In `main`, we will first use our cross-reference to cross-reference a
212/// collection of `std::filesystem::path` values. Note that the `/` separator
213/// is equally valid on Windows and Unix-derived systems when used
214/// programmatically. We define our array and take its length:
215/// @code
216/// const std::filesystem::path paths[] = { "/2/3",
217/// "/4/2",
218/// "/4/7",
219/// "/5/6",
220/// "/5/7",
221/// "/6/1",
222/// "/6/2",
223/// "/6/3",
224/// "/7/0",
225/// "/7/2",
226/// "/7/9"
227/// };
228/// enum { NUM_PATHS = sizeof paths / sizeof *paths };
229/// @endcode
230/// Now, we create our cross-reference `hcri` and verify it constructed
231/// properly. Note that we don't specify the second template parameter `HASHER`
232/// and let it default to `bslh::Hash<std::filesystem::path>`, which is already
233/// defined by this component:
234/// @code
235/// HashCrossReference<std::filesystem::path> hcri(paths, NUM_PATHS);
236/// assert(hcri.isValid());
237/// @endcode
238/// Finally, we use `hcri` to verify numbers that were and were not in the
239/// collection:
240/// @code
241/// assert(1 == hcri.count("/2/3"));
242/// assert(1 == hcri.count("/4/2"));
243/// assert(1 == hcri.count("/4/7"));
244/// assert(1 == hcri.count("/5/6"));
245/// assert(0 == hcri.count("/a/3"));
246/// assert(0 == hcri.count("/3/1"));
247/// assert(0 == hcri.count("/3/7"));
248/// assert(0 == hcri.count("/5/8"));
249/// @endcode
250/// @}
251/** @} */
252/** @} */
253
254/** @addtogroup bsl
255 * @{
256 */
257/** @addtogroup bslh
258 * @{
259 */
260/** @addtogroup bslh_filesystem
261 * @{
262 */
263
264#include <bslscm_version.h>
265
266#include <bslh_hash.h>
267
269#include <bsls_libraryfeatures.h>
270#include <bsls_platform.h>
271
272#ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_FILESYSTEM
273#include <filesystem>
274
275#define BSLH_FILESYSTEM_DEPRECATED_CPP17 \
276 BSLS_DEPRECATE_FEATURE("bsl", \
277 "deprecated_cpp17_standard_library_features", \
278 "do not use")
279
280namespace bslh {
281
282
283 // =========================
284 // class hash specialization
285 // =========================
286
287/// Specialization of `hash` for `std::filesystem::path` values.
288template <>
289struct Hash<std::filesystem::path> {
290
291 // STANDARD TYPEDEFS
292
293 /// @deprecated This typedef is depreacted in C++17, for details see
294 /// https://isocpp.org/files/papers/p0005r4.html.
295 BSLH_FILESYSTEM_DEPRECATED_CPP17
296 typedef std::filesystem::path argument_type;
297
298 /// @deprecated This typedef is depreacted in C++17, for details see
299 /// https://isocpp.org/files/papers/p0005r4.html.
300 BSLH_FILESYSTEM_DEPRECATED_CPP17
301 typedef std::size_t result_type;
302
303 /// Create a `hash` object.
304 hash() = default;
305
306 /// Create a `hash` object. Note that as `hash` is an empty (stateless)
307 /// type, this operation has no observable effect.
308 hash(const hash& original) = default;
309
310 /// Destroy this object.
311 ~hash() = default;
312
313 // MANIPULATORS
314
315 /// Assign to this object the value of the specified 'rhs' object, and
316 /// return a reference providing modifiable access to this object. Note
317 /// that as 'hash' is an empty (stateless) type, this operation has no
318 /// observable effect.
319 hash& operator=(const hash& rhs) = default;
320
321 // ACCESSORS
322
323 /// Return a hash value computed using the specified `x`.
324 std::size_t operator()(const std::filesystem::path &x) const;
325};
326
327// ============================================================================
328// TEMPLATE AND INLINE FUNCTION DEFINITIONS
329// ============================================================================
330
331inline
333 const std::filesystem::path& x) const
334{
335 return std::filesystem::hash_value(x);
336}
337
338/// Pass the specified `input` path to the specified `hashAlg` hashing
339/// algorithm of the (template parameter) type `HASHALG`. Note that this
340/// function violates the BDE coding standard, adding a function for a
341/// namespace for a different package, and none of the function parameters
342/// are from this package either. This is necessary in order to provide an
343/// implementation of `bslh::hashAppend` for the (native) standard library
344/// `std::filesystem::path` type as we are not allowed to add overloads
345/// directly into namespace `std`. Also note that this will NOT be found by
346/// the compiler if HASHALG is not in `BloombergLP::bslh`.
347template <class HASHALG>
349void hashAppend(HASHALG& hashAlg, const std::filesystem::path& path)
350{
351 using BloombergLP::bslh::hashAppend;
352 BloombergLP::bslh::Hash<std::filesystem::path> hashFunctor;
353
354 hashAppend(hashAlg, hashFunctor(path));
355}
356
357} // close package namespace
358
359
360#undef BSLH_FILESYSTEM_DEPRECATED_CPP17
361
362#endif // BSLS_LIBRARYFEATURES_HAS_CPP17_FILESYSTEM
363
364#endif // INCLUDED_BSLH_FILESYSTEM
365
366// ----------------------------------------------------------------------------
367// Copyright 2022 Bloomberg Finance L.P.
368//
369// Licensed under the Apache License, Version 2.0 (the "License");
370// you may not use this file except in compliance with the License.
371// You may obtain a copy of the License at
372//
373// http://www.apache.org/licenses/LICENSE-2.0
374//
375// Unless required by applicable law or agreed to in writing, software
376// distributed under the License is distributed on an "AS IS" BASIS,
377// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
378// See the License for the specific language governing permissions and
379// limitations under the License.
380// ----------------------------- END-OF-FILE ----------------------------------
381
382/** @} */
383/** @} */
384/** @} */
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_PLATFORM_AGGRESSIVE_INLINE
Definition bsls_platform.h:836
Definition bslh_defaulthashalgorithm.h:339
bsl::enable_if<(bsl::is_integral< TYPE >::value||bsl::is_pointer< TYPE >::value||bsl::is_enum< TYPE >::value)&&!bsl::is_same< TYPE, bool >::value >::type hashAppend(HASH_ALGORITHM &hashAlg, TYPE input)
Definition bslh_hash.h:638
Definition bdldfp_decimal.h:5188
result_type operator()(const TYPE &type) const
Hash & operator=(const Hash &rhs)=default
size_t result_type
Definition bslh_hash.h:586