1 //===-- runtime/unit-map.h --------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Maps Fortran unit numbers to their ExternalFileUnit instances.
10 // A simple hash table with forward-linked chains per bucket.
12 #ifndef FORTRAN_RUNTIME_UNIT_MAP_H_
13 #define FORTRAN_RUNTIME_UNIT_MAP_H_
17 #include "flang/Common/fast-int-set.h"
18 #include "flang/Runtime/memory.h"
22 namespace Fortran::runtime::io
{
26 ExternalFileUnit
*LookUp(int n
) {
27 CriticalSection critical
{lock_
};
31 ExternalFileUnit
*LookUpOrCreate(
32 int n
, const Terminator
&terminator
, bool &wasExtant
) {
33 CriticalSection critical
{lock_
};
34 if (auto *p
{Find(n
)}) {
39 return n
>= 0 ? &Create(n
, terminator
) : nullptr;
43 // Unit look-up by name is needed for INQUIRE(FILE="...")
44 ExternalFileUnit
*LookUp(const char *path
, std::size_t pathLen
) {
45 CriticalSection critical
{lock_
};
46 return Find(path
, pathLen
);
49 ExternalFileUnit
&NewUnit(const Terminator
&);
51 // To prevent races, the unit is removed from the map if it exists,
52 // and put on the closing_ list until DestroyClosed() is called.
53 ExternalFileUnit
*LookUpForClose(int);
55 void DestroyClosed(ExternalFileUnit
&);
56 void CloseAll(IoErrorHandler
&);
57 void FlushAll(IoErrorHandler
&);
61 explicit Chain(int n
) : unit
{n
} {}
62 ExternalFileUnit unit
;
63 OwningPtr
<Chain
> next
{nullptr};
66 static constexpr int buckets_
{1031}; // must be prime
68 // The pool of recyclable new unit numbers uses the range that
69 // works even with INTEGER(kind=1). 0 and -1 are never used.
70 static constexpr int maxNewUnits_
{129}; // [ -128 .. 0 ]
72 int Hash(int n
) { return std::abs(n
) % buckets_
; }
76 ExternalFileUnit
*Find(int n
) {
77 Chain
*previous
{nullptr};
79 for (Chain
*p
{bucket_
[hash
].get()}; p
; previous
= p
, p
= p
->next
.get()) {
80 if (p
->unit
.unitNumber() == n
) {
82 // Move found unit to front of chain for quicker lookup next time
83 previous
->next
.swap(p
->next
); // now p->next.get() == p
84 bucket_
[hash
].swap(p
->next
); // now bucket_[hash].get() == p
91 ExternalFileUnit
*Find(const char *path
, std::size_t pathLen
);
93 ExternalFileUnit
&Create(int, const Terminator
&);
96 bool isInitialized_
{false};
97 OwningPtr
<Chain
> bucket_
[buckets_
]{}; // all owned by *this
98 OwningPtr
<Chain
> closing_
{nullptr}; // units during CLOSE statement
99 common::FastIntSet
<maxNewUnits_
> freeNewUnits_
;
100 int emergencyNewUnit_
{maxNewUnits_
}; // not recycled
102 } // namespace Fortran::runtime::io
103 #endif // FORTRAN_RUNTIME_UNIT_MAP_H_