Resource Cleanup Order (try-with-resources)

hard Exception Handling

Problem

A program opens n resources one after the other (number 1, then 2, ...) and then does some work. Opening resource f fails (f = 0 means that nothing fails; f can also be bigger than n, then nothing fails). Print what happens, one event per line: open i when resource i opens, work when the work runs, and close i when resource i closes. Resources must close in the opposite order of opening, also when something fails. If an opening fails, print caught after the closes. Always print done as the last line.

Constraints

  • 1 <= n <= 1000
  • 0 <= f <= 2000

Examples

Input

3 0

Output

open 1
open 2
open 3
work
close 3
close 2
close 1
done

Input

3 2

Output

open 1
close 1
caught
done

Solutions

Best approachTime O(n)Space O(n)

Resources close in reverse order, like a stack. A resource whose constructor throws is never open, so it is not closed. try-with-resources (Java), with (Python) and try/finally (JavaScript) all guarantee the cleanup, also when an exception travels up.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Resource trace.
 * Input   : Two integers: n and f.
 * Output  : The events.
 * Approach: try-with-resources.
 * Time    : O(n)
 * Space   : O(n)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: A Resource writes "open" in its constructor and "close" in close(). AutoCloseable lets try-with-resources close it.
        static class Resource implements AutoCloseable {
            private final int number;
            private final java.util.List<String> trace;

            Resource(int number, long failAt, java.util.List<String> trace) {
                // Step 2: If this resource must fail, the constructor throws before it is open. Then there is nothing to close.
                if (number == failAt) {
                    throw new IllegalStateException("cannot open " + number);
                }
                this.number = number;
                this.trace = trace;
                trace.add("open " + number);
            }

            @Override
            public void close() {
                trace.add("close " + number);
            }
        }

        // Step 3: Open resource "index", then open the rest inside it. When the block ends, Java closes this resource,
        // so the inner resources always close first.
        static void run(int index, long total, long failAt, java.util.List<String> trace) {
            try (Resource resource = new Resource(index, failAt, trace)) {
                if (index < total) {
                    run(index + 1, total, failAt, trace);
                } else {
                    trace.add("work");
                }
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(long a, long b) {
        java.util.List<String> trace = new java.util.ArrayList<>();

        // Step 4: A failure inside run() travels up. Every resource that is already open is closed on the way.
        try {
            run(1, a, b, trace);
        } catch (IllegalStateException error) {
            trace.add("caught");
        } finally {
            // Step 5: finally runs in both cases.
            trace.add("done");
        }
        return trace.toArray(new String[0]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long a = scanner.nextLong();
        long b = scanner.nextLong();
        System.out.println(String.join("\n", solve(a, b)));
    }
}
Hints (1)
  1. In which order do resources close?