|
| 1 | +// Copyright 2016-2017 Diffblue Limited. All Rights Reserved. |
| 2 | + |
| 3 | +/// \file |
| 4 | +/// A lazy wrapper for goto_functionst. |
| 5 | + |
| 6 | +#ifndef CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H |
| 7 | +#define CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H |
| 8 | + |
| 9 | +#include <unordered_set> |
| 10 | +#include "goto_functions.h" |
| 11 | +#include "goto_convert_functions.h" |
| 12 | +#include <util/message.h> |
| 13 | +#include <util/language_file.h> |
| 14 | + |
| 15 | + |
| 16 | +/// Provides a wrapper for a map of lazily loaded goto_functiont. |
| 17 | +/// This incrementally builds a goto-functions object, while permitting |
| 18 | +/// access to goto programs while they are still under construction. |
| 19 | +/// The intended workflow: |
| 20 | +/// 1. The front-end registers the functions that are potentially |
| 21 | +/// available, probably by use of util/language_files.h |
| 22 | +/// 2. The main function registers functions that should be run on |
| 23 | +/// each program, in sequence, after it is converted. |
| 24 | +/// 3. Analyses will then access functions using the `at` function |
| 25 | +/// \tparam bodyt: The type of the function bodies, usually goto_programt |
| 26 | +template<typename bodyt> |
| 27 | +class lazy_goto_functions_mapt final |
| 28 | +{ |
| 29 | +public: |
| 30 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 31 | + typedef irep_idt key_type; |
| 32 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 33 | + typedef goto_function_templatet<bodyt> &mapped_type; |
| 34 | + /// The type of elements returned by const members |
| 35 | + // NOLINTNEXTLINE(readability/identifiers) - name matches mapped_type |
| 36 | + typedef const goto_function_templatet<bodyt> &const_mapped_type; |
| 37 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 38 | + typedef std::pair<const key_type, goto_function_templatet<bodyt>> value_type; |
| 39 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 40 | + typedef value_type &reference; |
| 41 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 42 | + typedef const value_type &const_reference; |
| 43 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 44 | + typedef value_type *pointer; |
| 45 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 46 | + typedef const value_type *const_pointer; |
| 47 | + // NOLINTNEXTLINE(readability/identifiers) - name matches those used in STL |
| 48 | + typedef std::size_t size_type; |
| 49 | + |
| 50 | + typedef |
| 51 | + std::function<void(goto_functionst::goto_functiont &function)> |
| 52 | + post_process_functiont; |
| 53 | + |
| 54 | +private: |
| 55 | + typedef std::map<key_type, goto_function_templatet<bodyt>> underlying_mapt; |
| 56 | + underlying_mapt &goto_functions; |
| 57 | + /// Names of functions that are already fully available in the programt state. |
| 58 | + /// \remarks These functions do not need processing before being returned |
| 59 | + /// whenever they are requested |
| 60 | + mutable std::unordered_set<irep_idt, irep_id_hash> processed_functions; |
| 61 | + |
| 62 | + language_filest &language_files; |
| 63 | + symbol_tablet &symbol_table; |
| 64 | + // This is mutable because it has internal state that it changes during the |
| 65 | + // course of conversion. Strictly it should make that state mutable or |
| 66 | + // recreate it for each conversion, but it's easier just to store it mutable. |
| 67 | + mutable goto_convert_functionst convert_functions; |
| 68 | + const post_process_functiont post_process_function; |
| 69 | + |
| 70 | +public: |
| 71 | + /// Creates a lazy_goto_functions_mapt. |
| 72 | + lazy_goto_functions_mapt( |
| 73 | + underlying_mapt &goto_functions, |
| 74 | + language_filest &language_files, |
| 75 | + symbol_tablet &symbol_table, |
| 76 | + post_process_functiont post_process_function, |
| 77 | + message_handlert &message_handler) |
| 78 | + : goto_functions(goto_functions), |
| 79 | + language_files(language_files), |
| 80 | + symbol_table(symbol_table), |
| 81 | + convert_functions(symbol_table, message_handler), |
| 82 | + post_process_function(std::move(post_process_function)) |
| 83 | + { |
| 84 | + } |
| 85 | + |
| 86 | + /// Gets the number of functions in the map. |
| 87 | + /// \return The number of functions in the map. |
| 88 | + size_type size() const |
| 89 | + { |
| 90 | + return language_files.lazy_method_map.size(); |
| 91 | + } |
| 92 | + |
| 93 | + /// Returns whether the map contains any mappings. |
| 94 | + /// \return Whether the map contains any mappings. |
| 95 | + bool empty() const { return language_files.lazy_method_map.empty(); } |
| 96 | + |
| 97 | + /// Checks whether a given function exists in the map. |
| 98 | + /// \param name: The name of the function to search for. |
| 99 | + /// \return True if the map contains the given function. |
| 100 | + bool contains(const key_type &name) const |
| 101 | + { |
| 102 | + return language_files.lazy_method_map.count(name)!=0; |
| 103 | + } |
| 104 | + |
| 105 | + /// Gets the body for a given function. |
| 106 | + /// \param name: The name of the function to search for. |
| 107 | + /// \return The function body corresponding to the given function. |
| 108 | + const_mapped_type at(const key_type &name) const |
| 109 | + { |
| 110 | + return ensure_function_loaded_internal(name).second; |
| 111 | + } |
| 112 | + |
| 113 | + /// Gets the body for a given function. |
| 114 | + /// \param name: The name of the function to search for. |
| 115 | + /// \return The function body corresponding to the given function. |
| 116 | + mapped_type at(const key_type &name) |
| 117 | + { |
| 118 | + return ensure_function_loaded_internal(name).second; |
| 119 | + } |
| 120 | + |
| 121 | + void unload(const key_type &name) const { goto_functions.erase(name); } |
| 122 | + |
| 123 | +private: |
| 124 | + // This returns a non-const reference, but if you use this method from a |
| 125 | + // const method then you should not return such a reference without making it |
| 126 | + // const first |
| 127 | + reference ensure_function_loaded_internal(const key_type &name) const |
| 128 | + { |
| 129 | + reference named_function=ensure_entry_converted(name); |
| 130 | + mapped_type function=named_function.second; |
| 131 | + if(processed_functions.count(name)==0) |
| 132 | + { |
| 133 | + // Run function-pass conversions |
| 134 | + post_process_function(function); |
| 135 | + // Assign procedure-local location numbers for now |
| 136 | + function.body.compute_location_numbers(); |
| 137 | + processed_functions.insert(name); |
| 138 | + } |
| 139 | + return named_function; |
| 140 | + } |
| 141 | + |
| 142 | + reference ensure_entry_converted(const key_type &name) const |
| 143 | + { |
| 144 | + typename underlying_mapt::iterator it=goto_functions.find(name); |
| 145 | + if(it!=goto_functions.end()) |
| 146 | + return *it; |
| 147 | + if(symbol_table.lookup_ref(name).value.is_nil()) |
| 148 | + { |
| 149 | + // Fill in symbol table entry body |
| 150 | + // If this returns false then it's a stub |
| 151 | + language_files.convert_lazy_method(name, symbol_table); |
| 152 | + } |
| 153 | + // Create goto_functiont |
| 154 | + goto_functionst::goto_functiont function; |
| 155 | + convert_functions.convert_function(name, function); |
| 156 | + // Add to map |
| 157 | + return *goto_functions.emplace(name, std::move(function)).first; |
| 158 | + } |
| 159 | +}; |
| 160 | + |
| 161 | +#endif // CPROVER_GOTO_PROGRAMS_LAZY_GOTO_FUNCTIONS_MAP_H |
0 commit comments