mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-10-31 04:32:33 +00:00 
			
		
		
		
	Speed up build
This commit is contained in:
		
							parent
							
								
									c68548a2ca
								
							
						
					
					
						commit
						bee8bacefd
					
				| @ -5,6 +5,7 @@ | ||||
| #include "optional.h" | ||||
| 
 | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <vector> | ||||
| 
 | ||||
| struct FileContents { | ||||
|  | ||||
| @ -30,6 +30,15 @@ void VerifyUnique(const std::vector<T>& values0) { | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) { | ||||
|   std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end()); | ||||
|   dest->erase( | ||||
|       std::remove_if(dest->begin(), dest->end(), | ||||
|                      [&](const T& t) { return to_remove_set.count(t) > 0; }), | ||||
|       dest->end()); | ||||
| } | ||||
| 
 | ||||
| optional<QueryType::Def> ToQuery(const IdMap& id_map, | ||||
|                                  const IndexType::Def& type) { | ||||
|   if (type.detailed_name.empty()) | ||||
|  | ||||
							
								
								
									
										204
									
								
								src/test.cc
									
									
									
									
									
								
							
							
						
						
									
										204
									
								
								src/test.cc
									
									
									
									
									
								
							| @ -5,8 +5,12 @@ | ||||
| #include "serializer.h" | ||||
| #include "utils.h" | ||||
| 
 | ||||
| #include <doctest/doctest.h> | ||||
| #include <loguru/loguru.hpp> | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <fstream> | ||||
| #include <iostream> | ||||
| 
 | ||||
| // The 'diff' utility is available and we can use dprintf(3).
 | ||||
| @ -33,6 +37,155 @@ std::string ToString(const rapidjson::Document& document) { | ||||
|   return UpdateToRnNewlines(output); | ||||
| } | ||||
| 
 | ||||
| void ParseTestExpectation( | ||||
|     const std::string& filename, | ||||
|     const std::vector<std::string>& lines_with_endings, | ||||
|     TextReplacer* replacer, | ||||
|     std::vector<std::string>* flags, | ||||
|     std::unordered_map<std::string, std::string>* output_sections) { | ||||
| #if false | ||||
| #include "bar.h" | ||||
| 
 | ||||
|   void foo(); | ||||
| 
 | ||||
|   /*
 | ||||
|   // DOCS for TEXT_REPLACE:
 | ||||
|   //  Each line under TEXT_REPLACE is a replacement, ie, the two entries will be
 | ||||
|   //  considered equivalent. This is useful for USRs which vary across files.
 | ||||
| 
 | ||||
|   // DOCS for EXTRA_FLAGS:
 | ||||
|   //  Additional flags to pass to clang.
 | ||||
| 
 | ||||
|   // DOCS for OUTPUT:
 | ||||
|   //  If no name is given assume to be this file name. If there is not an output
 | ||||
|   //  section for a file it is not checked.
 | ||||
| 
 | ||||
|   TEXT_REPLACE: | ||||
|   foo <===> bar | ||||
|   one <===> two | ||||
| 
 | ||||
|   EXTRA_FLAGS: | ||||
|   -std=c++14 | ||||
| 
 | ||||
|   OUTPUT: | ||||
|   {} | ||||
| 
 | ||||
|   OUTPUT: bar.cc | ||||
|   {} | ||||
| 
 | ||||
|   OUTPUT: bar.h | ||||
|   {} | ||||
|   */ | ||||
| #endif | ||||
| 
 | ||||
|   // Scan for TEXT_REPLACE:
 | ||||
|   { | ||||
|     bool in_output = false; | ||||
|     for (std::string line : lines_with_endings) { | ||||
|       TrimInPlace(line); | ||||
| 
 | ||||
|       if (StartsWith(line, "TEXT_REPLACE:")) { | ||||
|         assert(!in_output && "multiple TEXT_REPLACE sections"); | ||||
|         in_output = true; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       if (in_output && line.empty()) | ||||
|         break; | ||||
| 
 | ||||
|       if (in_output) { | ||||
|         static const std::string kKey = " <===> "; | ||||
|         size_t index = line.find(kKey); | ||||
|         LOG_IF_S(FATAL, index == std::string::npos) | ||||
|             << " No '" << kKey << "' in replacement string '" << line << "'" | ||||
|             << ", index=" << index; | ||||
| 
 | ||||
|         TextReplacer::Replacement replacement; | ||||
|         replacement.from = line.substr(0, index); | ||||
|         replacement.to = line.substr(index + kKey.size()); | ||||
|         TrimInPlace(replacement.from); | ||||
|         TrimInPlace(replacement.to); | ||||
|         replacer->replacements.push_back(replacement); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Scan for EXTRA_FLAGS:
 | ||||
|   { | ||||
|     bool in_output = false; | ||||
|     for (std::string line : lines_with_endings) { | ||||
|       TrimInPlace(line); | ||||
| 
 | ||||
|       if (StartsWith(line, "EXTRA_FLAGS:")) { | ||||
|         assert(!in_output && "multiple EXTRA_FLAGS sections"); | ||||
|         in_output = true; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       if (in_output && line.empty()) | ||||
|         break; | ||||
| 
 | ||||
|       if (in_output) | ||||
|         flags->push_back(line); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Scan for OUTPUT:
 | ||||
|   { | ||||
|     std::string active_output_filename; | ||||
|     std::string active_output_contents; | ||||
| 
 | ||||
|     bool in_output = false; | ||||
|     for (std::string line_with_ending : lines_with_endings) { | ||||
|       if (StartsWith(line_with_ending, "*/")) | ||||
|         break; | ||||
| 
 | ||||
|       if (StartsWith(line_with_ending, "OUTPUT:")) { | ||||
|         // Terminate the previous output section if we found a new one.
 | ||||
|         if (in_output) { | ||||
|           (*output_sections)[active_output_filename] = active_output_contents; | ||||
|         } | ||||
| 
 | ||||
|         // Try to tokenize OUTPUT: based one whitespace. If there is more than
 | ||||
|         // one token assume it is a filename.
 | ||||
|         std::vector<std::string> tokens = SplitString(line_with_ending, " "); | ||||
|         if (tokens.size() > 1) { | ||||
|           active_output_filename = tokens[1]; | ||||
|           TrimInPlace(active_output_filename); | ||||
|         } else { | ||||
|           active_output_filename = filename; | ||||
|         } | ||||
|         active_output_contents = ""; | ||||
| 
 | ||||
|         in_output = true; | ||||
|       } else if (in_output) | ||||
|         active_output_contents += line_with_ending; | ||||
|     } | ||||
| 
 | ||||
|     if (in_output) | ||||
|       (*output_sections)[active_output_filename] = active_output_contents; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UpdateTestExpectation(const std::string& filename, | ||||
|                            const std::string& expectation, | ||||
|                            const std::string& actual) { | ||||
|   // Read the entire file into a string.
 | ||||
|   std::ifstream in(filename); | ||||
|   std::string str; | ||||
|   str.assign(std::istreambuf_iterator<char>(in), | ||||
|              std::istreambuf_iterator<char>()); | ||||
|   in.close(); | ||||
| 
 | ||||
|   // Replace expectation
 | ||||
|   auto it = str.find(expectation); | ||||
|   assert(it != std::string::npos); | ||||
|   str.replace(it, expectation.size(), actual); | ||||
| 
 | ||||
|   // Write it back out.
 | ||||
|   WriteToFile(filename, str); | ||||
| } | ||||
| 
 | ||||
| void DiffDocuments(std::string path, | ||||
|                    std::string path_section, | ||||
|                    rapidjson::Document& expected, | ||||
| @ -309,3 +462,54 @@ bool RunIndexTests(const std::string& filter_path, bool enable_update) { | ||||
| // TODO: ctor/dtor, copy ctor
 | ||||
| // TODO: Always pass IndexFile by pointer, ie, search and remove all IndexFile&
 | ||||
| // refs.
 | ||||
| 
 | ||||
| TEST_SUITE("ParseTestExpectation") { | ||||
|   TEST_CASE("Parse TEXT_REPLACE") { | ||||
|     // clang-format off
 | ||||
|     std::vector<std::string> lines_with_endings = { | ||||
|         "/*\n", | ||||
|         "TEXT_REPLACE:\n", | ||||
|         "  foo   <===> \tbar  \n", | ||||
|         "01 <===> 2\n", | ||||
|         "\n", | ||||
|         "*/\n"}; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     TextReplacer text_replacer; | ||||
|     std::vector<std::string> flags; | ||||
|     std::unordered_map<std::string, std::string> all_expected_output; | ||||
|     ParseTestExpectation("foo.cc", lines_with_endings, &text_replacer, &flags, | ||||
|                          &all_expected_output); | ||||
| 
 | ||||
|     REQUIRE(text_replacer.replacements.size() == 2); | ||||
|     REQUIRE(text_replacer.replacements[0].from == "foo"); | ||||
|     REQUIRE(text_replacer.replacements[0].to == "bar"); | ||||
|     REQUIRE(text_replacer.replacements[1].from == "01"); | ||||
|     REQUIRE(text_replacer.replacements[1].to == "2"); | ||||
|   } | ||||
| 
 | ||||
|   TEST_CASE("Apply TEXT_REPLACE") { | ||||
|     TextReplacer replacer; | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"foo", "bar"}); | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"01", "2"}); | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"3", "456"}); | ||||
| 
 | ||||
|     // Equal-length.
 | ||||
|     REQUIRE(replacer.Apply("foo") == "bar"); | ||||
|     REQUIRE(replacer.Apply("bar") == "bar"); | ||||
| 
 | ||||
|     // Shorter replacement.
 | ||||
|     REQUIRE(replacer.Apply("01") == "2"); | ||||
|     REQUIRE(replacer.Apply("2") == "2"); | ||||
| 
 | ||||
|     // Longer replacement.
 | ||||
|     REQUIRE(replacer.Apply("3") == "456"); | ||||
|     REQUIRE(replacer.Apply("456") == "456"); | ||||
| 
 | ||||
|     // Content before-after replacement.
 | ||||
|     REQUIRE(replacer.Apply("aaaa01bbbb") == "aaaa2bbbb"); | ||||
| 
 | ||||
|     // Multiple replacements.
 | ||||
|     REQUIRE(replacer.Apply("foofoobar0123") == "barbarbar22456"); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										200
									
								
								src/utils.cc
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								src/utils.cc
									
									
									
									
									
								
							| @ -374,155 +374,6 @@ std::string TextReplacer::Apply(const std::string& content) { | ||||
|   return result; | ||||
| } | ||||
| 
 | ||||
| void ParseTestExpectation( | ||||
|     const std::string& filename, | ||||
|     const std::vector<std::string>& lines_with_endings, | ||||
|     TextReplacer* replacer, | ||||
|     std::vector<std::string>* flags, | ||||
|     std::unordered_map<std::string, std::string>* output_sections) { | ||||
| #if false | ||||
| #include "bar.h" | ||||
| 
 | ||||
|   void foo(); | ||||
| 
 | ||||
|   /*
 | ||||
|   // DOCS for TEXT_REPLACE:
 | ||||
|   //  Each line under TEXT_REPLACE is a replacement, ie, the two entries will be
 | ||||
|   //  considered equivalent. This is useful for USRs which vary across files.
 | ||||
| 
 | ||||
|   // DOCS for EXTRA_FLAGS:
 | ||||
|   //  Additional flags to pass to clang.
 | ||||
| 
 | ||||
|   // DOCS for OUTPUT:
 | ||||
|   //  If no name is given assume to be this file name. If there is not an output
 | ||||
|   //  section for a file it is not checked.
 | ||||
| 
 | ||||
|   TEXT_REPLACE: | ||||
|   foo <===> bar | ||||
|   one <===> two | ||||
| 
 | ||||
|   EXTRA_FLAGS: | ||||
|   -std=c++14 | ||||
| 
 | ||||
|   OUTPUT: | ||||
|   {} | ||||
| 
 | ||||
|   OUTPUT: bar.cc | ||||
|   {} | ||||
| 
 | ||||
|   OUTPUT: bar.h | ||||
|   {} | ||||
|   */ | ||||
| #endif | ||||
| 
 | ||||
|   // Scan for TEXT_REPLACE:
 | ||||
|   { | ||||
|     bool in_output = false; | ||||
|     for (std::string line : lines_with_endings) { | ||||
|       TrimInPlace(line); | ||||
| 
 | ||||
|       if (StartsWith(line, "TEXT_REPLACE:")) { | ||||
|         assert(!in_output && "multiple TEXT_REPLACE sections"); | ||||
|         in_output = true; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       if (in_output && line.empty()) | ||||
|         break; | ||||
| 
 | ||||
|       if (in_output) { | ||||
|         static const std::string kKey = " <===> "; | ||||
|         size_t index = line.find(kKey); | ||||
|         LOG_IF_S(FATAL, index == std::string::npos) | ||||
|             << " No '" << kKey << "' in replacement string '" << line << "'" | ||||
|             << ", index=" << index; | ||||
| 
 | ||||
|         TextReplacer::Replacement replacement; | ||||
|         replacement.from = line.substr(0, index); | ||||
|         replacement.to = line.substr(index + kKey.size()); | ||||
|         TrimInPlace(replacement.from); | ||||
|         TrimInPlace(replacement.to); | ||||
|         replacer->replacements.push_back(replacement); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Scan for EXTRA_FLAGS:
 | ||||
|   { | ||||
|     bool in_output = false; | ||||
|     for (std::string line : lines_with_endings) { | ||||
|       TrimInPlace(line); | ||||
| 
 | ||||
|       if (StartsWith(line, "EXTRA_FLAGS:")) { | ||||
|         assert(!in_output && "multiple EXTRA_FLAGS sections"); | ||||
|         in_output = true; | ||||
|         continue; | ||||
|       } | ||||
| 
 | ||||
|       if (in_output && line.empty()) | ||||
|         break; | ||||
| 
 | ||||
|       if (in_output) | ||||
|         flags->push_back(line); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // Scan for OUTPUT:
 | ||||
|   { | ||||
|     std::string active_output_filename; | ||||
|     std::string active_output_contents; | ||||
| 
 | ||||
|     bool in_output = false; | ||||
|     for (std::string line_with_ending : lines_with_endings) { | ||||
|       if (StartsWith(line_with_ending, "*/")) | ||||
|         break; | ||||
| 
 | ||||
|       if (StartsWith(line_with_ending, "OUTPUT:")) { | ||||
|         // Terminate the previous output section if we found a new one.
 | ||||
|         if (in_output) { | ||||
|           (*output_sections)[active_output_filename] = active_output_contents; | ||||
|         } | ||||
| 
 | ||||
|         // Try to tokenize OUTPUT: based one whitespace. If there is more than
 | ||||
|         // one token assume it is a filename.
 | ||||
|         std::vector<std::string> tokens = SplitString(line_with_ending, " "); | ||||
|         if (tokens.size() > 1) { | ||||
|           active_output_filename = tokens[1]; | ||||
|           TrimInPlace(active_output_filename); | ||||
|         } else { | ||||
|           active_output_filename = filename; | ||||
|         } | ||||
|         active_output_contents = ""; | ||||
| 
 | ||||
|         in_output = true; | ||||
|       } else if (in_output) | ||||
|         active_output_contents += line_with_ending; | ||||
|     } | ||||
| 
 | ||||
|     if (in_output) | ||||
|       (*output_sections)[active_output_filename] = active_output_contents; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void UpdateTestExpectation(const std::string& filename, | ||||
|                            const std::string& expectation, | ||||
|                            const std::string& actual) { | ||||
|   // Read the entire file into a string.
 | ||||
|   std::ifstream in(filename); | ||||
|   std::string str; | ||||
|   str.assign(std::istreambuf_iterator<char>(in), | ||||
|              std::istreambuf_iterator<char>()); | ||||
|   in.close(); | ||||
| 
 | ||||
|   // Replace expectation
 | ||||
|   auto it = str.find(expectation); | ||||
|   assert(it != std::string::npos); | ||||
|   str.replace(it, expectation.size(), actual); | ||||
| 
 | ||||
|   // Write it back out.
 | ||||
|   WriteToFile(filename, str); | ||||
| } | ||||
| 
 | ||||
| void WriteToFile(const std::string& filename, const std::string& content) { | ||||
|   std::ofstream file(filename, | ||||
|                      std::ios::out | std::ios::trunc | std::ios::binary); | ||||
| @ -601,57 +452,6 @@ std::string UpdateToRnNewlines(std::string output) { | ||||
|   return output; | ||||
| }; | ||||
| 
 | ||||
| TEST_SUITE("ParseTestExpectation") { | ||||
|   TEST_CASE("Parse TEXT_REPLACE") { | ||||
|     // clang-format off
 | ||||
|     std::vector<std::string> lines_with_endings = { | ||||
|         "/*\n", | ||||
|         "TEXT_REPLACE:\n", | ||||
|         "  foo   <===> \tbar  \n", | ||||
|         "01 <===> 2\n", | ||||
|         "\n", | ||||
|         "*/\n"}; | ||||
|     // clang-format on
 | ||||
| 
 | ||||
|     TextReplacer text_replacer; | ||||
|     std::vector<std::string> flags; | ||||
|     std::unordered_map<std::string, std::string> all_expected_output; | ||||
|     ParseTestExpectation("foo.cc", lines_with_endings, &text_replacer, &flags, | ||||
|                          &all_expected_output); | ||||
| 
 | ||||
|     REQUIRE(text_replacer.replacements.size() == 2); | ||||
|     REQUIRE(text_replacer.replacements[0].from == "foo"); | ||||
|     REQUIRE(text_replacer.replacements[0].to == "bar"); | ||||
|     REQUIRE(text_replacer.replacements[1].from == "01"); | ||||
|     REQUIRE(text_replacer.replacements[1].to == "2"); | ||||
|   } | ||||
| 
 | ||||
|   TEST_CASE("Apply TEXT_REPLACE") { | ||||
|     TextReplacer replacer; | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"foo", "bar"}); | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"01", "2"}); | ||||
|     replacer.replacements.push_back(TextReplacer::Replacement{"3", "456"}); | ||||
| 
 | ||||
|     // Equal-length.
 | ||||
|     REQUIRE(replacer.Apply("foo") == "bar"); | ||||
|     REQUIRE(replacer.Apply("bar") == "bar"); | ||||
| 
 | ||||
|     // Shorter replacement.
 | ||||
|     REQUIRE(replacer.Apply("01") == "2"); | ||||
|     REQUIRE(replacer.Apply("2") == "2"); | ||||
| 
 | ||||
|     // Longer replacement.
 | ||||
|     REQUIRE(replacer.Apply("3") == "456"); | ||||
|     REQUIRE(replacer.Apply("456") == "456"); | ||||
| 
 | ||||
|     // Content before-after replacement.
 | ||||
|     REQUIRE(replacer.Apply("aaaa01bbbb") == "aaaa2bbbb"); | ||||
| 
 | ||||
|     // Multiple replacements.
 | ||||
|     REQUIRE(replacer.Apply("foofoobar0123") == "barbarbar22456"); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| TEST_SUITE("Update \\n to \\r\\n") { | ||||
|   TEST_CASE("all") { | ||||
|     REQUIRE(UpdateToRnNewlines("\n") == "\r\n"); | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/utils.h
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/utils.h
									
									
									
									
									
								
							| @ -7,8 +7,6 @@ | ||||
| #include <iterator> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <unordered_map> | ||||
| #include <unordered_set> | ||||
| #include <vector> | ||||
| 
 | ||||
| // Trim from start (in place)
 | ||||
| @ -111,17 +109,6 @@ struct TextReplacer { | ||||
|   std::string Apply(const std::string& content); | ||||
| }; | ||||
| 
 | ||||
| void ParseTestExpectation( | ||||
|     const std::string& filename, | ||||
|     const std::vector<std::string>& lines_with_endings, | ||||
|     TextReplacer* text_replacer, | ||||
|     std::vector<std::string>* flags, | ||||
|     std::unordered_map<std::string, std::string>* output_sections); | ||||
| 
 | ||||
| void UpdateTestExpectation(const std::string& filename, | ||||
|                            const std::string& expectation, | ||||
|                            const std::string& actual); | ||||
| 
 | ||||
| void WriteToFile(const std::string& filename, const std::string& content); | ||||
| 
 | ||||
| // note: this implementation does not disable this overload for array types
 | ||||
| @ -143,15 +130,6 @@ void AddRange(std::vector<T>* dest, std::vector<T>&& to_add) { | ||||
|                std::make_move_iterator(to_add.end())); | ||||
| } | ||||
| 
 | ||||
| template <typename T> | ||||
| void RemoveRange(std::vector<T>* dest, const std::vector<T>& to_remove) { | ||||
|   std::unordered_set<T> to_remove_set(to_remove.begin(), to_remove.end()); | ||||
|   dest->erase( | ||||
|       std::remove_if(dest->begin(), dest->end(), | ||||
|                      [&](const T& t) { return to_remove_set.count(t) > 0; }), | ||||
|       dest->end()); | ||||
| } | ||||
| 
 | ||||
| // http://stackoverflow.com/a/38140932
 | ||||
| //
 | ||||
| //  struct SomeHashKey {
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user