File: file_base.h

package info (click to toggle)
seqan2 2.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 228,748 kB
  • sloc: cpp: 257,602; ansic: 91,967; python: 8,326; sh: 1,056; xml: 570; makefile: 229; awk: 51; javascript: 21
file content (646 lines) | stat: -rw-r--r-- 21,259 bytes parent folder | download
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
// ==========================================================================
//                 SeqAn - The Library for Sequence Analysis
// ==========================================================================
// Copyright (c) 2006-2026, Knut Reinert, FU Berlin
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of Knut Reinert or the FU Berlin nor the names of
//       its contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
//
// ==========================================================================
// Author: David Weese <david.weese@fu-berlin.de>
// ==========================================================================
// Defines basic file access functions.
// ==========================================================================

#ifndef SEQAN_INCLUDE_SEQAN_FILE_BASE_H_
#define SEQAN_INCLUDE_SEQAN_FILE_BASE_H_

/* IOREV
 * _doc_
 *
 * base class with SPecs and Tags
 * also contains standard calls for IO as wrappers around members
 * in system/file_sync.h and system/file_ssync.h
 * (these files are built around c++ fstream IO)
 * well documented (in comparison to other files)
 *
 * SEQAN_DIRECTIO Macro mentioned here but not documented or tested
 */

namespace seqan2 {

// Manual Forward.
template < typename TSpec, typename TPos >
inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs, int origin);
template < typename TSpec, typename TPos >
inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs);

    //////////////////////////////////////////////////////////////////////////////
    // generic open/close interface

/*!
 * @fn File#open
 * @brief Opens a file, stream, or persistent string.
 *
 * @signature bool open(file, fileName, openMode);
 *
 * @param[in,out] file     The File to open.
 * @param[in]     fileName A <tt>char const *</tt> string containing the file name.
 * @param[in]     openMode Combination of flags defining how the file should be opened.  See @link FileOpenMode
 *                         @endlink for more details.  Type: <tt>int</tt>.  If you omit the <tt>OPEN_APPEND</tt> flag in
 *                         write mode, the file will be cleared when opened.  Default: <tt>OPEN_RDWR | OPEN_CREATE |
 *                         OPEN_APPEND</tt>.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename TSpec >
    inline bool open(File<TSpec> &me, const char *fileName, int openMode)
    {
//IOREV resolves to member in file_(a)sync.h which resolves to fstream
        return me.open(fileName, openMode);
    }

    template < typename TSpec >
    inline bool open(File<TSpec> &me, const char *fileName)
    {
//IOREV
        return open(me, fileName, DefaultOpenMode<File<TSpec> >::VALUE);
    }

/*!
 * @fn File#openTemp
 * @brief Opens a temporary file.
 *
 * @signature bool openTemp(file);
 *
 * @param[in,out] file The File object to open the temporary file.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 *
 * @section Remarks
 *
 * After closing this file will be deleted automatically.  The openmode (see @link File#open @endlink) is <tt>OPEN_RDWR
 * | OPEN_CREATE</tt>.
 *
 * @return bool <tt>true</tt> on success <tt>false</tt> on failure.
 */

    template < typename TSpec >
    inline bool openTemp(File<TSpec> &me)
    {
//IOREV
        return me.openTemp();
    }

    template < typename TSpec >
    inline bool openTemp(File<TSpec> &me, int openMode)
    {
//IOREV
        return me.openTemp(openMode);
    }

    template < typename File >
    inline void reopen(File &, int)
    {
//IOREV _stub_ _nodoc_ This is currently a no-op. Is that intended?
    }

/*!
 * @fn File#close
 * @brief Close a file.
 *
 * @signature bool close(file);
 *
 * @param[in,out] file The File object to close.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename TSpec >
    inline bool close(File<TSpec> & me)
    {
//IOREV
        return me.close();
    }

    template < typename TSpec >
    inline unsigned sectorSize(File<TSpec> const & /*me*/)
    {
//IOREV _duplicate_ _nodoc_ duplicate or identical spec. in file_cstyle.h should'nt this be variable
        return 4096;
    }


    //////////////////////////////////////////////////////////////////////////////
    // generic read(At)/write(At) interface

/*!
 * @fn File#read
 * @brief Loads record from a file.
 *
 * @signature bool read(file, memPtr, count);
 *
 * @param[in,out] file   The File object.
 * @param[out]    memPtr A pointer to the first destination record in memory.
 * @param[in]     count  The amount of records to be read.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 *
 * @section Remarks
 *
 * The records are read from the position pointed to by the current file pointer (see @link File#seek @endlink).
 */

    template < typename TSpec, typename TValue, typename TSize >
    inline bool read(File<TSpec> & me, TValue *memPtr, TSize const count)
    {
//IOREV
        typedef typename Size<File<TSpec> >::Type TFileSize;
        TFileSize nbytes = (TFileSize)count * (TFileSize)sizeof(TValue);
        return me.read(memPtr, nbytes) == nbytes;
    }

