diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/oa_hash_map.h | 42 | ||||
-rw-r--r-- | core/project_settings.cpp | 67 |
2 files changed, 71 insertions, 38 deletions
diff --git a/core/oa_hash_map.h b/core/oa_hash_map.h index c595e445d5..775e17fdb5 100644 --- a/core/oa_hash_map.h +++ b/core/oa_hash_map.h @@ -48,17 +48,19 @@ * * Only used keys and values are constructed. For free positions there's space * in the arrays for each, but that memory is kept uninitialized. + * + * The assignment operator copy the pairs from one map to the other. */ template <class TKey, class TValue, class Hasher = HashMapHasherDefault, class Comparator = HashMapComparatorDefault<TKey>> class OAHashMap { private: - TValue *values; - TKey *keys; - uint32_t *hashes; + TValue *values = nullptr; + TKey *keys = nullptr; + uint32_t *hashes = nullptr; - uint32_t capacity; + uint32_t capacity = 0; uint32_t num_elements = 0; @@ -142,7 +144,9 @@ private: void _resize_and_rehash(uint32_t p_new_capacity) { uint32_t old_capacity = capacity; - capacity = p_new_capacity; + + // Capacity can't be 0. + capacity = MAX(1, p_new_capacity); TKey *old_keys = keys; TValue *old_values = values; @@ -157,6 +161,11 @@ private: hashes[i] = 0; } + if (old_capacity == 0) { + // Nothing to do. + return; + } + for (uint32_t i = 0; i < old_capacity; i++) { if (old_hashes[i] == EMPTY_HASH) { continue; @@ -341,17 +350,32 @@ public: return it; } - OAHashMap(const OAHashMap &) = delete; // Delete the copy constructor so we don't get unexpected copies and dangling pointers. - OAHashMap &operator=(const OAHashMap &) = delete; // Same for assignment operator. + OAHashMap(const OAHashMap &p_other) { + (*this) = p_other; + } + + OAHashMap &operator=(const OAHashMap &p_other) { + if (capacity != 0) { + clear(); + } + + _resize_and_rehash(p_other.capacity); + + for (Iterator it = p_other.iter(); it.valid; it = p_other.next_iter(it)) { + set(*it.key, *it.value); + } + return *this; + } OAHashMap(uint32_t p_initial_capacity = 64) { - capacity = p_initial_capacity; + // Capacity can't be 0. + capacity = MAX(1, p_initial_capacity); keys = static_cast<TKey *>(Memory::alloc_static(sizeof(TKey) * capacity)); values = static_cast<TValue *>(Memory::alloc_static(sizeof(TValue) * capacity)); hashes = static_cast<uint32_t *>(Memory::alloc_static(sizeof(uint32_t) * capacity)); - for (uint32_t i = 0; i < p_initial_capacity; i++) { + for (uint32_t i = 0; i < capacity; i++) { hashes[i] = EMPTY_HASH; } } diff --git a/core/project_settings.cpp b/core/project_settings.cpp index 83d94ad607..5247f6da40 100644 --- a/core/project_settings.cpp +++ b/core/project_settings.cpp @@ -295,10 +295,16 @@ void ProjectSettings::_convert_to_last_version(int p_from_version) { * using the following merit order: * - If using NetworkClient, try to lookup project file or fail. * - If --main-pack was passed by the user (`p_main_pack`), load it or fail. - * - Search for .pck file matching binary name. There are two possibilities: - * o exec_path.get_basename() + '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') - * o exec_path + '.pck' (e.g. 'linux_game' -> 'linux_game.pck') - * For each tentative, if the file exists, load it or fail. + * - Search for project PCKs automatically. For each step we try loading a potential + * PCK, and if it doesn't work, we proceed to the next step. If any step succeeds, + * we try loading the project settings, and abort if it fails. Steps: + * o Bundled PCK in the executable. + * o [macOS only] PCK with same basename as the binary in the .app resource dir. + * o PCK with same basename as the binary in the binary's directory. We handle both + * changing the extension to '.pck' (e.g. 'win_game.exe' -> 'win_game.pck') and + * appending '.pck' to the binary name (e.g. 'linux_game' -> 'linux_game.pck'). + * o PCK with the same basename as the binary in the current working directory. + * Same as above for the two possible PCK file names. * - On relevant platforms (Android/iOS), lookup project file in OS resource path. * If found, load it or fail. * - Lookup project file in passed `p_path` (--path passed by the user), i.e. we @@ -339,65 +345,68 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b String exec_path = OS::get_singleton()->get_executable_path(); if (exec_path != "") { - // Attempt with exec_name.pck - // (This is the usual case when distributing a Godot game.) + // We do several tests sequentially until one succeeds to find a PCK, + // and if so we attempt loading it at the end. - // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle) - // or the exec path's basename + '.pck' (Windows). - // We need to test both possibilities as extensions for Linux binaries are optional - // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck'). + // Attempt with PCK bundled into executable. + bool found = _load_resource_pack(exec_path); + // Attempt with exec_name.pck. + // (This is the usual case when distributing a Godot game.) String exec_dir = exec_path.get_base_dir(); String exec_filename = exec_path.get_file(); String exec_basename = exec_filename.get_basename(); - // Attempt with PCK bundled into executable - bool found = _load_resource_pack(exec_path); + // Based on the OS, it can be the exec path + '.pck' (Linux w/o extension, macOS in .app bundle) + // or the exec path's basename + '.pck' (Windows). + // We need to test both possibilities as extensions for Linux binaries are optional + // (so both 'mygame.bin' and 'mygame' should be able to find 'mygame.pck'). #ifdef OSX_ENABLED if (!found) { - // Attempt to load PCK from macOS .app bundle resources + // Attempt to load PCK from macOS .app bundle resources. found = _load_resource_pack(OS::get_singleton()->get_bundle_resource_dir().plus_file(exec_basename + ".pck")); } #endif if (!found) { - // Try to load data pack at the location of the executable - // As mentioned above, we have two potential names to attempt + // Try to load data pack at the location of the executable. + // As mentioned above, we have two potential names to attempt. found = _load_resource_pack(exec_dir.plus_file(exec_basename + ".pck")) || _load_resource_pack(exec_dir.plus_file(exec_filename + ".pck")); + } - if (!found) { - // If we couldn't find them next to the executable, we attempt - // the current working directory. Same story, two tests. - found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck"); - } + if (!found) { + // If we couldn't find them next to the executable, we attempt + // the current working directory. Same story, two tests. + found = _load_resource_pack(exec_basename + ".pck") || _load_resource_pack(exec_filename + ".pck"); } - // If we opened our package, try and load our project + // If we opened our package, try and load our project. if (found) { Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { - // Load override from location of executable - // Optional, we don't mind if it fails + // Load override from location of the executable. + // Optional, we don't mind if it fails. _load_settings_text(exec_path.get_base_dir().plus_file("override.cfg")); } return err; } } - // Try to use the filesystem for files, according to OS. (only Android -when reading from pck- and iOS use this) + // Try to use the filesystem for files, according to OS. + // (Only Android -when reading from pck- and iOS use this.) if (OS::get_singleton()->get_resource_dir() != "") { // OS will call ProjectSettings->get_resource_path which will be empty if not overridden! // If the OS would rather use a specific location, then it will not be empty. resource_path = OS::get_singleton()->get_resource_dir().replace("\\", "/"); if (resource_path != "" && resource_path[resource_path.length() - 1] == '/') { - resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. } Error err = _load_settings_text_or_binary("res://project.godot", "res://project.binary"); if (err == OK) { - // Optional, we don't mind if it fails + // Optional, we don't mind if it fails. _load_settings_text("res://override.cfg"); } return err; @@ -418,7 +427,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b while (true) { err = _load_settings_text_or_binary(current_dir.plus_file("project.godot"), current_dir.plus_file("project.binary")); if (err == OK) { - // Optional, we don't mind if it fails + // Optional, we don't mind if it fails. _load_settings_text(current_dir.plus_file("override.cfg")); candidate = current_dir; found = true; @@ -438,7 +447,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b } resource_path = candidate; - resource_path = resource_path.replace("\\", "/"); // windows path to unix path just in case + resource_path = resource_path.replace("\\", "/"); // Windows path to Unix path just in case. memdelete(d); if (!found) { @@ -446,7 +455,7 @@ Error ProjectSettings::_setup(const String &p_path, const String &p_main_pack, b } if (resource_path.length() && resource_path[resource_path.length() - 1] == '/') { - resource_path = resource_path.substr(0, resource_path.length() - 1); // chop end + resource_path = resource_path.substr(0, resource_path.length() - 1); // Chop end. } return OK; |