FLANG

unit-map.h
1 //===-- runtime/unit-map.h --------------------------------------*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Maps Fortran unit numbers to their ExternalFileUnit instances.
10 // A simple hash table with forward-linked chains per bucket.
11
12 #ifndef FORTRAN_RUNTIME_UNIT_MAP_H_
13 #define FORTRAN_RUNTIME_UNIT_MAP_H_
14
15 #include "lock.h"
16 #include "memory.h"
17 #include "unit.h"
18 #include <cstdlib>
19
20 namespace Fortran::runtime::io {
21
22 class UnitMap {
23 public:
24 ExternalFileUnit *LookUp(int n) {
25 CriticalSection critical{lock_};
26 return Find(n);
27 }
28
29 ExternalFileUnit &LookUpOrCreate(
30 int n, const Terminator &terminator, bool &wasExtant) {
31 CriticalSection critical{lock_};
32 auto *p{Find(n)};
33 wasExtant = p != nullptr;
34 return p ? *p : Create(n, terminator);
35 }
36
37 ExternalFileUnit &NewUnit(const Terminator &terminator) {
38 CriticalSection critical{lock_};
39 return Create(nextNewUnit_--, terminator);
40 }
41
42 // To prevent races, the unit is removed from the map if it exists,
43 // and put on the closing_ list until DestroyClosed() is called.
44 ExternalFileUnit *LookUpForClose(int);
45
46 void DestroyClosed(ExternalFileUnit &);
47 void CloseAll(IoErrorHandler &);
48 void FlushAll(IoErrorHandler &);
49
50 private:
51 struct Chain {
52 explicit Chain(int n) : unit{n} {}
53 ExternalFileUnit unit;
54 OwningPtr<Chain> next{nullptr};
55 };
56
57 static constexpr int buckets_{1031}; // must be prime
58 int Hash(int n) { return std::abs(n) % buckets_; }
59
60 ExternalFileUnit *Find(int n) {
61 Chain *previous{nullptr};
62 int hash{Hash(n)};
63 for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) {
64 if (p->unit.unitNumber() == n) {
65 if (previous) {
66 // Move found unit to front of chain for quicker lookup next time
67 previous->next.swap(p->next); // now p->next.get() == p
68 bucket_[hash].swap(p->next); // now bucket_[hash].get() == p
69 }
70 return &p->unit;
71 }
72 }
73 return nullptr;
74 }
75
76 ExternalFileUnit &Create(int, const Terminator &);
77
78 Lock lock_;
79 OwningPtr<Chain> bucket_[buckets_]{}; // all owned by *this
80 int nextNewUnit_{-1000}; // see 12.5.6.12 in Fortran 2018
81 OwningPtr<Chain> closing_{nullptr}; // units during CLOSE statement
82 };
83 } // namespace Fortran::runtime::io
84 #endif // FORTRAN_RUNTIME_UNIT_MAP_H_
Fortran::runtime::Terminator
Definition: terminator.h:21
Fortran::runtime::io::IoErrorHandler
Definition: io-error.h:26
Fortran::runtime::CriticalSection
Definition: lock.h:64
Fortran::runtime::io::ExternalFileUnit
Definition: unit.h:32
Fortran::runtime::Lock
Definition: lock.h:32
Fortran::runtime::io::UnitMap
Definition: unit-map.h:22