/*!
 * @fn File#write
 * @brief Saves records to a file.
 *
 * @signature bool write(file, memPtr, count);
 *
 * @param[in,out] file   The File object.
 * @param[in]     memPtr Pointer to the source for the data to write.
 * @param[in]     count  The number of records to write.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 *
 * @section Remarks
 *
 * The records are written at the position pointed to by the current file pointer (see @link File#seek @endlink).
 */

    template < typename TSpec, typename TValue, typename TSize >
    inline bool write(File<TSpec> & me, TValue const *memPtr, TSize const count)
    {
//IOREV
        typedef typename Size<File<TSpec> >::Type TFileSize;
        TFileSize nbytes = (TFileSize)count * (TFileSize)sizeof(TValue);
        return me.write(memPtr, nbytes) == nbytes;
    }

/*!
 * @fn File#readAt
 * @brief Loads records from a specific position in a file.
 *
 * @signature bool readAt(file, memPtr, count, fileOfs);
 *
 * @param[in,out] file    The File object to read from.
 * @param[out]    memPtr  A pointer to the first destination record in memory.
 * @param[in]     count   The amount of records to be read.
 * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
 *
 * @return bool <tt>true</tt> on success and <tt>false</tt> on failure.
 */

    template < typename TFile, typename TValue, typename TSize, typename TPos >
    inline bool readAt(TFile & me, TValue *memPtr, TSize const count, TPos const fileOfs)
    {
//IOREV
        typedef typename Position<TFile>::Type pos_t;
        seek(me, (pos_t)fileOfs * (pos_t)sizeof(TValue));
        return read(me, memPtr, count);
    }

/*!
 * @fn File#writeAt
 * @brief Saves records to a specific position in a file.
 *
 * @signature bool writeAt(file, memPtr, count, fileOfs);
 *
 * @param[in,out] file    The File object to write to.
 * @param[in]     memPtr  Pointer to the memory to write.
 * @param[in]     count   The amount of records to be written.
 * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename TFile, typename TValue, typename TSize, typename TPos >
    inline bool writeAt(TFile & me, TValue const *memPtr, TSize const count, TPos const fileOfs)
    {
//IOREV
        typedef typename Position<TFile>::Type pos_t;
        seek(me, (pos_t)fileOfs * (pos_t)sizeof(TValue));
        return write(me, memPtr, count);
    }



    //////////////////////////////////////////////////////////////////////////////
    // generic seek/tell/size/resize interface

/*!
 * @fn File#seek
 * @brief Changes the current file pointer.
 *
 * @signature TPosition seek(file, fileOfs[, origin]);
 *
 * @param[in,out] file    The File object to seek in.
 * @param[in]     fileOfs A file offset measured in bytes relative to <tt>origin</tt>.
 * @param[in]     origin  Selects the origin from where to calculate the new position.  One of <tt>SEEK_BEGIN</tt>,
 *                        <tt>SEEK_CURRENT</tt>, and <tt>SEEK_END<tt> (origin is beginning, current pointer, end of
 *                        the file).  Default: <tt>SEEK_BEGIN</tt>.
 *
 * @return TPosition The new file position measured in bytes from the beginning.
 */

    template < typename TSpec, typename TPos >
    inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs, int origin)
    {
//IOREV
        typedef typename Position< File<TSpec> >::Type TFilePos;
        TFilePos newOfs = me.seek(fileOfs, origin);
        #if SEQAN_ENABLE_DEBUG || SEQAN_ENABLE_TESTING
            if (origin == SEEK_BEGIN && newOfs != (TFilePos)fileOfs) {
                std::cerr << "seek returned " << std::hex << newOfs << " instead of " << fileOfs << std::dec << std::endl;
            }
        #endif
        return newOfs;
    }

    template < typename TSpec, typename TPos >
    inline typename Position< File<TSpec> >::Type seek(File<TSpec> &me, TPos const fileOfs)
    {
//IOREV
        return seek(me, fileOfs, SEEK_BEGIN);
    }

/*!
 * @fn File#tell
 * @brief Gets the current file pointer.
 *
 * @signature TPosition tell(file);
 *
 * @param[in] file The File object to query for the current position.
 *
 * @return TPosition The current position in the file.
 */

    template < typename TSpec >
    inline typename Position< File<TSpec> >::Type tell(File<TSpec> &me)
    {
//IOREV
        return me.tell();
    }

