diff --git a/src/Makefile b/src/Makefile index 3cb06d26..142b1784 100644 --- a/src/Makefile +++ b/src/Makefile @@ -36,7 +36,8 @@ OBJBASE=eclass.o fchar.o filedetails.o fileid.o pdtoken.o pltoken.o debug.o \ error.o fdep.o fcall.o call.o idquery.o query.o funquery.o \ logo.o workdb.o obfuscate.o sql.o md5.o os.o pager.o \ option.o filequery.o mcall.o filemetrics.o funmetrics.o ctconst.o \ - dirbrowse.o html.o fileutils.o gdisplay.o globobj.o ctag.o timer.o + dirbrowse.o html.o fileutils.o gdisplay.o globobj.o ctag.o timer.o \ + static_init.o # monitor.o @@ -63,7 +64,7 @@ CFILES=md5.c attr.cpp call.cpp cscout.cpp ctag.cpp ctconst.cpp \ logo.cpp macro.cpp mcall.cpp metrics.cpp obfuscate.cpp option.cpp os.cpp \ pager.cpp pdtoken.cpp pltoken.cpp ptoken.cpp query.cpp simple_cpp.cpp \ sql.cpp stab.cpp tchar.cpp timer.cpp token.cpp tokid.cpp \ - tokmap.cpp type.cpp workdb.cpp + tokmap.cpp type.cpp workdb.cpp static_init.cpp HEADERS=attr.h call.h compiledre.h cpp.h ctag.h ctconst.h ctoken.h \ debug.h defs.h dirbrowse.h eclass.h error.h eval.h fcall.h fchar.h fdep.h \ diff --git a/src/filedetails.cpp b/src/filedetails.cpp index 5718e04e..854f223c 100644 --- a/src/filedetails.cpp +++ b/src/filedetails.cpp @@ -57,27 +57,6 @@ #include "md5.h" #include "os.h" -/* - * Return the map from file id to file details, controlling the order of its - * construction through the "Construct on First Use" idiom. - */ -FI_id_to_details & -Filedetails::get_i2d() -{ - static FI_id_to_details i2d; - return i2d; -} - -/* - * Return a map of files that are exact duplicates, controlling the order - * of its construction through the "Construct on First Use" idiom. - */ -FI_hash_to_ids & -Filedetails::get_identical_files() -{ - static FI_hash_to_ids identical_files; - return identical_files; -} Filedetails::Filedetails(string n, bool r, const FileHash &h) : name(n), @@ -194,7 +173,7 @@ Filedetails::set_hand_edited() void Filedetails::clear_all_visited() { - for (FI_id_to_details::iterator i = get_i2d().begin(); i != get_i2d().end(); i++) + for (FI_id_to_details::iterator i = i2d.begin(); i != i2d.end(); i++) i->clear_visited(); } @@ -248,7 +227,7 @@ unify_file_identifiers(const set &fs) void Filedetails::unify_identical_files(void) { - for (FI_hash_to_ids::const_iterator i = get_identical_files().begin(); i != get_identical_files().end(); i++) + for (FI_hash_to_ids::const_iterator i = identical_files.begin(); i != identical_files.end(); i++) if (i->second.size() > 1) unify_file_identifiers(i->second); } diff --git a/src/filedetails.h b/src/filedetails.h index f935086d..232981e0 100644 --- a/src/filedetails.h +++ b/src/filedetails.h @@ -40,7 +40,6 @@ using namespace std; * in order to keep *values.begin() invariant. * This property is used by tokid unique for returning unique tokids */ -typedef vector FileHash; typedef map > FI_hash_to_ids; // Details we keep for each included file for a given includer @@ -95,7 +94,7 @@ class Filedetails { vector processed_lines;; FileIncMap includes; // Files we include FileIncMap includers; // Files that include us - FileHash hash; // MD5 hash for the file's contents + FileHash hash; // MD5 hash for the file's contents int ipath_offset; // Offset in the include file path where this file was found Fileidset runtime_uses; // Files whose global objects this file uses at runtime Fileidset runtime_used_by; // Files that use at runtime this file's global objects @@ -107,11 +106,8 @@ class Filedetails { string contents; // Original contents, if hand-edited bool visited; // For calculating transitive closures - // Get map from id to file details - static FI_id_to_details& get_i2d(); - - // Return map of files that are exact duplicates - static FI_hash_to_ids& get_identical_files(); + static FI_id_to_details i2d; // From id to file details + static FI_hash_to_ids identical_files;// Files that are exact duplicates public: Attributes attr; // The projects this file participates in FileMetrics pre_cpp_metrics; // File's metrics before cpp @@ -123,16 +119,16 @@ class Filedetails { // Return the instance associated with the specified id static Filedetails &get_instance(Fileid fi) { - return get_i2d()[fi.get_id()]; + return i2d[fi.get_id()]; } static FI_id_to_details::size_type get_i2d_map_size() { - return get_i2d().size(); + return i2d.size(); } // Add a new instance with the specified ctor values - static void add_instance(string n, bool r, const FileHash &hash) { - get_i2d().emplace_back(n, r, hash); + static void add_instance(string n, bool r, const FileHash &h) { + i2d.emplace_back(n, r, h); } // Unify identifiers of files that are exact copies @@ -142,9 +138,8 @@ class Filedetails { static void clear_all_visited(); // Add fi to the set of files that have the identical hash - static void add_identical_file(const FileHash &hash, Fileid fi) { - auto &file_set = get_identical_files()[hash]; - file_set.insert(fi); + static void add_identical_file(FileHash hash, Fileid fi) { + identical_files[hash].insert(fi); } const string& get_name() const { return name; } @@ -276,7 +271,7 @@ class Filedetails { ; // Return the set of files that are the same as this (including this) static const Fileidset & get_identical_files(Fileid id) { - return get_identical_files()[get_instance(id).get_filehash()]; + return identical_files[get_instance(id).get_filehash()]; } // Return the set of files that we depend on for runtime objects diff --git a/src/fileid.cpp b/src/fileid.cpp index 5491ef4f..5698282c 100644 --- a/src/fileid.cpp +++ b/src/fileid.cpp @@ -59,29 +59,6 @@ int Fileid::counter; // To generate ids list Fileid::ro_prefix; // Read-only prefix - // -/* - * Return the anonymous id, controlling the order of its construction - * through the "Construct on First Use" idiom. - */ -Fileid -Fileid::get_anonymous() -{ - static Fileid anonymous(Fileid("ANONYMOUS", 0)); - return anonymous; -} - -/* - * Return the map from unique name to id, controlling the order of its - * construction through the "Construct on First Use" idiom. - */ -FI_uname_to_id & -Fileid::get_u2i() -{ - static FI_uname_to_id u2i; - return u2i; -} - #ifdef WIN32 // Return the canonical representation of a WIN32 filename character @@ -128,7 +105,7 @@ Fileid::Fileid(const string &name) string sid(get_uniq_fname_string(name.c_str())); FI_uname_to_id::const_iterator uni; - if ((uni = get_u2i().find(sid)) != get_u2i().end()) { + if ((uni = u2i.find(sid)) != u2i.end()) { // Filename exists; our id is the one from the map id = uni->second; } else { @@ -137,7 +114,7 @@ Fileid::Fileid(const string &name) unsigned char *h = MD5File(name.c_str()); FileHash hash(h, h + 16); - get_u2i()[sid] = id = counter++; + u2i[sid] = id = counter++; Filedetails::add_instance(fpath, is_readonly(name.c_str()), hash); Filedetails::add_identical_file(hash, *this); @@ -146,10 +123,10 @@ Fileid::Fileid(const string &name) cout << "Fileid(" << name << ") = " << id << "\n"; } -// Used for initialization and testing; not for real files +// User for initialization and testing; not for real files Fileid::Fileid(const string &name, int i) { - get_u2i()[name] = i; + u2i[name] = i; Filedetails::add_instance(name, true, FileHash()); id = i; Filedetails::add_identical_file(FileHash(), *this); diff --git a/src/fileid.h b/src/fileid.h index f91ea046..7f3057c3 100644 --- a/src/fileid.h +++ b/src/fileid.h @@ -29,6 +29,7 @@ #include #include #include +#include #include using namespace std; @@ -36,6 +37,7 @@ using namespace std; class Fchar; class FileMetrics; +typedef vector FileHash; typedef map FI_uname_to_id; /* @@ -49,19 +51,13 @@ class Fileid { int id; // One global unique id per workspace file static int counter; // To generate ids - // Return map from unique name to id - static FI_uname_to_id& get_u2i(); + static FI_uname_to_id u2i; // From unique name to id // Construct a new Fileid given a name and id value // Only used internally for creating the anonymous id Fileid(const string& name, int id); - - /* - * Return an anonymous id, controlling the order of its construction - * through the "Construct on First Use" idiom. - */ - static Fileid get_anonymous(); - + // An anonymous id + static Fileid anonymous; // The prefix for read-only files static list ro_prefix; // And a function to check fnames against it @@ -73,7 +69,7 @@ class Fileid { // Create it without any checking from an integer Fileid(int i) : id(i) {} // Construct an anonymous Fileid - Fileid() { *this = get_anonymous(); }; + Fileid() { *this = Fileid::anonymous; }; // Return the full file path of a given id const string& get_path() const; const string get_fname() const; diff --git a/src/static_init.cpp b/src/static_init.cpp new file mode 100644 index 00000000..70087ba2 --- /dev/null +++ b/src/static_init.cpp @@ -0,0 +1,60 @@ +/* + * (C) Copyright 2024 Diomidis Spinellis + * + * This file is part of CScout. + * + * CScout is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * CScout is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with CScout. If not, see . + * + * + * Statically initialized values. C++ only guarantees the initialization + * order of values that reside in the same compilation unit (from top to + * bottom). Therefore, define and initialize all related elements here + * in the appropriate order. + * + * The correct order of initialization can be also automatically + * guaranted with the "Construct on First Use" idiom, at the cost + * however of one non-inlinable function call for each access. + * The best wall clock time for cscout -c awk.cs with the current approach + * approach is 0.473 s vs 0.484 s for the Construct on First Use approach. + * + */ + +#include "fileid.h" +#include "filedetails.h" + +/* + * For the following their order is established as follows: + * 1. anoynmous object is initialized via the constructor + * Fileid::Fileid(const string &name, int i) which: + * 1.1 uses u2i + * 1.2 calls Filedetails::add_instance(name, true, FileHash()) using i2d + * 1.3 calls Filedetails::add_identical_file(FileHash(), *this) using + * Filedetails::identical_files + * Initialize from inside (1.X) to outside. + */ + +// Map from unique name to id +FI_uname_to_id Fileid::u2i; + +// Map from id to file details; first element is anonymous +FI_id_to_details Filedetails::i2d; + +// Files that are exact duplicates +FI_hash_to_ids Filedetails::identical_files; + +/* + * An object used creating Fileids with an empty initializer, + * which is required for initially empty Tokids. + */ +Fileid Fileid::anonymous = Fileid("ANONYMOUS", 0);