feat: develop the basic functions.
This commit is contained in:
parent
9ddcad2f08
commit
52d9629a5c
|
@ -110,8 +110,8 @@ IndentGotoLabels: false
|
|||
# #endif
|
||||
# #endif
|
||||
IndentPPDirectives: BeforeHash
|
||||
# IndentAccessModifiers: true
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 3
|
||||
NamespaceIndentation: None
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -59,25 +59,27 @@ struct CodeDefinition
|
|||
struct ProblemContent
|
||||
{
|
||||
std::string title;
|
||||
std::string title_slug;
|
||||
std::string titleSlug;
|
||||
std::string content;
|
||||
std::vector<CodeDefinition> codeDefinitions;
|
||||
int questionId;
|
||||
|
||||
ProblemContent(std::string title,
|
||||
std::string title_slug,
|
||||
std::string titleSlug,
|
||||
std::string content,
|
||||
std::vector<CodeDefinition> 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<LeetCodeProblem> getProblems() const;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ProblemContent> 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
|
31
justfile
Normal file
31
justfile
Normal file
|
@ -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 }}
|
3
main.cpp
3
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]);
|
||||
|
|
7
src/CMakeLists.txt
Normal file
7
src/CMakeLists.txt
Normal file
|
@ -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)
|
100
src/fetcher.cpp
100
src/fetcher.cpp
|
@ -49,7 +49,38 @@ std::vector<LeetCodeProblem> Fetcher::getProblems() const
|
|||
return problems;
|
||||
}
|
||||
|
||||
std::string replaceString(const std::string &original,
|
||||
std::unique_ptr<ProblemContent> 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)
|
||||
{
|
||||
|
@ -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<LeetCodeProblem> 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> 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> 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)
|
||||
|
@ -226,3 +252,25 @@ std::string Fetcher::readTemplateFile()
|
|||
|
||||
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;
|
||||
});
|
||||
}
|
40
src/problems/1-two-sum.cpp
Normal file
40
src/problems/1-two-sum.cpp
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* [1] Two Sum
|
||||
*/
|
||||
#include <bits/stdc++.h>
|
||||
#include <gtest/gtest.h>
|
||||
using namespace std;
|
||||
|
||||
|
||||
// submission codes start here
|
||||
|
||||
class Solution
|
||||
{
|
||||
public:
|
||||
vector<int> twoSum(vector<int> &nums, int target)
|
||||
{
|
||||
unordered_map<int, int> 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);
|
||||
}
|
|
@ -1,9 +1,18 @@
|
|||
/**
|
||||
* [__PROBLEM_ID__] __PROBLEM_TITLE__
|
||||
*/
|
||||
#include <bits/stdc++.h>
|
||||
#include <gtest/gtest.h>
|
||||
using namespace std;
|
||||
|
||||
|
||||
// submission codes start here
|
||||
|
||||
__PROBLEM_DEFAULT_CODE__
|
||||
|
||||
// submission codes end
|
||||
// submission codes endo
|
||||
|
||||
TEST(__TEST_CASE_NAME__, Test1)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user