/*!
 * @fn File#rewind
 * @brief Sets the current file pointer to the beginning of a file.
 *
 * @signature void rewind(file);
 *
 * @param[in,out] file The file to reset the file pointer of.
 */

    template < typename File >
    inline void rewind(File &me)
    {
//IOREV
        seek(me, 0);
    }

/*!
 * @fn File#length
 * @brief Return the file size.
 *
 * @signature TSize length(file);
 *
 * @param[in] file The File object to query for its size.
 *
 * @return TSize The file size measured in bytes.
 */

    template < typename TSpec >
    inline typename Size<File<TSpec> >::Type length(File<TSpec> &me)
    {
//IOREV
        typename Size<File<TSpec> >::Type old_pos = tell(me);
        typename Size<File<TSpec> >::Type result = seek(me, 0, SEEK_END);
        seek(me, old_pos, SEEK_BEGIN);
        return result;
    }

/*!
 * @fn File#resize
 * @brief A file object.
 *
 * @signature void resize(file, newLength);
 *
 * @param[in,out] file      The File object to resize.
 * @param[in]     newLength The file size in bytes to resize to in bytes.
 */

    template < typename TSpec, typename TSize >
    inline void resize(File<TSpec> &me, TSize new_length)
    {
//IOREV possibly not standard-conformant, see resize() in file_cstyle.h
        typename Size<File<TSpec> >::Type old_pos = tell(me);
        seek(me, new_length, SEEK_BEGIN);
        setEof(me);
        seek(me, old_pos, SEEK_BEGIN);
    }

/*!
 * @fn File#setEof
 * @brief Sets the file end to the current pointer.
 *
 * @signature bool setEof(file);
 *
 * @param[in,out] file The File object to set the end of.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename TSpec >
    inline bool setEof(File<TSpec> &/*me*/)
    {
//IOREV _noop_ specialized for async file access but not for sync
        return true;
    }


    //////////////////////////////////////////////////////////////////////
    // Pseudo asynchronous Methods
    //////////////////////////////////////////////////////////////////////

    //////////////////////////////////////////////////////////////////////
    // callback based read/write
/*
    template < typename File, typename TValue, typename TSize,
               typename aCallback, typename aHint >
    inline typename AsyncRequest<File>::Type
    asyncRead(File & me, TValue *memPtr, TSize const count,
        aCallback* cb, aHint* hint)
    {
        result = read(me, memPtr, count);
        cb(hint);
        return NULL;
    }

    template < typename File, typename TValue, typename TSize,
               typename aCallback, typename aHint >
    inline typename AsyncRequest<File>::Type
    asyncWrite(File & me, TValue const *memPtr, TSize const count,
        aCallback* cb, aHint* hint)
    {
        write(me, memPtr, count);
        cb(hint);
        return NULL;
    }

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename aCallback, typename aHint >
    inline typename AsyncRequest<File>::Type
    asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
        aCallback* cb, aHint* hint)
    {
        readAt(me, memPtr, count, fileOfs);
        cb(hint);
        return NULL;
    }

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename aCallback, typename aHint >
    inline typename AsyncRequest<File>::Type
    asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
        aCallback* cb, aHint* hint)
    {
        result = writeAt(me, memPtr, count, fileOfs);
        cb(hint);
        return NULL;
    }


    //////////////////////////////////////////////////////////////////////
    // event based read/write

    template < typename File, typename TValue, typename TSize,
               typename aEvent >
    inline typename AsyncRequest<File>::Type
    asyncRead(File & me, TValue *memPtr, TSize const count,
        aEvent &event)
    {
        read(me, memPtr, count);
        event.signal();
        return NULL;
    }

    template < typename File, typename TValue, typename TSize,
               typename aEvent >
    inline typename AsyncRequest<File>::Type
    asyncWrite(File & me, TValue const *memPtr, TSize const count,
        aEvent &event)
    {
        write(me, memPtr, count);
        event.signal();
        return NULL;
    }

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename aEvent >
    inline typename AsyncRequest<File>::Type
    asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
        aEvent &event)
    {
        readAt(me, memPtr, count, fileOfs);
        event.signal();
        return NULL;
    }

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename aEvent >
    inline typename AsyncRequest<File>::Type
    asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
        aEvent &event)
    {
        writeAt(me, memPtr, count, fileOfs);
        event.signal();
        return NULL;
    }
*/

    //////////////////////////////////////////////////////////////////////
    // queue-less request based pseudo asynchronous read/write

