From 52d9629a5c28225d04035ce30183e1542dfd33ab Mon Sep 17 00:00:00 2001 From: jackfiled Date: Fri, 13 Jun 2025 16:53:25 +0800 Subject: [PATCH] feat: develop the basic functions. --- .clang-format | 2 +- CMakeLists.txt | 3 ++ include/fetcher.h | 14 +++-- justfile | 31 +++++++++++ main.cpp | 3 +- src/CMakeLists.txt | 7 +++ src/fetcher.cpp | 104 +++++++++++++++++++++++++++---------- src/problems/1-two-sum.cpp | 40 ++++++++++++++ src/template.cpp | 11 +++- 9 files changed, 179 insertions(+), 36 deletions(-) create mode 100644 justfile create mode 100644 src/CMakeLists.txt create mode 100644 src/problems/1-two-sum.cpp diff --git a/.clang-format b/.clang-format index f669e03..fc79bcc 100644 --- a/.clang-format +++ b/.clang-format @@ -110,8 +110,8 @@ IndentGotoLabels: false # #endif # #endif IndentPPDirectives: BeforeHash -# IndentAccessModifiers: true IndentWidth: 4 +AccessModifierOffset: -4 KeepEmptyLinesAtTheStartOfBlocks: false MaxEmptyLinesToKeep: 3 NamespaceIndentation: None diff --git a/CMakeLists.txt b/CMakeLists.txt index e2f9fe9..574bd03 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,9 @@ include_directories(include) find_package(CURL REQUIRED) find_package(nlohmann_json REQUIRED) +find_package(GTest REQUIRED) + +add_subdirectory(src) add_executable(leetcode-fetcher main.cpp src/fetcher.cpp) diff --git a/include/fetcher.h b/include/fetcher.h index d6d42b9..298fe05 100644 --- a/include/fetcher.h +++ b/include/fetcher.h @@ -59,25 +59,27 @@ struct CodeDefinition struct ProblemContent { std::string title; - std::string title_slug; + std::string titleSlug; std::string content; std::vector codeDefinitions; int questionId; ProblemContent(std::string title, - std::string title_slug, + std::string titleSlug, std::string content, std::vector codeDefinitions, int questionId) : title(std::move(title)) - , title_slug(std::move(title_slug)) + , titleSlug(std::move(titleSlug)) , content(std::move(content)) , codeDefinitions(std::move(codeDefinitions)) , questionId(questionId) { } - std::string formatTemplate(const std::string &templateContent) const; + [[nodiscard]] std::string formatTemplate(const std::string &templateContent) const; + + [[nodiscard]] std::string formatFilename() const; }; struct Fetcher @@ -104,6 +106,8 @@ private: [[nodiscard]] std::vector getProblems() const; + [[nodiscard]] std::unique_ptr fetchProblemContent(const LeetCodeProblem &problem) const; + /// The callback function used by curl to write the http response content into a string. static size_t httpWriteCallback(void *contents, const size_t size, size_t bufferLength, void *userData) { @@ -121,6 +125,8 @@ private: const LeetCodeProblem &problem); static std::string readTemplateFile(); + + static bool validateExistedProblem(const ProblemContent &problem); }; #endif //FETCHER_H \ No newline at end of file diff --git a/justfile b/justfile new file mode 100644 index 0000000..33ce382 --- /dev/null +++ b/justfile @@ -0,0 +1,31 @@ +#!/usr/bin/env just --justfile + +update: + git pull + +build: update + #!/usr/bin/env bash + set -euxo pipefail + mkdir -p cmake-build-debug-clang + cd cmake-build-debug-clang + cmake .. -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ + ninja + +fmt: + clang-format -i src/problems/*.cpp + +test: fmt build + ./cmake-build-debug-clang/src/problem-tests + +commit: test + #!/usr/bin/env bash + set -euxo pipefail + time=$(date "+%Y%m%d") + message="$time finished." + + git add -A + git commit -m "$message" + git push + +pull id: build + ./cmake-build-debug-clang/leetcode-fetcher {{ id }} diff --git a/main.cpp b/main.cpp index 45a512f..14ba58a 100644 --- a/main.cpp +++ b/main.cpp @@ -6,8 +6,7 @@ int main(int argc, char **argv) if (argc != 2) { - std::cout << "The fetcher expect the program id."; - return -1; + throw std::invalid_argument("The fetcher expect the program id."); } fetcher.fetchProblem(argv[1]); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..3cc4f73 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,7 @@ +enable_testing() + +aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR}/problems PROBLEMS_SRC) + +add_executable(problem-tests ${PROBLEMS_SRC}) + +target_link_libraries(problem-tests GTest::gtest_main) \ No newline at end of file diff --git a/src/fetcher.cpp b/src/fetcher.cpp index 5069883..53a7e55 100644 --- a/src/fetcher.cpp +++ b/src/fetcher.cpp @@ -49,9 +49,40 @@ std::vector Fetcher::getProblems() const return problems; } -std::string replaceString(const std::string &original, - const std::string_view old_sub, - const std::string_view new_sub) +std::unique_ptr Fetcher::fetchProblemContent(const LeetCodeProblem &problem) const +{ + curl_easy_setopt(client.get(), CURLOPT_URL, kGraphQlUrl.c_str()); + curl_easy_setopt(client.get(), CURLOPT_POST, 1L); + + curl_slist *headers = nullptr; + headers = curl_slist_append(headers, "Content-Type: application/json"); + + curl_easy_setopt(client.get(), CURLOPT_HTTPHEADER, headers); + + std::string requestBody = formatQueryJson(problem.questionTitleSlug).dump(); + + curl_easy_setopt(client.get(), CURLOPT_POSTFIELDS, requestBody.c_str()); + curl_easy_setopt(client.get(), CURLOPT_POSTFIELDSIZE, requestBody.size()); + + std::string responseBody; + + curl_easy_setopt(client.get(), CURLOPT_WRITEFUNCTION, Fetcher::httpWriteCallback); + curl_easy_setopt(client.get(), CURLOPT_WRITEDATA, &responseBody); + + CURLcode code = curl_easy_perform(client.get()); + + if (code != CURLE_OK) + { + throw std::runtime_error("Failed to fetch problem."); + } + + const nlohmann::json jsonResponse = nlohmann::json::parse(responseBody); + return extractContentFromJson(jsonResponse, problem); +} + +static std::string replaceString(const std::string &original, + const std::string_view old_sub, + const std::string_view new_sub) { if (old_sub.empty()) return original; // 防止空字符串导致死循环 @@ -108,10 +139,21 @@ std::string ProblemContent::formatTemplate(const std::string &templateContent) c std::string result = replaceString(templateContent, "__PROBLEM_ID__", std::to_string(questionId)); result = replaceString(result, "__PROBLEM_TITLE__", title); result = replaceString(result, "__PROBLEM_DEFAULT_CODE__", it->defaultCode); + std::string testCaseName = "P" + std::to_string(questionId); + result = replaceString(result, "__TEST_CASE_NAME__", testCaseName); return result; } +std::string ProblemContent::formatFilename() const +{ + std::ostringstream stream("p"); + stream << questionId; + stream << "-" << titleSlug << ".cpp"; + + return stream.str(); +} + void Fetcher::fetchProblem(const std::string &idString) const { std::vector problems = getProblems(); @@ -127,37 +169,21 @@ void Fetcher::fetchProblem(const std::string &idString) const throw std::runtime_error("The target problem does not exist."); } - curl_easy_setopt(client.get(), CURLOPT_URL, kGraphQlUrl.c_str()); - curl_easy_setopt(client.get(), CURLOPT_POST, 1L); + std::unique_ptr problemContent = fetchProblemContent(*it); + const std::string templateFile = readTemplateFile(); + std::string problemFileContent = problemContent->formatTemplate(templateFile); + std::string problemFilename = problemContent->formatFilename(); - curl_slist *headers = nullptr; - headers = curl_slist_append(headers, "Content-Type: application/json"); + auto problemFile = std::ofstream("src/problems/" + problemFilename); - curl_easy_setopt(client.get(), CURLOPT_HTTPHEADER, headers); - - std::string requestBody = formatQueryJson(it->questionTitleSlug).dump(); - - curl_easy_setopt(client.get(), CURLOPT_POSTFIELDS, requestBody.c_str()); - curl_easy_setopt(client.get(), CURLOPT_POSTFIELDSIZE, requestBody.size()); - - std::string responseBody; - - curl_easy_setopt(client.get(), CURLOPT_WRITEFUNCTION, Fetcher::httpWriteCallback); - curl_easy_setopt(client.get(), CURLOPT_WRITEDATA, &responseBody); - - CURLcode code = curl_easy_perform(client.get()); - - if (code != CURLE_OK) + if (!problemFile.is_open()) { - throw std::runtime_error("Failed to fetch problem."); + throw std::runtime_error("Failed to open problem file."); } - const nlohmann::json jsonResponse = nlohmann::json::parse(responseBody); - const std::unique_ptr problemContent = extractContentFromJson(jsonResponse, *it); + problemFile << problemFileContent; - std::string templateFile = readTemplateFile(); - - std::cout << problemContent->formatTemplate(templateFile) << std::endl; + problemFile.close(); } nlohmann::json Fetcher::formatQueryJson(const std::string &title) @@ -225,4 +251,26 @@ std::string Fetcher::readTemplateFile() file.close(); return buffer.str(); +} + +bool Fetcher::validateExistedProblem(const ProblemContent &problem) +{ + std::filesystem::path problemDirectory = "src/problems"; + std::string defaultFilename = problem.formatFilename(); + + if (!std::filesystem::exists(problemDirectory)) + { + throw std::runtime_error("The problem directory is not exitsed."); + } + + return std::ranges::any_of(std::filesystem::directory_iterator(problemDirectory), + [&](const std::filesystem::directory_entry &entry) + { + if (!entry.is_regular_file()) + { + return false; + } + + return entry.path().filename() == defaultFilename; + }); } \ No newline at end of file diff --git a/src/problems/1-two-sum.cpp b/src/problems/1-two-sum.cpp new file mode 100644 index 0000000..7a79f00 --- /dev/null +++ b/src/problems/1-two-sum.cpp @@ -0,0 +1,40 @@ +/** +* [1] Two Sum + */ +#include +#include +using namespace std; + + +// submission codes start here + +class Solution +{ +public: + vector twoSum(vector &nums, int target) + { + unordered_map map; + + for (int i = 0; i < nums.size(); ++i) + { + if (const auto &it = map.find(target - nums[i]); it != map.end()) + { + return {it->second, i}; + } + + map.insert({nums[i], i}); + } + + return {}; + } +}; + +// submission codes endo + +TEST(P1, Test1) +{ + Solution s; + vector nums = {2, 7, 11, 15}; + vector result = {0, 1}; + ASSERT_EQ(s.twoSum(nums, 9), result); +} \ No newline at end of file diff --git a/src/template.cpp b/src/template.cpp index 506658a..0abb202 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -1,9 +1,18 @@ /** * [__PROBLEM_ID__] __PROBLEM_TITLE__ */ +#include +#include +using namespace std; + // submission codes start here __PROBLEM_DEFAULT_CODE__ -// submission codes end +// submission codes endo + +TEST(__TEST_CASE_NAME__, Test1) +{ + +}