1 //===-- runtime/unit-map.cpp ------------------------------------*- 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 #include "unit-map.h" 10 11 namespace Fortran::runtime::io { 12 13 ExternalFileUnit *UnitMap::LookUpForClose(int n) { 14 CriticalSection critical{lock_}; 15 Chain *previous{nullptr}; 16 int hash{Hash(n)}; 17 for (Chain *p{bucket_[hash].get()}; p; previous = p, p = p->next.get()) { 18 if (p->unit.unitNumber() == n) { 19 if (previous) { 20 previous->next.swap(p->next); 21 } else { 22 bucket_[hash].swap(p->next); 23 } 24 // p->next.get() == p at this point; the next swap pushes p on closing_ 25 closing_.swap(p->next); 26 return &p->unit; 27 } 28 } 29 return nullptr; 30 } 31 32 void UnitMap::DestroyClosed(ExternalFileUnit &unit) { 33 Chain *p{nullptr}; 34 { 35 CriticalSection critical{lock_}; 36 Chain *previous{nullptr}; 37 for (p = closing_.get(); p; previous = p, p = p->next.get()) { 38 if (&p->unit == &unit) { 39 if (previous) { 40 previous->next.swap(p->next); 41 } else { 42 closing_.swap(p->next); 43 } 44 break; 45 } 46 } 47 } 48 if (p) { 49 p->unit.~ExternalFileUnit(); 50 FreeMemory(p); 51 } 52 } 53 54 void UnitMap::CloseAll(IoErrorHandler &handler) { 55 CriticalSection critical{lock_}; 56 for (int j{0}; j < buckets_; ++j) { 57 while (Chain * p{bucket_[j].get()}) { 58 bucket_[j].swap(p->next); // pops p from head of list 59 p->unit.CloseUnit(CloseStatus::Keep, handler); 60 p->unit.~ExternalFileUnit(); 61 FreeMemory(p); 62 } 63 } 64 } 65 66 void UnitMap::FlushAll(IoErrorHandler &handler) { 67 CriticalSection critical{lock_}; 68 for (int j{0}; j < buckets_; ++j) { 69 for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) { 70 p->unit.Flush(handler); 71 } 72 } 73 } 74 75 ExternalFileUnit *UnitMap::Find(const char *path) { 76 if (path) { 77 // TODO: Faster data structure 78 for (int j{0}; j < buckets_; ++j) { 79 for (Chain *p{bucket_[j].get()}; p; p = p->next.get()) { 80 if (p->unit.path() && std::strcmp(p->unit.path(), path) == 0) { 81 return &p->unit; 82 } 83 } 84 } 85 } 86 return nullptr; 87 } 88 89 ExternalFileUnit &UnitMap::Create(int n, const Terminator &terminator) { 90 Chain &chain{*New<Chain>{terminator}(n).release()}; 91 chain.next.reset(&chain); 92 bucket_[Hash(n)].swap(chain.next); // pushes new node as list head 93 return chain.unit; 94 } 95 96 } // namespace Fortran::runtime::io 97