/*!
 * @fn File#asyncReadAt
 * @brief Asynchronously loads records from a specific position in a file.
 *
 * @signature bool asyncReadAt(file, memPtr, count, fileOfs, request);
 *
 * @param[in,out] file    The File object to read from.
 * @param[out]    memPtr  A pointer to the first destination record in memory.
 * @param[in]     count   The amount of records to be read.
 * @param[in]     fileOfs The absolute file position in bytes measured from the beginning.
 * @param[in]     request Reference to a structure that will be associated with this asynchronous request.  Type:
 *                        @link AsyncRequest @endlink.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename AsyncRequest >
    inline bool
    asyncReadAt(File & me, TValue *memPtr, TSize const count, TPos const fileOfs,
        AsyncRequest &)
    {
//IOREV _stub_ see general discussion about AsynRequest
        return readAt(me, memPtr, count, fileOfs);
    }

/*!
 * @fn File#asyncWriteAt
 * @brief Asynchronously writes records to a specific position in a file.
 *
 * @signature bool asyncWriteAt(file, memPtr, count, fileOfs, request);
 *
 * @param[in,out] file    The File object.
 * @param[in]     memPtr  A pointer to the first source record in memory.
 * @param[in]     count   The amount of records to be written.
 * @param[in]     fileOfs The absolute file position in bytes measured form the beginning.
 * @param[in]     request Reference to a structure that will be associated with this asynchronous request.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename File, typename TValue, typename TSize, typename TPos,
               typename TAsyncRequest >
    inline bool
    asyncWriteAt(File & me, TValue const *memPtr, TSize const count, TPos const fileOfs,
        TAsyncRequest &)
    {
//IOREV _stub_ see general discussion about AsynRequest
        return writeAt(me, memPtr, count, fileOfs);
    }


    //////////////////////////////////////////////////////////////////////
    // pseudo queue specific functions

/*!
 * @fn File#flush
 * @brief Waits for all open requests to complete.
 *
 * @signature void flush(file);
 *
 * @param[in,out] file The File object to flush.
 */

    template < typename TSpec >
    inline void flush(File<TSpec> &)
    {
//IOREV _noop_ specialized for async file access but not for sync
    }

/*!
 * @fn File#waitFor
 * @brief Waits for an asynchronous request to complete.
 *
 * @signature bool waitFor(request[, timeout]);
 *
 * @param[in,out] request Reference to an AsyncRequest.
 * @param[in]     timeout A timeout value in milliseconds.  A value of 0 can be used to test for completion without
 *                        waiting.  Default: 0.
 *
 * @return bool <tt>true</tt> on completion, <tt>false</tt> on timeout.
 *
 * @section Remarks
 *
 * <tt>waitfor</tt> block sand suspends the calling thread process until <tt>request</tt> is completed or after
 * <tt>timeout</tt> milliseconds.
 */

    inline bool waitFor(AsyncDummyRequest &)
    {
//IOREV _noop_ see general discussion about AsynRequest
        return true;
    }

    template < typename TTime >
    inline bool waitFor(AsyncDummyRequest &, TTime, bool &inProgress)
    {
//IOREV _noop_ see general discussion about AsynRequest
        inProgress = false;
        return true;
    }

    // deprecated
    template < typename TSpec, typename AsyncRequest >
    [[deprecated]]
    inline void release(File<TSpec> &, AsyncRequest &)
    {
//IOREV _noop_ see general discussion about AsynRequest
    }

/*!
 * @fn File#cancel
 * @brief Cancels an asynchronous request.
 *
 * @signature bool cancel(file, request);
 *
 * @param[in,out] file    The File to cancel the request for.
 * @param[in]     request Reference to an AsyncRequest object.  Type: @link AsyncRequest @endlink.
 *
 * @return bool <tt>true</tt> on success, <tt>false</tt> on failure.
 */

    template < typename TSpec, typename AsyncRequest >
    inline bool cancel(File<TSpec> &, AsyncRequest &)
    {
//IOREV _noop_ see general discussion about AsynRequest
        return true;
    }


    // little helpers

    template <typename T1, typename T2> inline
    T1 enclosingBlocks(T1 _size, T2 _blockSize)
    {
//IOREV not sure what this does, but is used in several places
        return (_size + (T1)_blockSize - (T1)1) / (T1)_blockSize;
    }

    template <typename T1, typename T2> inline
    T1 alignSize(T1 _size, T2 _aligning)
    {
//IOREV not sure what this does, but is used in several places
        if (_size < (T1)_aligning)
            return _aligning;
        else
            return (_size / (T1)_aligning) * (T1)_aligning;
    }
}  // namespace seqan2

#endif  // #ifndef SEQAN_INCLUDE_SEQAN_FILE_BASE_H_