104 lines · c
1//===-- lib/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-exception6//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 FLANG_RT_RUNTIME_UNIT_MAP_H_13#define FLANG_RT_RUNTIME_UNIT_MAP_H_14 15#include "unit.h"16#include "flang-rt/runtime/lock.h"17#include "flang-rt/runtime/memory.h"18#include "flang/Common/fast-int-set.h"19#include <cstdint>20#include <cstdlib>21 22namespace Fortran::runtime::io {23 24class UnitMap {25public:26 ExternalFileUnit *LookUp(int n) {27 CriticalSection critical{lock_};28 return Find(n);29 }30 31 ExternalFileUnit *LookUpOrCreate(32 int n, const Terminator &terminator, bool &wasExtant) {33 CriticalSection critical{lock_};34 if (auto *p{Find(n)}) {35 wasExtant = true;36 return p;37 } else {38 wasExtant = false;39 return n >= 0 ? &Create(n, terminator) : nullptr;40 }41 }42 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);47 }48 49 ExternalFileUnit &NewUnit(const Terminator &);50 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);54 55 void DestroyClosed(ExternalFileUnit &);56 void CloseAll(IoErrorHandler &);57 void FlushAll(IoErrorHandler &);58 59private:60 struct Chain {61 explicit Chain(int n) : unit{n} {}62 ExternalFileUnit unit;63 OwningPtr<Chain> next{nullptr};64 };65 66 static constexpr int buckets_{1031}; // must be prime67 68 // The pool of recyclable new unit numbers uses the range that69 // works even with INTEGER(kind=1). 0 and -1 are never used.70 static constexpr int maxNewUnits_{129}; // [ -128 .. 0 ]71 72 int Hash(int n) { return std::abs(n) % buckets_; }73 74 void Initialize();75 76 ExternalFileUnit *Find(int n) {77 Chain *previous{nullptr};78 int hash{Hash(n)};79 for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) {80 if (p->unit.unitNumber() == n) {81 if (previous) {82 // Move found unit to front of chain for quicker lookup next time83 previous->next.swap(p->next); // now p->next.get() == p84 bucket_[hash].swap(p->next); // now bucket_[hash].get() == p85 }86 return &p->unit;87 }88 }89 return nullptr;90 }91 ExternalFileUnit *Find(const char *path, std::size_t pathLen);92 93 ExternalFileUnit &Create(int, const Terminator &);94 95 Lock lock_;96 bool isInitialized_{false};97 OwningPtr<Chain> bucket_[buckets_]{}; // all owned by *this98 OwningPtr<Chain> closing_{nullptr}; // units during CLOSE statement99 common::FastIntSet<maxNewUnits_> freeNewUnits_;100 int emergencyNewUnit_{maxNewUnits_}; // not recycled101};102} // namespace Fortran::runtime::io103#endif // FLANG_RT_RUNTIME_UNIT_MAP_H_104